Skip to content

Commit 9b620f1

Browse files
Merge pull request #683 from tiltedphoques/feat/vampireLordRevamped
Beast form sync (Vampire Lord, werewolf)
2 parents 61af7d1 + 04f7e03 commit 9b620f1

18 files changed

+170
-33
lines changed
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#pragma once
2+
3+
/**
4+
* @brief Dispatched when the local player enters or leaves beast form (vampire lord, werewolf).
5+
*/
6+
struct BeastFormChangeEvent
7+
{
8+
};

Code/client/Events/LeaveBeastFormEvent.h

Lines changed: 0 additions & 8 deletions
This file was deleted.

Code/client/Games/Animation.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
TP_THIS_FUNCTION(TPerformAction, uint8_t, ActorMediator, TESActionData* apAction);
1818
static TPerformAction* RealPerformAction;
1919

20+
// TODO: make scoped override
2021
thread_local bool g_forceAnimation = false;
2122

2223
uint8_t TP_MAKE_THISCALL(HookPerformAction, ActorMediator, TESActionData* apAction)

Code/client/Games/Skyrim/Actor.cpp

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <Services/PapyrusService.h>
2222

2323
#include <Forms/ActorValueInfo.h>
24+
#include <Forms/TESRace.h>
2425

2526
#include <Effects/ValueModifierEffect.h>
2627

@@ -579,12 +580,58 @@ void Actor::Reset() noexcept
579580
s_pReset(this, 0, nullptr);
580581
}
581582

583+
bool Actor::PlayIdle(TESIdleForm* apIdle) noexcept
584+
{
585+
PAPYRUS_FUNCTION(bool, Actor, PlayIdle, TESIdleForm*);
586+
return s_pPlayIdle(this, apIdle);
587+
}
588+
582589
void Actor::Respawn() noexcept
583590
{
584591
Resurrect(false);
585592
Reset();
586593
}
587594

595+
bool Actor::IsVampireLord() const noexcept
596+
{
597+
return race && race->formID == 0x200283A;
598+
}
599+
600+
extern thread_local bool g_forceAnimation;
601+
602+
void Actor::FixVampireLordModel() noexcept
603+
{
604+
TESBoundObject* pObject = Cast<TESBoundObject>(TESForm::GetById(0x2011a84));
605+
if (!pObject)
606+
return;
607+
608+
{
609+
ScopedInventoryOverride _;
610+
AddObjectToContainer(pObject, nullptr, 1, nullptr);
611+
}
612+
613+
EquipManager::Get()->Equip(this, pObject, nullptr, 1, nullptr, false, true, false, false);
614+
615+
g_forceAnimation = true;
616+
617+
BSFixedString str("isLevitating");
618+
uint32_t isLevitating = GetAnimationVariableInt(&str);
619+
spdlog::critical("isLevitating {}", isLevitating);
620+
621+
// By default, a loaded vampire lord is not levitating.
622+
if (isLevitating)
623+
{
624+
BSFixedString levitation("LevitationToggle");
625+
SendAnimationEvent(&levitation);
626+
}
627+
628+
// TODO: weapon draw code does not seem to take care of this
629+
//BSFixedString weapEquip("WeapEquip");
630+
//SendAnimationEvent(&weapEquip);
631+
632+
g_forceAnimation = false;
633+
}
634+
588635
TP_THIS_FUNCTION(TForceState, void, Actor, const NiPoint3&, float, float, TESObjectCELL*, TESWorldSpace*, bool);
589636
static TForceState* RealForceState = nullptr;
590637

Code/client/Games/Skyrim/Actor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ struct ExPlayerCharacter;
2121
struct ActorExtension;
2222
struct AIProcess;
2323
struct CombatController;
24+
struct TESIdleForm;
2425

