forked from OpenWF/SpaceNinjaServer
		
	feat: bounty chemistry bonus (#2070)
Re #388 Reviewed-on: OpenWF/SpaceNinjaServer#2070 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
							
								
									bfe2e93c76
								
							
						
					
					
						commit
						099f12a197
					
				@ -1,8 +1,7 @@
 | 
			
		||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
			
		||||
import { config } from "@/src/services/configService";
 | 
			
		||||
import { addEmailItem, getInventory, updateCurrency } from "@/src/services/inventoryService";
 | 
			
		||||
import { addEmailItem, getDialogue, getInventory, updateCurrency } from "@/src/services/inventoryService";
 | 
			
		||||
import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
			
		||||
import { ICompletedDialogue, IDialogueDatabase } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
			
		||||
import { ICompletedDialogue } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
			
		||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
			
		||||
import { RequestHandler } from "express";
 | 
			
		||||
 | 
			
		||||
@ -107,26 +106,3 @@ interface IOtherDialogueInfo {
 | 
			
		||||
    Tag: string;
 | 
			
		||||
    Value: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const getDialogue = (inventory: TInventoryDatabaseDocument, dialogueName: string): IDialogueDatabase => {
 | 
			
		||||
    let dialogue = inventory.DialogueHistory!.Dialogues!.find(x => x.DialogueName == dialogueName);
 | 
			
		||||
    if (!dialogue) {
 | 
			
		||||
        dialogue =
 | 
			
		||||
            inventory.DialogueHistory!.Dialogues![
 | 
			
		||||
                inventory.DialogueHistory!.Dialogues!.push({
 | 
			
		||||
                    Rank: 0,
 | 
			
		||||
                    Chemistry: 0,
 | 
			
		||||
                    AvailableDate: new Date(0),
 | 
			
		||||
                    AvailableGiftDate: new Date(0),
 | 
			
		||||
                    RankUpExpiry: new Date(0),
 | 
			
		||||
                    BountyChemExpiry: new Date(0),
 | 
			
		||||
                    QueuedDialogues: [],
 | 
			
		||||
                    Gifts: [],
 | 
			
		||||
                    Booleans: [],
 | 
			
		||||
                    Completed: [],
 | 
			
		||||
                    DialogueName: dialogueName
 | 
			
		||||
                }) - 1
 | 
			
		||||
            ];
 | 
			
		||||
    }
 | 
			
		||||
    return dialogue;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -28,7 +28,8 @@ import {
 | 
			
		||||
    ITraits,
 | 
			
		||||
    ICalendarProgress,
 | 
			
		||||
    INemesisWeaponTargetFingerprint,
 | 
			
		||||
    INemesisPetTargetFingerprint
 | 
			
		||||
    INemesisPetTargetFingerprint,
 | 
			
		||||
    IDialogueDatabase
 | 
			
		||||
} from "@/src/types/inventoryTypes/inventoryTypes";
 | 
			
		||||
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
 | 
			
		||||
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
 | 
			
		||||
@ -1906,6 +1907,29 @@ export const cleanupInventory = (inventory: TInventoryDatabaseDocument): void =>
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getDialogue = (inventory: TInventoryDatabaseDocument, dialogueName: string): IDialogueDatabase => {
 | 
			
		||||
    let dialogue = inventory.DialogueHistory!.Dialogues!.find(x => x.DialogueName == dialogueName);
 | 
			
		||||
    if (!dialogue) {
 | 
			
		||||
        dialogue =
 | 
			
		||||
            inventory.DialogueHistory!.Dialogues![
 | 
			
		||||
                inventory.DialogueHistory!.Dialogues!.push({
 | 
			
		||||
                    Rank: 0,
 | 
			
		||||
                    Chemistry: 0,
 | 
			
		||||
                    AvailableDate: new Date(0),
 | 
			
		||||
                    AvailableGiftDate: new Date(0),
 | 
			
		||||
                    RankUpExpiry: new Date(0),
 | 
			
		||||
                    BountyChemExpiry: new Date(0),
 | 
			
		||||
                    QueuedDialogues: [],
 | 
			
		||||
                    Gifts: [],
 | 
			
		||||
                    Booleans: [],
 | 
			
		||||
                    Completed: [],
 | 
			
		||||
                    DialogueName: dialogueName
 | 
			
		||||
                }) - 1
 | 
			
		||||
            ];
 | 
			
		||||
    }
 | 
			
		||||
    return dialogue;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICalendarProgress => {
 | 
			
		||||
    const currentSeason = getWorldState().KnownCalendarSeasons[0];
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -35,6 +35,7 @@ import {
 | 
			
		||||
    combineInventoryChanges,
 | 
			
		||||
    generateRewardSeed,
 | 
			
		||||
    getCalendarProgress,
 | 
			
		||||
    getDialogue,
 | 
			
		||||
    giveNemesisPetRecipe,
 | 
			
		||||
    giveNemesisWeaponRecipe,
 | 
			
		||||
    updateCurrency,
 | 
			
		||||
@ -63,7 +64,15 @@ import {
 | 
			
		||||
} from "@/src/helpers/nemesisHelpers";
 | 
			
		||||
import { Loadout } from "../models/inventoryModels/loadoutModel";
 | 
			
		||||
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
 | 
			
		||||
import { getLiteSortie, getSortie, idToBountyCycle, idToDay, idToWeek, pushClassicBounties } from "./worldStateService";
 | 
			
		||||
import {
 | 
			
		||||
    getLiteSortie,
 | 
			
		||||
    getSortie,
 | 
			
		||||
    getWorldState,
 | 
			
		||||
    idToBountyCycle,
 | 
			
		||||
    idToDay,
 | 
			
		||||
    idToWeek,
 | 
			
		||||
    pushClassicBounties
 | 
			
		||||
} from "./worldStateService";
 | 
			
		||||
import { config } from "./configService";
 | 
			
		||||
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
 | 
			
		||||
import { ISyndicateMissionInfo } from "../types/worldStateTypes";
 | 
			
		||||
@ -1188,8 +1197,9 @@ export const addMissionRewards = async (
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (rewardInfo.challengeMissionId) {
 | 
			
		||||
        const [syndicateTag, tierStr] = rewardInfo.challengeMissionId.split("_"); // TODO: third part in HexSyndicate jobs - Chemistry points
 | 
			
		||||
        const [syndicateTag, tierStr, chemistryStr] = rewardInfo.challengeMissionId.split("_");
 | 
			
		||||
        const tier = Number(tierStr);
 | 
			
		||||
        const chemistry = Number(chemistryStr);
 | 
			
		||||
        const isSteelPath = missions?.Tier;
 | 
			
		||||
        if (syndicateTag === "ZarimanSyndicate") {
 | 
			
		||||
            let medallionAmount = tier + 1;
 | 
			
		||||
@ -1206,6 +1216,23 @@ export const addMissionRewards = async (
 | 
			
		||||
            if (isSteelPath) standingAmount *= 1.5;
 | 
			
		||||
            AffiliationMods.push(addStanding(inventory, syndicateTag, standingAmount));
 | 
			
		||||
        }
 | 
			
		||||
        if (syndicateTag == "HexSyndicate" && chemistry && tier < 6) {
 | 
			
		||||
            const seed = getWorldState().SyndicateMissions.find(x => x.Tag == "HexSyndicate")!.Seed;
 | 
			
		||||
            const { nodes, buddies } = getHexBounties(seed);
 | 
			
		||||
            const buddy = buddies[tier];
 | 
			
		||||
            logger.debug(`Hex seed is ${seed}, giving chemistry for ${buddy}`);
 | 
			
		||||
            if (missions?.Tag != nodes[tier]) {
 | 
			
		||||
                logger.warn(
 | 
			
		||||
                    `Uh-oh, tier ${tier} bounty should've been on ${nodes[tier]} but you were just on ${missions?.Tag}`
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
            const tomorrowAt0Utc = config.noKimCooldowns
 | 
			
		||||
                ? Date.now()
 | 
			
		||||
                : (Math.trunc(Date.now() / 86400_000) + 1) * 86400_000;
 | 
			
		||||
            const dialogue = getDialogue(inventory, buddy);
 | 
			
		||||
            dialogue.Chemistry += chemistry;
 | 
			
		||||
            dialogue.BountyChemExpiry = new Date(tomorrowAt0Utc);
 | 
			
		||||
        }
 | 
			
		||||
        if (isSteelPath) {
 | 
			
		||||
            await addItem(inventory, "/Lotus/Types/Items/MiscItems/SteelEssence", 1);
 | 
			
		||||
            MissionRewards.push({
 | 
			
		||||
@ -1765,3 +1792,55 @@ const libraryPersonalTargetToAvatar: Record<string, string> = {
 | 
			
		||||
    "/Lotus/Types/Game/Library/Targets/Research10Target":
 | 
			
		||||
        "/Lotus/Types/Enemies/Corpus/Spaceman/AIWeek/NullifySpacemanAvatar"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const node_excluded_buddies: Record<string, string> = {
 | 
			
		||||
    SolNode856: "/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue",
 | 
			
		||||
    SolNode852: "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue",
 | 
			
		||||
    SolNode851: "/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue",
 | 
			
		||||
    SolNode850: "/Lotus/Types/Gameplay/1999Wf/Dialogue/EleanorDialogue_rom.dialogue",
 | 
			
		||||
    SolNode853: "/Lotus/Types/Gameplay/1999Wf/Dialogue/AoiDialogue_rom.dialogue",
 | 
			
		||||
    SolNode854: "/Lotus/Types/Gameplay/1999Wf/Dialogue/QuincyDialogue_rom.dialogue"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
const getHexBounties = (seed: number): { nodes: string[]; buddies: string[] } => {
 | 
			
		||||
    // We're gonna shuffle these arrays, so they're not truly 'const'.
 | 
			
		||||
    const nodes: string[] = [
 | 
			
		||||
        "SolNode850",
 | 
			
		||||
        "SolNode851",
 | 
			
		||||
        "SolNode852",
 | 
			
		||||
        "SolNode853",
 | 
			
		||||
        "SolNode854",
 | 
			
		||||
        "SolNode856",
 | 
			
		||||
        "SolNode858"
 | 
			
		||||
    ];
 | 
			
		||||
    const excludable_nodes: string[] = ["SolNode851", "SolNode852", "SolNode853", "SolNode854"];
 | 
			
		||||
    const buddies: string[] = [
 | 
			
		||||
        "/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue",
 | 
			
		||||
        "/Lotus/Types/Gameplay/1999Wf/Dialogue/AoiDialogue_rom.dialogue",
 | 
			
		||||
        "/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue",
 | 
			
		||||
        "/Lotus/Types/Gameplay/1999Wf/Dialogue/EleanorDialogue_rom.dialogue",
 | 
			
		||||
        "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue",
 | 
			
		||||
        "/Lotus/Types/Gameplay/1999Wf/Dialogue/QuincyDialogue_rom.dialogue"
 | 
			
		||||
    ];
 | 
			
		||||
 | 
			
		||||
    const rng = new SRng(seed);
 | 
			
		||||
    rng.shuffleArray(nodes);
 | 
			
		||||
    rng.shuffleArray(excludable_nodes);
 | 
			
		||||
    while (nodes.length > buddies.length) {
 | 
			
		||||
        nodes.splice(
 | 
			
		||||
            nodes.findIndex(x => x == excludable_nodes[0]),
 | 
			
		||||
            1
 | 
			
		||||
        );
 | 
			
		||||
        excludable_nodes.splice(0, 1);
 | 
			
		||||
    }
 | 
			
		||||
    rng.shuffleArray(buddies);
 | 
			
		||||
    for (let i = 0; i != 6; ++i) {
 | 
			
		||||
        if (buddies[i] == node_excluded_buddies[nodes[i]]) {
 | 
			
		||||
            const swapIdx = (i + 1) % buddies.length;
 | 
			
		||||
            const tmp = buddies[swapIdx];
 | 
			
		||||
            buddies[swapIdx] = buddies[i];
 | 
			
		||||
            buddies[i] = tmp;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return { nodes, buddies };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -115,4 +115,19 @@ export class SRng {
 | 
			
		||||
    randomReward<T extends { probability: number }>(pool: T[]): T | undefined {
 | 
			
		||||
        return getRewardAtPercentage(pool, this.randomFloat());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    churnSeed(its: number): void {
 | 
			
		||||
        while (its--) {
 | 
			
		||||
            this.state = (0x5851f42d4c957f2dn * this.state + 0x14057b7ef767814fn) & 0xffffffffffffffffn;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    shuffleArray<T>(arr: T[]): void {
 | 
			
		||||
        for (let lastIdx = arr.length - 1; lastIdx >= 1; --lastIdx) {
 | 
			
		||||
            const swapIdx = this.randomInt(0, lastIdx);
 | 
			
		||||
            const tmp = arr[swapIdx];
 | 
			
		||||
            arr[swapIdx] = arr[lastIdx];
 | 
			
		||||
            arr[lastIdx] = tmp;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user