feat: bounty chemistry bonus #2070
@ -1,8 +1,7 @@
 | 
				
			|||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
 | 
					 | 
				
			||||||
import { config } from "@/src/services/configService";
 | 
					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 { 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 { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
				
			||||||
import { RequestHandler } from "express";
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -107,26 +106,3 @@ interface IOtherDialogueInfo {
 | 
				
			|||||||
    Tag: string;
 | 
					    Tag: string;
 | 
				
			||||||
    Value: number;
 | 
					    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,
 | 
					    ITraits,
 | 
				
			||||||
    ICalendarProgress,
 | 
					    ICalendarProgress,
 | 
				
			||||||
    INemesisWeaponTargetFingerprint,
 | 
					    INemesisWeaponTargetFingerprint,
 | 
				
			||||||
    INemesisPetTargetFingerprint
 | 
					    INemesisPetTargetFingerprint,
 | 
				
			||||||
 | 
					    IDialogueDatabase
 | 
				
			||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
 | 
					} from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
 | 
					import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
 | 
				
			||||||
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
 | 
					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 => {
 | 
					export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICalendarProgress => {
 | 
				
			||||||
    const currentSeason = getWorldState().KnownCalendarSeasons[0];
 | 
					    const currentSeason = getWorldState().KnownCalendarSeasons[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -35,6 +35,7 @@ import {
 | 
				
			|||||||
    combineInventoryChanges,
 | 
					    combineInventoryChanges,
 | 
				
			||||||
    generateRewardSeed,
 | 
					    generateRewardSeed,
 | 
				
			||||||
    getCalendarProgress,
 | 
					    getCalendarProgress,
 | 
				
			||||||
 | 
					    getDialogue,
 | 
				
			||||||
    giveNemesisPetRecipe,
 | 
					    giveNemesisPetRecipe,
 | 
				
			||||||
    giveNemesisWeaponRecipe,
 | 
					    giveNemesisWeaponRecipe,
 | 
				
			||||||
    updateCurrency,
 | 
					    updateCurrency,
 | 
				
			||||||
@ -58,7 +59,15 @@ import conservationAnimals from "@/static/fixed_responses/conservationAnimals.js
 | 
				
			|||||||
import { getInfNodes, getWeaponsForManifest, sendCodaFinishedMessage } from "@/src/helpers/nemesisHelpers";
 | 
					import { getInfNodes, getWeaponsForManifest, sendCodaFinishedMessage } from "@/src/helpers/nemesisHelpers";
 | 
				
			||||||
import { Loadout } from "../models/inventoryModels/loadoutModel";
 | 
					import { Loadout } from "../models/inventoryModels/loadoutModel";
 | 
				
			||||||
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
 | 
					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 { config } from "./configService";
 | 
				
			||||||
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
 | 
					import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
 | 
				
			||||||
import { ISyndicateMissionInfo } from "../types/worldStateTypes";
 | 
					import { ISyndicateMissionInfo } from "../types/worldStateTypes";
 | 
				
			||||||
@ -1175,8 +1184,9 @@ export const addMissionRewards = async (
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (rewardInfo.challengeMissionId) {
 | 
					    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 tier = Number(tierStr);
 | 
				
			||||||
 | 
					        const chemistry = Number(chemistryStr);
 | 
				
			||||||
        const isSteelPath = missions?.Tier;
 | 
					        const isSteelPath = missions?.Tier;
 | 
				
			||||||
        if (syndicateTag === "ZarimanSyndicate") {
 | 
					        if (syndicateTag === "ZarimanSyndicate") {
 | 
				
			||||||
            let medallionAmount = tier + 1;
 | 
					            let medallionAmount = tier + 1;
 | 
				
			||||||
@ -1193,6 +1203,23 @@ export const addMissionRewards = async (
 | 
				
			|||||||
            if (isSteelPath) standingAmount *= 1.5;
 | 
					            if (isSteelPath) standingAmount *= 1.5;
 | 
				
			||||||
            AffiliationMods.push(addStanding(inventory, syndicateTag, standingAmount));
 | 
					            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) {
 | 
					        if (isSteelPath) {
 | 
				
			||||||
            await addItem(inventory, "/Lotus/Types/Items/MiscItems/SteelEssence", 1);
 | 
					            await addItem(inventory, "/Lotus/Types/Items/MiscItems/SteelEssence", 1);
 | 
				
			||||||
            MissionRewards.push({
 | 
					            MissionRewards.push({
 | 
				
			||||||
@ -1721,3 +1748,55 @@ const libraryPersonalTargetToAvatar: Record<string, string> = {
 | 
				
			|||||||
    "/Lotus/Types/Game/Library/Targets/Research10Target":
 | 
					    "/Lotus/Types/Game/Library/Targets/Research10Target":
 | 
				
			||||||
        "/Lotus/Types/Enemies/Corpus/Spaceman/AIWeek/NullifySpacemanAvatar"
 | 
					        "/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 {
 | 
					    randomReward<T extends { probability: number }>(pool: T[]): T | undefined {
 | 
				
			||||||
        return getRewardAtPercentage(pool, this.randomFloat());
 | 
					        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