cave-story-solaris/src/Main.cpp
Clownacy f6606b7748 Add some missing function names
These were retrieved from the Mac port (v0.0.7), which kept these
functions.

Unfortunately, this port is missing local variable names, so we can't
use it to make InitBack accurate.
2020-03-22 15:31:28 +00:00

804 lines
14 KiB
C++

#include "Main.h"
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include <shlwapi.h>
#include "WindowsWrapper.h"
#include "CommonDefines.h"
#include "Config.h"
#include "Dialog.h"
#include "Draw.h"
#include "Game.h"
#include "Generic.h"
#include "Input.h"
#include "KeyControl.h"
#include "MyChar.h"
#include "Organya.h"
#include "Profile.h"
#include "Sound.h"
#include "Triangle.h"
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
char gModulePath[MAX_PATH];
char gDataPath[MAX_PATH];
HWND ghWnd;
BOOL bFullscreen;
BOOL gbUseJoystick = FALSE;
int gJoystickButtonTable[8];
static BOOL bActive = TRUE;
static BOOL bFps = FALSE;
static HANDLE hObject;
static HANDLE hMutex;
static HINSTANCE ghInstance;
static int windowWidth;
static int windowHeight;
static const char *mutex_name = "Doukutsu";
#ifdef JAPANESE
static const char *lpWindowName = "\x93\xB4\x8C\x41\x95\xA8\x8C\xEA"; // '洞窟物語' (Cave Story) in Shift-JIS
#else
static const char *lpWindowName = "Cave Story ~ Doukutsu Monogatari";
#endif
void SetWindowName(HWND hWnd)
{
char window_name[0x100];
sprintf(window_name, "%s", lpWindowName);
SetWindowTextA(hWnd, window_name);
}
// Framerate stuff
void PutFramePerSecound(void)
{
if (bFps)
{
const unsigned long fps = GetFramePerSecound();
PutNumber4(WINDOW_WIDTH - 40, 8, fps, FALSE);
}
}
unsigned long GetFramePerSecound(void)
{
unsigned long current_tick;
static BOOL need_new_base_tick = TRUE;
static unsigned long frames_this_second;
static unsigned long current_frame;
static unsigned long base_tick;
if (need_new_base_tick)
{
base_tick = GetTickCount();
need_new_base_tick = FALSE;
}
current_tick = GetTickCount();
++current_frame;
if (base_tick + 1000 <= current_tick)
{
base_tick += 1000;
frames_this_second = current_frame;
current_frame = 0;
}
return frames_this_second;
}
// TODO - Inaccurate stack frame
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
(void)hPrevInstance;
(void)lpCmdLine;
(void)nShowCmd;
int i;
hObject = OpenMutexA(MUTEX_ALL_ACCESS, 0, mutex_name);
if (hObject != NULL)
{
CloseHandle(hObject);
return 0;
}
hMutex = CreateMutexA(NULL, FALSE, mutex_name);
ghInstance = hInstance;
// Get executable's path
GetModuleFileNameA(NULL, gModulePath, MAX_PATH);
PathRemoveFileSpecA(gModulePath);
// Get path of the data folder
strcpy(gDataPath, gModulePath);
strcat(gDataPath, "\\data");
CONFIG conf;
if (!LoadConfigData(&conf))
DefaultConfigData(&conf);
// Apply keybinds
// Swap X and Z buttons
switch (conf.attack_button_mode)
{
case 0:
gKeyJump = KEY_Z;
gKeyShot = KEY_X;
break;
case 1:
gKeyJump = KEY_X;
gKeyShot = KEY_Z;
break;
}
// Swap Okay and Cancel buttons
switch (conf.ok_button_mode)
{
case 0:
gKeyOk = gKeyJump;
gKeyCancel = gKeyShot;
break;
case 1:
gKeyOk = gKeyShot;
gKeyCancel = gKeyJump;
break;
}
// Swap left and right weapon switch keys
if (IsKeyFile("s_reverse"))
{
gKeyArms = KEY_ARMSREV;
gKeyArmsRev = KEY_ARMS;
}
// Alternate movement keys
switch (conf.move_button_mode)
{
case 0:
gKeyLeft = KEY_LEFT;
gKeyUp = KEY_UP;
gKeyRight = KEY_RIGHT;
gKeyDown = KEY_DOWN;
break;
case 1:
gKeyLeft = KEY_ALT_LEFT;
gKeyUp = KEY_ALT_UP;
gKeyRight = KEY_ALT_RIGHT;
gKeyDown = KEY_ALT_DOWN;
break;
}
// Set gamepad inputs
for (i = 0; i < 8; ++i)
{
switch (conf.joystick_button[i])
{
case 1:
gJoystickButtonTable[i] = gKeyJump;
break;
case 2:
gJoystickButtonTable[i] = gKeyShot;
break;
case 3:
gJoystickButtonTable[i] = gKeyArms;
break;
case 6:
gJoystickButtonTable[i] = gKeyArmsRev;
break;
case 4:
gJoystickButtonTable[i] = gKeyItem;
break;
case 5:
gJoystickButtonTable[i] = gKeyMap;
break;
}
}
RECT unused_rect = {0, 0, WINDOW_WIDTH, WINDOW_HEIGHT};
WNDCLASSEXA wndclassex;
memset(&wndclassex, 0, sizeof(WNDCLASSEXA));
wndclassex.cbSize = sizeof(WNDCLASSEXA);
wndclassex.lpfnWndProc = WindowProcedure;
wndclassex.hInstance = hInstance;
wndclassex.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH); // This is what gives the window's undrawn regions its grey colour
wndclassex.lpszClassName = lpWindowName;
wndclassex.hCursor = LoadCursorA(hInstance, "CURSOR_NORMAL");
wndclassex.hIcon = LoadIconA(hInstance, "0");
wndclassex.hIconSm = LoadIconA(hInstance, "ICON_MINI");
HWND hWnd;
HMENU hMenu;
int nWidth;
int nHeight;
int x;
int y;
switch (conf.display_mode)
{
case 1:
case 2:
wndclassex.lpszMenuName = "MENU_MAIN";
if (RegisterClassExA(&wndclassex) == 0)
{
ReleaseMutex(hMutex);
return 0;
}
// Set window dimensions
if (conf.display_mode == 1)
{
windowWidth = WINDOW_WIDTH;
windowHeight = WINDOW_HEIGHT;
}
else
{
windowWidth = WINDOW_WIDTH * 2;
windowHeight = WINDOW_HEIGHT * 2;
}
nWidth = (GetSystemMetrics(SM_CXFIXEDFRAME) * 2) + windowWidth + 2;
nHeight = (GetSystemMetrics(SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYMENU) + windowHeight + 2;
x = (GetSystemMetrics(SM_CXSCREEN) - nWidth) / 2;
y = (GetSystemMetrics(SM_CYSCREEN) - nHeight) / 2;
SetClientOffset(GetSystemMetrics(SM_CXFIXEDFRAME) + 1, GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYMENU) + 1);
hWnd = CreateWindowExA(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, lpWindowName, lpWindowName, WS_MINIMIZEBOX | WS_SYSMENU | WS_BORDER | WS_DLGFRAME | WS_VISIBLE, x, y, nWidth, nHeight, NULL, NULL, hInstance, NULL);
ghWnd = hWnd;
if (hWnd == NULL)
{
ReleaseMutex(hMutex);
return 0;
}
hMenu = GetMenu(hWnd);
#ifdef FIX_BUGS
if (conf.display_mode == 1)
{
if (!StartDirectDraw(hWnd, 0, 0))
return 0;
}
else
{
if (!StartDirectDraw(hWnd, 1, 0))
return 0;
}
#else
// Doesn't handle StartDirectDraw failing
if (conf.display_mode == 1)
StartDirectDraw(hWnd, 0, 0);
else
StartDirectDraw(hWnd, 1, 0);
#endif
break;
case 0:
case 3:
case 4:
if (RegisterClassExA(&wndclassex) == 0)
{
ReleaseMutex(hMutex);
return 0;
}
// Set window dimensions
windowWidth = WINDOW_WIDTH * 2;
windowHeight = WINDOW_HEIGHT * 2;
SetClientOffset(0, 0);
hWnd = CreateWindowExA(WS_EX_LEFT | WS_EX_LTRREADING | WS_EX_RIGHTSCROLLBAR, lpWindowName, lpWindowName, WS_SYSMENU | WS_VISIBLE | WS_POPUP, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), NULL, NULL, hInstance, NULL);
ghWnd = hWnd;
if (hWnd == NULL)
{
ReleaseMutex(hMutex);
return 0;
}
// Set colour depth
int depth;
switch (conf.display_mode)
{
case 0:
depth = 16;
break;
case 3:
depth = 24;
break;
case 4:
depth = 32;
break;
}
#ifdef FIX_BUGS
if (!StartDirectDraw(hWnd, 2, depth))
return 0;
#else
// Doesn't handle StartDirectDraw failing
StartDirectDraw(hWnd, 2, depth);
#endif
bFullscreen = TRUE;
ShowCursor(FALSE);
break;
}
// Set rects
RECT rcLoading = {0, 0, 64, 8};
RECT rcFull = {0, 0, 0, 0};
rcFull.right = WINDOW_WIDTH;
rcFull.bottom = WINDOW_HEIGHT;
// Load the "LOADING" text
BOOL b = MakeSurface_File("Loading", SURFACE_ID_LOADING);
// Draw loading screen
CortBox(&rcFull, 0x000000);
PutBitmap3(&rcFull, (WINDOW_WIDTH / 2) - 32, (WINDOW_HEIGHT / 2) - 4, &rcLoading, SURFACE_ID_LOADING);
// Draw to screen
if (!Flip_SystemTask(ghWnd))
{
ReleaseMutex(hMutex);
return 1;
}
// Initialize sound
InitDirectSound(hWnd);
// Initialize joystick
if (conf.bJoystick && InitDirectInput(hInstance, hWnd))
{
ResetJoystickStatus();
gbUseJoystick = TRUE;
}
// Initialize stuff
InitTextObject(conf.font_name);
InitTriangleTable();
// Run game code
Game(hWnd);
// End stuff
EndTextObject();
EndDirectSound();
EndDirectDraw(hWnd);
ReleaseMutex(hMutex);
return 1;
}
void InactiveWindow(void)
{
if (bActive)
{
bActive = FALSE;
StopOrganyaMusic();
SleepNoise();
}
PlaySoundObject(7, 0);
}
void ActiveWindow(void)
{
if (!bActive)
{
bActive = TRUE;
StopOrganyaMusic();
PlayOrganyaMusic();
ResetNoise();
}
PlaySoundObject(7, -1);
}
// Turns out you could drag-and-drop a save file onto the
// window to load it, but this behavior is dummied-out.
BOOL DragAndDropHandler(HWND hWnd, WPARAM wParam)
{
char path[MAX_PATH];
HDROP hDrop = (HDROP)wParam;
if (DragQueryFileA(hDrop, 0xFFFFFFFF, NULL, 0) != 0)
{
DragQueryFileA(hDrop, 0, path, sizeof(path));
LoadProfile(path);
}
DragFinish(hDrop);
return TRUE;
}
// TODO - Inaccurate stack frame
LRESULT CALLBACK WindowProcedure(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
{
BOOL window_focus;
HMENU hMenu;
switch (Msg)
{
case WM_CREATE:
hMenu = GetMenu(hWnd);
#ifdef DEBUG_SAVE
if (!CheckFileExists("save")) // Chances are a line like this used to exist
#endif
DeleteMenu(hMenu, 40005, MF_BYCOMMAND);
DrawMenuBar(hWnd);
hMenu = GetMenu(hWnd);
if (!IsKeyFile("mute"))
DeleteMenu(hMenu, 40007, MF_BYCOMMAND);
DrawMenuBar(hWnd);
if (IsKeyFile("fps"))
bFps = TRUE;
if (!bFullscreen)
LoadWindowRect(hWnd, "window.rect", FALSE);
SetWindowName(hWnd);
#ifdef DEBUG_SAVE
DragAcceptFiles(hWnd, TRUE);
#endif
break;
case WM_SYSCOMMAND:
switch (wParam)
{
case SC_MONITORPOWER:
break;
case SC_KEYMENU:
break;
case SC_SCREENSAVE:
break;
default:
DefWindowProcA(hWnd, Msg, wParam, lParam);
break;
}
break;
case WM_IME_NOTIFY:
if (wParam == IMN_SETOPENSTATUS)
{
HIMC hImc = ImmGetContext(hWnd);
ImmSetOpenStatus(hImc, 0);
ImmReleaseContext(hWnd, hImc);
}
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_ESCAPE:
gKey |= KEY_ESCAPE;
break;
case 'W':
gKey |= KEY_MAP;
break;
case VK_LEFT:
gKey |= KEY_LEFT;
break;
case VK_RIGHT:
gKey |= KEY_RIGHT;
break;
case VK_UP:
gKey |= KEY_UP;
break;
case VK_DOWN:
gKey |= KEY_DOWN;
break;
case 'X':
gKey |= KEY_X;
break;
case 'Z':
gKey |= KEY_Z;
break;
case 'S':
gKey |= KEY_ARMS;
break;
case 'A':
gKey |= KEY_ARMSREV;
break;
case VK_SHIFT:
gKey |= KEY_SHIFT;
break;
case VK_F1:
gKey |= KEY_F1;
break;
case VK_F2:
gKey |= KEY_F2;
break;
case 'Q':
gKey |= KEY_ITEM;
break;
case VK_OEM_COMMA:
gKey |= KEY_ALT_LEFT;
break;
case VK_OEM_PERIOD:
gKey |= KEY_ALT_DOWN;
break;
case VK_OEM_2:
gKey |= KEY_ALT_RIGHT;
break;
case 'L':
gKey |= KEY_L;
break;
case VK_OEM_PLUS:
gKey |= KEY_PLUS;
break;
case VK_F5:
gbUseJoystick = FALSE;
break;
}
break;
case WM_KEYUP:
switch (wParam)
{
case VK_ESCAPE:
gKey &= ~KEY_ESCAPE;
break;
case 'W':
gKey &= ~KEY_MAP;
break;
case VK_LEFT:
gKey &= ~KEY_LEFT;
break;
case VK_RIGHT:
gKey &= ~KEY_RIGHT;
break;
case VK_UP:
gKey &= ~KEY_UP;
break;
case VK_DOWN:
gKey &= ~KEY_DOWN;
break;
case 'X':
gKey &= ~KEY_X;
break;
case 'Z':
gKey &= ~KEY_Z;
break;
case 'S':
gKey &= ~KEY_ARMS;
break;
case 'A':
gKey &= ~KEY_ARMSREV;
break;
case VK_SHIFT:
gKey &= ~KEY_SHIFT;
break;
case VK_F1:
gKey &= ~KEY_F1;
break;
case VK_F2:
gKey &= ~KEY_F2;
break;
case 'Q':
gKey &= ~KEY_ITEM;
break;
case VK_OEM_COMMA:
gKey &= ~KEY_ALT_LEFT;
break;
case VK_OEM_PERIOD:
gKey &= ~KEY_ALT_DOWN;
break;
case VK_OEM_2:
gKey &= ~KEY_ALT_RIGHT;
break;
case 'L':
gKey &= ~KEY_L;
break;
case VK_OEM_PLUS:
gKey &= ~KEY_PLUS;
break;
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case 40001:
if (DialogBoxParamA(ghInstance, "DLG_YESNO", hWnd, QuitDialog, (LPARAM)"Quit?") == 1)
PostMessageA(hWnd, WM_CLOSE, 0, 0);
break;
case 40002:
DialogBoxParamA(ghInstance, "DLG_ABOUT", hWnd, VersionDialog, 0);
break;
case 40004:
if (!OpenSoundVolume(hWnd))
MessageBoxA(hWnd, "\x83\x7B\x83\x8A\x83\x85\x81\x5B\x83\x80\x90\xDD\x92\xE8\x82\xF0\x8B\x4E\x93\xAE\x82\xC5\x82\xAB\x82\xDC\x82\xB9\x82\xF1\x82\xC5\x82\xB5\x82\xBD", lpWindowName, 0); // 'ボリューム設定を起動できませんでした' (Could not launch volume configuration) in Shift-JIS
break;
case 40005:
DialogBoxParamA(ghInstance, "DLG_SAVE", hWnd, DebugSaveDialog, 0);
break;
case 40007:
DialogBoxParamA(ghInstance, "DLG_MUTE", hWnd, DebugMuteDialog, 0);
break;
}
break;
case WM_DROPFILES:
DragAndDropHandler(hWnd, wParam);
break;
case WM_ACTIVATE:
switch (LOWORD(wParam))
{
case WA_INACTIVE:
window_focus = FALSE;
break;
case WA_ACTIVE:
case WA_CLICKACTIVE:
if (HIWORD(wParam) != 0)
window_focus = FALSE;
else
window_focus = TRUE;
break;
}
if (window_focus)
ActiveWindow();
else
InactiveWindow();
break;
case WM_CLOSE:
StopOrganyaMusic();
PostQuitMessage(0);
break;
default:
return DefWindowProcA(hWnd, Msg, wParam, lParam);
}
return 1;
}
void JoystickProc(void);
BOOL SystemTask(void)
{
MSG Msg;
while (PeekMessageA(&Msg, NULL, 0, 0, PM_NOREMOVE) || !bActive)
{
if (!GetMessageA(&Msg, NULL, 0, 0))
return FALSE;
TranslateMessage(&Msg);
DispatchMessageA(&Msg);
}
// Run joystick code
if (gbUseJoystick)
JoystickProc();
return TRUE;
}
void JoystickProc(void)
{
int i;
JOYSTICK_STATUS status;
if (!GetJoystickStatus(&status))
return;
gKey &= (KEY_ESCAPE | KEY_F2 | KEY_F1);
// Set movement buttons
if (status.bLeft)
gKey |= gKeyLeft;
else
gKey &= ~gKeyLeft;
if (status.bRight)
gKey |= gKeyRight;
else
gKey &= ~gKeyRight;
if (status.bUp)
gKey |= gKeyUp;
else
gKey &= ~gKeyUp;
if (status.bDown)
gKey |= gKeyDown;
else
gKey &= ~gKeyDown;
// Clear held buttons
for (i = 0; i < 8; ++i)
gKey &= ~gJoystickButtonTable[i];
// Set held buttons
for (i = 0; i < 8; ++i)
if (status.bButton[i])
gKey |= gJoystickButtonTable[i];
}