diff --git a/src/openlrr/game/world/Teleporter.cpp b/src/openlrr/game/world/Teleporter.cpp index 8d5fec5..6bd39ba 100644 --- a/src/openlrr/game/world/Teleporter.cpp +++ b/src/openlrr/game/world/Teleporter.cpp @@ -2,6 +2,9 @@ // #include "Teleporter.h" +#include "..\object\Object.h" +#include "..\Game.h" +#include "..\..\..\openlrr\engine\core\Maths.h" /********************************************************************************** @@ -25,39 +28,268 @@ bool32 & LegoRR::g_Teleporter_BOOL_00504188 = *(bool32*)0x00504188; #pragma region Functions // -//void __cdecl LegoRR::Teleporter_RemoveAll(TeleporterService* teleporter); +void __cdecl LegoRR::Teleporter_RemoveAll(TeleporterService* teleporter) +{ + // -FC iterate through list and free memory + if (teleporter != nullptr) { + Teleporter_RemoveAll(teleporter->next); + Gods98::Mem_Free(teleporter); + } +} // -//void __cdecl LegoRR::Teleporter_Restart(void); +void __cdecl LegoRR::Teleporter_Restart(void) +{ + teleporterGlobs.count = 0; + Teleporter_RemoveAll(teleporterGlobs.current); + teleporterGlobs.current = nullptr; +} // -//bool32 __cdecl LegoRR::Teleporter_LiveObjectCallback_Service(LegoObject* liveObj, void* search); +bool32 __cdecl LegoRR::Teleporter_LiveObjectCallback_Service(LegoObject* liveObj, void* search) +{ + // -FC, make local pointer here to make this function useable as a callback + SearchTeleporter_10* locSearch = (SearchTeleporter_10*)search; + + if (liveObj->type == locSearch->objType) { + liveObj->teleporter_modeFlags = locSearch->modeFlags; + liveObj->teleporter_teleportFlags = locSearch->teleportFlags; + if (locSearch->modeFlags & 2) { + liveObj->teleporter = locSearch->teleporter; + locSearch->teleporter->count += 1; + } + teleporterGlobs.count = teleporterGlobs.count + 1; + liveObj->flags4 = liveObj->flags4 | LIVEOBJ4_UNK_8; // -FC, TODO: name this flag + } + return 0; +} + +/* This function is weird, it returns EDX:EAX, but what for?? */ // -//Point2F __cdecl LegoRR::Teleporter_GetCameraPosition(void); +Point2F __cdecl LegoRR::Teleporter_GetCameraPosition(void) +{ + Point2F PVar1; + Map3D* surfMap; + LegoCamera* cam; + Vector3F* out_worldPos; + Point2F local_14; + Vector3F surfPosition; + + cam = legoGlobs.cameraMain; + if (legoGlobs.viewMode != ViewMode_Top) { + cam = legoGlobs.cameraFP; + } + out_worldPos = &surfPosition; + surfMap = Lego_GetMap(); + Camera_GetTopdownWorldPos(cam, surfMap, out_worldPos); + PVar1.y = surfPosition.y; + PVar1.x = surfPosition.x; + return PVar1; +} // -//void __cdecl LegoRR::Teleporter_Add(TeleporterService* teleporter); +void __cdecl LegoRR::Teleporter_Add(TeleporterService* teleporter) +{ + teleporter->next =teleporterGlobs.current; + teleporterGlobs.current = teleporter; +} // -//bool32 __cdecl LegoRR::Teleporter_LiveObjectCallback_Unk(LegoObject* liveObj, void* teleportObjType); +bool32 __cdecl LegoRR::Teleporter_LiveObjectCallback_Unk(LegoObject* liveObj, void* teleportObjType) +{ + LegoObject_Type objType; + // -FC, make local typeflags object for function passthrough + LegoObject_TypeFlags *locTypeFlags = (LegoObject_TypeFlags*)teleportObjType; + + objType = Teleporter_GetServiceObjectType(*locTypeFlags); + if (liveObj->type == objType && liveObj->teleporter_modeFlags) { + g_Teleporter_BOOL_00504188 = FALSE; + } + return FALSE; +} // -//bool32 __cdecl LegoRR::Teleporter_ServiceAll(LegoObject_TypeFlags teleportObjTypes); +bool32 __cdecl LegoRR::Teleporter_ServiceAll(LegoObject_TypeFlags teleportObjTypes) +{ + TeleportObjectType teleObjFlag; + uint32 i; + + i = 0; + do { + teleObjFlag = (TeleportObjectType)(1 << ((byte)i & 0x1f)); + g_Teleporter_BOOL_00504188 = TRUE; + if ((teleportObjTypes & teleObjFlag) != TELEPORT_SERVIVE_NONE) { + LegoObject_RunThroughListsSkipUpgradeParts(Teleporter_LiveObjectCallback_Unk, (void*)teleObjFlag); + if (g_Teleporter_BOOL_00504188 == 0) { + return FALSE; + } + } + i = i + 1; + } while (i < 31); + return TRUE; +} + // -//void __cdecl LegoRR::Teleporter_Start(LegoObject_TypeFlags teleportObjType, uint32 modeFlags, uint32 teleportFlags); +void __cdecl LegoRR::Teleporter_Start(LegoObject_TypeFlags teleportObjType, uint32 modeFlags, uint32 teleportFlags) +{ + Point2F cameraPos; + SearchTeleporter_10 search; + + search.objType = Teleporter_GetServiceObjectType(teleportObjType); + search.modeFlags = modeFlags; + search.teleportFlags = teleportFlags; + if (modeFlags & 2) { + search.teleporter = (TeleporterService*)Gods98::Mem_Alloc(0x20); + Teleporter_Add(search.teleporter); + search.teleporter->count = 0; + if (teleportFlags & 2) { + cameraPos = Teleporter_GetCameraPosition(); + search.teleporter->cameraPos = cameraPos; + search.teleporter->float_8 = 0.0; + search.teleporter->float_c = teleporterGlobs.floatValue_3_0; + } + if (teleportFlags & 1) { + search.teleporter->int_14 = teleporterGlobs.intValue_40; + } + search.teleporter->flags = teleportFlags; + } + LegoObject_RunThroughListsSkipUpgradeParts(Teleporter_LiveObjectCallback_Service, &search); + return; +} // -//bool32 __cdecl LegoRR::Teleporter_LiveObjectCallback_Update(LegoObject* liveObj, void* data_unused); +bool32 __cdecl LegoRR::Teleporter_LiveObjectCallback_Update(LegoObject* liveObj, void* data_unused) +{ + uint32 uVar1; + float fVar2; + float fVar3; + short rng; + Point2F position; + TeleporterService* teleporter; + + if (liveObj->teleporter_modeFlags & 1) { + liveObj->health = -1.0; + liveObj->teleporter_teleportFlags = 0; + liveObj->teleporter_modeFlags = 4; + teleporterGlobs.count = teleporterGlobs.count - 1; + return FALSE; + } + if (liveObj->teleporter_modeFlags & 2) { + uVar1 = liveObj->teleporter_teleportFlags; + if ((uVar1 & 2) == 0) { + if ((uVar1 & 1) == 0) { + if ((uVar1 & 4) != 0) { + liveObj->health = -1.0; + liveObj->flags3 = liveObj->flags3 | LIVEOBJ3_REMOVING; + teleporterGlobs.count = teleporterGlobs.count - 1; + } + } + else { + teleporter = liveObj->teleporter; + rng = Gods98::Maths_Rand(); + if ((int)rng % teleporter->int_14 == 0) { + liveObj->health = -1.0; + teleporter->count = teleporter->count - 1; + goto LAB_0046a960; + } + } + } + else { + teleporter = liveObj->teleporter; + /* I think this teleports objects with priority to "near" the camera + when the level completed, as time progresses, units farther away + are teleported. */ + LegoObject_GetPosition(liveObj, &position.x, &position.y); + fVar3 = position.x - (teleporter->cameraPos).x; + fVar2 = position.y - (teleporter->cameraPos).y; + teleporter = liveObj->teleporter; + if (sqrt(fVar2 * fVar2 + fVar3 * fVar3) < teleporter->float_8) { + liveObj->health = -1.0; + teleporter->count = teleporter->count - 1; + LAB_0046a960: + liveObj->teleporter_modeFlags = 4; + liveObj->teleporter = nullptr; + liveObj->teleporter_teleportFlags = 0; + teleporterGlobs.count = teleporterGlobs.count - 1; + return FALSE; + } + } + } + return FALSE; +} // -//bool32 __cdecl LegoRR::Teleporter_UpdateService(TeleporterService* teleporter, real32 elapsedGame); +bool32 __cdecl LegoRR::Teleporter_UpdateService(TeleporterService* teleporter, real32 elapsedGame) +{ + if (teleporter != nullptr) { + do { + if ((teleporter->count) && (teleporter->flags == 2)) { + teleporter->float_8 = teleporter->float_c * elapsedGame + teleporter->float_8; + } + teleporter = teleporter->next; + } while (teleporter != nullptr); + } + return (bool32)teleporter; +} // -//void __cdecl LegoRR::Teleporter_Update(real32 elapsedGame); +void __cdecl LegoRR::Teleporter_Update(real32 elapsedGame) +{ + Teleporter_UpdateService(teleporterGlobs.current, elapsedGame); + if (teleporterGlobs.count) { + LegoObject_RunThroughListsSkipUpgradeParts(Teleporter_LiveObjectCallback_Update, nullptr); + } +} // -//LegoRR::LegoObject_Type __cdecl LegoRR::Teleporter_GetServiceObjectType(LegoObject_TypeFlags teleportObjType); +LegoRR::LegoObject_Type __cdecl LegoRR::Teleporter_GetServiceObjectType(LegoObject_TypeFlags teleportObjType) +{ + if ((teleportObjType & TELEPORT_SERVIVE_VEHICLE) != TELEPORT_SERVIVE_NONE) { + return LegoObject_Vehicle; + } + if ((teleportObjType & TELEPORT_SERVIVE_MINIFIGURE) != TELEPORT_SERVIVE_NONE) { + return LegoObject_MiniFigure; + } + if ((teleportObjType & TELEPORT_SERVIVE_ROCKMONSTER) != TELEPORT_SERVIVE_NONE) { + return LegoObject_RockMonster; + } + if ((teleportObjType & TELEPORT_SERVIVE_BUILDING) != TELEPORT_SERVIVE_NONE) { + return LegoObject_Building; + } + if ((teleportObjType & TELEPORT_SERVIVE_BOULDER) != TELEPORT_SERVIVE_NONE) { + return LegoObject_Boulder; + } + if ((teleportObjType & TELEPORT_SERVIVE_POWERCRYSTAL) != TELEPORT_SERVIVE_NONE) { + return LegoObject_PowerCrystal; + } + if ((teleportObjType & TELEPORT_SERVIVE_ORE) != TELEPORT_SERVIVE_NONE) { + return LegoObject_Ore; + } + if ((teleportObjType & TELEPORT_SERVIVE_DYNAMITE) != TELEPORT_SERVIVE_NONE) { + return LegoObject_Dynamite; + } + if ((teleportObjType & TELEPORT_SERVIVE_BARRIER) != TELEPORT_SERVIVE_NONE) { + return LegoObject_Barrier; + } + if ((teleportObjType & TELEPORT_SERVIVE_UPGRADEPART) != TELEPORT_SERVIVE_NONE) { + return LegoObject_UpgradePart; + } + if ((teleportObjType & TELEPORT_SERVIVE_ELECTRICFENCE) != TELEPORT_SERVIVE_NONE) { + return LegoObject_ElectricFence; + } + if ((teleportObjType & TELEPORT_SERVIVE_SPIDERWEB) != TELEPORT_SERVIVE_NONE) { + return LegoObject_SpiderWeb; + } + /* OBJECT_OOHSCARY */ + if ((teleportObjType & TELEPORT_SERVIVE_OOHSCARY) != TELEPORT_SERVIVE_NONE) { + return LegoObject_OohScary; + } + + // -FC, if we didnt find an object return none found + return LegoObject_None; +} + #pragma endregion diff --git a/src/openlrr/game/world/Teleporter.h b/src/openlrr/game/world/Teleporter.h index 528b342..5f4b27f 100644 --- a/src/openlrr/game/world/Teleporter.h +++ b/src/openlrr/game/world/Teleporter.h @@ -125,59 +125,47 @@ extern bool32 & g_Teleporter_BOOL_00504188; // Previously named Teleporter_Free (old name conflict with "Teleporter_RemoveAll", now Restart). // -#define Teleporter_RemoveAll ((void (__cdecl* )(TeleporterService* teleporter))0x0046a630) -//void __cdecl Teleporter_RemoveAll(TeleporterService* teleporter); +void __cdecl Teleporter_RemoveAll(TeleporterService* teleporter); // Previously named Teleporter_RemoveAll (old name conflict with "Teleporter_Free", now RemoveAll). // -#define Teleporter_Restart ((void (__cdecl* )(void))0x0046a650) -//void __cdecl Teleporter_Restart(void); +void __cdecl Teleporter_Restart(void); // DATA: SearchTeleporter_10* // -#define Teleporter_LiveObjectCallback_Service ((bool32 (__cdecl* )(LegoObject* liveObj, void* search))0x0046a680) -//bool32 __cdecl Teleporter_LiveObjectCallback_Service(LegoObject* liveObj, void* search); +bool32 __cdecl Teleporter_LiveObjectCallback_Service(LegoObject* liveObj, void* search); // Point2F is returned BY VALUE here. // -#define Teleporter_GetCameraPosition ((Point2F (__cdecl* )(void))0x0046a6e0) -//Point2F __cdecl Teleporter_GetCameraPosition(void); +Point2F __cdecl Teleporter_GetCameraPosition(void); // -#define Teleporter_Add ((void (__cdecl* )(TeleporterService* teleporter))0x0046a730) -//void __cdecl Teleporter_Add(TeleporterService* teleporter); +void __cdecl Teleporter_Add(TeleporterService* teleporter); // DATA: TeleportObjectType* (or LegoObject_TypeFlags*) // -#define Teleporter_LiveObjectCallback_Unk ((bool32 (__cdecl* )(LegoObject* liveObj, void* teleportObjType))0x0046a750) -//bool32 __cdecl Teleporter_LiveObjectCallback_Unk(LegoObject* liveObj, void* teleportObjType); +bool32 __cdecl Teleporter_LiveObjectCallback_Unk(LegoObject* liveObj, void* teleportObjType); // Returns true when all units specified by the flags have been teleported up. // -#define Teleporter_ServiceAll ((bool32 (__cdecl* )(LegoObject_TypeFlags teleportObjTypes))0x0046a780) -//bool32 __cdecl Teleporter_ServiceAll(LegoObject_TypeFlags teleportObjTypes); +bool32 __cdecl Teleporter_ServiceAll(LegoObject_TypeFlags teleportObjTypes); // -#define Teleporter_Start ((void (__cdecl* )(LegoObject_TypeFlags teleportObjType, uint32 modeFlags, uint32 teleportFlags))0x0046a7d0) -//void __cdecl Teleporter_Start(LegoObject_TypeFlags teleportObjType, uint32 modeFlags, uint32 teleportFlags); +void __cdecl Teleporter_Start(LegoObject_TypeFlags teleportObjType, uint32 modeFlags, uint32 teleportFlags); // -#define Teleporter_LiveObjectCallback_Update ((bool32 (__cdecl* )(LegoObject* liveObj, void* data_unused))0x0046a880) -//bool32 __cdecl Teleporter_LiveObjectCallback_Update(LegoObject* liveObj, void* data_unused); +bool32 __cdecl Teleporter_LiveObjectCallback_Update(LegoObject* liveObj, void* data_unused); // -#define Teleporter_UpdateService ((bool32 (__cdecl* )(TeleporterService* teleporter, real32 elapsedGame))0x0046a9c0) -//bool32 __cdecl Teleporter_UpdateService(TeleporterService* teleporter, real32 elapsedGame); +bool32 __cdecl Teleporter_UpdateService(TeleporterService* teleporter, real32 elapsedGame); // -#define Teleporter_Update ((void (__cdecl* )(real32 elapsedGame))0x0046a9f0) -//void __cdecl Teleporter_Update(real32 elapsedGame); +void __cdecl Teleporter_Update(real32 elapsedGame); // Returns the first object type matching the flags. // Only supports object types up to includeing LegoObject_OohScary. // -#define Teleporter_GetServiceObjectType ((LegoObject_Type (__cdecl* )(LegoObject_TypeFlags teleportObjType))0x0046aa20) -//LegoObject_Type __cdecl Teleporter_GetServiceObjectType(LegoObject_TypeFlags teleportObjType); +LegoObject_Type __cdecl Teleporter_GetServiceObjectType(LegoObject_TypeFlags teleportObjType); #pragma endregion diff --git a/src/openlrr/interop.cpp b/src/openlrr/interop.cpp index 4f4538b..932da34 100644 --- a/src/openlrr/interop.cpp +++ b/src/openlrr/interop.cpp @@ -82,6 +82,7 @@ #include "game/world/Fallin.h" #include "game/world/Roof.h" #include "game/world/SelectPlace.h" +#include "game/world/Teleporter.h" #include "game/world/Water.h" #include "game/Game.h" @@ -4160,6 +4161,49 @@ bool interop_hook_LegoRR_Stats(void) return_interop(result); } +bool interop_hook_LegoRR_Teleporter(void) +{ + bool result = true; + + // used by: Teleporter_Restart + result &= hook_write_jmpret(0x0046a630, LegoRR::Teleporter_RemoveAll); + + // used by: Lego_LoadLevel + result &= hook_write_jmpret(0x0046a650, LegoRR::Teleporter_Restart); + + // used by: Teleporter_Start + result &= hook_write_jmpret(0x0046a680, LegoRR::Teleporter_LiveObjectCallback_Service); + + // used by: Teleporter_Start + result &= hook_write_jmpret(0x0046a6e0, LegoRR::Teleporter_GetCameraPosition); + + // used by: Teleporter_Start + result &= hook_write_jmpret(0x0046a730, LegoRR::Teleporter_Add); + + // used by: Teleporter_ServiceAll + result &= hook_write_jmpret(0x0046a750, LegoRR::Teleporter_LiveObjectCallback_Unk); + + // used by: Lego_UnkTeleporterInit_FUN_0043598, NERPFunc__GetOxygenLevel, Objective_HandleKeys, Objective_Update + result &= hook_write_jmpret(0x0046a780, LegoRR::Teleporter_ServiceAll); + + // used by: Lego_StartLevelEnding, Objective_SetStatus + result &= hook_write_jmpret(0x0046a7d0, LegoRR::Teleporter_Start); + + // used by: Teleporter_Update + result &= hook_write_jmpret(0x0046a880, LegoRR::Teleporter_LiveObjectCallback_Update); + + // used by: Teleporter_Update + result &= hook_write_jmpret(0x0046a9c0, LegoRR::Teleporter_UpdateService); + + // used by: Lego_MainLoop + result &= hook_write_jmpret(0x0046a9f0, LegoRR::Teleporter_Update); + + // used by: Teleporter_LiveObjectCallback_Unk, Teleporter_Start + result &= hook_write_jmpret(0x0046aa20, LegoRR::Teleporter_GetServiceObjectType); + + return_interop(result); +} + bool interop_hook_LegoRR_TextMessages(void) { bool result = true; @@ -4560,6 +4604,7 @@ bool interop_hook_all(void) result &= interop_hook_LegoRR_SFX(); result &= interop_hook_LegoRR_Smoke(); result &= interop_hook_LegoRR_Stats(); + result &= interop_hook_LegoRR_Teleporter(); result &= interop_hook_LegoRR_TextMessages(); result &= interop_hook_LegoRR_ToolTip(); result &= interop_hook_LegoRR_Vehicle(); diff --git a/src/openlrr/interop.h b/src/openlrr/interop.h index 3cb9049..61dd8e6 100644 --- a/src/openlrr/interop.h +++ b/src/openlrr/interop.h @@ -94,6 +94,7 @@ bool interop_hook_LegoRR_SFX(void); bool interop_hook_LegoRR_Smoke(void); bool interop_hook_LegoRR_Stats(void); bool interop_hook_LegoRR_ToolTip(void); +bool interop_hook_LegoRR_Teleporter(void); bool interop_hook_LegoRR_TextMessages(void); bool interop_hook_LegoRR_Vehicle(void); bool interop_hook_LegoRR_Water(void);