From 49047a267b9f78af4a814b262ae0908dd5828b6a Mon Sep 17 00:00:00 2001 From: David Markowitz <39972741+EmosewaMC@users.noreply.github.com> Date: Sun, 5 Mar 2023 12:34:59 -0800 Subject: [PATCH] Fix racing imagination loss on death (#1006) * Fix imagination on death * Fix defaults * Fix visuals --- dCommon/dEnums/dMessageIdentifiers.h | 2 + dGame/dComponents/RacingControlComponent.cpp | 81 ++++++++++++-------- dGame/dGameMessages/GameMessages.cpp | 30 ++++++++ dGame/dGameMessages/GameMessages.h | 6 +- 4 files changed, 85 insertions(+), 34 deletions(-) diff --git a/dCommon/dEnums/dMessageIdentifiers.h b/dCommon/dEnums/dMessageIdentifiers.h index c1afc497..e11f9e7f 100644 --- a/dCommon/dEnums/dMessageIdentifiers.h +++ b/dCommon/dEnums/dMessageIdentifiers.h @@ -546,6 +546,8 @@ enum GAME_MSG : unsigned short { GAME_MSG_REMOVE_RUN_SPEED_MODIFIER = 1506, GAME_MSG_UPDATE_PROPERTY_PERFORMANCE_COST = 1547, GAME_MSG_PROPERTY_ENTRANCE_BEGIN = 1553, + GAME_MSG_SET_RESURRECT_RESTORE_VALUES = 1591, + GAME_MSG_VEHICLE_STOP_BOOST = 1617, GAME_MSG_REMOVE_BUFF = 1648, GAME_MSG_REQUEST_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1666, GAME_MSG_RESPONSE_MOVE_ITEM_BETWEEN_INVENTORY_TYPES = 1667, diff --git a/dGame/dComponents/RacingControlComponent.cpp b/dGame/dComponents/RacingControlComponent.cpp index 4b27ac0f..fe4f1faf 100644 --- a/dGame/dComponents/RacingControlComponent.cpp +++ b/dGame/dComponents/RacingControlComponent.cpp @@ -306,30 +306,58 @@ void RacingControlComponent::OnRequestDie(Entity* player) { auto* vehicle = EntityManager::Instance()->GetEntity(racingPlayer.vehicleID); - if (vehicle == nullptr) { - return; - } + if (!vehicle) return; if (!racingPlayer.noSmashOnReload) { racingPlayer.smashedTimes++; + GameMessages::SendDie(vehicle, vehicle->GetObjectID(), LWOOBJID_EMPTY, true, + VIOLENT, u"", 0, 0, 90.0f, false, true, 0); + + auto* destroyableComponent = vehicle->GetComponent(); + uint32_t respawnImagination = 0; + // Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live. + // Do not actually change the value yet. Do that on respawn. + if (destroyableComponent) { + respawnImagination = static_cast(ceil(destroyableComponent->GetImagination() / 2.0f / 10.0f)) * 10.0f; + GameMessages::SendSetResurrectRestoreValues(vehicle, -1, -1, respawnImagination); + } + + // Respawn the player in 2 seconds, as was done in live. Not sure if this value is in a setting somewhere else... + vehicle->AddCallbackTimer(2.0f, [=]() { + if (!vehicle || !this->m_Parent) return; + GameMessages::SendRacingResetPlayerToLastReset( + m_Parent->GetObjectID(), racingPlayer.playerID, + UNASSIGNED_SYSTEM_ADDRESS); + + GameMessages::SendVehicleStopBoost(vehicle, player->GetSystemAddress(), true); + + GameMessages::SendRacingSetPlayerResetInfo( + m_Parent->GetObjectID(), racingPlayer.lap, + racingPlayer.respawnIndex, player->GetObjectID(), + racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1, + UNASSIGNED_SYSTEM_ADDRESS); + + GameMessages::SendResurrect(vehicle); + auto* destroyableComponent = vehicle->GetComponent(); + // Reset imagination to half its current value, rounded up to the nearest value divisible by 10, as it was done in live. + if (destroyableComponent) destroyableComponent->SetImagination(respawnImagination); + EntityManager::Instance()->SerializeEntity(vehicle); + }); + + auto* characterComponent = player->GetComponent(); + if (characterComponent != nullptr) { + characterComponent->UpdatePlayerStatistic(RacingTimesWrecked); + } + } else { + GameMessages::SendRacingSetPlayerResetInfo( + m_Parent->GetObjectID(), racingPlayer.lap, + racingPlayer.respawnIndex, player->GetObjectID(), + racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1, + UNASSIGNED_SYSTEM_ADDRESS); + GameMessages::SendRacingResetPlayerToLastReset( + m_Parent->GetObjectID(), racingPlayer.playerID, + UNASSIGNED_SYSTEM_ADDRESS); } - - // Reset player to last checkpoint - GameMessages::SendRacingSetPlayerResetInfo( - m_Parent->GetObjectID(), racingPlayer.lap, - racingPlayer.respawnIndex, player->GetObjectID(), - racingPlayer.respawnPosition, racingPlayer.respawnIndex + 1, - UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendRacingResetPlayerToLastReset( - m_Parent->GetObjectID(), racingPlayer.playerID, - UNASSIGNED_SYSTEM_ADDRESS); - - auto* characterComponent = player->GetComponent(); - if (characterComponent != nullptr) { - characterComponent->UpdatePlayerStatistic(RacingTimesWrecked); - } - - return; } } @@ -348,19 +376,6 @@ void RacingControlComponent::OnRacingPlayerInfoResetFinished(Entity* player) { return; } - if (!racingPlayer.noSmashOnReload) { - GameMessages::SendDie(vehicle, LWOOBJID_EMPTY, LWOOBJID_EMPTY, true, - VIOLENT, u"", 0, 0, 0, true, false, 0); - - GameMessages::SendVehicleUnlockInput(racingPlayer.vehicleID, false, - UNASSIGNED_SYSTEM_ADDRESS); - GameMessages::SendVehicleSetWheelLockState( - racingPlayer.vehicleID, false, false, - UNASSIGNED_SYSTEM_ADDRESS); - - GameMessages::SendResurrect(vehicle); - } - racingPlayer.noSmashOnReload = false; return; diff --git a/dGame/dGameMessages/GameMessages.cpp b/dGame/dGameMessages/GameMessages.cpp index 9dcd2d74..c8860283 100644 --- a/dGame/dGameMessages/GameMessages.cpp +++ b/dGame/dGameMessages/GameMessages.cpp @@ -4396,6 +4396,36 @@ void GameMessages::SendRacingResetPlayerToLastReset(LWOOBJID objectId, LWOOBJID SEND_PACKET; } +void GameMessages::SendVehicleStopBoost(Entity* targetEntity, const SystemAddress& playerSysAddr, bool affectPassive) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(targetEntity->GetObjectID()); + bitStream.Write(GAME_MSG::GAME_MSG_VEHICLE_STOP_BOOST); + + bitStream.Write(affectPassive); + + SEND_PACKET_BROADCAST; +} + +void GameMessages::SendSetResurrectRestoreValues(Entity* targetEntity, int32_t armorRestore, int32_t healthRestore, int32_t imaginationRestore) { + CBITSTREAM; + CMSGHEADER; + + bitStream.Write(targetEntity->GetObjectID()); + bitStream.Write(GAME_MSG::GAME_MSG_SET_RESURRECT_RESTORE_VALUES); + + bitStream.Write(armorRestore != -1); + if (armorRestore != -1) bitStream.Write(armorRestore); + + bitStream.Write(healthRestore != -1); + if (healthRestore != -1) bitStream.Write(healthRestore); + + bitStream.Write(imaginationRestore != -1); + if (imaginationRestore != -1) bitStream.Write(imaginationRestore); + + SEND_PACKET_BROADCAST; +} void GameMessages::SendNotifyRacingClient(LWOOBJID objectId, int32_t eventType, int32_t param1, LWOOBJID paramObj, std::u16string paramStr, LWOOBJID singleClient, const SystemAddress& sysAddr) { CBITSTREAM; diff --git a/dGame/dGameMessages/GameMessages.h b/dGame/dGameMessages/GameMessages.h index 0675ae76..5d199995 100644 --- a/dGame/dGameMessages/GameMessages.h +++ b/dGame/dGameMessages/GameMessages.h @@ -31,7 +31,8 @@ namespace GameMessages { void SendPlayerAllowedRespawn(LWOOBJID entityID, bool doNotPromptRespawn, const SystemAddress& systemAddress); void SendInvalidZoneTransferList(Entity* entity, const SystemAddress& sysAddr, const std::u16string& feedbackURL, const std::u16string& invalidMapTransferList, bool feedbackOnExit, bool feedbackOnInvalidTransfer); void SendKnockback(const LWOOBJID& objectID, const LWOOBJID& caster, const LWOOBJID& originator, int knockBackTimeMS, const NiPoint3& vector); - + // https://lcdruniverse.org/lu_packets/lu_packets/world/gm/client/struct.VehicleStopBoost.html + void SendVehicleStopBoost(Entity* targetEntity, const SystemAddress& playerSysAddr, bool affectPassive); void SendStartArrangingWithItem( Entity* entity, const SystemAddress& sysAddr, @@ -125,6 +126,9 @@ namespace GameMessages { void HandleUnUseModel(RakNet::BitStream* inStream, Entity* entity, const SystemAddress& sysAddr); void SendStartCelebrationEffect(Entity* entity, const SystemAddress& sysAddr, int celebrationID); + // https://lcdruniverse.org/lu_packets/lu_packets/world/gm/client/struct.SetResurrectRestoreValues.html + void SendSetResurrectRestoreValues(Entity* targetEntity, int32_t armorRestore, int32_t healthRestore, int32_t imaginationRestore); + /** * Sends a message to an Entity to smash itself, but not delete or destroy itself from the world *