Compare commits

...

7 Commits

Author SHA1 Message Date
541ec3d702 feat: claiming of tennolive relay's secret (#2569)
Reviewed-on: OpenWF/SpaceNinjaServer#2569
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-30 01:51:07 -07:00
0a28eab65d feat: worldState.tennoLiveRelay config (#2568)
Re #2531

Reviewed-on: OpenWF/SpaceNinjaServer#2568
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-30 01:50:43 -07:00
8e639a16bd feat: initial protovyre/evolving cosmetics (#2566)
Basic handling of sending the challenge rewards to the inbox upon completion.

Re #2485. Still missing handling for the Protovyre armor pieces which require killing sentients.

Reviewed-on: OpenWF/SpaceNinjaServer#2566
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-30 01:50:23 -07:00
522924a823 chore: remove empty ModularParts arrays from equipment (#2565)
Reviewed-on: OpenWF/SpaceNinjaServer#2565
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-30 01:49:55 -07:00
48e3f324e2 chore: log when worldState time is behind real time + make sure client knows fissures are active (#2562)
Reviewed-on: OpenWF/SpaceNinjaServer#2562
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-07-30 01:49:34 -07:00
8f77c722cb chore(webui): update German translation (#2564)
Reviewed-on: OpenWF/SpaceNinjaServer#2564
Co-authored-by: Animan8000 <animan8000@noreply.localhost>
Co-committed-by: Animan8000 <animan8000@noreply.localhost>
2025-07-29 07:34:04 -07:00
e7287933b5 chore(webui): update Chinese translation (#2563)
Reviewed-on: OpenWF/SpaceNinjaServer#2563
Co-authored-by: Corvus <corvus@noreply.localhost>
Co-committed-by: Corvus <corvus@noreply.localhost>
2025-07-29 07:33:57 -07:00
14 changed files with 162 additions and 25 deletions

View File

@ -70,6 +70,7 @@
"creditBoost": false, "creditBoost": false,
"affinityBoost": false, "affinityBoost": false,
"resourceBoost": false, "resourceBoost": false,
"tennoLiveRelay": false,
"starDays": true, "starDays": true,
"galleonOfGhouls": 0, "galleonOfGhouls": 0,
"eidolonOverride": "", "eidolonOverride": "",

View File

@ -10,6 +10,7 @@ import { logger } from "@/src/utils/logger";
export const updateChallengeProgressController: RequestHandler = async (req, res) => { export const updateChallengeProgressController: RequestHandler = async (req, res) => {
const challenges = getJSONfromString<IUpdateChallengeProgressRequest>(String(req.body)); const challenges = getJSONfromString<IUpdateChallengeProgressRequest>(String(req.body));
const account = await getAccountForRequest(req); const account = await getAccountForRequest(req);
logger.debug(`challenge report:`, challenges);
const inventory = await getInventory( const inventory = await getInventory(
account._id.toString(), account._id.toString(),
@ -17,7 +18,7 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
); );
let affiliationMods: IAffiliationMods[] = []; let affiliationMods: IAffiliationMods[] = [];
if (challenges.ChallengeProgress) { if (challenges.ChallengeProgress) {
affiliationMods = addChallenges( affiliationMods = await addChallenges(
account, account,
inventory, inventory,
challenges.ChallengeProgress, challenges.ChallengeProgress,

View File

@ -81,6 +81,7 @@ export interface IConfig {
creditBoost?: boolean; creditBoost?: boolean;
affinityBoost?: boolean; affinityBoost?: boolean;
resourceBoost?: boolean; resourceBoost?: boolean;
tennoLiveRelay?: boolean;
starDays?: boolean; starDays?: boolean;
galleonOfGhouls?: number; galleonOfGhouls?: number;
eidolonOverride?: string; eidolonOverride?: string;

View File

@ -25,7 +25,8 @@ import {
INemesisWeaponTargetFingerprint, INemesisWeaponTargetFingerprint,
INemesisPetTargetFingerprint, INemesisPetTargetFingerprint,
IDialogueDatabase, IDialogueDatabase,
IKubrowPetPrintClient IKubrowPetPrintClient,
equipmentKeys
} from "@/src/types/inventoryTypes/inventoryTypes"; } from "@/src/types/inventoryTypes/inventoryTypes";
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "@/src/types/genericUpdate"; import { IGenericUpdate, IUpdateNodeIntrosResponse } from "@/src/types/genericUpdate";
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "@/src/types/requestTypes"; import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";
@ -1341,7 +1342,7 @@ export const addStanding = (
// TODO: AffiliationMods support (Nightwave). // TODO: AffiliationMods support (Nightwave).
export const updateGeneric = async (data: IGenericUpdate, accountId: string): Promise<IUpdateNodeIntrosResponse> => { export const updateGeneric = async (data: IGenericUpdate, accountId: string): Promise<IUpdateNodeIntrosResponse> => {
const inventory = await getInventory(accountId, "NodeIntrosCompleted MiscItems"); const inventory = await getInventory(accountId, "NodeIntrosCompleted MiscItems ShipDecorations");
// Make it an array for easier parsing. // Make it an array for easier parsing.
if (typeof data.NodeIntrosCompleted === "string") { if (typeof data.NodeIntrosCompleted === "string") {
@ -1350,7 +1351,15 @@ export const updateGeneric = async (data: IGenericUpdate, accountId: string): Pr
const inventoryChanges: IInventoryChanges = {}; const inventoryChanges: IInventoryChanges = {};
for (const node of data.NodeIntrosCompleted) { for (const node of data.NodeIntrosCompleted) {
if (node == "KayaFirstVisitPack") { if (node == "TC2025") {
inventoryChanges.ShipDecorations = [
{
ItemType: "/Lotus/Types/Items/ShipDecos/TauGrineerLancerBobbleHead",
ItemCount: 1
}
];
addShipDecorations(inventory, inventoryChanges.ShipDecorations);
} else if (node == "KayaFirstVisitPack") {
inventoryChanges.MiscItems = [ inventoryChanges.MiscItems = [
{ {
ItemType: "/Lotus/Types/Items/MiscItems/1999FixedStickersPack", ItemType: "/Lotus/Types/Items/MiscItems/1999FixedStickersPack",
@ -1903,25 +1912,87 @@ export const addLoreFragmentScans = (inventory: TInventoryDatabaseDocument, arr:
}); });
}; };
export const addChallenges = ( const challengeRewardsInboxMessages: Record<string, IMessageCreationTemplate> = {
SentEvoEphemeraRankOne: {
sub: "/Lotus/Language/Inbox/EvolvingEphemeraUnlockAName",
sndr: "/Lotus/Language/Bosses/Ordis",
msg: "/Lotus/Language/Inbox/EvolvingEphemeraUnlockADesc",
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
att: ["/Lotus/Upgrades/Skins/Effects/NarmerEvolvingEphemeraB"]
},
SentEvoEphemeraRankTwo: {
sub: "/Lotus/Language/Inbox/EvolvingEphemeraUnlockBName",
sndr: "/Lotus/Language/Bosses/Ordis",
msg: "/Lotus/Language/Inbox/EvolvingEphemeraUnlockBDesc",
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
att: ["/Lotus/Upgrades/Skins/Effects/NarmerEvolvingEphemeraC"]
},
SentEvoSyandanaRankOne: {
sub: "/Lotus/Language/Inbox/EvolvingSyandanaUnlockAName",
sndr: "/Lotus/Language/Bosses/Ordis",
msg: "/Lotus/Language/Inbox/EvolvingSyandanaUnlockADesc",
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
att: ["/Lotus/Upgrades/Skins/Scarves/NarmerEvolvingSyandanaBCape"]
},
SentEvoSyandanaRankTwo: {
sub: "/Lotus/Language/Inbox/EvolvingSyandanaUnlockBName",
sndr: "/Lotus/Language/Bosses/Ordis",
msg: "/Lotus/Language/Inbox/EvolvingSyandanaUnlockBDesc",
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
att: ["/Lotus/Upgrades/Skins/Scarves/NarmerEvolvingSyandanaCCape"]
},
SentEvoSekharaRankOne: {
sub: "/Lotus/Language/Inbox/EvolvingSekharaUnlockAName",
sndr: "/Lotus/Language/Bosses/Ordis",
msg: "/Lotus/Language/Inbox/EvolvingSekharaUnlockADesc",
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
att: ["/Lotus/Upgrades/Skins/Clan/ZarimanEvolvingSekharaBadgeItemB"]
},
SentEvoSekharaRankTwo: {
sub: "/Lotus/Language/Inbox/EvolvingSekharaUnlockBName",
sndr: "/Lotus/Language/Bosses/Ordis",
msg: "/Lotus/Language/Inbox/EvolvingSekharaUnlockBDesc",
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
att: ["/Lotus/Upgrades/Skins/Clan/ZarimanEvolvingSekharaBadgeItemC"]
}
};
export const addChallenges = async (
account: TAccountDocument, account: TAccountDocument,
inventory: TInventoryDatabaseDocument, inventory: TInventoryDatabaseDocument,
ChallengeProgress: IChallengeProgress[], ChallengeProgress: IChallengeProgress[],
SeasonChallengeCompletions: ISeasonChallenge[] | undefined SeasonChallengeCompletions: ISeasonChallenge[] | undefined
): IAffiliationMods[] => { ): Promise<IAffiliationMods[]> => {
ChallengeProgress.forEach(({ Name, Progress }) => { for (const { Name, Progress, Completed } of ChallengeProgress) {
const itemIndex = inventory.ChallengeProgress.findIndex(i => i.Name === Name); let dbChallenge = inventory.ChallengeProgress.find(x => x.Name == Name);
if (dbChallenge) {
if (itemIndex !== -1) { dbChallenge.Progress = Progress;
inventory.ChallengeProgress[itemIndex].Progress = Progress;
} else { } else {
inventory.ChallengeProgress.push({ Name, Progress }); dbChallenge = { Name, Progress };
inventory.ChallengeProgress.push(dbChallenge);
} }
if (Name.startsWith("Calendar")) { if (Name.startsWith("Calendar")) {
addString(getCalendarProgress(inventory).SeasonProgress.ActivatedChallenges, Name); addString(getCalendarProgress(inventory).SeasonProgress.ActivatedChallenges, Name);
} }
});
if ((Completed?.length ?? 0) > (dbChallenge.Completed?.length ?? 0)) {
dbChallenge.Completed ??= [];
for (const completion of Completed!) {
if (dbChallenge.Completed.indexOf(completion) == -1) {
if (completion == "challengeRewards") {
if (Name in challengeRewardsInboxMessages) {
await createMessage(account._id, [challengeRewardsInboxMessages[Name]]);
dbChallenge.Completed.push(completion);
// Would love to somehow let the client know about inbox or inventory changes, but there doesn't seem to anything for updateChallengeProgress.
continue;
}
}
logger.warn(`ignoring unknown challenge completion`, { challenge: Name, completion });
}
}
}
}
const affiliationMods: IAffiliationMods[] = []; const affiliationMods: IAffiliationMods[] = [];
if (SeasonChallengeCompletions) { if (SeasonChallengeCompletions) {
@ -2117,6 +2188,21 @@ export const cleanupInventory = (inventory: TInventoryDatabaseDocument): void =>
inventory.LotusCustomization.syancol = {}; inventory.LotusCustomization.syancol = {};
} }
} }
{
let numFixed = 0;
for (const equipmentKey of equipmentKeys) {
for (const item of inventory[equipmentKey]) {
if (item.ModularParts?.length === 0) {
item.ModularParts = undefined;
++numFixed;
}
}
}
if (numFixed != 0) {
logger.debug(`removed ModularParts from ${numFixed} non-modular items`);
}
}
}; };
export const getDialogue = (inventory: TInventoryDatabaseDocument, dialogueName: string): IDialogueDatabase => { export const getDialogue = (inventory: TInventoryDatabaseDocument, dialogueName: string): IDialogueDatabase => {

View File

@ -292,7 +292,7 @@ export const addMissionInventoryUpdates = async (
addRecipes(inventory, value); addRecipes(inventory, value);
break; break;
case "ChallengeProgress": case "ChallengeProgress":
addChallenges(account, inventory, value, inventoryUpdates.SeasonChallengeCompletions); await addChallenges(account, inventory, value, inventoryUpdates.SeasonChallengeCompletions);
break; break;
case "FusionTreasures": case "FusionTreasures":
addFusionTreasures(inventory, value); addFusionTreasures(inventory, value);

View File

@ -1038,13 +1038,13 @@ const pushVoidStorms = (arr: IVoidStorm[], hour: number): void => {
}; };
interface ITimeConstraint { interface ITimeConstraint {
//name: string; name: string;
isValidTime: (timeSecs: number) => boolean; isValidTime: (timeSecs: number) => boolean;
getIdealTimeBefore: (timeSecs: number) => number; getIdealTimeBefore: (timeSecs: number) => number;
} }
const eidolonDayConstraint: ITimeConstraint = { const eidolonDayConstraint: ITimeConstraint = {
//name: "eidolon day", name: "eidolon day",
isValidTime: (timeSecs: number): boolean => { isValidTime: (timeSecs: number): boolean => {
const eidolonEpoch = 1391992660; const eidolonEpoch = 1391992660;
const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000); const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
@ -1062,7 +1062,7 @@ const eidolonDayConstraint: ITimeConstraint = {
}; };
const eidolonNightConstraint: ITimeConstraint = { const eidolonNightConstraint: ITimeConstraint = {
//name: "eidolon night", name: "eidolon night",
isValidTime: (timeSecs: number): boolean => { isValidTime: (timeSecs: number): boolean => {
const eidolonEpoch = 1391992660; const eidolonEpoch = 1391992660;
const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000); const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
@ -1089,7 +1089,7 @@ const eidolonNightConstraint: ITimeConstraint = {
}; };
const venusColdConstraint: ITimeConstraint = { const venusColdConstraint: ITimeConstraint = {
//name: "venus cold", name: "venus cold",
isValidTime: (timeSecs: number): boolean => { isValidTime: (timeSecs: number): boolean => {
const vallisEpoch = 1541837628; const vallisEpoch = 1541837628;
const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600); const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
@ -1115,7 +1115,7 @@ const venusColdConstraint: ITimeConstraint = {
}; };
const venusWarmConstraint: ITimeConstraint = { const venusWarmConstraint: ITimeConstraint = {
//name: "venus warm", name: "venus warm",
isValidTime: (timeSecs: number): boolean => { isValidTime: (timeSecs: number): boolean => {
const vallisEpoch = 1541837628; const vallisEpoch = 1541837628;
const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600); const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
@ -1321,7 +1321,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
}); });
} else { } else {
constraints.push({ constraints.push({
//name: `duviri ${config.worldState.duviriOverride}`, name: `duviri ${config.worldState.duviriOverride}`,
isValidTime: (timeSecs: number): boolean => { isValidTime: (timeSecs: number): boolean => {
const moodIndex = Math.trunc(timeSecs / 7200); const moodIndex = Math.trunc(timeSecs / 7200);
return moodIndex % 5 == desiredMood; return moodIndex % 5 == desiredMood;
@ -1336,6 +1336,14 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
} }
} }
const timeSecs = getIdealTimeSatsifyingConstraints(constraints); const timeSecs = getIdealTimeSatsifyingConstraints(constraints);
if (constraints.length != 0) {
const delta = Math.trunc(Date.now() / 1000) - timeSecs;
if (delta > 1) {
logger.debug(
`reported time is ${delta} seconds behind real time to satisfy selected constraints (${constraints.map(x => x.name).join(", ")})`
);
}
}
const timeMs = timeSecs * 1000; const timeMs = timeSecs * 1000;
const day = Math.trunc((timeMs - EPOCH) / 86400000); const day = Math.trunc((timeMs - EPOCH) / 86400000);
const week = Math.trunc(day / 7); const week = Math.trunc(day / 7);
@ -1367,6 +1375,32 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
worldState.PVPChallengeInstances = []; worldState.PVPChallengeInstances = [];
} }
if (config.worldState?.tennoLiveRelay) {
worldState.Goals.push({
_id: {
$oid: "687bf9400000000000000000"
},
Activation: {
$date: {
$numberLong: "1752955200000"
}
},
Expiry: {
$date: {
$numberLong: "2000000000000"
}
},
Count: 0,
Goal: 0,
Success: 0,
Personal: true,
Desc: "/Lotus/Language/Locations/RelayStationTennoConB",
ToolTip: "/Lotus/Language/Locations/RelayStationTennoConDescB",
Icon: "/Lotus/Interface/Icons/Categories/IconTennoLive.png",
Tag: "TennoConRelayB",
Node: "TennoConBHUB6"
});
}
if (config.worldState?.starDays) { if (config.worldState?.starDays) {
worldState.Goals.push({ worldState.Goals.push({
_id: { $oid: "67a4dcce2a198564d62e1647" }, _id: { $oid: "67a4dcce2a198564d62e1647" },
@ -1823,7 +1857,10 @@ export const populateFissures = async (worldState: IWorldState): Promise<void> =
_id: toOid(fissure._id), _id: toOid(fissure._id),
Region: meta.systemIndex + 1, Region: meta.systemIndex + 1,
Seed: 1337, Seed: 1337,
Activation: toMongoDate(fissure.Activation), Activation:
fissure.Activation.getTime() < Date.now() // Activation is in the past?
? { $date: { $numberLong: "1000000000000" } } // Let the client know 'explicitly' to avoid interference from time constraints.
: toMongoDate(fissure.Activation),
Expiry: toMongoDate(fissure.Expiry), Expiry: toMongoDate(fissure.Expiry),
Node: fissure.Node, Node: fissure.Node,
MissionType: eMissionType[meta.missionIndex].tag, MissionType: eMissionType[meta.missionIndex].tag,

View File

@ -74,6 +74,7 @@ export type IInventoryChanges = {
InfestedFoundry?: IInfestedFoundryClient; InfestedFoundry?: IInfestedFoundryClient;
Drones?: IDroneClient[]; Drones?: IDroneClient[];
MiscItems?: IMiscItem[]; MiscItems?: IMiscItem[];
ShipDecorations?: ITypeCount[];
EmailItems?: ITypeCount[]; EmailItems?: ITypeCount[];
CrewShipRawSalvage?: ITypeCount[]; CrewShipRawSalvage?: ITypeCount[];
Nemesis?: Partial<INemesisClient>; Nemesis?: Partial<INemesisClient>;

View File

@ -925,6 +925,10 @@
<input class="form-check-input" type="checkbox" id="worldState.resourceBoost" /> <input class="form-check-input" type="checkbox" id="worldState.resourceBoost" />
<label class="form-check-label" for="worldState.resourceBoost" data-loc="worldState_resourceBoost"></label> <label class="form-check-label" for="worldState.resourceBoost" data-loc="worldState_resourceBoost"></label>
</div> </div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="worldState.tennoLiveRelay" />
<label class="form-check-label" for="worldState.tennoLiveRelay" data-loc="worldState_tennoLiveRelay"></label>
</div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="worldState.starDays" /> <input class="form-check-input" type="checkbox" id="worldState.starDays" />
<label class="form-check-label" for="worldState.starDays" data-loc="worldState_starDays"></label> <label class="form-check-label" for="worldState.starDays" data-loc="worldState_starDays"></label>

View File

@ -156,8 +156,8 @@ dict = {
invigorations_defensiveLabel: `Defensives Upgrade`, invigorations_defensiveLabel: `Defensives Upgrade`,
invigorations_expiryLabel: `Upgrades Ablaufdatum (optional)`, invigorations_expiryLabel: `Upgrades Ablaufdatum (optional)`,
abilityOverride_label: `[UNTRANSLATED] Ability Override`, abilityOverride_label: `Fähigkeitsüberschreibung`,
abilityOverride_onSlot: `[UNTRANSLATED] on slot`, abilityOverride_onSlot: `auf Slot`,
mods_addRiven: `Riven hinzufügen`, mods_addRiven: `Riven hinzufügen`,
mods_fingerprint: `Fingerabdruck`, mods_fingerprint: `Fingerabdruck`,
@ -242,6 +242,7 @@ dict = {
worldState_creditBoost: `Event Booster: Credit`, worldState_creditBoost: `Event Booster: Credit`,
worldState_affinityBoost: `Event Booster: Erfahrung`, worldState_affinityBoost: `Event Booster: Erfahrung`,
worldState_resourceBoost: `Event Booster: Ressourcen`, worldState_resourceBoost: `Event Booster: Ressourcen`,
worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`,
worldState_starDays: `Sternen-Tage`, worldState_starDays: `Sternen-Tage`,
worldState_galleonOfGhouls: `Galeone der Ghule`, worldState_galleonOfGhouls: `Galeone der Ghule`,
disabled: `Deaktiviert`, disabled: `Deaktiviert`,

View File

@ -241,6 +241,7 @@ dict = {
worldState_creditBoost: `Credit Boost`, worldState_creditBoost: `Credit Boost`,
worldState_affinityBoost: `Affinity Boost`, worldState_affinityBoost: `Affinity Boost`,
worldState_resourceBoost: `Resource Boost`, worldState_resourceBoost: `Resource Boost`,
worldState_tennoLiveRelay: `TennoLive Relay`,
worldState_starDays: `Star Days`, worldState_starDays: `Star Days`,
worldState_galleonOfGhouls: `Galleon of Ghouls`, worldState_galleonOfGhouls: `Galleon of Ghouls`,
disabled: `Disabled`, disabled: `Disabled`,

View File

@ -242,6 +242,7 @@ dict = {
worldState_creditBoost: `Potenciador de Créditos`, worldState_creditBoost: `Potenciador de Créditos`,
worldState_affinityBoost: `Potenciador de Afinidad`, worldState_affinityBoost: `Potenciador de Afinidad`,
worldState_resourceBoost: `Potenciador de Recursos`, worldState_resourceBoost: `Potenciador de Recursos`,
worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`,
worldState_starDays: `Días estelares`, worldState_starDays: `Días estelares`,
worldState_galleonOfGhouls: `Galeón de Gules`, worldState_galleonOfGhouls: `Galeón de Gules`,
disabled: `Desactivado`, disabled: `Desactivado`,

View File

@ -242,6 +242,7 @@ dict = {
worldState_creditBoost: `Booster de Crédit`, worldState_creditBoost: `Booster de Crédit`,
worldState_affinityBoost: `Booster d'Affinité`, worldState_affinityBoost: `Booster d'Affinité`,
worldState_resourceBoost: `Booster de Ressource`, worldState_resourceBoost: `Booster de Ressource`,
worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`,
worldState_starDays: `Jours Stellaires`, worldState_starDays: `Jours Stellaires`,
worldState_galleonOfGhouls: `Galion des Goules`, worldState_galleonOfGhouls: `Galion des Goules`,
disabled: `Désactivé`, disabled: `Désactivé`,

View File

@ -242,6 +242,7 @@ dict = {
worldState_creditBoost: `[UNTRANSLATED] Credit Boost`, worldState_creditBoost: `[UNTRANSLATED] Credit Boost`,
worldState_affinityBoost: `[UNTRANSLATED] Affinity Boost`, worldState_affinityBoost: `[UNTRANSLATED] Affinity Boost`,
worldState_resourceBoost: `[UNTRANSLATED] Resource Boost`, worldState_resourceBoost: `[UNTRANSLATED] Resource Boost`,
worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`,
worldState_starDays: `[UNTRANSLATED] Star Days`, worldState_starDays: `[UNTRANSLATED] Star Days`,
worldState_galleonOfGhouls: `[UNTRANSLATED] Galleon of Ghouls`, worldState_galleonOfGhouls: `[UNTRANSLATED] Galleon of Ghouls`,
disabled: `[UNTRANSLATED] Disabled`, disabled: `[UNTRANSLATED] Disabled`,

View File

@ -156,8 +156,8 @@ dict = {
invigorations_defensiveLabel: `功能型属性`, invigorations_defensiveLabel: `功能型属性`,
invigorations_expiryLabel: `活化时效(可选)`, invigorations_expiryLabel: `活化时效(可选)`,
abilityOverride_label: `[UNTRANSLATED] Ability Override`, abilityOverride_label: `技能替换`,
abilityOverride_onSlot: `[UNTRANSLATED] on slot`, abilityOverride_onSlot: `槽位`,
mods_addRiven: `添加裂罅MOD`, mods_addRiven: `添加裂罅MOD`,
mods_fingerprint: `印记`, mods_fingerprint: `印记`,
@ -242,6 +242,7 @@ dict = {
worldState_creditBoost: `现金加成`, worldState_creditBoost: `现金加成`,
worldState_affinityBoost: `经验加成`, worldState_affinityBoost: `经验加成`,
worldState_resourceBoost: `资源加成`, worldState_resourceBoost: `资源加成`,
worldState_tennoLiveRelay: `[UNTRANSLATED] TennoLive Relay`,
worldState_starDays: `活动:星日`, worldState_starDays: `活动:星日`,
worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`, worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`,
disabled: `关闭/取消配置`, disabled: `关闭/取消配置`,