diff --git a/include/RE/A/AIProcess.h b/include/RE/A/AIProcess.h index 07f3b8663..60304d4ed 100644 --- a/include/RE/A/AIProcess.h +++ b/include/RE/A/AIProcess.h @@ -179,6 +179,7 @@ namespace RE bool InLowProcess() const; bool IsArrested() const; bool IsGhost() const; + bool IsInCommandState() const; void KnockExplosion(Actor* a_actor, const NiPoint3& a_location, float a_magnitude); bool PlayIdle(Actor* a_actor, TESIdleForm* a_idle, TESObjectREFR* a_target); void SetActorsDetectionEvent(Actor* a_actor, const NiPoint3& a_location, std::int32_t a_soundLevel, TESObjectREFR* a_ref); diff --git a/include/RE/A/Actor.h b/include/RE/A/Actor.h index 5e79f3792..09b47219b 100644 --- a/include/RE/A/Actor.h +++ b/include/RE/A/Actor.h @@ -536,6 +536,7 @@ namespace RE TESForm* GetEquippedObjectInSlot(const BGSEquipSlot* slot) const; float GetEquippedWeight(); std::int32_t GetFactionRank(TESFaction* a_faction, bool a_isPlayer); + FIGHT_REACTION GetFactionReaction(Actor* a_other) const; std::int32_t GetGoldAmount(bool a_noInit = false); ActorHandle GetHandle(); [[nodiscard]] NiAVObject* GetHeadPartObject(BGSHeadPart::HeadPartType a_type); @@ -548,13 +549,16 @@ namespace RE bool GetMountedBy(NiPointer& a_outRider); double GetMoveDirectionRelativeToFacing(); ObjectRefHandle GetOccupiedFurniture() const; + bool GetPlayerControls() const; TESRace* GetRace() const; float GetRegenDelay(ActorValue a_actorValue) const; bool GetRider(NiPointer& a_outRider); [[nodiscard]] TESObjectARMO* GetSkin() const; [[nodiscard]] TESObjectARMO* GetSkin(BGSBipedObjectForm::BipedObjectSlot a_slot, bool a_noInit = false); [[nodiscard]] SOUL_LEVEL GetSoulSize() const; + TESNPC* GetTemplateBase(); float GetTotalCarryWeight(); + float GetTrackedDamage() const; TESFaction* GetVendorFaction(); const TESFaction* GetVendorFaction() const; float GetVoiceRecoveryTime(); @@ -573,12 +577,15 @@ namespace RE bool IsAIEnabled() const; bool IsAlarmed() const; bool IsAMount() const; + bool IsAngryWithPlayer() const { return boolFlags.all(BOOL_FLAGS::kAngryWithPlayer); }; bool IsAnimationDriven() const; bool IsBeingRidden() const; bool IsBlocking() const; bool IsCasting(MagicItem* a_spell) const; + bool IsCombatTarget(Actor* a_other) const; bool IsCommandedActor() const; bool IsCurrentShout(SpellItem* a_power); + bool IsDoingFavor() const; bool IsDualCasting() const; bool IsEssential() const; bool IsFactionInCrimeGroup(const TESFaction* a_faction) const; @@ -614,6 +621,7 @@ namespace RE void SetHeading(float a_angle); // SetRotationZ void SetLifeState(ACTOR_LIFE_STATE a_lifeState); void SetLooking(float a_angle); // SetRotationX + void SetPlayerControls(bool a_enable); bool SetSleepOutfit(BGSOutfit* a_outfit, bool a_update3D); void StealAlarm(TESObjectREFR* a_ref, TESForm* a_object, std::int32_t a_num, std::int32_t a_total, TESForm* a_owner, bool a_allowWarning); void StopAlarmOnActor(); diff --git a/include/RE/A/ActorState.h b/include/RE/A/ActorState.h index 50e731533..9ce53e665 100644 --- a/include/RE/A/ActorState.h +++ b/include/RE/A/ActorState.h @@ -182,6 +182,7 @@ namespace RE } } + [[nodiscard]] bool IsReanimated() const noexcept { return GetLifeState() == ACTOR_LIFE_STATE::kReanimate; } [[nodiscard]] bool IsSneaking() const noexcept { return static_cast(actorState1.sneaking); } [[nodiscard]] bool IsSprinting() const noexcept { return static_cast(actorState1.sprinting); } [[nodiscard]] bool IsSwimming() const noexcept { return static_cast(actorState1.swimming); } diff --git a/include/RE/B/bhkCharacterController.h b/include/RE/B/bhkCharacterController.h index 3c05662ca..be17057a7 100644 --- a/include/RE/B/bhkCharacterController.h +++ b/include/RE/B/bhkCharacterController.h @@ -169,7 +169,8 @@ namespace RE hkRefPtr bumpedBody; // 2C0 hkRefPtr bumpedCharCollisionObject; // 2C8 BSTHashMap, DamageImpactData*> damageImpacts; // 2D0 - std::uint64_t unk300; // 300 + std::uint32_t unk300; // 300 + MATERIAL_ID surfaceMaterial; // 304 std::uint64_t unk308; // 308 std::uint64_t unk310; // 310 std::uint64_t unk318; // 318 diff --git a/include/RE/M/MovementControllerNPC.h b/include/RE/M/MovementControllerNPC.h index 079fdaece..fe60807b6 100644 --- a/include/RE/M/MovementControllerNPC.h +++ b/include/RE/M/MovementControllerNPC.h @@ -26,38 +26,38 @@ namespace RE ~MovementControllerNPC() override; // 00 // add - virtual void Unk_0A(void); // 0A - virtual void Unk_0B(void); // 0B - virtual void Unk_0C(void); // 0C - virtual void Unk_0D(void); // 0D - virtual void Unk_0E(void); // 0E - { return unk1C5 == 0; } - virtual void Unk_0F(void); // 0F - { return unk1C5; } - virtual void Unk_10(void); // 10 - virtual void Unk_11(void); // 11 - virtual void Unk_12(void); // 12 - virtual void Unk_13(void); // 13 - virtual void Unk_14(void); // 14 + virtual void Unk_0A(void); // 0A + virtual void Unk_0B(void); // 0B + virtual void DisablePlayerControls(); // 0C + virtual void EnablePlayerControls(); // 0D + virtual bool IsPlayerControlsDisabled(); // 0E - { return unk1C5 == 0; } + virtual bool IsPlayerControlsEnabled(); // 0F - { return unk1C5; } + virtual void Unk_10(void); // 10 + virtual void Unk_11(void); // 11 + virtual void Unk_12(void); // 12 + virtual void Unk_13(void); // 13 + virtual void Unk_14(void); // 14 // members - std::uint64_t unk150; // 150 - std::uint64_t unk158; // 158 - std::uint64_t unk160; // 160 - std::uint64_t unk168; // 168 - std::uint64_t unk170; // 170 - std::uint64_t unk178; // 178 - std::uint64_t unk180; // 180 - std::uint64_t unk188; // 188 - std::uint64_t unk190; // 190 - std::uint64_t unk198; // 198 - std::uint64_t unk1A0; // 1A0 - std::uint64_t unk1A8; // 1A8 - std::uint64_t unk1B0; // 1B0 - std::uint64_t unk1B8; // 1B8 - std::uint32_t unk1C0; // 1C0 - std::uint8_t unk1C4; // 1C4 - std::uint8_t unk1C5; // 1C5 - std::uint16_t unk1C6; // 1C6 - std::uint64_t unk1C8; // 1C8 + std::uint64_t unk150; // 150 + std::uint64_t unk158; // 158 + std::uint64_t unk160; // 160 + std::uint64_t unk168; // 168 + std::uint64_t unk170; // 170 + std::uint64_t unk178; // 178 + std::uint64_t unk180; // 180 + std::uint64_t unk188; // 188 + std::uint64_t unk190; // 190 + std::uint64_t unk198; // 198 + std::uint64_t unk1A0; // 1A0 + std::uint64_t unk1A8; // 1A8 + std::uint64_t unk1B0; // 1B0 + std::uint64_t unk1B8; // 1B8 + std::uint32_t unk1C0; // 1C0 + std::uint8_t unk1C4; // 1C4 + bool playerControls; // 1C5 + std::uint16_t unk1C6; // 1C6 + std::uint64_t unk1C8; // 1C8 }; static_assert(sizeof(MovementControllerNPC) == 0x1D0); } diff --git a/include/RE/T/TESObjectREFR.h b/include/RE/T/TESObjectREFR.h index cad1d4ad8..c37a3dad9 100644 --- a/include/RE/T/TESObjectREFR.h +++ b/include/RE/T/TESObjectREFR.h @@ -374,6 +374,7 @@ namespace RE TESContainer* GetContainer() const; BGSLocation* GetCurrentLocation() const; const char* GetDisplayFullName(); + float GetDistance(TESObjectREFR* a_other, bool a_disabledRefs = false, bool a_ignoreWorldspace = false) const; InventoryDropMap GetDroppedInventory(); InventoryDropMap GetDroppedInventory(std::function a_filter); BGSEncounterZone* GetEncounterZone() const; @@ -405,6 +406,7 @@ namespace RE [[nodiscard]] float GetScale() const; NiControllerSequence* GetSequence(stl::zstring a_name) const; std::uint32_t GetStealValue(const InventoryEntryData* a_entryData, std::uint32_t a_numItems, bool a_useMult) const; + float GetSubmergeLevel(float a_zPos, TESObjectCELL* a_cell) const; void GetTransform(NiTransform& a_transform) const; float GetWaterHeight() const; float GetWeight() const; @@ -436,7 +438,6 @@ namespace RE bool IsMarkedForDeletion() const; bool IsOffLimits(); bool IsPersistent() const; - float IsPointDeepUnderWater(float a_zPos, TESObjectCELL* a_cell) const; bool IsPointSubmergedMoreThan(const NiPoint3& a_pos, TESObjectCELL* a_cell, float a_waterLevel) const; void MoveTo(TESObjectREFR* a_target); bool MoveToNode(TESObjectREFR* a_target, const BSFixedString& a_nodeName); diff --git a/src/RE/A/AIProcess.cpp b/src/RE/A/AIProcess.cpp index 4e36ef473..6c8ae17c6 100644 --- a/src/RE/A/AIProcess.cpp +++ b/src/RE/A/AIProcess.cpp @@ -194,6 +194,11 @@ namespace RE return cachedValues && cachedValues->flags.all(CachedValues::Flags::kActorIsGhost); } + bool AIProcess::IsInCommandState() const + { + return high && high->inCommandState; + } + void AIProcess::KnockExplosion(Actor* a_actor, const NiPoint3& a_location, float a_magnitude) { using func_t = decltype(&AIProcess::KnockExplosion); diff --git a/src/RE/A/Actor.cpp b/src/RE/A/Actor.cpp index f3eed92e4..0b430e181 100644 --- a/src/RE/A/Actor.cpp +++ b/src/RE/A/Actor.cpp @@ -12,11 +12,13 @@ #include "RE/B/bhkCharacterController.h" #include "RE/E/ExtraCanTalkToPlayer.h" #include "RE/E/ExtraFactionChanges.h" +#include "RE/E/ExtraLeveledCreature.h" #include "RE/F/FixedStrings.h" #include "RE/F/FormTraits.h" #include "RE/H/HighProcessData.h" #include "RE/I/InventoryEntryData.h" #include "RE/M/MiddleHighProcessData.h" +#include "RE/M/MovementControllerNPC.h" #include "RE/M/Misc.h" #include "RE/N/NiColor.h" #include "RE/N/NiMath.h" @@ -433,6 +435,13 @@ namespace RE return func(this, a_faction, a_isPlayer); } + FIGHT_REACTION Actor::GetFactionReaction(Actor* a_other) const + { + using func_t = decltype(&GetFactionReaction); + REL::Relocation func{ RELOCATION_ID(36658, 37666) }; + return func(this, a_other); + } + std::int32_t Actor::GetGoldAmount(bool a_noInit) { const auto inv = GetInventory([](TESBoundObject& a_object) -> bool { @@ -539,6 +548,14 @@ namespace RE } } + bool Actor::GetPlayerControls() const + { + if (movementController) { + return movementController->IsPlayerControlsEnabled(); + } + return false; + } + TESRace* Actor::GetRace() const { if (race) { @@ -589,6 +606,15 @@ namespace RE return func(this); } + TESNPC* Actor::GetTemplateBase() + { + auto leveledCreature = extraList.GetByType(); + if (leveledCreature) { + return static_cast(leveledCreature->templateBase); + } + return GetActorBase(); + } + float Actor::GetTotalCarryWeight() { using func_t = decltype(&Actor::GetTotalCarryWeight); @@ -596,6 +622,11 @@ namespace RE return func(this); } + float Actor::GetTrackedDamage() const + { + return currentProcess ? currentProcess->trackedDamage : 0.0f; + } + TESFaction* Actor::GetVendorFaction() { if (!vendorFaction) { @@ -766,6 +797,13 @@ namespace RE return func(this, a_spell); } + bool Actor::IsCombatTarget(Actor* a_other) const + { + using func_t = decltype(&IsCombatTarget); + REL::Relocation func{ RELOCATION_ID(37618, 38571) }; + return func(this, a_other); + } + bool Actor::IsCommandedActor() const { return boolFlags.all(BOOL_FLAGS::kIsCommandedActor); @@ -778,6 +816,14 @@ namespace RE return func(this, a_power); } + bool Actor::IsDoingFavor() const + { + if (currentProcess) { + return currentProcess->IsInCommandState(); + } + return false; + } + bool Actor::IsDualCasting() const { if (!currentProcess) { @@ -1036,6 +1082,18 @@ namespace RE return func(this, a_angle); } + void Actor::SetPlayerControls(bool a_enable) + { + if (movementController) { + EnableAI(!a_enable); + if (a_enable) { + movementController->EnablePlayerControls(); + } else { + movementController->DisablePlayerControls(); + } + } + } + bool Actor::SetSleepOutfit(BGSOutfit* a_outfit, bool a_update3D) { const auto npc = GetActorBase(); diff --git a/src/RE/T/TESObjectREFR.cpp b/src/RE/T/TESObjectREFR.cpp index 3e9f9b25c..de2f817a7 100644 --- a/src/RE/T/TESObjectREFR.cpp +++ b/src/RE/T/TESObjectREFR.cpp @@ -204,6 +204,13 @@ namespace RE return func(this); } + float TESObjectREFR::GetDistance(TESObjectREFR* a_other, bool a_disabledRefs, bool a_ignoreWorldspace) const + { + using func_t = decltype(&GetDistance); + REL::Relocation func{ RELOCATION_ID(19396, 19823) }; + return func(this, a_other, a_disabledRefs, a_ignoreWorldspace); + } + auto TESObjectREFR::GetDroppedInventory() -> InventoryDropMap { @@ -507,6 +514,21 @@ namespace RE return func(this, a_entryData, a_numItems, a_useMult); } + float TESObjectREFR::GetSubmergeLevel(float a_zPos, TESObjectCELL* a_cell) const + { + auto waterHeight = !a_cell || a_cell == parentCell ? GetWaterHeight() : a_cell->GetExteriorWaterHeight(); + + if (waterHeight == -NI_INFINITY && a_cell) { + waterHeight = a_cell->GetExteriorWaterHeight(); + } + + if (waterHeight <= a_zPos) { + return 0.0f; + } + + return std::fminf((waterHeight - a_zPos) / GetHeight(), 1.0f); + } + void TESObjectREFR::GetTransform(NiTransform& a_transform) const { using func_t = decltype(&TESObjectREFR::GetTransform); @@ -739,24 +761,9 @@ namespace RE return (GetFormFlags() & RecordFlags::kPersistent) != 0; } - float TESObjectREFR::IsPointDeepUnderWater(float a_zPos, TESObjectCELL* a_cell) const - { - auto waterHeight = !a_cell || a_cell == parentCell ? GetWaterHeight() : a_cell->GetExteriorWaterHeight(); - - if (waterHeight == -NI_INFINITY && a_cell) { - waterHeight = a_cell->GetExteriorWaterHeight(); - } - - if (waterHeight <= a_zPos) { - return 0.0f; - } - - return std::fminf((waterHeight - a_zPos) / GetHeight(), 1.0f); - } - bool TESObjectREFR::IsPointSubmergedMoreThan(const NiPoint3& a_pos, TESObjectCELL* a_cell, const float a_waterLevel) const { - return IsPointDeepUnderWater(a_pos.z, a_cell) >= a_waterLevel; + return GetSubmergeLevel(a_pos.z, a_cell) >= a_waterLevel; } void TESObjectREFR::MoveTo(TESObjectREFR* a_target)