diff --git a/CMakeLists.txt b/CMakeLists.txt index d62c2b2b..6c408d65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ add_library(lego1 SHARED LEGO1/buildingentity.cpp LEGO1/bumpbouy.cpp LEGO1/carrace.cpp + LEGO1/define.cpp LEGO1/dllmain.cpp LEGO1/dunebuggy.cpp LEGO1/elevatorbottom.cpp diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c9d3364a..005f599c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,7 +26,7 @@ This repository currently has only one goal: accuracy to the original executable In general, we're not exhaustively strict about coding style, but there are some preferable guidelines to follow that have been adopted from what we know about the original codebase: - Indent: 2 spaces -- `PascalCase` for classes and function names. +- `PascalCase` for classes, function names, and enumerations. - `m_camelCase` for member variables. - `g_camelCase` for global variables. - `p_camelCase` for function parameters. diff --git a/LEGO1/define.cpp b/LEGO1/define.cpp new file mode 100644 index 00000000..84073b9d --- /dev/null +++ b/LEGO1/define.cpp @@ -0,0 +1,10 @@ +#include "define.h" + +// 0x10101eac +const char *g_parseExtraTokens = ":;"; + +// 0x10101edc +const char *g_strWORLD = "WORLD"; + +// 0x10102040 +const char *g_strACTION = "ACTION"; diff --git a/LEGO1/define.h b/LEGO1/define.h new file mode 100644 index 00000000..ec41943e --- /dev/null +++ b/LEGO1/define.h @@ -0,0 +1,8 @@ +#ifndef DEFINE_H +#define DEFINE_H + +extern const char *g_parseExtraTokens; +extern const char *g_strWORLD; +extern const char *g_strACTION; + +#endif // DEFINE_H \ No newline at end of file diff --git a/LEGO1/extra.h b/LEGO1/extra.h new file mode 100644 index 00000000..05ed5f07 --- /dev/null +++ b/LEGO1/extra.h @@ -0,0 +1,21 @@ +#ifndef EXTRA_H +#define EXTRA_H + +// Items related to the Extra string of key-value pairs found in MxOb + +enum ExtraActionType +{ + ExtraActionType_opendisk = 1, + ExtraActionType_openram = 2, + ExtraActionType_close = 3, + ExtraActionType_start = 4, + ExtraActionType_stop = 5, + ExtraActionType_run = 6, + ExtraActionType_exit = 7, + ExtraActionType_enable = 8, + ExtraActionType_disable = 9, + ExtraActionType_notify = 10, + ExtraActionType_unknown = 11, +}; + +#endif // EXTRA_H diff --git a/LEGO1/legoentity.cpp b/LEGO1/legoentity.cpp index b8ed69f9..d2062946 100644 --- a/LEGO1/legoentity.cpp +++ b/LEGO1/legoentity.cpp @@ -1,5 +1,9 @@ #include "legoentity.h" +#include "legoomni.h" +#include "legoutil.h" +#include "define.h" + DECOMP_SIZE_ASSERT(LegoEntity, 0x68) // OFFSET: LEGO1 0x1000c290 @@ -16,8 +20,37 @@ MxLong LegoEntity::Notify(MxParam &p) return 0; } +// OFFSET: LEGO1 0x100107e0 STUB +void LegoEntity::vtable18() +{ + +} + // OFFSET: LEGO1 0x10010810 STUB void LegoEntity::Destroy() { // TODO } + +// OFFSET: LEGO1 0x10010e10 +void LegoEntity::ParseAction(char *p_extra) +{ + char copy[1024]; + char actionValue[1024]; + strcpy(copy, p_extra); + + if (KeyValueStringParse(actionValue, g_strACTION, copy)) { + m_actionType = MatchActionString(strtok(actionValue, g_parseExtraTokens)); + + if (m_actionType != ExtraActionType_exit) { + char *token = strtok(NULL, g_parseExtraTokens); + + m_actionArgString = new char[strlen(token) + 1]; + strcpy(m_actionArgString, token); + + if (m_actionType != ExtraActionType_run) { + m_actionArgNumber = atoi(strtok(NULL, g_parseExtraTokens)); + } + } + } +} diff --git a/LEGO1/legoentity.h b/LEGO1/legoentity.h index fdfe997f..9fbbb5bb 100644 --- a/LEGO1/legoentity.h +++ b/LEGO1/legoentity.h @@ -2,6 +2,7 @@ #define LEGOENTITY_H #include "mxentity.h" +#include "extra.h" // VTABLE 0x100d4858 // SIZE 0x68 (probably) @@ -31,7 +32,16 @@ class LegoEntity : public MxEntity return !strcmp(name, LegoEntity::ClassName()) || MxEntity::IsA(name); } - virtual void Destroy() override; // vtable+0x1c + virtual void vtable18(); // vtable+0x18 + virtual void Destroy(); // vtable+0x1c + virtual void ParseAction(char *); // vtable+0x20 + +protected: + // For tokens from the extra string that look like this: + // "Action:openram;\lego\scripts\Race\CarRaceR;0" + ExtraActionType m_actionType; // 0x5c + char *m_actionArgString; // 0x60 + MxS32 m_actionArgNumber; // 0x64 }; diff --git a/LEGO1/legoinputmanager.h b/LEGO1/legoinputmanager.h index 3a35d4b1..56b77445 100644 --- a/LEGO1/legoinputmanager.h +++ b/LEGO1/legoinputmanager.h @@ -28,10 +28,22 @@ class LegoInputManager : public MxPresenter virtual MxResult Tickle() override; // vtable+0x8 - undefined m_pad40[0x15c]; + undefined m_pad40[0x48]; + + MxBool m_unk88; + undefined m_unk89[0x113]; + + // 0x19C int m_joystickIndex; - undefined m_pad200[0x194]; + + undefined m_pad1a0[0x194]; + + // 0x334 MxBool m_useJoystick; + + undefined m_unk335; + MxBool m_unk336; + undefined m_unk337; }; #endif // LEGOINPUTMANAGER_H diff --git a/LEGO1/legoomni.cpp b/LEGO1/legoomni.cpp index 0c84395e..bbc8258b 100644 --- a/LEGO1/legoomni.cpp +++ b/LEGO1/legoomni.cpp @@ -58,7 +58,7 @@ void MakeSourceName(char *p_output, const char *p_input) } // OFFSET: LEGO1 0x100b7050 -MxBool KeyValueStringParse(char *p_outputValue, char *p_key, char *p_source) +MxBool KeyValueStringParse(char *p_outputValue, const char *p_key, const char *p_source) { MxBool didMatch = FALSE; diff --git a/LEGO1/legoomni.h b/LEGO1/legoomni.h index be289769..4e772cae 100644 --- a/LEGO1/legoomni.h +++ b/LEGO1/legoomni.h @@ -21,6 +21,7 @@ #include "legoplantmanager.h" class LegoSoundManager; +class MxTransitionManager; // VTABLE 0x100d8638 // SIZE: 0x140 @@ -113,6 +114,6 @@ __declspec(dllexport) MxLong Start(MxDSAction *a); LegoBuildingManager* BuildingManager(); Isle* GetIsle(); LegoPlantManager* PlantManager(); -MxBool KeyValueStringParse(char *, char *, char *); +MxBool KeyValueStringParse(char *, const char *, const char *); #endif // LEGOOMNI_H diff --git a/LEGO1/legoutil.cpp b/LEGO1/legoutil.cpp index bac8f284..cd46c902 100644 --- a/LEGO1/legoutil.cpp +++ b/LEGO1/legoutil.cpp @@ -1,7 +1,38 @@ #include "legoutil.h" +#include "mxomni.h" #include "mxtypes.h" +#include + +// OFFSET: LEGO1 0x1003e300 +ExtraActionType MatchActionString(const char *p_str) { + ExtraActionType result = ExtraActionType_unknown; + + if (!strcmpi("openram", p_str)) + result = ExtraActionType_openram; + else if (!strcmpi("opendisk", p_str)) + result = ExtraActionType_opendisk; + else if (!strcmpi("close", p_str)) + result = ExtraActionType_close; + else if (!strcmpi("start", p_str)) + result = ExtraActionType_start; + else if (!strcmpi("stop", p_str)) + result = ExtraActionType_stop; + else if (!strcmpi("run", p_str)) + result = ExtraActionType_run; + else if (!strcmpi("exit", p_str)) + result = ExtraActionType_exit; + else if (!strcmpi("enable", p_str)) + result = ExtraActionType_enable; + else if (!strcmpi("disable", p_str)) + result = ExtraActionType_disable; + else if (!strcmpi("notify", p_str)) + result = ExtraActionType_notify; + + return result; +} + // OFFSET: LEGO1 0x1003eae0 void ConvertHSVToRGB(float h, float s, float v, float *r_out, float *b_out, float *g_out) { @@ -71,3 +102,9 @@ void ConvertHSVToRGB(float h, float s, float v, float *r_out, float *b_out, floa return; } } + +// OFFSET: LEGO1 0x1003ef40 +void SetAppCursor(WPARAM p_wparam) +{ + PostMessageA(MxOmni::GetInstance()->GetWindowHandle(), 0x5400, p_wparam, 0); +} diff --git a/LEGO1/legoutil.h b/LEGO1/legoutil.h index 6a0113e8..e912991d 100644 --- a/LEGO1/legoutil.h +++ b/LEGO1/legoutil.h @@ -1,6 +1,10 @@ #ifndef LEGOUTIL_H #define LEGOUTIL_H +#include + +#include "extra.h" + template inline T Abs(T p_t) { @@ -19,6 +23,8 @@ inline T Max(T p_t1, T p_t2) return p_t1 > p_t2 ? p_t1 : p_t2; } +ExtraActionType MatchActionString(const char *); void ConvertHSVToRGB(float r, float g, float b, float* out_r, float* out_g, float* out_b); +void SetAppCursor(WPARAM p_wparam); #endif // LEGOUTIL_H diff --git a/LEGO1/legovideomanager.h b/LEGO1/legovideomanager.h index 60f670fb..d71c39a1 100644 --- a/LEGO1/legovideomanager.h +++ b/LEGO1/legovideomanager.h @@ -23,6 +23,7 @@ class LegoVideoManager : public MxVideoManager inline MxDirect3D *GetDirect3D() { return this->m_direct3d; } void SetSkyColor(float r, float g, float b); + inline void SetUnkE4(MxBool p_value) { this->m_unke4 = p_value; } private: undefined4 m_unk64; @@ -30,6 +31,8 @@ class LegoVideoManager : public MxVideoManager undefined4 m_unk6c; undefined4 m_unk70; MxDirect3D *m_direct3d; + undefined m_pad78[0x6c]; + MxBool m_unke4; }; #endif // LEGOVIDEOMANAGER_H diff --git a/LEGO1/mxbackgroundaudiomanager.h b/LEGO1/mxbackgroundaudiomanager.h index c6f2f1e7..a2c4cae3 100644 --- a/LEGO1/mxbackgroundaudiomanager.h +++ b/LEGO1/mxbackgroundaudiomanager.h @@ -28,8 +28,9 @@ class MxBackgroundAudioManager : public MxCore } __declspec(dllexport) void Enable(unsigned char p); -private: + void Stop(); +private: void Init(); MxBool m_musicEnabled; // 0x8 diff --git a/LEGO1/mxdisplaysurface.h b/LEGO1/mxdisplaysurface.h index c76266d7..4c2c3866 100644 --- a/LEGO1/mxdisplaysurface.h +++ b/LEGO1/mxdisplaysurface.h @@ -33,6 +33,8 @@ class MxDisplaySurface : public MxCore virtual void ReleaseDC(HDC p_hdc); virtual undefined4 vtable44(undefined4, undefined4*, undefined4, undefined4); + inline LPDIRECTDRAWSURFACE GetDirectDrawSurface2() { return this->m_ddSurface2; } + private: MxVideoParam m_videoParam; LPDIRECTDRAWSURFACE m_ddSurface1; diff --git a/LEGO1/mxdsactionlist.h b/LEGO1/mxdsactionlist.h index fe0e162c..b75ceb72 100644 --- a/LEGO1/mxdsactionlist.h +++ b/LEGO1/mxdsactionlist.h @@ -34,4 +34,13 @@ typedef MxListCursorChild MxDSActionListCursor; // OFFSET: LEGO1 0x100c9d30 TEMPLATE // MxList::~MxList +// OFFSET: LEGO1 0x100c9d20 TEMPLATE +// MxListParent::Destroy + +// OFFSET: LEGO1 0x100c9cd0 TEMPLATE +// MxListParent::~MxListParent + +// OFFSET: LEGO1 0x100c9d30 TEMPLATE +// MxList::~MxList + #endif // MXDSACTIONLIST_H diff --git a/LEGO1/mxdsstreamingaction.cpp b/LEGO1/mxdsstreamingaction.cpp index ab04c19e..665f079e 100644 --- a/LEGO1/mxdsstreamingaction.cpp +++ b/LEGO1/mxdsstreamingaction.cpp @@ -1,4 +1,5 @@ #include "mxdsstreamingaction.h" +#include "mxdsbuffer.h" DECOMP_SIZE_ASSERT(MxDSStreamingAction, 0xb4) @@ -22,7 +23,6 @@ MxDSStreamingAction::MxDSStreamingAction(MxDSStreamingAction &p_dsStreamingActio // OFFSET: LEGO1 0x100cd150 MxDSStreamingAction::~MxDSStreamingAction() { - // TODO: Implement MxDSBuffer if (this->m_unka0) delete this->m_unka0; if (this->m_unka4) diff --git a/LEGO1/mxentity.cpp b/LEGO1/mxentity.cpp index 65adad67..54e854ab 100644 --- a/LEGO1/mxentity.cpp +++ b/LEGO1/mxentity.cpp @@ -1,6 +1,8 @@ #include "mxentity.h" -DECOMP_SIZE_ASSERT(MxEntity, 0x68) +// Size subject to change. It's not clear yet which members belong to +// MxEntity and which belong only the subclasses. +DECOMP_SIZE_ASSERT(MxEntity, 0x5c) // OFFSET: LEGO1 0x1001d190 MxEntity::MxEntity() diff --git a/LEGO1/mxentity.h b/LEGO1/mxentity.h index 25e74d1b..3d73292e 100644 --- a/LEGO1/mxentity.h +++ b/LEGO1/mxentity.h @@ -31,7 +31,7 @@ class MxEntity : public MxCore private: MxS32 m_mxEntityId; // 0x8 MxAtomId m_atom; // 0xc - undefined m_unk10[0x58]; + undefined m_unk10[76]; }; #endif // MXENTITY_H diff --git a/LEGO1/mxmidipresenter.h b/LEGO1/mxmidipresenter.h index 1cd65c4a..07fc55a2 100644 --- a/LEGO1/mxmidipresenter.h +++ b/LEGO1/mxmidipresenter.h @@ -8,6 +8,20 @@ class MxMIDIPresenter : public MxMusicPresenter { public: MxMIDIPresenter(); + + // OFFSET: LEGO1 0x100c2650 + inline virtual const char *ClassName() const override // vtable+0xc + { + // 0x10101df8 + return "MxMIDIPresenter"; + } + + // OFFSET: LEGO1 0x100c2660 + inline virtual MxBool IsA(const char *name) const override // vtable+0x10 + { + return !strcmp(name, MxMIDIPresenter::ClassName()) || MxMusicPresenter::IsA(name); + } + private: void Init(); undefined4 m_unk54; diff --git a/LEGO1/mxmusicpresenter.cpp b/LEGO1/mxmusicpresenter.cpp index 562f047c..d33627ad 100644 --- a/LEGO1/mxmusicpresenter.cpp +++ b/LEGO1/mxmusicpresenter.cpp @@ -1,7 +1,12 @@ #include "mxmusicpresenter.h" -// OFFSET: LEGO1 0x100c22c0 STUB +// OFFSET: LEGO1 0x100c22c0 MxMusicPresenter::MxMusicPresenter() { - // TODO + Init(); +} + +// OFFSET: LEGO1 0x100c2540 +void MxMusicPresenter::Init() +{ } \ No newline at end of file diff --git a/LEGO1/mxmusicpresenter.h b/LEGO1/mxmusicpresenter.h index e244b036..c8e88604 100644 --- a/LEGO1/mxmusicpresenter.h +++ b/LEGO1/mxmusicpresenter.h @@ -7,7 +7,23 @@ class MxMusicPresenter : public MxAudioPresenter { public: + // OFFSET: LEGO1 0x100c23a0 + inline virtual const char *ClassName() const override // vtable+0xc + { + // 0x10101e48 + return "MxMusicPresenter"; + } + + // OFFSET: LEGO1 0x100c23b0 + inline virtual MxBool IsA(const char *name) const override // vtable+0x10 + { + return !strcmp(name, MxMusicPresenter::ClassName()) || MxAudioPresenter::IsA(name); + } + MxMusicPresenter(); + +private: + void Init(); }; #endif // MXMUSICPRESENTER_H diff --git a/LEGO1/mxomni.cpp b/LEGO1/mxomni.cpp index 22cc2a70..200e5bdf 100644 --- a/LEGO1/mxomni.cpp +++ b/LEGO1/mxomni.cpp @@ -288,4 +288,4 @@ MxMusicManager* MusicManager() MxEventManager* EventManager() { return MxOmni::GetInstance()->GetEventManager(); -} +} \ No newline at end of file diff --git a/LEGO1/mxpresenter.cpp b/LEGO1/mxpresenter.cpp index 940248a0..b57af821 100644 --- a/LEGO1/mxpresenter.cpp +++ b/LEGO1/mxpresenter.cpp @@ -7,15 +7,10 @@ #include #include "decomp.h" +#include "define.h" DECOMP_SIZE_ASSERT(MxPresenter, 0x40); -// 0x10101eac -char *g_parseExtraTokens = ":;"; - -// 0x10101edc -char *g_strWORLD = "WORLD"; - // OFFSET: LEGO1 0x100b4d50 void MxPresenter::Init() { diff --git a/LEGO1/mxpresenterlist.h b/LEGO1/mxpresenterlist.h index 0ee54a85..68ffb77e 100644 --- a/LEGO1/mxpresenterlist.h +++ b/LEGO1/mxpresenterlist.h @@ -35,4 +35,13 @@ typedef MxListCursorChildChild MxPresenterListCursor; // OFFSET: LEGO1 0x1001ce20 TEMPLATE // MxList::~MxList +// OFFSET: LEGO1 0x1001cd30 TEMPLATE +// MxListParent::Destroy + +// OFFSET: LEGO1 0x1001cdd0 TEMPLATE +// MxListParent::~MxListParent + +// OFFSET: LEGO1 0x1001ce20 TEMPLATE +// MxList::~MxList + #endif // MXPRESENTERLIST_H diff --git a/LEGO1/mxstring.cpp b/LEGO1/mxstring.cpp index e2f24cab..e82d431a 100644 --- a/LEGO1/mxstring.cpp +++ b/LEGO1/mxstring.cpp @@ -1,7 +1,11 @@ #include "mxstring.h" +#include "decomp.h" + #include #include +DECOMP_SIZE_ASSERT(MxString, 0x10) + // OFFSET: LEGO1 0x100ae200 MxString::MxString() { diff --git a/LEGO1/mxtransitionmanager.cpp b/LEGO1/mxtransitionmanager.cpp index fdae06ea..12bd0931 100644 --- a/LEGO1/mxtransitionmanager.cpp +++ b/LEGO1/mxtransitionmanager.cpp @@ -1,4 +1,8 @@ #include "mxtransitionmanager.h" +#include "legoutil.h" +#include "legovideomanager.h" + +DECOMP_SIZE_ASSERT(MxTransitionManager, 0x900); // OFFSET: LEGO1 0x1004b8d0 STUB MxTransitionManager::MxTransitionManager() @@ -25,3 +29,47 @@ void MxTransitionManager::SetWaitIndicator(MxVideoPresenter *videoPresenter) { // TODO } + +// OFFSET: LEGO1 0x1004baa0 +MxResult MxTransitionManager::GetDDrawSurfaceFromVideoManager() // vtable+0x14 +{ + LegoVideoManager *videoManager = VideoManager(); + this->m_ddSurface = videoManager->GetDisplaySurface()->GetDirectDrawSurface2(); + return SUCCESS; +} + +// OFFSET: LEGO1 0x1004bb70 +MxResult MxTransitionManager::StartTransition(TransitionType p_animationType, MxS32 p_speed, + undefined p_unk, MxBool p_playMusicInAnim) +{ + // TODO: Incomplete and far from matching + + if (this->m_transitionType == NOT_TRANSITIONING) { + if (!p_playMusicInAnim) { + MxBackgroundAudioManager *backgroundAudioManager = BackgroundAudioManager(); + backgroundAudioManager->Stop(); + } + this->m_transitionType = p_animationType; + + // TODO: This part of the function is mangled and I can't make out what it's doing right now + + MxU32 time = timeGetTime(); + this->m_systemTime = time; + + this->m_animationSpeed = p_speed; + + MxTickleManager *tickleManager = TickleManager(); + tickleManager->RegisterClient(this, p_speed); + + LegoInputManager *inputManager = InputManager(); + inputManager->m_unk88 = TRUE; + inputManager->m_unk336 = FALSE; + + LegoVideoManager *videoManager = VideoManager(); + videoManager->SetUnkE4(FALSE); + + SetAppCursor(1); + return SUCCESS; + } + return FAILURE; +} \ No newline at end of file diff --git a/LEGO1/mxtransitionmanager.h b/LEGO1/mxtransitionmanager.h index 215cd2d7..1b662e98 100644 --- a/LEGO1/mxtransitionmanager.h +++ b/LEGO1/mxtransitionmanager.h @@ -2,10 +2,10 @@ #define MXTRANSITIONMANAGER_H #include "mxcore.h" +#include "mxvideopresenter.h" +#include "legoomni.h" -class MxVideoPresenter; - -// 0x100d7ea0 +// VTABLE 0x100d7ea0 class MxTransitionManager : public MxCore { public: @@ -15,6 +15,42 @@ class MxTransitionManager : public MxCore __declspec(dllexport) void SetWaitIndicator(MxVideoPresenter *videoPresenter); virtual MxResult Tickle(); // vtable+0x8 + + // OFFSET: LEGO1 0x1004b950 + inline virtual const char *ClassName() const override // vtable+0x0c + { + return "MxTransitionManager"; + } + + // OFFSET: LEGO1 0x1004b960 + inline virtual MxBool IsA(const char *name) const override // vtable+0x10 + { + return !strcmp(name, MxTransitionManager::ClassName()) || MxCore::IsA(name); + } + + virtual MxResult GetDDrawSurfaceFromVideoManager(); // vtable+0x14 + + enum TransitionType { + NOT_TRANSITIONING, + NO_ANIMATION, + DISSOLVE, + PIXELATION, + SCREEN_WIPE, + WINDOWS, + BROKEN // Unknown what this is supposed to be, it locks the game up + }; + + MxResult StartTransition(TransitionType p_animationType, MxS32 p_speed, undefined p_unk, MxBool p_playMusicInAnim); + +private: + undefined m_pad00[0x20]; + undefined m_pad20[0x04]; + TransitionType m_transitionType; + LPDIRECTDRAWSURFACE m_ddSurface; + MxU16 m_animationTimer; + undefined m_pad36[0x8c2]; + MxULong m_systemTime; + MxS32 m_animationSpeed; }; #endif // MXTRANSITIONMANAGER_H diff --git a/LEGO1/mxvideomanager.h b/LEGO1/mxvideomanager.h index 4068b793..7888f7e7 100644 --- a/LEGO1/mxvideomanager.h +++ b/LEGO1/mxvideomanager.h @@ -26,6 +26,7 @@ class MxVideoManager : public MxMediaManager inline MxVideoParam& GetVideoParam() { return this->m_videoParam; } inline LPDIRECTDRAW GetDirectDraw() { return this->m_pDirectDraw; } + inline MxDisplaySurface *GetDisplaySurface() { return this->m_displaySurface; } private: MxVideoParam m_videoParam; LPDIRECTDRAW m_pDirectDraw;