|
16 | 16 | #include <Events/PartyJoinedEvent.h> |
17 | 17 | #include <Events/PartyLeftEvent.h> |
18 | 18 | #include <Events/BeastFormChangeEvent.h> |
| 19 | +#include <Events/EquipmentChangeEvent.h> |
19 | 20 |
|
20 | 21 | #include <Messages/PlayerRespawnRequest.h> |
21 | 22 | #include <Messages/NotifyPlayerRespawn.h> |
|
35 | 36 | #include <Games/References.h> |
36 | 37 | #include <AI/AIProcess.h> |
37 | 38 | #include <EquipManager.h> |
| 39 | +#include <DefaultObjectManager.h> |
38 | 40 | #include <Forms/TESRace.h> |
39 | 41 |
|
40 | 42 | PlayerService::PlayerService(World& aWorld, entt::dispatcher& aDispatcher, TransportService& aTransport) noexcept |
@@ -208,9 +210,32 @@ void PlayerService::RunRespawnUpdates(const double acDeltaTime) noexcept |
208 | 210 | PlayerCharacter* pPlayer = PlayerCharacter::Get(); |
209 | 211 | if (!pPlayer->actorState.IsBleedingOut()) |
210 | 212 | { |
211 | | - // Cache equipped spells and shouts so we can restore them after respawn. |
212 | | - m_cachedMainSpellId = pPlayer->magicItems[0] ? pPlayer->magicItems[0]->formID : 0; |
213 | | - m_cachedSecondarySpellId = pPlayer->magicItems[1] ? pPlayer->magicItems[1]->formID : 0; |
| 213 | + // Cache equipped items, spells, and shouts so we can restore them after respawn. |
| 214 | + m_cachedLeftHandSpellId = pPlayer->magicItems[0] ? pPlayer->magicItems[0]->formID : 0; |
| 215 | + m_cachedRightHandSpellId = pPlayer->magicItems[1] ? pPlayer->magicItems[1]->formID : 0; |
| 216 | + |
| 217 | + TESForm* pLeftEquipped = nullptr; |
| 218 | + TESForm* pRightEquipped = nullptr; |
| 219 | + |
| 220 | + if (m_cachedLeftHandSpellId == 0) |
| 221 | + pLeftEquipped = pPlayer->GetEquippedWeapon(0); |
| 222 | + if (m_cachedRightHandSpellId == 0) |
| 223 | + pRightEquipped = pPlayer->GetEquippedWeapon(1); |
| 224 | + |
| 225 | + m_cachedLeftHandItemId = pLeftEquipped ? pLeftEquipped->formID : 0; |
| 226 | + m_cachedRightHandItemId = pRightEquipped ? pRightEquipped->formID : 0; |
| 227 | + |
| 228 | + // Detect two-handed weapons so we can equip them via the either-hand slot. |
| 229 | + if (pLeftEquipped && pRightEquipped && pLeftEquipped == pRightEquipped) |
| 230 | + m_cachedTwoHandedItemId = pLeftEquipped->formID; |
| 231 | + else |
| 232 | + m_cachedTwoHandedItemId = 0; |
| 233 | + |
| 234 | + if (auto* pAmmo = pPlayer->GetEquippedAmmo()) |
| 235 | + m_cachedAmmoId = pAmmo->formID; |
| 236 | + else |
| 237 | + m_cachedAmmoId = 0; |
| 238 | + |
214 | 239 | m_cachedPowerId = pPlayer->equippedShout ? pPlayer->equippedShout->formID : 0; |
215 | 240 |
|
216 | 241 | s_startTimer = false; |
@@ -318,24 +343,57 @@ void PlayerService::RunRespawnUpdates(const double acDeltaTime) noexcept |
318 | 343 | m_knockdownTimer = 1.5; |
319 | 344 | m_knockdownStart = true; |
320 | 345 |
|
| 346 | + // Restore cached equipment |
| 347 | + auto* pEquipManager = EquipManager::Get(); |
| 348 | + auto& defaultObjects = DefaultObjectManager::Get(); |
| 349 | + |
| 350 | + if (m_cachedLeftHandSpellId) |
| 351 | + { |
| 352 | + if (TESForm* pSpell = TESForm::GetById(m_cachedLeftHandSpellId)) |
| 353 | + pEquipManager->EquipSpell(pPlayer, pSpell, 0); |
| 354 | + } |
| 355 | + else if (m_cachedLeftHandItemId && m_cachedTwoHandedItemId == 0) |
| 356 | + { |
| 357 | + if (TESForm* pItem = TESForm::GetById(m_cachedLeftHandItemId)) |
| 358 | + pEquipManager->Equip(pPlayer, pItem, nullptr, 1, defaultObjects.leftEquipSlot, false, true, false, false); |
| 359 | + } |
| 360 | + |
| 361 | + if (m_cachedRightHandSpellId) |
| 362 | + { |
| 363 | + if (TESForm* pSpell = TESForm::GetById(m_cachedRightHandSpellId)) |
| 364 | + pEquipManager->EquipSpell(pPlayer, pSpell, 1); |
| 365 | + } |
| 366 | + else if (m_cachedTwoHandedItemId) |
| 367 | + { |
| 368 | + if (TESForm* pItem = TESForm::GetById(m_cachedTwoHandedItemId)) |
| 369 | + pEquipManager->Equip(pPlayer, pItem, nullptr, 1, defaultObjects.eitherEquipSlot, false, true, false, false); |
| 370 | + } |
| 371 | + else if (m_cachedRightHandItemId) |
| 372 | + { |
| 373 | + if (TESForm* pItem = TESForm::GetById(m_cachedRightHandItemId)) |
| 374 | + pEquipManager->Equip(pPlayer, pItem, nullptr, 1, defaultObjects.rightEquipSlot, false, true, false, false); |
| 375 | + } |
| 376 | + |
| 377 | + if (m_cachedAmmoId) |
| 378 | + { |
| 379 | + if (TESForm* pAmmo = TESForm::GetById(m_cachedAmmoId)) |
| 380 | + pEquipManager->Equip(pPlayer, pAmmo, nullptr, 1, defaultObjects.rightEquipSlot, false, true, false, false); |
| 381 | + } |
| 382 | + |
| 383 | + if (m_cachedPowerId) |
| 384 | + { |
| 385 | + if (TESForm* pShout = TESForm::GetById(m_cachedPowerId)) |
| 386 | + pEquipManager->EquipShout(pPlayer, pShout); |
| 387 | + } |
| 388 | + |
| 389 | + SyncCachedEquipment(pPlayer); |
| 390 | + |
321 | 391 | m_transport.Send(PlayerRespawnRequest()); |
322 | 392 |
|
323 | 393 | PartyMemberDownedRequest revivedRequest{}; |
324 | 394 | revivedRequest.IsDowned = false; |
325 | 395 | m_transport.Send(revivedRequest); |
326 | 396 |
|
327 | | - // Restore spells and shouts |
328 | | - auto* pEquipManager = EquipManager::Get(); |
329 | | - TESForm* pSpell = TESForm::GetById(m_cachedMainSpellId); |
330 | | - if (pSpell) |
331 | | - pEquipManager->EquipSpell(pPlayer, pSpell, 0); |
332 | | - pSpell = TESForm::GetById(m_cachedSecondarySpellId); |
333 | | - if (pSpell) |
334 | | - pEquipManager->EquipSpell(pPlayer, pSpell, 1); |
335 | | - pSpell = TESForm::GetById(m_cachedPowerId); |
336 | | - if (pSpell) |
337 | | - pEquipManager->EquipShout(pPlayer, pSpell); |
338 | | - |
339 | 397 | m_waitingForRespawn = false; |
340 | 398 | m_canRespawn = false; |
341 | 399 | m_respawnTimer = 0.0; |
@@ -364,6 +422,53 @@ void PlayerService::RunRespawnUpdates(const double acDeltaTime) noexcept |
364 | 422 | } |
365 | 423 | } |
366 | 424 |
|
| 425 | +void PlayerService::SyncCachedEquipment(PlayerCharacter* apPlayer) noexcept |
| 426 | +{ |
| 427 | + if (!apPlayer) |
| 428 | + return; |
| 429 | + |
| 430 | + auto& defaultObjects = DefaultObjectManager::Get(); |
| 431 | + |
| 432 | + const auto dispatch = [&](uint32_t itemId, TESForm* pSlot, bool isSpell, bool isShout, bool isAmmo = false) |
| 433 | + { |
| 434 | + if (!itemId) |
| 435 | + return; |
| 436 | + |
| 437 | + if (!TESForm::GetById(itemId)) |
| 438 | + return; |
| 439 | + |
| 440 | + EquipmentChangeEvent evt{}; |
| 441 | + evt.ActorId = apPlayer->formID; |
| 442 | + evt.ItemId = itemId; |
| 443 | + evt.EquipSlotId = pSlot ? pSlot->formID : 0; |
| 444 | + evt.IsSpell = isSpell; |
| 445 | + evt.IsShout = isShout; |
| 446 | + evt.IsAmmo = isAmmo; |
| 447 | + if (!isSpell && !isShout) |
| 448 | + evt.Count = 1; |
| 449 | + |
| 450 | + m_world.GetRunner().Trigger(evt); |
| 451 | + }; |
| 452 | + |
| 453 | + dispatch(m_cachedLeftHandSpellId, defaultObjects.leftEquipSlot, true, false); |
| 454 | + dispatch(m_cachedRightHandSpellId, defaultObjects.rightEquipSlot, true, false); |
| 455 | + |
| 456 | + if (m_cachedTwoHandedItemId) |
| 457 | + { |
| 458 | + dispatch(m_cachedTwoHandedItemId, defaultObjects.eitherEquipSlot, false, false); |
| 459 | + } |
| 460 | + else |
| 461 | + { |
| 462 | + if (m_cachedLeftHandSpellId == 0) |
| 463 | + dispatch(m_cachedLeftHandItemId, defaultObjects.leftEquipSlot, false, false); |
| 464 | + if (m_cachedRightHandSpellId == 0) |
| 465 | + dispatch(m_cachedRightHandItemId, defaultObjects.rightEquipSlot, false, false); |
| 466 | + } |
| 467 | + |
| 468 | + dispatch(m_cachedAmmoId, defaultObjects.rightEquipSlot, false, false, true); |
| 469 | + dispatch(m_cachedPowerId, nullptr, false, true); |
| 470 | +} |
| 471 | + |
367 | 472 | void PlayerService::RequestManualRespawn() noexcept |
368 | 473 | { |
369 | 474 | try |
|
0 commit comments