forked from OpenWF/SpaceNinjaServer
feat: argon crystal decay (#1195)
Reviewed-on: OpenWF/SpaceNinjaServer#1195
This commit is contained in:
parent
2f59b3d775
commit
2d6e096fde
@ -29,6 +29,7 @@
|
|||||||
"unlockExilusEverywhere": false,
|
"unlockExilusEverywhere": false,
|
||||||
"unlockArcanesEverywhere": false,
|
"unlockArcanesEverywhere": false,
|
||||||
"noDailyStandingLimits": false,
|
"noDailyStandingLimits": false,
|
||||||
|
"noArgonCrystalDecay": false,
|
||||||
"noVendorPurchaseLimits": true,
|
"noVendorPurchaseLimits": true,
|
||||||
"instantResourceExtractorDrones": false,
|
"instantResourceExtractorDrones": false,
|
||||||
"noDojoRoomBuildStage": false,
|
"noDojoRoomBuildStage": false,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { Inventory, TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { Inventory, TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import allDialogue from "@/static/fixed_responses/allDialogue.json";
|
import allDialogue from "@/static/fixed_responses/allDialogue.json";
|
||||||
@ -14,12 +14,13 @@ import {
|
|||||||
ExportVirtuals
|
ExportVirtuals
|
||||||
} from "warframe-public-export-plus";
|
} from "warframe-public-export-plus";
|
||||||
import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "./infestedFoundryController";
|
import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "./infestedFoundryController";
|
||||||
import { allDailyAffiliationKeys, createLibraryDailyTask } from "@/src/services/inventoryService";
|
import { addMiscItems, allDailyAffiliationKeys, createLibraryDailyTask } from "@/src/services/inventoryService";
|
||||||
|
import { logger } from "@/src/utils/logger";
|
||||||
|
|
||||||
export const inventoryController: RequestHandler = async (request, response) => {
|
export const inventoryController: RequestHandler = async (request, response) => {
|
||||||
const account = await getAccountForRequest(request);
|
const accountId = await getAccountIdForRequest(request);
|
||||||
|
|
||||||
const inventory = await Inventory.findOne({ accountOwnerId: account._id.toString() });
|
const inventory = await Inventory.findOne({ accountOwnerId: accountId });
|
||||||
|
|
||||||
if (!inventory) {
|
if (!inventory) {
|
||||||
response.status(400).json({ error: "inventory was undefined" });
|
response.status(400).json({ error: "inventory was undefined" });
|
||||||
@ -27,11 +28,7 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handle daily reset
|
// Handle daily reset
|
||||||
const today: number = Math.trunc(new Date().getTime() / 86400000);
|
if (!inventory.NextRefill || Date.now() >= inventory.NextRefill.getTime()) {
|
||||||
if (account.LastLoginDay != today) {
|
|
||||||
account.LastLoginDay = today;
|
|
||||||
await account.save();
|
|
||||||
|
|
||||||
for (const key of allDailyAffiliationKeys) {
|
for (const key of allDailyAffiliationKeys) {
|
||||||
inventory[key] = 16000 + inventory.PlayerLevel * 500;
|
inventory[key] = 16000 + inventory.PlayerLevel * 500;
|
||||||
}
|
}
|
||||||
@ -39,6 +36,45 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
|||||||
|
|
||||||
inventory.LibraryAvailableDailyTaskInfo = createLibraryDailyTask();
|
inventory.LibraryAvailableDailyTaskInfo = createLibraryDailyTask();
|
||||||
|
|
||||||
|
if (inventory.NextRefill) {
|
||||||
|
if (config.noArgonCrystalDecay) {
|
||||||
|
inventory.FoundToday = undefined;
|
||||||
|
} else {
|
||||||
|
const lastLoginDay = Math.trunc(inventory.NextRefill.getTime() / 86400000) - 1;
|
||||||
|
const today = Math.trunc(Date.now() / 86400000);
|
||||||
|
const daysPassed = today - lastLoginDay;
|
||||||
|
for (let i = 0; i != daysPassed; ++i) {
|
||||||
|
const numArgonCrystals =
|
||||||
|
inventory.MiscItems.find(x => x.ItemType == "/Lotus/Types/Items/MiscItems/ArgonCrystal")
|
||||||
|
?.ItemCount ?? 0;
|
||||||
|
if (numArgonCrystals == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
const numStableArgonCrystals =
|
||||||
|
inventory.FoundToday?.find(x => x.ItemType == "/Lotus/Types/Items/MiscItems/ArgonCrystal")
|
||||||
|
?.ItemCount ?? 0;
|
||||||
|
const numDecayingArgonCrystals = numArgonCrystals - numStableArgonCrystals;
|
||||||
|
const numDecayingArgonCrystalsToRemove = Math.ceil(numDecayingArgonCrystals / 2);
|
||||||
|
logger.debug(`ticking argon crystals for day ${i + 1} of ${daysPassed}`, {
|
||||||
|
numArgonCrystals,
|
||||||
|
numStableArgonCrystals,
|
||||||
|
numDecayingArgonCrystals,
|
||||||
|
numDecayingArgonCrystalsToRemove
|
||||||
|
});
|
||||||
|
// Remove half of owned decaying argon crystals
|
||||||
|
addMiscItems(inventory, [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/ArgonCrystal",
|
||||||
|
ItemCount: numDecayingArgonCrystalsToRemove * -1
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
// All stable argon crystals are now decaying
|
||||||
|
inventory.FoundToday = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inventory.NextRefill = new Date((Math.trunc(Date.now() / 86400000) + 1) * 86400000);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,9 +255,6 @@ export const getInventoryResponse = async (
|
|||||||
applyCheatsToInfestedFoundry(inventoryResponse.InfestedFoundry);
|
applyCheatsToInfestedFoundry(inventoryResponse.InfestedFoundry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix for #380
|
|
||||||
inventoryResponse.NextRefill = { $date: { $numberLong: "9999999999999" } };
|
|
||||||
|
|
||||||
// This determines if the "void fissures" tab is shown in navigation.
|
// This determines if the "void fissures" tab is shown in navigation.
|
||||||
inventoryResponse.HasOwnedVoidProjectionsPreviously = true;
|
inventoryResponse.HasOwnedVoidProjectionsPreviously = true;
|
||||||
|
|
||||||
|
@ -1161,7 +1161,8 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
ChallengeProgress: [challengeProgressSchema],
|
ChallengeProgress: [challengeProgressSchema],
|
||||||
|
|
||||||
//Account Item like Ferrite,Form,Kuva etc
|
//Account Item like Ferrite,Form,Kuva etc
|
||||||
MiscItems: [typeCountSchema],
|
MiscItems: { type: [typeCountSchema], default: [] },
|
||||||
|
FoundToday: { type: [typeCountSchema], default: undefined },
|
||||||
|
|
||||||
//Non Upgrade Mods Example:I have 999 item WeaponElectricityDamageMod (only "ItemCount"+"ItemType")
|
//Non Upgrade Mods Example:I have 999 item WeaponElectricityDamageMod (only "ItemCount"+"ItemType")
|
||||||
RawUpgrades: [RawUpgrades],
|
RawUpgrades: [RawUpgrades],
|
||||||
@ -1360,7 +1361,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
//https://warframe.fandom.com/wiki/Helminth
|
//https://warframe.fandom.com/wiki/Helminth
|
||||||
InfestedFoundry: infestedFoundrySchema,
|
InfestedFoundry: infestedFoundrySchema,
|
||||||
|
|
||||||
NextRefill: Schema.Types.Mixed, // Date, convert to IMongoDate
|
NextRefill: { type: Date, default: undefined },
|
||||||
|
|
||||||
//Purchase this new permanent skin from the Lotus customization options in Personal Quarters located in your Orbiter.
|
//Purchase this new permanent skin from the Lotus customization options in Personal Quarters located in your Orbiter.
|
||||||
//https://warframe.fandom.com/wiki/Lotus#The_New_War
|
//https://warframe.fandom.com/wiki/Lotus#The_New_War
|
||||||
@ -1435,6 +1436,9 @@ inventorySchema.set("toJSON", {
|
|||||||
if (inventoryDatabase.BlessingCooldown) {
|
if (inventoryDatabase.BlessingCooldown) {
|
||||||
inventoryResponse.BlessingCooldown = toMongoDate(inventoryDatabase.BlessingCooldown);
|
inventoryResponse.BlessingCooldown = toMongoDate(inventoryDatabase.BlessingCooldown);
|
||||||
}
|
}
|
||||||
|
if (inventoryDatabase.NextRefill) {
|
||||||
|
inventoryResponse.NextRefill = toMongoDate(inventoryDatabase.NextRefill);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ const databaseAccountSchema = new Schema<IDatabaseAccountJson>(
|
|||||||
TrackedSettings: { type: [String], default: [] },
|
TrackedSettings: { type: [String], default: [] },
|
||||||
Nonce: { type: Number, default: 0 },
|
Nonce: { type: Number, default: 0 },
|
||||||
Dropped: Boolean,
|
Dropped: Boolean,
|
||||||
LastLoginDay: { type: Number },
|
|
||||||
LatestEventMessageDate: { type: Date, default: 0 }
|
LatestEventMessageDate: { type: Date, default: 0 }
|
||||||
},
|
},
|
||||||
opts
|
opts
|
||||||
|
@ -55,6 +55,7 @@ interface IConfig {
|
|||||||
unlockExilusEverywhere?: boolean;
|
unlockExilusEverywhere?: boolean;
|
||||||
unlockArcanesEverywhere?: boolean;
|
unlockArcanesEverywhere?: boolean;
|
||||||
noDailyStandingLimits?: boolean;
|
noDailyStandingLimits?: boolean;
|
||||||
|
noArgonCrystalDecay?: boolean;
|
||||||
noVendorPurchaseLimits?: boolean;
|
noVendorPurchaseLimits?: boolean;
|
||||||
instantResourceExtractorDrones?: boolean;
|
instantResourceExtractorDrones?: boolean;
|
||||||
noDojoRoomBuildStage?: boolean;
|
noDojoRoomBuildStage?: boolean;
|
||||||
|
@ -1045,6 +1045,22 @@ export const addMiscItems = (inventory: TInventoryDatabaseDocument, itemsArray:
|
|||||||
}
|
}
|
||||||
|
|
||||||
MiscItems[itemIndex].ItemCount += ItemCount;
|
MiscItems[itemIndex].ItemCount += ItemCount;
|
||||||
|
|
||||||
|
if (ItemType == "/Lotus/Types/Items/MiscItems/ArgonCrystal") {
|
||||||
|
inventory.FoundToday ??= [];
|
||||||
|
let foundTodayIndex = inventory.FoundToday.findIndex(x => x.ItemType == ItemType);
|
||||||
|
if (foundTodayIndex == -1) {
|
||||||
|
foundTodayIndex = inventory.FoundToday.push({ ItemType, ItemCount: 0 }) - 1;
|
||||||
|
}
|
||||||
|
inventory.FoundToday[foundTodayIndex].ItemCount += ItemCount;
|
||||||
|
if (inventory.FoundToday[foundTodayIndex].ItemCount <= 0) {
|
||||||
|
inventory.FoundToday.splice(foundTodayIndex, 1);
|
||||||
|
}
|
||||||
|
if (inventory.FoundToday.length == 0) {
|
||||||
|
inventory.FoundToday = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (MiscItems[itemIndex].ItemCount == 0) {
|
if (MiscItems[itemIndex].ItemCount == 0) {
|
||||||
MiscItems.splice(itemIndex, 1);
|
MiscItems.splice(itemIndex, 1);
|
||||||
} else if (MiscItems[itemIndex].ItemCount <= 0) {
|
} else if (MiscItems[itemIndex].ItemCount <= 0) {
|
||||||
|
@ -42,6 +42,7 @@ export interface IInventoryDatabase
|
|||||||
| "PendingCoupon"
|
| "PendingCoupon"
|
||||||
| "Drones"
|
| "Drones"
|
||||||
| "RecentVendorPurchases"
|
| "RecentVendorPurchases"
|
||||||
|
| "NextRefill"
|
||||||
| TEquipmentKey
|
| TEquipmentKey
|
||||||
>,
|
>,
|
||||||
InventoryDatabaseEquipment {
|
InventoryDatabaseEquipment {
|
||||||
@ -69,6 +70,7 @@ export interface IInventoryDatabase
|
|||||||
PendingCoupon?: IPendingCouponDatabase;
|
PendingCoupon?: IPendingCouponDatabase;
|
||||||
Drones: IDroneDatabase[];
|
Drones: IDroneDatabase[];
|
||||||
RecentVendorPurchases?: IRecentVendorPurchaseDatabase[];
|
RecentVendorPurchases?: IRecentVendorPurchaseDatabase[];
|
||||||
|
NextRefill?: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IQuestKeyDatabase {
|
export interface IQuestKeyDatabase {
|
||||||
@ -307,7 +309,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
UseAdultOperatorLoadout?: boolean;
|
UseAdultOperatorLoadout?: boolean;
|
||||||
NemesisAbandonedRewards: string[];
|
NemesisAbandonedRewards: string[];
|
||||||
LastInventorySync: IOid;
|
LastInventorySync: IOid;
|
||||||
NextRefill: IMongoDate; // Next time argon crystals will have a decay tick
|
NextRefill?: IMongoDate;
|
||||||
FoundToday?: IMiscItem[]; // for Argon Crystals
|
FoundToday?: IMiscItem[]; // for Argon Crystals
|
||||||
CustomMarkers?: ICustomMarkers[];
|
CustomMarkers?: ICustomMarkers[];
|
||||||
ActiveLandscapeTraps: any[];
|
ActiveLandscapeTraps: any[];
|
||||||
|
@ -15,7 +15,6 @@ export interface IDatabaseAccount extends IAccountAndLoginResponseCommons {
|
|||||||
email: string;
|
email: string;
|
||||||
password: string;
|
password: string;
|
||||||
Dropped?: boolean;
|
Dropped?: boolean;
|
||||||
LastLoginDay?: number;
|
|
||||||
LatestEventMessageDate: Date;
|
LatestEventMessageDate: Date;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -517,6 +517,10 @@
|
|||||||
<input class="form-check-input" type="checkbox" id="noDailyStandingLimits" />
|
<input class="form-check-input" type="checkbox" id="noDailyStandingLimits" />
|
||||||
<label class="form-check-label" for="noDailyStandingLimits" data-loc="cheats_noDailyStandingLimits"></label>
|
<label class="form-check-label" for="noDailyStandingLimits" data-loc="cheats_noDailyStandingLimits"></label>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="form-check">
|
||||||
|
<input class="form-check-input" type="checkbox" id="noArgonCrystalDecay" />
|
||||||
|
<label class="form-check-label" for="noArgonCrystalDecay" data-loc="cheats_noArgonCrystalDecay"></label>
|
||||||
|
</div>
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="noVendorPurchaseLimits" />
|
<input class="form-check-input" type="checkbox" id="noVendorPurchaseLimits" />
|
||||||
<label class="form-check-label" for="noVendorPurchaseLimits" data-loc="cheats_noVendorPurchaseLimits"></label>
|
<label class="form-check-label" for="noVendorPurchaseLimits" data-loc="cheats_noVendorPurchaseLimits"></label>
|
||||||
|
@ -110,6 +110,7 @@ dict = {
|
|||||||
cheats_unlockExilusEverywhere: `Exilus-Adapter überall`,
|
cheats_unlockExilusEverywhere: `Exilus-Adapter überall`,
|
||||||
cheats_unlockArcanesEverywhere: `Arkana-Adapter überall`,
|
cheats_unlockArcanesEverywhere: `Arkana-Adapter überall`,
|
||||||
cheats_noDailyStandingLimits: `Kein tägliches Ansehenslimit`,
|
cheats_noDailyStandingLimits: `Kein tägliches Ansehenslimit`,
|
||||||
|
cheats_noArgonCrystalDecay: `[UNTRANSLATED] No Argon Crystal Decay`,
|
||||||
cheats_noVendorPurchaseLimits: `Keine Kaufbeschränkungen bei Händlern`,
|
cheats_noVendorPurchaseLimits: `Keine Kaufbeschränkungen bei Händlern`,
|
||||||
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
|
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
|
||||||
cheats_noDojoRoomBuildStage: `Kein Dojo-Raum-Bauvorgang`,
|
cheats_noDojoRoomBuildStage: `Kein Dojo-Raum-Bauvorgang`,
|
||||||
|
@ -109,6 +109,7 @@ dict = {
|
|||||||
cheats_unlockExilusEverywhere: `Exilus Adapters Everywhere`,
|
cheats_unlockExilusEverywhere: `Exilus Adapters Everywhere`,
|
||||||
cheats_unlockArcanesEverywhere: `Arcane Adapters Everywhere`,
|
cheats_unlockArcanesEverywhere: `Arcane Adapters Everywhere`,
|
||||||
cheats_noDailyStandingLimits: `No Daily Standing Limits`,
|
cheats_noDailyStandingLimits: `No Daily Standing Limits`,
|
||||||
|
cheats_noArgonCrystalDecay: `No Argon Crystal Decay`,
|
||||||
cheats_noVendorPurchaseLimits: `No Vendor Purchase Limits`,
|
cheats_noVendorPurchaseLimits: `No Vendor Purchase Limits`,
|
||||||
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
|
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
|
||||||
cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
|
cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
|
||||||
|
@ -110,6 +110,7 @@ dict = {
|
|||||||
cheats_unlockExilusEverywhere: `Adaptateurs Exilus partout`,
|
cheats_unlockExilusEverywhere: `Adaptateurs Exilus partout`,
|
||||||
cheats_unlockArcanesEverywhere: `Adaptateur d'Arcanes partout`,
|
cheats_unlockArcanesEverywhere: `Adaptateur d'Arcanes partout`,
|
||||||
cheats_noDailyStandingLimits: `Pas de limite de réputation journalière`,
|
cheats_noDailyStandingLimits: `Pas de limite de réputation journalière`,
|
||||||
|
cheats_noArgonCrystalDecay: `[UNTRANSLATED] No Argon Crystal Decay`,
|
||||||
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
||||||
cheats_instantResourceExtractorDrones: `Ressources de drone d'extraction instantannées`,
|
cheats_instantResourceExtractorDrones: `Ressources de drone d'extraction instantannées`,
|
||||||
cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
|
cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
|
||||||
|
@ -110,6 +110,7 @@ dict = {
|
|||||||
cheats_unlockExilusEverywhere: `Адаптеры Эксилус везде`,
|
cheats_unlockExilusEverywhere: `Адаптеры Эксилус везде`,
|
||||||
cheats_unlockArcanesEverywhere: `Адаптеры для мистификаторов везде`,
|
cheats_unlockArcanesEverywhere: `Адаптеры для мистификаторов везде`,
|
||||||
cheats_noDailyStandingLimits: `Без ежедневных ограничений репутации`,
|
cheats_noDailyStandingLimits: `Без ежедневных ограничений репутации`,
|
||||||
|
cheats_noArgonCrystalDecay: `[UNTRANSLATED] No Argon Crystal Decay`,
|
||||||
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
||||||
cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`,
|
cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`,
|
||||||
cheats_noDojoRoomBuildStage: `Мгновенное Строительтво Комнат Додзё`,
|
cheats_noDojoRoomBuildStage: `Мгновенное Строительтво Комнат Додзё`,
|
||||||
|
@ -110,6 +110,7 @@ dict = {
|
|||||||
cheats_unlockExilusEverywhere: `全物品自带适配器`,
|
cheats_unlockExilusEverywhere: `全物品自带适配器`,
|
||||||
cheats_unlockArcanesEverywhere: `全物品自带赋能适配器`,
|
cheats_unlockArcanesEverywhere: `全物品自带赋能适配器`,
|
||||||
cheats_noDailyStandingLimits: `无每日声望限制`,
|
cheats_noDailyStandingLimits: `无每日声望限制`,
|
||||||
|
cheats_noArgonCrystalDecay: `[UNTRANSLATED] No Argon Crystal Decay`,
|
||||||
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
||||||
cheats_instantResourceExtractorDrones: `即时资源采集无人机`,
|
cheats_instantResourceExtractorDrones: `即时资源采集无人机`,
|
||||||
cheats_noDojoRoomBuildStage: `无视道场房间建造阶段`,
|
cheats_noDojoRoomBuildStage: `无视道场房间建造阶段`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user