feat: bounty chemistry bonus (#2070)
Re #388 Reviewed-on: #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 { 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,
|
||||||
@ -63,7 +64,15 @@ import {
|
|||||||
} from "@/src/helpers/nemesisHelpers";
|
} 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";
|
||||||
@ -1188,8 +1197,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;
|
||||||
@ -1206,6 +1216,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({
|
||||||
@ -1765,3 +1792,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