forked from OpenWF/SpaceNinjaServer
		
	feat: transmutation (#1112)
Closes #1098 Reviewed-on: OpenWF/SpaceNinjaServer#1112 Co-authored-by: Sainan <sainan@calamity.inc> Co-committed-by: Sainan <sainan@calamity.inc>
This commit is contained in:
		
							parent
							
								
									d7e3f33ecf
								
							
						
					
					
						commit
						901263ada3
					
				
							
								
								
									
										8
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							@ -12,7 +12,7 @@
 | 
			
		||||
        "copyfiles": "^2.4.1",
 | 
			
		||||
        "express": "^5",
 | 
			
		||||
        "mongoose": "^8.11.0",
 | 
			
		||||
        "warframe-public-export-plus": "^0.5.40",
 | 
			
		||||
        "warframe-public-export-plus": "^0.5.41",
 | 
			
		||||
        "warframe-riven-info": "^0.1.2",
 | 
			
		||||
        "winston": "^3.17.0",
 | 
			
		||||
        "winston-daily-rotate-file": "^5.0.0"
 | 
			
		||||
@ -4083,9 +4083,9 @@
 | 
			
		||||
      }
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/warframe-public-export-plus": {
 | 
			
		||||
      "version": "0.5.40",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.40.tgz",
 | 
			
		||||
      "integrity": "sha512-/qr46LE/KqDdEkW4z52EG0vZP0Z8U26FscFJ2G5K5ewbQdlSVxtf5fpOnzRkAO7jWWKfgoqx7l5WUgaLSPDj0g=="
 | 
			
		||||
      "version": "0.5.41",
 | 
			
		||||
      "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.41.tgz",
 | 
			
		||||
      "integrity": "sha512-qVOUY4UjF1cyBrBbMwD25xHSdSf9q57/CJgjHsfSE7NUu/6pBDSZzwS0iAetAukws/1V2kDvsuy8AGtOec2L1w=="
 | 
			
		||||
    },
 | 
			
		||||
    "node_modules/warframe-riven-info": {
 | 
			
		||||
      "version": "0.1.2",
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@
 | 
			
		||||
    "copyfiles": "^2.4.1",
 | 
			
		||||
    "express": "^5",
 | 
			
		||||
    "mongoose": "^8.11.0",
 | 
			
		||||
    "warframe-public-export-plus": "^0.5.40",
 | 
			
		||||
    "warframe-public-export-plus": "^0.5.41",
 | 
			
		||||
    "warframe-riven-info": "^0.1.2",
 | 
			
		||||
    "winston": "^3.17.0",
 | 
			
		||||
    "winston-daily-rotate-file": "^5.0.0"
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,9 @@
 | 
			
		||||
import { toOid } from "@/src/helpers/inventoryHelpers";
 | 
			
		||||
import { IRivenChallenge } from "@/src/helpers/rivenFingerprintHelper";
 | 
			
		||||
import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "@/src/helpers/rivenHelper";
 | 
			
		||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
			
		||||
import { addMods, getInventory } from "@/src/services/inventoryService";
 | 
			
		||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
			
		||||
import { getRandomElement, getRandomInt, getRandomReward } from "@/src/services/rngService";
 | 
			
		||||
import { logger } from "@/src/utils/logger";
 | 
			
		||||
import { getRandomElement } from "@/src/services/rngService";
 | 
			
		||||
import { RequestHandler } from "express";
 | 
			
		||||
import { ExportUpgrades } from "warframe-public-export-plus";
 | 
			
		||||
 | 
			
		||||
@ -19,40 +18,18 @@ export const activateRandomModController: RequestHandler = async (req, res) => {
 | 
			
		||||
        }
 | 
			
		||||
    ]);
 | 
			
		||||
    const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType]);
 | 
			
		||||
    const challenge = getRandomElement(ExportUpgrades[rivenType].availableChallenges!);
 | 
			
		||||
    const fingerprintChallenge: IRivenChallenge = {
 | 
			
		||||
        Type: challenge.fullName,
 | 
			
		||||
        Progress: 0,
 | 
			
		||||
        Required: getRandomInt(challenge.countRange[0], challenge.countRange[1])
 | 
			
		||||
    };
 | 
			
		||||
    if (Math.random() < challenge.complicationChance) {
 | 
			
		||||
        const complications: { type: string; probability: number }[] = [];
 | 
			
		||||
        for (const complication of challenge.complications) {
 | 
			
		||||
            complications.push({
 | 
			
		||||
                type: complication.fullName,
 | 
			
		||||
                probability: complication.weight
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        fingerprintChallenge.Complication = getRandomReward(complications)!.type;
 | 
			
		||||
        logger.debug(
 | 
			
		||||
            `riven rolled challenge ${fingerprintChallenge.Type} with complication ${fingerprintChallenge.Complication}`
 | 
			
		||||
        );
 | 
			
		||||
        const complication = challenge.complications.find(x => x.fullName == fingerprintChallenge.Complication)!;
 | 
			
		||||
        fingerprintChallenge.Required *= complication.countMultiplier;
 | 
			
		||||
    } else {
 | 
			
		||||
        logger.debug(`riven rolled challenge ${fingerprintChallenge.Type}`);
 | 
			
		||||
    }
 | 
			
		||||
    const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
 | 
			
		||||
    const upgradeIndex =
 | 
			
		||||
        inventory.Upgrades.push({
 | 
			
		||||
            ItemType: rivenType,
 | 
			
		||||
            UpgradeFingerprint: JSON.stringify({ challenge: fingerprintChallenge })
 | 
			
		||||
            UpgradeFingerprint: JSON.stringify(fingerprint)
 | 
			
		||||
        }) - 1;
 | 
			
		||||
    await inventory.save();
 | 
			
		||||
    // For some reason, in this response, the UpgradeFingerprint is simply a nested object and not a string
 | 
			
		||||
    res.json({
 | 
			
		||||
        NewMod: {
 | 
			
		||||
            UpgradeFingerprint: { challenge: fingerprintChallenge },
 | 
			
		||||
            ItemType: inventory.Upgrades[upgradeIndex].ItemType,
 | 
			
		||||
            UpgradeFingerprint: fingerprint,
 | 
			
		||||
            ItemType: rivenType,
 | 
			
		||||
            ItemId: toOid(inventory.Upgrades[upgradeIndex]._id)
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
@ -61,37 +38,3 @@ export const activateRandomModController: RequestHandler = async (req, res) => {
 | 
			
		||||
interface IActiveRandomModRequest {
 | 
			
		||||
    ItemType: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const rivenRawToRealWeighted: Record<string, string[]> = {
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawArchgunRandomMod": [
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusArchgunRandomModRare"
 | 
			
		||||
    ],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawMeleeRandomMod": [
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare"
 | 
			
		||||
    ],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawModularMeleeRandomMod": [
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusModularMeleeRandomModRare"
 | 
			
		||||
    ],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawModularPistolRandomMod": [
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusModularPistolRandomModRare"
 | 
			
		||||
    ],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawPistolRandomMod": ["/Lotus/Upgrades/Mods/Randomized/LotusPistolRandomModRare"],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawRifleRandomMod": ["/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare"],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawShotgunRandomMod": [
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusShotgunRandomModRare"
 | 
			
		||||
    ],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawSentinelWeaponRandomMod": [
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusShotgunRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusPistolRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare"
 | 
			
		||||
    ]
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										124
									
								
								src/controllers/api/artifactTransmutationController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								src/controllers/api/artifactTransmutationController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,124 @@
 | 
			
		||||
import { toOid } from "@/src/helpers/inventoryHelpers";
 | 
			
		||||
import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "@/src/helpers/rivenHelper";
 | 
			
		||||
import { addMiscItems, addMods, getInventory } from "@/src/services/inventoryService";
 | 
			
		||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
			
		||||
import { getRandomElement, getRandomWeightedReward, getRandomWeightedRewardUc } from "@/src/services/rngService";
 | 
			
		||||
import { IOid } from "@/src/types/commonTypes";
 | 
			
		||||
import { RequestHandler } from "express";
 | 
			
		||||
import { ExportBoosterPacks, ExportUpgrades, TRarity } from "warframe-public-export-plus";
 | 
			
		||||
 | 
			
		||||
export const artifactTransmutationController: RequestHandler = async (req, res) => {
 | 
			
		||||
    const accountId = await getAccountIdForRequest(req);
 | 
			
		||||
    const inventory = await getInventory(accountId);
 | 
			
		||||
    const payload = JSON.parse(String(req.body)) as IArtifactTransmutationRequest;
 | 
			
		||||
 | 
			
		||||
    inventory.RegularCredits -= payload.Cost;
 | 
			
		||||
    inventory.FusionPoints -= payload.FusionPointCost;
 | 
			
		||||
 | 
			
		||||
    if (payload.RivenTransmute) {
 | 
			
		||||
        addMiscItems(inventory, [
 | 
			
		||||
            {
 | 
			
		||||
                ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientSecretItem",
 | 
			
		||||
                ItemCount: -1
 | 
			
		||||
            }
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        payload.Consumed.forEach(upgrade => {
 | 
			
		||||
            inventory.Upgrades.pull({ _id: upgrade.ItemId.$oid });
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const rawRivenType = getRandomRawRivenType();
 | 
			
		||||
        const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType]);
 | 
			
		||||
        const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
 | 
			
		||||
 | 
			
		||||
        const upgradeIndex =
 | 
			
		||||
            inventory.Upgrades.push({
 | 
			
		||||
                ItemType: rivenType,
 | 
			
		||||
                UpgradeFingerprint: JSON.stringify(fingerprint)
 | 
			
		||||
            }) - 1;
 | 
			
		||||
        await inventory.save();
 | 
			
		||||
        res.json({
 | 
			
		||||
            NewMods: [
 | 
			
		||||
                {
 | 
			
		||||
                    ItemId: toOid(inventory.Upgrades[upgradeIndex]._id),
 | 
			
		||||
                    ItemType: rivenType,
 | 
			
		||||
                    UpgradeFingerprint: fingerprint
 | 
			
		||||
                }
 | 
			
		||||
            ]
 | 
			
		||||
        });
 | 
			
		||||
    } else {
 | 
			
		||||
        const counts: Record<TRarity, number> = {
 | 
			
		||||
            COMMON: 0,
 | 
			
		||||
            UNCOMMON: 0,
 | 
			
		||||
            RARE: 0,
 | 
			
		||||
            LEGENDARY: 0
 | 
			
		||||
        };
 | 
			
		||||
        payload.Consumed.forEach(upgrade => {
 | 
			
		||||
            const meta = ExportUpgrades[upgrade.ItemType];
 | 
			
		||||
            counts[meta.rarity] += upgrade.ItemCount;
 | 
			
		||||
            addMods(inventory, [
 | 
			
		||||
                {
 | 
			
		||||
                    ItemType: upgrade.ItemType,
 | 
			
		||||
                    ItemCount: upgrade.ItemCount * -1
 | 
			
		||||
                }
 | 
			
		||||
            ]);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // 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: { uniqueName: string; rarity: TRarity }[] = [];
 | 
			
		||||
        Object.entries(ExportUpgrades).forEach(([uniqueName, upgrade]) => {
 | 
			
		||||
            if (upgrade.canBeTransmutation) {
 | 
			
		||||
                options.push({ uniqueName, rarity: upgrade.rarity });
 | 
			
		||||
            }
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        const newModType = getRandomWeightedReward(options, weights)!.uniqueName;
 | 
			
		||||
        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: IAgnosticUpgradeClient;
 | 
			
		||||
    LevelDiff: number;
 | 
			
		||||
    Consumed: IAgnosticUpgradeClient[];
 | 
			
		||||
    Cost: number;
 | 
			
		||||
    FusionPointCost: number;
 | 
			
		||||
    RivenTransmute?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IAgnosticUpgradeClient {
 | 
			
		||||
    ItemType: string;
 | 
			
		||||
    ItemId: IOid;
 | 
			
		||||
    FromSKU: boolean;
 | 
			
		||||
    UpgradeFingerprint: string;
 | 
			
		||||
    PendingRerollFingerprint: string;
 | 
			
		||||
    ItemCount: number;
 | 
			
		||||
    LastAdded: IOid;
 | 
			
		||||
}
 | 
			
		||||
@ -4,7 +4,7 @@ import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inven
 | 
			
		||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
			
		||||
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
			
		||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
			
		||||
import { createUnveiledRivenFingerprint } from "@/src/helpers/rivenFingerprintHelper";
 | 
			
		||||
import { createUnveiledRivenFingerprint } from "@/src/helpers/rivenHelper";
 | 
			
		||||
import { ExportUpgrades } from "warframe-public-export-plus";
 | 
			
		||||
 | 
			
		||||
export const completeRandomModChallengeController: RequestHandler = async (req, res) => {
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,7 @@ import { RequestHandler } from "express";
 | 
			
		||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
			
		||||
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
 | 
			
		||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
			
		||||
import {
 | 
			
		||||
    createUnveiledRivenFingerprint,
 | 
			
		||||
    randomiseRivenStats,
 | 
			
		||||
    RivenFingerprint
 | 
			
		||||
} from "@/src/helpers/rivenFingerprintHelper";
 | 
			
		||||
import { createUnveiledRivenFingerprint, randomiseRivenStats, RivenFingerprint } from "@/src/helpers/rivenHelper";
 | 
			
		||||
import { ExportUpgrades } from "warframe-public-export-plus";
 | 
			
		||||
import { IOid } from "@/src/types/commonTypes";
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,65 +0,0 @@
 | 
			
		||||
import { IUpgrade } from "warframe-public-export-plus";
 | 
			
		||||
import { getRandomElement, getRandomInt } from "../services/rngService";
 | 
			
		||||
 | 
			
		||||
export type RivenFingerprint = IVeiledRivenFingerprint | IUnveiledRivenFingerprint;
 | 
			
		||||
 | 
			
		||||
export interface IVeiledRivenFingerprint {
 | 
			
		||||
    challenge: IRivenChallenge;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IRivenChallenge {
 | 
			
		||||
    Type: string;
 | 
			
		||||
    Progress: number;
 | 
			
		||||
    Required: number;
 | 
			
		||||
    Complication?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IUnveiledRivenFingerprint {
 | 
			
		||||
    compat: string;
 | 
			
		||||
    lim: 0;
 | 
			
		||||
    lvl: number;
 | 
			
		||||
    lvlReq: number;
 | 
			
		||||
    rerolls?: number;
 | 
			
		||||
    pol: string;
 | 
			
		||||
    buffs: IRivenStat[];
 | 
			
		||||
    curses: IRivenStat[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IRivenStat {
 | 
			
		||||
    Tag: string;
 | 
			
		||||
    Value: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const createUnveiledRivenFingerprint = (meta: IUpgrade): IUnveiledRivenFingerprint => {
 | 
			
		||||
    const fingerprint: IUnveiledRivenFingerprint = {
 | 
			
		||||
        compat: getRandomElement(meta.compatibleItems!),
 | 
			
		||||
        lim: 0,
 | 
			
		||||
        lvl: 0,
 | 
			
		||||
        lvlReq: getRandomInt(8, 16),
 | 
			
		||||
        pol: getRandomElement(["AP_ATTACK", "AP_DEFENSE", "AP_TACTIC"]),
 | 
			
		||||
        buffs: [],
 | 
			
		||||
        curses: []
 | 
			
		||||
    };
 | 
			
		||||
    randomiseRivenStats(meta, fingerprint);
 | 
			
		||||
    return fingerprint;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const randomiseRivenStats = (meta: IUpgrade, fingerprint: IUnveiledRivenFingerprint): void => {
 | 
			
		||||
    fingerprint.buffs = [];
 | 
			
		||||
    const numBuffs = 2 + Math.trunc(Math.random() * 2); // 2 or 3
 | 
			
		||||
    const buffEntries = meta.upgradeEntries!.filter(x => x.canBeBuff);
 | 
			
		||||
    for (let i = 0; i != numBuffs; ++i) {
 | 
			
		||||
        const buffIndex = Math.trunc(Math.random() * buffEntries.length);
 | 
			
		||||
        const entry = buffEntries[buffIndex];
 | 
			
		||||
        fingerprint.buffs.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
 | 
			
		||||
        buffEntries.splice(buffIndex, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fingerprint.curses = [];
 | 
			
		||||
    if (Math.random() < 0.5) {
 | 
			
		||||
        const entry = getRandomElement(
 | 
			
		||||
            meta.upgradeEntries!.filter(x => x.canBeCurse && !fingerprint.buffs.find(y => y.Tag == x.tag))
 | 
			
		||||
        );
 | 
			
		||||
        fingerprint.curses.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
							
								
								
									
										121
									
								
								src/helpers/rivenHelper.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/helpers/rivenHelper.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,121 @@
 | 
			
		||||
import { IUpgrade } from "warframe-public-export-plus";
 | 
			
		||||
import { getRandomElement, getRandomInt, getRandomReward } from "../services/rngService";
 | 
			
		||||
 | 
			
		||||
export type RivenFingerprint = IVeiledRivenFingerprint | IUnveiledRivenFingerprint;
 | 
			
		||||
 | 
			
		||||
export interface IVeiledRivenFingerprint {
 | 
			
		||||
    challenge: IRivenChallenge;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IRivenChallenge {
 | 
			
		||||
    Type: string;
 | 
			
		||||
    Progress: number;
 | 
			
		||||
    Required: number;
 | 
			
		||||
    Complication?: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface IUnveiledRivenFingerprint {
 | 
			
		||||
    compat: string;
 | 
			
		||||
    lim: 0;
 | 
			
		||||
    lvl: number;
 | 
			
		||||
    lvlReq: number;
 | 
			
		||||
    rerolls?: number;
 | 
			
		||||
    pol: string;
 | 
			
		||||
    buffs: IRivenStat[];
 | 
			
		||||
    curses: IRivenStat[];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface IRivenStat {
 | 
			
		||||
    Tag: string;
 | 
			
		||||
    Value: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export const createVeiledRivenFingerprint = (meta: IUpgrade): IVeiledRivenFingerprint => {
 | 
			
		||||
    const challenge = getRandomElement(meta.availableChallenges!);
 | 
			
		||||
    const fingerprintChallenge: IRivenChallenge = {
 | 
			
		||||
        Type: challenge.fullName,
 | 
			
		||||
        Progress: 0,
 | 
			
		||||
        Required: getRandomInt(challenge.countRange[0], challenge.countRange[1])
 | 
			
		||||
    };
 | 
			
		||||
    if (Math.random() < challenge.complicationChance) {
 | 
			
		||||
        const complications: { type: string; probability: number }[] = [];
 | 
			
		||||
        for (const complication of challenge.complications) {
 | 
			
		||||
            complications.push({
 | 
			
		||||
                type: complication.fullName,
 | 
			
		||||
                probability: complication.weight
 | 
			
		||||
            });
 | 
			
		||||
        }
 | 
			
		||||
        fingerprintChallenge.Complication = getRandomReward(complications)!.type;
 | 
			
		||||
        const complication = challenge.complications.find(x => x.fullName == fingerprintChallenge.Complication)!;
 | 
			
		||||
        fingerprintChallenge.Required *= complication.countMultiplier;
 | 
			
		||||
    }
 | 
			
		||||
    return { challenge: fingerprintChallenge };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const createUnveiledRivenFingerprint = (meta: IUpgrade): IUnveiledRivenFingerprint => {
 | 
			
		||||
    const fingerprint: IUnveiledRivenFingerprint = {
 | 
			
		||||
        compat: getRandomElement(meta.compatibleItems!),
 | 
			
		||||
        lim: 0,
 | 
			
		||||
        lvl: 0,
 | 
			
		||||
        lvlReq: getRandomInt(8, 16),
 | 
			
		||||
        pol: getRandomElement(["AP_ATTACK", "AP_DEFENSE", "AP_TACTIC"]),
 | 
			
		||||
        buffs: [],
 | 
			
		||||
        curses: []
 | 
			
		||||
    };
 | 
			
		||||
    randomiseRivenStats(meta, fingerprint);
 | 
			
		||||
    return fingerprint;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const randomiseRivenStats = (meta: IUpgrade, fingerprint: IUnveiledRivenFingerprint): void => {
 | 
			
		||||
    fingerprint.buffs = [];
 | 
			
		||||
    const numBuffs = 2 + Math.trunc(Math.random() * 2); // 2 or 3
 | 
			
		||||
    const buffEntries = meta.upgradeEntries!.filter(x => x.canBeBuff);
 | 
			
		||||
    for (let i = 0; i != numBuffs; ++i) {
 | 
			
		||||
        const buffIndex = Math.trunc(Math.random() * buffEntries.length);
 | 
			
		||||
        const entry = buffEntries[buffIndex];
 | 
			
		||||
        fingerprint.buffs.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
 | 
			
		||||
        buffEntries.splice(buffIndex, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fingerprint.curses = [];
 | 
			
		||||
    if (Math.random() < 0.5) {
 | 
			
		||||
        const entry = getRandomElement(
 | 
			
		||||
            meta.upgradeEntries!.filter(x => x.canBeCurse && !fingerprint.buffs.find(y => y.Tag == x.tag))
 | 
			
		||||
        );
 | 
			
		||||
        fingerprint.curses.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const rivenRawToRealWeighted: Record<string, string[]> = {
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawArchgunRandomMod": [
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusArchgunRandomModRare"
 | 
			
		||||
    ],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawMeleeRandomMod": [
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare"
 | 
			
		||||
    ],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawModularMeleeRandomMod": [
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusModularMeleeRandomModRare"
 | 
			
		||||
    ],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawModularPistolRandomMod": [
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusModularPistolRandomModRare"
 | 
			
		||||
    ],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawPistolRandomMod": ["/Lotus/Upgrades/Mods/Randomized/LotusPistolRandomModRare"],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawRifleRandomMod": ["/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare"],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawShotgunRandomMod": [
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusShotgunRandomModRare"
 | 
			
		||||
    ],
 | 
			
		||||
    "/Lotus/Upgrades/Mods/Randomized/RawSentinelWeaponRandomMod": [
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusRifleRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusShotgunRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/LotusPistolRandomModRare",
 | 
			
		||||
        "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare"
 | 
			
		||||
    ]
 | 
			
		||||
};
 | 
			
		||||
@ -7,6 +7,7 @@ import { addFriendImageController } from "@/src/controllers/api/addFriendImageCo
 | 
			
		||||
import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
 | 
			
		||||
import { archonFusionController } from "@/src/controllers/api/archonFusionController";
 | 
			
		||||
import { artifactsController } from "@/src/controllers/api/artifactsController";
 | 
			
		||||
import { artifactTransmutationController } from "@/src/controllers/api/artifactTransmutationController";
 | 
			
		||||
import { changeDojoRootController } from "@/src/controllers/api/changeDojoRootController";
 | 
			
		||||
import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController";
 | 
			
		||||
import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController";
 | 
			
		||||
@ -150,6 +151,7 @@ apiRouter.post("/addFriendImage.php", addFriendImageController);
 | 
			
		||||
apiRouter.post("/arcaneCommon.php", arcaneCommonController);
 | 
			
		||||
apiRouter.post("/archonFusion.php", archonFusionController);
 | 
			
		||||
apiRouter.post("/artifacts.php", artifactsController);
 | 
			
		||||
apiRouter.post("/artifactTransmutation.php", artifactTransmutationController);
 | 
			
		||||
apiRouter.post("/changeDojoRoot.php", changeDojoRootController);
 | 
			
		||||
apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
 | 
			
		||||
apiRouter.post("/clearDialogueHistory.php", clearDialogueHistoryController);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user