XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 0 Star 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
AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
提交于

代码差异

14 个文件 +1008 -284
Modified src/controllers/custom/getItemListsController.ts +15 -2
@@ -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
Modified src/controllers/custom/updateFingerprintController.ts +38 -11
@@ -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 }
Modified src/helpers/inventoryHelpers.ts +11 -10
@@ -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>) {
Modified src/services/inventoryService.ts +14 -12
@@ -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 }
Modified src/services/itemDataService.ts +286 -204
@@ -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 };
Modified static/webui/index.html +20 -0
@@ -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>
Modified static/webui/script.js +323 -45
@@ -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);
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