2023-06-29 04:10:08 -04:00
|
|
|
#include "isleapp.h"
|
2023-06-27 16:07:29 -04:00
|
|
|
|
2023-10-24 19:38:27 -04:00
|
|
|
#include "define.h"
|
2023-06-27 16:07:29 -04:00
|
|
|
#include "legoanimationmanager.h"
|
|
|
|
#include "legobuildingmanager.h"
|
2023-10-07 11:30:04 -04:00
|
|
|
#include "legogamestate.h"
|
|
|
|
#include "legoinputmanager.h"
|
2023-06-27 16:07:29 -04:00
|
|
|
#include "legomodelpresenter.h"
|
2023-10-07 11:30:04 -04:00
|
|
|
#include "legoomni.h"
|
2023-06-27 16:07:29 -04:00
|
|
|
#include "legopartpresenter.h"
|
2023-10-07 11:30:04 -04:00
|
|
|
#include "legoroi.h"
|
|
|
|
#include "legovideomanager.h"
|
2023-06-27 16:07:29 -04:00
|
|
|
#include "legoworldpresenter.h"
|
2023-10-07 11:30:04 -04:00
|
|
|
#include "mxbackgroundaudiomanager.h"
|
2023-06-27 16:07:29 -04:00
|
|
|
#include "mxdirectdraw.h"
|
|
|
|
#include "mxdsaction.h"
|
2023-10-07 11:30:04 -04:00
|
|
|
#include "mxomnicreateflags.h"
|
|
|
|
#include "mxomnicreateparam.h"
|
|
|
|
#include "mxstreamer.h"
|
|
|
|
#include "mxticklemanager.h"
|
|
|
|
#include "mxtimer.h"
|
|
|
|
#include "mxtransitionmanager.h"
|
2023-06-27 16:07:29 -04:00
|
|
|
#include "res/resource.h"
|
2023-04-27 22:19:39 -04:00
|
|
|
|
2023-10-24 19:38:27 -04:00
|
|
|
#include <dsound.h>
|
|
|
|
|
2023-12-09 12:49:13 -05:00
|
|
|
// Might be static functions of IsleApp
|
|
|
|
BOOL FindExistingInstance(void);
|
|
|
|
BOOL StartDirectSound(void);
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x401000
|
2023-06-27 20:10:11 -04:00
|
|
|
IsleApp::IsleApp()
|
2023-04-27 22:19:39 -04:00
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
m_hdPath = NULL;
|
|
|
|
m_cdPath = NULL;
|
|
|
|
m_deviceId = NULL;
|
|
|
|
m_savePath = NULL;
|
|
|
|
m_fullScreen = 1;
|
|
|
|
m_flipSurfaces = 0;
|
|
|
|
m_backBuffersInVram = 1;
|
|
|
|
m_using8bit = 0;
|
|
|
|
m_using16bit = 1;
|
2023-12-13 05:48:14 -05:00
|
|
|
m_unk0x24 = 0;
|
2023-10-24 19:38:27 -04:00
|
|
|
m_drawCursor = 0;
|
|
|
|
m_use3dSound = 1;
|
|
|
|
m_useMusic = 1;
|
|
|
|
m_useJoystick = 0;
|
|
|
|
m_joystickIndex = 0;
|
|
|
|
m_wideViewAngle = 1;
|
|
|
|
m_islandQuality = 1;
|
|
|
|
m_islandTexture = 1;
|
|
|
|
m_gameStarted = 0;
|
|
|
|
m_frameDelta = 10;
|
|
|
|
m_windowActive = 1;
|
|
|
|
|
|
|
|
m_videoParam = MxVideoParam(MxRect32(0, 0, 639, 479), NULL, 1, MxVideoParamFlags());
|
2023-12-13 05:48:14 -05:00
|
|
|
m_videoParam.Flags().Set16Bit(MxDirectDraw::GetPrimaryBitDepth() == 16);
|
2023-10-24 19:38:27 -04:00
|
|
|
|
|
|
|
m_windowHandle = NULL;
|
|
|
|
m_cursorArrow = NULL;
|
|
|
|
m_cursorBusy = NULL;
|
|
|
|
m_cursorNo = NULL;
|
|
|
|
m_cursorCurrent = NULL;
|
|
|
|
|
|
|
|
LegoOmni::CreateInstance();
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x4011a0
|
2023-06-27 20:10:11 -04:00
|
|
|
IsleApp::~IsleApp()
|
2023-04-27 22:19:39 -04:00
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
if (LegoOmni::GetInstance()) {
|
|
|
|
Close();
|
|
|
|
MxOmni::DestroyInstance();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_hdPath) {
|
|
|
|
delete[] m_hdPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_cdPath) {
|
|
|
|
delete[] m_cdPath;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_deviceId) {
|
|
|
|
delete[] m_deviceId;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_savePath) {
|
|
|
|
delete[] m_savePath;
|
|
|
|
}
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x401260
|
2023-06-27 20:10:11 -04:00
|
|
|
void IsleApp::Close()
|
2023-04-27 22:19:39 -04:00
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
MxDSAction ds;
|
|
|
|
ds.SetUnknown24(-2);
|
|
|
|
|
|
|
|
if (Lego()) {
|
|
|
|
GameState()->Save(0);
|
|
|
|
if (InputManager()) {
|
2023-11-07 03:30:26 -05:00
|
|
|
InputManager()->QueueEvent(c_notificationKeyPress, 0, 0, 0, 0x20);
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
VideoManager()->Get3DManager()->GetLego3DView()->GetViewManager()->RemoveAll(NULL);
|
|
|
|
|
|
|
|
Lego()->RemoveWorld(ds.GetAtomId(), ds.GetObjectId());
|
|
|
|
Lego()->DeleteObject(ds);
|
|
|
|
TransitionManager()->SetWaitIndicator(NULL);
|
|
|
|
Lego()->StopTimer();
|
|
|
|
|
|
|
|
MxLong lVar8;
|
|
|
|
do {
|
|
|
|
lVar8 = Streamer()->Close(NULL);
|
|
|
|
} while (lVar8 == 0);
|
|
|
|
|
|
|
|
while (Lego()) {
|
|
|
|
if (Lego()->DoesEntityExist(ds)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Timer()->GetRealTime();
|
|
|
|
TickleManager()->Tickle();
|
|
|
|
}
|
|
|
|
}
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x4013b0
|
2023-06-27 20:10:11 -04:00
|
|
|
BOOL IsleApp::SetupLegoOmni()
|
2023-06-27 16:07:29 -04:00
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
BOOL result = FALSE;
|
|
|
|
char mediaPath[256];
|
|
|
|
GetProfileStringA("LEGO Island", "MediaPath", "", mediaPath, sizeof(mediaPath));
|
|
|
|
|
|
|
|
BOOL failure =
|
|
|
|
Lego()->Create(MxOmniCreateParam(mediaPath, (struct HWND__*) m_windowHandle, m_videoParam, MxOmniCreateFlags())
|
|
|
|
) == FAILURE;
|
|
|
|
if (!failure) {
|
|
|
|
VariableTable()->SetVariable("ACTOR_01", "");
|
|
|
|
TickleManager()->SetClientTickleInterval(VideoManager(), 10);
|
|
|
|
result = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
2023-06-27 16:07:29 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x401560
|
2023-10-24 19:38:27 -04:00
|
|
|
void IsleApp::SetupVideoFlags(
|
|
|
|
BOOL fullScreen,
|
|
|
|
BOOL flipSurfaces,
|
|
|
|
BOOL backBuffers,
|
|
|
|
BOOL using8bit,
|
|
|
|
BOOL using16bit,
|
|
|
|
BOOL param_6,
|
|
|
|
BOOL param_7,
|
|
|
|
BOOL wideViewAngle,
|
|
|
|
char* deviceId
|
|
|
|
)
|
2023-06-27 16:07:29 -04:00
|
|
|
{
|
2023-12-13 05:48:14 -05:00
|
|
|
m_videoParam.Flags().SetFullScreen(fullScreen);
|
|
|
|
m_videoParam.Flags().SetFlipSurfaces(flipSurfaces);
|
|
|
|
m_videoParam.Flags().SetBackBuffers(!backBuffers);
|
|
|
|
m_videoParam.Flags().SetF2bit0(!param_6);
|
|
|
|
m_videoParam.Flags().SetF1bit7(param_7);
|
|
|
|
m_videoParam.Flags().SetWideViewAngle(wideViewAngle);
|
|
|
|
m_videoParam.Flags().SetF2bit1(1);
|
2023-10-24 19:38:27 -04:00
|
|
|
m_videoParam.SetDeviceName(deviceId);
|
|
|
|
if (using8bit) {
|
2023-12-13 05:48:14 -05:00
|
|
|
m_videoParam.Flags().Set16Bit(0);
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
|
|
|
if (using16bit) {
|
2023-12-13 05:48:14 -05:00
|
|
|
m_videoParam.Flags().Set16Bit(1);
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
2023-06-27 16:07:29 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x401610
|
2023-06-27 16:07:29 -04:00
|
|
|
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
|
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
// Look for another instance, if we find one, bring it to the foreground instead
|
|
|
|
if (!FindExistingInstance()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Attempt to create DirectSound instance
|
|
|
|
BOOL soundReady = FALSE;
|
|
|
|
for (int i = 0; i < 20; i++) {
|
|
|
|
if (StartDirectSound()) {
|
|
|
|
soundReady = TRUE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
Sleep(500);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Throw error if sound unavailable
|
|
|
|
if (!soundReady) {
|
|
|
|
MessageBoxA(
|
|
|
|
NULL,
|
|
|
|
"\"LEGO\xAE Island\" is not detecting a DirectSound compatible sound card. Please quit all other "
|
|
|
|
"applications and try again.",
|
|
|
|
"Lego Island Error",
|
|
|
|
MB_OK
|
|
|
|
);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create global app instance
|
|
|
|
g_isle = new IsleApp();
|
|
|
|
|
|
|
|
// Create window
|
|
|
|
if (g_isle->SetupWindow(hInstance, lpCmdLine) != SUCCESS) {
|
|
|
|
MessageBoxA(
|
|
|
|
NULL,
|
|
|
|
"\"LEGO\xAE Island\" failed to start. Please quit all other applications and try again.",
|
|
|
|
"LEGO\xAE Island Error",
|
|
|
|
MB_OK
|
|
|
|
);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get reference to window
|
|
|
|
HWND window;
|
|
|
|
if (g_isle->m_windowHandle) {
|
|
|
|
window = g_isle->m_windowHandle;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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.)
|
|
|
|
LoadAcceleratorsA(hInstance, "AppAccel");
|
|
|
|
|
|
|
|
MSG msg;
|
|
|
|
|
|
|
|
while (!g_closed) {
|
|
|
|
while (!PeekMessageA(&msg, NULL, 0, 0, PM_NOREMOVE)) {
|
|
|
|
if (g_isle) {
|
|
|
|
g_isle->Tick(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_isle) {
|
|
|
|
g_isle->Tick(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (!g_closed) {
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_reqEnableRMDevice) {
|
|
|
|
g_reqEnableRMDevice = 0;
|
|
|
|
VideoManager()->EnableRMDevice();
|
|
|
|
g_rmDisabled = 0;
|
|
|
|
Lego()->StopTimer();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_closed) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_mousedown && g_mousemoved && g_isle) {
|
|
|
|
g_isle->Tick(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_mousemoved) {
|
|
|
|
g_mousemoved = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
DestroyWindow(window);
|
|
|
|
|
|
|
|
return msg.wParam;
|
2023-06-27 16:07:29 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x401ca0
|
2023-06-27 16:07:29 -04:00
|
|
|
BOOL FindExistingInstance(void)
|
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
HWND hWnd = FindWindowA(WNDCLASS_NAME, WINDOW_TITLE);
|
|
|
|
if (hWnd) {
|
|
|
|
if (SetForegroundWindow(hWnd)) {
|
|
|
|
ShowWindow(hWnd, SW_RESTORE);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
2023-06-27 16:07:29 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x401ce0
|
2023-06-27 16:07:29 -04:00
|
|
|
BOOL StartDirectSound(void)
|
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
LPDIRECTSOUND lpDS = NULL;
|
|
|
|
HRESULT ret = DirectSoundCreate(NULL, &lpDS, NULL);
|
|
|
|
if (ret == DS_OK && lpDS != NULL) {
|
|
|
|
lpDS->Release();
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
2023-06-27 16:07:29 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x401d20
|
2023-06-27 16:07:29 -04:00
|
|
|
LRESULT WINAPI WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
NotificationId type;
|
|
|
|
unsigned char keyCode = 0;
|
|
|
|
|
|
|
|
if (!g_isle) {
|
|
|
|
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (uMsg) {
|
|
|
|
case WM_PAINT:
|
|
|
|
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
|
|
|
|
case WM_ACTIVATE:
|
|
|
|
return DefWindowProcA(hWnd, uMsg, 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, uMsg, 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, uMsg, wParam, lParam);
|
|
|
|
case WM_GETMINMAXINFO:
|
|
|
|
((MINMAXINFO*) lParam)->ptMaxTrackSize.x = (g_windowRect.right - g_windowRect.left) + 1;
|
|
|
|
((MINMAXINFO*) lParam)->ptMaxTrackSize.y = (g_windowRect.bottom - g_windowRect.top) + 1;
|
|
|
|
((MINMAXINFO*) lParam)->ptMinTrackSize.x = (g_windowRect.right - g_windowRect.left) + 1;
|
|
|
|
((MINMAXINFO*) lParam)->ptMinTrackSize.y = (g_windowRect.bottom - g_windowRect.top) + 1;
|
|
|
|
return 0;
|
|
|
|
case WM_ENTERMENULOOP:
|
|
|
|
return DefWindowProcA(hWnd, uMsg, 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, uMsg, wParam, lParam);
|
|
|
|
case WM_EXITMENULOOP:
|
|
|
|
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
|
|
|
|
case WM_MOVING:
|
|
|
|
if (g_isle && g_isle->m_fullScreen) {
|
|
|
|
GetWindowRect(hWnd, (LPRECT) lParam);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
|
|
|
|
case WM_NCPAINT:
|
|
|
|
if (g_isle && g_isle->m_fullScreen) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
|
|
|
|
case WM_DISPLAYCHANGE:
|
2023-12-09 12:49:13 -05:00
|
|
|
if (g_isle && VideoManager() && g_isle->m_fullScreen && VideoManager()->GetDirect3D()) {
|
|
|
|
if (VideoManager()->GetDirect3D()->GetDeviceModeFinder()) {
|
|
|
|
int targetDepth = wParam;
|
|
|
|
int targetWidth = LOWORD(lParam);
|
|
|
|
int targetHeight = HIWORD(lParam);
|
|
|
|
|
|
|
|
if (g_waitingForTargetDepth) {
|
|
|
|
g_waitingForTargetDepth = 0;
|
|
|
|
g_targetDepth = targetDepth;
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
2023-12-09 12:49:13 -05:00
|
|
|
else {
|
|
|
|
BOOL valid = FALSE;
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2023-12-09 12:49:13 -05:00
|
|
|
if (g_targetWidth == targetWidth && g_targetHeight == targetHeight &&
|
|
|
|
g_targetDepth == targetDepth) {
|
|
|
|
valid = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_rmDisabled) {
|
|
|
|
if (valid) {
|
|
|
|
g_reqEnableRMDevice = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!valid) {
|
|
|
|
g_rmDisabled = 1;
|
|
|
|
Lego()->StartTimer();
|
|
|
|
VideoManager()->DisableRMDevice();
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
|
|
|
|
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, uMsg, wParam, lParam);
|
|
|
|
}
|
2023-11-07 03:30:26 -05:00
|
|
|
type = c_notificationKeyPress;
|
2023-12-09 12:49:13 -05:00
|
|
|
keyCode = wParam;
|
2023-10-24 19:38:27 -04:00
|
|
|
break;
|
|
|
|
case WM_MOUSEMOVE:
|
|
|
|
g_mousemoved = 1;
|
2023-11-07 03:30:26 -05:00
|
|
|
type = c_notificationMouseMove;
|
2023-10-24 19:38:27 -04:00
|
|
|
break;
|
|
|
|
case WM_TIMER:
|
2023-11-07 03:30:26 -05:00
|
|
|
type = c_notificationTimer;
|
2023-10-24 19:38:27 -04:00
|
|
|
break;
|
|
|
|
case WM_LBUTTONDOWN:
|
|
|
|
g_mousedown = 1;
|
2023-11-07 03:30:26 -05:00
|
|
|
type = c_notificationButtonDown;
|
2023-10-24 19:38:27 -04:00
|
|
|
break;
|
|
|
|
case WM_LBUTTONUP:
|
|
|
|
g_mousedown = 0;
|
2023-11-07 03:30:26 -05:00
|
|
|
type = c_notificationButtonUp;
|
2023-10-24 19:38:27 -04:00
|
|
|
break;
|
|
|
|
case 0x5400:
|
|
|
|
if (g_isle) {
|
|
|
|
g_isle->SetupCursor(wParam);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
2023-12-09 12:49:13 -05:00
|
|
|
case WM_SETCURSOR:
|
|
|
|
if (g_isle && (g_isle->m_cursorCurrent == g_isle->m_cursorBusy ||
|
|
|
|
g_isle->m_cursorCurrent == g_isle->m_cursorNo || !g_isle->m_cursorCurrent)) {
|
|
|
|
SetCursor(g_isle->m_cursorCurrent);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
2023-10-24 19:38:27 -04:00
|
|
|
default:
|
|
|
|
return DefWindowProcA(hWnd, uMsg, wParam, lParam);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_isle) {
|
|
|
|
if (InputManager()) {
|
|
|
|
InputManager()->QueueEvent(type, wParam, LOWORD(lParam), HIWORD(lParam), keyCode);
|
|
|
|
}
|
2023-11-07 03:30:26 -05:00
|
|
|
if (g_isle && g_isle->m_drawCursor && type == c_notificationMouseMove) {
|
2023-10-24 19:38:27 -04:00
|
|
|
int x = LOWORD(lParam);
|
|
|
|
int y = HIWORD(lParam);
|
|
|
|
if (x >= 640) {
|
|
|
|
x = 639;
|
|
|
|
}
|
|
|
|
if (y >= 480) {
|
|
|
|
y = 479;
|
|
|
|
}
|
|
|
|
VideoManager()->MoveCursor(x, y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
2023-06-27 16:07:29 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x4023e0
|
2023-06-27 20:10:11 -04:00
|
|
|
MxResult IsleApp::SetupWindow(HINSTANCE hInstance, LPSTR lpCmdLine)
|
2023-06-27 16:07:29 -04:00
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
WNDCLASSA wndclass;
|
|
|
|
ZeroMemory(&wndclass, sizeof(WNDCLASSA));
|
|
|
|
|
|
|
|
LoadConfig();
|
|
|
|
|
|
|
|
SetupVideoFlags(
|
|
|
|
m_fullScreen,
|
|
|
|
m_flipSurfaces,
|
|
|
|
m_backBuffersInVram,
|
|
|
|
m_using8bit,
|
|
|
|
m_using16bit,
|
2023-12-13 05:48:14 -05:00
|
|
|
m_unk0x24,
|
2023-10-24 19:38:27 -04:00
|
|
|
FALSE,
|
|
|
|
m_wideViewAngle,
|
|
|
|
m_deviceId
|
|
|
|
);
|
|
|
|
|
|
|
|
MxOmni::SetSound3D(m_use3dSound);
|
|
|
|
|
|
|
|
srand(timeGetTime() / 1000);
|
|
|
|
SystemParametersInfoA(SPI_SETMOUSETRAILS, 0, NULL, 0);
|
|
|
|
|
|
|
|
ZeroMemory(&wndclass, sizeof(WNDCLASSA));
|
|
|
|
|
|
|
|
wndclass.cbClsExtra = 0;
|
|
|
|
wndclass.style = CS_HREDRAW | CS_VREDRAW;
|
|
|
|
wndclass.lpfnWndProc = WndProc;
|
|
|
|
wndclass.cbWndExtra = 0;
|
|
|
|
wndclass.hIcon = LoadIconA(hInstance, MAKEINTRESOURCEA(APP_ICON));
|
|
|
|
wndclass.hCursor = m_cursorArrow = m_cursorCurrent = LoadCursorA(hInstance, MAKEINTRESOURCEA(ISLE_ARROW));
|
|
|
|
m_cursorBusy = LoadCursorA(hInstance, MAKEINTRESOURCEA(ISLE_BUSY));
|
|
|
|
m_cursorNo = LoadCursorA(hInstance, MAKEINTRESOURCEA(ISLE_NO));
|
|
|
|
wndclass.hInstance = hInstance;
|
|
|
|
wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
|
|
|
|
wndclass.lpszClassName = WNDCLASS_NAME;
|
|
|
|
|
|
|
|
if (!RegisterClassA(&wndclass)) {
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_fullScreen) {
|
|
|
|
AdjustWindowRectEx(&g_windowRect, WS_CAPTION | WS_SYSMENU, 0, WS_EX_APPWINDOW);
|
|
|
|
|
|
|
|
m_windowHandle = CreateWindowExA(
|
|
|
|
WS_EX_APPWINDOW,
|
|
|
|
WNDCLASS_NAME,
|
|
|
|
WINDOW_TITLE,
|
|
|
|
WS_CAPTION | WS_SYSMENU,
|
|
|
|
g_windowRect.left,
|
|
|
|
g_windowRect.top,
|
|
|
|
g_windowRect.right - g_windowRect.left + 1,
|
|
|
|
g_windowRect.bottom - g_windowRect.top + 1,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
hInstance,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
AdjustWindowRectEx(&g_windowRect, WS_CAPTION | WS_SYSMENU, 0, WS_EX_APPWINDOW);
|
|
|
|
|
|
|
|
m_windowHandle = CreateWindowExA(
|
|
|
|
WS_EX_APPWINDOW,
|
|
|
|
WNDCLASS_NAME,
|
|
|
|
WINDOW_TITLE,
|
|
|
|
WS_CAPTION | WS_SYSMENU | WS_MAXIMIZEBOX | WS_MINIMIZEBOX,
|
|
|
|
CW_USEDEFAULT,
|
|
|
|
CW_USEDEFAULT,
|
|
|
|
g_windowRect.right - g_windowRect.left + 1,
|
|
|
|
g_windowRect.bottom - g_windowRect.top + 1,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
hInstance,
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_windowHandle) {
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_fullScreen) {
|
|
|
|
MoveWindow(
|
|
|
|
m_windowHandle,
|
|
|
|
g_windowRect.left,
|
|
|
|
g_windowRect.top,
|
|
|
|
(g_windowRect.right - g_windowRect.left) + 1,
|
|
|
|
(g_windowRect.bottom - g_windowRect.top) + 1,
|
|
|
|
TRUE
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
ShowWindow(m_windowHandle, SW_SHOWNORMAL);
|
|
|
|
UpdateWindow(m_windowHandle);
|
|
|
|
if (!SetupLegoOmni()) {
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GameState()->SetSavePath(m_savePath);
|
|
|
|
GameState()->SerializePlayersInfo(1);
|
|
|
|
GameState()->SerializeScoreHistory(1);
|
|
|
|
|
|
|
|
int iVar10;
|
|
|
|
switch (m_islandQuality) {
|
|
|
|
case 0:
|
|
|
|
iVar10 = 1;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
iVar10 = 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
iVar10 = 100;
|
|
|
|
}
|
|
|
|
|
|
|
|
int uVar1 = (m_islandTexture == 0);
|
|
|
|
LegoModelPresenter::configureLegoModelPresenter(uVar1);
|
|
|
|
LegoPartPresenter::configureLegoPartPresenter(uVar1, iVar10);
|
|
|
|
LegoWorldPresenter::configureLegoWorldPresenter(m_islandQuality);
|
|
|
|
LegoBuildingManager::configureLegoBuildingManager(m_islandQuality);
|
|
|
|
LegoROI::configureLegoROI(iVar10);
|
|
|
|
LegoAnimationManager::configureLegoAnimationManager(m_islandQuality);
|
|
|
|
if (LegoOmni::GetInstance()) {
|
|
|
|
if (LegoOmni::GetInstance()->GetInputManager()) {
|
|
|
|
LegoOmni::GetInstance()->GetInputManager()->m_useJoystick = m_useJoystick;
|
|
|
|
LegoOmni::GetInstance()->GetInputManager()->m_joystickIndex = m_joystickIndex;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m_fullScreen) {
|
|
|
|
MoveWindow(
|
|
|
|
m_windowHandle,
|
|
|
|
g_windowRect.left,
|
|
|
|
g_windowRect.top,
|
|
|
|
(g_windowRect.right - g_windowRect.left) + 1,
|
|
|
|
(g_windowRect.bottom - g_windowRect.top) + 1,
|
|
|
|
TRUE
|
|
|
|
);
|
|
|
|
}
|
|
|
|
ShowWindow(m_windowHandle, SW_SHOWNORMAL);
|
|
|
|
UpdateWindow(m_windowHandle);
|
|
|
|
|
|
|
|
return SUCCESS;
|
2023-06-27 16:07:29 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x402740
|
2023-06-27 20:10:11 -04:00
|
|
|
BOOL IsleApp::ReadReg(LPCSTR name, LPSTR outValue, DWORD outSize)
|
2023-04-27 22:19:39 -04:00
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
HKEY hKey;
|
|
|
|
DWORD valueType;
|
|
|
|
|
|
|
|
BOOL out = FALSE;
|
|
|
|
DWORD size = outSize;
|
|
|
|
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Mindscape\\LEGO Island", 0, KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
if (RegQueryValueExA(hKey, name, NULL, &valueType, (LPBYTE) outValue, &size) == ERROR_SUCCESS) {
|
|
|
|
if (RegCloseKey(hKey) == ERROR_SUCCESS) {
|
|
|
|
out = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return out;
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x4027b0
|
2023-10-24 19:38:27 -04:00
|
|
|
int IsleApp::ReadRegBool(LPCSTR name, BOOL* out)
|
2023-04-27 22:19:39 -04:00
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
char buffer[256];
|
|
|
|
|
|
|
|
BOOL read = ReadReg(name, buffer, sizeof(buffer));
|
|
|
|
if (read) {
|
|
|
|
if (strcmp("YES", buffer) == 0) {
|
|
|
|
*out = TRUE;
|
|
|
|
return read;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strcmp("NO", buffer) == 0) {
|
|
|
|
*out = FALSE;
|
|
|
|
return read;
|
|
|
|
}
|
|
|
|
|
|
|
|
read = FALSE;
|
|
|
|
}
|
|
|
|
return read;
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x402880
|
2023-10-24 19:38:27 -04:00
|
|
|
int IsleApp::ReadRegInt(LPCSTR name, int* out)
|
2023-04-27 22:19:39 -04:00
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
char buffer[256];
|
2023-04-27 22:19:39 -04:00
|
|
|
|
2023-10-24 19:38:27 -04:00
|
|
|
BOOL read = ReadReg(name, buffer, sizeof(buffer));
|
|
|
|
if (read) {
|
|
|
|
*out = atoi(buffer);
|
|
|
|
}
|
2023-04-27 22:19:39 -04:00
|
|
|
|
2023-10-24 19:38:27 -04:00
|
|
|
return read;
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x4028d0
|
2023-06-27 20:10:11 -04:00
|
|
|
void IsleApp::LoadConfig()
|
2023-04-27 22:19:39 -04:00
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
char buffer[1024];
|
|
|
|
|
|
|
|
if (!ReadReg("diskpath", buffer, sizeof(buffer))) {
|
|
|
|
strcpy(buffer, MxOmni::GetHD());
|
|
|
|
}
|
|
|
|
|
|
|
|
m_hdPath = new char[strlen(buffer) + 1];
|
|
|
|
strcpy(m_hdPath, buffer);
|
|
|
|
MxOmni::SetHD(m_hdPath);
|
|
|
|
|
|
|
|
if (!ReadReg("cdpath", buffer, sizeof(buffer))) {
|
|
|
|
strcpy(buffer, MxOmni::GetCD());
|
|
|
|
}
|
|
|
|
|
|
|
|
m_cdPath = new char[strlen(buffer) + 1];
|
|
|
|
strcpy(m_cdPath, buffer);
|
|
|
|
MxOmni::SetCD(m_cdPath);
|
|
|
|
|
|
|
|
ReadRegBool("Flip Surfaces", &m_flipSurfaces);
|
|
|
|
ReadRegBool("Full Screen", &m_fullScreen);
|
|
|
|
ReadRegBool("Wide View Angle", &m_wideViewAngle);
|
|
|
|
ReadRegBool("3DSound", &m_use3dSound);
|
|
|
|
ReadRegBool("Music", &m_useMusic);
|
|
|
|
ReadRegBool("UseJoystick", &m_useJoystick);
|
|
|
|
ReadRegInt("JoystickIndex", &m_joystickIndex);
|
|
|
|
ReadRegBool("Draw Cursor", &m_drawCursor);
|
|
|
|
|
|
|
|
int backBuffersInVRAM;
|
|
|
|
if (ReadRegBool("Back Buffers in Video RAM", &backBuffersInVRAM)) {
|
|
|
|
m_backBuffersInVram = !backBuffersInVRAM;
|
|
|
|
}
|
|
|
|
|
|
|
|
int bitDepth;
|
|
|
|
if (ReadRegInt("Display Bit Depth", &bitDepth)) {
|
|
|
|
if (bitDepth == 8) {
|
|
|
|
m_using8bit = TRUE;
|
|
|
|
}
|
|
|
|
else if (bitDepth == 16) {
|
|
|
|
m_using16bit = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!ReadReg("Island Quality", buffer, sizeof(buffer))) {
|
|
|
|
strcpy(buffer, "1");
|
|
|
|
}
|
|
|
|
m_islandQuality = atoi(buffer);
|
|
|
|
|
|
|
|
if (!ReadReg("Island Texture", buffer, sizeof(buffer))) {
|
|
|
|
strcpy(buffer, "1");
|
|
|
|
}
|
|
|
|
m_islandTexture = atoi(buffer);
|
|
|
|
|
|
|
|
if (ReadReg("3D Device ID", buffer, sizeof(buffer))) {
|
|
|
|
m_deviceId = new char[strlen(buffer) + 1];
|
|
|
|
strcpy(m_deviceId, buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ReadReg("savepath", buffer, sizeof(buffer))) {
|
|
|
|
m_savePath = new char[strlen(buffer) + 1];
|
|
|
|
strcpy(m_savePath, buffer);
|
|
|
|
}
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x402c20
|
2023-06-27 20:10:11 -04:00
|
|
|
inline void IsleApp::Tick(BOOL sleepIfNotNextFrame)
|
2023-04-27 22:19:39 -04:00
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
if (!this->m_windowActive) {
|
|
|
|
Sleep(0);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Lego())
|
|
|
|
return;
|
|
|
|
if (!TickleManager())
|
|
|
|
return;
|
|
|
|
if (!Timer())
|
|
|
|
return;
|
|
|
|
|
|
|
|
MxLong currentTime = Timer()->GetRealTime();
|
|
|
|
if (currentTime < g_lastFrameTime) {
|
|
|
|
g_lastFrameTime = -this->m_frameDelta;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (this->m_frameDelta + g_lastFrameTime < currentTime) {
|
|
|
|
if (!Lego()->IsTimerRunning()) {
|
|
|
|
TickleManager()->Tickle();
|
|
|
|
}
|
|
|
|
g_lastFrameTime = currentTime;
|
|
|
|
|
|
|
|
if (g_startupDelay == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_startupDelay--;
|
|
|
|
if (g_startupDelay != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LegoOmni::GetInstance()->CreateBackgroundAudio();
|
|
|
|
BackgroundAudioManager()->Enable(this->m_useMusic);
|
|
|
|
|
2023-12-24 15:00:20 -05:00
|
|
|
MxStreamController* stream = Streamer()->Open("\\lego\\scripts\\isle\\isle", MxStreamer::e_DiskStream);
|
2023-10-24 19:38:27 -04:00
|
|
|
MxDSAction ds;
|
|
|
|
|
|
|
|
if (!stream) {
|
2023-12-24 15:00:20 -05:00
|
|
|
stream = Streamer()->Open("\\lego\\scripts\\nocd", MxStreamer::e_DiskStream);
|
2023-10-24 19:38:27 -04:00
|
|
|
if (!stream) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
ds.SetAtomId(stream->GetAtom());
|
|
|
|
ds.SetUnknown24(-1);
|
|
|
|
ds.SetObjectId(0);
|
|
|
|
VideoManager()->EnableFullScreenMovie(TRUE, TRUE);
|
|
|
|
|
|
|
|
if (Start(&ds) != SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
ds.SetAtomId(stream->GetAtom());
|
|
|
|
ds.SetUnknown24(-1);
|
|
|
|
ds.SetObjectId(0);
|
|
|
|
if (Start(&ds) != SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
this->m_gameStarted = 1;
|
|
|
|
}
|
|
|
|
}
|
2023-12-09 12:49:13 -05:00
|
|
|
else if (sleepIfNotNextFrame != 0)
|
2023-10-24 19:38:27 -04:00
|
|
|
Sleep(0);
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x402e80
|
2023-06-27 20:10:11 -04:00
|
|
|
void IsleApp::SetupCursor(WPARAM wParam)
|
2023-04-27 23:34:11 -04:00
|
|
|
{
|
2023-10-24 19:38:27 -04:00
|
|
|
switch (wParam) {
|
|
|
|
case 0:
|
|
|
|
m_cursorCurrent = m_cursorArrow;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
m_cursorCurrent = m_cursorBusy;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
m_cursorCurrent = m_cursorNo;
|
|
|
|
break;
|
|
|
|
case 0xB:
|
|
|
|
m_cursorCurrent = NULL;
|
|
|
|
case 3:
|
|
|
|
case 4:
|
|
|
|
case 5:
|
|
|
|
case 6:
|
|
|
|
case 7:
|
|
|
|
case 8:
|
|
|
|
case 9:
|
|
|
|
case 0xA:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetCursor(m_cursorCurrent);
|
2023-06-27 20:10:11 -04:00
|
|
|
}
|