Skip to content

Commit 6bc8861

Browse files
Merge pull request #674 from tiltedphoques/dev
V1.6.5
2 parents bd9a756 + df47981 commit 6bc8861

36 files changed

+884
-33
lines changed

Code/client/CrashHandler.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@ std::string SerializeTimePoint(const time_point& time, const std::string& format
2222

2323
LONG WINAPI VectoredExceptionHandler(PEXCEPTION_POINTERS pExceptionInfo)
2424
{
25-
if (pExceptionInfo->ExceptionRecord->ExceptionCode == 0xC0000005)
25+
static int alreadycrashed = 0;
26+
27+
if (pExceptionInfo->ExceptionRecord->ExceptionCode == 0xC0000005 && alreadycrashed++ == 0)
2628
{
2729
spdlog::error("Crash occurred!");
2830
MINIDUMP_EXCEPTION_INFORMATION M;

Code/client/Games/Primitives.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,17 @@ template <class T> struct GameList
101101
Entry entry;
102102

103103
inline bool Empty() const noexcept { return entry.data == nullptr; }
104+
inline size_t Size() const noexcept
105+
{
106+
if (entry.data == nullptr)
107+
return 0ULL;
108+
109+
size_t size = 0;
110+
for (const Entry* current = &entry; current; current = current->next)
111+
size++;
112+
113+
return size;
114+
}
104115

105116
// Range for loop compatibility
106117
struct Iterator

Code/client/Games/Skyrim/Actor.cpp

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <Components/TESActorBaseData.h>
1010
#include <ExtraData/ExtraFactionChanges.h>
1111
#include <Games/Memory.h>
12+
#include <Forms/TESLevItem.h>
1213

1314
#include <Events/HealthChangeEvent.h>
1415
#include <Events/InventoryChangeEvent.h>
@@ -44,6 +45,8 @@
4445
#include <Games/Skyrim/BSAnimationGraphManager.h>
4546
#include <Havok/hkbStateMachine.h>
4647
#include <Havok/hkbBehaviorGraph.h>
48+
#include <Forms/BGSOutfit.h>
49+
#include <Forms/TESObjectARMO.h>
4750

4851
#ifdef SAVE_STUFF
4952

@@ -191,6 +194,48 @@ TESForm* Actor::GetEquippedAmmo() const noexcept
191194
return nullptr;
192195
}
193196

197+
bool Actor::IsWearingBodyPiece() const noexcept
198+
{
199+
return GetContainerChanges()->GetArmor(32) != nullptr;
200+
}
201+
202+
bool Actor::ShouldWearBodyPiece() const noexcept
203+
{
204+
TESNPC* pBase = Cast<TESNPC>(baseForm);
205+
if (!pBase)
206+
return false;
207+
208+
BGSOutfit* pDefaultOutfit = pBase->outfits[0];
209+
if (!pDefaultOutfit)
210+
return false;
211+
212+
for (auto* pItem : pDefaultOutfit->outfitItems)
213+
{
214+
TESObjectARMO* pArmor = nullptr;
215+
216+
if (pItem->formType == FormType::Armor)
217+
pArmor = Cast<TESObjectARMO>(pItem);
218+
else if (pItem->formType == FormType::LeveledItem)
219+
{
220+
TESLevItem* pLevItem = Cast<TESLevItem>(pItem);
221+
if (!pLevItem || !pLevItem->pLeveledListA || !pLevItem->pLeveledListA->pForm)
222+
continue;
223+
224+
pArmor = Cast<TESObjectARMO>(pLevItem->pLeveledListA->pForm);
225+
}
226+
else
227+
continue;
228+
229+
if (!pArmor)
230+
continue;
231+
232+
if (pArmor->IsBodyPiece())
233+
return true;
234+
}
235+
236+
return false;
237+
}
238+
194239
// Get owner of a summon or raised corpse
195240
Actor* Actor::GetCommandingActor() const noexcept
196241
{
@@ -207,7 +252,7 @@ Actor* Actor::GetCommandingActor() const noexcept
207252
// Get owner of a summon or raised corpse
208253
void Actor::SetCommandingActor(BSPointerHandle<TESObjectREFR> aCommandingActor) noexcept
209254
{
210-
if (currentProcess && currentProcess->middleProcess && currentProcess->middleProcess)
255+
if (currentProcess && currentProcess->middleProcess)
211256
{
212257
currentProcess->middleProcess->commandingActor = aCommandingActor;
213258
flags2 |= ActorFlags::IS_COMMANDED_ACTOR;

Code/client/Games/Skyrim/Actor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,8 @@ struct Actor : TESObjectREFR
205205
[[nodiscard]] Actor* GetCombatTarget() const noexcept;
206206
[[nodiscard]] bool HasPerk(uint32_t aPerkFormId) const noexcept;
207207
[[nodiscard]] uint8_t GetPerkRank(uint32_t aPerkFormId) const noexcept;
208+
[[nodiscard]] bool IsWearingBodyPiece() const noexcept;
209+
[[nodiscard]] bool ShouldWearBodyPiece() const noexcept;
208210

209211
// Setters
210212
void SetSpeed(float aSpeed) noexcept;

Code/client/Games/Skyrim/EquipManager.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ void* TP_MAKE_THISCALL(EquipHook, EquipManager, Actor* apActor, TESForm* apItem,
157157
// Consumables are "equipped" as well. We don't want this to sync, for several reasons.
158158
// The right hand item on the server would be overridden by the consumable.
159159
// Furthermore, the equip action on the other clients would doubly subtract the consumables.
160-
if (pExtension->IsLocal() && !apItem->IsConsumable())
160+
if (pExtension->IsLocal() && !apItem->IsConsumable() && !apData->bQueueEquip)
161161
{
162162
EquipmentChangeEvent evt{};
163163
evt.ActorId = apActor->formID;
@@ -189,7 +189,7 @@ void* TP_MAKE_THISCALL(UnEquipHook, EquipManager, Actor* apActor, TESForm* apIte
189189
return nullptr;
190190
}
191191

192-
if (pExtension->IsLocal() && !ScopedUnequipOverride::IsOverriden())
192+
if (pExtension->IsLocal() && !ScopedUnequipOverride::IsOverriden() && !apData->bQueueEquip)
193193
{
194194
EquipmentChangeEvent evt{};
195195
evt.ActorId = apActor->formID;
@@ -216,7 +216,7 @@ void* TP_MAKE_THISCALL(EquipSpellHook, EquipManager, Actor* apActor, TESForm* ap
216216
if (pExtension->IsRemote() && !ScopedEquipOverride::IsOverriden())
217217
return nullptr;
218218

219-
if (pExtension->IsLocal())
219+
if (pExtension->IsLocal() && !apData->bQueueEquip)
220220
{
221221
EquipmentChangeEvent evt{};
222222
evt.ActorId = apActor->formID;
@@ -241,7 +241,7 @@ void* TP_MAKE_THISCALL(UnEquipSpellHook, EquipManager, Actor* apActor, TESForm*
241241
if (pExtension->IsRemote() && !ScopedEquipOverride::IsOverriden())
242242
return nullptr;
243243

244-
if (pExtension->IsLocal() && !ScopedUnequipOverride::IsOverriden())
244+
if (pExtension->IsLocal() && !ScopedUnequipOverride::IsOverriden() && !apData->bQueueEquip)
245245
{
246246
EquipmentChangeEvent evt{};
247247
evt.ActorId = apActor->formID;
@@ -265,6 +265,7 @@ void* TP_MAKE_THISCALL(EquipShoutHook, EquipManager, Actor* apActor, TESForm* ap
265265
if (pExtension->IsRemote() && !ScopedEquipOverride::IsOverriden())
266266
return nullptr;
267267

268+
// TODO: queue check?
268269
if (pExtension->IsLocal())
269270
{
270271
EquipmentChangeEvent evt{};
@@ -289,6 +290,7 @@ void* TP_MAKE_THISCALL(UnEquipShoutHook, EquipManager, Actor* apActor, TESForm*
289290
if (pExtension->IsRemote() && !ScopedEquipOverride::IsOverriden())
290291
return nullptr;
291292

293+
// TODO: queue check?
292294
if (pExtension->IsLocal() && !ScopedUnequipOverride::IsOverriden())
293295
{
294296
EquipmentChangeEvent evt{};

Code/client/Games/Skyrim/ExtraData/ExtraContainerChanges.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,12 @@ bool ExtraContainerChanges::Entry::IsQuestObject() noexcept
2828

2929
return TiltedPhoques::ThisCall(s_isQuestObject, this);
3030
}
31+
32+
TESObjectARMO* ExtraContainerChanges::Data::GetArmor(uint32_t aSlotId) noexcept
33+
{
34+
TP_THIS_FUNCTION(TGetArmor, TESObjectARMO*, ExtraContainerChanges::Data, uint32_t);
35+
36+
POINTER_SKYRIMSE(TGetArmor, s_getArmor, 16113);
37+
38+
return TiltedPhoques::ThisCall(s_getArmor, this, aSlotId);
39+
}

Code/client/Games/Skyrim/ExtraData/ExtraContainerChanges.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ struct BGSLoadFormBuffer;
66
struct BGSSaveFormBuffer;
77
struct TESObjectREFR;
88
struct TESForm;
9+
struct TESObjectARMO;
910

1011
struct ExtraContainerChanges : BSExtraData
1112
{
@@ -25,6 +26,7 @@ struct ExtraContainerChanges : BSExtraData
2526
{
2627
void Save(BGSSaveFormBuffer* apBuffer);
2728
void Load(BGSLoadFormBuffer* apBuffer);
29+
TESObjectARMO* GetArmor(uint32_t aSlotId) noexcept;
2830

2931
GameList<Entry>* entries;
3032
TESObjectREFR* parent;

Code/client/Games/Skyrim/Forms/BGSOutfit.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44

55
struct BGSOutfit : TESForm
66
{
7+
GameArray<TESForm*> outfitItems;
78
};

Code/client/Games/Skyrim/Forms/TESForm.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ enum class FormType : uint8_t
1414
Npc = 43,
1515
LeveledCharacter = 44,
1616
Alchemy = 46,
17+
LeveledItem = 53,
1718
Character = 62,
1819
QuestItem = 77,
1920
Count = 0x87
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#pragma once
2+
3+
#include "TESLeveledList.h"
4+
5+
struct TESLevItem : TESBoundObject, TESLeveledList
6+
{
7+
};
8+
9+
static_assert(sizeof(TESLevItem) == 0x58);

0 commit comments

Comments
 (0)