From 9ffab95d8e74c9259867721ca29043805df823e6 Mon Sep 17 00:00:00 2001 From: oz Date: Wed, 2 Dec 2020 20:12:34 +0300 Subject: [PATCH] winmain message_handler v1. --- Doc/FuncStats.xlsx | Bin 31931 -> 31972 bytes SpaceCadetPinball/Sound.cpp | 17 + SpaceCadetPinball/Sound.h | 4 + SpaceCadetPinball/SpaceCadetPinball.cpp | 7 +- SpaceCadetPinball/SpaceCadetPinball.vcxproj | 7 +- .../SpaceCadetPinball.vcxproj.filters | 12 + SpaceCadetPinball/fullscrn.h | 2 +- SpaceCadetPinball/gdrv.cpp | 5 +- SpaceCadetPinball/midi.cpp | 22 + SpaceCadetPinball/midi.h | 9 + SpaceCadetPinball/nudge.cpp | 26 ++ SpaceCadetPinball/nudge.h | 12 + SpaceCadetPinball/options.cpp | 63 ++- SpaceCadetPinball/options.h | 8 +- SpaceCadetPinball/pb.cpp | 250 ++++++++++- SpaceCadetPinball/pb.h | 15 +- SpaceCadetPinball/pch.h | 1 + SpaceCadetPinball/pinball.cpp | 1 - SpaceCadetPinball/pinball.h | 1 - SpaceCadetPinball/winmain.cpp | 424 +++++++++++++++++- SpaceCadetPinball/winmain.h | 13 +- 21 files changed, 871 insertions(+), 28 deletions(-) create mode 100644 SpaceCadetPinball/midi.cpp create mode 100644 SpaceCadetPinball/midi.h create mode 100644 SpaceCadetPinball/nudge.cpp create mode 100644 SpaceCadetPinball/nudge.h diff --git a/Doc/FuncStats.xlsx b/Doc/FuncStats.xlsx index 8031207d30f2117e8b1bebe262de0a56f671f5f3..11912f7620cb12ae843cc73162e50011715b9ac2 100644 GIT binary patch delta 23134 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 delta 23120 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