2526
struct Actor : TESObjectREFR
2627
{
@@ -208,6 +209,7 @@ struct Actor : TESObjectREFR
208209
[[nodiscard]] uint8_t GetPerkRank(uint32_t aPerkFormId) const noexcept;
209210
[[nodiscard]] bool IsWearingBodyPiece() const noexcept;
210211
[[nodiscard]] bool ShouldWearBodyPiece() const noexcept;
212+
[[nodiscard]] bool IsVampireLord() const noexcept;
211213

212214
// Setters
213215
void SetSpeed(float aSpeed) noexcept;
@@ -246,6 +248,8 @@ struct Actor : TESObjectREFR
246248
void SetCombatTargetEx(Actor* apTarget) noexcept;
247249
void StartCombat(Actor* apTarget) noexcept;
248250
void StopCombat() noexcept;
251+
bool PlayIdle(TESIdleForm* apIdle) noexcept;
252+
void FixVampireLordModel() noexcept;
249253

250254
enum ActorFlags
251255
{

Code/client/Games/Skyrim/PlayerCharacter.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@
22
#include <Games/ActorExtension.h>
33

44
#include <Structs/Skyrim/AnimationGraphDescriptor_Master_Behavior.h>
5+
#include <Structs/Skyrim/AnimationGraphDescriptor_VampireLordBehavior.h>
56

67
#include <Games/Overrides.h>
78

89
#include <Events/InventoryChangeEvent.h>
9-
#include <Events/LeaveBeastFormEvent.h>
10+
#include <Events/BeastFormChangeEvent.h>
1011
#include <Events/AddExperienceEvent.h>
1112
#include <Events/SetWaypointEvent.h>
1213
#include <Events/RemoveWaypointEvent.h>
@@ -162,7 +163,7 @@ void TP_MAKE_THISCALL(HookSetBeastForm, void, void* apUnk1, void* apUnk2, bool a
162163
if (!aEntering)
163164
{
164165
PlayerCharacter::Get()->GetExtension()->GraphDescriptorHash = AnimationGraphDescriptor_Master_Behavior::m_key;
165-
World::Get().GetRunner().Trigger(LeaveBeastFormEvent());
166+
World::Get().GetRunner().Trigger(BeastFormChangeEvent());
166167
}
167168

168169
TiltedPhoques::ThisCall(RealSetBeastForm, apThis, apUnk1, apUnk2, aEntering);

Code/client/Games/Skyrim/TESObjectREFR.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,15 @@ void TESObjectREFR::EnableImpl() noexcept
536536
TiltedPhoques::ThisCall(s_enable, this, false);
537537
}
538538

539+
uint32_t TESObjectREFR::GetAnimationVariableInt(BSFixedString* apVariableName) noexcept
540+
{
541+
using ObjectReference = TESObjectREFR;
542+
543+
PAPYRUS_FUNCTION(uint32_t, ObjectReference, GetAnimationVariableInt, BSFixedString*);
544+
545+
return s_pGetAnimationVariableInt(this, apVariableName);
546+
}
547+
539548
static thread_local bool s_cancelAnimationWaitEvent = false;
540549

541550
bool TESObjectREFR::PlayAnimationAndWait(BSFixedString* apAnimation, BSFixedString* apEventName) noexcept
@@ -578,6 +587,11 @@ bool TESObjectREFR::PlayAnimation(BSFixedString* apEventName) noexcept
578587
return result;
579588
}
580589

590+
bool TESObjectREFR::SendAnimationEvent(BSFixedString* apEventName) noexcept
591+
{
592+
return animationGraphHolder.SendAnimationEvent(apEventName);
593+
}
594+
581595
bool TP_MAKE_THISCALL(HookPlayAnimation, void, uint32_t auiStackID, TESObjectREFR* apSelf, BSFixedString* apEventName)
582596
{
583597
spdlog::debug("EventName: {}", apEventName->AsAscii());

Code/client/Games/Skyrim/TESObjectREFR.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ struct TESObjectREFR : TESForm
167167

168168
void SaveAnimationVariables(AnimationVariables& aWriter) const noexcept;
169169
void LoadAnimationVariables(const AnimationVariables& aReader) const noexcept;
170+
uint32_t GetAnimationVariableInt(BSFixedString* apVariableName) noexcept;
170171

171172
void RemoveAllItems() noexcept;
172173
void Delete() const noexcept;
@@ -175,6 +176,7 @@ struct TESObjectREFR : TESForm
175176
void MoveTo(TESObjectCELL* apCell, const NiPoint3& acPosition) const noexcept;
176177
void PayGold(int32_t aAmount) noexcept;
177178
void PayGoldToContainer(TESObjectREFR* pContainer, int32_t aAmount) noexcept;
179+
bool SendAnimationEvent(BSFixedString* apEventName) noexcept;
178180

179181
bool Activate(TESObjectREFR* apActivator, uint8_t aUnk1, TESBoundObject* apObjectToGet, int32_t aCount, char aDefaultProcessing) noexcept;
180182

Code/client/Services/CharacterService.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ struct NotifyMount;
3131
struct InitPackageEvent;
3232
struct NotifyNewPackage;
3333
struct NotifyRespawn;
34-
struct LeaveBeastFormEvent;
34+
struct BeastFormChangeEvent;
3535
struct AddExperienceEvent;
3636
struct NotifySyncExperience;
3737
struct DialogueEvent;
@@ -78,7 +78,7 @@ struct CharacterService
7878
void OnInitPackageEvent(const InitPackageEvent& acEvent) const noexcept;
7979
void OnNotifyNewPackage(const NotifyNewPackage& acMessage) const noexcept;
8080
void OnNotifyRespawn(const NotifyRespawn& acMessage) const noexcept;
81-
void OnLeaveBeastForm(const LeaveBeastFormEvent& acEvent) const noexcept;
81+
void OnBeastFormChange(const BeastFormChangeEvent& acEvent) const noexcept;
8282
void OnAddExperienceEvent(const AddExperienceEvent& acEvent) noexcept;
8383
void OnNotifySyncExperience(const NotifySyncExperience& acMessage) noexcept;
8484
void OnDialogueEvent(const DialogueEvent& acEvent) noexcept;
@@ -114,6 +114,7 @@ struct CharacterService
114114

115115
float m_cachedExperience = 0.f;
116116

117+
// TODO: revamp this, read the local anim var like vampire lord?
117118
struct WeaponDrawData
118119
{
119120
WeaponDrawData() = default;
@@ -147,7 +148,7 @@ struct CharacterService
147148
entt::scoped_connection m_initPackageConnection;
148149
entt::scoped_connection m_newPackageConnection;
149150
entt::scoped_connection m_notifyRespawnConnection;
150-
entt::scoped_connection m_leaveBeastFormConnection;
151+
entt::scoped_connection m_beastFormChangeConnection;
151152
entt::scoped_connection m_addExperienceEventConnection;
152153
entt::scoped_connection m_syncExperienceConnection;
153154
entt::scoped_connection m_dialogueEventConnection;

Code/client/Services/Debug/DebugService.cpp

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@ void DebugService::OnMoveActor(const MoveActorEvent& acEvent) noexcept
147147
moveData.position = acEvent.Position;
148148
}
149149

150+
extern thread_local bool g_forceAnimation;
151+
150152
void DebugService::OnUpdate(const UpdateEvent& acUpdateEvent) noexcept
151153
{
152154
if (!BSGraphics::GetMainWindow()->IsForeground())
@@ -197,11 +199,7 @@ void DebugService::OnUpdate(const UpdateEvent& acUpdateEvent) noexcept
197199
{
198200
s_f7Pressed = true;
199201

200-
static char s_address[256] = "de.playtogether.gg:10100";
201-
if (!m_transport.IsOnline())
202-
m_transport.Connect(s_address);
203-
else
204-
m_transport.Close();
202+
//
205203
}
206204
}
207205
else
@@ -213,7 +211,7 @@ void DebugService::OnUpdate(const UpdateEvent& acUpdateEvent) noexcept
213211
{
214212
s_f8Pressed = true;
215213

216-
PlaceActorInWorld();
214+
//PlaceActorInWorld();
217215
}
218216
}
219217
else

0 commit comments

Comments
 (0)