feat(webui): skins #2816
@ -15,6 +15,7 @@ import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "../../ser
|
||||
import {
|
||||
addEmailItem,
|
||||
addItem,
|
||||
addItems,
|
||||
addMiscItems,
|
||||
allDailyAffiliationKeys,
|
||||
checkCalendarAutoAdvance,
|
||||
@ -268,6 +269,65 @@ export const inventoryController: RequestHandler = async (request, response) =>
|
||||
}
|
||||
}
|
||||
inventory.LastInventorySync = new Types.ObjectId();
|
||||
|
||||
const weaponMap = new Map<string, string>();
|
||||
for (const skin of inventory.WeaponSkins) {
|
||||
weaponMap.set(skin.ItemType, skin._id.toString());
|
||||
}
|
||||
|
||||
const itemsToAdd = new Set<string>();
|
||||
|
||||
for (const key of equipmentKeys) {
|
||||
if (key in inventory) {
|
||||
for (const equipment of inventory[key]) {
|
||||
for (const config of equipment.Configs) {
|
||||
if (config.Skins) collectSkins(config.Skins, weaponMap, itemsToAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of ["AdultOperatorLoadOuts", "OperatorLoadOuts", "KahlLoadOuts"] as const) {
|
||||
if (key in inventory) {
|
||||
for (const loadOut of inventory[key]) {
|
||||
if (loadOut.Skins) collectSkins(loadOut.Skins, weaponMap, itemsToAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inventory.LotusCustomization?.Skins) collectSkins(inventory.LotusCustomization.Skins, weaponMap, itemsToAdd);
|
||||
|
||||
if (itemsToAdd.size > 0) {
|
||||
logger.debug(`Adding ${itemsToAdd.size} items due to migration from unlockAllSkins cheat`);
|
||||
const inventoryChanges = await addItems(inventory, Array.from(itemsToAdd));
|
||||
|
||||
if (inventoryChanges.WeaponSkins) {
|
||||
for (const skin of inventoryChanges.WeaponSkins as IWeaponSkinClient[]) {
|
||||
weaponMap.set(skin.ItemType, skin.ItemId.toString());
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of equipmentKeys) {
|
||||
if (key in inventory) {
|
||||
for (const equipment of inventory[key]) {
|
||||
for (const config of equipment.Configs) {
|
||||
if (config.Skins) replaceSkinIds(config.Skins, weaponMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of ["AdultOperatorLoadOuts", "OperatorLoadOuts", "KahlLoadOuts"] as const) {
|
||||
if (key in inventory) {
|
||||
for (const loadOut of inventory[key]) {
|
||||
if (loadOut.Skins) replaceSkinIds(loadOut.Skins, weaponMap);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (inventory.LotusCustomization?.Skins) replaceSkinIds(inventory.LotusCustomization.Skins, weaponMap);
|
||||
}
|
||||
|
||||
await inventory.save();
|
||||
|
||||
response.json(
|
||||
@ -334,45 +394,6 @@ export const getInventoryResponse = async (
|
||||
});
|
||||
}
|
||||
|
||||
if (inventory.unlockAllSkins) {
|
||||
const missingWeaponSkins = new Set(Object.keys(ExportCustoms));
|
||||
inventoryResponse.WeaponSkins.forEach(x => missingWeaponSkins.delete(x.ItemType));
|
||||
for (const uniqueName of missingWeaponSkins) {
|
||||
inventoryResponse.WeaponSkins.push({
|
||||
ItemId: {
|
||||
$oid: "ca70ca70ca70ca70" + catBreadHash(uniqueName).toString(16).padStart(8, "0")
|
||||
},
|
||||
ItemType: uniqueName
|
||||
});
|
||||
}
|
||||
} else {
|
||||
for (const key of equipmentKeys) {
|
||||
if (key in inventoryResponse) {
|
||||
for (const equipment of inventoryResponse[key]) {
|
||||
equipment.Configs.forEach(config => {
|
||||
if (config.Skins) processSkins(config.Skins, inventoryResponse.WeaponSkins, equipment.ItemType);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of ["AdultOperatorLoadOuts", "OperatorLoadOuts", "KahlLoadOuts"] as const) {
|
||||
if (key in inventoryResponse) {
|
||||
inventoryResponse[key].forEach(loadOut => {
|
||||
if (loadOut.Skins) processSkins(loadOut.Skins, inventoryResponse.WeaponSkins, key);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (inventoryResponse.LotusCustomization?.Skins) {
|
||||
processSkins(
|
||||
inventoryResponse.LotusCustomization.Skins,
|
||||
inventoryResponse.WeaponSkins,
|
||||
"LotusCustomization"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof config.spoofMasteryRank === "number" && config.spoofMasteryRank >= 0) {
|
||||
inventoryResponse.PlayerLevel = config.spoofMasteryRank;
|
||||
if (!xpBasedLevelCapDisabled) {
|
||||
@ -508,20 +529,21 @@ for (const key of Object.keys(ExportCustoms)) {
|
||||
skinLookupTable[catBreadHash(key)] = key;
|
||||
}
|
||||
|
||||
const processSkins = (skins: string[], weaponSKins: IWeaponSkinClient[], contextName: string): void => {
|
||||
skins.forEach((skinId, i) => {
|
||||
const collectSkins = (skins: string[], weaponMap: Map<string, string>, itemsToAdd: Set<string>): void => {
|
||||
for (const skinId of skins) {
|
||||
if (skinId.startsWith("ca70ca70ca70ca70")) {
|
||||
const skinItemType = skinLookupTable[parseInt(skinId.slice(16), 16)];
|
||||
const inventoryItem = weaponSKins.find(x => x.ItemType === skinItemType);
|
||||
|
||||
if (inventoryItem) {
|
||||
skins[i] = inventoryItem.ItemId.$oid;
|
||||
} else {
|
||||
skins[i] = skinItemType;
|
||||
if (!ExportCustoms[skinItemType].alwaysAvailable) {
|
||||
logger.warn(`Get ${skinItemType} or you may loose your appearance on ${contextName}`);
|
||||
}
|
||||
}
|
||||
const typeName = skinLookupTable[parseInt(skinId.slice(16), 16)];
|
||||
if (!weaponMap.has(typeName)) itemsToAdd.add(typeName);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const replaceSkinIds = (skins: string[], weaponMap: Map<string, string>): void => {
|
||||
for (let i = 0; i < skins.length; i++) {
|
||||
const skinId = skins[i];
|
||||
if (skinId.startsWith("ca70ca70ca70ca70")) {
|
||||
const inventoryId = weaponMap.get(skinLookupTable[parseInt(skinId.slice(16), 16)]);
|
||||
if (inventoryId) skins[i] = inventoryId;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@ -1445,7 +1445,6 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
||||
unlockDoubleCapacityPotatoesEverywhere: Boolean,
|
||||
unlockExilusEverywhere: Boolean,
|
||||
unlockArcanesEverywhere: Boolean,
|
||||
unlockAllSkins: Boolean,
|
||||
syndicateMissionsRepeatable: Boolean,
|
||||
instantFinishRivenChallenge: Boolean,
|
||||
noDailyStandingLimits: Boolean,
|
||||
|
||||
@ -139,22 +139,16 @@ export const handleInventoryItemConfigChange = async (
|
||||
case "WeaponSkins": {
|
||||
const itemEntries = equipment as IItemEntry;
|
||||
for (const [itemId, itemConfigEntries] of Object.entries(itemEntries)) {
|
||||
if (itemId.startsWith("ca70ca70ca70ca70")) {
|
||||
logger.warn(
|
||||
`unlockAllSkins does not work with favoriting items because you don't actually own it`
|
||||
);
|
||||
} else {
|
||||
const inventoryItem = inventory.WeaponSkins.id(itemId);
|
||||
if (!inventoryItem) {
|
||||
logger.warn(`inventory item WeaponSkins not found with id ${itemId}`);
|
||||
continue;
|
||||
}
|
||||
if ("Favorite" in itemConfigEntries) {
|
||||
inventoryItem.Favorite = itemConfigEntries.Favorite;
|
||||
}
|
||||
if ("IsNew" in itemConfigEntries) {
|
||||
inventoryItem.IsNew = itemConfigEntries.IsNew;
|
||||
}
|
||||
const inventoryItem = inventory.WeaponSkins.id(itemId);
|
||||
if (!inventoryItem) {
|
||||
logger.warn(`inventory item WeaponSkins not found with id ${itemId}`);
|
||||
continue;
|
||||
}
|
||||
if ("Favorite" in itemConfigEntries) {
|
||||
inventoryItem.Favorite = itemConfigEntries.Favorite;
|
||||
}
|
||||
if ("IsNew" in itemConfigEntries) {
|
||||
inventoryItem.IsNew = itemConfigEntries.IsNew;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
@ -38,7 +38,6 @@ export interface IAccountCheats {
|
||||
unlockDoubleCapacityPotatoesEverywhere?: boolean;
|
||||
unlockExilusEverywhere?: boolean;
|
||||
unlockArcanesEverywhere?: boolean;
|
||||
unlockAllSkins?: boolean;
|
||||
syndicateMissionsRepeatable?: boolean;
|
||||
instantFinishRivenChallenge?: boolean;
|
||||
noDailyStandingLimits?: boolean;
|
||||
|
||||
@ -962,10 +962,6 @@
|
||||
<input class="form-check-input" type="checkbox" id="unlockArcanesEverywhere" />
|
||||
<label class="form-check-label" for="unlockArcanesEverywhere" data-loc="cheats_unlockArcanesEverywhere"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="unlockAllSkins" />
|
||||
<label class="form-check-label" for="unlockAllSkins" data-loc="cheats_unlockAllSkins"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="syndicateMissionsRepeatable" />
|
||||
<label class="form-check-label" for="syndicateMissionsRepeatable" data-loc="cheats_syndicateMissionsRepeatable"></label>
|
||||
|
||||
@ -215,7 +215,6 @@ dict = {
|
||||
cheats_dontSubtractVoidTraces: `Void-Spuren nicht verbrauchen`,
|
||||
cheats_dontSubtractConsumables: `Verbrauchsgegenstände (Ausrüstung) nicht verbrauchen`,
|
||||
cheats_unlockAllShipFeatures: `Alle Schiffs-Funktionen freischalten`,
|
||||
cheats_unlockAllSkins: `Alle Skins freischalten`,
|
||||
cheats_unlockAllCapturaScenes: `Alle Photora-Szenen freischalten`,
|
||||
cheats_universalPolarityEverywhere: `Universelle Polarität überall`,
|
||||
cheats_unlockDoubleCapacityPotatoesEverywhere: `Orokin Reaktor & Beschleuniger überall`,
|
||||
|
||||
@ -214,7 +214,6 @@ dict = {
|
||||
cheats_dontSubtractVoidTraces: `Don't Subtract Void Traces`,
|
||||
cheats_dontSubtractConsumables: `Don't Subtract Consumables`,
|
||||
cheats_unlockAllShipFeatures: `Unlock All Ship Features`,
|
||||
cheats_unlockAllSkins: `Unlock All Skins`,
|
||||
cheats_unlockAllCapturaScenes: `Unlock All Captura Scenes`,
|
||||
cheats_universalPolarityEverywhere: `Universal Polarity Everywhere`,
|
||||
cheats_unlockDoubleCapacityPotatoesEverywhere: `Potatoes Everywhere`,
|
||||
|
||||
@ -215,7 +215,6 @@ dict = {
|
||||
cheats_dontSubtractVoidTraces: `No descontar vestigios del Vacío`,
|
||||
cheats_dontSubtractConsumables: `No restar consumibles`,
|
||||
cheats_unlockAllShipFeatures: `Desbloquear todas las funciones de nave`,
|
||||
cheats_unlockAllSkins: `Desbloquear todas las skins`,
|
||||
cheats_unlockAllCapturaScenes: `Desbloquear todas las escenas de Captura`,
|
||||
cheats_universalPolarityEverywhere: `Polaridad universal en todas partes`,
|
||||
cheats_unlockDoubleCapacityPotatoesEverywhere: `Patatas en todas partes`,
|
||||
|
||||
@ -215,7 +215,6 @@ dict = {
|
||||
cheats_dontSubtractVoidTraces: `Ne pas consommer de Void Traces`,
|
||||
cheats_dontSubtractConsumables: `Ne pas retirer de consommables`,
|
||||
cheats_unlockAllShipFeatures: `Débloquer tous les segments du vaisseau`,
|
||||
cheats_unlockAllSkins: `Débloquer tous les skins`,
|
||||
cheats_unlockAllCapturaScenes: `Débloquer toutes les scènes captura`,
|
||||
cheats_universalPolarityEverywhere: `Polarités universelles partout`,
|
||||
cheats_unlockDoubleCapacityPotatoesEverywhere: `Réacteurs et Catalyseurs partout`,
|
||||
|
||||
@ -215,7 +215,6 @@ dict = {
|
||||
cheats_dontSubtractVoidTraces: `Не вычитать количество Отголосков Бездны`,
|
||||
cheats_dontSubtractConsumables: `Не вычитать количество расходников`,
|
||||
cheats_unlockAllShipFeatures: `Разблокировать все функции корабля`,
|
||||
cheats_unlockAllSkins: `Разблокировать все скины`,
|
||||
cheats_unlockAllCapturaScenes: `Разблокировать все сцены Каптуры`,
|
||||
cheats_universalPolarityEverywhere: `Универсальная полярность везде`,
|
||||
cheats_unlockDoubleCapacityPotatoesEverywhere: `Реакторы/Катализаторы орокин везде`,
|
||||
|
||||
@ -215,7 +215,6 @@ dict = {
|
||||
cheats_dontSubtractVoidTraces: `Не вираховувати кількість Відлуння`,
|
||||
cheats_dontSubtractConsumables: `Не вираховувати кількість витратних матеріалів`,
|
||||
cheats_unlockAllShipFeatures: `Розблокувати всі функції судна`,
|
||||
cheats_unlockAllSkins: `Розблокувати всі скіни`,
|
||||
cheats_unlockAllCapturaScenes: `Розблокувати всі сцени Світлописця`,
|
||||
cheats_universalPolarityEverywhere: `Будь-яка полярність скрізь`,
|
||||
cheats_unlockDoubleCapacityPotatoesEverywhere: `Орокінські Реактори/Каталізатори скрізь`,
|
||||
|
||||
@ -215,7 +215,6 @@ dict = {
|
||||
cheats_dontSubtractVoidTraces: `虚空光体无消耗`,
|
||||
cheats_dontSubtractConsumables: `消耗物品使用时无损耗`,
|
||||
cheats_unlockAllShipFeatures: `解锁所有飞船功能`,
|
||||
cheats_unlockAllSkins: `解锁所有外观`,
|
||||
cheats_unlockAllCapturaScenes: `解锁所有Captura场景`,
|
||||
cheats_universalPolarityEverywhere: `全局万用极性`,
|
||||
cheats_unlockDoubleCapacityPotatoesEverywhere: `全物品自带Orokin反应堆`,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user