aP@2G 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 diff --git a/SpaceCadetPinball/Sound.cpp b/SpaceCadetPinball/Sound.cpp index 9c4df2e..422a790 100644 --- a/SpaceCadetPinball/Sound.cpp +++ b/SpaceCadetPinball/Sound.cpp @@ -1,6 +1,11 @@ #include "pch.h" #include "Sound.h" +int Sound::Init(HINSTANCE hInstance, int voices, void(__stdcall* someFuncPtr)(int, int, int)) +{ + return 1; +} + void Sound::Enable(int a1, int a2, int a3) { } @@ -12,3 +17,15 @@ void Sound::nullsub_1(int a1, int a2, int a3) void Sound::Idle() { } + +void Sound::Activate() +{ +} + +void Sound::Deactivate() +{ +} + +void Sound::Close() +{ +} diff --git a/SpaceCadetPinball/Sound.h b/SpaceCadetPinball/Sound.h index 1fca981..f25c162 100644 --- a/SpaceCadetPinball/Sound.h +++ b/SpaceCadetPinball/Sound.h @@ -2,7 +2,11 @@ class Sound { public: + static int Init(HINSTANCE hInstance, int voices, void (__stdcall* someFuncPtr)(int, int, int)); static void Enable(int a1, int a2, int a3); static void nullsub_1(int a1, int a2, int a3); static void Idle(); + static void Activate(); + static void Deactivate(); + static void Close(); }; diff --git a/SpaceCadetPinball/SpaceCadetPinball.cpp b/SpaceCadetPinball/SpaceCadetPinball.cpp index 92292a6..4c5b028 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.cpp +++ b/SpaceCadetPinball/SpaceCadetPinball.cpp @@ -14,17 +14,16 @@ #include "score.h" #include "TPinballTable.h" #include "TTextBox.h" +#include "winmain.h" int main() { std::cout << "Hello World!\n"; { // Testing with UI - /* lstrcpyA(pinball::DatFileName, "PINBALL.DAT"); - pinball::hinst = GetModuleHandleA(nullptr); char cmdLine[1]{}; pb::init(); - WinMain(pinball::hinst, 0, cmdLine, 10);*/ + WinMain(pinball::hinst, 0, cmdLine, 10); } gdrv::init(0, 0); @@ -40,7 +39,7 @@ int main() auto xx = sizeof(datFileHeader); - lstrcpyA(pinball::DatFileName, "PINBALL.DAT"); + lstrcpyA(winmain::DatFileName, "PINBALL.DAT"); pb::init(); auto datFile = pb::record_table; diff --git a/SpaceCadetPinball/SpaceCadetPinball.vcxproj b/SpaceCadetPinball/SpaceCadetPinball.vcxproj index 5350bc3..a394ae6 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.vcxproj +++ b/SpaceCadetPinball/SpaceCadetPinball.vcxproj @@ -96,7 +96,7 @@ Console true - Comctl32.lib;Winmm.lib;%(AdditionalDependencies) + Comctl32.lib;Winmm.lib;Htmlhelp.lib;%(AdditionalDependencies) @@ -131,6 +131,7 @@ true true true + Comctl32.lib;Winmm.lib;Htmlhelp.lib;%(AdditionalDependencies) @@ -159,6 +160,8 @@ + + @@ -217,6 +220,8 @@ + + diff --git a/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters b/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters index 56254e7..1876e8d 100644 --- a/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters +++ b/SpaceCadetPinball/SpaceCadetPinball.vcxproj.filters @@ -201,6 +201,12 @@ Header Files + + Header Files + + + Header Files + @@ -368,6 +374,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/SpaceCadetPinball/fullscrn.h b/SpaceCadetPinball/fullscrn.h index 7969d64..bb1a9df 100644 --- a/SpaceCadetPinball/fullscrn.h +++ b/SpaceCadetPinball/fullscrn.h @@ -28,6 +28,7 @@ public: static int convert_mouse_pos(unsigned int mouseXY); static void getminmaxinfo(MINMAXINFO* maxMin); static void paint(); + static bool set_menu_mode(int menuEnabled); private : static int MenuEnabled; static HMENU MenuHandle; @@ -37,6 +38,5 @@ private : static int setWindowFlagsDisDlg(); static int enableFullscreen(); static int disableFullscreen(); - static bool set_menu_mode(int menuEnabled); static void fillRect(int right, int bottom); }; diff --git a/SpaceCadetPinball/gdrv.cpp b/SpaceCadetPinball/gdrv.cpp index d1915ad..0145dc7 100644 --- a/SpaceCadetPinball/gdrv.cpp +++ b/SpaceCadetPinball/gdrv.cpp @@ -206,9 +206,10 @@ int gdrv::display_palette(PALETTEENTRY* plt) { if (plt) { - pltDst->peRed = pltSrc->peRed; + // Todo: verify RGB order + pltDst->peRed = pltSrc->peBlue; pltDst->peGreen = pltSrc->peGreen; - pltDst->peBlue = pltSrc->peBlue; + pltDst->peBlue = pltSrc->peRed; } pltDst->peFlags = 4; pltSrc++; diff --git a/SpaceCadetPinball/midi.cpp b/SpaceCadetPinball/midi.cpp new file mode 100644 index 0000000..61a4478 --- /dev/null +++ b/SpaceCadetPinball/midi.cpp @@ -0,0 +1,22 @@ +#include "pch.h" +#include "midi.h" + +MCIERROR midi::play_pb_theme(int flag) +{ + return MCIERROR(); +} + +MCIERROR midi::music_stop() +{ + return MCIERROR(); +} + +int midi::music_init(HWND hwnd) +{ + return 1; +} + +MCIERROR midi::restart_midi_seq(int param) +{ + return MCIERROR(); +} diff --git a/SpaceCadetPinball/midi.h b/SpaceCadetPinball/midi.h new file mode 100644 index 0000000..335574e --- /dev/null +++ b/SpaceCadetPinball/midi.h @@ -0,0 +1,9 @@ +#pragma once +class midi +{ +public: + static MCIERROR play_pb_theme(int flag); + static MCIERROR music_stop(); + static int music_init(HWND hwnd); + static MCIERROR restart_midi_seq(int param); +}; diff --git a/SpaceCadetPinball/nudge.cpp b/SpaceCadetPinball/nudge.cpp new file mode 100644 index 0000000..410202c --- /dev/null +++ b/SpaceCadetPinball/nudge.cpp @@ -0,0 +1,26 @@ +#include "pch.h" +#include "nudge.h" + +void nudge::un_nudge_right(int x, int y) +{ +} + +void nudge::un_nudge_left(int x, int y) +{ +} + +void nudge::un_nudge_up(int x, int y) +{ +} + +void nudge::nudge_right() +{ +} + +void nudge::nudge_left() +{ +} + +void nudge::nudge_up() +{ +} diff --git a/SpaceCadetPinball/nudge.h b/SpaceCadetPinball/nudge.h new file mode 100644 index 0000000..7301902 --- /dev/null +++ b/SpaceCadetPinball/nudge.h @@ -0,0 +1,12 @@ +#pragma once +class nudge +{ +public : + + static void un_nudge_right(int x, int y); + static void un_nudge_left(int x, int y); + static void un_nudge_up(int x, int y); + static void nudge_right(); + static void nudge_left(); + static void nudge_up(); +}; diff --git a/SpaceCadetPinball/options.cpp b/SpaceCadetPinball/options.cpp index 1313bd6..d9fcb62 100644 --- a/SpaceCadetPinball/options.cpp +++ b/SpaceCadetPinball/options.cpp @@ -1,6 +1,9 @@ #include "pch.h" #include "options.h" + +#include "fullscrn.h" #include "memory.h" +#include "midi.h" #include "pinball.h" #include "Sound.h" @@ -185,10 +188,62 @@ void options::set_string(LPCSTR optPath, LPCSTR lpValueName, LPCSTR value) } -HMENU options::menu_check(UINT uIDCheckItem, int value) +void options::menu_check(UINT uIDCheckItem, int check) { - HMENU result = MenuHandle; if (MenuHandle) - result = (HMENU)CheckMenuItem(MenuHandle, uIDCheckItem, value != 0 ? 8 : 0); - return result; + CheckMenuItem(MenuHandle, uIDCheckItem, check != 0 ? 8 : 0); +} + +void options::menu_set(UINT uIDEnableItem, int enable) +{ + if (MenuHandle) + EnableMenuItem(MenuHandle, uIDEnableItem, enable == 0); +} + + +void options::toggle(UINT uIDCheckItem) +{ + int newValue; + switch (uIDCheckItem) + { + case 0xC9u: + newValue = Options.Sounds == 0; + Options.Sounds = Options.Sounds == 0; + Sound::Enable(0, 7, newValue); + menu_check(uIDCheckItem, newValue); + return; + case 0xCAu: + newValue = Options.Music == 0; + Options.Music = Options.Music == 0; + if (!newValue) + midi::music_stop(); + else + midi::play_pb_theme(0); + menu_check(uIDCheckItem, newValue); + return; + case 0x193u: + newValue = Options.FullScreen == 0; + Options.FullScreen = Options.FullScreen == 0; + fullscrn::set_screen_mode(newValue); + menu_check(uIDCheckItem, newValue); + return; + } + if (uIDCheckItem > 407 && uIDCheckItem <= 411) + { + Options.Players = uIDCheckItem - 407; + menu_check(0x198u, uIDCheckItem == 408); + menu_check(0x199u, Options.Players == 2); + menu_check(0x19Au, Options.Players == 3); + menu_check(0x19Bu, Options.Players == 4); + } +} + +void options::keyboard() +{ + DialogBoxParamA(pinball::hinst, "KEYMAPPER", pinball::hwnd_frame, KeyMapDlgProc, 0); +} + +INT_PTR _stdcall options::KeyMapDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + return 0; } diff --git a/SpaceCadetPinball/options.h b/SpaceCadetPinball/options.h index e9b9d80..19cc41a 100644 --- a/SpaceCadetPinball/options.h +++ b/SpaceCadetPinball/options.h @@ -33,8 +33,12 @@ public: 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 set_string(LPCSTR optPath, LPCSTR lpValueName, LPCSTR value); - static HMENU menu_check(UINT uIDCheckItem, int value); - + static void menu_check(UINT uIDCheckItem, int check); + static void menu_set(UINT uIDEnableItem, int enable); + static void toggle(UINT uIDCheckItem); + static void keyboard(); + static INT_PTR _stdcall KeyMapDlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); + static optionsStruct Options; private: static LPCSTR OptionsRegPath; diff --git a/SpaceCadetPinball/pb.cpp b/SpaceCadetPinball/pb.cpp index a566fef..0f766c6 100644 --- a/SpaceCadetPinball/pb.cpp +++ b/SpaceCadetPinball/pb.cpp @@ -6,12 +6,17 @@ #include "proj.h" #include "render.h" #include "loader.h" +#include "midi.h" +#include "nudge.h" #include "options.h" #include "timer.h" +#include "winmain.h" TPinballTable* pb::MainTable = nullptr; datFileStruct* pb::record_table = nullptr; -int pb::time_ticks = 0, pb::demo_mode = 0; +int pb::time_ticks = 0, pb::demo_mode = 0, pb::cheat_mode = 0, pb::game_mode = 2, pb::mode_countdown_, pb:: + ball_speed_limit; +float pb::time_now, pb::time_next; int pb::init() { @@ -20,7 +25,7 @@ int pb::init() CHAR dataFilePath[300]; ++memory::critical_allocation; - lstrcpyA(datFileName, pinball::DatFileName); + lstrcpyA(datFileName, winmain::DatFileName); pinball::make_path_name(dataFilePath, datFileName, 300); record_table = partman::load_records(dataFilePath); @@ -53,6 +58,7 @@ int pb::init() } render::init(nullptr, zMin, zScaler, tableSize[0], tableSize[1]); + gdrv::fill_bitmap(&render::vscreen, render::vscreen.Width, render::vscreen.Height, 0, 0, 0xff); // temp gdrv::copy_bitmap( &render::vscreen, backgroundBmp->Width, @@ -130,15 +136,249 @@ void pb::replay_level(int demoMode) demo_mode = demoMode; mode_change(1); //if (options::Options.Music) - //midi_play_pb_theme(0); + midi::play_pb_theme(0); MainTable->Message(1014, static_cast(options::Options.Players)); } void pb::ballset(int x, int y) -{ +{ } int pb::frame(int time) { + if (time > 100) + time = 100; + float timeMul = time * 0.001f; + if (!mode_countdown(time)) + { + time_next = time_now + timeMul; + //pb::timed_frame(time_now, timeMul, 1); + time_now = time_next; + time_ticks += time; + /*if (nudged_left || nudged_right || nudged_up) + { + nudge_count = timeMul * 4.0 + nudge_count; + } + else + { + v2 = nudge_count - timeMul; + if (v2 <= 0.0) + v2 = 0.0; + nudge_count = v2; + }*/ + //timer::check(); + render::update(); + //score::update(MainTable->Score1); + /*if (!MainTable->UnknownP83) + { + if (nudge_count > 0.5) + { + v3 = pinball:: get_rc_string(25, 0); + pinball::InfoTextBox->Display( v3, 2.0); + } + if (nudge_count > 1.0) + TPinballTable::tilt(MainTable, v1, time_now); + }*/ + } return 1; -} \ No newline at end of file +} + +void pb::window_size(int* width, int* height) +{ + *width = 600; + *height = 416; +} + +void pb::pause_continue() +{ + winmain::single_step = winmain::single_step == 0; + pinball::InfoTextBox->Clear(); + pinball::MissTextBox->Clear(); + if (winmain::single_step) + { + if (MainTable) + MainTable->Message(1008, time_now); + pinball::InfoTextBox->Display(pinball::get_rc_string(22, 0), -1.0); + midi::music_stop(); + } + else + { + if (MainTable) + MainTable->Message(1009, 0.0); + if (!demo_mode) + { + char* text; + float textTime; + if (game_mode == 2) + { + textTime = -1.0; + text = pinball::get_rc_string(24, 0); + } + else + { + textTime = 5.0; + text = pinball::get_rc_string(23, 0); + } + pinball::InfoTextBox->Display(text, textTime); + } + if (options::Options.Music && !winmain::single_step) + midi::play_pb_theme(0); + } +} + +void pb::loose_focus() +{ + if (MainTable) + MainTable->Message(1010, time_now); +} + +void pb::keyup(int key) +{ + if (game_mode == 1 && !winmain::single_step && !demo_mode) + { + if (key == options::Options.LeftFlipperKey) + { + MainTable->Message(1001, time_now); + } + else if (key == options::Options.RightFlipperKey) + { + MainTable->Message(1003, time_now); + } + else if (key == options::Options.PlungerKey) + { + MainTable->Message(1005, time_now); + } + else if (key == options::Options.LeftTableBumpKey) + { + nudge::un_nudge_right(0, 0); + } + else if (key == options::Options.RightTableBumpKey) + { + nudge::un_nudge_left(0, 0); + } + else if (key == options::Options.BottomTableBumpKey) + { + nudge::un_nudge_up(0, 0); + } + } +} + +void pb::keydown(int key) +{ + if (winmain::single_step || demo_mode) + return; + if (game_mode != 1) + { + mode_countdown(-1); + return; + } + ctrl_bdoor_controller(key); + if (key == options::Options.LeftFlipperKey) + { + MainTable->Message(1000, time_now); + return; + } + if (key == options::Options.RightFlipperKey) + { + MainTable->Message(1002, time_now); + } + else + { + if (key == options::Options.PlungerKey) + { + MainTable->Message(1004, time_now); + return; + } + if (key == options::Options.LeftTableBumpKey) + { + if (!MainTable->UnknownP83) + nudge::nudge_right(); + return; + } + if (key == options::Options.RightTableBumpKey) + { + if (!MainTable->UnknownP83) + nudge::nudge_left(); + return; + } + if (key == options::Options.BottomTableBumpKey) + { + if (!MainTable->UnknownP83) + nudge::nudge_up(); + return; + } + } + if (cheat_mode) + { + switch (key) + { + case 'B': + /**/ + break; + case 'H': + /*auto v1 = get_rc_string(26, 0); + lstrcpyA(&String1, v1); + show_and_set_high_score_dialog(highscore_table, 1000000000, 1, &String1);*/ + break; + case 'M': + char buffer[20]; + sprintf_s(buffer, "%ld", memory::use_total); + MessageBoxA(pinball::hwnd_frame, buffer, "Mem:", 0x2000u); + break; + case 'R': + cheat_bump_rank(); + break; + case VK_F11: + gdrv::get_focus(); + break; + case VK_F12: + MainTable->port_draw(); + break; + } + } +} + +void pb::ctrl_bdoor_controller(int key) +{ +} + +int pb::mode_countdown(int time) +{ + if (!game_mode || game_mode <= 0) + return 1; + if (game_mode > 2) + { + if (game_mode == 3) + { + mode_countdown_ -= time; + if (mode_countdown_ < 0 || time < 0) + mode_change(4); + } + else if (game_mode == 4) + { + mode_countdown_ -= time; + if (mode_countdown_ < 0 || time < 0) + mode_change(1); + } + return 1; + } + return 0; +} + +int pb::cheat_bump_rank() +{ + return 0; +} + +void pb::launch_ball() +{ +} + +int pb::end_game() +{ + return 0; +} + +void pb::high_scores() +{ +} diff --git a/SpaceCadetPinball/pb.h b/SpaceCadetPinball/pb.h index 31b3d62..8a644bd 100644 --- a/SpaceCadetPinball/pb.h +++ b/SpaceCadetPinball/pb.h @@ -7,6 +7,7 @@ class pb public: static int time_ticks; static int ball_speed_limit; + static int cheat_mode, game_mode; static datFileStruct* record_table; static TPinballTable* MainTable; @@ -19,6 +20,18 @@ public: static void replay_level(int demoMode); static void ballset(int x, int y); static int frame(int time); + static void window_size(int* width, int* height); + static void pause_continue(); + static void loose_focus(); + static void keyup(int key); + static void keydown(int key); + static void ctrl_bdoor_controller(int key); + static int mode_countdown(int time); + static int cheat_bump_rank(); + static void launch_ball(); + static int end_game(); + static void high_scores(); private : - static int demo_mode; + static int demo_mode, mode_countdown_; + static float time_now, time_next; }; diff --git a/SpaceCadetPinball/pch.h b/SpaceCadetPinball/pch.h index abc1f98..6b6ed30 100644 --- a/SpaceCadetPinball/pch.h +++ b/SpaceCadetPinball/pch.h @@ -15,6 +15,7 @@ #include #include #include +#include //#include // Use (void) to silent unused warnings. diff --git a/SpaceCadetPinball/pinball.cpp b/SpaceCadetPinball/pinball.cpp index 8c9ff66..23001b2 100644 --- a/SpaceCadetPinball/pinball.cpp +++ b/SpaceCadetPinball/pinball.cpp @@ -10,7 +10,6 @@ char pinball::getRcBuffer[6 * 256]; int pinball::rc_string_slot = 0; HINSTANCE pinball::hinst; char pinball::WindowName[2]{}; -char pinball::DatFileName[300]{}; int pinball::LeftShift = -1; int pinball::RightShift = -1; HWND pinball::hwnd_frame = nullptr; diff --git a/SpaceCadetPinball/pinball.h b/SpaceCadetPinball/pinball.h index f15c00b..c794450 100644 --- a/SpaceCadetPinball/pinball.h +++ b/SpaceCadetPinball/pinball.h @@ -9,7 +9,6 @@ public: static TTextBox* MissTextBox; static HINSTANCE hinst; static char WindowName[2]; - static char DatFileName[300]; static int RightShift; static int LeftShift; static HWND hwnd_frame; diff --git a/SpaceCadetPinball/winmain.cpp b/SpaceCadetPinball/winmain.cpp index 3f9c6ca..1aa2b94 100644 --- a/SpaceCadetPinball/winmain.cpp +++ b/SpaceCadetPinball/winmain.cpp @@ -3,16 +3,20 @@ #include "fullscrn.h" #include "memory.h" +#include "midi.h" #include "pinball.h" #include "options.h" #include "pb.h" #include "Sound.h" -int winmain::iFrostUniqueMsg, winmain::return_value = 0, winmain::bQuit = 0; +int winmain::return_value = 0, winmain::bQuit = 0, winmain::activated; DWORD winmain::then, winmain::now; +UINT winmain::iFrostUniqueMsg; gdrv_bitmap8 winmain::gfr_display{}; int winmain::DispFrameRate = 1, winmain::DispGRhistory = 1, winmain::single_step = 0; int winmain::has_focus = 1, winmain::last_mouse_x, winmain::last_mouse_y, winmain::mouse_down, winmain::no_time_loss; +char winmain::DatFileName[300]{}; +HCURSOR winmain::mouse_hsave; int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) { @@ -89,7 +93,7 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi pinball::quickFlag = strstr(lpCmdLine, "-quick") != nullptr; pinball::hinst = hInstance; - options::get_string(regSpaceCadet, "Pinball Data", pinball::DatFileName, pinball::get_rc_string(168, 0), 300); + options::get_string(regSpaceCadet, "Pinball Data", DatFileName, pinball::get_rc_string(168, 0), 300); iFrostUniqueMsg = RegisterWindowMessageA("PinballThemeSwitcherUniqueMsgString"); auto windowHandle = FindWindowA(pinball::get_rc_string(167, 0), nullptr); @@ -272,6 +276,364 @@ int winmain::WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi LRESULT CALLBACK winmain::message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) { + if (Msg == iFrostUniqueMsg) + { + if (IsIconic(hWnd)) + ShowWindow(hWnd, 9); + SetForegroundWindow(hWnd); + return 0; + } + + if (Msg <= WM_ACTIVATEAPP) + { + switch (Msg) + { + case WM_ACTIVATEAPP: + if (wParam) + { + activated = 1; + Sound::Activate(); + if (options::Options.Music && !single_step) + midi::play_pb_theme(0); + no_time_loss = 1; + pinball::adjust_priority(options::Options.PriorityAdj); + } + else + { + activated = 0; + fullscrn::activate(0); + options::menu_check(0x193u, 0); + options::Options.FullScreen = 0; + SetThreadPriority(GetCurrentThread(), 0); + Sound::Deactivate(); + midi::music_stop(); + } + + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_KILLFOCUS: + has_focus = 0; + gdrv::get_focus(); + pb::loose_focus(); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_CREATE: + { + RECT rect{}; + ++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, (LPCSTR)IDC_WAIT)); + gdrv::init(pinball::hinst, hWnd); + + auto voiceCount = options::get_int(nullptr, "Voices", 8); + if (!Sound::Init(pinball::hinst, voiceCount, nullptr)) + options::menu_set(0xC9u, 0); + Sound::Activate(); + + if (!pinball::quickFlag && !midi::music_init(hWnd)) + options::menu_set(0xCAu, 0); + + if (pb::init()) + _exit(0); + SetCursor(prevCursor); + auto changeDisplayFg = options::get_int(nullptr, "Change Display", 1); + auto menuHandle = GetMenu(hWnd); + fullscrn::init(width, static_cast(height), options::Options.FullScreen, hWnd, menuHandle, + changeDisplayFg); + + --memory::critical_allocation; + return DefWindowProcA(hWnd, Msg, wParam, lParam); + } + case WM_MOVE: + no_time_loss = 1; + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_SETFOCUS: + has_focus = 1; + no_time_loss = 1; + gdrv::get_focus(); + fullscrn::force_redraw(); + pb::paint(); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_PAINT: + { + PAINTSTRUCT paint{}; + _BeginPaint(hWnd, &paint); + fullscrn::paint(); + EndPaint(hWnd, &paint); + break; + } + case WM_CLOSE: + case WM_QUIT: + case WM_DESTROY: + end_pause(); + bQuit = 1; + PostQuitMessage(0); + fullscrn::shutdown(); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_ERASEBKGND: + break; + default: + return DefWindowProcA(hWnd, Msg, wParam, lParam); + } + return 0; + } + + if (Msg <= WM_MENUSELECT) + { + switch (Msg) + { + case WM_MENUSELECT: + if (lParam) + return DefWindowProcA(hWnd, Msg, wParam, lParam); + if (fullscrn::screen_mode) + fullscrn::set_menu_mode(0); + return 0; + case WM_SYSKEYDOWN: + no_time_loss = 1; + if (fullscrn::screen_mode) + fullscrn::set_menu_mode(1); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_GETMINMAXINFO: + fullscrn::getminmaxinfo((MINMAXINFO*)lParam); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_DISPLAYCHANGE: + if (fullscrn::displaychange()) + { + options::Options.FullScreen = 0; + options::menu_check(0x193u, 0); + } + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_KEYUP: + pb::keyup(wParam); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_KEYDOWN: + if (!(lParam & 0x40000000)) + pb::keydown(wParam); + switch (wParam) + { + case VK_ESCAPE: + if (options::Options.FullScreen) + options::toggle(0x193u); + SendMessageA(pinball::hwnd_frame, 0x112u, 0xF020u, 0); + break; + case VK_F1: + help_introduction(pinball::hinst, hWnd); + break; + case VK_F2: + new_game(); + break; + case VK_F3: + pause(); + break; + case VK_F4: + options::toggle(0x193u); + break; + case VK_F8: + if (!single_step) + pause(); + options::keyboard(); + break; + } + if (!pb::cheat_mode) + return DefWindowProcA(hWnd, Msg, wParam, lParam); + switch (wParam) + { + case 'H': + DispGRhistory = 1; + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case 'Y': + SetWindowTextA(hWnd, "Pinball"); + DispFrameRate = DispFrameRate == 0; + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case VK_F1: + pb::frame(10); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case VK_F15: + single_step = single_step == 0; + if (single_step == 0) + no_time_loss = 1; + return DefWindowProcA(hWnd, Msg, wParam, lParam); + default: + return DefWindowProcA(hWnd, Msg, wParam, lParam); + } + case WM_SYSCOMMAND: + switch (wParam & 0xFFF0) + { + case SC_MOVE: + if (fullscrn::screen_mode) + return 0; + case SC_MINIMIZE: + if (!single_step) + pause(); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case SC_SCREENSAVE: + fullscrn::activate(0); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + default: break; + } + end_pause(); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_INITMENU: + no_time_loss = 1; + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_COMMAND: + no_time_loss = 1; + switch (wParam) + { + case 0x191u: + end_pause(); + pb::launch_ball(); + break; + case 0x192u: + pause(); + break; + case 0x193u: + if (!single_step) + pause(); + options::toggle(wParam); + break; + case 0x194u: + end_pause(); + pb::toggle_demo(); + break; + case 0x195u: + { + if (!single_step) + pause(); + auto tmpBuf = memory::allocate(0x1F4u); + if (tmpBuf) + { + char cmdLine[0x1F4u]; + options::get_string(nullptr, "Shell Exe", tmpBuf, pinball::WindowName, 500); + sprintf_s( + cmdLine, + "%s %s%lX %s%lX", + tmpBuf, + "select=", + (int)pinball::hwnd_frame, + "confirm=", + (int)pinball::hwnd_frame + * (int)pinball::hwnd_frame + * (int)pinball::hwnd_frame + * (int)pinball::hwnd_frame + * (int)pinball::hwnd_frame + * (int)pinball::hwnd_frame + * (int)pinball::hwnd_frame); + if (static_cast(WinExec(cmdLine, 5u)) < 32) + { + auto caption = pinball::get_rc_string(170, 0); + auto text = pinball::get_rc_string(171, 0); + MessageBoxA(pinball::hwnd_frame, text, caption, 0x2010u); + } + memory::free(tmpBuf); + } + break; + } + case 0x196u: + if (!single_step) + pause(); + options::keyboard(); + break; + case 0x198u: + case 0x199u: + case 0x19Au: + case 0x19Bu: + options::toggle(wParam); + new_game(); + break; + case 301: + if (!single_step) + pause(); + help_introduction(pinball::hinst, hWnd); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case 0x6A: + pb::end_game(); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case 201: + case 202: + if (!single_step) + pause(); + options::toggle(wParam); + break; + case 204: + if (!single_step) + pause(); + options::keyboard(); + break; + case 0x69u: + PostMessageA(hWnd, 0x12u, 0, 0); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case 0x65u: + new_game(); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case 0x66u: + if (!single_step) + pause(); + a_dialog(pinball::hinst, hWnd); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case 0x67u: + if (!single_step) + pause(); + pb::high_scores(); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case 1: + midi::restart_midi_seq(lParam); + default: + break; + } + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_LBUTTONDOWN: + if (pb::game_mode) + { + if (pb::cheat_mode) + { + mouse_down = 1; + mouse_hsave = SetCursor(nullptr); + auto lParam2 = fullscrn::convert_mouse_pos(lParam); + last_mouse_x = static_cast(lParam2); + last_mouse_y = static_cast(lParam2) >> 16; + SetCapture(hWnd); + } + return DefWindowProcA(hWnd, Msg, wParam, lParam); + } + break; + case WM_LBUTTONUP: + if (mouse_down) + { + mouse_down = 0; + SetCursor(mouse_hsave); + ReleaseCapture(); + } + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_RBUTTONDOWN: + case WM_MBUTTONDOWN: + if (pb::game_mode) + return DefWindowProcA(hWnd, Msg, wParam, lParam); + break; + case WM_POWERBROADCAST: + if (wParam == 4 && options::Options.FullScreen) + { + options::Options.FullScreen = 0; + options::menu_check(0x193u, 0); + fullscrn::set_screen_mode(options::Options.FullScreen); + } + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_PALETTECHANGED: + InvalidateRect(hWnd, nullptr, 0); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + case WM_POINTERDEVICEINRANGE | LB_ADDSTRING: + if (wParam == 1) + midi::restart_midi_seq(lParam); + return DefWindowProcA(hWnd, Msg, wParam, lParam); + default: + return DefWindowProcA(hWnd, Msg, wParam, lParam); + } + } + + pb::mode_countdown(-1); return DefWindowProcA(hWnd, Msg, wParam, lParam); } @@ -306,8 +668,8 @@ int winmain::ProcessWindowMessages() void winmain::memalloc_failure() { - /*midi_music_stop(); - Sound_Close();*/ + midi::music_stop(); + Sound::Close(); gdrv::uninit(); char* caption = pinball::get_rc_string(170, 0); char* text = pinball::get_rc_string(179, 0); @@ -347,3 +709,57 @@ int winmain::a_dialog(HINSTANCE hInstance, HWND hWnd) auto icon = LoadIconA(hInstance, "ICON_1"); return ShellAboutA(hWnd, appName, szOtherStuff, icon); } + +void winmain::end_pause() +{ + if (single_step) + { + if (fullscrn::screen_mode) + fullscrn::set_menu_mode(0); + pb::pause_continue(); + no_time_loss = 1; + } +} + +void winmain::new_game() +{ + end_pause(); + HCURSOR prevCursor = SetCursor(LoadCursorA(nullptr, (LPCSTR)IDC_WAIT)); + pb::replay_level(0); + SetCursor(prevCursor); +} + +void winmain::pause() +{ + if (fullscrn::screen_mode) + { + if (single_step) + fullscrn::set_menu_mode(0); + else + fullscrn::set_menu_mode(1); + } + pb::pause_continue(); + no_time_loss = 1; +} + +void winmain::help_introduction(HINSTANCE a1, HWND a2) +{ + char* buf1 = memory::allocate(0x1F4u); + if (buf1) + { + char* buf2 = memory::allocate(0x1F4u); + if (buf2) + { + options::get_string(nullptr, "HelpFile", buf1, pinball::get_rc_string(178, 0), 500); + options::get_string(pinball::get_rc_string(166, 0), "HelpFile", buf1, buf1, 500); + lstrcpyA(buf2, buf1); + memory::free(buf1); + HtmlHelpA(GetDesktopWindow(), buf2, 0, 0); + memory::free(buf2); + } + else + { + memory::free(buf1); + } + } +} diff --git a/SpaceCadetPinball/winmain.h b/SpaceCadetPinball/winmain.h index c424130..b916b28 100644 --- a/SpaceCadetPinball/winmain.h +++ b/SpaceCadetPinball/winmain.h @@ -4,6 +4,9 @@ class winmain { public: + static char DatFileName[300]; + static int single_step; + static int WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd); static LRESULT CALLBACK message_handler(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam); static void memalloc_failure(); @@ -11,11 +14,17 @@ public: static int check_expiration_date(); static HDC _GetDC(HWND hWnd); static int a_dialog(HINSTANCE hInstance, HWND hWnd); + static void end_pause(); + static void new_game(); + static void pause(); + static void help_introduction(HINSTANCE a1, HWND a2); private: - static int iFrostUniqueMsg, return_value, bQuit, DispFrameRate, DispGRhistory; - static int has_focus, single_step, mouse_down, last_mouse_x, last_mouse_y, no_time_loss; + static int return_value, bQuit, DispFrameRate, DispGRhistory, activated; + static int has_focus, mouse_down, last_mouse_x, last_mouse_y, no_time_loss; static DWORD then, now; + static UINT iFrostUniqueMsg; static gdrv_bitmap8 gfr_display; + static HCURSOR mouse_hsave; static HDC _BeginPaint(HWND hWnd, LPPAINTSTRUCT lpPaint); };