This repository has been archived by the owner on May 30, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathff2_config_to_vsh2.sp
457 lines (371 loc) · 10.2 KB
/
ff2_config_to_vsh2.sp
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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
#include <profiler>
// note: the new VSH2/FF2 way of handling sections like 'abilities' and sounds, etc... will consists of checking
// if the config contains a specific new section 'info', if not then it will assume the plugin wasn't mean to be
// an VSH2/FF2 config, so it will internally rewrite some of those sections to match the new ones.
// for more check out: https://github.com/01Pollux/Vs-Saxton-Hale-2/blob/develop/addons/sourcemod/scripting/freaks/vsh2ff2_sample.cfg
/// show the time it took to process each config
//#define FF2_COMPILE_WITH_BECHMARK
/// forcibly change ffbat_defaults and deault_abilities to ff2_vsh2defaults
/// yes this also does recreate all of your args with new name just in case
#define FF2_DEFAULTS_TO_VSH2
/// set's some enumeration keys with "<enum>"
/// note: temporarily disabled until it gets updated for the new VSH2 slots handling,
//#define FF2_USING_CONFIGMAP_ENUMERATION
/// rewrite the old slots with new one, note: it will not rewrite them if the section has "__update_slot__" key set to "1"
/// note: temporarily disabled until it gets updated for the new VSH2 slots handling,
//#define FF2_USING_NEW_SLOTS
static const char PATH_TO_CFG[] = "configs/freak_fortress_2"
typedef OnProcessCallback = function bool(KeyValues kv, File hFile, const char[] section_name);
#if defined FF2_COMPILE_WITH_BECHMARK
#define BEGIN_PROF_SECTION() \
float elapsed;\
Profiler _benchmark = new Profiler(); \
_benchmark.Start()
#define END_PROF_SECTION(%0) \
_benchmark.Stop(); \
elapsed = _benchmark.Time; \
delete _benchmark; \
PrintToServer("(elapsed: %.12f second) %s", elapsed, %0)
#else
void DummyFunction() { } /// for empty statements warning
#define BEGIN_PROF_SECTION() DummyFunction()
#define END_PROF_SECTION(%0) DummyFunction()
#endif
public Plugin myinfo = { name = "01Pollux" };
enum struct KVAndPath
{
KeyValues kv;
char path[PLATFORM_MAX_PATH];
}
methodmap FF2ConfigList < ArrayList
{
public FF2ConfigList()
{
char path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, PLATFORM_MAX_PATH, PATH_TO_CFG);
if (!DirExists(path))
SetFailState("Failed to open Directory: \"%s\"", PATH_TO_CFG);
DirectoryListing Dir = OpenDirectory(path);
ArrayList FileList = new ArrayList(sizeof(KVAndPath));
_RecursiveOpenFile(Dir, FileList);
if (!FileList.Length)
SetFailState("No boss was found in %s", PATH_TO_CFG);
return view_as<FF2ConfigList>(FileList);
}
public void FreeAll()
{
int count = this.Length;
for (int i; i < count; i++)
{
delete view_as<KeyValues>(this.Get(i));
}
}
}
enum FF2GetKeyType
{
AsStrStri,
AsStrNCmpi,
AsStrCmpi
}
enum struct FF2FunctionInfo
{
char str[48];
Function fn;
FF2GetKeyType type;
int extra;
}
methodmap FF2AutoProcess < ArrayList
{
public FF2AutoProcess()
{
return view_as<FF2AutoProcess>(new ArrayList(sizeof(FF2FunctionInfo)));
}
public void Register(OnProcessCallback callback, const char[] str, FF2GetKeyType type, int extra = 0)
{
FF2FunctionInfo f;
strcopy(f.str, sizeof(FF2FunctionInfo::str), str);
f.fn = callback;
f.type = type;
f.extra = extra;
this.PushArray(f);
}
public Function GetFunction(const char[] incoming)
{
FF2FunctionInfo f;
int count = this.Length;
for (int i = 0; i < count; i++)
{
this.GetArray(i, f);
switch (f.type)
{
case AsStrStri:
{
if (StrContains(incoming, f.str) != -1)
return f.fn;
}
case AsStrNCmpi:
{
if (!strncmp(incoming, f.str, f.extra, false))
return f.fn;
}
case AsStrCmpi:
{
if (strcmp(incoming, f.str, false) == f.extra)
return f.fn;
}
}
}
return INVALID_FUNCTION;
}
public bool ProcessOne(KeyValues kv, File hFile, const char[] incoming)
{
bool res;
Function fn = this.GetFunction(incoming);
if (fn != INVALID_FUNCTION)
{
Call_StartFunction(null, fn);
Call_PushCell(kv);
Call_PushCell(hFile);
Call_PushString(incoming);
Call_Finish(res);
}
return res;
}
}
typedef OnProcessDefaults = function void(KeyValues kv);
methodmap FF2DefaultsToVSH2 < FF2AutoProcess
{
public FF2DefaultsToVSH2()
{
return view_as<FF2DefaultsToVSH2>(new FF2AutoProcess());
}
public void Register(OnProcessDefaults callback, const char[] str, FF2GetKeyType type, int extra = 0)
{
FF2FunctionInfo f;
strcopy(f.str, sizeof(FF2FunctionInfo::str), str);
f.fn = callback;
f.type = type;
f.extra = extra;
this.PushArray(f);
}
public bool ProcessOne(KeyValues kv)
{
char[] incoming = new char[64];
kv.GetString("plugin_name", incoming, 64, "Wat");
Function fn = this.GetFunction(incoming);
if (fn != INVALID_FUNCTION)
{
Call_StartFunction(null, fn);
Call_PushCell(kv);
Call_Finish();
}
}
}
enum struct FF2Utility
{
FF2ConfigList cfg_list;
int size_of_list;
FF2AutoProcess proc;
FF2DefaultsToVSH2 defaults;
void FreeAll()
{
delete this.proc;
this.cfg_list.FreeAll();
delete this.cfg_list;
}
}
FF2Utility ff2u;
#include "ff2config_to_vsh2/default_abilities.sp"
#include "ff2config_to_vsh2/new_slots.sp"
#include "ff2config_to_vsh2/new_enums.sp"
public void OnPluginStart()
{
ff2u.cfg_list = new FF2ConfigList();
ff2u.proc = new FF2AutoProcess();
ff2u.size_of_list = ff2u.cfg_list.Length;
#if defined FF2_DEFAULTS_TO_VSH2
ff2u.defaults = new FF2DefaultsToVSH2();
Defaults_OnPluginStart();
#endif /// FF2_DEFAULTS_TO_VSH2
#if defined FF2_USING_NEW_SLOTS
Abilities_OnPluginStart();
#endif /// FF2_USING_NEW_SLOTS
#if defined FF2_USING_CONFIGMAP_ENUMERATION
VSH2Enums_OnPluginStart();
#endif /// FF2_USING_CONFIGMAP_ENUMERATION
CreateTimer(0.1, Schedule_WriteConfigs, 0);
}
static Action Schedule_WriteConfigs(Handle timer, int current)
{
if (ff2u.size_of_list <= current)
{
ff2u.FreeAll();
CreateTimer(0.1, Schedule_FinishCharacters, 0);
return Plugin_Continue;
}
KVAndPath data;
ff2u.cfg_list.GetArray(current, data);
KeyValues kv = data.kv;
File hFile = OpenFile(data.path, "wt");
BEGIN_PROF_SECTION();
_RecursiveProcessSection(kv, hFile);
END_PROF_SECTION(data.path);
hFile.Close();
CreateTimer(0.1, Schedule_WriteConfigs, current + 1);
return Plugin_Continue;
}
static Action Schedule_FinishCharacters(Handle timer)
{
KeyValues kv = new KeyValues("");
char path[PLATFORM_MAX_PATH];
BuildPath(Path_SM, path, sizeof(path), "data/freak_fortress_2/characters.cfg");
kv.ImportFromFile(path);
File hFile = OpenFile(path, "wt");
BEGIN_PROF_SECTION();
_RecursiveChangeSectionName(kv, hFile);
END_PROF_SECTION("Characters.cfg");
hFile.Close();
delete kv;
return Plugin_Continue;
}
static void _RecursiveChangeSectionName(KeyValues kv, File hFile, int deep = 0)
{
char[] tabs = new char[deep];
for(int i; i < deep; i++) tabs[i] = '\t';
char[] val = new char[512];
char section[64];
do
{
kv.GetSectionName(section, sizeof(section));
if (kv.GotoFirstSubKey(false))
{
hFile.WriteLine("%s\"%s\"\n%s{", tabs, section, tabs);
_RecursiveChangeSectionName(kv, hFile, deep + 1);
kv.GoBack();
hFile.WriteLine("%s}", tabs);
}
else
{
if (kv.GetDataType(NULL_STRING))
{
kv.GetString(NULL_STRING, val, 512);
hFile.WriteLine("%s\"<enum>\"\t\"%s\"", tabs, val);
}
else
{
hFile.WriteLine("%s\"%s\"", tabs, section);
hFile.WriteLine("%s{\n%s}", tabs, tabs);
}
}
} while (kv.GotoNextKey(false));
}
static void _RecursiveProcessSection(KeyValues kv, File hFile, int deep = 0)
{
char[] tabs = new char[deep];
for(int i; i < deep; i++) tabs[i] = '\t';
char[] val = new char[512];
char section[64];
do
{
kv.GetSectionName(section, sizeof(section));
if (!kv.GetDataType(NULL_STRING) && ff2u.proc.ProcessOne(kv, hFile, section))
{
// _RecursiveProcessSection(kv, hFile, deep + 1);
kv.GoBack();
continue;
}
else if (kv.GotoFirstSubKey(false))
{
hFile.WriteLine("%s\"%s\"\n%s{", tabs, section, tabs);
_RecursiveProcessSection(kv, hFile, deep + 1);
kv.GoBack();
hFile.WriteLine("%s}", tabs);
}
else
{
if (kv.GetDataType(NULL_STRING))
{
kv.GetSectionName(section, sizeof(section));
kv.GetString(NULL_STRING, val, 512);
hFile.WriteLine("%s\"%s\"\t\"%s\"", tabs, section, val);
}
else
{
hFile.WriteLine("%s\"%s\"", tabs, section);
hFile.WriteLine("%s{\n%s}", tabs, tabs);
}
}
} while (kv.GotoNextKey(false));
}
static void _RecursiveOpenFile(DirectoryListing Dir, ArrayList& List)
{
if (!Dir)
return;
KVAndPath data;
FileType ft;
while (Dir.GetNext(data.path, sizeof(KVAndPath::path), ft))
{
switch (ft)
{
case FileType_File:
{
BuildPath(Path_SM, data.path, sizeof(KVAndPath::path), "%s/%s", PATH_TO_CFG, data.path);
KeyValues kv = new KeyValues("character");
if (kv)
{
kv.ImportFromFile(data.path);
data.kv = kv;
List.PushArray(data);
}
}
case FileType_Directory:
{
if (data.path[0] == '.') continue;
BuildPath(Path_SM, data.path, sizeof(KVAndPath::path), "%s/%s", PATH_TO_CFG, data.path);
_RecursiveOpenFile(OpenDirectory(data.path), List);
}
}
}
delete Dir;
}
enum FF2CallType_t {
CT_NONE = 0b000000000, /// Inactive, default to CT_RAGE
CT_LIFE_LOSS = 0b000000001,
CT_RAGE = 0b000000010,
CT_CHARGE = 0b000000100,
CT_UNUSED_DEMO = 0b000001000, /// UNUSED
CT_WEIGHDOWN = 0b000010000,
CT_PLAYER_KILLED = 0b000100000,
CT_BOSS_KILLED = 0b001000000,
CT_BOSS_STABBED = 0b010000000,
CT_BOSS_MG = 0b100000000,
};
stock FF2CallType_t Num_To_Slot(int slot)
{
/**
* -2 - Invalid slot(internally used by FF2 for detecting missing "arg0" argument). Don't use!
* -1 - When Boss loses a life (if he has over 1)
* 0 - Rage
* 1 - Used by charging brave Jump. Fired every 0.2s
* 2 - Demopan's charge of targe, projectiles etc.
* 3 - Weighdown
* 4 - Killed player (not used for sounds)
* 5 - Boss killed (not used for sounds)
* 6 - Boss backstabbed (not used for sounds)
* 7 - Boss market gardened (not used for sounds)
*/
switch (slot)
{
case -2, 2: {
// 2, -2 should never be used unless you're calling with FF2Player.ForceAbility
return CT_UNUSED_DEMO;
}
case -1: return CT_LIFE_LOSS;
case 1: return CT_CHARGE;
case 0: return CT_RAGE;
// case 3, 4, 5, 6, 7:
default: {
return view_as<FF2CallType_t>(1 << (1 + slot));
}
}
}