From f157f01f71bda8ffe96b8f884d3954f358e01368 Mon Sep 17 00:00:00 2001 From: Ramen2X Date: Thu, 28 Mar 2024 10:27:44 -0400 Subject: [PATCH 01/17] implement/match UpdateLightPosition() (#744) --- LEGO1/lego/legoomni/include/legoutils.h | 2 +- LEGO1/lego/legoomni/src/common/legoutils.cpp | 34 +++++++++++++++++--- LEGO1/lego/legoomni/src/worlds/isle.cpp | 4 +-- 3 files changed, 33 insertions(+), 7 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoutils.h b/LEGO1/lego/legoomni/include/legoutils.h index cf8e57ea..5d495665 100644 --- a/LEGO1/lego/legoomni/include/legoutils.h +++ b/LEGO1/lego/legoomni/include/legoutils.h @@ -25,7 +25,7 @@ void FUN_1003ef00(MxBool); void SetAppCursor(WPARAM p_wparam); MxBool FUN_1003ef60(); MxBool RemoveFromWorld(MxAtomId& p_entityAtom, MxS32 p_entityId, MxAtomId& p_worldAtom, MxS32 p_worldEntityId); -MxS32 FUN_1003f050(MxS32); +MxS32 UpdateLightPosition(MxS32 p_value); void SetLightPosition(MxU32); LegoNamedTexture* ReadNamedTexture(LegoFile* p_file); void FUN_1003f540(LegoFile* p_file, const char* p_filename); diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp index fc0585f6..8491f736 100644 --- a/LEGO1/lego/legoomni/src/common/legoutils.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -339,11 +339,37 @@ MxBool FUN_1003ef60() return FALSE; } -// STUB: LEGO1 0x1003f050 -MxS32 FUN_1003f050(MxS32) +// FUNCTION: LEGO1 0x1003f050 +MxS32 UpdateLightPosition(MxS32 p_value) { - // TODO - return 0; + // This function updates the light position + // relatively by the amount passed in p_value. + // Because it operates relatively, it does not set + // the light position to an arbitrary value. + + MxS32 lightPosition = atoi(VariableTable()->GetVariable("lightposition")); + + if (p_value > 0) { + lightPosition += 1; + if (lightPosition > 5) { + lightPosition = 5; + } + } + else { + lightPosition -= 1; + if (lightPosition < 0) { + lightPosition = 0; + } + } + + SetLightPosition(lightPosition); + + char lightPositionBuffer[32]; + sprintf(lightPositionBuffer, "%d", lightPosition); + + VariableTable()->SetVariable("lightposition", lightPositionBuffer); + + return lightPosition; } // STUB: LEGO1 0x1003f0d0 diff --git a/LEGO1/lego/legoomni/src/worlds/isle.cpp b/LEGO1/lego/legoomni/src/worlds/isle.cpp index cf692fd9..bf5f85a8 100644 --- a/LEGO1/lego/legoomni/src/worlds/isle.cpp +++ b/LEGO1/lego/legoomni/src/worlds/isle.cpp @@ -399,11 +399,11 @@ MxLong Isle::HandleClick(LegoControlManagerEvent& p_param) FUN_10031590(); break; case IsleScript::c_Observe_GlobeLArrow_Ctl: - FUN_1003f050(-1); + UpdateLightPosition(-1); FUN_10031590(); break; case IsleScript::c_Observe_GlobeRArrow_Ctl: - FUN_1003f050(1); + UpdateLightPosition(1); FUN_10031590(); break; case IsleScript::c_Observe_Draw1_Ctl: From e4570b520b97348dc8705469cc5431b61a0138ff Mon Sep 17 00:00:00 2001 From: MS Date: Thu, 28 Mar 2024 14:15:39 -0400 Subject: [PATCH 02/17] Define g_characters (#743) * Define g_characters * Update with known struct types --- .../legoomni/include/legoanimationmanager.h | 19 +++--- .../src/common/legoanimationmanager.cpp | 61 ++++++++++++++++++- 2 files changed, 70 insertions(+), 10 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoanimationmanager.h b/LEGO1/lego/legoomni/include/legoanimationmanager.h index 15a05c8d..2254f744 100644 --- a/LEGO1/lego/legoomni/include/legoanimationmanager.h +++ b/LEGO1/lego/legoomni/include/legoanimationmanager.h @@ -10,13 +10,18 @@ // SIZE 0x18 struct Character { - char* m_name; // 0x00 - undefined m_unk0x04; // 0x04 - MxS8 m_vehicleId; // 0x05 - undefined m_unk0x06; // 0x06 - MxBool m_unk0x07; // 0x07 - undefined m_unk0x08[12]; // 0x08 - MxBool m_active; // 0x14 + char* m_name; // 0x00 + MxBool m_unk0x04; // 0x04 + MxS8 m_vehicleId; // 0x05 + undefined m_unk0x06; // 0x06 (unused?) + MxBool m_unk0x07; // 0x07 + MxBool m_unk0x08; // 0x08 + MxBool m_unk0x09; // 0x09 + MxU32 m_unk0x0c; // 0x0c + MxU32 m_unk0x10; // 0x10 + MxBool m_active; // 0x14 + MxU8 m_unk0x15; // 0x15 + MxU8 m_unk0x16; // 0x16 }; // SIZE 0x08 diff --git a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp index 0b1dd6d9..c48f1c97 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp @@ -15,11 +15,66 @@ DECOMP_SIZE_ASSERT(Vehicle, 0x8) DECOMP_SIZE_ASSERT(Unknown0x3c, 0x18) // GLOBAL: LEGO1 0x100f6d20 -Vehicle g_vehicles[] = {"bikebd", 0, FALSE, "bikepg", 0, FALSE, "bikerd", 0, FALSE, "bikesy", 0, - FALSE, "motoni", 0, FALSE, "motola", 0, FALSE, "board", 0, FALSE}; +Vehicle g_vehicles[] = { + {"bikebd", 0, FALSE}, + {"bikepg", 0, FALSE}, + {"bikerd", 0, FALSE}, + {"bikesy", 0, FALSE}, + {"motoni", 0, FALSE}, + {"motola", 0, FALSE}, + {"board", 0, FALSE} +}; // GLOBAL: LEGO1 0x100f7048 -Character g_characters[47]; // TODO: Initialize this +Character g_characters[47] = { + {"pepper", FALSE, 6, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 50, 1}, + {"mama", FALSE, -1, 0, FALSE, FALSE, FALSE, 1500, 20000, FALSE, 0, 2}, + {"papa", FALSE, -1, 0, FALSE, FALSE, FALSE, 1500, 20000, FALSE, 0, 3}, + {"nick", FALSE, 4, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 20, 4}, + {"laura", FALSE, 5, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 20, 5}, + {"brickstr", FALSE, -1, 0, FALSE, FALSE, FALSE, 1000, 20000, FALSE, 0, 6}, + {"studs", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"rhoda", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"valerie", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"snap", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"pt", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"mg", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"bu", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"ml", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"nu", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"na", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"cl", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"en", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"re", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"ro", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"d1", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"d2", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"d3", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"d4", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"l1", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"l2", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"l3", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"l4", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"l5", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"l6", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"b1", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"b2", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"b3", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"b4", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"cm", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"gd", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"rd", FALSE, 2, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 50, 9}, + {"pg", FALSE, 1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 50, 8}, + {"bd", FALSE, 0, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 100, 7}, + {"sy", FALSE, 3, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 100, 10}, + {"gn", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"df", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"bs", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"lt", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"st", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"bm", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0}, + {"jk", FALSE, -1, 0, FALSE, FALSE, TRUE, 1500, 20000, FALSE, 0, 0} +}; // GLOBAL: LEGO1 0x100f74f8 MxS32 g_legoAnimationManagerConfig = 1; From 5e10e010143c0f45d27dbc388aeb8605056c8d18 Mon Sep 17 00:00:00 2001 From: Ramen2X Date: Thu, 28 Mar 2024 17:03:51 -0400 Subject: [PATCH 03/17] implement/match ReadNamedTexture() (#745) --- LEGO1/lego/legoomni/src/common/legoutils.cpp | 23 ++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp index 8491f736..be85e1f6 100644 --- a/LEGO1/lego/legoomni/src/common/legoutils.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -377,10 +377,29 @@ void SetLightPosition(MxU32) { } -// STUB: LEGO1 0x1003f3b0 +// FUNCTION: LEGO1 0x1003f3b0 LegoNamedTexture* ReadNamedTexture(LegoFile* p_file) { - return NULL; + LegoTexture* texture = NULL; + LegoNamedTexture* namedTexture = NULL; + MxString string; + + p_file->ReadString(string); + + texture = new LegoTexture(); + if (texture != NULL) { + if (texture->Read(p_file, 0) != SUCCESS) { + delete texture; + return namedTexture; + } + + namedTexture = new LegoNamedTexture(string.GetData(), texture); + if (namedTexture == NULL) { + delete texture; + } + } + + return namedTexture; } // STUB: LEGO1 0x1003f540 From 53b3d0b195891f147a957ddabcb19eeac7fb32d8 Mon Sep 17 00:00:00 2001 From: MS Date: Fri, 29 Mar 2024 07:58:59 -0400 Subject: [PATCH 04/17] Add datacmp to CI (#746) --- .github/workflows/build.yml | 7 ++ ISLE/library_smartheap.h | 2 +- tools/datacmp.py | 28 ++++++-- tools/isledecomp/isledecomp/cvdump/types.py | 76 +++++++++++---------- tools/isledecomp/tests/test_cvdump_types.py | 21 ++++-- 5 files changed, 89 insertions(+), 45 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d5085268..efbe1c2e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -156,6 +156,13 @@ jobs: python3 tools/vtable/vtable.py legobin/ISLE.EXE build/ISLE.EXE build/ISLE.PDB . python3 tools/vtable/vtable.py legobin/LEGO1.DLL build/LEGO1.DLL build/LEGO1.PDB . + - name: Check Variables + shell: bash + run: | + python3 tools/datacmp.py legobin/CONFIG.EXE build/CONFIG.EXE build/CONFIG.PDB . + python3 tools/datacmp.py legobin/ISLE.EXE build/ISLE.EXE build/ISLE.PDB . + python3 tools/datacmp.py legobin/LEGO1.DLL build/LEGO1.DLL build/LEGO1.PDB . + - name: Upload Artifact uses: actions/upload-artifact@master with: diff --git a/ISLE/library_smartheap.h b/ISLE/library_smartheap.h index 53ef5f0d..c503372e 100644 --- a/ISLE/library_smartheap.h +++ b/ISLE/library_smartheap.h @@ -297,7 +297,7 @@ // GLOBAL: ISLE 0x4105b0 // __shi_TaskRecord -// GLOBAL: ISLE 0x4125f8 +// ~GLOBAL: ISLE 0x4125f8 // ?_pnhHeap@@3P6AHI@ZA // GLOBAL: ISLE 0x412830 diff --git a/tools/datacmp.py b/tools/datacmp.py index 0837f288..28895876 100644 --- a/tools/datacmp.py +++ b/tools/datacmp.py @@ -47,6 +47,13 @@ def parse_args() -> argparse.Namespace: parser.add_argument( "--no-color", "-n", action="store_true", help="Do not color the output" ) + parser.add_argument( + "--all", + "-a", + dest="show_all", + action="store_true", + help="Only show variables with a problem", + ) parser.add_argument( "--print-rec-addr", action="store_true", @@ -236,7 +243,7 @@ def do_the_comparison(args: argparse.Namespace) -> Iterable[ComparisonItem]: # If we are here, we can do the type-aware comparison. compared = [] - compare_items = mini_cvdump.types.get_scalars(type_name) + compare_items = mini_cvdump.types.get_scalars_gapless(type_name) format_str = mini_cvdump.types.get_format_string(type_name) orig_data = unpack(format_str, orig_raw) @@ -308,8 +315,15 @@ def display_match(result: CompareResult) -> str: ) return f"{match_color}{result.name}{colorama.Style.RESET_ALL}" + var_count = 0 + problems = 0 + for item in do_the_comparison(args): - if not args.verbose and item.result == CompareResult.MATCH: + var_count += 1 + if item.result in (CompareResult.DIFF, CompareResult.ERROR): + problems += 1 + + if not args.show_all and item.result == CompareResult.MATCH: continue address_display = ( @@ -334,8 +348,14 @@ def display_match(result: CompareResult) -> str: f" {c.offset:5} {value_get(c.name, '(value)'):30} {value_a} : {value_b}" ) - print() + if args.verbose: + print() + + print( + f"{os.path.basename(args.original)} - Variables: {var_count}. Issues: {problems}" + ) + return 0 if problems == 0 else 1 if __name__ == "__main__": - main() + raise SystemExit(main()) diff --git a/tools/isledecomp/isledecomp/cvdump/types.py b/tools/isledecomp/isledecomp/cvdump/types.py index 87ae4b6e..547d3ce9 100644 --- a/tools/isledecomp/isledecomp/cvdump/types.py +++ b/tools/isledecomp/isledecomp/cvdump/types.py @@ -1,5 +1,5 @@ import re -from typing import Dict, Iterator, List, NamedTuple, Optional +from typing import Dict, List, NamedTuple, Optional class CvdumpTypeError(Exception): @@ -109,38 +109,10 @@ def scalar_type_format_char(type_name: str) -> str: return char if scalar_type_signed(type_name) else char.upper() -def member_string_iter( - members: List[ScalarType], size: Optional[int] = None -) -> Iterator[str]: - if len(members) == 0: - yield "x" * (size or 0) +def member_list_to_struct_string(members: List[ScalarType]) -> str: + """Create a string for use with struct.unpack""" - last_offset = 0 - last_size = 0 - for m in members: - padding = m.offset - last_offset - last_size - if padding > 0: - yield "x" * padding - - yield m.format_char - last_offset = m.offset - last_size = m.size - - if size is not None: - padding = size - (last_offset + last_size) - if padding > 0: - yield "x" * padding - - -def member_list_to_struct_string( - members: List[ScalarType], size: Optional[int] = None -) -> str: - """Create a string for use with struct.unpack - Will pad to `size` bytes if present.""" - if len(members) == 0: - return "x" * (size or 0) - - format_string = "".join(list(member_string_iter(members, size))) + format_string = "".join(m.format_char for m in members) if len(format_string) > 0: return "<" + format_string @@ -372,11 +344,43 @@ def get_scalars(self, type_key: str) -> List[ScalarType]: for cm in self.get_scalars(m.type) ] - def get_format_string(self, type_key: str) -> str: + def get_scalars_gapless(self, type_key: str) -> List[ScalarType]: + """Reduce the given type to a list of scalars so we can + compare each component value.""" + obj = self.get(type_key) - members = self.get_scalars(type_key) - # We need both to pad the data to size - return member_list_to_struct_string(members, obj.size) + total_size = obj.size + + scalars = self.get_scalars(type_key) + + output = [] + last_extent = total_size + + # Walk the scalar list in reverse; we assume a gap could not + # come at the start of the struct. + for scalar in scalars[::-1]: + this_extent = scalar.offset + scalar_type_size(scalar.type) + size_diff = last_extent - this_extent + # We need to add the gap fillers in reverse here + for i in range(size_diff - 1, -1, -1): + # Push to front + output.insert( + 0, + ScalarType( + offset=this_extent + i, + name="(padding)", + type="T_UCHAR", + ), + ) + + output.insert(0, scalar) + last_extent = scalar.offset + + return output + + def get_format_string(self, type_key: str) -> str: + members = self.get_scalars_gapless(type_key) + return member_list_to_struct_string(members) def read_line(self, line: str): if (match := self.INDEX_RE.match(line)) is not None: diff --git a/tools/isledecomp/tests/test_cvdump_types.py b/tools/isledecomp/tests/test_cvdump_types.py index d6182b25..e90cff0f 100644 --- a/tools/isledecomp/tests/test_cvdump_types.py +++ b/tools/isledecomp/tests/test_cvdump_types.py @@ -313,14 +313,27 @@ def test_struct(parser): def test_struct_padding(parser): - """Struct format string should insert padding characters 'x' - where a value is padded to alignment size (probably 4 bytes)""" + """For data comparison purposes, make sure we have no gaps in the + list of scalar types. Any gap is filled by an unsigned char.""" + # MxString, padded to 16 bytes. 4 actual members. 2 bytes of padding. + assert len(parser.get_scalars("0x4db6")) == 4 + assert len(parser.get_scalars_gapless("0x4db6")) == 6 + + # MxVariable, with two MxStrings (and a vtable) + # Fill in the middle gap and the outer gap. + assert len(parser.get_scalars("0x22d5")) == 9 + assert len(parser.get_scalars_gapless("0x22d5")) == 13 + + +def test_struct_format_string(parser): + """Generate the struct.unpack format string using the + list of scalars with padding filled in.""" # MxString, padded to 16 bytes. - assert parser.get_format_string("0x4db6") == " Date: Fri, 29 Mar 2024 10:41:12 -0400 Subject: [PATCH 05/17] Implement/match LegoCharacterManager::FUN_100832a0 (#747) --- .../legoomni/include/legocharactermanager.h | 1 + .../src/common/legocharactermanager.cpp | 27 +++++++++++++++++-- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legocharactermanager.h b/LEGO1/lego/legoomni/include/legocharactermanager.h index 2347f55e..6067c326 100644 --- a/LEGO1/lego/legoomni/include/legocharactermanager.h +++ b/LEGO1/lego/legoomni/include/legocharactermanager.h @@ -50,6 +50,7 @@ class LegoCharacterManager { static MxBool FUN_10084c00(const LegoChar*); void FUN_100832a0(); + undefined4 FUN_10083bc0(LegoROI* p_roi); void FUN_10083db0(LegoROI* p_roi); void FUN_10083f10(LegoROI* p_roi); LegoExtraActor* FUN_10084c40(const LegoChar*); diff --git a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp index 16d7f2de..024c547d 100644 --- a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp @@ -38,10 +38,26 @@ void LegoCharacterManager::Init() } } -// STUB: LEGO1 0x100832a0 +// FUNCTION: LEGO1 0x100832a0 void LegoCharacterManager::FUN_100832a0() { - // TODO + for (MxS32 i = 0; i < _countof(g_characterData) - 1; i++) { + LegoCharacterData* data = Find(g_characterData[i].m_name); + + if (data != NULL) { + LegoExtraActor* actor = data->m_actor; + + if (actor != NULL && actor->IsA("LegoExtraActor")) { + LegoROI* roi = g_characterData[i].m_roi; + undefined4 und = FUN_10083bc0(roi); + + while (und) { + FUN_10083db0(roi); + und = FUN_10083bc0(roi); + } + } + } + } } // FUNCTION: LEGO1 0x10083310 @@ -189,6 +205,13 @@ LegoROI* LegoCharacterManager::GetROI(const char* p_key, MxBool p_createEntity) return NULL; } +// STUB: LEGO1 0x10083bc0 +undefined4 LegoCharacterManager::FUN_10083bc0(LegoROI* p_roi) +{ + // TODO + return 0; +} + // STUB: LEGO1 0x10083db0 void LegoCharacterManager::FUN_10083db0(LegoROI* p_roi) { From 7431d9d65056c2dbeaa6d876bcb13f9d86840839 Mon Sep 17 00:00:00 2001 From: Ramen2X Date: Fri, 29 Mar 2024 11:50:16 -0400 Subject: [PATCH 06/17] implement/match LegoAnimationManager::FindVehicle() (#748) --- LEGO1/lego/legoomni/include/legoanimationmanager.h | 2 +- .../legoomni/src/common/legoanimationmanager.cpp | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoanimationmanager.h b/LEGO1/lego/legoomni/include/legoanimationmanager.h index 2254f744..1f93f907 100644 --- a/LEGO1/lego/legoomni/include/legoanimationmanager.h +++ b/LEGO1/lego/legoomni/include/legoanimationmanager.h @@ -67,7 +67,7 @@ class LegoAnimationManager : public MxCore { void FUN_1005f6d0(MxBool); void FUN_1005f700(MxBool); MxResult LoadScriptInfo(MxS32 p_scriptIndex); - MxBool FUN_10060140(char* p_name, MxU32& p_index); + MxBool FindVehicle(const char* p_name, MxU32& p_index); MxResult ReadAnimInfo(LegoFile* p_file, AnimInfo* p_info); MxResult ReadModelInfo(LegoFile* p_file, ModelInfo* p_info); void FUN_100603c0(); diff --git a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp index c48f1c97..d4ee0254 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp @@ -254,7 +254,7 @@ MxResult LegoAnimationManager::LoadScriptInfo(MxS32 p_scriptIndex) for (MxS32 m = 0; m < m_anims[j].m_modelCount; m++) { MxU32 n; - if (FUN_10060140(m_anims[j].m_models[m].m_modelName, n) && m_anims[j].m_models[m].m_unk0x2c) { + if (FindVehicle(m_anims[j].m_models[m].m_modelName, n) && m_anims[j].m_models[m].m_unk0x2c) { m_anims[j].m_unk0x2a[count++] = n; if (count > 3) { break; @@ -294,10 +294,16 @@ MxResult LegoAnimationManager::LoadScriptInfo(MxS32 p_scriptIndex) return result; } -// STUB: LEGO1 0x10060140 -MxBool LegoAnimationManager::FUN_10060140(char* p_name, MxU32& p_index) +// FUNCTION: LEGO1 0x10060140 +MxBool LegoAnimationManager::FindVehicle(const char* p_name, MxU32& p_index) { - // TODO + for (MxS32 i = 0; i < _countof(g_vehicles); i++) { + if (!strcmpi(p_name, g_vehicles[i].m_name)) { + p_index = i; + return TRUE; + } + } + return FALSE; } From 6fda6ca92bdcbedffb54b1e3e351090e5d457112 Mon Sep 17 00:00:00 2001 From: MS Date: Fri, 29 Mar 2024 13:29:44 -0400 Subject: [PATCH 07/17] reccmp: Don't use placeholder for address comparison (#751) --- .../isledecomp/compare/asm/parse.py | 26 +++++++++++--- tools/isledecomp/tests/test_sanitize.py | 35 +++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/tools/isledecomp/isledecomp/compare/asm/parse.py b/tools/isledecomp/isledecomp/compare/asm/parse.py index 459cbd3d..d69fe76b 100644 --- a/tools/isledecomp/isledecomp/compare/asm/parse.py +++ b/tools/isledecomp/isledecomp/compare/asm/parse.py @@ -69,14 +69,16 @@ def float_replace(self, addr: int, data_size: int) -> Optional[str]: return None - def lookup(self, addr: int) -> Optional[str]: + def lookup(self, addr: int, use_cache: bool = True) -> Optional[str]: """Return a replacement name for this address if we find one.""" - if (cached := self.replacements.get(addr, None)) is not None: + if use_cache and (cached := self.replacements.get(addr, None)) is not None: return cached if callable(self.name_lookup): if (name := self.name_lookup(addr)) is not None: - self.replacements[addr] = name + if use_cache: + self.replacements[addr] = name + return name return None @@ -110,6 +112,16 @@ def hex_replace_relocated(self, match: re.Match) -> str: return match.group(0) + def hex_replace_annotated(self, match: re.Match) -> str: + """For replacing immediate value operands. Here we replace the value + only if the name lookup returns something. Do not use a placeholder.""" + value = int(match.group(1), 16) + placeholder = self.lookup(value, use_cache=False) + if placeholder is not None: + return match.group(0).replace(match.group(1), placeholder) + + return match.group(0) + def hex_replace_float(self, match: re.Match) -> str: """Special case for replacements on float instructions. If the pointer is a float constant, read it from the binary.""" @@ -178,7 +190,13 @@ def sanitize(self, inst: DisasmLiteInst) -> Tuple[str, str]: # vtable call, or this->member access. op_str = displace_replace_regex.sub(self.hex_replace_relocated, op_str) - op_str = immediate_replace_regex.sub(self.hex_replace_relocated, op_str) + # In the event of pointer comparison, only replace the immediate value + # if it is a known address. + if inst.mnemonic == "cmp": + op_str = immediate_replace_regex.sub(self.hex_replace_annotated, op_str) + else: + op_str = immediate_replace_regex.sub(self.hex_replace_relocated, op_str) + return (inst.mnemonic, op_str) def parse_asm(self, data: bytes, start_addr: Optional[int] = 0) -> List[str]: diff --git a/tools/isledecomp/tests/test_sanitize.py b/tools/isledecomp/tests/test_sanitize.py index 200cbf0a..d13fae56 100644 --- a/tools/isledecomp/tests/test_sanitize.py +++ b/tools/isledecomp/tests/test_sanitize.py @@ -221,3 +221,38 @@ def substitute_float(_: int, __: int) -> str: inst = DisasmLiteInst(0x1000, 6, "fld", "dword ptr [0x1234]") (_, op_str) = p.sanitize(inst) assert op_str == "dword ptr [g_myFloatVariable]" + + +def test_pointer_compare(): + """A loop on an array could get optimized into comparing on the address + that immediately follows the array. This may or may not be a valid address + and it may or may not be annotated. To avoid a situation where an + erroneous address value would get replaced with a placeholder and silently + pass the comparison check, we will only replace an immediate value on the + CMP instruction if it is a known address.""" + + # 0x1234 and 0x5555 are relocated and so are considered to be addresses. + def relocate_lookup(addr: int) -> bool: + return addr in (0x1234, 0x5555) + + # Only 0x5555 is a "known" address + def name_lookup(addr: int) -> Optional[str]: + return "hello" if addr == 0x5555 else None + + p = ParseAsm(relocate_lookup=relocate_lookup, name_lookup=name_lookup) + + # Will always replace on MOV instruction + (_, op_str) = p.sanitize(mock_inst("mov", "eax, 0x1234")) + assert op_str == "eax, " + (_, op_str) = p.sanitize(mock_inst("mov", "eax, 0x5555")) + assert op_str == "eax, hello" + + # n.b. We have already cached the replacement for 0x1234, but the + # special handling for CMP should skip the cache and not use it. + + # Do not replace here + (_, op_str) = p.sanitize(mock_inst("cmp", "eax, 0x1234")) + assert op_str == "eax, 0x1234" + # Should replace here + (_, op_str) = p.sanitize(mock_inst("cmp", "eax, 0x5555")) + assert op_str == "eax, hello" From e260a407baae59b808d934f9772073eeaf5bfcc2 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 29 Mar 2024 13:30:31 -0400 Subject: [PATCH 08/17] Implement/match LegoCharacterManager::GetRefCount (#749) --- .../legoomni/include/legocharactermanager.h | 2 +- .../src/common/legocharactermanager.cpp | 22 ++++++++++++++----- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legocharactermanager.h b/LEGO1/lego/legoomni/include/legocharactermanager.h index 6067c326..0b74f99b 100644 --- a/LEGO1/lego/legoomni/include/legocharactermanager.h +++ b/LEGO1/lego/legoomni/include/legocharactermanager.h @@ -50,7 +50,7 @@ class LegoCharacterManager { static MxBool FUN_10084c00(const LegoChar*); void FUN_100832a0(); - undefined4 FUN_10083bc0(LegoROI* p_roi); + MxU32 GetRefCount(LegoROI* p_roi); void FUN_10083db0(LegoROI* p_roi); void FUN_10083f10(LegoROI* p_roi); LegoExtraActor* FUN_10084c40(const LegoChar*); diff --git a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp index 024c547d..35451e73 100644 --- a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp @@ -49,11 +49,11 @@ void LegoCharacterManager::FUN_100832a0() if (actor != NULL && actor->IsA("LegoExtraActor")) { LegoROI* roi = g_characterData[i].m_roi; - undefined4 und = FUN_10083bc0(roi); + MxU32 refCount = GetRefCount(roi); - while (und) { + while (refCount != 0) { FUN_10083db0(roi); - und = FUN_10083bc0(roi); + refCount = GetRefCount(roi); } } } @@ -205,10 +205,20 @@ LegoROI* LegoCharacterManager::GetROI(const char* p_key, MxBool p_createEntity) return NULL; } -// STUB: LEGO1 0x10083bc0 -undefined4 LegoCharacterManager::FUN_10083bc0(LegoROI* p_roi) +// FUNCTION: LEGO1 0x10083bc0 +MxU32 LegoCharacterManager::GetRefCount(LegoROI* p_roi) { - // TODO + LegoCharacterMap::iterator it; + + for (it = m_characters->begin(); it != m_characters->end(); it++) { + LegoCharacter* character = (*it).second; + LegoROI* roi = character->m_roi; + + if (roi == p_roi) { + return character->m_refCount; + } + } + return 0; } From ed1a25a636f3535d13a23f012325e316199eea1a Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 29 Mar 2024 13:30:46 -0400 Subject: [PATCH 09/17] Implement/match LegoCharacterManager GetActor/Exists, fix loops (#750) --- .../legoomni/include/legocharactermanager.h | 10 ++-- .../src/common/legoanimationmanager.cpp | 2 +- .../src/common/legocharactermanager.cpp | 59 +++++++++++-------- .../legoomni/src/video/legoanimpresenter.cpp | 2 +- 4 files changed, 42 insertions(+), 31 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legocharactermanager.h b/LEGO1/lego/legoomni/include/legocharactermanager.h index 0b74f99b..79fde62e 100644 --- a/LEGO1/lego/legoomni/include/legocharactermanager.h +++ b/LEGO1/lego/legoomni/include/legocharactermanager.h @@ -47,18 +47,18 @@ class LegoCharacterManager { void Init(); static void SetCustomizeAnimFile(const char* p_value); - static MxBool FUN_10084c00(const LegoChar*); + static MxBool Exists(const char* p_key); void FUN_100832a0(); MxU32 GetRefCount(LegoROI* p_roi); void FUN_10083db0(LegoROI* p_roi); void FUN_10083f10(LegoROI* p_roi); - LegoExtraActor* FUN_10084c40(const LegoChar*); - LegoCharacterData* Find(const char* p_key); + LegoExtraActor* GetActor(const char* p_key); + LegoCharacterData* GetData(const char* p_key); MxBool FUN_10084ec0(LegoROI* p_roi); MxU32 FUN_10085140(LegoROI*, MxBool); - LegoROI* FUN_10085210(const LegoChar*, LegoChar*, undefined); - LegoROI* FUN_10085a80(LegoChar* p_und1, LegoChar* p_und2, undefined p_und3); + LegoROI* FUN_10085210(const char*, char*, undefined); + LegoROI* FUN_10085a80(char* p_und1, char* p_und2, undefined p_und3); static const char* GetCustomizeAnimFile() { return g_customizeAnimFile; } diff --git a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp index d4ee0254..41616e41 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp @@ -427,7 +427,7 @@ MxResult LegoAnimationManager::StartEntityAction(MxDSAction& p_dsAction, LegoEnt LegoROI* roi = p_entity->GetROI(); if (p_entity->GetUnknown0x59() == 0) { - LegoPathActor* actor = CharacterManager()->FUN_10084c40(roi->GetName()); + LegoPathActor* actor = CharacterManager()->GetActor(roi->GetName()); if (actor) { LegoPathController* controller = actor->GetController(); diff --git a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp index 35451e73..f3734716 100644 --- a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp @@ -41,8 +41,8 @@ void LegoCharacterManager::Init() // FUNCTION: LEGO1 0x100832a0 void LegoCharacterManager::FUN_100832a0() { - for (MxS32 i = 0; i < _countof(g_characterData) - 1; i++) { - LegoCharacterData* data = Find(g_characterData[i].m_name); + for (MxS32 i = 0; i < _countof(g_characterData); i++) { + LegoCharacterData* data = GetData(g_characterData[i].m_name); if (data != NULL) { LegoExtraActor* actor = data->m_actor; @@ -65,7 +65,7 @@ MxResult LegoCharacterManager::Write(LegoStorage* p_storage) { MxResult result = FAILURE; - for (MxS32 i = 0; i < _countof(g_characterData) - 1; i++) { + for (MxS32 i = 0; i < _countof(g_characterData); i++) { LegoCharacterData* data = &g_characterData[i]; if (p_storage->Write(&data->m_unk0x0c, sizeof(data->m_unk0x0c)) != SUCCESS) { @@ -111,7 +111,7 @@ MxResult LegoCharacterManager::Read(LegoStorage* p_storage) { MxResult result = FAILURE; - for (MxS32 i = 0; i < _countof(g_characterData) - 1; i++) { + for (MxS32 i = 0; i < _countof(g_characterData); i++) { LegoCharacterData* data = &g_characterData[i]; if (p_storage->Read(&data->m_unk0x0c, sizeof(data->m_unk0x0c)) != SUCCESS) { @@ -196,7 +196,7 @@ LegoROI* LegoCharacterManager::GetROI(const char* p_key, MxBool p_createEntity) actor->SetROI(character->m_roi, FALSE, FALSE); actor->FUN_100114e0(0); actor->SetFlag(LegoActor::c_bit2); - Find(p_key)->m_actor = actor; + GetData(p_key)->m_actor = actor; } return character->m_roi; @@ -248,21 +248,21 @@ LegoROI* LegoCharacterManager::CreateROI(const char* p_key) Tgl::Renderer* renderer = VideoManager()->GetRenderer(); ViewLODListManager* lodManager = GetViewLODListManager(); LegoTextureContainer* textureContainer = TextureContainer(); - LegoCharacterData* characterData = Find(p_key); + LegoCharacterData* data = GetData(p_key); - if (characterData == NULL) { + if (data == NULL) { goto done; } if (!strcmpi(p_key, "pep")) { - LegoCharacterData* pepper = Find("pepper"); + LegoCharacterData* pepper = GetData("pepper"); - characterData->m_unk0x0c = pepper->m_unk0x0c; - characterData->m_unk0x10 = pepper->m_unk0x10; - characterData->m_unk0x14 = pepper->m_unk0x14; + data->m_unk0x0c = pepper->m_unk0x0c; + data->m_unk0x10 = pepper->m_unk0x10; + data->m_unk0x14 = pepper->m_unk0x14; - for (i = 0; i < _countof(characterData->m_parts); i++) { - characterData->m_parts[i] = pepper->m_parts[i]; + for (i = 0; i < _countof(data->m_parts); i++) { + data->m_parts[i] = pepper->m_parts[i]; } } @@ -293,7 +293,7 @@ LegoROI* LegoCharacterManager::CreateROI(const char* p_key) const char* parentName; char lodName[64]; - LegoCharacterData::Part& part = characterData->m_parts[i]; + LegoCharacterData::Part& part = data->m_parts[i]; if (i == 0 || i == 1) { parentName = part.m_unk0x04[part.m_unk0x00[part.m_unk0x08]]; @@ -371,7 +371,7 @@ LegoROI* LegoCharacterManager::CreateROI(const char* p_key) ); roi->WrappedSetLocalTransform(mat); - characterData->m_roi = roi; + data->m_roi = roi; success = TRUE; done: @@ -383,25 +383,36 @@ LegoROI* LegoCharacterManager::CreateROI(const char* p_key) return roi; } -// STUB: LEGO1 0x10084c00 -MxBool LegoCharacterManager::FUN_10084c00(const LegoChar*) +// FUNCTION: LEGO1 0x10084c00 +MxBool LegoCharacterManager::Exists(const char* p_key) { - // TODO + for (MxU32 i = 0; i < _countof(g_characterData); i++) { + if (!strcmpi(g_characterData[i].m_name, p_key)) { + return TRUE; + } + } + return FALSE; } -// STUB: LEGO1 0x10084c40 -LegoExtraActor* LegoCharacterManager::FUN_10084c40(const LegoChar*) +// FUNCTION: LEGO1 0x10084c40 +LegoExtraActor* LegoCharacterManager::GetActor(const char* p_key) { + LegoCharacterData* data = GetData(p_key); + + if (data != NULL) { + return data->m_actor; + } + return NULL; } // FUNCTION: LEGO1 0x10084c60 -LegoCharacterData* LegoCharacterManager::Find(const char* p_key) +LegoCharacterData* LegoCharacterManager::GetData(const char* p_key) { MxU32 i; - for (i = 0; i < _countof(g_characterData) - 1; i++) { + for (i = 0; i < _countof(g_characterData); i++) { if (!strcmpi(g_characterData[i].m_name, p_key)) { break; } @@ -448,13 +459,13 @@ void LegoCharacterManager::SetCustomizeAnimFile(const char* p_value) } // STUB: LEGO1 0x10085210 -LegoROI* LegoCharacterManager::FUN_10085210(const LegoChar*, LegoChar*, undefined) +LegoROI* LegoCharacterManager::FUN_10085210(const char*, char*, undefined) { return NULL; } // FUNCTION: LEGO1 0x10085a80 -LegoROI* LegoCharacterManager::FUN_10085a80(LegoChar* p_und1, LegoChar* p_und2, undefined p_und3) +LegoROI* LegoCharacterManager::FUN_10085a80(char* p_und1, char* p_und2, undefined p_und3) { return FUN_10085210(p_und1, p_und2, p_und3); } diff --git a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp index a295df96..7ea6c730 100644 --- a/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp +++ b/LEGO1/lego/legoomni/src/video/legoanimpresenter.cpp @@ -115,7 +115,7 @@ LegoChar* LegoAnimPresenter::FUN_10069150(const LegoChar* p_und1) { LegoChar* str; - if (LegoCharacterManager::FUN_10084c00(p_und1 + 1)) { + if (LegoCharacterManager::Exists(p_und1 + 1)) { str = new LegoChar[strlen(p_und1)]; if (str != NULL) { From 2c57e33ce53cffbc191757270f1b49d5c6dff07e Mon Sep 17 00:00:00 2001 From: Ramen2X Date: Fri, 29 Mar 2024 14:09:46 -0400 Subject: [PATCH 10/17] implement/match LegoAnimationManager::DeleteAnimations() (#753) --- .../legoomni/include/legoanimationmanager.h | 2 +- .../src/common/legoanimationmanager.cpp | 29 +++++++++++++++---- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoanimationmanager.h b/LEGO1/lego/legoomni/include/legoanimationmanager.h index 1f93f907..d0a0eb40 100644 --- a/LEGO1/lego/legoomni/include/legoanimationmanager.h +++ b/LEGO1/lego/legoomni/include/legoanimationmanager.h @@ -70,7 +70,7 @@ class LegoAnimationManager : public MxCore { MxBool FindVehicle(const char* p_name, MxU32& p_index); MxResult ReadAnimInfo(LegoFile* p_file, AnimInfo* p_info); MxResult ReadModelInfo(LegoFile* p_file, ModelInfo* p_info); - void FUN_100603c0(); + void DeleteAnimations(); MxResult StartEntityAction(MxDSAction& p_dsAction, LegoEntity* p_entity); void FUN_10060570(MxBool); undefined4 FUN_10060dc0( diff --git a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp index 41616e41..c2a5d7a4 100644 --- a/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legoanimationmanager.cpp @@ -173,7 +173,7 @@ MxResult LegoAnimationManager::LoadScriptInfo(MxS32 p_scriptIndex) m_animState->FUN_10065240(m_animCount, m_anims, m_unk0x3fc); } - FUN_100603c0(); + DeleteAnimations(); LegoFile file; @@ -288,7 +288,7 @@ MxResult LegoAnimationManager::LoadScriptInfo(MxS32 p_scriptIndex) done: if (result == FAILURE) { - FUN_100603c0(); + DeleteAnimations(); } return result; @@ -408,10 +408,29 @@ MxResult LegoAnimationManager::ReadModelInfo(LegoFile* p_file, ModelInfo* p_info return result; } -// STUB: LEGO1 0x100603c0 -void LegoAnimationManager::FUN_100603c0() +// FUNCTION: LEGO1 0x100603c0 +void LegoAnimationManager::DeleteAnimations() { - // TODO + undefined unk0x42b = m_unk0x42b; + + if (m_anims != NULL) { + for (MxS32 i = 0; i < m_animCount; i++) { + delete m_anims[i].m_animName; + + if (m_anims[i].m_models != NULL) { + for (MxS32 j = 0; j < m_anims[i].m_modelCount; j++) { + delete m_anims[i].m_models[j].m_modelName; + } + + delete m_anims[i].m_models; + } + } + + delete m_anims; + } + + Init(); + m_unk0x42b = unk0x42b; } // STUB: LEGO1 0x10060570 From 87f633af54f88bf742148d7855313f53dd941124 Mon Sep 17 00:00:00 2001 From: Joshua Peisach Date: Fri, 29 Mar 2024 14:09:53 -0400 Subject: [PATCH 11/17] InfoCenterEntity::VTable0x50 implementation (#725) * Start InfoCenterEntity::VTable0x50 implementation * Fully implement InfoCenterEntity::VTable0x50 * Fix function name typo * match * fix style --------- Co-authored-by: Christian Semmler --- LEGO1/lego/legoomni/include/act3.h | 4 +- .../lego/legoomni/include/infocenterentity.h | 3 +- LEGO1/lego/legoomni/include/isle.h | 1 + LEGO1/lego/legoomni/include/legoact2.h | 2 + LEGO1/lego/legoomni/include/legoact2state.h | 3 +- LEGO1/lego/legoomni/include/policeentity.h | 2 +- LEGO1/lego/legoomni/src/actors/helicopter.cpp | 4 +- .../src/infocenter/infocenterentity.cpp | 57 +++++++++++++++++++ LEGO1/lego/legoomni/src/worlds/isle.cpp | 6 ++ 9 files changed, 74 insertions(+), 8 deletions(-) diff --git a/LEGO1/lego/legoomni/include/act3.h b/LEGO1/lego/legoomni/include/act3.h index eb4161ff..2883ff9d 100644 --- a/LEGO1/lego/legoomni/include/act3.h +++ b/LEGO1/lego/legoomni/include/act3.h @@ -35,8 +35,8 @@ class Act3 : public LegoWorld { MxBool VTable0x64() override; // vtable+0x64 void Enable(MxBool p_enable) override; // vtable+0x68 - inline void SetUnkown420c(MxEntity* p_entity) { m_unk0x420c = p_entity; } - inline void SetUnkown4270(MxU32 p_unk0x4270) { m_unk0x4270 = p_unk0x4270; } + inline void SetUnknown420c(MxEntity* p_entity) { m_unk0x420c = p_entity; } + inline void SetUnknown4270(MxU32 p_unk0x4270) { m_unk0x4270 = p_unk0x4270; } // SYNTHETIC: LEGO1 0x10072630 // Act3::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/infocenterentity.h b/LEGO1/lego/legoomni/include/infocenterentity.h index 0584db7f..82fa3d30 100644 --- a/LEGO1/lego/legoomni/include/infocenterentity.h +++ b/LEGO1/lego/legoomni/include/infocenterentity.h @@ -20,8 +20,7 @@ class InfoCenterEntity : public BuildingEntity { return !strcmp(p_name, InfoCenterEntity::ClassName()) || BuildingEntity::IsA(p_name); } - // STUB: LEGO1 0x100150c0 - MxLong VTable0x50(MxParam& p_param) override { return 0; } + MxLong VTable0x50(MxParam& p_param) override; // vtable+0x50 // SYNTHETIC: LEGO1 0x1000f7b0 // InfoCenterEntity::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/isle.h b/LEGO1/lego/legoomni/include/isle.h index 0439d0a1..38895964 100644 --- a/LEGO1/lego/legoomni/include/isle.h +++ b/LEGO1/lego/legoomni/include/isle.h @@ -69,6 +69,7 @@ class Isle : public LegoWorld { void FUN_10031590(); void FUN_10032620(); void FUN_100330e0(); + void FUN_10033350(); void FUN_10032d30( IsleScript::Script p_script, JukeboxScript::Script p_music, diff --git a/LEGO1/lego/legoomni/include/legoact2.h b/LEGO1/lego/legoomni/include/legoact2.h index d90fe268..f0ee58dd 100644 --- a/LEGO1/lego/legoomni/include/legoact2.h +++ b/LEGO1/lego/legoomni/include/legoact2.h @@ -19,6 +19,8 @@ class LegoAct2 : public LegoWorld { MxBool VTable0x64() override; // vtable+0x64 void Enable(MxBool p_enable) override; // vtable+0x68 + inline void SetUnknown0x1150(undefined4 p_unk0x1150) { m_unk0x1150 = p_unk0x1150; } + // SYNTHETIC: LEGO1 0x1004fe20 // LegoAct2::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/legoact2state.h b/LEGO1/lego/legoomni/include/legoact2state.h index 8fcb4829..e4898960 100644 --- a/LEGO1/lego/legoomni/include/legoact2state.h +++ b/LEGO1/lego/legoomni/include/legoact2state.h @@ -28,10 +28,11 @@ class LegoAct2State : public LegoState { // LegoAct2State::`scalar deleting destructor' inline undefined4 GetUnknown0x08() { return m_unk0x08; } + inline void SetUnknown0x0c(undefined p_unk0x0c) { m_unk0x0c = p_unk0x0c; } private: undefined4 m_unk0x08; // 0x08 - undefined4 m_unk0x0c; // 0x0c + undefined m_unk0x0c; // 0x0c }; #endif // LEGOACT2STATE_H diff --git a/LEGO1/lego/legoomni/include/policeentity.h b/LEGO1/lego/legoomni/include/policeentity.h index 42792204..48156150 100644 --- a/LEGO1/lego/legoomni/include/policeentity.h +++ b/LEGO1/lego/legoomni/include/policeentity.h @@ -20,7 +20,7 @@ class PoliceEntity : public BuildingEntity { return !strcmp(p_name, PoliceEntity::ClassName()) || BuildingEntity::IsA(p_name); } - MxLong VTable0x50(MxParam& p_param) override; + MxLong VTable0x50(MxParam& p_param) override; // vtable+0x50 // SYNTHETIC: LEGO1 0x1000f900 // PoliceEntity::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/src/actors/helicopter.cpp b/LEGO1/lego/legoomni/src/actors/helicopter.cpp index 2f8de444..ded0b705 100644 --- a/LEGO1/lego/legoomni/src/actors/helicopter.cpp +++ b/LEGO1/lego/legoomni/src/actors/helicopter.cpp @@ -41,7 +41,7 @@ MxResult Helicopter::Create(MxDSAction& p_dsAction) LegoWorld* world = CurrentWorld(); SetWorld(world); if (world->IsA("Act3")) { - ((Act3*) GetWorld())->SetUnkown420c(this); + ((Act3*) GetWorld())->SetUnknown420c(this); } world = GetWorld(); if (world) { @@ -160,7 +160,7 @@ MxU32 Helicopter::VTable0xd4(LegoControlManagerEvent& p_param) switch (p_param.GetClickedObjectId()) { case IsleScript::c_HelicopterArms_Ctl: if (*g_act3Script == script) { - ((Act3*) CurrentWorld())->SetUnkown4270(2); + ((Act3*) CurrentWorld())->SetUnknown4270(2); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); } else if (m_state->GetUnkown8() != 0) { diff --git a/LEGO1/lego/legoomni/src/infocenter/infocenterentity.cpp b/LEGO1/lego/legoomni/src/infocenter/infocenterentity.cpp index 0f5689ac..5157cb25 100644 --- a/LEGO1/lego/legoomni/src/infocenter/infocenterentity.cpp +++ b/LEGO1/lego/legoomni/src/infocenter/infocenterentity.cpp @@ -1,3 +1,60 @@ #include "infocenterentity.h" +#include "act1state.h" +#include "act2main_actions.h" +#include "act3.h" +#include "act3_actions.h" +#include "act3state.h" +#include "isle.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "legoact2.h" +#include "legoact2state.h" +#include "legoanimationmanager.h" +#include "legogamestate.h" +#include "legoomni.h" +#include "legoutils.h" +#include "legoworld.h" +#include "misc.h" +#include "mxtransitionmanager.h" + DECOMP_SIZE_ASSERT(InfoCenterEntity, 0x68) + +// FUNCTION: LEGO1 0x100150c0 +MxLong InfoCenterEntity::VTable0x50(MxParam& p_param) +{ + switch (GameState()->GetCurrentAct()) { + case LegoGameState::Act::e_act1: { + if (CurrentActor()->GetActorId() != GameState()->GetActorId()) { + CurrentActor()->VTable0xe4(); + } + + Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); + isle->FUN_10033350(); + isle->SetDestLocation(LegoGameState::Area::e_infomain); + + Act1State* act1state = (Act1State*) GameState()->GetState("Act1State"); + act1state->SetUnknown18(0); + break; + } + case LegoGameState::Act::e_act2: { + LegoAct2* act2 = (LegoAct2*) FindWorld(*g_act2mainScript, Act2mainScript::c__Act2Main); + act2->SetUnknown0x1150(2); + + LegoAct2State* act2state = (LegoAct2State*) GameState()->GetState("LegoAct2State"); + if (act2state) { + act2state->SetUnknown0x0c(0); + } + break; + } + case LegoGameState::Act::e_act3: + Act3* act3 = (Act3*) FindWorld(*g_act3Script, Act3Script::c__Act3); + act3->SetUnknown4270(2); + break; + } + + AnimationManager()->FUN_10061010(0); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + + return 1; +} diff --git a/LEGO1/lego/legoomni/src/worlds/isle.cpp b/LEGO1/lego/legoomni/src/worlds/isle.cpp index bf5f85a8..2a6f900c 100644 --- a/LEGO1/lego/legoomni/src/worlds/isle.cpp +++ b/LEGO1/lego/legoomni/src/worlds/isle.cpp @@ -1115,3 +1115,9 @@ MxBool Isle::VTable0x64() // TODO return FALSE; } + +// STUB: LEGO1 0x10033350 +void Isle::FUN_10033350() +{ + // TODO +} From 92357d77e17bb10102c329a046a5a5775d3827c1 Mon Sep 17 00:00:00 2001 From: Joshua Peisach Date: Fri, 29 Mar 2024 14:11:48 -0400 Subject: [PATCH 12/17] Most entities with VTable0x50 function overrides (#752) * BeachHouseEntity::VTable0x50 * GasStationEntity::VTable0x50 * RaceStandsEntity::VTable0x50 * Run clang-format * Fix use of NULL --------- Co-authored-by: Christian Semmler --- .../lego/legoomni/include/beachhouseentity.h | 3 +- .../lego/legoomni/include/gasstationentity.h | 3 +- .../lego/legoomni/include/racestandsentity.h | 3 +- .../src/gasstation/gasstationentity.cpp | 36 +++++++++++++++++++ .../legoomni/src/hospital/hospitalentity.cpp | 2 +- .../legoomni/src/isle/beachhouseentity.cpp | 33 +++++++++++++++++ .../lego/legoomni/src/police/policeentity.cpp | 2 +- .../legoomni/src/race/racestandsentity.cpp | 33 +++++++++++++++++ 8 files changed, 107 insertions(+), 8 deletions(-) diff --git a/LEGO1/lego/legoomni/include/beachhouseentity.h b/LEGO1/lego/legoomni/include/beachhouseentity.h index 662f6382..34e9db47 100644 --- a/LEGO1/lego/legoomni/include/beachhouseentity.h +++ b/LEGO1/lego/legoomni/include/beachhouseentity.h @@ -20,8 +20,7 @@ class BeachHouseEntity : public BuildingEntity { return !strcmp(p_name, BeachHouseEntity::ClassName()) || BuildingEntity::IsA(p_name); } - // STUB: LEGO1 0x100153b0 - MxLong VTable0x50(MxParam& p_param) override { return 0; } + MxLong VTable0x50(MxParam& p_param) override; // SYNTHETIC: LEGO1 0x1000f970 // BeachHouseEntity::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/gasstationentity.h b/LEGO1/lego/legoomni/include/gasstationentity.h index 776c3c00..1b25cfd2 100644 --- a/LEGO1/lego/legoomni/include/gasstationentity.h +++ b/LEGO1/lego/legoomni/include/gasstationentity.h @@ -20,8 +20,7 @@ class GasStationEntity : public BuildingEntity { return !strcmp(p_name, GasStationEntity::ClassName()) || BuildingEntity::IsA(p_name); } - // STUB: LEGO1 0x100151d0 - MxLong VTable0x50(MxParam& p_param) override { return 0; } + MxLong VTable0x50(MxParam& p_param) override; // SYNTHETIC: LEGO1 0x1000f890 // GasStationEntity::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/include/racestandsentity.h b/LEGO1/lego/legoomni/include/racestandsentity.h index 61c70bd0..22bc4dd2 100644 --- a/LEGO1/lego/legoomni/include/racestandsentity.h +++ b/LEGO1/lego/legoomni/include/racestandsentity.h @@ -19,8 +19,7 @@ class RaceStandsEntity : public BuildingEntity { return !strcmp(p_name, RaceStandsEntity::ClassName()) || BuildingEntity::IsA(p_name); } - // STUB: LEGO1 0x10015450 - MxLong VTable0x50(MxParam& p_param) override { return 0; } + MxLong VTable0x50(MxParam& p_param) override; // SYNTHETIC: LEGO1 0x1000f9e0 // RaceStandsEntity::`scalar deleting destructor' diff --git a/LEGO1/lego/legoomni/src/gasstation/gasstationentity.cpp b/LEGO1/lego/legoomni/src/gasstation/gasstationentity.cpp index 142c7466..238059b1 100644 --- a/LEGO1/lego/legoomni/src/gasstation/gasstationentity.cpp +++ b/LEGO1/lego/legoomni/src/gasstation/gasstationentity.cpp @@ -1,3 +1,39 @@ #include "gasstationentity.h" +#include "act1state.h" +#include "isle.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "legoanimationmanager.h" +#include "legogamestate.h" +#include "legoomni.h" +#include "legoutils.h" +#include "legoworld.h" +#include "misc.h" +#include "mxtransitionmanager.h" + DECOMP_SIZE_ASSERT(GasStationEntity, 0x68) + +// FUNCTION: LEGO1 0x100151d0 +MxLong GasStationEntity::VTable0x50(MxParam& p_param) +{ + if (FUN_1003ef60()) { + Act1State* state = (Act1State*) GameState()->GetState("Act1State"); + + if (state->GetUnknown18() != 8) { + state->SetUnknown18(0); + + if (CurrentActor()->GetActorId() != GameState()->GetActorId()) { + CurrentActor()->VTable0xe4(); + } + + Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); + isle->SetDestLocation(LegoGameState::Area::e_garage); + + AnimationManager()->FUN_10061010(0); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + } + + return 1; +} diff --git a/LEGO1/lego/legoomni/src/hospital/hospitalentity.cpp b/LEGO1/lego/legoomni/src/hospital/hospitalentity.cpp index 9e55303e..60fedd36 100644 --- a/LEGO1/lego/legoomni/src/hospital/hospitalentity.cpp +++ b/LEGO1/lego/legoomni/src/hospital/hospitalentity.cpp @@ -30,7 +30,7 @@ MxLong HospitalEntity::VTable0x50(MxParam& p_param) Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); isle->SetDestLocation(LegoGameState::Area::e_hospital); - AnimationManager()->FUN_10061010(NULL); + AnimationManager()->FUN_10061010(0); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); } } diff --git a/LEGO1/lego/legoomni/src/isle/beachhouseentity.cpp b/LEGO1/lego/legoomni/src/isle/beachhouseentity.cpp index a872b95a..b30ae739 100644 --- a/LEGO1/lego/legoomni/src/isle/beachhouseentity.cpp +++ b/LEGO1/lego/legoomni/src/isle/beachhouseentity.cpp @@ -1,3 +1,36 @@ #include "beachhouseentity.h" +#include "act1state.h" +#include "isle.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "legoanimationmanager.h" +#include "legogamestate.h" +#include "legoomni.h" +#include "legoutils.h" +#include "legoworld.h" +#include "misc.h" +#include "mxtransitionmanager.h" + DECOMP_SIZE_ASSERT(BeachHouseEntity, 0x68) + +// FUNCTION: LEGO1 0x100153b0 +MxLong BeachHouseEntity::VTable0x50(MxParam& p_param) +{ + if (FUN_1003ef60()) { + Act1State* state = (Act1State*) GameState()->GetState("Act1State"); + state->SetUnknown18(0); + + if (CurrentActor()->GetActorId() != GameState()->GetActorId()) { + CurrentActor()->VTable0xe4(); + } + + Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); + isle->SetDestLocation(LegoGameState::Area::e_jetskibuild); + + AnimationManager()->FUN_10061010(0); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + + return 1; +} diff --git a/LEGO1/lego/legoomni/src/police/policeentity.cpp b/LEGO1/lego/legoomni/src/police/policeentity.cpp index 227799d4..365b8ef9 100644 --- a/LEGO1/lego/legoomni/src/police/policeentity.cpp +++ b/LEGO1/lego/legoomni/src/police/policeentity.cpp @@ -30,7 +30,7 @@ MxLong PoliceEntity::VTable0x50(MxParam& p_param) Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); isle->SetDestLocation(LegoGameState::Area::e_police); - AnimationManager()->FUN_10061010(NULL); + AnimationManager()->FUN_10061010(0); TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); } } diff --git a/LEGO1/lego/legoomni/src/race/racestandsentity.cpp b/LEGO1/lego/legoomni/src/race/racestandsentity.cpp index 8b4b7be5..01d64153 100644 --- a/LEGO1/lego/legoomni/src/race/racestandsentity.cpp +++ b/LEGO1/lego/legoomni/src/race/racestandsentity.cpp @@ -1,3 +1,36 @@ #include "racestandsentity.h" +#include "act1state.h" +#include "isle.h" +#include "isle_actions.h" +#include "islepathactor.h" +#include "legoanimationmanager.h" +#include "legogamestate.h" +#include "legoomni.h" +#include "legoutils.h" +#include "legoworld.h" +#include "misc.h" +#include "mxtransitionmanager.h" + DECOMP_SIZE_ASSERT(RaceStandsEntity, 0x68) + +// FUNCTION: LEGO1 0x10015450 +MxLong RaceStandsEntity::VTable0x50(MxParam& p_param) +{ + if (FUN_1003ef60()) { + Act1State* state = (Act1State*) GameState()->GetState("Act1State"); + state->SetUnknown18(0); + + if (CurrentActor()->GetActorId() != GameState()->GetActorId()) { + CurrentActor()->VTable0xe4(); + } + + Isle* isle = (Isle*) FindWorld(*g_isleScript, IsleScript::c__Isle); + isle->SetDestLocation(LegoGameState::Area::e_racecarbuild); + + AnimationManager()->FUN_10061010(0); + TransitionManager()->StartTransition(MxTransitionManager::e_mosaic, 50, FALSE, FALSE); + } + + return 1; +} From dd4d7cca9c3d1812c89dbe1ec380dcb2b33ca400 Mon Sep 17 00:00:00 2001 From: Ramen2X Date: Fri, 29 Mar 2024 14:20:02 -0400 Subject: [PATCH 13/17] fix typo in reccmp effective match string (#754) --- tools/reccmp/reccmp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/reccmp/reccmp.py b/tools/reccmp/reccmp.py index 711375d6..e77020cc 100755 --- a/tools/reccmp/reccmp.py +++ b/tools/reccmp/reccmp.py @@ -107,7 +107,7 @@ def print_match_verbose(match, show_both_addrs: bool = False, is_plain: bool = F print(f"{addrs}: {match.name} 100% match.\n\n{ok_text}\n\n") else: print( - f"{addrs}: {match.name} Effective 100%% match. (Differs in register allocation only)\n\n{ok_text} (still differs in register allocation)\n\n" + f"{addrs}: {match.name} Effective 100% match. (Differs in register allocation only)\n\n{ok_text} (still differs in register allocation)\n\n" ) else: print_combined_diff(match.udiff, is_plain, show_both_addrs) From 3878f798476fa29b561753d8cb3f824ba8c515eb Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 29 Mar 2024 14:34:50 -0400 Subject: [PATCH 14/17] Implement/match LegoCharacterData::GetData and FUN_10085140 (#755) --- .../legoomni/include/legocharactermanager.h | 3 +- .../src/common/legocharactermanager.cpp | 39 +++++++++++++++++-- 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legocharactermanager.h b/LEGO1/lego/legoomni/include/legocharactermanager.h index 79fde62e..faf31337 100644 --- a/LEGO1/lego/legoomni/include/legocharactermanager.h +++ b/LEGO1/lego/legoomni/include/legocharactermanager.h @@ -55,8 +55,9 @@ class LegoCharacterManager { void FUN_10083f10(LegoROI* p_roi); LegoExtraActor* GetActor(const char* p_key); LegoCharacterData* GetData(const char* p_key); + LegoCharacterData* GetData(LegoROI* p_roi); MxBool FUN_10084ec0(LegoROI* p_roi); - MxU32 FUN_10085140(LegoROI*, MxBool); + MxU32 FUN_10085140(LegoROI* p_roi, MxBool p_und); LegoROI* FUN_10085210(const char*, char*, undefined); LegoROI* FUN_10085a80(char* p_und1, char* p_und2, undefined p_und3); diff --git a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp index f3734716..848d695f 100644 --- a/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp +++ b/LEGO1/lego/legoomni/src/common/legocharactermanager.cpp @@ -17,6 +17,12 @@ DECOMP_SIZE_ASSERT(LegoCharacterManager, 0x08) // GLOBAL: LEGO1 0x100fc4e4 char* LegoCharacterManager::g_customizeAnimFile = NULL; +// GLOBAL: LEGO1 0x100fc4d8 +MxU32 g_unk0x100fc4d8 = 50; + +// GLOBAL: LEGO1 0x100fc4dc +MxU32 g_unk0x100fc4dc = 66; + // GLOBAL: LEGO1 0x10104f20 LegoCharacterData g_characterData[66]; @@ -425,6 +431,24 @@ LegoCharacterData* LegoCharacterManager::GetData(const char* p_key) return NULL; } +// FUNCTION: LEGO1 0x10084cb0 +LegoCharacterData* LegoCharacterManager::GetData(LegoROI* p_roi) +{ + MxU32 i; + + for (i = 0; i < _countof(g_characterData); i++) { + if (g_characterData[i].m_roi == p_roi) { + break; + } + } + + if (i < _countof(g_characterData)) { + return &g_characterData[i]; + } + + return NULL; +} + // STUB: LEGO1 0x10084ec0 MxBool LegoCharacterManager::FUN_10084ec0(LegoROI* p_roi) { @@ -432,10 +456,19 @@ MxBool LegoCharacterManager::FUN_10084ec0(LegoROI* p_roi) return FALSE; } -// STUB: LEGO1 0x10085140 -MxU32 LegoCharacterManager::FUN_10085140(LegoROI*, MxBool) +// FUNCTION: LEGO1 0x10085140 +MxU32 LegoCharacterManager::FUN_10085140(LegoROI* p_roi, MxBool p_und) { - // TODO + LegoCharacterData* data = GetData(p_roi); + + if (p_und) { + return data->m_unk0x14 + g_unk0x100fc4dc; + } + + if (data != NULL) { + return data->m_unk0x0c + g_unk0x100fc4d8; + } + return 0; } From f447397eef661cfc19ccbd61dacbdd201599f2d5 Mon Sep 17 00:00:00 2001 From: MS Date: Fri, 29 Mar 2024 14:47:46 -0400 Subject: [PATCH 15/17] Fix loop in LegoROI::ColorAliasLookup (#756) --- LEGO1/lego/sources/roi/legoroi.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/LEGO1/lego/sources/roi/legoroi.cpp b/LEGO1/lego/sources/roi/legoroi.cpp index 36e5551e..d4649093 100644 --- a/LEGO1/lego/sources/roi/legoroi.cpp +++ b/LEGO1/lego/sources/roi/legoroi.cpp @@ -23,9 +23,6 @@ typedef struct { int m_alpha; } ROIColorAlias; -// GLOBAL: LEGO1 0x100dbe28 -const double g_normalizeByteToFloat = 1.0 / 255; - // GLOBAL: LEGO1 0x101011b0 ROIColorAlias g_roiColorAliases[22] = { {"lego black", 0x21, 0x21, 0x21, 0}, {"lego black f", 0x21, 0x21, 0x21, 0}, @@ -529,19 +526,15 @@ LegoBool LegoROI::FUN_100a9bf0(const LegoChar* p_param, float& p_red, float& p_g // FUNCTION: LEGO1 0x100a9c50 LegoBool LegoROI::ColorAliasLookup(const LegoChar* p_param, float& p_red, float& p_green, float& p_blue, float& p_alpha) { - // TODO: this seems awfully hacky for these devs. is there a dynamic way - // to represent `the end of this array` that would improve this? - unsigned int i = 0; - do { + for (MxU32 i = 0; i < _countof(g_roiColorAliases); i++) { if (strcmpi(g_roiColorAliases[i].m_name, p_param) == 0) { - p_red = g_roiColorAliases[i].m_red * g_normalizeByteToFloat; - p_green = g_roiColorAliases[i].m_green * g_normalizeByteToFloat; - p_blue = g_roiColorAliases[i].m_blue * g_normalizeByteToFloat; - p_alpha = g_roiColorAliases[i].m_alpha * g_normalizeByteToFloat; + p_red = g_roiColorAliases[i].m_red / 255.0; + p_green = g_roiColorAliases[i].m_green / 255.0; + p_blue = g_roiColorAliases[i].m_blue / 255.0; + p_alpha = g_roiColorAliases[i].m_alpha / 255.0; return TRUE; } - i++; - } while ((int*) &g_roiColorAliases[i] < &g_roiConfig); + } return FALSE; } From 369f3fba22c8519142ecff061b18610facd952c0 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 29 Mar 2024 16:42:39 -0400 Subject: [PATCH 16/17] Implement SetLightPosition and related (#757) * Implement SetLightPosition and related * Update p name * style --- LEGO1/lego/legoomni/include/legoutils.h | 4 +- LEGO1/lego/legoomni/src/common/legoutils.cpp | 48 ++++++++++++++++---- LEGO1/lego/sources/3dmanager/legoview1.cpp | 21 +++++++++ LEGO1/lego/sources/3dmanager/legoview1.h | 7 ++- 4 files changed, 68 insertions(+), 12 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legoutils.h b/LEGO1/lego/legoomni/include/legoutils.h index 5d495665..55b65bea 100644 --- a/LEGO1/lego/legoomni/include/legoutils.h +++ b/LEGO1/lego/legoomni/include/legoutils.h @@ -25,8 +25,8 @@ void FUN_1003ef00(MxBool); void SetAppCursor(WPARAM p_wparam); MxBool FUN_1003ef60(); MxBool RemoveFromWorld(MxAtomId& p_entityAtom, MxS32 p_entityId, MxAtomId& p_worldAtom, MxS32 p_worldEntityId); -MxS32 UpdateLightPosition(MxS32 p_value); -void SetLightPosition(MxU32); +MxS32 UpdateLightPosition(MxS32 p_increase); +void SetLightPosition(MxS32 p_index); LegoNamedTexture* ReadNamedTexture(LegoFile* p_file); void FUN_1003f540(LegoFile* p_file, const char* p_filename); void WriteNamedTexture(LegoFile* p_file, LegoNamedTexture* p_texture); diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp index be85e1f6..b5f7fde1 100644 --- a/LEGO1/lego/legoomni/src/common/legoutils.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -14,9 +14,11 @@ #include "mxnotificationmanager.h" #include "mxstreamer.h" #include "mxtypes.h" +#include "realtime/realtime.h" #include #include +#include // STUB: LEGO1 0x1003e050 void FUN_1003e050(LegoAnimPresenter* p_presenter) @@ -340,16 +342,12 @@ MxBool FUN_1003ef60() } // FUNCTION: LEGO1 0x1003f050 -MxS32 UpdateLightPosition(MxS32 p_value) +MxS32 UpdateLightPosition(MxS32 p_increase) { - // This function updates the light position - // relatively by the amount passed in p_value. - // Because it operates relatively, it does not set - // the light position to an arbitrary value. - MxS32 lightPosition = atoi(VariableTable()->GetVariable("lightposition")); - if (p_value > 0) { + // Only ever increases by 1 irrespective of p_increase + if (p_increase > 0) { lightPosition += 1; if (lightPosition > 5) { lightPosition = 5; @@ -372,9 +370,41 @@ MxS32 UpdateLightPosition(MxS32 p_value) return lightPosition; } -// STUB: LEGO1 0x1003f0d0 -void SetLightPosition(MxU32) +// FUNCTION: LEGO1 0x1003f0d0 +void SetLightPosition(MxS32 p_index) { + float lights[6][6] = { + {1.0, 0.0, 0.0, -150.0, 50.0, -50.0}, + {0.809, -0.588, 0.0, -75.0, 50.0, -50.0}, + {0.0, -1.0, 0.0, 0.0, 150.0, -150.0}, + {-0.309, -0.951, 0.0, 25.0, 50.0, -50.0}, + {-0.809, -0.588, 0.0, 75.0, 50.0, -50.0}, + {-1.0, 0.0, 0.0, 150.0, 50.0, -50.0} + }; + + Mx3DPointFloat up(1.0, 0.0, 0.0); + Mx3DPointFloat direction; + Mx3DPointFloat position; + + Tgl::FloatMatrix4 matrix; + Matrix4 in(matrix); + MxMatrix transform; + + if (p_index < 0) { + p_index = 0; + } + else if (p_index > 5) { + p_index = 5; + } + + direction = lights[p_index]; + position = &lights[p_index][3]; + + CalcLocalTransform(position, direction, up, transform); + SETMAT4(in, transform); + + VideoManager()->Get3DManager()->GetLego3DView()->SetLight(FALSE, matrix); + VideoManager()->Get3DManager()->GetLego3DView()->SetLight(TRUE, matrix); } // FUNCTION: LEGO1 0x1003f3b0 diff --git a/LEGO1/lego/sources/3dmanager/legoview1.cpp b/LEGO1/lego/sources/3dmanager/legoview1.cpp index 033afce7..fa78e155 100644 --- a/LEGO1/lego/sources/3dmanager/legoview1.cpp +++ b/LEGO1/lego/sources/3dmanager/legoview1.cpp @@ -182,3 +182,24 @@ void LegoView1::Destroy() LegoView::Destroy(); } + +// FUNCTION: LEGO1 0x100abb60 +void LegoView1::SetLight(BOOL bDirectionalLight, Tgl::FloatMatrix4& rMatrix) +{ + Tgl::Light* pLight; + + if (bDirectionalLight == FALSE) { + pLight = m_pSunLight; + } + else { + pLight = m_pDirectionalLight; + } + + SetLight(pLight, rMatrix); +} + +// FUNCTION: LEGO1 0x100abb80 +void LegoView1::SetLight(Tgl::Light* pLight, Tgl::FloatMatrix4& rMatrix) +{ + pLight->SetTransformation(rMatrix); +} diff --git a/LEGO1/lego/sources/3dmanager/legoview1.h b/LEGO1/lego/sources/3dmanager/legoview1.h index 34b8f026..b8ad225f 100644 --- a/LEGO1/lego/sources/3dmanager/legoview1.h +++ b/LEGO1/lego/sources/3dmanager/legoview1.h @@ -8,7 +8,8 @@ namespace Tgl { class Camera; -} +class Light; +} // namespace Tgl ///////////////////////////////////////////////////////////////////////////// // LegoView @@ -64,7 +65,11 @@ class LegoView1 : public LegoView { BOOL Create(const TglSurface::CreateStruct&, Tgl::Renderer*); void Destroy() override; // vtable+0x08 + void SetLight(BOOL bDirectionalLight, Tgl::FloatMatrix4& rMatrix); + private: + void SetLight(Tgl::Light* pLight, Tgl::FloatMatrix4& rMatrix); + Tgl::Light* m_pSunLight; // 0x78 Tgl::Light* m_pDirectionalLight; // 0x7c Tgl::Light* m_pAmbientLight; // 0x80 From ed9e9efdab2cc7d3b49bf919def211b3e8594607 Mon Sep 17 00:00:00 2001 From: Christian Semmler Date: Fri, 29 Mar 2024 16:50:00 -0400 Subject: [PATCH 17/17] Implement/match LegoBackgroundColor::SetLightColor and related (#758) --- .../legoomni/include/legobackgroundcolor.h | 4 +-- .../src/common/legobackgroundcolor.cpp | 33 +++++++++++++++---- .../legoomni/src/common/legogamestate.cpp | 4 +-- LEGO1/lego/legoomni/src/common/legoutils.cpp | 4 +-- LEGO1/lego/sources/3dmanager/legoview1.cpp | 27 +++++++++++++-- LEGO1/lego/sources/3dmanager/legoview1.h | 6 ++-- 6 files changed, 61 insertions(+), 17 deletions(-) diff --git a/LEGO1/lego/legoomni/include/legobackgroundcolor.h b/LEGO1/lego/legoomni/include/legobackgroundcolor.h index 015d51b5..3e8b4457 100644 --- a/LEGO1/lego/legoomni/include/legobackgroundcolor.h +++ b/LEGO1/lego/legoomni/include/legobackgroundcolor.h @@ -10,8 +10,8 @@ class LegoBackgroundColor : public MxVariable { LegoBackgroundColor(const char* p_key, const char* p_value); void SetValue(const char* p_colorString) override; - void SetLights(float p_r, float p_g, float p_b); - void SetLights(); + void SetLightColor(float p_r, float p_g, float p_b); + void SetLightColor(); void ToggleDayNight(MxBool); void ToggleSkyColor(); diff --git a/LEGO1/lego/legoomni/src/common/legobackgroundcolor.cpp b/LEGO1/lego/legoomni/src/common/legobackgroundcolor.cpp index 5cf43c65..fa5795d7 100644 --- a/LEGO1/lego/legoomni/src/common/legobackgroundcolor.cpp +++ b/LEGO1/lego/legoomni/src/common/legobackgroundcolor.cpp @@ -91,7 +91,7 @@ void LegoBackgroundColor::ToggleDayNight(MxBool p_sun) float convertedR, convertedG, convertedB; ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB); VideoManager()->SetSkyColor(convertedR, convertedG, convertedB); - SetLights(convertedR, convertedG, convertedB); + SetLightColor(convertedR, convertedG, convertedB); } // FUNCTION: LEGO1 0x1003c330 @@ -110,18 +110,39 @@ void LegoBackgroundColor::ToggleSkyColor() float convertedR, convertedG, convertedB; ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB); VideoManager()->SetSkyColor(convertedR, convertedG, convertedB); - SetLights(convertedR, convertedG, convertedB); + SetLightColor(convertedR, convertedG, convertedB); } -// STUB: LEGO1 0x1003c400 -void LegoBackgroundColor::SetLights(float p_r, float p_g, float p_b) +// FUNCTION: LEGO1 0x1003c400 +void LegoBackgroundColor::SetLightColor(float p_r, float p_g, float p_b) { + if (!VideoManager()->GetVideoParam().Flags().GetF2bit0()) { + // TODO: Computed constants based on what? + p_r *= 4.3478260869565215; + p_g *= 1.5873015873015872; + p_b *= 1.1764705882352942; + + if (p_r > 1.0) { + p_r = 1.0; + } + + if (p_g > 1.0) { + p_g = 1.0; + } + + if (p_b > 1.0) { + p_b = 1.0; + } + + VideoManager()->Get3DManager()->GetLego3DView()->SetLightColor(FALSE, p_r, p_g, p_b); + VideoManager()->Get3DManager()->GetLego3DView()->SetLightColor(TRUE, p_r, p_g, p_b); + } } // FUNCTION: LEGO1 0x1003c4b0 -void LegoBackgroundColor::SetLights() +void LegoBackgroundColor::SetLightColor() { float convertedR, convertedG, convertedB; ConvertHSVToRGB(m_h, m_s, m_v, &convertedR, &convertedG, &convertedB); - SetLights(convertedR, convertedG, convertedB); + SetLightColor(convertedR, convertedG, convertedB); } diff --git a/LEGO1/lego/legoomni/src/common/legogamestate.cpp b/LEGO1/lego/legoomni/src/common/legogamestate.cpp index 09ebf305..d149d4e6 100644 --- a/LEGO1/lego/legoomni/src/common/legogamestate.cpp +++ b/LEGO1/lego/legoomni/src/common/legogamestate.cpp @@ -350,7 +350,7 @@ MxResult LegoGameState::Load(MxULong p_slot) } } while (status != 2); - m_backgroundColor->SetLights(); + m_backgroundColor->SetLightColor(); lightPosition = VariableTable()->GetVariable("lightposition"); if (lightPosition) { @@ -1072,7 +1072,7 @@ void LegoGameState::RegisterState(LegoState* p_state) void LegoGameState::Init() { m_backgroundColor->SetValue("set 56 54 68"); - m_backgroundColor->SetLights(); + m_backgroundColor->SetLightColor(); m_tempBackgroundColor->SetValue("set 56 54 68"); VariableTable()->SetVariable("lightposition", "2"); SetLightPosition(2); diff --git a/LEGO1/lego/legoomni/src/common/legoutils.cpp b/LEGO1/lego/legoomni/src/common/legoutils.cpp index b5f7fde1..86242395 100644 --- a/LEGO1/lego/legoomni/src/common/legoutils.cpp +++ b/LEGO1/lego/legoomni/src/common/legoutils.cpp @@ -403,8 +403,8 @@ void SetLightPosition(MxS32 p_index) CalcLocalTransform(position, direction, up, transform); SETMAT4(in, transform); - VideoManager()->Get3DManager()->GetLego3DView()->SetLight(FALSE, matrix); - VideoManager()->Get3DManager()->GetLego3DView()->SetLight(TRUE, matrix); + VideoManager()->Get3DManager()->GetLego3DView()->SetLightTransform(FALSE, matrix); + VideoManager()->Get3DManager()->GetLego3DView()->SetLightTransform(TRUE, matrix); } // FUNCTION: LEGO1 0x1003f3b0 diff --git a/LEGO1/lego/sources/3dmanager/legoview1.cpp b/LEGO1/lego/sources/3dmanager/legoview1.cpp index fa78e155..ac2aed33 100644 --- a/LEGO1/lego/sources/3dmanager/legoview1.cpp +++ b/LEGO1/lego/sources/3dmanager/legoview1.cpp @@ -184,7 +184,7 @@ void LegoView1::Destroy() } // FUNCTION: LEGO1 0x100abb60 -void LegoView1::SetLight(BOOL bDirectionalLight, Tgl::FloatMatrix4& rMatrix) +void LegoView1::SetLightTransform(BOOL bDirectionalLight, Tgl::FloatMatrix4& rMatrix) { Tgl::Light* pLight; @@ -195,11 +195,32 @@ void LegoView1::SetLight(BOOL bDirectionalLight, Tgl::FloatMatrix4& rMatrix) pLight = m_pDirectionalLight; } - SetLight(pLight, rMatrix); + SetLightTransform(pLight, rMatrix); } // FUNCTION: LEGO1 0x100abb80 -void LegoView1::SetLight(Tgl::Light* pLight, Tgl::FloatMatrix4& rMatrix) +void LegoView1::SetLightTransform(Tgl::Light* pLight, Tgl::FloatMatrix4& rMatrix) { pLight->SetTransformation(rMatrix); } + +// FUNCTION: LEGO1 0x100abba0 +void LegoView1::SetLightColor(BOOL bDirectionalLight, float red, float green, float blue) +{ + Tgl::Light* pLight; + + if (bDirectionalLight == FALSE) { + pLight = m_pSunLight; + } + else { + pLight = m_pDirectionalLight; + } + + SetLightColor(pLight, red, green, blue); +} + +// FUNCTION: LEGO1 0x100abbd0 +void LegoView1::SetLightColor(Tgl::Light* pLight, float red, float green, float blue) +{ + pLight->SetColor(red, green, blue); +} diff --git a/LEGO1/lego/sources/3dmanager/legoview1.h b/LEGO1/lego/sources/3dmanager/legoview1.h index b8ad225f..fb1aa5bd 100644 --- a/LEGO1/lego/sources/3dmanager/legoview1.h +++ b/LEGO1/lego/sources/3dmanager/legoview1.h @@ -65,10 +65,12 @@ class LegoView1 : public LegoView { BOOL Create(const TglSurface::CreateStruct&, Tgl::Renderer*); void Destroy() override; // vtable+0x08 - void SetLight(BOOL bDirectionalLight, Tgl::FloatMatrix4& rMatrix); + void SetLightTransform(BOOL bDirectionalLight, Tgl::FloatMatrix4& rMatrix); + void SetLightColor(BOOL bDirectionalLight, float red, float green, float blue); private: - void SetLight(Tgl::Light* pLight, Tgl::FloatMatrix4& rMatrix); + void SetLightTransform(Tgl::Light* pLight, Tgl::FloatMatrix4& rMatrix); + void SetLightColor(Tgl::Light* pLight, float red, float green, float blue); Tgl::Light* m_pSunLight; // 0x78 Tgl::Light* m_pDirectionalLight; // 0x7c