2023-06-19 00:45:25 -04:00
|
|
|
#include <dsound.h>
|
2023-04-27 22:19:39 -04:00
|
|
|
|
2023-06-22 02:13:15 -04:00
|
|
|
#include "legoinc.h"
|
2023-04-27 22:19:39 -04:00
|
|
|
#include "define.h"
|
2023-06-22 02:13:15 -04:00
|
|
|
|
2023-05-05 05:54:17 -04:00
|
|
|
#include "legoomni.h"
|
2023-06-22 02:13:15 -04:00
|
|
|
#include "isle.h"
|
2023-04-27 22:19:39 -04:00
|
|
|
|
2023-06-18 23:28:18 -04:00
|
|
|
// OFFSET: ISLE 0x401ca0
|
2023-06-19 02:22:32 -04:00
|
|
|
BOOL FindExistingInstance(void)
|
2023-04-27 22:19:39 -04:00
|
|
|
{
|
|
|
|
HWND hWnd = FindWindowA(WNDCLASS_NAME, WINDOW_TITLE);
|
|
|
|
if (hWnd) {
|
|
|
|
if (SetForegroundWindow(hWnd)) {
|
|
|
|
ShowWindow(hWnd, SW_RESTORE);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2023-06-18 23:28:18 -04:00
|
|
|
// OFFSET: ISLE 0x401ce0
|
2023-06-19 02:22:32 -04:00
|
|
|
BOOL StartDirectSound(void)
|
2023-04-27 22:19:39 -04:00
|
|
|
{
|
2023-06-19 00:45:25 -04:00
|
|
|
LPDIRECTSOUND lpDS = NULL;
|
2023-04-27 22:19:39 -04:00
|
|
|
HRESULT ret = DirectSoundCreate(NULL, &lpDS, NULL);
|
|
|
|
if (ret == DS_OK && lpDS != NULL) {
|
|
|
|
lpDS->Release();
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2023-06-18 23:28:18 -04:00
|
|
|
// OFFSET: ISLE 0x401610
|
2023-04-27 22:19:39 -04:00
|
|
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
|
|
|
{
|
|
|
|
// Look for another instance, if we find one, bring it to the foreground instead
|
2023-06-19 04:12:12 -04:00
|
|
|
if (!FindExistingInstance()) {
|
2023-04-27 22:19:39 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to create DirectSound instance
|
|
|
|
BOOL soundReady = FALSE;
|
|
|
|
for (int i = 0; i < 20; i++) {
|
2023-06-19 04:12:12 -04:00
|
|
|
if (StartDirectSound()) {
|
2023-04-27 22:19:39 -04:00
|
|
|
soundReady = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Sleep(500);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Throw error if sound unavailable
|
|
|
|
if (!soundReady) {
|
2023-06-13 11:59:03 -04:00
|
|
|
MessageBoxA(NULL, "\"LEGO\xAE Island\" is not detecting a DirectSound compatible sound card. Please quit all other applications and try again.",
|
2023-06-19 00:45:25 -04:00
|
|
|
"Lego Island Error", MB_OK);
|
2023-04-27 22:19:39 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create global app instance
|
|
|
|
g_isle = new Isle();
|
|
|
|
|
|
|
|
// Create window
|
2023-06-23 14:45:25 -04:00
|
|
|
if (g_isle->SetupWindow(hInstance, lpCmdLine) != SUCCESS) {
|
2023-06-19 00:45:25 -04:00
|
|
|
MessageBoxA(NULL, "\"LEGO\xAE Island\" failed to start. Please quit all other applications and try again.", "LEGO\xAE Island Error", MB_OK);
|
2023-04-27 22:19:39 -04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get reference to window
|
|
|
|
HWND window;
|
|
|
|
if (g_isle->m_windowHandle) {
|
|
|
|
window = g_isle->m_windowHandle;
|
|
|
|
}
|
|
|
|
|
2023-06-19 04:21:51 -04:00
|
|
|
// Load accelerators (this call actually achieves nothing - there is no "AppAccel" resource in the original - but we'll keep this for authenticity)
|
|
|
|
// This line may actually be here because it's in DFVIEW, an example project that ships with
|
|
|
|
// MSVC420, and was such a clean example of a Win32 app, that it was later adapted
|
|
|
|
// into an "ExeSkeleton" sample for MSVC600. It's quite possible Mindscape derived
|
|
|
|
// this app from that example since they no longer had the luxury of the
|
|
|
|
// MFC AppWizard which we know they used for the frontend used during development (ISLEMFC.EXE, MAIN.EXE, et al.)
|
2023-04-27 22:19:39 -04:00
|
|
|
LoadAcceleratorsA(hInstance, "AppAccel");
|
|
|
|
|
|
|
|
MSG msg;
|
|
|
|
|
|
|
|
while (!g_closed) {
|
|
|
|
while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
|
|
|
if (g_isle) {
|
2023-06-19 00:51:06 -04:00
|
|
|
g_isle->Tick(1);
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_isle) {
|
2023-06-23 14:45:25 -04:00
|
|
|
g_isle->Tick(0);
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
2023-06-23 14:45:25 -04:00
|
|
|
while (!g_closed) {
|
2023-04-27 22:19:39 -04:00
|
|
|
if (!PeekMessageA(&msg, NULL, 0, 0, PM_REMOVE)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
MSG nextMsg;
|
|
|
|
if (!g_isle
|
|
|
|
|| !g_isle->m_windowHandle
|
|
|
|
|| msg.message != WM_MOUSEMOVE
|
|
|
|
|| !PeekMessageA(&nextMsg, NULL, 0, 0, PM_NOREMOVE)
|
|
|
|
|| nextMsg.message != WM_MOUSEMOVE) {
|
|
|
|
TranslateMessage(&msg);
|
|
|
|
DispatchMessageA(&msg);
|
|
|
|
}
|
|
|
|
|
2023-06-11 01:11:05 -04:00
|
|
|
if (g_reqEnableRMDevice) {
|
|
|
|
g_reqEnableRMDevice = 0;
|
2023-04-27 22:19:39 -04:00
|
|
|
VideoManager()->EnableRMDevice();
|
2023-06-11 01:11:05 -04:00
|
|
|
g_rmDisabled = 0;
|
2023-04-27 22:19:39 -04:00
|
|
|
Lego()->vtable3c();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_closed) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_mousedown == 0) {
|
|
|
|
LAB_00401bc7:
|
|
|
|
if (g_mousemoved) {
|
|
|
|
g_mousemoved = FALSE;
|
|
|
|
}
|
|
|
|
} else if (g_mousemoved) {
|
|
|
|
if (g_isle) {
|
2023-06-19 00:51:06 -04:00
|
|
|
g_isle->Tick(0);
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
goto LAB_00401bc7;
|
|
|
|
}
|
2023-06-23 14:45:25 -04:00
|
|
|
}
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
DestroyWindow(window);
|
|
|
|
|
|
|
|
return msg.wParam;
|
|
|
|
}
|
2023-06-23 14:45:25 -04:00
|
|
|
|
|
|
|
// OFFSET: ISLE 0x401d20
|
|
|
|
LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
|
|
|
if (!g_isle) {
|
|
|
|
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (uMsg) {
|
|
|
|
case WM_PAINT:
|
|
|
|
return DefWindowProcA(hWnd, WM_PAINT, wParam, lParam);
|
|
|
|
case WM_ACTIVATE:
|
|
|
|
return DefWindowProcA(hWnd, WM_ACTIVATE, wParam, lParam);
|
|
|
|
case WM_ACTIVATEAPP:
|
|
|
|
if (g_isle) {
|
|
|
|
if ((wParam != 0) && (g_isle->m_fullScreen)) {
|
|
|
|
MoveWindow(hWnd, g_windowRect.left, g_windowRect.top,
|
|
|
|
(g_windowRect.right - g_windowRect.left) + 1,
|
|
|
|
(g_windowRect.bottom - g_windowRect.top) + 1, TRUE);
|
|
|
|
}
|
|
|
|
g_isle->m_windowActive = wParam;
|
|
|
|
}
|
|
|
|
return DefWindowProcA(hWnd,WM_ACTIVATEAPP,wParam,lParam);
|
|
|
|
case WM_CLOSE:
|
|
|
|
if (!g_closed && g_isle) {
|
|
|
|
if (g_isle) {
|
|
|
|
delete g_isle;
|
|
|
|
}
|
|
|
|
g_isle = NULL;
|
|
|
|
g_closed = TRUE;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return DefWindowProcA(hWnd,WM_CLOSE,wParam,lParam);
|
|
|
|
case WM_GETMINMAXINFO:
|
|
|
|
{
|
|
|
|
MINMAXINFO *mmi = (MINMAXINFO *) lParam;
|
|
|
|
|
|
|
|
mmi->ptMaxTrackSize.x = (g_windowRect.right - g_windowRect.left) + 1;
|
|
|
|
mmi->ptMaxTrackSize.y = (g_windowRect.bottom - g_windowRect.top) + 1;
|
|
|
|
mmi->ptMinTrackSize.x = (g_windowRect.right - g_windowRect.left) + 1;
|
|
|
|
mmi->ptMinTrackSize.y = (g_windowRect.bottom - g_windowRect.top) + 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
case WM_ENTERMENULOOP:
|
|
|
|
return DefWindowProcA(hWnd,WM_ENTERMENULOOP,wParam,lParam);
|
|
|
|
case WM_SYSCOMMAND:
|
|
|
|
if (wParam == SC_SCREENSAVE) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (wParam == SC_CLOSE && g_closed == 0) {
|
|
|
|
if (g_isle) {
|
|
|
|
if (g_rmDisabled) {
|
|
|
|
ShowWindow(g_isle->m_windowHandle, SW_RESTORE);
|
|
|
|
}
|
|
|
|
PostMessageA(g_isle->m_windowHandle, WM_CLOSE, 0, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
} else if (g_isle && g_isle->m_fullScreen && (wParam == SC_MOVE || wParam == SC_KEYMENU)) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return DefWindowProcA(hWnd,WM_SYSCOMMAND,wParam,lParam);
|
|
|
|
case WM_EXITMENULOOP:
|
|
|
|
return DefWindowProcA(hWnd, WM_EXITMENULOOP, wParam, lParam);
|
|
|
|
case WM_MOVING:
|
|
|
|
if (g_isle && g_isle->m_fullScreen) {
|
|
|
|
GetWindowRect(hWnd, (LPRECT) lParam);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return DefWindowProcA(hWnd, WM_MOVING, wParam, lParam);
|
|
|
|
case WM_NCPAINT:
|
|
|
|
if (g_isle && g_isle->m_fullScreen) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return DefWindowProcA(hWnd, WM_NCPAINT, wParam, lParam);
|
|
|
|
case WM_DISPLAYCHANGE:
|
|
|
|
if (g_isle && VideoManager() && g_isle->m_fullScreen && VideoManager()->m_unk74 && VideoManager()->m_unk74[0x220]) {
|
|
|
|
if (!g_waitingForTargetDepth) {
|
|
|
|
unsigned char valid = FALSE;
|
|
|
|
if (LOWORD(lParam) == g_targetWidth && HIWORD(lParam) == g_targetHeight && g_targetDepth == wParam) {
|
|
|
|
valid = TRUE;
|
|
|
|
}
|
|
|
|
if (!g_rmDisabled) {
|
|
|
|
if (!valid) {
|
|
|
|
g_rmDisabled = 1;
|
|
|
|
Lego()->vtable38();
|
|
|
|
VideoManager()->DisableRMDevice();
|
|
|
|
}
|
|
|
|
} else if (valid) {
|
|
|
|
g_reqEnableRMDevice = 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
g_waitingForTargetDepth = 0;
|
|
|
|
g_targetDepth = wParam;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return DefWindowProcA(hWnd, WM_DISPLAYCHANGE, wParam, lParam);
|
|
|
|
case WM_SETCURSOR:
|
|
|
|
case WM_KEYDOWN:
|
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
case WM_TIMER:
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
case 0x5400:
|
|
|
|
{
|
|
|
|
|
|
|
|
NotificationId type = NONE;
|
|
|
|
unsigned char keyCode = 0;
|
|
|
|
|
|
|
|
switch (uMsg) {
|
|
|
|
case WM_KEYDOWN:
|
|
|
|
// While this probably should be (HIWORD(lParam) & KF_REPEAT), this seems
|
|
|
|
// to be what the assembly is actually doing
|
|
|
|
if (lParam & (KF_REPEAT << 16)) {
|
|
|
|
return DefWindowProcA(hWnd, WM_KEYDOWN, wParam, lParam);
|
|
|
|
}
|
|
|
|
keyCode = wParam;
|
|
|
|
type = KEYDOWN;
|
|
|
|
break;
|
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
g_mousemoved = 1;
|
|
|
|
type = MOUSEMOVE;
|
|
|
|
break;
|
|
|
|
case WM_TIMER:
|
|
|
|
type = TIMER;
|
|
|
|
break;
|
|
|
|
case WM_SETCURSOR:
|
|
|
|
if (g_isle) {
|
|
|
|
HCURSOR hCursor = g_isle->m_cursorCurrent;
|
|
|
|
if (hCursor == g_isle->m_cursorBusy || hCursor == g_isle->m_cursorNo || !hCursor) {
|
|
|
|
SetCursor(hCursor);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
g_mousedown = 1;
|
|
|
|
type = MOUSEDOWN;
|
|
|
|
break;
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
g_mousedown = 0;
|
|
|
|
type = MOUSEUP;
|
|
|
|
break;
|
|
|
|
case 0x5400:
|
|
|
|
if (g_isle) {
|
|
|
|
g_isle->SetupCursor(wParam);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_isle) {
|
|
|
|
if (InputManager()) {
|
|
|
|
InputManager()->QueueEvent(type, wParam, LOWORD(lParam), HIWORD(lParam), keyCode);
|
|
|
|
}
|
|
|
|
if (g_isle && g_isle->m_drawCursor && type == MOUSEMOVE) {
|
|
|
|
unsigned short x = LOWORD(lParam);
|
|
|
|
unsigned short y = HIWORD(lParam);
|
|
|
|
if (639 < x) {
|
|
|
|
x = 639;
|
|
|
|
}
|
|
|
|
if (479 < y) {
|
|
|
|
y = 479;
|
|
|
|
}
|
|
|
|
VideoManager()->MoveCursor(x,y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return DefWindowProcA(hWnd,uMsg,wParam,lParam);
|
|
|
|
}
|