2023-06-29 04:10:08 -04:00
|
|
|
#include "isleapp.h"
|
2023-06-27 16:07:29 -04:00
|
|
|
|
2024-05-03 12:19:12 -04:00
|
|
|
#include "3dmanager/lego3dmanager.h"
|
2024-02-05 09:01:48 -05:00
|
|
|
#include "decomp.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"
|
2024-05-04 08:06:32 -04:00
|
|
|
#include "legomain.h"
|
2023-06-27 16:07:29 -04:00
|
|
|
#include "legomodelpresenter.h"
|
|
|
|
#include "legopartpresenter.h"
|
2024-06-01 10:54:17 -04:00
|
|
|
#include "legoutils.h"
|
2023-10-07 11:30:04 -04:00
|
|
|
#include "legovideomanager.h"
|
2023-06-27 16:07:29 -04:00
|
|
|
#include "legoworldpresenter.h"
|
2024-03-09 15:07:52 -05:00
|
|
|
#include "misc.h"
|
2023-10-07 11:30:04 -04:00
|
|
|
#include "mxbackgroundaudiomanager.h"
|
2024-05-03 12:19:12 -04:00
|
|
|
#include "mxdirectx/mxdirect3d.h"
|
2023-06-27 16:07:29 -04:00
|
|
|
#include "mxdsaction.h"
|
2024-03-09 15:07:52 -05:00
|
|
|
#include "mxmisc.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"
|
2024-05-31 17:56:00 -04:00
|
|
|
#include "mxutilities.h"
|
2024-05-03 12:19:12 -04:00
|
|
|
#include "mxvariabletable.h"
|
2023-06-27 16:07:29 -04:00
|
|
|
#include "res/resource.h"
|
2024-05-03 12:19:12 -04:00
|
|
|
#include "roi/legoroi.h"
|
2024-01-06 21:29:32 -05:00
|
|
|
#include "viewmanager/viewmanager.h"
|
2023-04-27 22:19:39 -04:00
|
|
|
|
2024-05-31 10:45:51 -04:00
|
|
|
#define SDL_MAIN_USE_CALLBACKS
|
2024-06-26 14:24:40 -04:00
|
|
|
#include <SDL3/SDL.h>
|
2024-05-31 10:45:51 -04:00
|
|
|
#include <SDL3/SDL_main.h>
|
2024-05-31 14:04:00 -04:00
|
|
|
#include <iniparser.h>
|
2024-05-31 17:56:00 -04:00
|
|
|
#include <time.h>
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-02-05 09:01:48 -05:00
|
|
|
DECOMP_SIZE_ASSERT(IsleApp, 0x8c)
|
|
|
|
|
|
|
|
// GLOBAL: ISLE 0x410030
|
|
|
|
IsleApp* g_isle = NULL;
|
|
|
|
|
|
|
|
// GLOBAL: ISLE 0x410034
|
2024-05-31 23:13:27 -04:00
|
|
|
MxU8 g_mousedown = FALSE;
|
2024-02-05 09:01:48 -05:00
|
|
|
|
|
|
|
// GLOBAL: ISLE 0x410038
|
2024-05-31 23:13:27 -04:00
|
|
|
MxU8 g_mousemoved = FALSE;
|
2024-02-05 09:01:48 -05:00
|
|
|
|
|
|
|
// GLOBAL: ISLE 0x41003c
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 g_closed = FALSE;
|
2024-02-05 09:01:48 -05:00
|
|
|
|
|
|
|
// GLOBAL: ISLE 0x410050
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 g_rmDisabled = FALSE;
|
2024-02-05 09:01:48 -05:00
|
|
|
|
|
|
|
// GLOBAL: ISLE 0x410054
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 g_waitingForTargetDepth = TRUE;
|
2024-02-05 09:01:48 -05:00
|
|
|
|
|
|
|
// GLOBAL: ISLE 0x410058
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 g_targetWidth = 640;
|
2024-02-05 09:01:48 -05:00
|
|
|
|
|
|
|
// GLOBAL: ISLE 0x41005c
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 g_targetHeight = 480;
|
2024-02-05 09:01:48 -05:00
|
|
|
|
|
|
|
// GLOBAL: ISLE 0x410060
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 g_targetDepth = 16;
|
2024-02-05 09:01:48 -05:00
|
|
|
|
|
|
|
// GLOBAL: ISLE 0x410064
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 g_reqEnableRMDevice = FALSE;
|
2024-02-05 09:01:48 -05:00
|
|
|
|
|
|
|
// STRING: ISLE 0x4101dc
|
2024-05-31 17:56:00 -04:00
|
|
|
#define WINDOW_TITLE "LEGO®"
|
2023-12-09 12:49:13 -05:00
|
|
|
|
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;
|
2024-02-05 09:01:48 -05:00
|
|
|
m_fullScreen = TRUE;
|
|
|
|
m_flipSurfaces = FALSE;
|
|
|
|
m_backBuffersInVram = TRUE;
|
|
|
|
m_using8bit = FALSE;
|
|
|
|
m_using16bit = TRUE;
|
2023-12-13 05:48:14 -05:00
|
|
|
m_unk0x24 = 0;
|
2024-02-05 09:01:48 -05:00
|
|
|
m_drawCursor = FALSE;
|
|
|
|
m_use3dSound = TRUE;
|
|
|
|
m_useMusic = TRUE;
|
|
|
|
m_useJoystick = FALSE;
|
2023-10-24 19:38:27 -04:00
|
|
|
m_joystickIndex = 0;
|
2024-02-05 09:01:48 -05:00
|
|
|
m_wideViewAngle = TRUE;
|
2023-10-24 19:38:27 -04:00
|
|
|
m_islandQuality = 1;
|
|
|
|
m_islandTexture = 1;
|
2024-02-05 09:01:48 -05:00
|
|
|
m_gameStarted = FALSE;
|
2023-10-24 19:38:27 -04:00
|
|
|
m_frameDelta = 10;
|
2024-02-05 09:01:48 -05:00
|
|
|
m_windowActive = TRUE;
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-01-24 21:16:29 -05:00
|
|
|
#ifdef COMPAT_MODE
|
|
|
|
{
|
|
|
|
MxRect32 r(0, 0, 639, 479);
|
|
|
|
MxVideoParamFlags flags;
|
|
|
|
m_videoParam = MxVideoParam(r, NULL, 1, flags);
|
|
|
|
}
|
|
|
|
#else
|
2023-10-24 19:38:27 -04:00
|
|
|
m_videoParam = MxVideoParam(MxRect32(0, 0, 639, 479), NULL, 1, MxVideoParamFlags());
|
2024-01-24 21:16:29 -05:00
|
|
|
#endif
|
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();
|
2024-06-26 14:24:40 -04:00
|
|
|
|
|
|
|
m_iniPath = NULL;
|
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()) {
|
2024-05-31 23:13:27 -04:00
|
|
|
InputManager()->QueueEvent(c_notificationKeyPress, 0, 0, 0, SDLK_SPACE);
|
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);
|
2024-06-09 13:39:22 -04:00
|
|
|
Lego()->Resume();
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-06-05 06:31:23 -04:00
|
|
|
while (Streamer()->Close(NULL) == SUCCESS) {
|
|
|
|
}
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-06-05 06:31:23 -04:00
|
|
|
while (Lego() && !Lego()->DoesEntityExist(ds)) {
|
2023-10-24 19:38:27 -04:00
|
|
|
Timer()->GetRealTime();
|
|
|
|
TickleManager()->Tickle();
|
|
|
|
}
|
|
|
|
}
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x4013b0
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 IsleApp::SetupLegoOmni()
|
2023-06-27 16:07:29 -04:00
|
|
|
{
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 result = FALSE;
|
2023-10-24 19:38:27 -04:00
|
|
|
char mediaPath[256];
|
|
|
|
GetProfileStringA("LEGO Island", "MediaPath", "", mediaPath, sizeof(mediaPath));
|
|
|
|
|
2024-05-31 17:56:00 -04:00
|
|
|
// [library:window] For now, get the underlying Windows HWND to pass into Omni
|
|
|
|
HWND hwnd =
|
|
|
|
(HWND) SDL_GetProperty(SDL_GetWindowProperties(m_windowHandle), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
|
|
|
|
|
2024-01-07 12:30:45 -05:00
|
|
|
#ifdef COMPAT_MODE
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 failure;
|
2024-01-07 12:30:45 -05:00
|
|
|
{
|
2024-05-31 17:56:00 -04:00
|
|
|
MxOmniCreateParam param(mediaPath, (struct HWND__*) hwnd, m_videoParam, MxOmniCreateFlags());
|
2024-01-07 12:30:45 -05:00
|
|
|
failure = Lego()->Create(param) == FAILURE;
|
|
|
|
}
|
|
|
|
#else
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 failure =
|
|
|
|
Lego()->Create(MxOmniCreateParam(mediaPath, (struct HWND__*) hwnd, m_videoParam, MxOmniCreateFlags())) ==
|
|
|
|
FAILURE;
|
2024-01-07 12:30:45 -05:00
|
|
|
#endif
|
|
|
|
|
2023-10-24 19:38:27 -04:00
|
|
|
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(
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 fullScreen,
|
|
|
|
MxS32 flipSurfaces,
|
|
|
|
MxS32 backBuffers,
|
|
|
|
MxS32 using8bit,
|
|
|
|
MxS32 using16bit,
|
|
|
|
MxS32 param_6,
|
|
|
|
MxS32 param_7,
|
|
|
|
MxS32 wideViewAngle,
|
2023-10-24 19:38:27 -04:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2024-05-31 10:45:51 -04:00
|
|
|
int SDL_AppInit(void** appstate, int argc, char** argv)
|
2023-06-27 16:07:29 -04:00
|
|
|
{
|
2024-05-31 18:05:05 -04:00
|
|
|
*appstate = NULL;
|
|
|
|
|
2024-06-16 09:26:04 -04:00
|
|
|
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0) {
|
2024-05-31 17:56:00 -04:00
|
|
|
SDL_ShowSimpleMessageBox(
|
|
|
|
SDL_MESSAGEBOX_ERROR,
|
|
|
|
"LEGO® Island Error",
|
|
|
|
"\"LEGO® Island\" failed to start. Please quit all other applications and try again.",
|
|
|
|
NULL
|
2023-10-24 19:38:27 -04:00
|
|
|
);
|
2024-05-31 23:20:14 -04:00
|
|
|
return SDL_APP_FAILURE;
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
|
|
|
|
2024-05-31 17:56:00 -04:00
|
|
|
// [library:window]
|
|
|
|
// Original game checks for an existing instance here.
|
|
|
|
// We don't really need that.
|
|
|
|
|
2023-10-24 19:38:27 -04:00
|
|
|
// Create global app instance
|
|
|
|
g_isle = new IsleApp();
|
|
|
|
|
2024-06-26 14:24:40 -04:00
|
|
|
if (g_isle->ParseArguments(argc, argv) != SUCCESS) {
|
|
|
|
SDL_ShowSimpleMessageBox(
|
|
|
|
SDL_MESSAGEBOX_ERROR,
|
|
|
|
"LEGO® Island Error",
|
|
|
|
"\"LEGO® Island\" failed to start. Invalid CLI arguments.",
|
|
|
|
NULL
|
|
|
|
);
|
|
|
|
return SDL_APP_FAILURE;
|
|
|
|
}
|
|
|
|
|
2023-10-24 19:38:27 -04:00
|
|
|
// Create window
|
2024-05-31 17:56:00 -04:00
|
|
|
if (g_isle->SetupWindow() != SUCCESS) {
|
|
|
|
SDL_ShowSimpleMessageBox(
|
|
|
|
SDL_MESSAGEBOX_ERROR,
|
|
|
|
"LEGO® Island Error",
|
|
|
|
"\"LEGO® Island\" failed to start. Please quit all other applications and try again.",
|
|
|
|
NULL
|
2023-10-24 19:38:27 -04:00
|
|
|
);
|
2024-05-31 23:20:14 -04:00
|
|
|
return SDL_APP_FAILURE;
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get reference to window
|
2024-05-31 10:45:51 -04:00
|
|
|
*appstate = g_isle->GetWindowHandle();
|
2024-05-31 23:20:14 -04:00
|
|
|
return SDL_APP_CONTINUE;
|
2024-05-31 10:45:51 -04:00
|
|
|
}
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 10:45:51 -04:00
|
|
|
int SDL_AppIterate(void* appstate)
|
|
|
|
{
|
|
|
|
if (g_closed) {
|
2024-05-31 23:20:14 -04:00
|
|
|
return SDL_APP_SUCCESS;
|
2024-05-31 10:45:51 -04:00
|
|
|
}
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
g_isle->Tick();
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 17:56:00 -04:00
|
|
|
if (!g_closed) {
|
2024-05-31 10:45:51 -04:00
|
|
|
if (g_reqEnableRMDevice) {
|
|
|
|
g_reqEnableRMDevice = FALSE;
|
|
|
|
VideoManager()->EnableRMDevice();
|
|
|
|
g_rmDisabled = FALSE;
|
2024-06-25 13:32:52 -04:00
|
|
|
Lego()->Resume();
|
2024-05-31 10:45:51 -04:00
|
|
|
}
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 10:45:51 -04:00
|
|
|
if (g_closed) {
|
2024-05-31 23:20:14 -04:00
|
|
|
return SDL_APP_SUCCESS;
|
2024-05-31 10:45:51 -04:00
|
|
|
}
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 10:45:51 -04:00
|
|
|
if (g_mousedown && g_mousemoved && g_isle) {
|
2024-05-31 23:13:27 -04:00
|
|
|
g_isle->Tick();
|
2024-05-31 10:45:51 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (g_mousemoved) {
|
|
|
|
g_mousemoved = FALSE;
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-31 23:20:14 -04:00
|
|
|
return SDL_APP_CONTINUE;
|
2024-05-31 10:45:51 -04:00
|
|
|
}
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 10:45:51 -04:00
|
|
|
int SDL_AppEvent(void* appstate, const SDL_Event* event)
|
|
|
|
{
|
2024-05-31 17:56:00 -04:00
|
|
|
if (!g_isle) {
|
2024-05-31 23:20:14 -04:00
|
|
|
return SDL_APP_CONTINUE;
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
2023-06-27 16:07:29 -04:00
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
// [library:window]
|
|
|
|
// Remaining functionality to be implemented:
|
2024-06-16 09:26:04 -04:00
|
|
|
// Full screen - crashes when minimizing/maximizing, but this will probably be fixed once DirectDraw is replaced
|
2024-05-31 17:56:00 -04:00
|
|
|
// WM_TIMER - use SDL_Timer functionality instead
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 17:56:00 -04:00
|
|
|
switch (event->type) {
|
|
|
|
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
|
|
|
g_isle->SetWindowActive(TRUE);
|
2024-06-16 09:26:04 -04:00
|
|
|
Lego()->Resume();
|
2024-05-31 17:56:00 -04:00
|
|
|
break;
|
|
|
|
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
|
|
|
g_isle->SetWindowActive(FALSE);
|
2024-06-16 09:26:04 -04:00
|
|
|
Lego()->Pause();
|
2024-05-31 17:56:00 -04:00
|
|
|
break;
|
|
|
|
case SDL_EVENT_WINDOW_CLOSE_REQUESTED:
|
|
|
|
if (!g_closed) {
|
|
|
|
delete g_isle;
|
2023-10-24 19:38:27 -04:00
|
|
|
g_isle = NULL;
|
|
|
|
g_closed = TRUE;
|
|
|
|
}
|
2024-05-31 17:56:00 -04:00
|
|
|
break;
|
|
|
|
case SDL_EVENT_KEY_DOWN: {
|
|
|
|
if (event->key.repeat) {
|
|
|
|
break;
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
2024-05-31 17:56:00 -04:00
|
|
|
|
2024-06-24 10:25:51 -04:00
|
|
|
SDL_Keycode keyCode = event->key.key;
|
2024-05-31 17:56:00 -04:00
|
|
|
if (InputManager()) {
|
|
|
|
InputManager()->QueueEvent(c_notificationKeyPress, keyCode, 0, 0, keyCode);
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
|
|
|
break;
|
2024-05-31 17:56:00 -04:00
|
|
|
}
|
|
|
|
case SDL_EVENT_MOUSE_MOTION:
|
|
|
|
g_mousemoved = TRUE;
|
|
|
|
|
|
|
|
if (InputManager()) {
|
|
|
|
InputManager()->QueueEvent(
|
|
|
|
c_notificationMouseMove,
|
|
|
|
IsleApp::MapMouseButtonFlagsToModifier(event->motion.state),
|
|
|
|
event->motion.x,
|
|
|
|
event->motion.y,
|
|
|
|
0
|
|
|
|
);
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
2024-05-31 17:56:00 -04:00
|
|
|
|
|
|
|
if (g_isle->GetDrawCursor()) {
|
2024-05-31 23:13:27 -04:00
|
|
|
VideoManager()->MoveCursor(Min((MxS32) event->motion.x, 639), Min((MxS32) event->motion.y, 479));
|
2023-12-09 12:49:13 -05:00
|
|
|
}
|
|
|
|
break;
|
2024-05-31 17:56:00 -04:00
|
|
|
case SDL_EVENT_MOUSE_BUTTON_DOWN:
|
|
|
|
g_mousedown = TRUE;
|
2023-10-24 19:38:27 -04:00
|
|
|
|
|
|
|
if (InputManager()) {
|
2024-05-31 17:56:00 -04:00
|
|
|
InputManager()->QueueEvent(
|
|
|
|
c_notificationButtonDown,
|
|
|
|
IsleApp::MapMouseButtonFlagsToModifier(SDL_GetMouseState(NULL, NULL)),
|
|
|
|
event->button.x,
|
|
|
|
event->button.y,
|
|
|
|
0
|
|
|
|
);
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
2024-05-31 17:56:00 -04:00
|
|
|
break;
|
|
|
|
case SDL_EVENT_MOUSE_BUTTON_UP:
|
|
|
|
g_mousedown = FALSE;
|
|
|
|
|
|
|
|
if (InputManager()) {
|
|
|
|
InputManager()->QueueEvent(
|
|
|
|
c_notificationButtonUp,
|
|
|
|
IsleApp::MapMouseButtonFlagsToModifier(SDL_GetMouseState(NULL, NULL)),
|
|
|
|
event->button.x,
|
|
|
|
event->button.y,
|
|
|
|
0
|
|
|
|
);
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
2024-05-31 17:56:00 -04:00
|
|
|
break;
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
|
|
|
|
2024-06-25 21:47:43 -04:00
|
|
|
// FIXME: use g_userEvent instead of SDL_EVENT_USER
|
2024-06-01 10:54:17 -04:00
|
|
|
if (event->type >= SDL_EVENT_USER && event->type <= SDL_EVENT_LAST - 1) {
|
|
|
|
switch (event->user.code) {
|
|
|
|
case WM_ISLE_SETCURSOR:
|
2024-06-25 21:47:43 -04:00
|
|
|
g_isle->SetupCursor((Cursor) (uintptr_t) event->user.data1);
|
2024-06-01 10:54:17 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-31 23:20:14 -04:00
|
|
|
return SDL_APP_CONTINUE;
|
2023-06-27 16:07:29 -04:00
|
|
|
}
|
|
|
|
|
2024-05-31 17:56:00 -04:00
|
|
|
void SDL_AppQuit(void* appstate)
|
2023-06-27 16:07:29 -04:00
|
|
|
{
|
2024-05-31 17:56:00 -04:00
|
|
|
if (appstate != NULL) {
|
|
|
|
SDL_DestroyWindow((SDL_Window*) appstate);
|
|
|
|
}
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 17:56:00 -04:00
|
|
|
SDL_Quit();
|
|
|
|
}
|
|
|
|
|
|
|
|
MxU8 IsleApp::MapMouseButtonFlagsToModifier(SDL_MouseButtonFlags p_flags)
|
|
|
|
{
|
|
|
|
// [library:window]
|
|
|
|
// Map button states to Windows button states (LegoEventNotificationParam)
|
|
|
|
// Not mapping mod keys SHIFT and CTRL since they are not used by the game.
|
|
|
|
|
|
|
|
MxU8 modifier = 0;
|
|
|
|
if (p_flags & SDL_BUTTON_LMASK) {
|
|
|
|
modifier |= LegoEventNotificationParam::c_lButtonState;
|
|
|
|
}
|
|
|
|
if (p_flags & SDL_BUTTON_RMASK) {
|
|
|
|
modifier |= LegoEventNotificationParam::c_rButtonState;
|
|
|
|
}
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 17:56:00 -04:00
|
|
|
return modifier;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FUNCTION: ISLE 0x4023e0
|
|
|
|
MxResult IsleApp::SetupWindow()
|
|
|
|
{
|
|
|
|
LoadConfig();
|
2023-10-24 19:38:27 -04:00
|
|
|
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);
|
|
|
|
|
2024-05-31 17:56:00 -04:00
|
|
|
srand(time(NULL));
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-06-01 10:54:17 -04:00
|
|
|
// [library:window] Use original game cursors in the resources instead?
|
2024-06-02 11:20:41 -04:00
|
|
|
m_cursorCurrent = m_cursorArrow = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_DEFAULT);
|
2024-06-01 10:54:17 -04:00
|
|
|
m_cursorBusy = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_WAIT);
|
2024-06-02 11:20:41 -04:00
|
|
|
m_cursorNo = SDL_CreateSystemCursor(SDL_SYSTEM_CURSOR_NOT_ALLOWED);
|
2024-06-01 10:54:17 -04:00
|
|
|
SDL_SetCursor(m_cursorCurrent);
|
|
|
|
|
2024-06-26 14:24:40 -04:00
|
|
|
SDL_PropertiesID props = SDL_CreateProperties();
|
|
|
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_WIDTH_NUMBER, g_targetWidth);
|
|
|
|
SDL_SetNumberProperty(props, SDL_PROP_WINDOW_CREATE_HEIGHT_NUMBER, g_targetHeight);
|
|
|
|
SDL_SetBooleanProperty(props, SDL_PROP_WINDOW_CREATE_FULLSCREEN_BOOLEAN, m_fullScreen);
|
|
|
|
SDL_SetStringProperty(props, SDL_PROP_WINDOW_CREATE_TITLE_STRING, WINDOW_TITLE);
|
|
|
|
|
|
|
|
m_windowHandle = SDL_CreateWindowWithProperties(props);
|
|
|
|
|
|
|
|
SDL_DestroyProperties(props);
|
2023-10-24 19:38:27 -04:00
|
|
|
|
|
|
|
if (!m_windowHandle) {
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!SetupLegoOmni()) {
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
GameState()->SetSavePath(m_savePath);
|
2024-06-05 06:31:23 -04:00
|
|
|
GameState()->SerializePlayersInfo(LegoStorage::c_read);
|
|
|
|
GameState()->SerializeScoreHistory(LegoStorage::c_read);
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 iVar10;
|
2023-10-24 19:38:27 -04:00
|
|
|
switch (m_islandQuality) {
|
|
|
|
case 0:
|
|
|
|
iVar10 = 1;
|
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
iVar10 = 2;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
iVar10 = 100;
|
|
|
|
}
|
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 uVar1 = (m_islandTexture == 0);
|
2023-10-24 19:38:27 -04:00
|
|
|
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()) {
|
2024-01-14 16:58:00 -05:00
|
|
|
LegoOmni::GetInstance()->GetInputManager()->SetUseJoystick(m_useJoystick);
|
|
|
|
LegoOmni::GetInstance()->GetInputManager()->SetJoystickIndex(m_joystickIndex);
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SUCCESS;
|
2023-06-27 16:07:29 -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
|
|
|
{
|
2024-05-31 14:04:00 -04:00
|
|
|
char* basePath = SDL_GetBasePath();
|
|
|
|
char* prefPath = SDL_GetPrefPath("isledecomp", "isle");
|
2024-06-26 14:24:40 -04:00
|
|
|
char* iniConfig;
|
|
|
|
if (m_iniPath) {
|
|
|
|
iniConfig = new char[strlen(m_iniPath) + 1];
|
|
|
|
strcpy(iniConfig, m_iniPath);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
iniConfig = new char[strlen(prefPath) + strlen("isle.ini") + 1]();
|
|
|
|
strcat(iniConfig, prefPath);
|
|
|
|
strcat(iniConfig, "isle.ini");
|
|
|
|
}
|
|
|
|
SDL_Log("Reading configuration from \"%s\"", iniConfig);
|
|
|
|
|
2024-05-31 14:04:00 -04:00
|
|
|
dictionary* dict = iniparser_load(iniConfig);
|
|
|
|
|
|
|
|
const char* hdPath = iniparser_getstring(dict, "isle:diskpath", basePath);
|
|
|
|
m_hdPath = new char[strlen(hdPath) + 1];
|
|
|
|
strcpy(m_hdPath, hdPath);
|
2023-10-24 19:38:27 -04:00
|
|
|
MxOmni::SetHD(m_hdPath);
|
|
|
|
|
2024-05-31 14:04:00 -04:00
|
|
|
const char* cdPath = iniparser_getstring(dict, "isle:cdpath", MxOmni::GetCD());
|
|
|
|
m_cdPath = new char[strlen(cdPath) + 1];
|
|
|
|
strcpy(m_cdPath, cdPath);
|
2023-10-24 19:38:27 -04:00
|
|
|
MxOmni::SetCD(m_cdPath);
|
|
|
|
|
2024-05-31 14:04:00 -04:00
|
|
|
m_flipSurfaces = iniparser_getboolean(dict, "isle:Flip Surfaces", m_flipSurfaces);
|
|
|
|
m_fullScreen = iniparser_getboolean(dict, "isle:Full Screen", m_fullScreen);
|
|
|
|
m_wideViewAngle = iniparser_getboolean(dict, "isle:Wide View Angle", m_wideViewAngle);
|
|
|
|
m_use3dSound = iniparser_getboolean(dict, "isle:3DSound", m_use3dSound);
|
|
|
|
m_useMusic = iniparser_getboolean(dict, "isle:Music", m_useMusic);
|
|
|
|
m_useJoystick = iniparser_getboolean(dict, "isle:UseJoystick", m_useJoystick);
|
|
|
|
m_joystickIndex = iniparser_getint(dict, "isle:JoystickIndex", m_joystickIndex);
|
|
|
|
m_drawCursor = iniparser_getboolean(dict, "isle:Draw Cursor", m_drawCursor);
|
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 backBuffersInVRAM = iniparser_getboolean(dict, "isle:Back Buffers in Video RAM", -1);
|
2024-05-31 14:04:00 -04:00
|
|
|
if (backBuffersInVRAM != -1) {
|
2023-10-24 19:38:27 -04:00
|
|
|
m_backBuffersInVram = !backBuffersInVRAM;
|
|
|
|
}
|
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
MxS32 bitDepth = iniparser_getint(dict, "isle:Display Bit Depth", -1);
|
2024-05-31 14:04:00 -04:00
|
|
|
if (bitDepth != -1) {
|
2023-10-24 19:38:27 -04:00
|
|
|
if (bitDepth == 8) {
|
|
|
|
m_using8bit = TRUE;
|
|
|
|
}
|
|
|
|
else if (bitDepth == 16) {
|
|
|
|
m_using16bit = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-05-31 14:04:00 -04:00
|
|
|
m_islandQuality = iniparser_getint(dict, "isle:Island Quality", 1);
|
|
|
|
m_islandTexture = iniparser_getint(dict, "isle:Island Texture", 1);
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 14:04:00 -04:00
|
|
|
const char* deviceId = iniparser_getstring(dict, "isle:3D Device ID", NULL);
|
|
|
|
if (deviceId != NULL) {
|
|
|
|
m_deviceId = new char[strlen(deviceId) + 1];
|
|
|
|
strcpy(m_deviceId, deviceId);
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
|
|
|
|
2024-05-31 17:56:00 -04:00
|
|
|
// [library:config]
|
|
|
|
// The original game does not save any data if no savepath is given.
|
2024-05-31 14:04:00 -04:00
|
|
|
// Instead, we use SDLs prefPath as a default fallback and always save data.
|
|
|
|
const char* savePath = iniparser_getstring(dict, "isle:savepath", prefPath);
|
|
|
|
m_savePath = new char[strlen(savePath) + 1];
|
|
|
|
strcpy(m_savePath, savePath);
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 14:04:00 -04:00
|
|
|
iniparser_freedict(dict);
|
|
|
|
delete[] iniConfig;
|
|
|
|
SDL_free(prefPath);
|
|
|
|
SDL_free(basePath);
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x402c20
|
2024-05-31 23:13:27 -04:00
|
|
|
inline void IsleApp::Tick()
|
2023-04-27 22:19:39 -04:00
|
|
|
{
|
2024-02-05 06:43:13 -05:00
|
|
|
// GLOBAL: ISLE 0x4101c0
|
|
|
|
static MxLong g_lastFrameTime = 0;
|
|
|
|
|
|
|
|
// GLOBAL: ISLE 0x4101bc
|
2024-05-31 23:13:27 -04:00
|
|
|
static MxS32 g_startupDelay = 200;
|
2024-02-05 06:43:13 -05:00
|
|
|
|
2024-02-05 09:01:48 -05:00
|
|
|
if (!m_windowActive) {
|
2024-05-31 23:13:27 -04:00
|
|
|
SDL_Delay(1);
|
2023-10-24 19:38:27 -04:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-02-01 15:42:10 -05:00
|
|
|
if (!Lego()) {
|
2023-10-24 19:38:27 -04:00
|
|
|
return;
|
2024-02-01 15:42:10 -05:00
|
|
|
}
|
|
|
|
if (!TickleManager()) {
|
2023-10-24 19:38:27 -04:00
|
|
|
return;
|
2024-02-01 15:42:10 -05:00
|
|
|
}
|
|
|
|
if (!Timer()) {
|
2023-10-24 19:38:27 -04:00
|
|
|
return;
|
2024-02-01 15:42:10 -05:00
|
|
|
}
|
2023-10-24 19:38:27 -04:00
|
|
|
|
|
|
|
MxLong currentTime = Timer()->GetRealTime();
|
|
|
|
if (currentTime < g_lastFrameTime) {
|
2024-02-05 09:01:48 -05:00
|
|
|
g_lastFrameTime = -m_frameDelta;
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
if (m_frameDelta + g_lastFrameTime >= currentTime) {
|
|
|
|
SDL_Delay(1);
|
|
|
|
return;
|
|
|
|
}
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-06-25 13:32:52 -04:00
|
|
|
if (!Lego()->IsPaused()) {
|
2024-05-31 23:13:27 -04:00
|
|
|
TickleManager()->Tickle();
|
|
|
|
}
|
|
|
|
g_lastFrameTime = currentTime;
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
if (g_startupDelay == 0) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
g_startupDelay--;
|
|
|
|
if (g_startupDelay != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
LegoOmni::GetInstance()->CreateBackgroundAudio();
|
|
|
|
BackgroundAudioManager()->Enable(m_useMusic);
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
MxStreamController* stream = Streamer()->Open("\\lego\\scripts\\isle\\isle", MxStreamer::e_diskStream);
|
|
|
|
MxDSAction ds;
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
if (!stream) {
|
|
|
|
stream = Streamer()->Open("\\lego\\scripts\\nocd", MxStreamer::e_diskStream);
|
2023-10-24 19:38:27 -04:00
|
|
|
if (!stream) {
|
2024-05-31 23:13:27 -04:00
|
|
|
return;
|
|
|
|
}
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
ds.SetAtomId(stream->GetAtom());
|
|
|
|
ds.SetUnknown24(-1);
|
|
|
|
ds.SetObjectId(0);
|
|
|
|
VideoManager()->EnableFullScreenMovie(TRUE, TRUE);
|
2023-10-24 19:38:27 -04:00
|
|
|
|
2024-05-31 23:13:27 -04:00
|
|
|
if (Start(&ds) != SUCCESS) {
|
|
|
|
return;
|
2023-10-24 19:38:27 -04:00
|
|
|
}
|
|
|
|
}
|
2024-05-31 23:13:27 -04:00
|
|
|
else {
|
|
|
|
ds.SetAtomId(stream->GetAtom());
|
|
|
|
ds.SetUnknown24(-1);
|
|
|
|
ds.SetObjectId(0);
|
|
|
|
if (Start(&ds) != SUCCESS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
m_gameStarted = TRUE;
|
2024-02-01 15:42:10 -05:00
|
|
|
}
|
2023-04-27 22:19:39 -04:00
|
|
|
}
|
|
|
|
|
2023-12-06 07:10:45 -05:00
|
|
|
// FUNCTION: ISLE 0x402e80
|
2024-06-01 10:54:17 -04:00
|
|
|
void IsleApp::SetupCursor(Cursor p_cursor)
|
2023-04-27 23:34:11 -04:00
|
|
|
{
|
2024-06-01 10:54:17 -04:00
|
|
|
switch (p_cursor) {
|
|
|
|
case e_cursorArrow:
|
2023-10-24 19:38:27 -04:00
|
|
|
m_cursorCurrent = m_cursorArrow;
|
|
|
|
break;
|
2024-06-01 10:54:17 -04:00
|
|
|
case e_cursorBusy:
|
2023-10-24 19:38:27 -04:00
|
|
|
m_cursorCurrent = m_cursorBusy;
|
|
|
|
break;
|
2024-06-01 10:54:17 -04:00
|
|
|
case e_cursorNo:
|
2023-10-24 19:38:27 -04:00
|
|
|
m_cursorCurrent = m_cursorNo;
|
|
|
|
break;
|
2024-06-01 10:54:17 -04:00
|
|
|
case e_cursorNone:
|
2023-10-24 19:38:27 -04:00
|
|
|
m_cursorCurrent = NULL;
|
2024-06-01 10:54:17 -04:00
|
|
|
case e_cursorUnused3:
|
|
|
|
case e_cursorUnused4:
|
|
|
|
case e_cursorUnused5:
|
|
|
|
case e_cursorUnused6:
|
|
|
|
case e_cursorUnused7:
|
|
|
|
case e_cursorUnused8:
|
|
|
|
case e_cursorUnused9:
|
|
|
|
case e_cursorUnused10:
|
2023-10-24 19:38:27 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-06-01 10:54:17 -04:00
|
|
|
if (m_cursorCurrent != NULL) {
|
|
|
|
SDL_SetCursor(m_cursorCurrent);
|
|
|
|
SDL_ShowCursor();
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
SDL_HideCursor();
|
|
|
|
}
|
2023-06-27 20:10:11 -04:00
|
|
|
}
|
2024-06-26 14:24:40 -04:00
|
|
|
|
|
|
|
MxResult IsleApp::ParseArguments(int argc, char** argv)
|
|
|
|
{
|
|
|
|
|
|
|
|
for (int i = 1, consumed; i < argc; i += consumed) {
|
|
|
|
consumed = -1;
|
|
|
|
|
|
|
|
if (strcmp(argv[i], "--ini") == 0 && i + 1 < argc) {
|
|
|
|
m_iniPath = argv[i + 1];
|
|
|
|
consumed = 2;
|
|
|
|
}
|
|
|
|
if (consumed <= 0) {
|
|
|
|
SDL_Log("Invalid argument(s): %s", argv[i]);
|
|
|
|
return FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return SUCCESS;
|
|
|
|
}
|