forked from OpenWF/SpaceNinjaServer
		
	feat: handle NemesisKillConvert at missionInventoryUpdate (#1880)
Closes #1848 Reviewed-on: OpenWF/SpaceNinjaServer#1880 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									9e94083875
								
							
						
					
					
						commit
						ee1a49f5f2
					
				@ -133,7 +133,14 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
 | 
			
		||||
        if (recipe.secretIngredientAction != "SIA_UNBRAND") {
 | 
			
		||||
            InventoryChanges = {
 | 
			
		||||
                ...InventoryChanges,
 | 
			
		||||
                ...(await addItem(inventory, recipe.resultType, recipe.num, false))
 | 
			
		||||
                ...(await addItem(
 | 
			
		||||
                    inventory,
 | 
			
		||||
                    recipe.resultType,
 | 
			
		||||
                    recipe.num,
 | 
			
		||||
                    false,
 | 
			
		||||
                    undefined,
 | 
			
		||||
                    pendingRecipe.TargetFingerprint
 | 
			
		||||
                ))
 | 
			
		||||
            };
 | 
			
		||||
        }
 | 
			
		||||
        await inventory.save();
 | 
			
		||||
 | 
			
		||||
@ -3,6 +3,7 @@ import {
 | 
			
		||||
    encodeNemesisGuess,
 | 
			
		||||
    getInfNodes,
 | 
			
		||||
    getNemesisPasscode,
 | 
			
		||||
    getWeaponsForManifest,
 | 
			
		||||
    IKnifeResponse
 | 
			
		||||
} from "@/src/helpers/nemesisHelpers";
 | 
			
		||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
			
		||||
@ -170,18 +171,7 @@ export const nemesisController: RequestHandler = async (req, res) => {
 | 
			
		||||
 | 
			
		||||
        let weaponIdx = -1;
 | 
			
		||||
        if (body.target.Faction != "FC_INFESTATION") {
 | 
			
		||||
            let weapons: readonly string[];
 | 
			
		||||
            if (body.target.manifest == "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix") {
 | 
			
		||||
                weapons = kuvaLichVersionSixWeapons;
 | 
			
		||||
            } else if (
 | 
			
		||||
                body.target.manifest == "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour" ||
 | 
			
		||||
                body.target.manifest == "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree"
 | 
			
		||||
            ) {
 | 
			
		||||
                weapons = corpusVersionThreeWeapons;
 | 
			
		||||
            } else {
 | 
			
		||||
                throw new Error(`unknown nemesis manifest: ${body.target.manifest}`);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const weapons = getWeaponsForManifest(body.target.manifest);
 | 
			
		||||
            const initialWeaponIdx = new SRng(body.target.fp).randomInt(0, weapons.length - 1);
 | 
			
		||||
            weaponIdx = initialWeaponIdx;
 | 
			
		||||
            do {
 | 
			
		||||
@ -283,39 +273,3 @@ interface INemesisRequiemRequest {
 | 
			
		||||
        HiddenWhenHolstered: boolean;
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const kuvaLichVersionSixWeapons = [
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Drakgoon/KuvaDrakgoon",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Karak/KuvaKarak",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/Melee/GrnKuvaLichScythe/GrnKuvaLichScytheWeapon",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Kohm/KuvaKohm",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Ogris/KuvaOgris",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Quartakk/KuvaQuartakk",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Tonkor/KuvaTonkor",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Brakk/KuvaBrakk",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Kraken/KuvaKraken",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Seer/KuvaSeer",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Stubba/KuvaStubba",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/HeavyWeapons/GrnHeavyGrenadeLauncher",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/LongGuns/GrnKuvaLichRifle/GrnKuvaLichRifleWeapon",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/Bows/GrnBow/GrnBowWeapon",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hind/KuvaHind",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Nukor/KuvaNukor",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hek/KuvaHekWeapon",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Zarr/KuvaZarr",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/HeavyWeapons/Grattler/KuvaGrattler",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Sobek/KuvaSobek"
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const corpusVersionThreeWeapons = [
 | 
			
		||||
    "/Lotus/Weapons/Corpus/LongGuns/CrpBriefcaseLauncher/CrpBriefcaseLauncher",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEArcaPlasmor/CrpBEArcaPlasmor",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEFluxRifle/CrpBEFluxRifle",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBETetra/CrpBETetra",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBECycron/CrpBECycron",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEDetron/CrpBEDetron",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/Pistols/CrpIgniterPistol/CrpIgniterPistol",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/Pistols/CrpBriefcaseAkimbo/CrpBriefcaseAkimboPistol",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEPlinx/CrpBEPlinxWeapon",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEGlaxion/CrpBEGlaxion"
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
import { ExportRegions } from "warframe-public-export-plus";
 | 
			
		||||
import { ExportRegions, ExportWarframes } from "warframe-public-export-plus";
 | 
			
		||||
import { IInfNode } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
			
		||||
import { SRng } from "@/src/services/rngService";
 | 
			
		||||
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
 | 
			
		||||
@ -129,3 +129,147 @@ export const consumeModCharge = (
 | 
			
		||||
        response.UpgradeNew.push(true);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const kuvaLichVersionSixWeapons = [
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Drakgoon/KuvaDrakgoon",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Karak/KuvaKarak",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/Melee/GrnKuvaLichScythe/GrnKuvaLichScytheWeapon",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Kohm/KuvaKohm",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Ogris/KuvaOgris",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Quartakk/KuvaQuartakk",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Tonkor/KuvaTonkor",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Brakk/KuvaBrakk",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Kraken/KuvaKraken",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Seer/KuvaSeer",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Stubba/KuvaStubba",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/HeavyWeapons/GrnHeavyGrenadeLauncher",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/LongGuns/GrnKuvaLichRifle/GrnKuvaLichRifleWeapon",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/Bows/GrnBow/GrnBowWeapon",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hind/KuvaHind",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Nukor/KuvaNukor",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hek/KuvaHekWeapon",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Zarr/KuvaZarr",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/HeavyWeapons/Grattler/KuvaGrattler",
 | 
			
		||||
    "/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Sobek/KuvaSobek"
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
const corpusVersionThreeWeapons = [
 | 
			
		||||
    "/Lotus/Weapons/Corpus/LongGuns/CrpBriefcaseLauncher/CrpBriefcaseLauncher",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEArcaPlasmor/CrpBEArcaPlasmor",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEFluxRifle/CrpBEFluxRifle",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBETetra/CrpBETetra",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBECycron/CrpBECycron",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEDetron/CrpBEDetron",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/Pistols/CrpIgniterPistol/CrpIgniterPistol",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/Pistols/CrpBriefcaseAkimbo/CrpBriefcaseAkimboPistol",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEPlinx/CrpBEPlinxWeapon",
 | 
			
		||||
    "/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEGlaxion/CrpBEGlaxion"
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
export const getWeaponsForManifest = (manifest: string): readonly string[] => {
 | 
			
		||||
    switch (manifest) {
 | 
			
		||||
        case "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix":
 | 
			
		||||
            return kuvaLichVersionSixWeapons;
 | 
			
		||||
        case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree":
 | 
			
		||||
        case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour":
 | 
			
		||||
            return corpusVersionThreeWeapons;
 | 
			
		||||
    }
 | 
			
		||||
    throw new Error(`unknown nemesis manifest: ${manifest}`);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// TODO: This sucks.
 | 
			
		||||
export const getInnateDamageTag = (
 | 
			
		||||
    KillingSuit: string
 | 
			
		||||
):
 | 
			
		||||
    | "InnateElectricityDamage"
 | 
			
		||||
    | "InnateFreezeDamage"
 | 
			
		||||
    | "InnateHeatDamage"
 | 
			
		||||
    | "InnateImpactDamage"
 | 
			
		||||
    | "InnateMagDamage"
 | 
			
		||||
    | "InnateRadDamage"
 | 
			
		||||
    | "InnateToxinDamage" => {
 | 
			
		||||
    const baseSuitType = ExportWarframes[KillingSuit].parentName;
 | 
			
		||||
    switch (baseSuitType) {
 | 
			
		||||
        case "/Lotus/Powersuits/Volt/VoltBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Excalibur/ExcaliburBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/AntiMatter/NovaBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Banshee/BansheeBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Berserker/BerserkerBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Magician/MagicianBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Sentient/SentientBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Gyre/GyreBaseSuit":
 | 
			
		||||
            return "InnateElectricityDamage";
 | 
			
		||||
        case "/Lotus/Powersuits/Ember/EmberBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Dragon/DragonBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Nezha/NezhaBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Sandman/SandmanBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Trapper/TrapperBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Wisp/WispBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Odalisk/OdaliskBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/PaxDuviricus/PaxDuviricusBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Choir/ChoirBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Temple/TempleBaseSuit":
 | 
			
		||||
            return "InnateHeatDamage";
 | 
			
		||||
        case "/Lotus/Powersuits/Frost/FrostBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Glass/GlassBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Fairy/FairyBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/IronFrame/IronFrameBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Revenant/RevenantBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Trinity/TrinityBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Hoplite/HopliteBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Koumei/KoumeiBaseSuit":
 | 
			
		||||
            return "InnateFreezeDamage";
 | 
			
		||||
        case "/Lotus/Powersuits/Saryn/SarynBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Paladin/PaladinBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Brawler/BrawlerBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Infestation/InfestationBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Necro/NecroBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Khora/KhoraBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Ranger/RangerBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Dagath/DagathBaseSuit":
 | 
			
		||||
            return "InnateToxinDamage";
 | 
			
		||||
        case "/Lotus/Powersuits/Mag/MagBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Pirate/PirateBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Cowgirl/CowgirlBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Priest/PriestBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/BrokenFrame/BrokenFrameBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Alchemist/AlchemistBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Yareli/YareliBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Geode/GeodeBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Frumentarius/FrumentariusBaseSuit":
 | 
			
		||||
            return "InnateMagDamage";
 | 
			
		||||
        case "/Lotus/Powersuits/Loki/LokiBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Ninja/NinjaBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Jade/JadeBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Bard/BardBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Harlequin/HarlequinBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Garuda/GarudaBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/YinYang/YinYangBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Werewolf/WerewolfBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/ConcreteFrame/ConcreteFrameBaseSuit":
 | 
			
		||||
            return "InnateRadDamage";
 | 
			
		||||
        case "/Lotus/Powersuits/Rhino/RhinoBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Tengu/TenguBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/MonkeyKing/MonkeyKingBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Runner/RunnerBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Pacifist/PacifistBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Devourer/DevourerBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Wraith/WraithBaseSuit":
 | 
			
		||||
        case "/Lotus/Powersuits/Pagemaster/PagemasterBaseSuit":
 | 
			
		||||
            return "InnateImpactDamage";
 | 
			
		||||
    }
 | 
			
		||||
    logger.warn(`unknown innate damage type for ${KillingSuit}, using heat as a fallback`);
 | 
			
		||||
    return "InnateHeatDamage";
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
// TODO: For -1399275245665749231n, the value should be 75306944, but we're off by 59 with 75307003.
 | 
			
		||||
export const getInnateDamageValue = (fp: bigint): number => {
 | 
			
		||||
    const rng = new SRng(fp);
 | 
			
		||||
    rng.randomFloat(); // used for the weapon index
 | 
			
		||||
    const WeaponUpgradeValueAttenuationExponent = 2.25;
 | 
			
		||||
    let value = Math.pow(rng.randomFloat(), WeaponUpgradeValueAttenuationExponent);
 | 
			
		||||
    if (value >= 0.941428) {
 | 
			
		||||
        value = 1;
 | 
			
		||||
    }
 | 
			
		||||
    return Math.trunc(value * 0x40000000);
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1039,6 +1039,8 @@ const pendingRecipeSchema = new Schema<IPendingRecipeDatabase>(
 | 
			
		||||
    {
 | 
			
		||||
        ItemType: String,
 | 
			
		||||
        CompletionDate: Date,
 | 
			
		||||
        TargetItemId: String,
 | 
			
		||||
        TargetFingerprint: String,
 | 
			
		||||
        LongGuns: { type: [EquipmentSchema], default: undefined },
 | 
			
		||||
        Pistols: { type: [EquipmentSchema], default: undefined },
 | 
			
		||||
        Melee: { type: [EquipmentSchema], default: undefined },
 | 
			
		||||
@ -1260,11 +1262,11 @@ const nemesisSchema = new Schema<INemesisDatabase>(
 | 
			
		||||
        PrevOwners: Number,
 | 
			
		||||
        SecondInCommand: Boolean,
 | 
			
		||||
        Weakened: Boolean,
 | 
			
		||||
        InfNodes: [infNodeSchema],
 | 
			
		||||
        InfNodes: { type: [infNodeSchema], default: undefined },
 | 
			
		||||
        HenchmenKilled: Number,
 | 
			
		||||
        HintProgress: Number,
 | 
			
		||||
        Hints: [Number],
 | 
			
		||||
        GuessHistory: [Number],
 | 
			
		||||
        Hints: { type: [Number], default: undefined },
 | 
			
		||||
        GuessHistory: { type: [Number], default: undefined },
 | 
			
		||||
        MissionCount: Number,
 | 
			
		||||
        LastEnc: Number
 | 
			
		||||
    },
 | 
			
		||||
@ -1609,7 +1611,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
 | 
			
		||||
        //CorpusLich or GrineerLich
 | 
			
		||||
        NemesisAbandonedRewards: { type: [String], default: [] },
 | 
			
		||||
        Nemesis: nemesisSchema,
 | 
			
		||||
        NemesisHistory: [Schema.Types.Mixed],
 | 
			
		||||
        NemesisHistory: { type: [nemesisSchema], default: undefined },
 | 
			
		||||
        LastNemesisAllySpawnTime: Schema.Types.Mixed,
 | 
			
		||||
 | 
			
		||||
        //TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
 | 
			
		||||
 | 
			
		||||
@ -26,7 +26,9 @@ import {
 | 
			
		||||
    Status,
 | 
			
		||||
    IKubrowPetDetailsDatabase,
 | 
			
		||||
    ITraits,
 | 
			
		||||
    ICalendarProgress
 | 
			
		||||
    ICalendarProgress,
 | 
			
		||||
    INemesisWeaponTargetFingerprint,
 | 
			
		||||
    INemesisPetTargetFingerprint
 | 
			
		||||
} from "@/src/types/inventoryTypes/inventoryTypes";
 | 
			
		||||
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
 | 
			
		||||
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
 | 
			
		||||
@ -79,6 +81,7 @@ import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from ".
 | 
			
		||||
import { createMessage } from "./inboxService";
 | 
			
		||||
import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
 | 
			
		||||
import { getWorldState } from "./worldStateService";
 | 
			
		||||
import { getInnateDamageTag, getInnateDamageValue } from "../helpers/nemesisHelpers";
 | 
			
		||||
 | 
			
		||||
export const createInventory = async (
 | 
			
		||||
    accountOwnerId: Types.ObjectId,
 | 
			
		||||
@ -327,7 +330,8 @@ export const addItem = async (
 | 
			
		||||
    typeName: string,
 | 
			
		||||
    quantity: number = 1,
 | 
			
		||||
    premiumPurchase: boolean = false,
 | 
			
		||||
    seed?: bigint
 | 
			
		||||
    seed?: bigint,
 | 
			
		||||
    targetFingerprint?: string
 | 
			
		||||
): Promise<IInventoryChanges> => {
 | 
			
		||||
    // Bundles are technically StoreItems but a) they don't have a normal counterpart, and b) they are used in non-StoreItem contexts, e.g. email attachments.
 | 
			
		||||
    if (typeName in ExportBundles) {
 | 
			
		||||
@ -530,6 +534,12 @@ export const addItem = async (
 | 
			
		||||
                    ]
 | 
			
		||||
                });
 | 
			
		||||
            }
 | 
			
		||||
            if (targetFingerprint) {
 | 
			
		||||
                const targetFingerprintObj = JSON.parse(targetFingerprint) as INemesisWeaponTargetFingerprint;
 | 
			
		||||
                defaultOverwrites.UpgradeType = targetFingerprintObj.ItemType;
 | 
			
		||||
                defaultOverwrites.UpgradeFingerprint = JSON.stringify(targetFingerprintObj.UpgradeFingerprint);
 | 
			
		||||
                defaultOverwrites.ItemName = targetFingerprintObj.Name;
 | 
			
		||||
            }
 | 
			
		||||
            const inventoryChanges = addEquipment(inventory, weapon.productCategory, typeName, defaultOverwrites);
 | 
			
		||||
            if (weapon.additionalItems) {
 | 
			
		||||
                for (const item of weapon.additionalItems) {
 | 
			
		||||
@ -544,6 +554,27 @@ export const addItem = async (
 | 
			
		||||
                    premiumPurchase
 | 
			
		||||
                )
 | 
			
		||||
            };
 | 
			
		||||
        } else if (targetFingerprint) {
 | 
			
		||||
            // Sister's Hound
 | 
			
		||||
            const targetFingerprintObj = JSON.parse(targetFingerprint) as INemesisPetTargetFingerprint;
 | 
			
		||||
            const head = targetFingerprintObj.Parts[0];
 | 
			
		||||
            const defaultOverwrites: Partial<IEquipmentDatabase> = {
 | 
			
		||||
                ModularParts: targetFingerprintObj.Parts,
 | 
			
		||||
                ItemName: targetFingerprintObj.Name,
 | 
			
		||||
                Configs: applyDefaultUpgrades(inventory, ExportWeapons[head].defaultUpgrades)
 | 
			
		||||
            };
 | 
			
		||||
            const itemType = {
 | 
			
		||||
                "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadA":
 | 
			
		||||
                    "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetAPowerSuit",
 | 
			
		||||
                "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadB":
 | 
			
		||||
                    "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetBPowerSuit",
 | 
			
		||||
                "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadC":
 | 
			
		||||
                    "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetCPowerSuit"
 | 
			
		||||
            }[head] as string;
 | 
			
		||||
            return {
 | 
			
		||||
                ...addEquipment(inventory, "MoaPets", itemType, defaultOverwrites),
 | 
			
		||||
                ...occupySlot(inventory, InventorySlot.SENTINELS, premiumPurchase)
 | 
			
		||||
            };
 | 
			
		||||
        } else {
 | 
			
		||||
            // Modular weapon parts
 | 
			
		||||
            const miscItemChanges = [
 | 
			
		||||
@ -1851,3 +1882,78 @@ export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICal
 | 
			
		||||
 | 
			
		||||
    return inventory.CalendarProgress;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const giveNemesisWeaponRecipe = (
 | 
			
		||||
    inventory: TInventoryDatabaseDocument,
 | 
			
		||||
    weaponType: string,
 | 
			
		||||
    nemesisName: string = "AGOR ROK",
 | 
			
		||||
    weaponLoc?: string,
 | 
			
		||||
    KillingSuit: string = "/Lotus/Powersuits/Ember/Ember",
 | 
			
		||||
    fp: bigint = generateRewardSeed()
 | 
			
		||||
): void => {
 | 
			
		||||
    if (!weaponLoc) {
 | 
			
		||||
        weaponLoc = ExportWeapons[weaponType].name;
 | 
			
		||||
    }
 | 
			
		||||
    const recipeType = Object.entries(ExportRecipes).find(arr => arr[1].resultType == weaponType)![0];
 | 
			
		||||
    addRecipes(inventory, [
 | 
			
		||||
        {
 | 
			
		||||
            ItemType: recipeType,
 | 
			
		||||
            ItemCount: 1
 | 
			
		||||
        }
 | 
			
		||||
    ]);
 | 
			
		||||
    inventory.PendingRecipes.push({
 | 
			
		||||
        CompletionDate: new Date(),
 | 
			
		||||
        ItemType: recipeType,
 | 
			
		||||
        TargetFingerprint: JSON.stringify({
 | 
			
		||||
            ItemType: "/Lotus/Weapons/Grineer/KuvaLich/Upgrades/InnateDamageRandomMod",
 | 
			
		||||
            UpgradeFingerprint: {
 | 
			
		||||
                compat: weaponType,
 | 
			
		||||
                buffs: [
 | 
			
		||||
                    {
 | 
			
		||||
                        Tag: getInnateDamageTag(KillingSuit),
 | 
			
		||||
                        Value: getInnateDamageValue(fp)
 | 
			
		||||
                    }
 | 
			
		||||
                ]
 | 
			
		||||
            },
 | 
			
		||||
            Name: weaponLoc + "|" + nemesisName
 | 
			
		||||
        } satisfies INemesisWeaponTargetFingerprint)
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const giveNemesisPetRecipe = (inventory: TInventoryDatabaseDocument, nemesisName: string = "AGOR ROK"): void => {
 | 
			
		||||
    const head = getRandomElement([
 | 
			
		||||
        "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadA",
 | 
			
		||||
        "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadB",
 | 
			
		||||
        "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadC"
 | 
			
		||||
    ]);
 | 
			
		||||
    const body = getRandomElement([
 | 
			
		||||
        "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyA",
 | 
			
		||||
        "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyB",
 | 
			
		||||
        "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyC"
 | 
			
		||||
    ]);
 | 
			
		||||
    const legs = getRandomElement([
 | 
			
		||||
        "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsA",
 | 
			
		||||
        "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsB",
 | 
			
		||||
        "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsC"
 | 
			
		||||
    ]);
 | 
			
		||||
    const tail = getRandomElement([
 | 
			
		||||
        "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailA",
 | 
			
		||||
        "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailB",
 | 
			
		||||
        "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailC"
 | 
			
		||||
    ]);
 | 
			
		||||
    const recipeType = Object.entries(ExportRecipes).find(arr => arr[1].resultType == head)![0];
 | 
			
		||||
    addRecipes(inventory, [
 | 
			
		||||
        {
 | 
			
		||||
            ItemType: recipeType,
 | 
			
		||||
            ItemCount: 1
 | 
			
		||||
        }
 | 
			
		||||
    ]);
 | 
			
		||||
    inventory.PendingRecipes.push({
 | 
			
		||||
        CompletionDate: new Date(),
 | 
			
		||||
        ItemType: recipeType,
 | 
			
		||||
        TargetFingerprint: JSON.stringify({
 | 
			
		||||
            Parts: [head, body, legs, tail],
 | 
			
		||||
            Name: "/Lotus/Language/Pets/ZanukaPetName|" + nemesisName
 | 
			
		||||
        } satisfies INemesisPetTargetFingerprint)
 | 
			
		||||
    });
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -35,6 +35,8 @@ import {
 | 
			
		||||
    combineInventoryChanges,
 | 
			
		||||
    generateRewardSeed,
 | 
			
		||||
    getCalendarProgress,
 | 
			
		||||
    giveNemesisPetRecipe,
 | 
			
		||||
    giveNemesisWeaponRecipe,
 | 
			
		||||
    updateCurrency,
 | 
			
		||||
    updateSyndicate
 | 
			
		||||
} from "@/src/services/inventoryService";
 | 
			
		||||
@ -53,7 +55,7 @@ import kuriaMessage50 from "@/static/fixed_responses/kuriaMessages/fiftyPercent.
 | 
			
		||||
import kuriaMessage75 from "@/static/fixed_responses/kuriaMessages/seventyFivePercent.json";
 | 
			
		||||
import kuriaMessage100 from "@/static/fixed_responses/kuriaMessages/oneHundredPercent.json";
 | 
			
		||||
import conservationAnimals from "@/static/fixed_responses/conservationAnimals.json";
 | 
			
		||||
import { getInfNodes } from "@/src/helpers/nemesisHelpers";
 | 
			
		||||
import { getInfNodes, getWeaponsForManifest } from "@/src/helpers/nemesisHelpers";
 | 
			
		||||
import { Loadout } from "../models/inventoryModels/loadoutModel";
 | 
			
		||||
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
 | 
			
		||||
import { getLiteSortie, getWorldState, idToWeek } from "./worldStateService";
 | 
			
		||||
@ -612,6 +614,52 @@ export const addMissionInventoryUpdates = async (
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case "NemesisKillConvert":
 | 
			
		||||
                if (inventory.Nemesis) {
 | 
			
		||||
                    inventory.NemesisHistory ??= [];
 | 
			
		||||
                    inventory.NemesisHistory.push({
 | 
			
		||||
                        // Copy over all 'base' values
 | 
			
		||||
                        fp: inventory.Nemesis.fp,
 | 
			
		||||
                        d: inventory.Nemesis.d,
 | 
			
		||||
                        manifest: inventory.Nemesis.manifest,
 | 
			
		||||
                        KillingSuit: inventory.Nemesis.KillingSuit,
 | 
			
		||||
                        killingDamageType: inventory.Nemesis.killingDamageType,
 | 
			
		||||
                        ShoulderHelmet: inventory.Nemesis.ShoulderHelmet,
 | 
			
		||||
                        WeaponIdx: inventory.Nemesis.WeaponIdx,
 | 
			
		||||
                        AgentIdx: inventory.Nemesis.AgentIdx,
 | 
			
		||||
                        BirthNode: inventory.Nemesis.BirthNode,
 | 
			
		||||
                        Faction: inventory.Nemesis.Faction,
 | 
			
		||||
                        Rank: inventory.Nemesis.Rank,
 | 
			
		||||
                        Traded: inventory.Nemesis.Traded,
 | 
			
		||||
                        PrevOwners: inventory.Nemesis.PrevOwners,
 | 
			
		||||
                        SecondInCommand: inventory.Nemesis.SecondInCommand,
 | 
			
		||||
                        Weakened: inventory.Nemesis.Weakened,
 | 
			
		||||
                        // And set killed flag
 | 
			
		||||
                        k: value.killed
 | 
			
		||||
                    });
 | 
			
		||||
 | 
			
		||||
                    if (value.killed) {
 | 
			
		||||
                        if (value.weaponLoc) {
 | 
			
		||||
                            const weaponType = getWeaponsForManifest(inventory.Nemesis.manifest)[
 | 
			
		||||
                                inventory.Nemesis.WeaponIdx
 | 
			
		||||
                            ];
 | 
			
		||||
                            giveNemesisWeaponRecipe(
 | 
			
		||||
                                inventory,
 | 
			
		||||
                                weaponType,
 | 
			
		||||
                                value.nemesisName,
 | 
			
		||||
                                value.weaponLoc,
 | 
			
		||||
                                inventory.Nemesis.KillingSuit,
 | 
			
		||||
                                inventory.Nemesis.fp
 | 
			
		||||
                            );
 | 
			
		||||
                        }
 | 
			
		||||
                        if (value.petLoc) {
 | 
			
		||||
                            giveNemesisPetRecipe(inventory);
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    inventory.Nemesis = undefined;
 | 
			
		||||
                }
 | 
			
		||||
                break;
 | 
			
		||||
            default:
 | 
			
		||||
                // Equipment XP updates
 | 
			
		||||
                if (equipmentKeys.includes(key as TEquipmentKey)) {
 | 
			
		||||
 | 
			
		||||
@ -43,6 +43,7 @@ export interface IInventoryDatabase
 | 
			
		||||
            | "RecentVendorPurchases"
 | 
			
		||||
            | "NextRefill"
 | 
			
		||||
            | "Nemesis"
 | 
			
		||||
            | "NemesisHistory"
 | 
			
		||||
            | "EntratiVaultCountResetDate"
 | 
			
		||||
            | "BrandedSuits"
 | 
			
		||||
            | "LockedWeaponGroup"
 | 
			
		||||
@ -79,6 +80,7 @@ export interface IInventoryDatabase
 | 
			
		||||
    RecentVendorPurchases?: IRecentVendorPurchaseDatabase[];
 | 
			
		||||
    NextRefill?: Date;
 | 
			
		||||
    Nemesis?: INemesisDatabase;
 | 
			
		||||
    NemesisHistory?: INemesisBaseDatabase[];
 | 
			
		||||
    EntratiVaultCountResetDate?: Date;
 | 
			
		||||
    BrandedSuits?: Types.ObjectId[];
 | 
			
		||||
    LockedWeaponGroup?: ILockedWeaponGroupDatabase;
 | 
			
		||||
@ -313,7 +315,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
 | 
			
		||||
    EquippedInstrument?: string;
 | 
			
		||||
    InvasionChainProgress: IInvasionChainProgress[];
 | 
			
		||||
    Nemesis?: INemesisClient;
 | 
			
		||||
    NemesisHistory: INemesisBaseClient[];
 | 
			
		||||
    NemesisHistory?: INemesisBaseClient[];
 | 
			
		||||
    LastNemesisAllySpawnTime?: IMongoDate;
 | 
			
		||||
    Settings?: ISettings;
 | 
			
		||||
    PersonalTechProjects: IPersonalTechProjectClient[];
 | 
			
		||||
@ -902,8 +904,8 @@ export interface IPendingRecipeDatabase {
 | 
			
		||||
    ItemType: string;
 | 
			
		||||
    CompletionDate: Date;
 | 
			
		||||
    ItemId: IOid;
 | 
			
		||||
    TargetItemId?: string; // likely related to liches
 | 
			
		||||
    TargetFingerprint?: string; // likely related to liches
 | 
			
		||||
    TargetItemId?: string; // unsure what this is for
 | 
			
		||||
    TargetFingerprint?: string;
 | 
			
		||||
    LongGuns?: IEquipmentDatabase[];
 | 
			
		||||
    Pistols?: IEquipmentDatabase[];
 | 
			
		||||
    Melee?: IEquipmentDatabase[];
 | 
			
		||||
@ -951,6 +953,17 @@ export interface ICrewShipComponentFingerprint extends IInnateDamageFingerprint
 | 
			
		||||
    SubroutineIndex?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface INemesisWeaponTargetFingerprint {
 | 
			
		||||
    ItemType: string;
 | 
			
		||||
    UpgradeFingerprint: IInnateDamageFingerprint;
 | 
			
		||||
    Name: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface INemesisPetTargetFingerprint {
 | 
			
		||||
    Parts: string[];
 | 
			
		||||
    Name: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export enum GettingSlotOrderInfo {
 | 
			
		||||
    Empty = "",
 | 
			
		||||
    LotusUpgradesModsRandomizedPlayerMeleeWeaponRandomModRare0 = "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare:0",
 | 
			
		||||
 | 
			
		||||
@ -22,7 +22,8 @@ import {
 | 
			
		||||
    ILoadOutPresets,
 | 
			
		||||
    IInvasionProgressClient,
 | 
			
		||||
    IWeaponSkinClient,
 | 
			
		||||
    IKubrowPetEggClient
 | 
			
		||||
    IKubrowPetEggClient,
 | 
			
		||||
    INemesisClient
 | 
			
		||||
} from "./inventoryTypes/inventoryTypes";
 | 
			
		||||
import { IGroup } from "./loginTypes";
 | 
			
		||||
 | 
			
		||||
@ -74,6 +75,14 @@ export type IMissionInventoryUpdateRequest = {
 | 
			
		||||
    PS: string;
 | 
			
		||||
    ActiveDojoColorResearch: string;
 | 
			
		||||
    RewardInfo?: IRewardInfo;
 | 
			
		||||
    NemesisKillConvert?: {
 | 
			
		||||
        nemesisName: string;
 | 
			
		||||
        weaponLoc: string;
 | 
			
		||||
        petLoc: "" | "/Lotus/Language/Pets/ZanukaPetName";
 | 
			
		||||
        fingerprint: bigint | number;
 | 
			
		||||
        killed: boolean;
 | 
			
		||||
    };
 | 
			
		||||
    target?: INemesisClient;
 | 
			
		||||
    ReceivedCeremonyMsg: boolean;
 | 
			
		||||
    LastCeremonyResetDate: number;
 | 
			
		||||
    MissionPTS: number;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user