Compare commits

..

9 Commits

Author SHA1 Message Date
9d5d3f17bf fix: generate rewards based on RewardSeed to match what's show in client
Some checks failed
Build / build (push) Has been cancelled
Build / build (pull_request) Successful in 57s
2025-04-15 15:24:17 +02:00
d28437b658 feat: give 5 steel essence when completing an SP incursion (#1637)
All checks were successful
Build Docker image / docker (push) Successful in 54s
Build / build (push) Successful in 54s
Closes #1631

Reviewed-on: #1637
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-04-15 06:16:40 -07:00
a6d2c8b18a fix: don't give credits for junctions, the index, and free flight (#1635)
Some checks failed
Build / build (push) Has been cancelled
Build Docker image / docker (push) Has been cancelled
Closes #1625

Reviewed-on: #1635
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-04-15 06:16:31 -07:00
0c884576bd feat: picking up prex cards (#1634)
Some checks failed
Build / build (push) Has been cancelled
Build Docker image / docker (push) Has been cancelled
Closes #1621

Reviewed-on: #1634
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-04-15 06:16:19 -07:00
380f0662a4 fix: don't try to subtract MiscItems for polarity swap (#1633)
Some checks failed
Build / build (push) Has been cancelled
Build Docker image / docker (push) Has been cancelled
Closes #1620

Reviewed-on: #1633
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-04-15 06:16:07 -07:00
bd83738168 fix: provide a response to setPlacedDecoInfo (#1632)
Some checks failed
Build / build (push) Has been cancelled
Build Docker image / docker (push) Has been cancelled
This seems to be needed for the client when refreshing the ship after loading into a mission as it does not resync the ship otherwise.

Closes #1629

Reviewed-on: #1632
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-04-15 06:15:49 -07:00
fa68a1357d chore(webui): update to German translation (#1642)
Some checks failed
Build / build (push) Has been cancelled
Build Docker image / docker (push) Has been cancelled
Reviewed-on: #1642
Co-authored-by: Animan8000 <animan8000@noreply.localhost>
Co-committed-by: Animan8000 <animan8000@noreply.localhost>
2025-04-15 06:15:33 -07:00
43f3917b09 fix: additional checks in bounty rewards (#1626)
All checks were successful
Build Docker image / docker (push) Successful in 58s
Build / build (push) Successful in 1m28s
Reviewed-on: #1626
Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
2025-04-15 06:10:25 -07:00
8ebb749732 chore(webui): update to Spanish translation (#1636)
All checks were successful
Build Docker image / docker (push) Successful in 35s
Build / build (push) Successful in 1m21s
Reviewed-on: #1636
Co-authored-by: hxedcl <hxedcl@noreply.localhost>
Co-committed-by: hxedcl <hxedcl@noreply.localhost>
2025-04-14 11:45:00 -07:00
8 changed files with 92 additions and 28 deletions

View File

@ -0,0 +1,20 @@
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { addLoreFragmentScans, addShipDecorations, getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { ILoreFragmentScan, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
import { RequestHandler } from "express";
export const giveShipDecoAndLoreFragmentController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId, "LoreFragmentScans ShipDecorations");
const data = getJSONfromString<IGiveShipDecoAndLoreFragmentRequest>(String(req.body));
addLoreFragmentScans(inventory, data.LoreFragmentScans);
addShipDecorations(inventory, data.ShipDecorations);
await inventory.save();
res.end();
};
interface IGiveShipDecoAndLoreFragmentRequest {
LoreFragmentScans: ILoreFragmentScan[];
ShipDecorations: ITypeCount[];
}

View File

@ -1,5 +1,5 @@
import { getAccountIdForRequest } from "@/src/services/loginService";
import { ISetPlacedDecoInfoRequest } from "@/src/types/shipTypes";
import { IPictureFrameInfo, ISetPlacedDecoInfoRequest } from "@/src/types/shipTypes";
import { RequestHandler } from "express";
import { handleSetPlacedDecoInfo } from "@/src/services/shipCustomizationsService";
@ -7,5 +7,17 @@ export const setPlacedDecoInfoController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const payload = JSON.parse(req.body as string) as ISetPlacedDecoInfoRequest;
await handleSetPlacedDecoInfo(accountId, payload);
res.end();
res.json({
DecoId: payload.DecoId,
IsPicture: true,
PictureFrameInfo: payload.PictureFrameInfo,
BootLocation: payload.BootLocation
} satisfies ISetPlacedDecoInfoResponse);
};
interface ISetPlacedDecoInfoResponse {
DecoId: string;
IsPicture: boolean;
PictureFrameInfo?: IPictureFrameInfo;
BootLocation?: string;
}

View File

@ -25,7 +25,13 @@ export const upgradesController: RequestHandler = async (req, res) => {
operation.UpgradeRequirement == "/Lotus/Types/Items/MiscItems/CustomizationSlotUnlocker"
) {
updateCurrency(inventory, 10, true);
} else if (operation.OperationType != "UOT_ABILITY_OVERRIDE") {
} else if (
operation.OperationType != "UOT_SWAP_POLARITY" &&
operation.OperationType != "UOT_ABILITY_OVERRIDE"
) {
if (!operation.UpgradeRequirement) {
throw new Error(`${operation.OperationType} operation should be free?`);
}
addMiscItems(inventory, [
{
ItemType: operation.UpgradeRequirement,

View File

@ -62,6 +62,7 @@ import { gildWeaponController } from "@/src/controllers/api/gildWeaponController
import { giveKeyChainTriggeredItemsController } from "@/src/controllers/api/giveKeyChainTriggeredItemsController";
import { giveKeyChainTriggeredMessageController } from "@/src/controllers/api/giveKeyChainTriggeredMessageController";
import { giveQuestKeyRewardController } from "@/src/controllers/api/giveQuestKey";
import { giveShipDecoAndLoreFragmentController } from "@/src/controllers/api/giveShipDecoAndLoreFragmentController";
import { giveStartingGearController } from "@/src/controllers/api/giveStartingGearController";
import { guildTechController } from "@/src/controllers/api/guildTechController";
import { hostSessionController } from "@/src/controllers/api/hostSessionController";
@ -239,6 +240,7 @@ apiRouter.post("/gildWeapon.php", gildWeaponController);
apiRouter.post("/giveKeyChainTriggeredItems.php", giveKeyChainTriggeredItemsController);
apiRouter.post("/giveKeyChainTriggeredMessage.php", giveKeyChainTriggeredMessageController);
apiRouter.post("/giveQuestKeyReward.php", giveQuestKeyRewardController);
apiRouter.post("/giveShipDecoAndLoreFragment.php", giveShipDecoAndLoreFragmentController);
apiRouter.post("/giveStartingGear.php", giveStartingGearController);
apiRouter.post("/guildTech.php", guildTechController);
apiRouter.post("/hostSession.php", hostSessionController);

View File

@ -21,7 +21,8 @@ import {
ICalendarProgress,
IDroneClient,
IUpgradeClient,
TPartialStartingGear
TPartialStartingGear,
ILoreFragmentScan
} from "@/src/types/inventoryTypes/inventoryTypes";
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
@ -1350,6 +1351,17 @@ export const addFocusXpIncreases = (inventory: TInventoryDatabaseDocument, focus
inventory.DailyFocus -= focusXpPlus.reduce((a, b) => a + b, 0);
};
export const addLoreFragmentScans = (inventory: TInventoryDatabaseDocument, arr: ILoreFragmentScan[]): void => {
arr.forEach(clientFragment => {
const fragment = inventory.LoreFragmentScans.find(x => x.ItemType == clientFragment.ItemType);
if (fragment) {
fragment.Progress += clientFragment.Progress;
} else {
inventory.LoreFragmentScans.push(clientFragment);
}
});
};
export const addChallenges = (
inventory: TInventoryDatabaseDocument,
ChallengeProgress: IChallengeProgress[],

View File

@ -23,6 +23,7 @@ import {
addGearExpByCategory,
addItem,
addLevelKeys,
addLoreFragmentScans,
addMiscItems,
addMissionComplete,
addMods,
@ -297,14 +298,7 @@ export const addMissionInventoryUpdates = async (
break;
}
case "LoreFragmentScans":
value.forEach(clientFragment => {
const fragment = inventory.LoreFragmentScans.find(x => x.ItemType == clientFragment.ItemType);
if (fragment) {
fragment.Progress += clientFragment.Progress;
} else {
inventory.LoreFragmentScans.push(clientFragment);
}
});
addLoreFragmentScans(inventory, value);
break;
case "LibraryScans":
value.forEach(scan => {
@ -603,7 +597,14 @@ export const addMissionRewards = async (
const node = ExportRegions[missions.Tag];
//node based credit rewards for mission completion
if (node.missionIndex !== 28) {
if (
node.missionIndex != 23 && // junction
node.missionIndex != 28 && // open world
missions.Tag != "SolNode761" && // the index
missions.Tag != "SolNode762" && // the index
missions.Tag != "SolNode763" && // the index
missions.Tag != "CrewBattleNode556" // free flight
) {
const levelCreditReward = getLevelCreditRewards(node);
missionCompletionCredits += levelCreditReward;
inventory.RegularCredits += levelCreditReward;
@ -909,6 +910,12 @@ function getLevelCreditRewards(node: IRegion): number {
function getRandomMissionDrops(RewardInfo: IRewardInfo, tierOverride: number | undefined): IMissionReward[] {
const drops: IMissionReward[] = [];
if (RewardInfo.periodicMissionTag?.startsWith("HardDaily")) {
drops.push({
StoreItem: "/Lotus/StoreItems/Types/Items/MiscItems/SteelEssence",
ItemCount: 5
});
}
if (RewardInfo.node in ExportRegions) {
const region = ExportRegions[RewardInfo.node];
let rewardManifests: string[] =
@ -933,7 +940,7 @@ function getRandomMissionDrops(RewardInfo: IRewardInfo, tierOverride: number | u
if (syndicateEntry.Tag === "EntratiSyndicate") {
const vault = syndicateEntry.Jobs.find(j => j.locationTag === locationTag);
if (vault) job = vault;
if (vault && locationTag) job = vault;
// if (
// [
// "DeimosRuinsExterminateBounty",
@ -1008,8 +1015,10 @@ function getRandomMissionDrops(RewardInfo: IRewardInfo, tierOverride: number | u
(RewardInfo.JobStage === job.xpAmounts.length - 1 || job.isVault) &&
!isEndlessJob
) {
rewardManifests.push(job.rewards);
rotations.push(ExportRewards[job.rewards].length - 1);
if (ExportRewards[job.rewards]) {
rewardManifests.push(job.rewards);
rotations.push(ExportRewards[job.rewards].length - 1);
}
}
}
}
@ -1065,17 +1074,20 @@ function getRandomMissionDrops(RewardInfo: IRewardInfo, tierOverride: number | u
logger.debug(`generating random mission rewards`, { rewardManifests, rotations });
}
const rng = new SRng(BigInt(RewardInfo.rewardSeed ?? generateRewardSeed()) ^ 0xffffffffffffffffn);
rewardManifests
.map(name => ExportRewards[name])
.forEach(table => {
for (const rotation of rotations) {
const rotationRewards = table[rotation];
const drop = getRandomRewardByChance(rotationRewards, rng);
if (drop) {
drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
}
rewardManifests.forEach(name => {
const table = ExportRewards[name];
if (!table) {
logger.error(`unknown droptable: ${name}`);
return;
}
for (const rotation of rotations) {
const rotationRewards = table[rotation];
const drop = getRandomRewardByChance(rotationRewards, rng);
if (drop) {
drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
}
});
}
});
if (region.cacheRewardManifest && RewardInfo.EnemyCachesFound) {
const deck = ExportRewards[region.cacheRewardManifest];

View File

@ -139,7 +139,7 @@ dict = {
cheats_noVendorPurchaseLimits: `Keine Kaufbeschränkungen bei Händlern`,
cheats_noKimCooldowns: `Keine Wartezeit bei KIM`,
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
cheats_noResourceExtractorDronesDamage: `[UNTRANSLATED] No Resource Extractor Drones Damage`,
cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`,
cheats_noDojoRoomBuildStage: `Kein Dojo-Raum-Bauvorgang`,
cheats_noDojoDecoBuildStage: `Kein Dojo-Deko-Bauvorgang`,
cheats_fastDojoRoomDestruction: `Schnelle Dojo-Raum-Zerstörung`,

View File

@ -139,7 +139,7 @@ dict = {
cheats_noVendorPurchaseLimits: `Sin límite de compras de vendedores`,
cheats_noKimCooldowns: `Sin tiempo de espera para conversaciones KIM`,
cheats_instantResourceExtractorDrones: `Drones de extracción de recursos instantáneos`,
cheats_noResourceExtractorDronesDamage: `[UNTRANSLATED] No Resource Extractor Drones Damage`,
cheats_noResourceExtractorDronesDamage: `Sin daño a los drones extractores de recursos`,
cheats_noDojoRoomBuildStage: `Sin etapa de construcción de sala del dojo`,
cheats_noDojoDecoBuildStage: `Sin etapa de construcción de decoraciones del dojo`,
cheats_fastDojoRoomDestruction: `Destrucción rápida de salas del dojo`,