返回提交历史
Modified
src/controllers/custom/getItemListsController.ts
+15
-2
Modified
src/controllers/custom/updateFingerprintController.ts
+38
-11
Modified
src/helpers/inventoryHelpers.ts
+11
-10
Modified
src/services/inventoryService.ts
+14
-12
Modified
src/services/itemDataService.ts
+286
-204
Modified
static/webui/index.html
+20
-0
Modified
static/webui/script.js
+323
-45
Modified
static/webui/translations/de.js
+43
-0
Modified
static/webui/translations/en.js
+43
-0
Modified
static/webui/translations/es.js
+43
-0
Modified
static/webui/translations/fr.js
+43
-0
Modified
static/webui/translations/ru.js
+43
-0
Modified
static/webui/translations/uk.js
+43
-0
Modified
static/webui/translations/zh.js
+43
-0
XFEstudio/XFESpaceNinjaServer
feat(webui): U5 mod editor (#3797)
Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3797 Reviewed-by: Sainan <63328889+sainan@users.noreply.github.com> Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
29a814f0
代码差异
14 个文件
+1008
-284
@@ -1,6 +1,7 @@
1
1
import type { RequestHandler } from "express";
2
import { getDict, getItemName, getNormalizedString, getString } from "../../services/itemDataService.ts";
3
import type { TRelicQuality } from "warframe-public-export-plus";
2
import { getDict, getItemName, getNormalizedString, getString, U5Modules } from "../../services/itemDataService.ts";
3
import type { IU5FingerprintUpgrade } from "../../services/itemDataService.ts";
4
import type { TRarity, TRelicQuality } from "warframe-public-export-plus";
4
5
import {
5
6
ExportAbilities,
6
7
ExportArcanes,
@@ -44,6 +45,8 @@ interface ListedItem {
44
45
maxLevelCap?: number;
45
46
eligibleForVault?: boolean;
46
47
parentName?: string;
48
fits?: { type: string; rarity: TRarity; statAtten?: number }[];
49
upgrades?: IU5FingerprintUpgrade[];
47
50
}
48
51
49
52
interface ItemLists {
@@ -581,6 +584,16 @@ const getItemListsController: RequestHandler = (req, response) => {
581
584
});
582
585
}
583
586
587
for (const [uniqueName, mod] of Object.entries(U5Modules)) {
588
res.mods.push({
589
uniqueName,
590
name: uniqueName,
591
fusionLimit: 0,
592
fits: mod.fits,
593
upgrades: mod.upgrades
594
});
595
}
596
584
597
response.json(res);
585
598
};
586
599
@@ -3,30 +3,42 @@ import type { WeaponTypeInternal } from "../../services/itemDataService.ts";
3
3
import { getAccountIdForRequest } from "../../services/loginService.ts";
4
4
import type { RequestHandler } from "express";
5
5
import { sendWsBroadcastToGame } from "../../services/wsService.ts";
6
import type { TRarity } from "warframe-public-export-plus";
6
7
7
8
export const updateFingerprintController: RequestHandler = async (req, res) => {
8
9
const accountId = await getAccountIdForRequest(req);
9
10
const request = req.body as IUpdateFingerPrintRequest;
10
11
const inventory = await getInventory(accountId, request.category);
11
const item = inventory[request.category].id(request.oid);
12
if (item) {
13
if (request.action == "set" && request.upgradeFingerprint.buffs[0].Tag) {
14
const newUpgradeFingerprint = request.upgradeFingerprint;
15
if (!newUpgradeFingerprint.compact) newUpgradeFingerprint.compact = item.ItemType;
12
if (request.category !== "Upgrades") {
13
const item = inventory[request.category].id(request.oid);
14
if (item) {
15
if (request.action == "set" && request.upgradeFingerprint.buffs[0].Tag) {
16
const newUpgradeFingerprint = request.upgradeFingerprint;
17
if (!newUpgradeFingerprint.compact) newUpgradeFingerprint.compact = item.ItemType;
16
18
17
item.UpgradeType = request.upgradeType;
19
item.UpgradeType = request.upgradeType;
20
item.UpgradeFingerprint = JSON.stringify(newUpgradeFingerprint);
21
} else if (request.action == "remove") {
22
item.UpgradeFingerprint = undefined;
23
item.UpgradeType = undefined;
24
}
25
await inventory.save();
26
}
27
} else {
28
const item = inventory.Upgrades.id(request.oid);
29
if (item) {
30
const newUpgradeFingerprint = request.upgradeFingerprint;
18
31
item.UpgradeFingerprint = JSON.stringify(newUpgradeFingerprint);
19
} else if (request.action == "remove") {
20
item.UpgradeFingerprint = undefined;
21
item.UpgradeType = undefined;
32
await inventory.save();
22
33
}
23
await inventory.save();
24
34
}
25
35
res.end();
26
36
sendWsBroadcastToGame(accountId, { sync_inventory: true });
27
37
};
28
38
29
interface IUpdateFingerPrintRequest {
39
type IUpdateFingerPrintRequest = IEquipmentRequest | IUpgradeRequest;
40
41
interface IEquipmentRequest {
30
42
category: WeaponTypeInternal;
31
43
oid: string;
32
44
action: "set" | "remove";
@@ -39,3 +51,18 @@ interface IUpdateFingerPrintRequest {
39
51
}[];
40
52
};
41
53
}
54
55
interface IUpgradeRequest {
56
category: "Upgrades";
57
oid: string;
58
action: "set";
59
upgradeFingerprint: {
60
reqLevel: number;
61
fits: string;
62
upgrades: {
63
upgrade: string;
64
valueRarity: TRarity;
65
value: number;
66
}[];
67
};
68
}
@@ -109,14 +109,12 @@ export const convertIColorToLegacyColorsWithAtt = (
109
109
export const convertFromLegacyFingerprint = (s: string): string => {
110
110
let index = 0;
111
111
112
const parseBlock = (isArrayItem = false): Record<string, unknown> | Record<string, unknown>[] => {
112
const parseBlock = (): Record<string, unknown> | Record<string, unknown>[] => {
113
113
const obj: Record<string, unknown> = {};
114
114
115
115
while (index < s.length) {
116
if (s[index] === "|") {
117
index++;
118
continue;
119
}
116
while (s[index] === "|" || s[index] === ",") index++;
117
if (index >= s.length) break;
120
118
if (s[index] === "}") {
121
119
index++;
122
120
break;
@@ -131,9 +129,12 @@ export const convertFromLegacyFingerprint = (s: string): string => {
131
129
index += 2;
132
130
const items: Record<string, unknown>[] = [];
133
131
while (index < s.length && !(s[index] === "|" && s[index + 1] === "}")) {
134
if (s[index] === "{" && s[index + 1] === "|") index += 2;
135
const item = parseBlock(true) as Record<string, unknown>;
136
items.push(item);
132
if (s[index] === "{" && s[index + 1] === "|") {
133
index += 2;
134
items.push(parseBlock() as Record<string, unknown>);
135
} else {
136
index++;
137
}
137
138
}
138
139
index += 2;
139
140
obj[key] = items;
@@ -157,7 +158,7 @@ export const convertFromLegacyFingerprint = (s: string): string => {
157
158
}
158
159
}
159
160
160
return isArrayItem ? obj : obj;
161
return obj;
161
162
};
162
163
163
164
const result = parseBlock() as Record<string, unknown>;
@@ -169,7 +170,7 @@ export const convertToLegacyFingerprint = (s: string): string => {
169
170
const obj: Record<string, unknown> = JSON.parse(s);
170
171
const serialize = (o: unknown): string => {
171
172
if (Array.isArray(o)) {
172
return o.map(item => `{|${serialize(item)}|}`).join("|");
173
return o.map(item => `{|${serialize(item)}|}`).join(",");
173
174
} else if (typeof o === "object" && o !== null) {
174
175
const parts: string[] = [];
175
176
for (const k in o as Record<string, unknown>) {
@@ -633,21 +633,23 @@ export const addItem = async (
633
633
const equipment = getRandomWeightedReward(meta.fits, U5ModsWeights)!;
634
634
const upgrades = [];
635
635
{
636
const rolledUpgrade = getRandomWeightedReward(meta.upgrades, U5ModsWeights)!;
637
const rolledRarity = getRandomWeightedReward(
638
(["COMMON", "UNCOMMON", "RARE"] as const).map(rarity => ({ rarity })),
639
U5ModsWeights
640
)!.rarity;
641
const valueRange = rolledUpgrade.ValueRanges[rolledRarity];
642
upgrades.push({
643
upgrade: rolledUpgrade.UpgradeType,
644
valueRarity: rolledRarity,
645
value: getRandomFloat(valueRange[0], valueRange[1]) * (equipment.StatAtten || 1)
646
});
636
const rolledCount = getRandomWeightedReward(meta.numUpgrades, U5ModsWeights)!.number;
637
for (let i = 0; i < rolledCount; i++) {
638
const rolledUpgrade = getRandomWeightedReward(meta.upgrades, U5ModsWeights)!;
639
const rolledRarity = getRandomWeightedReward(
640
(["COMMON", "UNCOMMON", "RARE"] as const).map(rarity => ({ rarity })),
641
U5ModsWeights
642
)!.rarity;
643
upgrades.push({
644
upgrade: rolledUpgrade.type,
645
valueRarity: rolledRarity,
646
value: getRandomFloat(0, 1)
647
});
648
}
647
649
}
648
650
targetFingerprint = JSON.stringify({
649
651
reqLevel: getRandomInt(0, 30),
650
fits: equipment.Type,
652
fits: equipment.type,
651
653
upgrades: upgrades
652
654
});
653
655
}
@@ -475,142 +475,169 @@ export const supplementalRecipes: Record<string, IRecipe> = {
475
475
};
476
476
477
477
interface IU5FingerprintData {
478
fits: { Type: string; rarity: TRarity; StatAtten?: number }[];
478
fits: { type: string; rarity: TRarity; statAtten?: number }[];
479
479
upgrades: IU5FingerprintUpgrade[];
480
numUpgrades: {
481
number: number;
482
rarity: TRarity;
483
}[];
480
484
}
481
485
482
interface IU5FingerprintUpgrade {
483
UpgradeType: string;
484
ValueRanges: Record<Exclude<TRarity, "LEGENDARY">, [number, number]>;
486
export interface IU5FingerprintUpgrade {
487
type: string;
488
valueRarity: Record<Exclude<TRarity, "LEGENDARY">, [number, number]>;
485
489
rarity: TRarity;
490
operation: "MULTIPLY" | "ADD";
491
displayAsPercent?: true;
486
492
}
487
493
488
494
const U5WeaponUpgrades: IU5FingerprintUpgrade[] = [
489
495
{
490
UpgradeType: "WEAPON_DAMAGE_AMOUNT",
491
ValueRanges: {
496
type: "WEAPON_DAMAGE_AMOUNT",
497
valueRarity: {
492
498
COMMON: [1.015, 1.15],
493
499
UNCOMMON: [1.05, 1.25],
494
500
RARE: [1.1, 1.5]
495
501
},
496
rarity: "COMMON"
502
rarity: "COMMON",
503
operation: "MULTIPLY"
497
504
},
498
505
{
499
UpgradeType: "WEAPON_FIRE_DAMAGE",
500
ValueRanges: {
501
COMMON: [0.015, 0.15000001],
502
UNCOMMON: [0.050000001, 0.25],
506
type: "WEAPON_FIRE_DAMAGE",
507
valueRarity: {
508
COMMON: [0.015, 0.15],
509
UNCOMMON: [0.05, 0.25],
503
510
RARE: [0.1, 0.5]
504
511
},
505
rarity: "RARE"
512
rarity: "RARE",
513
operation: "ADD",
514
displayAsPercent: true
506
515
},
507
516
{
508
UpgradeType: "WEAPON_ELECTRICITY_DAMAGE",
509
ValueRanges: {
510
COMMON: [0.015, 0.15000001],
511
UNCOMMON: [0.050000001, 0.25],
517
type: "WEAPON_ELECTRICITY_DAMAGE",
518
valueRarity: {
519
COMMON: [0.015, 0.15],
520
UNCOMMON: [0.05, 0.25],
512
521
RARE: [0.1, 0.5]
513
522
},
514
rarity: "COMMON"
523
rarity: "COMMON",
524
operation: "ADD",
525
displayAsPercent: true
515
526
},
516
527
{
517
UpgradeType: "WEAPON_FREEZE_DAMAGE",
518
ValueRanges: {
519
COMMON: [0.015, 0.15000001],
520
UNCOMMON: [0.050000001, 0.25],
528
type: "WEAPON_FREEZE_DAMAGE",
529
valueRarity: {
530
COMMON: [0.015, 0.15],
531
UNCOMMON: [0.05, 0.25],
521
532
RARE: [0.1, 0.5]
522
533
},
523
rarity: "COMMON"
534
rarity: "COMMON",
535
operation: "ADD",
536
displayAsPercent: true
524
537
},
525
538
{
526
UpgradeType: "WEAPON_ARMOR_PIERCING_DAMAGE",
527
ValueRanges: {
528
COMMON: [0.015, 0.15000001],
529
UNCOMMON: [0.050000001, 0.25],
539
type: "WEAPON_ARMOR_PIERCING_DAMAGE",
540
valueRarity: {
541
COMMON: [0.015, 0.15],
542
UNCOMMON: [0.05, 0.25],
530
543
RARE: [0.1, 0.5]
531
544
},
532
rarity: "COMMON"
545
rarity: "COMMON",
546
operation: "ADD",
547
displayAsPercent: true
533
548
},
534
549
{
535
UpgradeType: "WEAPON_STUN_CHANCE",
536
ValueRanges: {
550
type: "WEAPON_STUN_CHANCE",
551
valueRarity: {
537
552
COMMON: [0.025, 0.1],
538
UNCOMMON: [0.050000001, 0.2],
539
RARE: [0.1, 0.40000001]
553
UNCOMMON: [0.05, 0.2],
554
RARE: [0.1, 0.4]
540
555
},
541
rarity: "UNCOMMON"
556
rarity: "UNCOMMON",
557
operation: "ADD",
558
displayAsPercent: true
542
559
},
543
560
{
544
UpgradeType: "WEAPON_CLIP_MAX",
545
ValueRanges: {
561
type: "WEAPON_CLIP_MAX",
562
valueRarity: {
546
563
COMMON: [1.05, 1.35],
547
564
UNCOMMON: [1.1, 1.5],
548
565
RARE: [1.15, 2]
549
566
},
550
rarity: "UNCOMMON"
567
rarity: "UNCOMMON",
568
operation: "MULTIPLY"
551
569
},
552
570
{
553
UpgradeType: "WEAPON_FIRE_ITERATIONS",
554
ValueRanges: {
571
type: "WEAPON_FIRE_ITERATIONS",
572
valueRarity: {
555
573
COMMON: [1.25, 1.75],
556
574
UNCOMMON: [1.5, 2],
557
575
RARE: [2, 4]
558
576
},
559
rarity: "RARE"
577
rarity: "RARE",
578
operation: "MULTIPLY"
560
579
},
561
580
{
562
UpgradeType: "WEAPON_PUNCTURE_DEPTH",
563
ValueRanges: {
581
type: "WEAPON_PUNCTURE_DEPTH",
582
valueRarity: {
564
583
COMMON: [2, 5],
565
584
UNCOMMON: [2, 10],
566
585
RARE: [3, 15]
567
586
},
568
rarity: "RARE"
587
rarity: "RARE",
588
operation: "ADD"
569
589
},
570
590
{
571
UpgradeType: "WEAPON_AMMO_MAX",
572
ValueRanges: {
591
type: "WEAPON_AMMO_MAX",
592
valueRarity: {
573
593
COMMON: [1.05, 1.5],
574
594
UNCOMMON: [1.1, 1.75],
575
595
RARE: [1.15, 2]
576
596
},
577
rarity: "UNCOMMON"
597
rarity: "UNCOMMON",
598
operation: "MULTIPLY"
578
599
},
579
600
{
580
UpgradeType: "WEAPON_RELOAD_SPEED",
581
ValueRanges: {
601
type: "WEAPON_RELOAD_SPEED",
602
valueRarity: {
582
603
COMMON: [1.05, 1.5],
583
604
UNCOMMON: [1.075, 1.75],
584
605
RARE: [1.1, 2]
585
606
},
586
rarity: "UNCOMMON"
607
rarity: "UNCOMMON",
608
operation: "MULTIPLY"
587
609
},
588
610
{
589
UpgradeType: "WEAPON_FIRE_RATE",
590
ValueRanges: {
611
type: "WEAPON_FIRE_RATE",
612
valueRarity: {
591
613
COMMON: [1.01, 1.2],
592
614
UNCOMMON: [1.05, 1.5],
593
615
RARE: [1.1, 1.75]
594
616
},
595
rarity: "UNCOMMON"
617
rarity: "UNCOMMON",
618
operation: "MULTIPLY"
596
619
},
597
620
{
598
UpgradeType: "WEAPON_CRIT_CHANCE",
599
ValueRanges: {
621
type: "WEAPON_CRIT_CHANCE",
622
valueRarity: {
600
623
COMMON: [0.0099999998, 0.1],
601
UNCOMMON: [0.025, 0.15000001],
602
RARE: [0.050000001, 0.2]
624
UNCOMMON: [0.025, 0.15],
625
RARE: [0.05, 0.2]
603
626
},
604
rarity: "COMMON"
627
rarity: "COMMON",
628
operation: "ADD",
629
displayAsPercent: true
605
630
},
606
631
{
607
UpgradeType: "WEAPON_CRIT_DAMAGE",
608
ValueRanges: {
632
type: "WEAPON_CRIT_DAMAGE",
633
valueRarity: {
609
634
COMMON: [0.1, 0.5],
610
635
UNCOMMON: [0.2, 1],
611
RARE: [0.30000001, 1.5]
636
RARE: [0.3, 1.5]
612
637
},
613
rarity: "COMMON"
638
rarity: "COMMON",
639
operation: "ADD",
640
displayAsPercent: true
614
641
}
615
642
];
616
643
@@ -626,399 +653,454 @@ export const U5Modules: Record<string, IU5FingerprintData> = {
626
653
"/Lotus/Upgrades/Modules/Crafted/IncendiaryRifleMod": {
627
654
fits: [
628
655
{
629
Type: "/Lotus/Weapons/Tenno/Rifle/Rifle",
656
type: "/Lotus/Weapons/Tenno/Rifle/Rifle",
630
657
rarity: "COMMON"
631
658
}
632
659
],
633
660
upgrades: [
634
661
{
635
UpgradeType: "WEAPON_FIRE_DAMAGE",
636
ValueRanges: {
637
COMMON: [0.025, 0.30000001],
638
UNCOMMON: [0.050000001, 0.40000001],
639
RARE: [0.1, 0.69999999]
662
type: "WEAPON_FIRE_DAMAGE",
663
valueRarity: {
664
COMMON: [0.025, 0.3],
665
UNCOMMON: [0.05, 0.4],
666
RARE: [0.1, 0.7]
640
667
},
641
rarity: "COMMON"
668
rarity: "COMMON",
669
operation: "ADD",
670
displayAsPercent: true
642
671
}
643
]
672
],
673
numUpgrades: [{ number: 1, rarity: "COMMON" }]
644
674
},
645
675
"/Lotus/Upgrades/Modules/GrineerMeleeModule": {
646
676
fits: [
647
677
{
648
Type: "/Lotus/Weapons/Tenno/Melee/DualShortSword/DualShortSword",
678
type: "/Lotus/Weapons/Tenno/Melee/DualShortSword/DualShortSword",
649
679
rarity: "UNCOMMON"
650
680
},
651
681
{
652
Type: "/Lotus/Weapons/Tenno/Melee/LongSword/LongSword",
682
type: "/Lotus/Weapons/Tenno/Melee/LongSword/LongSword",
653
683
rarity: "UNCOMMON"
654
684
},
655
685
{
656
Type: "/Lotus/Weapons/Tenno/Melee/Staff/Staff",
686
type: "/Lotus/Weapons/Tenno/Melee/Staff/Staff",
657
687
rarity: "UNCOMMON"
658
688
},
659
689
{
660
Type: "/Lotus/Types/Game/LotusMeleeWeapon",
690
type: "/Lotus/Types/Game/LotusMeleeWeapon",
661
691
rarity: "COMMON"
662
692
},
663
693
{
664
Type: "/Lotus/Weapons/Tenno/Melee/Fist/Fist",
694
type: "/Lotus/Weapons/Tenno/Melee/Fist/Fist",
665
695
rarity: "UNCOMMON"
666
696
},
667
697
{
668
Type: "/Lotus/Weapons/Tenno/Melee/Dagger/Dagger",
698
type: "/Lotus/Weapons/Tenno/Melee/Dagger/Dagger",
669
699
rarity: "UNCOMMON"
670
700
}
671
701
],
672
702
upgrades: [
673
703
{
674
UpgradeType: "WEAPON_MELEE_DAMAGE",
675
ValueRanges: {
704
type: "WEAPON_MELEE_DAMAGE",
705
valueRarity: {
676
706
COMMON: [1.05, 1.15],
677
707
UNCOMMON: [1.075, 1.25],
678
708
RARE: [1.15, 1.5]
679
709
},
680
rarity: "COMMON"
710
rarity: "COMMON",
711
operation: "MULTIPLY"
681
712
},
682
713
{
683
UpgradeType: "WEAPON_FIRE_DAMAGE",
684
ValueRanges: {
685
COMMON: [0.050000001, 0.15000001],
686
UNCOMMON: [0.075000003, 0.25],
714
type: "WEAPON_FIRE_DAMAGE",
715
valueRarity: {
716
COMMON: [0.05, 0.15],
717
UNCOMMON: [0.075, 0.25],
687
718
RARE: [0.1, 0.5]
688
719
},
689
rarity: "RARE"
720
rarity: "RARE",
721
operation: "ADD",
722
displayAsPercent: true
690
723
},
691
724
{
692
UpgradeType: "WEAPON_ELECTRICITY_DAMAGE",
693
ValueRanges: {
694
COMMON: [0.050000001, 0.15000001],
695
UNCOMMON: [0.075000003, 0.25],
725
type: "WEAPON_ELECTRICITY_DAMAGE",
726
valueRarity: {
727
COMMON: [0.05, 0.15],
728
UNCOMMON: [0.075, 0.25],
696
729
RARE: [0.1, 0.5]
697
730
},
698
rarity: "COMMON"
731
rarity: "COMMON",
732
operation: "ADD",
733
displayAsPercent: true
699
734
},
700
735
{
701
UpgradeType: "WEAPON_FREEZE_DAMAGE",
702
ValueRanges: {
703
COMMON: [0.050000001, 0.15000001],
704
UNCOMMON: [0.075000003, 0.25],
736
type: "WEAPON_FREEZE_DAMAGE",
737
valueRarity: {
738
COMMON: [0.05, 0.15],
739
UNCOMMON: [0.075, 0.25],
705
740
RARE: [0.1, 0.5]
706
741
},
707
rarity: "COMMON"
742
rarity: "COMMON",
743
operation: "ADD",
744
displayAsPercent: true
708
745
},
709
746
{
710
UpgradeType: "WEAPON_ARMOR_PIERCING_DAMAGE",
711
ValueRanges: {
712
COMMON: [0.050000001, 0.15000001],
713
UNCOMMON: [0.075000003, 0.25],
747
type: "WEAPON_ARMOR_PIERCING_DAMAGE",
748
valueRarity: {
749
COMMON: [0.05, 0.15],
750
UNCOMMON: [0.075, 0.25],
714
751
RARE: [0.1, 0.5]
715
752
},
716
rarity: "COMMON"
753
rarity: "COMMON",
754
operation: "ADD",
755
displayAsPercent: true
717
756
},
718
757
{
719
UpgradeType: "WEAPON_STUN_CHANCE",
720
ValueRanges: {
721
COMMON: [0.050000001, 0.1],
758
type: "WEAPON_STUN_CHANCE",
759
valueRarity: {
760
COMMON: [0.05, 0.1],
722
761
UNCOMMON: [0.1, 0.2],
723
RARE: [0.2, 0.40000001]
762
RARE: [0.2, 0.4]
724
763
},
725
rarity: "UNCOMMON"
764
rarity: "UNCOMMON",
765
operation: "ADD",
766
displayAsPercent: true
726
767
},
727
768
{
728
UpgradeType: "WEAPON_CRIT_CHANCE",
729
ValueRanges: {
730
COMMON: [0.0099999998, 0.1],
731
UNCOMMON: [0.02, 0.15000001],
732
RARE: [0.050000001, 0.25]
769
type: "WEAPON_CRIT_CHANCE",
770
valueRarity: {
771
COMMON: [0.01, 0.1],
772
UNCOMMON: [0.02, 0.15],
773
RARE: [0.05, 0.25]
733
774
},
734
rarity: "COMMON"
775
rarity: "COMMON",
776
operation: "ADD",
777
displayAsPercent: true
735
778
},
736
779
{
737
UpgradeType: "WEAPON_CRIT_DAMAGE",
738
ValueRanges: {
739
COMMON: [0.050000001, 1],
780
type: "WEAPON_CRIT_DAMAGE",
781
valueRarity: {
782
COMMON: [0.05, 1],
740
783
UNCOMMON: [0.1, 1.5],
741
784
RARE: [0.2, 2]
742
785
},
743
rarity: "COMMON"
786
rarity: "COMMON",
787
operation: "ADD",
788
displayAsPercent: true
744
789
},
745
790
{
746
UpgradeType: "WEAPON_MELEE_HEAVY_DAMAGE",
747
ValueRanges: {
791
type: "WEAPON_MELEE_HEAVY_DAMAGE",
792
valueRarity: {
748
793
COMMON: [1.025, 1.25],
749
794
UNCOMMON: [1.05, 1.5],
750
795
RARE: [1.15, 1.75]
751
796
},
752
rarity: "UNCOMMON"
797
rarity: "UNCOMMON",
798
operation: "MULTIPLY"
753
799
},
754
800
{
755
UpgradeType: "WEAPON_MELEE_CHARGE_RATE",
756
ValueRanges: {
757
COMMON: [0.025, 0.30000001],
758
UNCOMMON: [0.050000001, 0.40000001],
801
type: "WEAPON_MELEE_CHARGE_RATE",
802
valueRarity: {
803
COMMON: [0.025, 0.3],
804
UNCOMMON: [0.05, 0.4],
759
805
RARE: [0.1, 0.5]
760
806
},
761
rarity: "UNCOMMON"
807
rarity: "UNCOMMON",
808
operation: "ADD",
809
displayAsPercent: true
762
810
},
763
811
{
764
UpgradeType: "WEAPON_FIRE_RATE",
765
ValueRanges: {
812
type: "WEAPON_FIRE_RATE",
813
valueRarity: {
766
814
COMMON: [1.05, 1.15],
767
815
UNCOMMON: [1.075, 1.35],
768
816
RARE: [1.1, 1.5]
769
817
},
770
rarity: "UNCOMMON"
818
rarity: "UNCOMMON",
819
operation: "MULTIPLY"
771
820
}
821
],
822
numUpgrades: [
823
{ number: 1, rarity: "COMMON" },
824
{ number: 1, rarity: "RARE" }
772
825
]
773
826
},
774
827
"/Lotus/Upgrades/Modules/GrineerPistolModule": {
775
828
fits: [
776
829
{
777
Type: "/Lotus/Weapons/Tenno/Pistol/LotusPistol",
830
type: "/Lotus/Weapons/Tenno/Pistol/LotusPistol",
778
831
rarity: "COMMON"
779
832
},
780
833
{
781
Type: "/Lotus/Weapons/Tenno/Pistol/AutoPistol",
834
type: "/Lotus/Weapons/Tenno/Pistol/AutoPistol",
782
835
rarity: "RARE"
783
836
},
784
837
{
785
Type: "/Lotus/Weapons/Tenno/Pistol/BurstPistol",
838
type: "/Lotus/Weapons/Tenno/Pistol/BurstPistol",
786
839
rarity: "UNCOMMON"
787
840
},
788
841
{
789
Type: "/Lotus/Weapons/Tenno/Pistol/CrossBow",
842
type: "/Lotus/Weapons/Tenno/Pistol/CrossBow",
790
843
rarity: "UNCOMMON"
791
844
},
792
845
{
793
Type: "/Lotus/Weapons/Tenno/Pistol/HandShotGun",
846
type: "/Lotus/Weapons/Tenno/Pistol/HandShotGun",
794
847
rarity: "UNCOMMON"
795
848
},
796
849
{
797
Type: "/Lotus/Weapons/Tenno/Pistol/Pistol",
850
type: "/Lotus/Weapons/Tenno/Pistol/Pistol",
798
851
rarity: "UNCOMMON"
799
852
}
800
853
],
801
upgrades: U5WeaponUpgrades
854
upgrades: U5WeaponUpgrades,
855
numUpgrades: [
856
{ number: 1, rarity: "COMMON" },
857
{ number: 1, rarity: "RARE" }
858
]
802
859
},
803
860
"/Lotus/Upgrades/Modules/GrineerRifleModule": {
804
861
fits: [
805
862
{
806
Type: "/Lotus/Weapons/Tenno/Rifle/LotusRifle",
863
type: "/Lotus/Weapons/Tenno/Rifle/LotusRifle",
807
864
rarity: "COMMON"
808
865
},
809
866
{
810
Type: "/Lotus/Weapons/Tenno/Rifle/BurstRifle",
867
type: "/Lotus/Weapons/Tenno/Rifle/BurstRifle",
811
868
rarity: "UNCOMMON",
812
StatAtten: 1.2
869
statAtten: 1.2
813
870
},
814
871
{
815
Type: "/Lotus/Weapons/Tenno/Rifle/SniperRifle",
872
type: "/Lotus/Weapons/Tenno/Rifle/SniperRifle",
816
873
rarity: "RARE",
817
StatAtten: 1.1
874
statAtten: 1.1
818
875
},
819
876
{
820
Type: "/Lotus/Weapons/Tenno/Rifle/HeavyRifle",
877
type: "/Lotus/Weapons/Tenno/Rifle/HeavyRifle",
821
878
rarity: "RARE",
822
StatAtten: 1.3
879
statAtten: 1.3
823
880
},
824
881
{
825
Type: "/Lotus/Weapons/Tenno/Rifle/Rifle",
882
type: "/Lotus/Weapons/Tenno/Rifle/Rifle",
826
883
rarity: "UNCOMMON",
827
StatAtten: 1.2
884
statAtten: 1.2
828
885
},
829
886
{
830
Type: "/Lotus/Weapons/Tenno/Rifle/SemiAutoRifle",
887
type: "/Lotus/Weapons/Tenno/Rifle/SemiAutoRifle",
831
888
rarity: "UNCOMMON",
832
StatAtten: 1.1
889
statAtten: 1.1
833
890
}
834
891
],
835
upgrades: U5WeaponUpgrades
892
upgrades: U5WeaponUpgrades,
893
numUpgrades: [
894
{ number: 1, rarity: "COMMON" },
895
{ number: 1, rarity: "RARE" }
896
]
836
897
},
837
898
"/Lotus/Upgrades/Modules/GrineerShotgunModule": {
838
899
fits: [
839
900
{
840
Type: "/Lotus/Weapons/Tenno/Shotgun/LotusShotgun",
901
type: "/Lotus/Weapons/Tenno/Shotgun/LotusShotgun",
841
902
rarity: "COMMON",
842
StatAtten: 1
903
statAtten: 1
843
904
},
844
905
{
845
Type: "/Lotus/Weapons/Tenno/Shotgun/Shotgun",
906
type: "/Lotus/Weapons/Tenno/Shotgun/Shotgun",
846
907
rarity: "UNCOMMON",
847
StatAtten: 1.2
908
statAtten: 1.2
848
909
},
849
910
{
850
Type: "/Lotus/Weapons/Tenno/Shotgun/FullAutoShotgun",
911
type: "/Lotus/Weapons/Tenno/Shotgun/FullAutoShotgun",
851
912
rarity: "RARE",
852
StatAtten: 1.1
913
statAtten: 1.1
853
914
}
854
915
],
855
upgrades: U5WeaponUpgrades
916
upgrades: U5WeaponUpgrades,
917
numUpgrades: [
918
{ number: 1, rarity: "COMMON" },
919
{ number: 1, rarity: "RARE" }
920
]
856
921
},
857
922
"/Lotus/Upgrades/Modules/OrokinWarframeModule": {
858
923
fits: [
859
924
{
860
Type: "/Lotus/Types/Game/PowerSuit",
925
type: "/Lotus/Types/Game/PowerSuit",
861
926
rarity: "COMMON"
862
927
},
863
928
{
864
Type: "/Lotus/Powersuits/Ember/Ember",
929
type: "/Lotus/Powersuits/Ember/Ember",
865
930
rarity: "UNCOMMON",
866
StatAtten: 1.2
931
statAtten: 1.2
867
932
},
868
933
{
869
Type: "/Lotus/Powersuits/Excalibur/Excalibur",
934
type: "/Lotus/Powersuits/Excalibur/Excalibur",
870
935
rarity: "UNCOMMON",
871
StatAtten: 1.1
936
statAtten: 1.1
872
937
},
873
938
{
874
Type: "/Lotus/Powersuits/Loki/Loki",
939
type: "/Lotus/Powersuits/Loki/Loki",
875
940
rarity: "UNCOMMON",
876
StatAtten: 1.1
941
statAtten: 1.1
877
942
},
878
943
{
879
Type: "/Lotus/Powersuits/Mag/Mag",
944
type: "/Lotus/Powersuits/Mag/Mag",
880
945
rarity: "UNCOMMON",
881
StatAtten: 1.1
946
statAtten: 1.1
882
947
},
883
948
{
884
Type: "/Lotus/Powersuits/Ninja/Ninja",
949
type: "/Lotus/Powersuits/Ninja/Ninja",
885
950
rarity: "UNCOMMON",
886
StatAtten: 1.1
951
statAtten: 1.1
887
952
},
888
953
{
889
Type: "/Lotus/Powersuits/Rhino/Rhino",
954
type: "/Lotus/Powersuits/Rhino/Rhino",
890
955
rarity: "UNCOMMON",
891
StatAtten: 1.1
956
statAtten: 1.1
892
957
},
893
958
{
894
Type: "/Lotus/Powersuits/Trinity/Trinity",
959
type: "/Lotus/Powersuits/Trinity/Trinity",
895
960
rarity: "UNCOMMON",
896
StatAtten: 1.1
961
statAtten: 1.1
897
962
},
898
963
{
899
Type: "/Lotus/Powersuits/Volt/Volt",
964
type: "/Lotus/Powersuits/Volt/Volt",
900
965
rarity: "UNCOMMON",
901
StatAtten: 1.1
966
statAtten: 1.1
902
967
}
903
968
],
904
969
upgrades: [
905
970
{
906
UpgradeType: "AVATAR_SHIELD_MAX",
907
ValueRanges: {
971
type: "AVATAR_SHIELD_MAX",
972
valueRarity: {
908
973
COMMON: [1.05, 1.4],
909
974
UNCOMMON: [1.1, 1.7],
910
975
RARE: [1.2, 2]
911
976
},
912
rarity: "COMMON"
977
rarity: "COMMON",
978
operation: "MULTIPLY"
913
979
},
914
980
{
915
UpgradeType: "AVATAR_ARMOUR",
916
ValueRanges: {
981
type: "AVATAR_ARMOUR",
982
valueRarity: {
917
983
COMMON: [1.05, 1.4],
918
984
UNCOMMON: [1.1, 1.7],
919
985
RARE: [1.2, 2]
920
986
},
921
rarity: "COMMON"
987
rarity: "COMMON",
988
operation: "MULTIPLY"
922
989
},
923
990
{
924
UpgradeType: "AVATAR_HEALTH_MAX",
925
ValueRanges: {
991
type: "AVATAR_HEALTH_MAX",
992
valueRarity: {
926
993
COMMON: [1.1, 1.4],
927
994
UNCOMMON: [1.15, 1.8],
928
995
RARE: [1.2, 2]
929
996
},
930
rarity: "UNCOMMON"
997
rarity: "UNCOMMON",
998
operation: "MULTIPLY"
931
999
},
932
1000
{
933
UpgradeType: "AVATAR_POWER_MAX",
934
ValueRanges: {
1001
type: "AVATAR_POWER_MAX",
1002
valueRarity: {
935
1003
COMMON: [1.05, 1.4],
936
1004
UNCOMMON: [1.1, 1.75],
937
1005
RARE: [1.15, 2]
938
1006
},
939
rarity: "RARE"
1007
rarity: "RARE",
1008
operation: "MULTIPLY"
940
1009
},
941
1010
{
942
UpgradeType: "AVATAR_SHIELD_RECHARGE_RATE",
943
ValueRanges: {
1011
type: "AVATAR_SHIELD_RECHARGE_RATE",
1012
valueRarity: {
944
1013
COMMON: [1.05, 1.4],
945
1014
UNCOMMON: [1.1, 1.75],
946
1015
RARE: [1.15, 2]
947
1016
},
948
rarity: "UNCOMMON"
1017
rarity: "UNCOMMON",
1018
operation: "MULTIPLY"
949
1019
},
950
1020
{
951
UpgradeType: "WEAPON_MELEE_DAMAGE",
952
ValueRanges: {
1021
type: "WEAPON_MELEE_DAMAGE",
1022
valueRarity: {
953
1023
COMMON: [1.05, 1.4],
954
1024
UNCOMMON: [1.1, 1.75],
955
1025
RARE: [1.15, 2]
956
1026
},
957
rarity: "UNCOMMON"
1027
rarity: "UNCOMMON",
1028
operation: "MULTIPLY"
958
1029
},
959
1030
{
960
UpgradeType: "AVATAR_SPRINT_SPEED",
961
ValueRanges: {
1031
type: "AVATAR_SPRINT_SPEED",
1032
valueRarity: {
962
1033
COMMON: [1.03, 1.1],
963
1034
UNCOMMON: [1.05, 1.25],
964
1035
RARE: [1.1, 1.35]
965
1036
},
966
rarity: "UNCOMMON"
1037
rarity: "UNCOMMON",
1038
operation: "MULTIPLY"
967
1039
},
968
1040
{
969
UpgradeType: "AVATAR_ENEMY_RADAR",
970
ValueRanges: {
1041
type: "AVATAR_ENEMY_RADAR",
1042
valueRarity: {
971
1043
COMMON: [15, 20],
972
1044
UNCOMMON: [20, 40],
973
1045
RARE: [25, 60]
974
1046
},
975
rarity: "RARE"
1047
rarity: "RARE",
1048
operation: "ADD"
976
1049
},
977
1050
{
978
UpgradeType: "AVATAR_LOOT_RADAR",
979
ValueRanges: {
1051
type: "AVATAR_LOOT_RADAR",
1052
valueRarity: {
980
1053
COMMON: [15, 20],
981
1054
UNCOMMON: [20, 40],
982
1055
RARE: [25, 60]
983
1056
},
984
rarity: "UNCOMMON"
1057
rarity: "UNCOMMON",
1058
operation: "ADD"
985
1059
},
986
1060
{
987
UpgradeType: "AVATAR_ABILITY_RANGE",
988
ValueRanges: {
1061
type: "AVATAR_ABILITY_RANGE",
1062
valueRarity: {
989
1063
COMMON: [1.05, 1.4],
990
1064
UNCOMMON: [1.1, 1.5],
991
1065
RARE: [1.15, 1.8]
992
1066
},
993
rarity: "UNCOMMON"
1067
rarity: "UNCOMMON",
1068
operation: "MULTIPLY"
994
1069
},
995
1070
{
996
UpgradeType: "AVATAR_ABILITY_DURATION",
997
ValueRanges: {
1071
type: "AVATAR_ABILITY_DURATION",
1072
valueRarity: {
998
1073
COMMON: [1.02, 1.3],
999
1074
UNCOMMON: [1.05, 1.4],
1000
1075
RARE: [1.05, 1.5]
1001
1076
},
1002
rarity: "RARE"
1077
rarity: "RARE",
1078
operation: "MULTIPLY"
1003
1079
},
1004
1080
{
1005
UpgradeType: "AVATAR_ABILITY_EFFICIENCY",
1006
ValueRanges: {
1081
type: "AVATAR_ABILITY_EFFICIENCY",
1082
valueRarity: {
1007
1083
COMMON: [1.03, 1.3],
1008
1084
UNCOMMON: [1.05, 1.5],
1009
1085
RARE: [1.1, 1.7]
1010
1086
},
1011
rarity: "RARE"
1087
rarity: "RARE",
1088
operation: "MULTIPLY"
1012
1089
},
1013
1090
{
1014
UpgradeType: "AVATAR_ABILITY_STRENGTH",
1015
ValueRanges: {
1091
type: "AVATAR_ABILITY_STRENGTH",
1092
valueRarity: {
1016
1093
COMMON: [1.03, 1.4],
1017
1094
UNCOMMON: [1.05, 1.5],
1018
1095
RARE: [1.1, 1.7]
1019
1096
},
1020
rarity: "RARE"
1097
rarity: "RARE",
1098
operation: "MULTIPLY"
1021
1099
}
1100
],
1101
numUpgrades: [
1102
{ number: 1, rarity: "COMMON" },
1103
{ number: 1, rarity: "RARE" }
1022
1104
]
1023
1105
}
1024
1106
};
@@ -846,6 +846,26 @@
846
846
<h5 class="card-header" data-loc="detailedView_equipmentFeaturesLabel"></h5>
847
847
<div id="equipmentFeaturesButtons-card" class="card-body d-flex flex-wrap gap-2"></div>
848
848
</div>
849
<div id="u5ModEdit-card" class="card mb-3 d-none">
850
<h5 class="card-header" data-loc="detailedView_u5ModEditLabel"></h5>
851
<div class="card-body">
852
<p id="u5ModEdit-Description" data-loc="detailedView_u5ModEditDescription"></p>
853
<form class="mb-3" onsubmit="handleU5ModEdit(event)">
854
<div class="d-flex gap-2 align-items-end">
855
<div class="mb-2">
856
<label for="u5ModEdit-fits" class="form-label" data-loc="detailedView_u5ModEditFits"></label>
857
<select id="u5ModEdit-fits" class="form-control"></select>
858
</div>
859
<div class="mb-2">
860
<label for="u5ModEdit-reqLevel" class="form-label" data-loc="detailedView_u5ModEditReqLevel"></label>
861
<input type="number" id="u5ModEdit-reqLevel" min="0" max="30" step="1" class="form-control" style="max-width:100px" />
862
</div>
863
</div>
864
<div id="u5ModEdit-upgradeFields" class="mb-2"></div>
865
<button class="btn btn-primary" type="submit" value="set" data-loc="general_setButton"></button>
866
</form>
867
</div>
868
</div>
849
869
</div>
850
870
<div data-route="/webui/mods" data-title-tag="navbar_mods">
851
871
<p class="mb-3 inventory-update-note"></p>
@@ -692,36 +692,6 @@ function fetchItemList() {
692
692
{
693
693
uniqueName: "/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod",
694
694
name: loc("code_traumaticPeculiar")
695
},
696
{
697
uniqueName: "/Lotus/Upgrades/Modules/GrineerMeleeModule",
698
name: loc("code_U5Mod").replace("|TYPE|", loc("code_melee")),
699
fusionLimit: 0
700
},
701
{
702
uniqueName: "/Lotus/Upgrades/Modules/GrineerPistolModule",
703
name: loc("code_U5Mod").replace("|TYPE|", loc("code_pistol")),
704
fusionLimit: 0
705
},
706
{
707
uniqueName: "/Lotus/Upgrades/Modules/GrineerRifleModule",
708
name: loc("code_U5Mod").replace("|TYPE|", loc("code_rifle")),
709
fusionLimit: 0
710
},
711
{
712
uniqueName: "/Lotus/Upgrades/Modules/GrineerShotgunModule",
713
name: loc("code_U5Mod").replace("|TYPE|", loc("code_shotgun")),
714
fusionLimit: 0
715
},
716
{
717
uniqueName: "/Lotus/Upgrades/Modules/OrokinWarframeModule",
718
name: loc("code_U5Mod").replace("|TYPE|", loc("code_warframe")),
719
fusionLimit: 0
720
},
721
{
722
uniqueName: "/Lotus/Upgrades/Modules/Crafted/IncendiaryRifleMod",
723
name: loc("code_infernoMod"),
724
fusionLimit: 0
725
695
}
726
696
);
727
697
@@ -991,7 +961,9 @@ function fetchItemList() {
991
961
"/Lotus/Language/Game/Rank_Utility": {
992
962
name: loc("guildView_rank_utility")
993
963
},
994
"/Lotus/Types/Game/PowerSuit": { name: loc("code_warframe") }
964
// U5
965
"/Lotus/Types/Game/PowerSuit": { name: loc("code_warframe") },
966
"/Lotus/Types/Game/LotusMeleeWeapon": { name: loc("code_melee") }
995
967
};
996
968
for (const [type, items] of Object.entries(data)) {
997
969
if (type == "archonCrystalUpgrades") {
@@ -1086,8 +1058,36 @@ function fetchItemList() {
1086
1058
const nameToItems = {};
1087
1059
items.forEach(item => {
1088
1060
item.name = item.name.replace(/<.+>/g, "").trim();
1089
if (item.name == "/Lotus/Language/Suits/RiftWalkAbilityName") {
1090
item.name = loc("code_RiftWalkAbilityName");
1061
const nameMap = {
1062
"/Lotus/Language/Suits/RiftWalkAbilityName": loc("code_RiftWalkAbilityName"),
1063
"/Lotus/Upgrades/Modules/GrineerMeleeModule": loc("code_U5Mod").replace(
1064
"|TYPE|",
1065
loc("code_melee")
1066
),
1067
1068
"/Lotus/Upgrades/Modules/GrineerPistolModule": loc("code_U5Mod").replace(
1069
"|TYPE|",
1070
loc("code_pistol")
1071
),
1072
1073
"/Lotus/Upgrades/Modules/GrineerRifleModule": loc("code_U5Mod").replace(
1074
"|TYPE|",
1075
loc("code_rifle")
1076
),
1077
1078
"/Lotus/Upgrades/Modules/GrineerShotgunModule": loc("code_U5Mod").replace(
1079
"|TYPE|",
1080
loc("code_shotgun")
1081
),
1082
1083
"/Lotus/Upgrades/Modules/OrokinWarframeModule": loc("code_U5Mod").replace(
1084
"|TYPE|",
1085
loc("code_warframe")
1086
),
1087
"/Lotus/Upgrades/Modules/Crafted/IncendiaryRifleMod": loc("code_infernoMod")
1088
};
1089
if (nameMap[item.name]) {
1090
item.name = nameMap[item.name];
1091
1091
}
1092
1092
if ("badReason" in item) {
1093
1093
if (item.badReason == "starter") {
@@ -1226,6 +1226,15 @@ function translateInventoryDataToDom() {
1226
1226
"/Lotus/Types/Friendly/Pets/CreaturePets/MedjayPredatorKubrowPetPowerSuit"
1227
1227
];
1228
1228
1229
const U5Mods = [
1230
"/Lotus/Upgrades/Modules/GrineerMeleeModule",
1231
"/Lotus/Upgrades/Modules/GrineerPistolModule",
1232
"/Lotus/Upgrades/Modules/GrineerRifleModule",
1233
"/Lotus/Upgrades/Modules/GrineerShotgunModule",
1234
"/Lotus/Upgrades/Modules/OrokinWarframeModule",
1235
"/Lotus/Upgrades/Modules/Crafted/IncendiaryRifleMod"
1236
];
1237
1229
1238
// Populate inventory route
1230
1239
1231
1240
document.getElementById("typeName-tab").classList.remove("active");
@@ -1866,13 +1875,8 @@ function translateInventoryDataToDom() {
1866
1875
const td = document.createElement("td");
1867
1876
td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
1868
1877
if (
1869
[
1870
"/Lotus/Upgrades/Modules/GrineerMeleeModule",
1871
"/Lotus/Upgrades/Modules/GrineerPistolModule",
1872
"/Lotus/Upgrades/Modules/GrineerRifleModule",
1873
"/Lotus/Upgrades/Modules/GrineerShotgunModule",
1874
"/Lotus/Upgrades/Modules/OrokinWarframeModule"
1875
].includes(item.ItemType)
1878
U5Mods.includes(item.ItemType) &&
1879
item.ItemType != "/Lotus/Upgrades/Modules/Crafted/IncendiaryRifleMod"
1876
1880
) {
1877
1881
if (item.UpgradeFingerprint) {
1878
1882
const fingerprint = JSON.parse(item.UpgradeFingerprint);
@@ -1905,6 +1909,12 @@ function translateInventoryDataToDom() {
1905
1909
a.innerHTML = icons.arrowUp;
1906
1910
td.appendChild(a);
1907
1911
}
1912
if (U5Mods.includes(item.ItemType)) {
1913
const a = document.createElement("a");
1914
a.href = "/webui/detailedView?productCategory=Upgrades&itemId=" + item.ItemId.$oid;
1915
a.innerHTML = icons.feather;
1916
td.appendChild(a);
1917
}
1908
1918
{
1909
1919
const a = document.createElement("a");
1910
1920
a.href = "#";
@@ -1991,7 +2001,7 @@ function translateInventoryDataToDom() {
1991
2001
$("#detailedView-title").text(itemName);
1992
2002
}
1993
2003
1994
{
2004
if (category != "Upgrades") {
1995
2005
document.getElementById("equipmentFeatures-card").classList.remove("d-none");
1996
2006
const buttonsCard = document.getElementById("equipmentFeaturesButtons-card");
1997
2007
buttonsCard.innerHTML = "";
@@ -2239,11 +2249,46 @@ function translateInventoryDataToDom() {
2239
2249
2240
2250
if (item.UpgradeFingerprint) {
2241
2251
const buff = JSON.parse(item.UpgradeFingerprint).buffs[0];
2242
const buffValue = fromUpdradeFingerPrintVaule(buff.Value, 0.25);
2252
const buffValue = fromUpgradeFingerprintValue(buff.Value, 0.25);
2243
2253
document.getElementById("valenceBonus-innateDamage").value = buff.Tag ?? "";
2244
2254
document.getElementById("valenceBonus-procent").value = Math.round(buffValue * 1000) / 10;
2245
2255
}
2246
2256
}
2257
if (U5Mods.includes(item.ItemType)) {
2258
document.getElementById("u5ModEdit-card").classList.remove("d-none");
2259
const oldFitsSelect = document.getElementById("u5ModEdit-fits");
2260
const fitsSelect = oldFitsSelect.cloneNode(false);
2261
oldFitsSelect.parentNode.replaceChild(fitsSelect, oldFitsSelect);
2262
const upgradeFields = document.getElementById("u5ModEdit-upgradeFields");
2263
upgradeFields.innerHTML = "";
2264
const fits = itemMap[item.ItemType].fits;
2265
const fp = JSON.parse(item.UpgradeFingerprint);
2266
const statAtten = fits.find(fit => fit.type == fp.fits).statAtten || 1;
2267
2268
fits.forEach(fit => {
2269
const option = document.createElement("option");
2270
option.value = fit.type;
2271
option.textContent =
2272
(itemMap[fit.type]?.name ?? fit.type) +
2273
(fit.statAtten ? ` (${loc("code_statAtten")}: ${fit.statAtten || 1})` : "");
2274
fitsSelect.appendChild(option);
2275
});
2276
2277
fitsSelect.addEventListener("change", () => {
2278
upgradeFields.querySelectorAll(".upgrade-group").forEach(group => {
2279
updateUpgradeInput(itemMap[item.ItemType], group);
2280
});
2281
});
2282
2283
upgradeFields.setAttribute("data-stat-atten", statAtten);
2284
document.getElementById("u5ModEdit-reqLevel").value = fp.reqLevel ?? 0;
2285
document.getElementById("u5ModEdit-fits").value = fp.fits ?? fits[0].type;
2286
2287
fp.upgrades.forEach(up => {
2288
createUpgradeInput(upgradeFields, itemMap, item.ItemType, up);
2289
});
2290
createUpgradeInput(upgradeFields, itemMap, item.ItemType, null);
2291
}
2247
2292
if (modularWeapons.includes(item.ItemType)) {
2248
2293
document.getElementById("modularParts-card").classList.remove("d-none");
2249
2294
const form = document.getElementById("modularParts-form");
@@ -4307,6 +4352,7 @@ single.getRoute("#detailedView-route").on("beforeload", function () {
4307
4352
document.getElementById("modularParts-card").classList.add("d-none");
4308
4353
document.getElementById("modularParts-form").innerHTML = "";
4309
4354
document.getElementById("valenceBonus-card").classList.add("d-none");
4355
document.getElementById("u5ModEdit-card").classList.add("d-none");
4310
4356
document.getElementById("equipmentFeatures-card").classList.add("d-none");
4311
4357
document.getElementById("equipmentFeaturesButtons-card").innerHTML = "";
4312
4358
if (window.didInitialInventoryUpdate) {
@@ -5046,22 +5092,32 @@ document.querySelectorAll(".tags-input").forEach(input => {
5046
5092
input.oninput();
5047
5093
});
5048
5094
5049
function fromUpdradeFingerPrintVaule(raw, min) {
5095
function fromUpgradeFingerprintValue(raw, min) {
5050
5096
const range = 0.6 - min;
5051
5097
return min + (raw * range) / 0x3fffffff;
5052
5098
}
5053
5099
5054
function toUpdradeFingerPrintVaule(value, min) {
5100
function toUpgradeFingerprintValue(value, min) {
5055
5101
const range = 0.6 - min;
5056
5102
return Math.trunc(((value - min) * 0x3fffffff) / range);
5057
5103
}
5058
5104
5105
function fromU5UpgradeFingerprintValue(raw, min, max) {
5106
const range = max - min;
5107
return min + range * raw;
5108
}
5109
5110
function toU5UpgradeFingerprintValue(value, min, max) {
5111
const range = max - min;
5112
return (value - min) / range;
5113
}
5114
5059
5115
function handleValenceBonusChange(event) {
5060
5116
event.preventDefault();
5061
5117
const urlParams = new URLSearchParams(window.location.search);
5062
5118
const action = event.submitter.value;
5063
5119
const Tag = document.getElementById("valenceBonus-innateDamage").value;
5064
const Value = toUpdradeFingerPrintVaule(document.getElementById("valenceBonus-procent").value / 100, 0.25);
5120
const Value = toUpgradeFingerprintValue(document.getElementById("valenceBonus-procent").value / 100, 0.25);
5065
5121
revalidateAuthz().then(() => {
5066
5122
$.post({
5067
5123
url: "/custom/updateFingerprint?" + window.authz,
@@ -5086,6 +5142,228 @@ function handleValenceBonusChange(event) {
5086
5142
});
5087
5143
}
5088
5144
5145
function handleU5ModEdit(event) {
5146
event.preventDefault();
5147
const urlParams = new URLSearchParams(window.location.search);
5148
const action = event.submitter.value;
5149
revalidateAuthz().then(() => {
5150
const upgradeFields = document.getElementById("u5ModEdit-upgradeFields");
5151
const upgradeGroups = Array.from(upgradeFields.children);
5152
const upgrades = upgradeGroups
5153
.map(group => {
5154
const upgradeSelect = group.querySelector("#u5ModEdit-upgradeType");
5155
const raritySelect = group.querySelector("#u5ModEdit-upgradeRarity");
5156
const valueInput = group.querySelector("#u5ModEdit-upgradeValue");
5157
const statAtten = parseFloat(group.parentNode.getAttribute("data-stat-atten"));
5158
const value =
5159
valueInput.valueAsNumber == valueInput.min
5160
? valueInput.valueAsNumber + 0.001
5161
: valueInput.valueAsNumber;
5162
return {
5163
upgrade: upgradeSelect.value,
5164
valueRarity: raritySelect.value,
5165
value: Math.min(
5166
toU5UpgradeFingerprintValue(
5167
value / statAtten,
5168
valueInput.min / statAtten,
5169
valueInput.max / statAtten
5170
),
5171
1
5172
)
5173
};
5174
})
5175
.filter(item => {
5176
return item.upgrade != "" && item.value != 0;
5177
});
5178
$.post({
5179
url: "/custom/updateFingerprint?" + window.authz,
5180
contentType: "application/json",
5181
data: JSON.stringify({
5182
category: urlParams.get("productCategory"),
5183
oid: urlParams.get("itemId"),
5184
action,
5185
upgradeFingerprint: {
5186
reqLevel: Number(document.getElementById("u5ModEdit-reqLevel").value),
5187
fits: document.getElementById("u5ModEdit-fits").value,
5188
upgrades
5189
}
5190
})
5191
}).done(function () {
5192
updateInventory();
5193
});
5194
});
5195
}
5196
5197
function createUpgradeInput(targetDiv, itemMap, itemType, upgrade) {
5198
const meta = itemMap[itemType];
5199
const statAtten = targetDiv.getAttribute("data-stat-atten") || 1;
5200
5201
const group = document.createElement("div");
5202
group.classList.add("upgrade-group", "mb-2", "d-flex", "gap-2");
5203
5204
{
5205
const select = document.createElement("select");
5206
select.classList.add("form-control");
5207
select.id = "u5ModEdit-upgradeType";
5208
const optionNone = document.createElement("option");
5209
select.appendChild(optionNone);
5210
meta.upgrades.forEach(up => {
5211
const option = document.createElement("option");
5212
option.value = up.type;
5213
const locType =
5214
itemType.endsWith("GrineerMeleeModule") && up.type == "WEAPON_FIRE_RATE"
5215
? "WEAPON_MELEE_FIRE_RATE"
5216
: up.type;
5217
option.textContent = loc(locType);
5218
select.appendChild(option);
5219
});
5220
if (upgrade) {
5221
select.value = upgrade.upgrade;
5222
}
5223
select.addEventListener("change", () => {
5224
updateUpgradeInput(meta, group);
5225
checkAddOrDeleteUpgradeInput(itemMap, itemType);
5226
});
5227
group.appendChild(select);
5228
}
5229
{
5230
const select = document.createElement("select");
5231
select.classList.add("form-control");
5232
select.id = "u5ModEdit-upgradeRarity";
5233
["COMMON", "UNCOMMON", "RARE"].forEach(rarity => {
5234
const option = document.createElement("option");
5235
option.value = rarity;
5236
const locKey = "code_rarity" + rarity.charAt(0) + rarity.slice(1).toLowerCase();
5237
option.textContent = loc(locKey);
5238
option.setAttribute("data-loc", locKey);
5239
select.appendChild(option);
5240
});
5241
if (upgrade) {
5242
select.value = upgrade.valueRarity ?? "COMMON";
5243
} else {
5244
select.value = "COMMON";
5245
}
5246
select.addEventListener("change", () => updateUpgradeInput(meta, group));
5247
group.appendChild(select);
5248
}
5249
{
5250
let valueRange = [0, 0];
5251
let upgradeValue = 0;
5252
let displayAsPercent = undefined;
5253
if (upgrade) {
5254
// U5.1 client just igrone Rare value ranges
5255
const targetValueRarity = upgrade.valueRarity == "RARE" ? "UNCOMMON" : upgrade.valueRarity;
5256
const upgradeMeta = meta.upgrades.find(up => up.type == upgrade.upgrade);
5257
valueRange = [...(upgradeMeta.valueRarity[targetValueRarity] || [0, 0])];
5258
const operation = upgradeMeta.operation;
5259
displayAsPercent = upgradeMeta.displayAsPercent || operation == "MULTIPLY";
5260
if (displayAsPercent) {
5261
valueRange[0] = valueRange[0] * 100 - (operation == "MULTIPLY" ? 100 : 0);
5262
valueRange[1] = valueRange[1] * 100 - (operation == "MULTIPLY" ? 100 : 0);
5263
}
5264
upgradeValue = +(
5265
fromU5UpgradeFingerprintValue(upgrade.value, valueRange[0], valueRange[1]) * statAtten
5266
).toFixed(1);
5267
}
5268
5269
const inputGroup = document.createElement("div");
5270
inputGroup.classList.add("input-group", "d-flex", "flex-shrink-0");
5271
inputGroup.style.flexBasis = "200px";
5272
5273
const input = document.createElement("input");
5274
input.type = "number";
5275
input.classList.add("form-control");
5276
input.step = "0.1";
5277
input.id = "u5ModEdit-upgradeValue";
5278
input.min = valueRange[0] ? +(valueRange[0] * statAtten).toFixed(1) : 0;
5279
input.max = valueRange[1] ? +(valueRange[1] * statAtten).toFixed(1) : 0;
5280
input.value = upgradeValue;
5281
input.title = loc("code_range").replace("|MIN|", input.min).replace("|MAX|", input.max);
5282
5283
const rangePrefix = document.createElement("span");
5284
rangePrefix.textContent = "+";
5285
rangePrefix.classList.add("input-group-text");
5286
5287
const rangeSuffix = document.createElement("span");
5288
rangeSuffix.classList.add("input-group-text");
5289
rangeSuffix.id = "u5ModEdit-upgradeValueSuffix";
5290
rangeSuffix.textContent = displayAsPercent ? "%" : loc("code_metersShort");
5291
5292
inputGroup.appendChild(rangePrefix);
5293
inputGroup.appendChild(input);
5294
5295
if (displayAsPercent != undefined) {
5296
inputGroup.appendChild(rangeSuffix);
5297
}
5298
5299
group.appendChild(inputGroup);
5300
}
5301
targetDiv.appendChild(group);
5302
}
5303
5304
function updateUpgradeInput(meta, group) {
5305
const fitsSelect = document.getElementById("u5ModEdit-fits");
5306
const fit = meta.fits.find(f => f.type == fitsSelect.value);
5307
const statAtten = fit?.statAtten || 1;
5308
5309
const upgradeSelect = group.querySelector("#u5ModEdit-upgradeType");
5310
const raritySelect = group.querySelector("#u5ModEdit-upgradeRarity");
5311
const input = group.querySelector("#u5ModEdit-upgradeValue");
5312
let rangeSuffix = group.querySelector("#u5ModEdit-upgradeValueSuffix");
5313
5314
const upgradeMeta = meta.upgrades.find(up => up.type == upgradeSelect.value);
5315
const targetValueRarity = raritySelect.value == "RARE" ? "UNCOMMON" : raritySelect.value;
5316
let valueRange = [...(upgradeMeta?.valueRarity[targetValueRarity] || [0, 0])];
5317
const operation = upgradeMeta?.operation;
5318
const displayAsPercent = upgradeMeta?.displayAsPercent || operation == "MULTIPLY";
5319
if (displayAsPercent) {
5320
valueRange[0] = valueRange[0] * 100 - (operation == "MULTIPLY" ? 100 : 0);
5321
valueRange[1] = valueRange[1] * 100 - (operation == "MULTIPLY" ? 100 : 0);
5322
}
5323
if (upgradeMeta && !rangeSuffix) {
5324
rangeSuffix = document.createElement("span");
5325
rangeSuffix.classList.add("input-group-text");
5326
rangeSuffix.id = "u5ModEdit-upgradeValueSuffix";
5327
input.parentNode.appendChild(rangeSuffix);
5328
}
5329
if (rangeSuffix) rangeSuffix.textContent = displayAsPercent ? "%" : "m";
5330
5331
const oldstatAtten = parseFloat(group.parentNode.getAttribute("data-stat-atten")) || 1;
5332
const oldUpgradeValue = toU5UpgradeFingerprintValue(
5333
input.valueAsNumber / oldstatAtten,
5334
input.min / oldstatAtten,
5335
input.max / oldstatAtten
5336
);
5337
5338
input.min = valueRange[0] ? +(valueRange[0] * statAtten).toFixed(1) : 0;
5339
input.max = valueRange[1] ? +(valueRange[1] * statAtten).toFixed(1) : 0;
5340
input.title = loc("code_range").replace("|MIN|", input.min).replace("|MAX|", input.max);
5341
group.parentNode.setAttribute("data-stat-atten", statAtten);
5342
5343
input.value =
5344
+(fromU5UpgradeFingerprintValue(oldUpgradeValue, valueRange[0], valueRange[1]) * statAtten).toFixed(1) ||
5345
input.max;
5346
if (input.value < input.min) input.value = input.min;
5347
}
5348
5349
function checkAddOrDeleteUpgradeInput(itemMap, itemType) {
5350
const upgradeFields = document.getElementById("u5ModEdit-upgradeFields");
5351
const upgradeGroups = Array.from(upgradeFields.children);
5352
5353
upgradeGroups.forEach((group, index) => {
5354
const upgradeSelect = group.querySelector("#u5ModEdit-upgradeType");
5355
if (!upgradeSelect.value && index !== upgradeGroups.length - 1) {
5356
upgradeFields.removeChild(group);
5357
}
5358
});
5359
5360
const lastUpgradeSelect = upgradeGroups[upgradeGroups.length - 1].querySelector("#u5ModEdit-upgradeType");
5361
5362
if (lastUpgradeSelect.value) {
5363
createUpgradeInput(upgradeFields, itemMap, itemType, null);
5364
}
5365
}
5366
5089
5367
document.querySelectorAll("#sidebar .nav-link").forEach(function (elm) {
5090
5368
elm.addEventListener("click", function () {
5091
5369
window.scrollTo(0, 0);