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

XFESpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 0 Star 0
UTF-8
import { fromOid, toOid2, version_compare } from "../../helpers/inventoryHelpers.ts";
import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "../../helpers/rivenHelper.ts";
import {
    addFusionPoints,
    addMiscItems,
    addMods,
    getInventory2,
    updateCredits
} from "../../services/inventoryService.ts";
import { getUpgrade } from "../../services/itemDataService.ts";
import { getAccountForRequest, getBuildLabel } from "../../services/loginService.ts";
import { getRandomElement, getRandomWeightedRewardUc } from "../../services/rngService.ts";
import type { IUpgradeFromClient } from "../../types/inventoryTypes/inventoryTypes.ts";
import type { RequestHandler } from "express";
import type { TRarity } from "warframe-public-export-plus";
import { ExportBoosterPacks, ExportUpgrades } from "warframe-public-export-plus";
import { logger } from "../../utils/logger.ts";

export const artifactTransmutationController: RequestHandler = async (req, res) => {
    const account = await getAccountForRequest(req);
    const buildLabel = getBuildLabel(req, account);
    const inventory = await getInventory2(
        account._id,
        "infiniteCredits",
        "RegularCredits",
        "infiniteEndo",
        "FusionPoints",
        "MiscItems",
        "Upgrades",
        "RawUpgrades"
    );
    const payload = JSON.parse(String(req.body)) as IArtifactTransmutationRequest;

    updateCredits(inventory, payload.Cost);
    if (payload.FusionPointCost) {
        addFusionPoints(inventory, -payload.FusionPointCost);
    }

    if (payload.RivenTransmute) {
        addMiscItems(inventory, [
            {
                ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientSecretItem",
                ItemCount: -1
            }
        ]);

        for (const upgrade of payload.Consumed) {
            inventory.Upgrades.pull({ _id: fromOid(upgrade.ItemId) });
        }

        const rawRivenType = getRandomRawRivenType();
        const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType])!;
        const IsSentinel =
            rawRivenType == "/Lotus/Upgrades/Mods/Randomized/RawSentinelWeaponRandomMod" ? true : undefined;
        const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType], IsSentinel);

        const upgradeIndex =
            inventory.Upgrades.push({
                ItemType: rivenType,
                UpgradeFingerprint: JSON.stringify(fingerprint)
            }) - 1;
        await inventory.save();

        res.json({
            NewMods: [
                {
                    ItemId: toOid2(inventory.Upgrades[upgradeIndex]._id, buildLabel),
                    ItemType: rivenType,
                    UpgradeFingerprint: fingerprint
                }
            ]
        });
    } else {
        const counts: Record<TRarity, number> = {
            COMMON: 0,
            UNCOMMON: 0,
            RARE: 0,
            LEGENDARY: 0
        };
        let forcedPolarity: string | undefined;
        payload.Consumed.forEach(upgrade => {
            upgrade.ItemCount ??= 1;
            const meta = getUpgrade(upgrade.ItemType)!;
            counts[meta.rarity] += upgrade.ItemCount;
            if (fromOid(upgrade.ItemId) != "" && fromOid(upgrade.ItemId) != "000000000000000000000000") {
                inventory.Upgrades.pull({ _id: fromOid(upgrade.ItemId) });
            } else {
                addMods(inventory, [
                    {
                        ItemType: upgrade.ItemType,
                        ItemCount: upgrade.ItemCount * -1
                    }
                ]);
            }
            if (upgrade.ItemType == "/Lotus/Upgrades/Mods/TransmuteCores/AttackTransmuteCore") {
                forcedPolarity = "AP_ATTACK";
            } else if (upgrade.ItemType == "/Lotus/Upgrades/Mods/TransmuteCores/DefenseTransmuteCore") {
                forcedPolarity = "AP_DEFENSE";
            } else if (upgrade.ItemType == "/Lotus/Upgrades/Mods/TransmuteCores/TacticTransmuteCore") {
                forcedPolarity = "AP_TACTIC";
            }
        });

        let newModType: string | undefined;
        for (const specialModSet of specialModSets) {
            if (specialModSet.indexOf(payload.Consumed[0].ItemType) != -1) {
                newModType = getRandomElement(specialModSet);
                break;
            }
        }

        if (!newModType) {
            // Based on the table on https://wiki.warframe.com/w/Transmutation
            const weights: Record<TRarity, number> = {
                COMMON: counts.COMMON * 95 + counts.UNCOMMON * 15 + counts.RARE * 4,
                UNCOMMON: counts.COMMON * 4 + counts.UNCOMMON * 80 + counts.RARE * 10,
                RARE: counts.COMMON * 1 + counts.UNCOMMON * 5 + counts.RARE * 50,
                LEGENDARY: 0
            };

            const options = ExportBoosterPacks["/Lotus/Types/BoosterPacks/ModFuserResult"].components.filter(
                ({ Item }) => {
                    // When changing this logic, please ensure the self-test below stays useful.
                    const meta = getUpgrade(Item)!;
                    if ((forcedPolarity && meta.polarity != forcedPolarity) || !meta.introducedAt) {
                        return false;
                    }
                    const date = new Date(meta.introducedAt * 1000);
                    return (
                        version_compare(
                            buildLabel,
                            `${date.getUTCFullYear()}.${date.getUTCMonth()}.${date.getUTCDate()}.${date.getUTCHours()}.${date.getUTCMinutes()}`
                        ) >= 0
                    );
                }
            );
            newModType = getRandomWeightedRewardUc(options, weights)!.Item;
        }

        addMods(inventory, [
            {
                ItemType: newModType,
                ItemCount: 1
            }
        ]);

        await inventory.save();
        res.json({
            NewMods: [
                {
                    ItemType: newModType,
                    ItemCount: 1
                }
            ]
        });
    }
};

