From 0ab8fc52d2eecd029a1d420b204e7ed35e5ae0b5 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Tue, 20 Jun 2023 02:18:53 +0200 Subject: [PATCH] lego1/isle: Add MxDSObject, implement SetObjectName, adjust MxDSAction (#20) * add MxDSObject, implement SetObjectName, adjust MxDSAction * add a TODO * update project files * add WIP MxDSObject stuff * merge * update project file * add addresses and SetAtomId * switch addresses * remove comment since it's fixed now (?) * refactor * update project file * refactor into separate unit * refactor into separate unit * rename unit to avoid NMAKE issue * rename param * add last missing piece to Isle::Close * fix spelling * merge * use union hack --- ISLE/isle.cpp | 16 ++-- ISLE/mx.cpp | 7 ++ LEGO1/lego3dmanager.h | 0 LEGO1/lego3dview.h | 0 LEGO1/mxatomid.cpp | 14 ++++ LEGO1/mxatomid.h | 7 +- LEGO1/mxdsaction.h | 21 +---- LEGO1/mxdsobject.cpp | 45 +++++++++++ LEGO1/mxdsobject.h | 33 +++++++- isle.mak | 178 +++++++++++++++++++++++++++++++++++++++++- isle.mdp | Bin 48128 -> 50688 bytes 11 files changed, 291 insertions(+), 30 deletions(-) create mode 100644 ISLE/mx.cpp mode change 100755 => 100644 LEGO1/lego3dmanager.h mode change 100755 => 100644 LEGO1/lego3dview.h create mode 100644 LEGO1/mxatomid.cpp create mode 100644 LEGO1/mxdsobject.cpp diff --git a/ISLE/isle.cpp b/ISLE/isle.cpp index 3517cb78..5e9e1ec4 100644 --- a/ISLE/isle.cpp +++ b/ISLE/isle.cpp @@ -84,6 +84,7 @@ Isle::~Isle() void Isle::Close() { MxDSAction ds; + ds.SetUnknown24(0xFFFE); if (Lego()) { GameState()->Save(0); @@ -93,8 +94,7 @@ void Isle::Close() VideoManager()->Get3DManager()->GetLego3DView()->GetViewManager()->RemoveAll(NULL); - long local_88 = 0; - Lego()->RemoveWorld(ds.m_atomId, local_88); + Lego()->RemoveWorld(ds.GetAtomId(), ds.GetUnknown1c()); Lego()->vtable24(ds); TransitionManager()->SetWaitIndicator(NULL); Lego()->vtable3c(); @@ -608,18 +608,18 @@ void Isle::Tick(BOOL sleepIfNotNextFrame) return; } - ds.setAtomId(stream->atom); - ds.m_unk24 = 0xFFFF; - ds.m_unk1c = 0; + ds.SetAtomId(stream->atom); + ds.SetUnknown24(0xFFFF); + ds.SetUnknown1c(0); VideoManager()->EnableFullScreenMovie(TRUE, TRUE); if (Start(&ds) != SUCCESS) { return; } } else { - ds.setAtomId(stream->atom); - ds.m_unk24 = 0xFFFF; - ds.m_unk1c = 0; + ds.SetAtomId(stream->atom); + ds.SetUnknown24(0xFFFF); + ds.SetUnknown1c(0); if (Start(&ds) != SUCCESS) { return; } diff --git a/ISLE/mx.cpp b/ISLE/mx.cpp new file mode 100644 index 00000000..c0417e5a --- /dev/null +++ b/ISLE/mx.cpp @@ -0,0 +1,7 @@ +#include "mxdsobject.h" + +// OFFSET: ISLE 0x00401c40 +void MxDSObject::SetAtomId(MxAtomId p_atomId) +{ + this->m_atomId = p_atomId; +} \ No newline at end of file diff --git a/LEGO1/lego3dmanager.h b/LEGO1/lego3dmanager.h old mode 100755 new mode 100644 diff --git a/LEGO1/lego3dview.h b/LEGO1/lego3dview.h old mode 100755 new mode 100644 diff --git a/LEGO1/mxatomid.cpp b/LEGO1/mxatomid.cpp new file mode 100644 index 00000000..f2171360 --- /dev/null +++ b/LEGO1/mxatomid.cpp @@ -0,0 +1,14 @@ +#include "mxatomid.h" + +// OFFSET: LEGO1 0x100acfd0 +MxAtomId::~MxAtomId() +{ + // TODO +} + +// OFFSET: LEGO1 0x100ad1c0 +MxAtomId &MxAtomId::operator=(const MxAtomId &id) +{ + // TODO + return *this; +} \ No newline at end of file diff --git a/LEGO1/mxatomid.h b/LEGO1/mxatomid.h index 537b097e..b28704c0 100644 --- a/LEGO1/mxatomid.h +++ b/LEGO1/mxatomid.h @@ -12,8 +12,13 @@ class MxAtomId __declspec(dllexport) MxAtomId &operator=(const MxAtomId &id); __declspec(dllexport) ~MxAtomId(); - char *m_internal; + MxAtomId() + { + this->m_internal = 0; + }; +private: + char *m_internal; }; #endif // MXATOMID_H diff --git a/LEGO1/mxdsaction.h b/LEGO1/mxdsaction.h index aa5a7e4b..558cd035 100644 --- a/LEGO1/mxdsaction.h +++ b/LEGO1/mxdsaction.h @@ -1,25 +1,14 @@ #ifndef MXDSACTION_H #define MXDSACTION_H -#include "mxatomid.h" +#include "mxdsobject.h" -class MxDSAction +class MxDSAction : public MxDSObject { public: __declspec(dllexport) MxDSAction(); __declspec(dllexport) virtual ~MxDSAction(); - int m_unk04; - int m_unk08; - int m_unk0c; - int m_unk10; - int m_unk14; - int m_unk18; - int m_unk1c; - MxAtomId m_atomId; - unsigned short m_unk24; - unsigned short m_unk26; - int m_unk28; int m_unk2c; int m_unk30; int m_unk34; @@ -46,12 +35,6 @@ class MxDSAction int m_unk88; int m_unk8c; int m_unk90; - - void setAtomId(MxAtomId &atomId) - { - this->m_atomId = atomId; - } - }; #endif // MXDSACTION_H diff --git a/LEGO1/mxdsobject.cpp b/LEGO1/mxdsobject.cpp new file mode 100644 index 00000000..5e7d7103 --- /dev/null +++ b/LEGO1/mxdsobject.cpp @@ -0,0 +1,45 @@ +#include "mxdsobject.h" + +#include +#include + +// OFFSET: LEGO1 0x100bf6a0 +MxDSObject::MxDSObject() +{ + // The following code yields 100% matching assembly if m_unk24 is declared as (signed) short. + // However, in other areas m_unk24 (notably, ISLE.EXE) is treated as unsigned short. + // Since we don't have a proper solution yet, we are using a union to work around this discrepancy. + this->m_unk0c = 0; + this->m_unk10 = 0; + this->m_unk14 = 0; + this->m_name = NULL; + this->m_unk24signed = -1; + this->m_unk1c = -1; + this->m_unk28 = 0; +} + +// OFFSET: LEGO1 0x100bf8e0 +void MxDSObject::SetObjectName(const char *p_name) +{ + if (p_name != this->m_name) + { + free(this->m_name); + + if (p_name) { + this->m_name = (char *)malloc(strlen(p_name) + 1); + + if (this->m_name) { + strcpy(this->m_name, p_name); + } + } + else { + this->m_name = NULL; + } + } +} + +// OFFSET: LEGO1 0x10005530 +void MxDSObject::SetAtomId(MxAtomId p_atomId) +{ + this->m_atomId = p_atomId; +} diff --git a/LEGO1/mxdsobject.h b/LEGO1/mxdsobject.h index 05ee1fd0..99c62dd2 100644 --- a/LEGO1/mxdsobject.h +++ b/LEGO1/mxdsobject.h @@ -1,10 +1,41 @@ #ifndef MXDSOBJECT_H #define MXDSOBJECT_H -class MxDSObject +#include "mxcore.h" +#include "mxatomid.h" + +class MxDSObject : public MxCore { public: __declspec(dllexport) void SetObjectName(const char *); + + MxDSObject(); + + inline const MxAtomId& GetAtomId() { return this->m_atomId; } + inline int GetUnknown1c() { return this->m_unk1c; } + + inline void SetUnknown1c(int p_unk1c) { this->m_unk1c = p_unk1c; } + inline void SetUnknown24(unsigned short p_unk24) { this->m_unk24 = p_unk24; } + + void SetAtomId(MxAtomId p_atomId); + +private: + int m_unk08; + short m_unk0c; + char* m_unk10; + int m_unk14; + char *m_name; + int m_unk1c; + MxAtomId m_atomId; + // So far, implementing MxDSObject::MxDSObject correctly required that m_unk24 is declared a (signed) short. + // Most of the other game's code appears to treat it as unsigned short, however. + // This union is a workaround until we have figured this out. + union { + unsigned short m_unk24; + short m_unk24signed; + }; + unsigned short m_unk26; + int m_unk28; }; #endif // MXDSOBJECT_H diff --git a/isle.mak b/isle.mak index fea5a64e..f0f905ff 100644 --- a/isle.mak +++ b/isle.mak @@ -57,9 +57,11 @@ CLEAN : -@erase "$(INTDIR)\dllmain.obj" -@erase "$(INTDIR)\legonavcontroller.obj" -@erase "$(INTDIR)\legoomni.obj" + -@erase "$(INTDIR)\mxatomid.obj" -@erase "$(INTDIR)\mxautolocker.obj" -@erase "$(INTDIR)\mxcore.obj" -@erase "$(INTDIR)\mxcriticalsection.obj" + -@erase "$(INTDIR)\mxdsobject.obj" -@erase "$(INTDIR)\mxomni.obj" -@erase "$(INTDIR)\mxomnicreateflags.obj" -@erase "$(INTDIR)\mxomnicreateparam.obj" @@ -129,9 +131,11 @@ LINK32_OBJS= \ "$(INTDIR)\dllmain.obj" \ "$(INTDIR)\legonavcontroller.obj" \ "$(INTDIR)\legoomni.obj" \ + "$(INTDIR)\mxatomid.obj" \ "$(INTDIR)\mxautolocker.obj" \ "$(INTDIR)\mxcore.obj" \ "$(INTDIR)\mxcriticalsection.obj" \ + "$(INTDIR)\mxdsobject.obj" \ "$(INTDIR)\mxomni.obj" \ "$(INTDIR)\mxomnicreateflags.obj" \ "$(INTDIR)\mxomnicreateparam.obj" \ @@ -167,9 +171,11 @@ CLEAN : -@erase "$(INTDIR)\dllmain.obj" -@erase "$(INTDIR)\legonavcontroller.obj" -@erase "$(INTDIR)\legoomni.obj" + -@erase "$(INTDIR)\mxatomid.obj" -@erase "$(INTDIR)\mxautolocker.obj" -@erase "$(INTDIR)\mxcore.obj" -@erase "$(INTDIR)\mxcriticalsection.obj" + -@erase "$(INTDIR)\mxdsobject.obj" -@erase "$(INTDIR)\mxomni.obj" -@erase "$(INTDIR)\mxomnicreateflags.obj" -@erase "$(INTDIR)\mxomnicreateparam.obj" @@ -241,9 +247,11 @@ LINK32_OBJS= \ "$(INTDIR)\dllmain.obj" \ "$(INTDIR)\legonavcontroller.obj" \ "$(INTDIR)\legoomni.obj" \ + "$(INTDIR)\mxatomid.obj" \ "$(INTDIR)\mxautolocker.obj" \ "$(INTDIR)\mxcore.obj" \ "$(INTDIR)\mxcriticalsection.obj" \ + "$(INTDIR)\mxdsobject.obj" \ "$(INTDIR)\mxomni.obj" \ "$(INTDIR)\mxomnicreateflags.obj" \ "$(INTDIR)\mxomnicreateparam.obj" \ @@ -280,6 +288,7 @@ CLEAN : -@erase "$(INTDIR)\isle.obj" -@erase "$(INTDIR)\isle.res" -@erase "$(INTDIR)\main.obj" + -@erase "$(INTDIR)\mx.obj" -@erase "$(INTDIR)\vc40.pdb" -@erase ".\Release\ISLE.EXE" -@erase ".\Release\ISLE.PDB" @@ -341,6 +350,7 @@ LINK32_OBJS= \ "$(INTDIR)\isle.obj" \ "$(INTDIR)\isle.res" \ "$(INTDIR)\main.obj" \ + "$(INTDIR)\mx.obj" \ ".\Release\LEGO1.LIB" ".\Release\ISLE.EXE" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) @@ -370,6 +380,7 @@ CLEAN : -@erase "$(INTDIR)\isle.obj" -@erase "$(INTDIR)\isle.res" -@erase "$(INTDIR)\main.obj" + -@erase "$(INTDIR)\mx.obj" -@erase "$(INTDIR)\vc40.idb" -@erase "$(INTDIR)\vc40.pdb" -@erase ".\Debug\ISLE.EXE" @@ -433,6 +444,7 @@ LINK32_OBJS= \ "$(INTDIR)\isle.obj" \ "$(INTDIR)\isle.res" \ "$(INTDIR)\main.obj" \ + "$(INTDIR)\mx.obj" \ ".\LEGO1\Debug\LEGO1.lib" ".\Debug\ISLE.EXE" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) @@ -620,7 +632,7 @@ DEP_CPP_MXOMN=\ SOURCE=.\LEGO1\mxvideoparam.cpp DEP_CPP_MXVID=\ - ".\LEGO1\mxbool.h"\ + ".\LEGO1\legoinc.h"\ ".\LEGO1\mxpalette.h"\ ".\LEGO1\mxrect32.h"\ ".\LEGO1\mxvariabletable.h"\ @@ -638,6 +650,7 @@ DEP_CPP_MXVID=\ SOURCE=.\LEGO1\mxvideoparamflags.cpp DEP_CPP_MXVIDE=\ + ".\LEGO1\legoinc.h"\ ".\LEGO1\mxvideoparamflags.h"\ @@ -651,6 +664,7 @@ DEP_CPP_MXVIDE=\ SOURCE=.\LEGO1\mxomnicreateparam.cpp DEP_CPP_MXOMNI=\ + ".\LEGO1\legoinc.h"\ ".\LEGO1\mxbool.h"\ ".\LEGO1\mxcore.h"\ ".\LEGO1\mxomnicreateflags.h"\ @@ -674,6 +688,7 @@ DEP_CPP_MXOMNI=\ SOURCE=.\LEGO1\mxomnicreateparambase.cpp DEP_CPP_MXOMNIC=\ + ".\LEGO1\legoinc.h"\ ".\LEGO1\mxbool.h"\ ".\LEGO1\mxcore.h"\ ".\LEGO1\mxomnicreateflags.h"\ @@ -775,6 +790,35 @@ DEP_CPP_LEGON=\ $(CPP) $(CPP_PROJ) $(SOURCE) +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\LEGO1\mxdsobject.cpp +DEP_CPP_MXDSO=\ + ".\LEGO1\mxatomid.h"\ + ".\LEGO1\mxbool.h"\ + ".\LEGO1\mxcore.h"\ + ".\LEGO1\mxdsobject.h"\ + + +"$(INTDIR)\mxdsobject.obj" : $(SOURCE) $(DEP_CPP_MXDSO) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\LEGO1\mxatomid.cpp +DEP_CPP_MXATO=\ + ".\LEGO1\mxatomid.h"\ + + +"$(INTDIR)\mxatomid.obj" : $(SOURCE) $(DEP_CPP_MXATO) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + # End Source File # End Target ################################################################################ @@ -806,6 +850,9 @@ DEP_CPP_DEFIN=\ # Begin Source File SOURCE=.\ISLE\isle.cpp + +!IF "$(CFG)" == "ISLE - Win32 Release" + DEP_CPP_ISLE_=\ ".\ISLE\define.h"\ ".\ISLE\isle.h"\ @@ -816,6 +863,7 @@ DEP_CPP_ISLE_=\ ".\LEGO1\legobuildingmanager.h"\ ".\LEGO1\legoentity.h"\ ".\LEGO1\legogamestate.h"\ + ".\LEGO1\legoinc.h"\ ".\LEGO1\legoinputmanager.h"\ ".\LEGO1\legomodelpresenter.h"\ ".\LEGO1\legonavcontroller.h"\ @@ -862,11 +910,72 @@ DEP_CPP_ISLE_=\ $(CPP) $(CPP_PROJ) $(SOURCE) +!ELSEIF "$(CFG)" == "ISLE - Win32 Debug" + +DEP_CPP_ISLE_=\ + ".\ISLE\define.h"\ + ".\ISLE\isle.h"\ + ".\ISLE\res\resource.h"\ + ".\LEGO1\lego3dmanager.h"\ + ".\LEGO1\lego3dview.h"\ + ".\LEGO1\legoanimationmanager.h"\ + ".\LEGO1\legobuildingmanager.h"\ + ".\LEGO1\legoentity.h"\ + ".\LEGO1\legogamestate.h"\ + ".\LEGO1\legoinc.h"\ + ".\LEGO1\legoinputmanager.h"\ + ".\LEGO1\legomodelpresenter.h"\ + ".\LEGO1\legonavcontroller.h"\ + ".\LEGO1\legoomni.h"\ + ".\LEGO1\legopartpresenter.h"\ + ".\LEGO1\legoroi.h"\ + ".\LEGO1\legovideomanager.h"\ + ".\LEGO1\legoworldpresenter.h"\ + ".\LEGO1\mxatomid.h"\ + ".\LEGO1\mxbackgroundaudiomanager.h"\ + ".\LEGO1\mxbool.h"\ + ".\LEGO1\mxcore.h"\ + ".\LEGO1\mxcriticalsection.h"\ + ".\LEGO1\mxdirectdraw.h"\ + ".\LEGO1\mxdsaction.h"\ + ".\LEGO1\mxdsfile.h"\ + ".\LEGO1\mxdsobject.h"\ + ".\LEGO1\mxeventmanager.h"\ + ".\LEGO1\mxmusicmanager.h"\ + ".\LEGO1\mxnotificationmanager.h"\ + ".\LEGO1\mxobjectfactory.h"\ + ".\LEGO1\mxomni.h"\ + ".\LEGO1\mxomnicreateflags.h"\ + ".\LEGO1\mxomnicreateparam.h"\ + ".\LEGO1\mxomnicreateparambase.h"\ + ".\LEGO1\mxresult.h"\ + ".\LEGO1\mxsoundmanager.h"\ + ".\LEGO1\mxstreamcontroller.h"\ + ".\LEGO1\mxstreamer.h"\ + ".\LEGO1\mxstring.h"\ + ".\LEGO1\mxticklemanager.h"\ + ".\LEGO1\mxtimer.h"\ + ".\LEGO1\mxtransitionmanager.h"\ + ".\LEGO1\mxvariabletable.h"\ + ".\LEGO1\mxvideomanager.h"\ + ".\LEGO1\mxvideoparam.h"\ + ".\LEGO1\viewmanager.h"\ + + +"$(INTDIR)\isle.obj" : $(SOURCE) $(DEP_CPP_ISLE_) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + # End Source File ################################################################################ # Begin Source File SOURCE=.\ISLE\main.cpp + +!IF "$(CFG)" == "ISLE - Win32 Release" + DEP_CPP_MAIN_=\ ".\ISLE\define.h"\ ".\ISLE\isle.h"\ @@ -917,6 +1026,57 @@ DEP_CPP_MAIN_=\ $(CPP) $(CPP_PROJ) $(SOURCE) +!ELSEIF "$(CFG)" == "ISLE - Win32 Debug" + +DEP_CPP_MAIN_=\ + ".\ISLE\define.h"\ + ".\ISLE\isle.h"\ + ".\LEGO1\lego3dmanager.h"\ + ".\LEGO1\lego3dview.h"\ + ".\LEGO1\legoentity.h"\ + ".\LEGO1\legogamestate.h"\ + ".\LEGO1\legoinc.h"\ + ".\LEGO1\legoinputmanager.h"\ + ".\LEGO1\legonavcontroller.h"\ + ".\LEGO1\legoomni.h"\ + ".\LEGO1\legoroi.h"\ + ".\LEGO1\legovideomanager.h"\ + ".\LEGO1\mxatomid.h"\ + ".\LEGO1\mxbackgroundaudiomanager.h"\ + ".\LEGO1\mxbool.h"\ + ".\LEGO1\mxcore.h"\ + ".\LEGO1\mxcriticalsection.h"\ + ".\LEGO1\mxdsaction.h"\ + ".\LEGO1\mxdsfile.h"\ + ".\LEGO1\mxdsobject.h"\ + ".\LEGO1\mxeventmanager.h"\ + ".\LEGO1\mxmusicmanager.h"\ + ".\LEGO1\mxnotificationmanager.h"\ + ".\LEGO1\mxobjectfactory.h"\ + ".\LEGO1\mxomni.h"\ + ".\LEGO1\mxomnicreateflags.h"\ + ".\LEGO1\mxomnicreateparam.h"\ + ".\LEGO1\mxomnicreateparambase.h"\ + ".\LEGO1\mxresult.h"\ + ".\LEGO1\mxsoundmanager.h"\ + ".\LEGO1\mxstreamcontroller.h"\ + ".\LEGO1\mxstreamer.h"\ + ".\LEGO1\mxstring.h"\ + ".\LEGO1\mxticklemanager.h"\ + ".\LEGO1\mxtimer.h"\ + ".\LEGO1\mxtransitionmanager.h"\ + ".\LEGO1\mxvariabletable.h"\ + ".\LEGO1\mxvideomanager.h"\ + ".\LEGO1\mxvideoparam.h"\ + ".\LEGO1\viewmanager.h"\ + + +"$(INTDIR)\main.obj" : $(SOURCE) $(DEP_CPP_MAIN_) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + # End Source File ################################################################################ # Begin Source File @@ -1357,6 +1517,22 @@ SOURCE=.\LEGO1\mxvideoparamflags.h !ENDIF # End Project Dependency +################################################################################ +# Begin Source File + +SOURCE=.\ISLE\mx.cpp +DEP_CPP_MX_CP=\ + ".\LEGO1\mxatomid.h"\ + ".\LEGO1\mxbool.h"\ + ".\LEGO1\mxcore.h"\ + ".\LEGO1\mxdsobject.h"\ + + +"$(INTDIR)\mx.obj" : $(SOURCE) $(DEP_CPP_MX_CP) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File # End Target # End Project ################################################################################ diff --git a/isle.mdp b/isle.mdp index f31e19c58e9a2653cf5210cbf3d5aeac9fd27672..e164ac1ec45b5477842f4919ab402efe54cf7ffe 100644 GIT binary patch literal 50688 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