@blizzhackers/d2data 3.1.91737 → 3.1.91738

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. package/.vscode/launch.json +20 -0
  2. package/README.md +1 -7
  3. package/package.json +3 -7
  4. package/.eslintrc.js +0 -59
  5. package/_config.yml +0 -1
  6. package/compile.js +0 -908
  7. package/docs/_config.yml +0 -1
  8. package/docs/armor.js +0 -134
  9. package/docs/drops/.vscode/extensions.json +0 -3
  10. package/docs/drops/README.md +0 -7
  11. package/docs/drops/dist/assets/index.12ae3c90.js +0 -6675
  12. package/docs/drops/dist/index.html +0 -10
  13. package/docs/drops/index.html +0 -23
  14. package/docs/drops/package-lock.json +0 -1143
  15. package/docs/drops/package.json +0 -17
  16. package/docs/drops/src/App.vue +0 -870
  17. package/docs/drops/src/main.js +0 -4
  18. package/docs/drops/vite.config.js +0 -8
  19. package/docs/drops.html +0 -10
  20. package/docs/effort.css +0 -118
  21. package/docs/effort.js +0 -367
  22. package/docs/elem-effort.html +0 -130
  23. package/docs/images/0-0.svg +0 -18
  24. package/docs/images/0-1.svg +0 -17
  25. package/docs/images/0-2.svg +0 -17
  26. package/docs/images/1-0.svg +0 -18
  27. package/docs/images/1-1.svg +0 -18
  28. package/docs/images/1-2.svg +0 -17
  29. package/docs/images/2-0.svg +0 -17
  30. package/docs/images/2-1.svg +0 -11
  31. package/docs/images/2-2.svg +0 -18
  32. package/docs/images/3-0.svg +0 -17
  33. package/docs/images/3-1.svg +0 -18
  34. package/docs/images/3-2.svg +0 -18
  35. package/docs/images/4-0.svg +0 -18
  36. package/docs/images/4-1.svg +0 -18
  37. package/docs/images/4-2.svg +0 -18
  38. package/docs/images/5-0.svg +0 -18
  39. package/docs/images/5-1.svg +0 -18
  40. package/docs/images/5-2.svg +0 -14
  41. package/docs/images/6-0.svg +0 -17
  42. package/docs/images/6-1.svg +0 -17
  43. package/docs/images/6-2.svg +0 -17
  44. package/docs/images/AmSkillicon.png +0 -0
  45. package/docs/images/AsSkillicon.png +0 -0
  46. package/docs/images/BaSkillicon.png +0 -0
  47. package/docs/images/DrSkillicon.png +0 -0
  48. package/docs/images/NeSkillicon.png +0 -0
  49. package/docs/images/PaSkillicon.png +0 -0
  50. package/docs/images/Skillicon.png +0 -0
  51. package/docs/images/SoSkillicon.png +0 -0
  52. package/docs/index.md +0 -5
  53. package/docs/items.html +0 -170
  54. package/docs/leveling/.vscode/extensions.json +0 -3
  55. package/docs/leveling/README.md +0 -7
  56. package/docs/leveling/dist/assets/index.f9765357.js +0 -1
  57. package/docs/leveling/dist/index.html +0 -24
  58. package/docs/leveling/index.html +0 -23
  59. package/docs/leveling/package-lock.json +0 -1143
  60. package/docs/leveling/package.json +0 -17
  61. package/docs/leveling/src/App.vue +0 -526
  62. package/docs/leveling/src/main.js +0 -4
  63. package/docs/leveling/vite.config.js +0 -8
  64. package/docs/runewords/.vscode/extensions.json +0 -3
  65. package/docs/runewords/README.md +0 -7
  66. package/docs/runewords/dist/assets/index.0838f27c.js +0 -6673
  67. package/docs/runewords/dist/assets/index.73bf3e23.css +0 -1
  68. package/docs/runewords/dist/index.html +0 -25
  69. package/docs/runewords/index.html +0 -23
  70. package/docs/runewords/package-lock.json +0 -1143
  71. package/docs/runewords/package.json +0 -17
  72. package/docs/runewords/src/App.vue +0 -781
  73. package/docs/runewords/src/main.js +0 -4
  74. package/docs/runewords/src/modorder.json +0 -234
  75. package/docs/runewords/vite.config.js +0 -8
  76. package/docs/skills.css +0 -1250
  77. package/docs/skills.html +0 -63
  78. package/docs/skills.js +0 -2192
  79. package/docs/vue-setup.js +0 -12
  80. package/docs/weapons.js +0 -149
  81. package/font-example.html +0 -34
  82. package/generatecsv.js +0 -64
  83. package/json/.gitkeep +0 -0
  84. package/json/base/.gitkeep +0 -0
  85. package/json/base/precalctc/.gitkeep +0 -0
  86. package/json/precalctc/.gitkeep +0 -0
  87. package/objext.js +0 -53
  88. package/precalctc.php +0 -318
  89. package/string.js +0 -93
