diff --git a/config.json.example b/config.json.example index b9ebaab0..bf6eae91 100644 --- a/config.json.example +++ b/config.json.example @@ -50,6 +50,7 @@ "noDojoResearchTime": false, "fastClanAscension": false, "spoofMasteryRank": -1, + "nightwaveStandingMultiplier": 1, "worldState": { "creditBoost": false, "affinityBoost": false, @@ -58,5 +59,8 @@ "eidolonOverride": "", "vallisOverride": "", "nightwaveOverride": "" + }, + "dev": { + "keepVendorsExpired": false } } diff --git a/src/controllers/api/fishmongerController.ts b/src/controllers/api/fishmongerController.ts index d85f7a4c..16fcc69b 100644 --- a/src/controllers/api/fishmongerController.ts +++ b/src/controllers/api/fishmongerController.ts @@ -30,15 +30,14 @@ export const fishmongerController: RequestHandler = async (req, res) => { miscItemChanges.push({ ItemType: fish.ItemType, ItemCount: fish.ItemCount * -1 }); } addMiscItems(inventory, miscItemChanges); - let affiliationMod; - if (gainedStanding && syndicateTag) affiliationMod = addStanding(inventory, syndicateTag, gainedStanding); + if (gainedStanding && syndicateTag) addStanding(inventory, syndicateTag, gainedStanding); await inventory.save(); res.json({ InventoryChanges: { MiscItems: miscItemChanges }, SyndicateTag: syndicateTag, - StandingChange: affiliationMod?.Standing || 0 + StandingChange: gainedStanding }); }; diff --git a/src/controllers/api/getVendorInfoController.ts b/src/controllers/api/getVendorInfoController.ts index 5f9d3292..15ec9287 100644 --- a/src/controllers/api/getVendorInfoController.ts +++ b/src/controllers/api/getVendorInfoController.ts @@ -2,6 +2,7 @@ import { RequestHandler } from "express"; import { applyStandingToVendorManifest, getVendorManifestByTypeName } from "@/src/services/serversideVendorsService"; import { getInventory } from "@/src/services/inventoryService"; import { getAccountIdForRequest } from "@/src/services/loginService"; +import { config } from "@/src/services/configService"; export const getVendorInfoController: RequestHandler = async (req, res) => { let manifest = getVendorManifestByTypeName(req.query.vendor as string); @@ -14,6 +15,14 @@ export const getVendorInfoController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); const inventory = await getInventory(accountId); manifest = applyStandingToVendorManifest(inventory, manifest); + if (config.dev?.keepVendorsExpired) { + manifest = { + VendorInfo: { + ...manifest.VendorInfo, + Expiry: { $date: { $numberLong: "0" } } + } + }; + } } res.json(manifest); diff --git a/src/controllers/api/syndicateStandingBonusController.ts b/src/controllers/api/syndicateStandingBonusController.ts index 3170bc93..f5f0a5d2 100644 --- a/src/controllers/api/syndicateStandingBonusController.ts +++ b/src/controllers/api/syndicateStandingBonusController.ts @@ -5,7 +5,7 @@ import { IMiscItem, InventorySlot } from "@/src/types/inventoryTypes/inventoryTy import { IOid } from "@/src/types/commonTypes"; import { ExportSyndicates, ExportWeapons } from "warframe-public-export-plus"; import { logger } from "@/src/utils/logger"; -import { IInventoryChanges } from "@/src/types/purchaseTypes"; +import { IAffiliationMods, IInventoryChanges } from "@/src/types/purchaseTypes"; import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes"; export const syndicateStandingBonusController: RequestHandler = async (req, res) => { @@ -54,13 +54,14 @@ export const syndicateStandingBonusController: RequestHandler = async (req, res) inventoryChanges[slotBin] = { count: -1, platinum: 0, Slots: 1 }; } - const affiliationMod = addStanding(inventory, request.Operation.AffiliationTag, gainedStanding, true); + const affiliationMods: IAffiliationMods[] = []; + addStanding(inventory, request.Operation.AffiliationTag, gainedStanding, affiliationMods, true); await inventory.save(); res.json({ InventoryChanges: inventoryChanges, - AffiliationMods: [affiliationMod] + AffiliationMods: affiliationMods }); }; diff --git a/src/helpers/syndicateStandingHelper.ts b/src/helpers/syndicateStandingHelper.ts index a412bdbf..ac478dda 100644 --- a/src/helpers/syndicateStandingHelper.ts +++ b/src/helpers/syndicateStandingHelper.ts @@ -10,3 +10,14 @@ export const getMaxStanding = (syndicate: ISyndicate, title: number): number => } return syndicate.titles.find(x => x.level == title)!.maxStanding; }; + +export const getMinStanding = (syndicate: ISyndicate, title: number): number => { + if (!syndicate.titles) { + // LibrarySyndicate + return 0; + } + if (title == 0) { + return syndicate.titles.find(x => x.level == -1)!.maxStanding; + } + return syndicate.titles.find(x => x.level == title)!.minStanding; +}; diff --git a/src/services/configService.ts b/src/services/configService.ts index 1989330a..82cc4f31 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -56,6 +56,7 @@ interface IConfig { noDojoResearchTime?: boolean; fastClanAscension?: boolean; spoofMasteryRank?: number; + nightwaveStandingMultiplier?: number; worldState?: { creditBoost?: boolean; affinityBoost?: boolean; @@ -65,7 +66,9 @@ interface IConfig { vallisOverride?: string; nightwaveOverride?: string; }; - nightwaveStandingMultiplier?: number; + dev?: { + keepVendorsExpired?: boolean; + }; } export const configPath = path.join(repoDir, "config.json"); diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index ae9158c5..ad53cad5 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -82,7 +82,7 @@ import { handleBundleAcqusition } from "./purchaseService"; import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json"; import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from "./rngService"; import { createMessage } from "./inboxService"; -import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper"; +import { getMaxStanding, getMinStanding } from "@/src/helpers/syndicateStandingHelper"; import { getNightwaveSyndicateTag, getWorldState } from "./worldStateService"; import { generateNemesisProfile, INemesisProfile } from "../helpers/nemesisHelpers"; import { TAccountDocument } from "./loginService"; @@ -1202,8 +1202,10 @@ export const addStanding = ( inventory: TInventoryDatabaseDocument, syndicateTag: string, gainedStanding: number, - isMedallion: boolean = false -): IAffiliationMods => { + affiliationMods: IAffiliationMods[] = [], + isMedallion: boolean = false, + propagateAlignments: boolean = true +): void => { let syndicate = inventory.Affiliations.find(x => x.Tag == syndicateTag); const syndicateMeta = ExportSyndicates[syndicateTag]; @@ -1215,6 +1217,10 @@ export const addStanding = ( const max = getMaxStanding(syndicateMeta, syndicate.Title ?? 0); if (syndicate.Standing + gainedStanding > max) gainedStanding = max - syndicate.Standing; + if (syndicate.Title == -2 && syndicate.Standing + gainedStanding < -71000) { + gainedStanding = -71000 + syndicate.Standing; + } + if (!isMedallion || syndicateMeta.medallionsCappedByDailyLimit) { if (gainedStanding > getStandingLimit(inventory, syndicateMeta.dailyLimitBin)) { gainedStanding = getStandingLimit(inventory, syndicateMeta.dailyLimitBin); @@ -1223,10 +1229,27 @@ export const addStanding = ( } syndicate.Standing += gainedStanding; - return { + const affiliationMod: IAffiliationMods = { Tag: syndicateTag, Standing: gainedStanding }; + affiliationMods.push(affiliationMod); + + if (syndicateMeta.alignments) { + if (propagateAlignments) { + for (const [tag, factor] of Object.entries(syndicateMeta.alignments)) { + addStanding(inventory, tag, gainedStanding * factor, affiliationMods, isMedallion, false); + } + } else { + while (syndicate.Standing < getMinStanding(syndicateMeta, syndicate.Title ?? 0)) { + syndicate.Title ??= 0; + syndicate.Title -= 1; + affiliationMod.Title ??= 0; + affiliationMod.Title -= 1; + logger.debug(`${syndicateTag} is decreasing to title ${syndicate.Title} after applying alignment`); + } + } + } }; // TODO: AffiliationMods support (Nightwave). diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 21aff3b1..3a50cfcf 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -1236,19 +1236,18 @@ export const addMissionRewards = async ( SyndicateXPItemReward = medallionAmount; } else { if (rewardInfo.JobTier! >= 0) { - AffiliationMods.push( - addStanding( - inventory, - syndicateEntry.Tag, - Math.floor(currentJob.xpAmounts[rewardInfo.JobStage] / (rewardInfo.Q ? 0.8 : 1)) - ) + addStanding( + inventory, + syndicateEntry.Tag, + Math.floor(currentJob.xpAmounts[rewardInfo.JobStage] / (rewardInfo.Q ? 0.8 : 1)), + AffiliationMods ); } else { if (jobType.endsWith("Heists/HeistProfitTakerBountyOne") && rewardInfo.JobStage === 2) { - AffiliationMods.push(addStanding(inventory, syndicateEntry.Tag, 1000)); + addStanding(inventory, syndicateEntry.Tag, 1000, AffiliationMods); } if (jobType.endsWith("Hunts/AllTeralystsHunt") && rewardInfo.JobStage === 2) { - AffiliationMods.push(addStanding(inventory, syndicateEntry.Tag, 5000)); + addStanding(inventory, syndicateEntry.Tag, 5000, AffiliationMods); } if ( [ @@ -1259,7 +1258,7 @@ export const addMissionRewards = async ( "Heists/HeistExploiterBountyOne" ].some(ending => jobType.endsWith(ending)) ) { - AffiliationMods.push(addStanding(inventory, syndicateEntry.Tag, 1000)); + addStanding(inventory, syndicateEntry.Tag, 1000, AffiliationMods); } } } @@ -1284,7 +1283,7 @@ export const addMissionRewards = async ( let standingAmount = (tier + 1) * 1000; if (tier > 5) standingAmount = 7500; // InfestedLichBounty if (isSteelPath) standingAmount *= 1.5; - AffiliationMods.push(addStanding(inventory, syndicateTag, standingAmount)); + addStanding(inventory, syndicateTag, standingAmount, AffiliationMods); } if (syndicateTag == "HexSyndicate" && chemistry && tier < 6) { const seed = getWorldState().SyndicateMissions.find(x => x.Tag == "HexSyndicate")!.Seed; diff --git a/static/webui/translations/es.js b/static/webui/translations/es.js index bfe10139..907b9298 100644 --- a/static/webui/translations/es.js +++ b/static/webui/translations/es.js @@ -176,56 +176,56 @@ dict = { import_importNote: `Puedes proporcionar una respuesta de inventario completa o parcial (representación del cliente) aquí. Todos los campos compatibles con el importador serán sobrescritos en tu cuenta.`, import_submit: `Enviar`, - upgrade_Equilibrium: `[UNTRANSLATED] +|VAL|% Energy from Health pickups, +|VAL|% Health from Energy pickups`, - upgrade_MeleeCritDamage: `[UNTRANSLATED] +|VAL|% Melee Critical Damage`, - upgrade_PrimaryStatusChance: `[UNTRANSLATED] +|VAL|% Primary Status Chance`, - upgrade_SecondaryCritChance: `[UNTRANSLATED] +|VAL|% Secondary Critical Chance`, - upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`, - upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`, - upgrade_WarframeArmourMax: `[UNTRANSLATED] +|VAL| Armor`, - upgrade_WarframeBlastProc: `[UNTRANSLATED] +|VAL| Shields on inflicting Blast Status`, - upgrade_WarframeCastingSpeed: `[UNTRANSLATED] +|VAL|% Casting Speed`, - upgrade_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`, - upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`, - upgrade_WarframeCritDamageBoost: `[UNTRANSLATED] +|VAL|% Melee Critical Damage (Doubles over 500 Energy)`, - upgrade_WarframeElectricDamage: `[UNTRANSLATED] +|VAL1|% Primary Electricity Damage (+|VAL2|% per additional Shard)`, - upgrade_WarframeElectricDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Electricity Status`, - upgrade_WarframeEnergyMax: `[UNTRANSLATED] +|VAL| Energy Max`, - upgrade_WarframeGlobeEffectEnergy: `[UNTRANSLATED] +|VAL|% Energy Orb Effectiveness`, - upgrade_WarframeGlobeEffectHealth: `[UNTRANSLATED] +|VAL|% Health Orb Effectiveness`, - upgrade_WarframeHealthMax: `[UNTRANSLATED] +|VAL| Health`, - upgrade_WarframeHPBoostFromImpact: `[UNTRANSLATED] +|VAL1| Health per enemy killed with Blast Damage (Max |VAL2| Health)`, - upgrade_WarframeParkourVelocity: `[UNTRANSLATED] +|VAL|% Parkour Velocity`, - upgrade_WarframeRadiationDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Radiation Status`, - upgrade_WarframeRegen: `[UNTRANSLATED] +|VAL| Health Regen/s`, - upgrade_WarframeShieldMax: `[UNTRANSLATED] +|VAL| Shield`, - upgrade_WarframeStartingEnergy: `[UNTRANSLATED] +|VAL|% Energy on Spawn`, - upgrade_WarframeToxinDamage: `[UNTRANSLATED] +|VAL|% Toxin Status Effect Damage`, - upgrade_WarframeToxinHeal: `[UNTRANSLATED] +|VAL| Health on damaging enemies with Toxin Status`, - upgrade_WeaponCritBoostFromHeat: `[UNTRANSLATED] +|VAL1|% Secondary Critical Chance per Heat-affected enemy killed (Max |VAL2|%)`, - upgrade_AvatarAbilityRange: `[UNTRANSLATED] +7.5% Ability Range`, - upgrade_AvatarAbilityEfficiency: `[UNTRANSLATED] +5% Ability Efficiency`, - upgrade_AvatarEnergyRegen: `[UNTRANSLATED] +0.5 Energy Regen/s`, - upgrade_AvatarEnemyRadar: `[UNTRANSLATED] +5m Enemy Radar`, - upgrade_AvatarLootRadar: `[UNTRANSLATED] +7m Loot Radar`, - upgrade_WeaponAmmoMax: `[UNTRANSLATED] +15% Ammo Max`, - upgrade_EnemyArmorReductionAura: `[UNTRANSLATED] -3% Enemy Armor`, - upgrade_OnExecutionAmmo: `[UNTRANSLATED] 100% Primary and Secondary Magazine Refill on Mercy`, - upgrade_OnExecutionHealthDrop: `[UNTRANSLATED] 100% chance to drop a Health Orb on Mercy`, - upgrade_OnExecutionEnergyDrop: `[UNTRANSLATED] 50% chance to drop an Energy Orb on Mercy`, - upgrade_OnFailHackReset: `[UNTRANSLATED] +50% to retry on Hacking failure`, - upgrade_DamageReductionOnHack: `[UNTRANSLATED] 75% Damage Reduction while Hacking`, - upgrade_OnExecutionReviveCompanion: `[UNTRANSLATED] Mercy Kills reduce Companion Recovery by 15s`, - upgrade_OnExecutionParkourSpeed: `[UNTRANSLATED] +60% Parkour Speed after a Mercy for 15s`, - upgrade_AvatarTimeLimitIncrease: `[UNTRANSLATED] s to Hacking`, - upgrade_ElectrifyOnHack: `[UNTRANSLATED] Shock enemies within 20m while Hacking`, - upgrade_OnExecutionTerrify: `[UNTRANSLATED] 50% chance for enemies within 15m to cower in fear for 8 seconds on Mercy`, - upgrade_OnHackLockers: `[UNTRANSLATED] Unlock 5 lockers within 20m after Hacking`, - upgrade_OnExecutionBlind: `[UNTRANSLATED] Blind enemies within 18m on Mercy`, - upgrade_OnExecutionDrainPower: `[UNTRANSLATED] 100% chance for next ability cast to gain +50% Ability Strength on Mercy`, - upgrade_OnHackSprintSpeed: `[UNTRANSLATED] +75% Sprint Speed for 15s after Hacking`, - upgrade_SwiftExecute: `[UNTRANSLATED] Speed of Mercy Kills increased by 50%`, - upgrade_OnHackInvis: `[UNTRANSLATED] Invisible for 15 seconds after hacking`, + upgrade_Equilibrium: `+|VAL|% de Energía al recoger salud, +|VAL|% de Salud al recoger energía`, + upgrade_MeleeCritDamage: `+|VAL|% de daño crítico cuerpo a cuerpo`, + upgrade_PrimaryStatusChance: `+|VAL|% de probabilidad de estado en armas primarias`, + upgrade_SecondaryCritChance: `+|VAL|% de probabilidad crítica en armas secundarias`, + upgrade_WarframeAbilityDuration: `+|VAL|% de duración de habilidades`, + upgrade_WarframeAbilityStrength: `+|VAL|% de fuerza de habilidades`, + upgrade_WarframeArmourMax: `+|VAL| de armadura`, + upgrade_WarframeBlastProc: `+|VAL| de escudos al infligir estado de explosión`, + upgrade_WarframeCastingSpeed: `+|VAL|% de velocidad de lanzamiento de habilidades`, + upgrade_WarframeCorrosiveDamageBoost: `+|VAL|% de daño de habilidades a enemigos con estado corrosivo`, + upgrade_WarframeCorrosiveStack: `Aumenta los acumuladores máximos de estado corrosivo en +|VAL|`, + upgrade_WarframeCritDamageBoost: `+|VAL|% de daño crítico cuerpo a cuerpo (se duplica con más de 500 de energía)`, + upgrade_WarframeElectricDamage: `+|VAL1|% de daño eléctrico en armas primarias (+|VAL2|% por fragmento adicional)`, + upgrade_WarframeElectricDamageBoost: `+|VAL|% de daño de habilidades a enemigos con estado eléctrico`, + upgrade_WarframeEnergyMax: `+|VAL| de energía máxima`, + upgrade_WarframeGlobeEffectEnergy: `+|VAL|% de efectividad de orbes de energía`, + upgrade_WarframeGlobeEffectHealth: `+|VAL|% de efectividad de orbes de salud`, + upgrade_WarframeHealthMax: `+|VAL| de salud máxima`, + upgrade_WarframeHPBoostFromImpact: `+|VAL1| de salud por enemigo eliminado con daño explosivo (máximo |VAL2| de salud)`, + upgrade_WarframeParkourVelocity: `+|VAL|% de velocidad de parkour`, + upgrade_WarframeRadiationDamageBoost: `+|VAL|% de daño de habilidades a enemigos con estado radiactivo`, + upgrade_WarframeRegen: `+|VAL| de regeneración de salud por segundo`, + upgrade_WarframeShieldMax: `+|VAL| de escudo`, + upgrade_WarframeStartingEnergy: `+|VAL|% de energía al reaparecer`, + upgrade_WarframeToxinDamage: `+|VAL|% de daño por efecto de estado tóxico`, + upgrade_WarframeToxinHeal: `+|VAL| de salud al dañar enemigos con estado tóxico`, + upgrade_WeaponCritBoostFromHeat: `+|VAL1|% de probabilidad crítica secundaria por enemigo afectado por calor eliminado (máx. |VAL2|%)`, + upgrade_AvatarAbilityRange: `+7.5% de alcance de habilidades`, + upgrade_AvatarAbilityEfficiency: `+5% de eficiencia de habilidades`, + upgrade_AvatarEnergyRegen: `+0.5 de regeneración de energía por segundo`, + upgrade_AvatarEnemyRadar: `+5m de radar de enemigos`, + upgrade_AvatarLootRadar: `+7m de radar de botín`, + upgrade_WeaponAmmoMax: `+15% de munición máxima`, + upgrade_EnemyArmorReductionAura: `-3% de armadura enemiga`, + upgrade_OnExecutionAmmo: `Recarga al 100% el cargador primario y secundario tras ejecución (Misericordia)`, + upgrade_OnExecutionHealthDrop: `100% de probabilidad de soltar un orbe de salud tras ejecución (Misericordia)`, + upgrade_OnExecutionEnergyDrop: `50% de probabilidad de soltar un orbe de energía tras ejecución (Misericordia)`, + upgrade_OnFailHackReset: `+50% de probabilidad de reintento al fallar un hackeo`, + upgrade_DamageReductionOnHack: `75% de reducción de daño al hackear`, + upgrade_OnExecutionReviveCompanion: `Las ejecuciones reducen el tiempo de recuperación del compañero en 15s`, + upgrade_OnExecutionParkourSpeed: `+60% de velocidad de parkour durante 15s tras una ejecución`, + upgrade_AvatarTimeLimitIncrease: `+|VAL|s al tiempo de hackeo`, + upgrade_ElectrifyOnHack: `Electrocuta a los enemigos en un radio de 20m al hackear`, + upgrade_OnExecutionTerrify: `50% de probabilidad de que enemigos en un radio de 15m entren en pánico por 8s tras una ejecución`, + upgrade_OnHackLockers: `Desbloquea 5 casilleros en un radio de 20m tras hackear`, + upgrade_OnExecutionBlind: `Ciega a los enemigos en un radio de 18m tras una ejecución`, + upgrade_OnExecutionDrainPower: `100% de probabilidad de que la siguiente habilidad tenga +50% de fuerza tras una ejecución`, + upgrade_OnHackSprintSpeed: `+75% de velocidad de carrera durante 15s después de hackear`, + upgrade_SwiftExecute: `Velocidad de ejecuciones aumentada en un 50%`, + upgrade_OnHackInvis: `Invisible durante 15 segundos después de hackear`, prettier_sucks_ass: `` };