-
Notifications
You must be signed in to change notification settings - Fork 0
/
MXPF - LunarArmorPatcher.pas
303 lines (251 loc) · 10.9 KB
/
MXPF - LunarArmorPatcher.pas
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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
unit UserScript;
uses 'lib\mxpf';
function Initialize: Integer;
var
i, total: integer;
e, slMasters, resistances: IInterface;
armor, energy, weight, value, newWeight: float;
torso, larm, rarm, lleg, rleg, damType: String;
const
masterPlugin = fileByName('LunarFalloutOverhaul.esp');
begin
// set MXPF options and initialize it
DefaultOptionsMXPF;
InitializeMXPF;
SetExclusions('Fallout4.esm,DLCCoast.esm,DLCRobot.esm,DLCNukaWorld.esm,DLCWorkshop01.esm,DLCWorkshop02.esm,DLCWorkshop03.esm,LunarFalloutOverhaul.esp,Unofficial Fallout 4 Patch.esp');
// select/create a new patch file that will be identified by its author field
PatchFileByAuthor('LuanrArmorPatcher');
slMasters := TStringList.Create;
slMasters.Add('LunarFalloutOverhaul.esp');
AddMastersToFile(mxPatchFile, slMasters, False);
LoadRecords('ARMO');
for i := MaxRecordIndex downto 0 do begin
e := GetRecord(i);
if (getElementEditValues(e, 'Record Header\record flags\Non-Playable') = '1') then removeRecord(i)
else if (hasKeyword(e, 'ArmorTypeHelmet') or hasKeyword(e, 'ArmorTypeHat')) AND NOT HasAp(e, 'Ap_Legendary') then begin
end
//else if not (hasKeyword(e, 'ma_Railroad_ClothingArmor') OR HasAp(e, 'ap_Railroad_ClothingArmor')) then removeRecord(i);
;
end;
// then copy records to the patch file
CopyRecordsToPatch;
addMessage( IntToStr(MaxPatchRecordIndex) + ' Records copied to patch');
// and set values on them
for i := 0 to MaxPatchRecordIndex do begin
process(GetPatchRecord(i));
end;
// call PrintMXPFReport for a report on successes and failures
PrintMXPFReport;
// always call FinalizeMXPF when done
FinalizeMXPF;
end;
//============================================================================
function Process(e: IInterface): integer;
var
i: integer;
appr: IInterface;
begin
addMessage('----- Patching ' + EditorID(e) + ' ' + IntToHex(GetLoadOrderFormID(e), 8) + ' ---------------------------------------');
if false then begin
if hasKeyword(e, 'ArmorTypeHelmet') or hasKeyword(e, 'ArmorTypeHat') then begin
if hasKeyword(e, 'ma_Railroad_ClothingArmor') or HasAp(e, 'ap_Railroad_ClothingArmor') then begin
addMessage('Removing ma_Railroad_ClothingArmor from hat');
removeRailroad(e);
end;
if NOT HasAp(e, 'Ap_Legendary') then begin
if not Assigned(ElementBySignature(e, 'APPR')) then begin
Add(e, 'APPR', true);
//appr := ElementAssign(ElementByPath(e, 'APPR'), HighInteger, nil, False);
SetEditValue(ElementAssign(ElementByPath(e, 'APPR'), HighInteger, nil, False), '001E32C8');
end
else SetEditValue(ElementAssign(ElementByPath(e, 'APPR'), HighInteger, nil, False), '001E32C8');
end;
exit;
end;
if hasKeyword(e, 'ma_Railroad_ClothingArmor') and (NOT HasAp(e, 'ap_Railroad_ClothingArmor')) then begin
addMessage('Removing left behind ma_Railroad_ClothingArmor');
removeRailroad(e);
exit;
end;
end;
if not hasBipedSlots(e) then begin
addMessage('Removing railroad keywords from armor without all required body flags');
removeRailroad(e);
exit;
end;
if shouldRecalcWeight(e) then setElementEditValues(e, 'DATA\weight', Round(getRecalcWeight(e)));
if (StrToFloat(GetElementEditValues(e, 'DATA\weight')) > 20) and (NOT HasKeyword(e, 'ObjectTypeArmor')) then begin
SetEditValue(ElementAssign(ElementByPath(e, 'KWDA'), HighInteger, nil, False), '000F4AE9');
AddMessage('Added Keyword ObjectTypeArmor');
end;
if (not hasKeyword(e, 'ObjectTypeArmor') OR not hasAp(e, 'ap_armor_lining')) then begin
addMessage('Removing Armor Lining from Weaveable Clothing');
removeArmorLining(e);
exit;
end;
if hasKeyword(e, 'ma_Railroad_ClothingArmor') and (NOT HasAp(e, 'Ap_Legendary')) then begin
SetEditValue(ElementAssign(ElementByPath(e, 'APPR'), HighInteger, nil, False), '001E32C8');
AddMessage('Added Legendary AP');
end;
end;
//============================================================================
function hasBipedSlots(e: IInterface): boolean;
begin
result := (
(GetElementEditValues(e, 'BOD2\First Person Flags\33 - Body') = '1')
and (GetElementEditValues(e, 'BOD2\First Person Flags\41 - [A] Torso') = '1')
and (GetElementEditValues(e, 'BOD2\First Person Flags\42 - [A] L Arm') = '1')
and (GetElementEditValues(e, 'BOD2\First Person Flags\43 - [A] R Arm') = '1')
and (GetElementEditValues(e, 'BOD2\First Person Flags\44 - [A] L Leg') = '1')
and (GetElementEditValues(e, 'BOD2\First Person Flags\45 - [A] R Leg') = '1')
);
end;
//============================================================================
function getRecalcWeight(e: IInterface): float;
var
armor, energy, weight, value, newWeight: float;
resistances, damType: IInterface;
i: Integer;
begin
armor := StrToInt(GetElementEditValues(e, 'FNAM\Armor Rating'));
value := StrToInt(GetElementEditValues(e, 'DATA\value'));
weight := StrToFloat(GetElementEditValues(e, 'DATA\weight'));
resistances := ElementByPath(e, 'DAMA');
for i := 0 to ElementCount(resistances)-1 do Begin
damType := GetElementEditValues(ElementByIndex(resistances, i), 'Damage Type');
if damType = 'dtEnergy [DMGT:00060A81]' then energy := GetElementEditValues(ElementByIndex(resistances, i), 'Value');
end;
result := 2 + Power(Armor/4, 1.3) + Power(Energy/4, 1.1);
end;
//============================================================================
function shouldRecalcWeight(e: IInterface): boolean;
begin
result := true;
//result := Abs(StrToFloat(GetElementEditValues(e, 'DATA\weight'))-getRecalcWeight(e)) > (2 + GetElementEditValues(e, 'DATA\weight')/5);
end;
//============================================================================
function HasAp(r: IInterface; keyword: string): boolean;
var
i: integer;
apprs: IwbElement;
ap: String;
begin
Result := false;
apprs := ElementByPath(r, 'APPR');
if apprs <> nil then for i := 0 to ElementCount(apprs)-1 do begin
ap :=EditorID(LinksTo(ElementByIndex(apprs, i)));
if ContainsText(ap, keyword) then begin
Result := true;
exit;
end;
end;
end;
//============================================================================
// remove railroad keywords
function removeRailroad(e: IInterface): boolean;
var
kwda, appr: IInterface;
n: integer;
begin
kwda := ElementByPath(e, 'KWDA');
for n := 0 to ElementCount(kwda) - 1 do begin
//addMessage('looking at keyword ' +GetEditValue(ElementByIndex(kwda, n)));
if Copy(GetEditValue(ElementByIndex(kwda, n)), 1, 25) = 'ma_Railroad_ClothingArmor' then
begin
//addMessage('Found the keyword, and trying to remove it');
Remove(ElementByIndex(kwda, n));
end;
end;
appr := ElementByPath(e, 'APPR');
for n := 0 to ElementCount(appr) - 1 do begin
if ContainsText(GetEditValue(ElementByIndex(appr, n)), 'Ap_Legendary') then Remove(ElementByIndex(appr, n));
if ContainsText(GetEditValue(ElementByIndex(appr, n)), 'ap_Railroad_ClothingArmor') then Remove(ElementByIndex(appr, n));
end;
removeCombinationForRailroad(e)
end;
//============================================================================
// remove armor lining AP
function removeArmorLining(e: IInterface): boolean;
var
kwda, appr: IInterface;
n: integer;
value: String;
begin
kwda := ElementByPath(e, 'KWDA');
for n := ElementCount(kwda) - 1 downTo 0 do begin
value := GetEditValue(ElementByIndex(kwda, n));
addMessage('looking at keyword ' +value);
if Containstext(value, 'ma_armor_' ) then Remove(ElementByIndex(kwda, n));
end;
appr := ElementByPath(e, 'APPR');
for n := 0 to ElementCount(appr) - 1 do begin
//addMessage('looking at keyword ' +GetEditValue(ElementByIndex(kwda, n)));
if ContainsText(GetEditValue(ElementByIndex(appr, n)), 'ap_armor_Lining') then Remove(ElementByIndex(appr, n));
end;
removeOmod(e, 'mod_armor_Lining_Null "No Misc" [OMOD:0018E59C]');
end;
//============================================================================
// remove resistances
function removeResistances(e: IInterface): boolean;
var
resistances: IInterface;
n, i, inum: integer;
damType: string;
begin
setElementEditValues(e, 'FNAM\Armor Rating', 0);
resistances := ElementByPath(e, 'DAMA');
inum := ElementCount(resistances);
for i := 0 to inum do Begin
damType := GetElementEditValues(ElementByIndex(resistances, i), 'Damage Type');
if damType = 'dtEnergy [DMGT:00060A81]' then Remove(ElementByIndex(resistances, i));
end;
end;
//============================================================================
// set use body slots
function SetUseBodySlots(e: IInterface): boolean;
var
resistances: IInterface;
begin
SetElementEditValues(e, 'BOD2\First Person Flags\41 - [A] Torso', 1);
SetElementEditValues(e, 'BOD2\First Person Flags\42 - [A] L Arm', 1);
SetElementEditValues(e, 'BOD2\First Person Flags\43 - [A] R Arm', 1);
SetElementEditValues(e, 'BOD2\First Person Flags\44 - [A] L Leg', 1);
SetElementEditValues(e, 'BOD2\First Person Flags\45 - [A] R Leg', 1);
end;
//============================================================================
// set use body slots
function removeOmod(e: IInterface; omod: string): boolean;
var
templateList, template, obts, includesList, includes: IInterface;
inum, i, jnum, j: integer;
begin
templateList := ElementByPath(e, 'Object Template\Combinations');
inum := ElementCount(templateList);
for i := 0 to inum do Begin
template := ElementByIndex(templateList, i);
obts := ElementByPath(template, 'OBTS');
includesList := ElementByPath(obts, 'Includes');
jnum := ElementCount(includesList);
for j := 0 to jnum do Begin
includes := ElementByIndex(includesList, j);
if GetElementEditValues(includes, 'Mod') = omod then Remove(ElementByIndex(includesList, j));
end;
end;
end;
//============================================================================
// Remove railroad template combination
function removeCombinationForRailroad(e: IInterface): boolean;
var
templateList, template, obts, kwds: IInterface;
inum, i, jnum, j: integer;
begin
templateList := ElementByPath(e, 'Object Template\Combinations');
inum := ElementCount(templateList);
for i := 0 to inum do Begin
template := ElementByIndex(templateList, i);
obts := ElementByPath(template, 'OBTS');
kwds := ElementByPath(obts, 'Keywords');
if EditorID(LinksTo(ElementByIndex(kwds, 0))) = 'if_Railroad_ClothingArmor' then Remove(ElementByIndex(templateList, i));
end;
end;
end.