package/compile.js DELETED
@@ -1,908 +0,0 @@
1
- /**
2
- * Compile script for the json data. Basically, put all your txt files into
3
- * the txt/ directory, and this will compile it all into json. It assumes that
4
- * you've provided at least 'armor.txt', 'weapons.txt', 'TreasureClassEx.txt',
5
- * 'ItemTypes.txt', and 'monstats.txt'.
6
- *
7
- * @todo Refactor it, since I hacked it together fairly quickly.
8
- */
9
-
10
- require('./objext.js');
11
- const fs = require('fs');
12
-
13
- [
14
- ['txt/', 'json/'],
15
- ['txt/base/', 'json/base/'],
16
- ].forEach(dirs => {
17
- const inDir = dirs[0], outDir = dirs[1];
18
- const lineEnd = /[\n\r]+/g, fieldEnd = /\t/g, full = {};
19
- const files = fs.readdirSync(inDir).filter(fn => fn.slice(-4) === '.txt').map(fn => fn.slice(0, -4));
20
- const decimalPrecision = 15;
21
-
22
- function keySort(obj) {
23
- let keys = Object.keys(obj).sort(), ret = {};
24
-
25
- keys.forEach(key => {
26
- ret[key] = obj[key];
27
- });
28
-
29
- return ret;
30
- }
31
-
32
- const indexes = {
33
- actinfo: 'act',
34
- armor: 'code',
35
- armtype: 'Token',
36
- bodylocs: 'Code',
37
- books: 'Name',
38
- charstats: 'class',
39
- colors: 'Code',
40
- compcode: 'code',
41
- composit: 'Name',
42
- cubemod: 'Code',
43
- difficultylevels: 'Name',
44
- elemtypes: 'Code',
45
- experience: 'Level',
46
- events: 'event',
47
- gems: 'code',
48
- hirelingdesc: 'id',
49
- hitclass: 'Code',
50
- inventory: 'class',
51
- itemstatcost: 'Stat',
52
- itemtypes: 'Code',
53
- levelgroups: 'LevelGroupId',
54
- levels: 'Id',
55
- lvlmaze: 'Level',
56
- lvlprest: 'Def',
57
- lvltypes: 'Name',
58
- misc: 'code',
59
- misscalc: 'code',
60
- missiles: 'Missile',
61
- monai: 'AI',
62
- monmode: 'code',
63
- monpet: 'monster',
64
- monprop: 'Id',
65
- monstats: 'Id',
66
- monstats2: 'Id',
67
- monsounds: 'Id',
68
- montype: 'type',
69
- monumod: 'id',
70
- npc: 'npc',
71
- objmode: 'Token',
72
- overlay: 'overlay',
73
- pettype: 'pet type',
74
- plrmode: 'Code',
75
- plrtype: 'Token',
76
- playerclass: 'Code',
77
- properties: 'code',
78
- propertygroups: 'code',
79
- runes: '*Rune Name',
80
- runeworduicategories: 'Name',
81
- setitems: 'index',
82
- sets: 'index',
83
- shrines: 'Code',
84
- skillcalc: 'code',
85
- skilldesc: 'code',
86
- skills: '*Id',
87
- soundenviron: 'Handle',
88
- sounds: '*Index',
89
- states: 'state',
90
- storepage: 'Code',
91
- superuniques: 'Superunique',
92
- treasureclassex: 'Treasure Class',
93
- uniqueitems: '*ID',
94
- weapons: 'code',
95
- weaponclass: 'Code',
96
- };
97
-
98
- const filterValues = {
99
- '': true,
100
- 'unused': true,
101
- 'none': true,
102
- 'null': true,
103
- };
104
-
105
- function noDrop(e, nd, ...d) {
106
- if (e <= 1) {
107
- return nd | 0;
108
- }
109
-
110
- e = e | 0;
111
- nd = nd | 0;
112
- d = d.reduce((t, v) => t + v | 0, 0);
113
-
114
- if (d < 1) {
115
- return Infinity;
116
- }
117
-
118
- return (d / (((nd + d) / nd)**e - 1)) | 0;
119
- }
120
-
121
- files.forEach(fn => {
122
- let data = fs.readFileSync(inDir + fn + '.txt').toString().split(lineEnd);
123
- let header = data.shift().split(fieldEnd);
124
- let indexColumn = header.indexOf(indexes[fn]);
125
- let usesVersion = header.includes('version');
126
- let expansion = false;
127
- let maxKeyCount = 0;
128
-
129
- if (indexColumn === -1) {
130
- console.log('Using default Index for:', fn);
131
- }
132
-
133
- full[fn] = data.reduce((obj, line, index) => {
134
- if (line.trim()) {
135
- line = line.split(fieldEnd).map(v => v.trim());
136
-
137
- if (line[0].toLowerCase() === 'expansion') {
138
- expansion = true;
139
- } else if (header.length === 1 || line.filter(Boolean).length > 1) {
140
- let key = indexColumn >= 0 ? (line[indexColumn]) : index;
141
-
142
- if (key !== undefined) {
143
- if (key !== '') {
144
- while (obj[key]) {
145
- console.warn('Duplicate key ' + JSON.stringify(key) + ' in ' + fn);
146
- key += ' [dup]';
147
- }
148
-
149
- {
150
- let tmp = {};
151
-
152
- for (let c = 0; c < header.length; c++) {
153
- if (indexColumn >= 0 && c === indexColumn || !filterValues[line[c].toString().toLowerCase()]) {
154
- tmp[header[c] || 'unknown'] = line[c] !== 'Infinity' && Number(line[c]).toString() === line[c].trim() ? Number(line[c]) : line[c];
155
- }
156
- }
157
-
158
- let keyCount = Object.keys(tmp).length;
159
-
160
- if (keyCount > 0) {
161
- if (usesVersion) {
162
- if (tmp.version >= 100) {
163
- tmp.expansion = 1;
164
- }
165
- } else if (expansion) {
166
- tmp.expansion = 1;
167
- }
168
-
169
- obj[key] = tmp;
170
-
171
- delete obj[key]['*eol'];
172
- delete obj[key]['*EOL'];
173
- delete obj[key]['eol'];
174
- delete obj[key]['EOL'];
175
-
176
- if (indexColumn >= 0) {
177
- obj[key].lineNumber = index;
178
- }
179
- }
180
-
181
- maxKeyCount = Math.max(maxKeyCount, keyCount);
182
- }
183
- }
184
- } else {
185
- throw new Error('No viable key in: ' + fn + ' : ' + key);
186
- }
187
- }
188
- }
189
-
190
- return obj;
191
- }, {});
192
-
193
- if (maxKeyCount === 1) {
194
- full[fn] = Object.values(full[fn]).map(line => Object.values(line)[0]);
195
- console.log(fn, 'was reduced!');
196
- }
197
-
198
- if (fn === 'treasureclassex') {
199
- full[fn].forEach(tc => {
200
- let precalc = {}, nodropcalc = {
201
- 1: 0,
202
- 2: 0,
203
- 3: 0,
204
- 4: 0,
205
- 5: 0,
206
- 6: 0,
207
- 7: 0,
208
- 8: 0,
209
- };
210
-
211
- if (tc.Picks > 0) {
212
- let total = 0;
213
-
214
- for (let c = 1; c <= 9; c++) {
215
- if (tc['Item' + c]) {
216
- total += tc['Prob' + c] | 0;
217
- }
218
- }
219
-
220
- [1, 2, 3, 4, 5, 6, 7, 8].forEach(exp => {
221
- nodropcalc[exp] = noDrop(exp, tc.NoDrop, total);
222
- });
223
-
224
- for (let c = 1; c <= 9; c++) {
225
- if (tc['Item' + c]) {
226
- let prob = (tc['Prob' + c] | 0) / total;
227
- precalc[tc['Item' + c]] = precalc[tc['Item' + c]] || 0;
228
- precalc[tc['Item' + c]] += prob;
229
- }
230
- }
231
-
232
- precalc = precalc.map(v => v * tc.Picks);
233
- tc['*ItemProbTotal'] = total;
234
- }
235
- else if (tc.Picks < 0) {
236
- let picksleft = -tc.Picks;
237
-
238
- for (let c = 1; c <= 9; c++) {
239
- if (tc['Item' + c] && picksleft > 0) {
240
- let pickcount = Math.min(picksleft, tc['Prob' + c] | 0);
241
-
242
- if (pickcount > 0) {
243
- precalc[tc['Item' + c]] = precalc[tc['Item' + c]] || 0;
244
- precalc[tc['Item' + c]] += pickcount;
245
- picksleft -= pickcount;
246
- }
247
- }
248
- }
249
- }
250
-
251
- tc.nodropcalc = nodropcalc;
252
- tc.precalc = precalc;
253
- });
254
- }
255
-
256
- if (fn === 'superuniques') {
257
- full[fn]['Bishibosh'].areaId = 3;
258
- full[fn]['Bonebreak'].areaId = 18;
259
- full[fn]['Coldcrow'].areaId = 9;
260
- full[fn]['Rakanishu'].areaId = 4;
261
- full[fn]['Treehead WoodFist'].areaId = 5;
262
- full[fn]['Griswold'].areaId = 38;
263
- full[fn]['The Countess'].areaId = 25;
264
- full[fn]['Pitspawn Fouldog'].areaId = 30;
265
- full[fn]['Boneash'].areaId = 33;
266
- full[fn]['Radament'].areaId = 49;
267
- full[fn]['Bloodwitch the Wild'].areaId = 60;
268
- full[fn]['Fangskin'].areaId = 61;
269
- full[fn]['Beetleburst'].areaId = 43;
270
- full[fn]['Leatherarm'].areaId = 59;
271
- full[fn]['Coldworm the Burrower'].areaId = 64;
272
- full[fn]['Fire Eye'].areaId = 54;
273
- full[fn]['Dark Elder'].areaId = 44;
274
- // full[fn]['The Summoner'].areaId = 74; // I don't think he spawns a superunique.
275
- full[fn]['The Smith'].areaId = 28;
276
- full[fn]['Web Mage the Burning'].areaId = 85;
277
- full[fn]['Witch Doctor Endugu'].areaId = 91;
278
- full[fn]['Stormtree'].areaId = 78;
279
- full[fn]['Sarina the Battlemaid'].areaId = 94;
280
- full[fn]['Icehawk Riftwing'].areaId = 92;
281
- full[fn]['Ismail Vilehand'].areaId = 83;
282
- full[fn]['Geleb Flamefinger'].areaId = 83;
283
- full[fn]['Bremm Sparkfist'].areaId = 102;
284
- full[fn]['Toorc Icefist'].areaId = 83;
285
- full[fn]['Wyand Voidfinger'].areaId = 102;
286
- full[fn]['Maffer Dragonhand'].areaId = 102;
287
- full[fn]['Infector of Souls'].areaId = 108;
288
- full[fn]['Lord De Seis'].areaId = 108;
289
- full[fn]['Grand Vizier of Chaos'].areaId = 108;
290
- full[fn]['The Cow King'].areaId = 39;
291
- full[fn]['Corpsefire'].areaId = 8;
292
- full[fn]['The Feature Creep'].areaId = 107;
293
- full[fn]['Siege Boss'].areaId = 110;
294
- full[fn]['Ancient Barbarian 1'].areaId = 120;
295
- full[fn]['Ancient Barbarian 2'].areaId = 120;
296
- full[fn]['Ancient Barbarian 3'].areaId = 120;
297
- full[fn]['Bonesaw Breaker'].areaId = 115;
298
- full[fn]['Dac Farren'].areaId = 110;
299
- full[fn]['Megaflow Rectifier'].areaId = 111;
300
- full[fn]['Eyeback Unleashed'].areaId = 111;
301
- full[fn]['Threash Socket'].areaId = 112;
302
- full[fn]['Pindleskin'].areaId = 121;
303
- full[fn]['Snapchip Shatter'].areaId = 119;
304
- full[fn]['Sharp Tooth Sayer'].areaId = 111;
305
- full[fn]['Frozenstein'].areaId = 114;
306
- full[fn]['Nihlathak Boss'].areaId = 124;
307
- full[fn]['Baal Subject 1'].areaId = 131;
308
- full[fn]['Baal Subject 2'].areaId = 131;
309
- full[fn]['Baal Subject 3'].areaId = 131;
310
- full[fn]['Baal Subject 4'].areaId = 131;
311
- full[fn]['Baal Subject 5'].areaId = 131;
312
- }
313
-
314
- if (fn === 'monstats') {
315
- full[fn]['bloodraven'].areaId = 17;
316
- full[fn]['summoner'].areaId = 74;
317
- full[fn]['andariel'].areaId = 37;
318
- full[fn]['duriel'].areaId = 73;
319
- full[fn]['mephisto'].areaId = 102;
320
- full[fn]['izual'].areaId = 105;
321
- full[fn]['diablo'].areaId = 108;
322
- full[fn]['baalcrab'].areaId = 132;
323
- full[fn]['ubermephisto'].areaId = 136;
324
- full[fn]['uberdiablo'].areaId = 136;
325
- full[fn]['uberizual'].areaId = 135;
326
- full[fn]['uberandariel'].areaId = 133;
327
- full[fn]['uberduriel'].areaId = 134;
328
- full[fn]['uberbaal'].areaId = 136;
329
- }
330
- });
331
-
332
- const items = {};
333
-
334
- [
335
- ...Object.values(full.weapons).sort((a, b) => a.lineNumber - b.lineNumber),
336
- ...Object.values(full.armor).sort((a, b) => a.lineNumber - b.lineNumber),
337
- ...Object.values(full.misc).sort((a, b) => a.lineNumber - b.lineNumber),
338
- ].forEach((item, classid) => {
339
- item.classid = classid;
340
- items[item.code] = item;
341
- });
342
-
343
- let atomic = {};
344
- let atomicTypes = {};
345
- let atomicMax = 87;
346
-
347
- let calcTC = x => {
348
- let ret = Math.max(1, Math.ceil((x || 0) / 3)) * 3;
349
- atomicMax = Math.max(ret, atomicMax);
350
- return ret;
351
- }
352
-
353
- let weaponsarmor = [...Object.values(full.weapons), ...Object.values(full.armor)];
354
-
355
- weaponsarmor.forEach(item => {
356
- if (!item.spawnable) {
357
- return;
358
- }
359
-
360
- let tc = calcTC(item.level);
361
-
362
- function handleAtomic(itemType) {
363
- if (full.itemtypes[itemType] && itemType !== 'tpot') {
364
- if (full.itemtypes[itemType].TreasureClass) {
365
- atomicTypes[itemType] = true;
366
- atomic[itemType + tc] = atomic[itemType + tc] || [];
367
- atomic[itemType + tc][item.lineNumber] = item.code;
368
- }
369
-
370
- if (full.itemtypes[itemType].Equiv1) {
371
- handleAtomic(full.itemtypes[itemType].Equiv1);
372
- }
373
-
374
- if (full.itemtypes[itemType].Equiv2) {
375
- handleAtomic(full.itemtypes[itemType].Equiv2);
376
- }
377
- }
378
- }
379
-
380
- handleAtomic(item.type);
381
- });
382
-
383
- atomicTypes = Object.keys(atomicTypes);
384
-
385
- for (let c = 3; c <= atomicMax; c += 3) {
386
- atomicTypes.forEach(type => {
387
- atomic[type + c] = atomic[type + c] || [];
388
- });
389
- }
390
-
391
- atomic.forEach((atom, atomName) => {
392
- let precalc = {}, total = 0;
393
-
394
- atom.forEach((itc, i) => {
395
- let rarity = full.itemtypes[items[itc].type].Rarity | 0;
396
- total += rarity;
397
- atom[i] = [itc, rarity];
398
- });
399
-
400
- atom.forEach(([itc, chance]) => {
401
- precalc[itc] = chance / total;
402
- });
403
-
404
- atomic[atomName] = precalc;
405
- });
406
-
407
- full.atomic = atomic;
408
-
409
- let groupsEx = {};
410
-
411
- full.treasureclassex.forEach((tc, key) => {
412
- if (tc.group) {
413
- groupsEx[tc.group] = groupsEx[tc.group] || [];
414
- groupsEx[tc.group][tc.level|0] = key;
415
- }
416
- });
417
-
418
- groupsEx = groupsEx.map(group => {
419
- let length = group.length;
420
- group = Object.assign({}, group);
421
- group.length = length;
422
- return group;
423
- });
424
-
425
- function avg(...nums) {
426
- return nums.reduce((t, v) => t + v, 0) / nums.length || 0;
427
- }
428
-
429
- function _s(diff) {
430
- return (str) => str + ["", "(N)", "(H)"][diff];
431
- }
432
-
433
- function monlevel(mon, level, diff) {
434
- if (!diff) {
435
- return mon["Level"] || 0;
436
- }
437
-
438
- let s = _s(diff),
439
- lvl = level[s("MonLvlEx")] || 0,
440
- mlvl = mon[s("Level")] || 0;
441
-
442
- return (diff && !mon.boss) ? lvl : mlvl;
443
- }
444
-
445
- function forEachMonster(level, diff, func) {
446
- let s = _s(diff);
447
-
448
- [0, 1, 2].forEach((type) => {
449
- if (type && !level[s("MonUMin")] && !level[s("MonUMax")]) {
450
- return;
451
- }
452
-
453
- let m = (num) => level[(diff ? "nmon" : type ? "umon" : "mon") + num];
454
-
455
- let totalrarity = 0;
456
- let rarity = {};
457
-
458
- for (let c = 1; c <= 9; c++) {
459
- if (m(c)) {
460
- let mon = full.monstats[m(c)];
461
-
462
- if (mon && mon.enabled && mon.killable) {
463
- totalrarity += mon.Rarity || 0;
464
- rarity[mon.Id] = rarity[mon.Id] || 0;
465
- rarity[mon.Id] += (mon.Rarity || 0);
466
- }
467
- }
468
- }
469
-
470
- for (let key in rarity) {
471
- let mon = full.monstats[key];
472
-
473
- if (rarity[key] > 0 && mon && mon.enabled && mon.killable) {
474
- let mlvl = monlevel(mon, level, diff) + [0, 2, 3][type];
475
-
476
- func(mon, mlvl, type, rarity[key] / totalrarity);
477
- }
478
- }
479
- });
480
- }
481
-
482
- const moncountest = require('./json/moncountest.json');
483
-
484
- let monpopulation = {};
485
-
486
- [0, 1, 2].forEach((diff) => {
487
- let uniqueCount = 3.5 + diff;
488
- let champCount = 3;
489
- let uniqueRatio = 0.8, champRatio = 0.2;
490
- let s = _s(diff);
491
- full.levels.forEach((level) => {
492
- let l = (key) => level[key] || 0;
493
-
494
- monpopulation[level.Id] = monpopulation[level.Id] || {
495
- 'normal': {},
496
- 'champion': {},
497
- 'unique': {},
498
- 'superunique': {},
499
- 'boss': {},
500
- };
501
-
502
- if (level.Id) {
503
- let supers = full.superuniques.filter(s => s.areaId == level.Id || (s.hcIdx === 19 && [66, 67, 68, 69, 70, 71, 72].includes(level.Id | 0))),
504
- bosses = full.monstats.filter((mon) => mon.areaId == level.Id),
505
- acount = (moncountest[level.Id] && moncountest[level.Id][diff]) || 0,
506
- scount = supers.reduce((total, sup) => {
507
- let mon = full.monstats[sup.Class];
508
-
509
- return (
510
- total +
511
- 1 +
512
- diff +
513
- avg(
514
- (sup["MinGrp"] || 0),
515
- (sup["MaxGrp"] || 0)
516
- ) +
517
- avg(
518
- (mon["PartyMin"] || 0),
519
- (mon["PartyMax"] || 0)
520
- )
521
- );
522
- }, 0),
523
- bcount = bosses.reduce((total, mon) => {
524
- return (
525
- total +
526
- 1 +
527
- avg(
528
- (mon["MinGrp"] || 0),
529
- (mon["MaxGrp"] || 0)
530
- ) +
531
- avg(
532
- (mon["PartyMin"] || 0),
533
- (mon["PartyMax"] || 0)
534
- )
535
- );
536
- }, 0),
537
- monucount = avg(l(s("MonUMin")), l(s("MonUMax"))),
538
- ucount = monucount * uniqueRatio * uniqueCount,
539
- ccount = 0;
540
-
541
- forEachMonster(level, diff, (mon, mlvl, type, rarity) => {
542
- if (type === 1) {
543
- ccount += (monucount * rarity * champRatio) * (champCount + avg((mon["PartyMin"] || 0), (mon["PartyMax"] || 0)));
544
- }
545
- });
546
-
547
- let count = acount - ucount - ccount - scount - bcount;
548
-
549
- if (count > 0) {
550
- let ratio = [{}, {}, {}, {}, {}];
551
-
552
- forEachMonster(level, diff, (mon, mlvl, type, rarity) => {
553
- let grp = [
554
- avg(
555
- (mon["MinGrp"] || 0),
556
- (mon["MaxGrp"] || 0)
557
- ),
558
- 3,
559
- 1,
560
- ][type];
561
- ratio[type][mon.Id] = rarity * grp +
562
- avg(
563
- (mon["PartyMin"] || 0),
564
- (mon["PartyMax"] || 0)
565
- );
566
- });
567
-
568
- for (let stype = 0; stype < 5; stype++) {
569
- let totalratio = 0;
570
-
571
- for (let skey in ratio[stype]) {
572
- totalratio += ratio[stype][skey];
573
- }
574
-
575
- for (let skey in ratio[stype]) {
576
- ratio[stype][skey] /= totalratio;
577
- }
578
- }
579
-
580
- forEachMonster(level, diff, (mon, mlvl, type, rarity) => {
581
- let mult = [
582
- count * ratio[type][mon.Id] / (avg((mon["MinGrp"] || 0), (mon["MaxGrp"] || 0)) + avg((mon["PartyMin"] || 0), (mon["PartyMax"] || 0))),
583
- monucount * rarity * champRatio,
584
- monucount * rarity * uniqueRatio,
585
- ][type];
586
- monpopulation[level.Id][['normal', 'champion', 'unique'][type]][mon.Id] = monpopulation[level.Id][['normal', 'champion', 'unique'][type]][mon.Id] || {
587
- "mlvl": 0,
588
- "packCount": 0,
589
- "mlvl(N)": 0,
590
- "packCount(N)": 0,
591
- "mlvl(H)": 0,
592
- "packCount(H)": 0,
593
- };
594
- monpopulation[level.Id][['normal', 'champion', 'unique'][type]][mon.Id][s('mlvl')] = mlvl;
595
- monpopulation[level.Id][['normal', 'champion', 'unique'][type]][mon.Id][s('packCount')] = Math.round(mult * (10 ** decimalPrecision)) / (10 ** decimalPrecision);
596
- });
597
- }
598
-
599
- supers.forEach((sup) => {
600
- let mon = full.monstats[sup.Class],
601
- mlvl = monlevel(mon, level, diff) + 3;
602
-
603
- monpopulation[level.Id]['superunique'][sup.Superunique] = monpopulation[level.Id]['superunique'][sup.Superunique] || {
604
- "mlvl": 0,
605
- "packCount": 0,
606
- "mlvl(N)": 0,
607
- "packCount(N)": 0,
608
- "mlvl(H)": 0,
609
- "packCount(H)": 0,
610
- "hasStaticLevel": false,
611
- };
612
-
613
- monpopulation[level.Id]['superunique'][sup.Superunique][s('mlvl')] = mlvl;
614
- monpopulation[level.Id]['superunique'][sup.Superunique][s('packCount')] = sup.hcIdx === 19 ? 1 / 7 : 1;
615
- monpopulation[level.Id]['superunique'][sup.Superunique].hasStaticLevel = Boolean(mon.boss);
616
- });
617
-
618
- bosses.forEach((mon) => {
619
- let mlvl = monlevel(mon, level, diff);
620
-
621
- monpopulation[level.Id]['boss'][mon.Id] = monpopulation[level.Id]['boss'][mon.Id] || {
622
- "mlvl": 0,
623
- "packCount": 0,
624
- "mlvl(N)": 0,
625
- "packCount(N)": 0,
626
- "mlvl(H)": 0,
627
- "packCount(H)": 0,
628
- "hasStaticLevel": false,
629
- };
630
- monpopulation[level.Id]['boss'][mon.Id][s('mlvl')] = mlvl;
631
- monpopulation[level.Id]['boss'][mon.Id][s('packCount')] = 1;
632
- monpopulation[level.Id]['boss'][mon.Id].hasStaticLevel = Boolean(mon.boss);
633
- });
634
- }
635
- });
636
- });
637
-
638
- let actprofile = {};
639
- let montypes = ['normal', 'champion', 'unique', 'superunique', 'boss'];
640
- let dmgtypes = [
641
- 'ResDm',
642
- 'ResMa',
643
- 'ResFi',
644
- 'ResLi',
645
- 'ResCo',
646
- 'ResPo',
647
- ];
648
-
649
- let progressionAreas = [ // Areas that we're forced to deal with while progressing through the main quest lines.
650
- // Act 1
651
- 2,3,4,5,6,7,10,26,27,28,29,30,31,32,33,34,35,36,
652
- // Act 2
653
- 41,42,43,44,45,46,50,51,52,53,54,56,57,58,60,61,62,63,64,66,67,68,69,70,71,72,73,
654
- // Act 3
655
- 76,77,78,79,80,81,82,83,85,88,89,91,92,93,100,101,
656
- // Act 4
657
- 104,105,106,107,
658
- // Act 5
659
- 110,111,112,113,115,117,118,120,128,129,130,
660
- ];
661
-
662
- let bossAreas = [ // Areas that we're forced to deal with for boss farming.
663
- 37,74,102,108,131,132,
664
- ];
665
-
666
- for (let diff of [0, 1, 2]) {
667
- let s = str => str + ['', '(N)', '(H)'][diff];
668
-
669
- for (let levelid in monpopulation) {
670
- levelid = Number(levelid);
671
-
672
- let level = full.levels[levelid];
673
- let act = (level.Act || 0);
674
- let pop = monpopulation[levelid];
675
-
676
- if (levelid < 1 || levelid > 132) {
677
- continue;
678
- }
679
-
680
- let category = bossAreas.indexOf(levelid) >= 0 ? 'boss' : (progressionAreas.indexOf(levelid) >= 0 ? 'progression' : 'optional');
681
-
682
- for (let montype of montypes) {
683
- for (let id in pop[montype]) {
684
- let sup = undefined,
685
- mon = undefined;
686
-
687
- if (montype === 'superunique') {
688
- sup = full.superuniques[id];
689
- mon = full.monstats[sup.Class];
690
- }
691
- else {
692
- mon = full.monstats[id];
693
- }
694
-
695
- let grp = Math.max(1, ((mon['MinGrp'] || 1) + (mon['MaxGrp'] || 1)) / 2),
696
- party = ((mon['PartyMin'] || 0) + mon['PartyMax'] || 0) / 4,
697
- minions = [
698
- mon['minion1'] || undefined,
699
- mon['minion2'] || undefined,
700
- ].filter(Boolean),
701
- packCount = pop[montype][id][s('packCount')],
702
- mlvl = pop[montype][id][s('mlvl')],
703
- hp = full.monlvl[mlvl][s('HP')] *
704
- (mon[['minHP', 'MinHP(N)', 'MinHP(H)'][diff]] + mon[['maxHP', 'MaxHP(N)', 'MaxHP(H)'][diff]]) / 200;
705
-
706
- if ((montype === 'superunique' || montype === 'unique') && !minions.length) {
707
- minions.push(mon.Id);
708
- }
709
-
710
- actprofile[act] = actprofile[act] || {};
711
- actprofile[act][category] = actprofile[act][category] || {};
712
-
713
- for (let dmgtype of dmgtypes) {
714
- actprofile[act][category][s(dmgtype)] = actprofile[act][category][s(dmgtype)] || {};
715
- }
716
-
717
- for (let dmgtype of dmgtypes) {
718
- let resist = mon[s(dmgtype)] || 0;
719
-
720
- actprofile[act][category][s(dmgtype)][resist] = actprofile[act][category][s(dmgtype)][resist] || 0;
721
-
722
- if (montype === 'superunique' || montype === 'unique') {
723
- if (montype === 'superunique') {
724
- grp = Math.max(1, ((sup['MinGrp'] || mon['MinGrp'] || 1) + (sup['MaxGrp'] || mon['MaxGrp'] || 1)) / 2);
725
- }
726
- else {
727
- grp = Math.max(1, ((mon['MinGrp'] || 1) + (mon['MaxGrp'] || 1)) / 2);
728
- }
729
- actprofile[act][category][s(dmgtype)][resist] += packCount * hp * [4, 3, 2][diff];
730
- party = 2.5 + diff;
731
- }
732
- else if (montype === 'champion') {
733
- actprofile[act][category][s(dmgtype)][resist] += packCount * hp * 3 * [3, 2.5, 2][diff];
734
- }
735
- else {
736
- actprofile[act][category][s(dmgtype)][resist] += packCount * hp * grp;
737
- }
738
-
739
- if (party > 0 && minions.length > 0) {
740
- for (let minion of minions) {
741
- let mmon = full.monstats[minion],
742
- mresist = mmon[s(dmgtype)] || 0,
743
- mmlvl = (diff ? mmon['Level'] : level[s('MonLvl')]) + (montype === 'superunique' || montype === 'unique' ? 3 : 0),
744
- mhp = full.monlvl[mmlvl][s('HP')] *
745
- (mmon[['minHP', 'MinHP(N)', 'MinHP(H)'][diff]] + mmon[['maxHP', 'MaxHP(N)', 'MaxHP(H)'][diff]]) / 100;
746
-
747
- actprofile[act][category][s(dmgtype)][mresist] = actprofile[act][category][s(dmgtype)][mresist] || 0;
748
- actprofile[act][category][s(dmgtype)][mresist] += packCount * mhp * party / minions.length;
749
- }
750
- }
751
- }
752
- }
753
- }
754
- }
755
- }
756
-
757
- (function roundValues (obj) {
758
- for (let key in obj) {
759
- if (typeof obj[key] === 'number') {
760
- obj[key] = Math.round(obj[key]);
761
- }
762
- else if(typeof obj[key] === 'object') {
763
- roundValues(obj[key]);
764
- }
765
- }
766
- })(actprofile);
767
-
768
- let coldmasterybreakpoints = {}, coldhpbyres = {};
769
-
770
- for (let act of Object.values(actprofile)) {
771
- for (let resset of Object.values(act)) {
772
- if (resset['ResCo(H)']) {
773
- for (let res in resset['ResCo(H)']) {
774
- res = Number(res);
775
- coldhpbyres[res] = coldhpbyres[res] || 0;
776
- coldhpbyres[res] += resset['ResCo(H)'][res];
777
- }
778
- }
779
- }
780
- }
781
-
782
- (function () {
783
- for (let mastery = 0; mastery <= 195; mastery === 0 ? mastery = 20 : mastery ++) {
784
- let ehp = 0;
785
-
786
- for (let res in coldhpbyres) {
787
- res = Number(res);
788
- let pierce = (res >= 100 ? (mastery / 5) : mastery);
789
- let mod = Math.min(2, 1 - (Math.min(95, res) - pierce) / 100);
790
- ehp += coldhpbyres[res] / mod;
791
- }
792
-
793
- coldmasterybreakpoints[mastery] = ehp;
794
- }
795
-
796
- let masterylist = Object.keys(coldmasterybreakpoints);
797
-
798
- for (let i = masterylist.length - 1; i; i--) {
799
- coldmasterybreakpoints[masterylist[i]] = (coldmasterybreakpoints[masterylist[i - 1]] / coldmasterybreakpoints[masterylist[i]] - 1);
800
- }
801
-
802
- coldmasterybreakpoints[0] = 0;
803
-
804
- for (let c = 0; c < 2; c++) {
805
- for (let i = masterylist.length - 1; i; i--) {
806
- coldmasterybreakpoints[masterylist[i]] = coldmasterybreakpoints[masterylist[i]] - coldmasterybreakpoints[masterylist[i - 1]];
807
- }
808
- }
809
-
810
- for (let i = masterylist.length - 1; i; i--) {
811
- coldmasterybreakpoints[masterylist[i]] = coldmasterybreakpoints[masterylist[i]] * 10000;
812
- }
813
-
814
- let newMasteryList = {}, mmin = Infinity;
815
-
816
- for (let i = masterylist.length; i; i--) {
817
- if (coldmasterybreakpoints[masterylist[i]] <= -0.5) {
818
- mmin = Math.min(mmin, -coldmasterybreakpoints[masterylist[i]]);
819
- newMasteryList[masterylist[i - 1]] = -coldmasterybreakpoints[masterylist[i]];
820
- }
821
- }
822
-
823
- for (let key in newMasteryList) {
824
- newMasteryList[key] = Math.round(newMasteryList[key] / mmin);
825
- }
826
-
827
- coldmasterybreakpoints = newMasteryList;
828
- })();
829
-
830
- let tcprecalc = {};
831
-
832
- full.treasureclassex.forEach((tc, key) => {
833
- tcprecalc[key] = tcprecalc[key] || {};
834
- tcprecalc[key].droprate = tc.nodropcalc.map(noDrop => noDrop ? tc['*ItemProbTotal'] / (noDrop + tc['*ItemProbTotal']) : 1);
835
- tcprecalc[key].droprateRoot = {};
836
- tcprecalc[key].counts = tc.precalc;
837
- delete tc['nodropcalc'];
838
- delete tc['precalc'];
839
- });
840
-
841
- atomic.forEach((precalc, key) => {
842
- tcprecalc[key] = {
843
- droprate: {
844
- 1: 1,
845
- 2: 1,
846
- 3: 1,
847
- 4: 1,
848
- 5: 1,
849
- 6: 1,
850
- 7: 1,
851
- 8: 1,
852
- },
853
- droprateRoot: {},
854
- counts: precalc,
855
- };
856
- });
857
-
858
- function totalTC (key, debug = []) {
859
- if (key in tcprecalc) {
860
- let tc = tcprecalc[key], total = 0;
861
-
862
- for (let subtc in tc.counts) {
863
- if (
864
- subtc in items &&
865
- !(subtc in tcprecalc)
866
- ) {
867
- if (!items[subtc].spawnable) {
868
- continue;
869
- }
870
- }
871
-
872
- total += tc.counts[subtc] * totalTC(subtc, debug);
873
- }
874
-
875
- return Math.round(total * 1e15) / 1e15;
876
- }
877
-
878
- return 1;
879
- }
880
-
881
- for (let key in tcprecalc) {
882
- let debug = [], total = totalTC(key, debug), tc = tcprecalc[key];
883
-
884
- tc.droprateRoot = {
885
- ...tc.droprate,
886
- };
887
-
888
- if (total > 6) {
889
- console.log('Normalizing TC', key, 'with total', total, 'picks');
890
- for (let exp in tc.droprateRoot) {
891
- tc.droprateRoot[exp] = tc.droprateRoot[exp] * 6 / total;
892
- }
893
- }
894
- }
895
-
896
- files.forEach(fn => {
897
- fs.writeFileSync(outDir + fn + '.json', JSON.stringify(keySort(full[fn]), null, ' '));
898
- });
899
-
900
- fs.writeFileSync(outDir + 'items.json', JSON.stringify(items, null, ' '));
901
- fs.writeFileSync(outDir + 'atomic.json', JSON.stringify(keySort(atomic), null, ' '));
902
- fs.writeFileSync(outDir + 'treasureclassgroupsex.json', JSON.stringify(groupsEx, null, ' '));
903
- fs.writeFileSync(outDir + 'monpopulationest.json', JSON.stringify(monpopulation, null, ' '));
904
- fs.writeFileSync(outDir + 'tcprecalc.json', JSON.stringify(tcprecalc, null, ' '));
905
- fs.writeFileSync(outDir + 'actprofile.json', JSON.stringify(actprofile, null, ' '));
906
- fs.writeFileSync(outDir + 'coldmasterybreakpoints.json', JSON.stringify(coldmasterybreakpoints, null, ' '));
907
- });
908
-