const getRandomRawRivenType = (): string => {
    const pack = ExportBoosterPacks["/Lotus/Types/BoosterPacks/CalendarRivenPack"];
    return getRandomWeightedRewardUc(pack.components, pack.rarityWeightsPerRoll[0])!.Item;
};

interface IArtifactTransmutationRequest {
    Upgrade: IUpgradeFromClient;
    LevelDiff: number;
    Consumed: IUpgradeFromClient[];
    Cost: number;
    FusionPointCost?: number;
    RivenTransmute?: boolean;
}

const specialModSets: string[][] = [
    [
        "/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
        "/Lotus/Upgrades/Mods/Immortal/ImmortalTwoMod",
        "/Lotus/Upgrades/Mods/Immortal/ImmortalThreeMod",
        "/Lotus/Upgrades/Mods/Immortal/ImmortalFourMod",
        "/Lotus/Upgrades/Mods/Immortal/ImmortalFiveMod",
        "/Lotus/Upgrades/Mods/Immortal/ImmortalSixMod",
        "/Lotus/Upgrades/Mods/Immortal/ImmortalSevenMod",
        "/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod",
        "/Lotus/Upgrades/Mods/Immortal/ImmortalWildcardMod"
    ],
    [
        "/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod",
        "/Lotus/Upgrades/Mods/Immortal/AntivirusTwoMod",
        "/Lotus/Upgrades/Mods/Immortal/AntivirusThreeMod",
        "/Lotus/Upgrades/Mods/Immortal/AntivirusFourMod",
        "/Lotus/Upgrades/Mods/Immortal/AntivirusFiveMod",
        "/Lotus/Upgrades/Mods/Immortal/AntivirusSixMod",
        "/Lotus/Upgrades/Mods/Immortal/AntivirusSevenMod",
        "/Lotus/Upgrades/Mods/Immortal/AntivirusEightMod"
    ],
    [
        "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod",
        "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod",
        "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod",
        "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod",
        "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod"
    ]
];

export const selfTestTransmutation = (): boolean => {
    let allGood = true;

    // Ensure we don't error during the .filter logic above.
    for (const { Item } of ExportBoosterPacks["/Lotus/Types/BoosterPacks/ModFuserResult"].components) {
        if (!getUpgrade(Item)) {
            logger.warn(`Transmutation result is not a known upgrade: ${Item}`);
            allGood = false;
        }
    }

    return allGood;
};