#include "common.h" #include "patcher.h" #include "Bridge.h" #include "Pools.h" #include "ModelIndices.h" #include "PathFind.h" #include "Stats.h" CEntity*& CBridge::pLiftRoad = *(CEntity**)0x8E2C8C; CEntity*& CBridge::pLiftPart = *(CEntity**)0x8E2C94; CEntity*& CBridge::pWeight = *(CEntity**)0x8E28BC; int& CBridge::State = *(int*)0x8F2A1C; int& CBridge::OldState = *(int*)0x8F2A20; float& CBridge::DefaultZLiftPart = *(float*)0x941430; float& CBridge::DefaultZLiftRoad = *(float*)0x941438; float& CBridge::DefaultZLiftWeight = *(float*)0x8F1A44; float& CBridge::OldLift = *(float*)0x8F6254; uint32& CBridge::TimeOfBridgeBecomingOperational = *(uint32*)0x8F2BC0; void CBridge::Init() { FindBridgeEntities(); OldLift = -1.0; if (pLiftPart && pWeight) { DefaultZLiftPart = pLiftPart->GetPosition().z; DefaultZLiftWeight = pWeight->GetPosition().z; if (pLiftRoad) DefaultZLiftRoad = pLiftRoad->GetPosition().z; ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, true); } } void CBridge::Update() { if (!pLiftPart || !pWeight) return; OldState = State; float liftHeight; // Set bridge height and state if (CStats::CommercialPassed) { if (TimeOfBridgeBecomingOperational == 0) TimeOfBridgeBecomingOperational = CTimer::GetTimeInMilliseconds(); // Time remaining for bridge to become operational // uint16, so after about a minute it overflows to 0 and the cycle repeats uint16 timeElapsed = CTimer::GetTimeInMilliseconds() - TimeOfBridgeBecomingOperational; // Calculate lift part height and bridge state if (timeElapsed < 10000) { State = STATE_LIFT_PART_MOVING_DOWN; liftHeight = 25.0 - timeElapsed / 10000.0 * 25.0; } else if (timeElapsed < 40000) { liftHeight = 0.0; State = STATE_LIFT_PART_IS_DOWN; } else if (timeElapsed < 50000) { liftHeight = 0.0; State = STATE_LIFT_PART_ABOUT_TO_MOVE_UP; } else if (timeElapsed < 60000) { State = STATE_LIFT_PART_MOVING_UP; liftHeight = (timeElapsed - 50000) / 10000.0 * 25.0; } else { liftHeight = 25.0; State = STATE_LIFT_PART_IS_UP; } } else { liftHeight = 25.0; TimeOfBridgeBecomingOperational = 0; State = STATE_BRIDGE_LOCKED; } // Move bridge part if (liftHeight != OldLift) { pLiftPart->GetPosition().z = DefaultZLiftPart + liftHeight; pLiftPart->GetMatrix().UpdateRW(); pLiftPart->UpdateRwFrame(); if (pLiftRoad) { pLiftRoad->GetPosition().z = DefaultZLiftRoad + liftHeight; pLiftRoad->GetMatrix().UpdateRW(); pLiftRoad->UpdateRwFrame(); } pWeight->GetPosition().z = DefaultZLiftWeight - liftHeight; pWeight->GetMatrix().UpdateRW(); pWeight->UpdateRwFrame(); OldLift = liftHeight; } if (State == STATE_LIFT_PART_ABOUT_TO_MOVE_UP && OldState == STATE_LIFT_PART_IS_DOWN) ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, true); else if (State == STATE_LIFT_PART_IS_DOWN && OldState == STATE_LIFT_PART_MOVING_DOWN) ThePaths.SetLinksBridgeLights(-330.0, -230.0, -700.0, -588.0, false); } bool CBridge::ShouldLightsBeFlashing() { return State != STATE_LIFT_PART_IS_DOWN; } void CBridge::FindBridgeEntities() { pWeight = nil; pLiftRoad = nil; pLiftPart = nil; for (int i = CPools::GetBuildingPool()->GetSize()-1; i >= 0; i--) { CBuilding* entry = CPools::GetBuildingPool()->GetSlot(i); if (entry) { if (entry->GetModelIndex() == MI_BRIDGELIFT) pLiftPart = entry; else if (entry->GetModelIndex() == MI_BRIDGEROADSEGMENT) pLiftRoad = entry; else if (entry->GetModelIndex() == MI_BRIDGEWEIGHT) pWeight = entry; } } } bool CBridge::ThisIsABridgeObjectMovingUp(int index) { if (index != MI_BRIDGEROADSEGMENT && index != MI_BRIDGELIFT) return false; return State == STATE_LIFT_PART_ABOUT_TO_MOVE_UP || State == STATE_LIFT_PART_MOVING_UP; } STARTPATCHES InjectHook(0x413A30, &CBridge::Init, PATCH_JUMP); InjectHook(0x413AC0, &CBridge::Update, PATCH_JUMP); InjectHook(0x413D10, &CBridge::ShouldLightsBeFlashing, PATCH_JUMP); InjectHook(0x413D20, &CBridge::FindBridgeEntities, PATCH_JUMP); InjectHook(0x413DE0, &CBridge::ThisIsABridgeObjectMovingUp, PATCH_JUMP); ENDPATCHES