-
Notifications
You must be signed in to change notification settings - Fork 224
/
Copy pathForms.cpp
155 lines (120 loc) · 3.7 KB
/
Forms.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <TiltedOnlinePCH.h>
#include <PlayerCharacter.h>
#include <Forms/BGSHeadPart.h>
#include <Forms/TESNPC.h>
#include <Games/IFormFactory.h>
#include <SaveLoad.h>
#include <Games/Overrides.h>
TESForm* TESForm::GetById(const uint32_t aId)
{
using TGetFormById = TESForm*(uint32_t);
POINTER_FALLOUT4(TGetFormById, getFormById, 796115);
POINTER_SKYRIMSE(TGetFormById, getFormById, 14617);
return getFormById.Get()(aId);
}
void TESNPC::Serialize(String* apSaveBuffer) const noexcept
{
ScopedSaveLoadOverride saveLoadOverride;
char buffer[1 << 15];
BGSSaveFormBuffer saveBuffer;
saveBuffer.buffer = buffer;
saveBuffer.capacity = 1 << 15;
saveBuffer.changeFlags = GetChangeFlags();
Save(&saveBuffer);
apSaveBuffer->assign(saveBuffer.buffer, saveBuffer.position);
saveBuffer.buffer = nullptr;
}
void TESNPC::Deserialize(const String& acBuffer, uint32_t aChangeFlags) noexcept
{
ScopedSaveLoadOverride saveLoadOverride;
BGSLoadFormBuffer loadBuffer(aChangeFlags);
loadBuffer.SetSize(acBuffer.size() & 0xFFFFFFFF);
loadBuffer.buffer = acBuffer.data();
loadBuffer.formId = formID;
loadBuffer.form = this;
Load(&loadBuffer);
loadBuffer.buffer = nullptr;
}
void TESNPC::Initialize() noexcept
{
auto pPlayerBaseForm = Cast<TESNPC>(PlayerCharacter::Get()->baseForm);
// These values are all defaulted, if the other actor did not modify them they won't be loaded, therefore we need to force them before load
attackDataForm.attackDataMap = pPlayerBaseForm->attackDataForm.attackDataMap;
npcClass = pPlayerBaseForm->npcClass;
combatStyle = pPlayerBaseForm->combatStyle;
raceForm.race = pPlayerBaseForm->raceForm.race;
outfits[0] = pPlayerBaseForm->outfits[0];
#if TP_SKYRIM
spellList.Initialize();
#endif
// End defaults
flags |= 0x200000;
}
void TESForm::Save_Reversed(const uint32_t aChangeFlags, Buffer::Writer& aWriter)
{
if (aChangeFlags & 1)
{
aWriter.WriteBytes(reinterpret_cast<uint8_t*>(&flags), 4);
aWriter.WriteBytes(reinterpret_cast<uint8_t*>(&unk10), 2);
}
}
void TESForm::SetSkipSaveFlag(bool aSet) noexcept
{
if (aSet)
{
unk10 = 0xFFFF;
}
/*const uint32_t flag = 1 << 14;
if (aSet)
flags |= flag;
else
flags &= ~flag;*/
}
uint32_t TESForm::GetChangeFlags() const noexcept
{
struct Unk
{
#if TP_SKYRIM64
uint8_t unk0[0x330];
#elif TP_FALLOUT4
uint8_t unk0[0x350];
#endif
void* unk330;
};
TP_THIS_FUNCTION(InternalGetChangeFlags, bool, void, uint32_t formId, ChangeFlags& changeFlags);
POINTER_FALLOUT4(InternalGetChangeFlags, internalGetChangeFlags, 1464380);
POINTER_SKYRIMSE(InternalGetChangeFlags, internalGetChangeFlags, 35503);
POINTER_FALLOUT4(Unk*, s_singleton, 177948);
POINTER_SKYRIMSE(Unk*, s_singleton, 403330);
const auto pUnk = *(s_singleton.Get());
ChangeFlags changeFlags;
const auto cResult = TiltedPhoques::ThisCall(internalGetChangeFlags, pUnk->unk330, formID, changeFlags);
if (!cResult)
return 0;
return changeFlags.flags;
}
TESNPC* TESNPC::Create(const String& acBuffer, const uint32_t aChangeFlags) noexcept
{
auto pNpc = IFormFactory::Create<TESNPC>();
pNpc->Initialize();
pNpc->Deserialize(acBuffer, aChangeFlags);
// This forces facegen for some reason
#if TP_SKYRIM
pNpc->overlayRace = nullptr;
#endif
return pNpc;
}
BGSHeadPart* TESNPC::GetHeadPart(uint32_t aType)
{
#ifdef TP_SKYRIM
if (headparts)
{
for (auto i = 0; i < headpartsCount; ++i)
{
if (headparts[i] && headparts[i]->type == aType)
return headparts[i];
}
}
#endif
return nullptr;
}