feat: railjack valence fusion (#2194)
Closes #1678 Reviewed-on: OpenWF/SpaceNinjaServer#2194 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									9af0e06b70
								
							
						
					
					
						commit
						b8b8b6a6c6
					
				
							
								
								
									
										107
									
								
								src/controllers/api/crewShipFusionController.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								src/controllers/api/crewShipFusionController.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,107 @@
 | 
				
			|||||||
 | 
					import { getJSONfromString } from "@/src/helpers/stringHelpers";
 | 
				
			||||||
 | 
					import { addMiscItems, freeUpSlot, getInventory, updateCurrency } from "@/src/services/inventoryService";
 | 
				
			||||||
 | 
					import { getAccountIdForRequest } from "@/src/services/loginService";
 | 
				
			||||||
 | 
					import { IOid } from "@/src/types/commonTypes";
 | 
				
			||||||
 | 
					import { ICrewShipComponentFingerprint, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
 | 
				
			||||||
 | 
					import { IInventoryChanges } from "@/src/types/purchaseTypes";
 | 
				
			||||||
 | 
					import { RequestHandler } from "express";
 | 
				
			||||||
 | 
					import { ExportCustoms, ExportDojoRecipes } from "warframe-public-export-plus";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export const crewShipFusionController: RequestHandler = async (req, res) => {
 | 
				
			||||||
 | 
					    const accountId = await getAccountIdForRequest(req);
 | 
				
			||||||
 | 
					    const inventory = await getInventory(accountId);
 | 
				
			||||||
 | 
					    const payload = getJSONfromString<ICrewShipFusionRequest>(String(req.body));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const isWeapon = inventory.CrewShipWeapons.id(payload.PartA.$oid);
 | 
				
			||||||
 | 
					    const itemA = isWeapon ?? inventory.CrewShipWeaponSkins.id(payload.PartA.$oid)!;
 | 
				
			||||||
 | 
					    const category = isWeapon ? "CrewShipWeapons" : "CrewShipWeaponSkins";
 | 
				
			||||||
 | 
					    const salvageCategory = isWeapon ? "CrewShipSalvagedWeapons" : "CrewShipSalvagedWeaponSkins";
 | 
				
			||||||
 | 
					    const itemB = inventory[payload.SourceRecipe ? salvageCategory : category].id(payload.PartB.$oid)!;
 | 
				
			||||||
 | 
					    const tierA = itemA.ItemType.charCodeAt(itemA.ItemType.length - 1) - 65;
 | 
				
			||||||
 | 
					    const tierB = itemB.ItemType.charCodeAt(itemB.ItemType.length - 1) - 65;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const inventoryChanges: IInventoryChanges = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Charge partial repair cost if fusing with an identified but unrepaired part
 | 
				
			||||||
 | 
					    if (payload.SourceRecipe) {
 | 
				
			||||||
 | 
					        const recipe = ExportDojoRecipes.research[payload.SourceRecipe];
 | 
				
			||||||
 | 
					        updateCurrency(inventory, Math.round(recipe.price * 0.4), false, inventoryChanges);
 | 
				
			||||||
 | 
					        const miscItemChanges = recipe.ingredients.map(x => ({ ...x, ItemCount: Math.round(x.ItemCount * -0.4) }));
 | 
				
			||||||
 | 
					        addMiscItems(inventory, miscItemChanges);
 | 
				
			||||||
 | 
					        inventoryChanges.MiscItems = miscItemChanges;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Remove inferior item
 | 
				
			||||||
 | 
					    if (payload.SourceRecipe) {
 | 
				
			||||||
 | 
					        inventory[salvageCategory].pull({ _id: payload.PartB.$oid });
 | 
				
			||||||
 | 
					        inventoryChanges.RemovedIdItems = [{ ItemId: payload.PartB }];
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        const inferiorId = tierA < tierB ? payload.PartA : payload.PartB;
 | 
				
			||||||
 | 
					        inventory[category].pull({ _id: inferiorId.$oid });
 | 
				
			||||||
 | 
					        inventoryChanges.RemovedIdItems = [{ ItemId: inferiorId }];
 | 
				
			||||||
 | 
					        freeUpSlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS);
 | 
				
			||||||
 | 
					        inventoryChanges[InventorySlot.RJ_COMPONENT_AND_ARMAMENTS] = { count: -1, platinum: 0, Slots: 1 };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Upgrade superior item
 | 
				
			||||||
 | 
					    const superiorItem = tierA < tierB ? itemB : itemA;
 | 
				
			||||||
 | 
					    const inferiorItem = tierA < tierB ? itemA : itemB;
 | 
				
			||||||
 | 
					    const fingerprint: ICrewShipComponentFingerprint = JSON.parse(
 | 
				
			||||||
 | 
					        superiorItem.UpgradeFingerprint!
 | 
				
			||||||
 | 
					    ) as ICrewShipComponentFingerprint;
 | 
				
			||||||
 | 
					    const inferiorFingerprint: ICrewShipComponentFingerprint = inferiorItem.UpgradeFingerprint
 | 
				
			||||||
 | 
					        ? (JSON.parse(inferiorItem.UpgradeFingerprint) as ICrewShipComponentFingerprint)
 | 
				
			||||||
 | 
					        : { compat: "", buffs: [] };
 | 
				
			||||||
 | 
					    if (isWeapon) {
 | 
				
			||||||
 | 
					        for (let i = 0; i != fingerprint.buffs.length; ++i) {
 | 
				
			||||||
 | 
					            const buffA = fingerprint.buffs[i];
 | 
				
			||||||
 | 
					            const buffB = i < inferiorFingerprint.buffs.length ? inferiorFingerprint.buffs[i] : undefined;
 | 
				
			||||||
 | 
					            const fvalA = buffA.Value / 0x3fffffff;
 | 
				
			||||||
 | 
					            const fvalB = (buffB?.Value ?? 0) / 0x3fffffff;
 | 
				
			||||||
 | 
					            const percA = 0.3 + fvalA * (0.6 - 0.3);
 | 
				
			||||||
 | 
					            const percB = 0.3 + fvalB * (0.6 - 0.3);
 | 
				
			||||||
 | 
					            const newPerc = Math.min(0.6, Math.max(percA, percB) * FUSE_MULTIPLIERS[Math.abs(tierA - tierB)]);
 | 
				
			||||||
 | 
					            const newFval = (newPerc - 0.3) / (0.6 - 0.3);
 | 
				
			||||||
 | 
					            buffA.Value = Math.trunc(newFval * 0x3fffffff);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        const superiorMeta = ExportCustoms[superiorItem.ItemType].randomisedUpgrades ?? [];
 | 
				
			||||||
 | 
					        const inferiorMeta = ExportCustoms[inferiorItem.ItemType].randomisedUpgrades ?? [];
 | 
				
			||||||
 | 
					        for (let i = 0; i != inferiorFingerprint.buffs.length; ++i) {
 | 
				
			||||||
 | 
					            const buffA = fingerprint.buffs[i];
 | 
				
			||||||
 | 
					            const buffB = inferiorFingerprint.buffs[i];
 | 
				
			||||||
 | 
					            const fvalA = buffA.Value / 0x3fffffff;
 | 
				
			||||||
 | 
					            const fvalB = buffB.Value / 0x3fffffff;
 | 
				
			||||||
 | 
					            const rangeA = superiorMeta[i].range;
 | 
				
			||||||
 | 
					            const rangeB = inferiorMeta[i].range;
 | 
				
			||||||
 | 
					            const percA = rangeA[0] + fvalA * (rangeA[1] - rangeA[0]);
 | 
				
			||||||
 | 
					            const percB = rangeB[0] + fvalB * (rangeB[1] - rangeB[0]);
 | 
				
			||||||
 | 
					            const newPerc = Math.min(rangeA[1], Math.max(percA, percB) * FUSE_MULTIPLIERS[Math.abs(tierA - tierB)]);
 | 
				
			||||||
 | 
					            const newFval = (newPerc - rangeA[0]) / (rangeA[1] - rangeA[0]);
 | 
				
			||||||
 | 
					            buffA.Value = Math.trunc(newFval * 0x3fffffff);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (inferiorFingerprint.SubroutineIndex) {
 | 
				
			||||||
 | 
					            const useSuperiorSubroutine = tierA < tierB ? !payload.UseSubroutineA : payload.UseSubroutineA;
 | 
				
			||||||
 | 
					            if (!useSuperiorSubroutine) {
 | 
				
			||||||
 | 
					                fingerprint.SubroutineIndex = inferiorFingerprint.SubroutineIndex;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    superiorItem.UpgradeFingerprint = JSON.stringify(fingerprint);
 | 
				
			||||||
 | 
					    // eslint-disable-next-line @typescript-eslint/no-explicit-any
 | 
				
			||||||
 | 
					    inventoryChanges[category] = [superiorItem.toJSON() as any];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    await inventory.save();
 | 
				
			||||||
 | 
					    res.json({
 | 
				
			||||||
 | 
					        InventoryChanges: inventoryChanges
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					interface ICrewShipFusionRequest {
 | 
				
			||||||
 | 
					    PartA: IOid;
 | 
				
			||||||
 | 
					    PartB: IOid;
 | 
				
			||||||
 | 
					    SourceRecipe: string;
 | 
				
			||||||
 | 
					    UseSubroutineA: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const FUSE_MULTIPLIERS = [1.1, 1.05, 1.02];
 | 
				
			||||||
@ -33,6 +33,7 @@ import { createAllianceController } from "@/src/controllers/api/createAllianceCo
 | 
				
			|||||||
import { createGuildController } from "@/src/controllers/api/createGuildController";
 | 
					import { createGuildController } from "@/src/controllers/api/createGuildController";
 | 
				
			||||||
import { creditsController } from "@/src/controllers/api/creditsController";
 | 
					import { creditsController } from "@/src/controllers/api/creditsController";
 | 
				
			||||||
import { crewMembersController } from "@/src/controllers/api/crewMembersController";
 | 
					import { crewMembersController } from "@/src/controllers/api/crewMembersController";
 | 
				
			||||||
 | 
					import { crewShipFusionController } from "@/src/controllers/api/crewShipFusionController";
 | 
				
			||||||
import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
 | 
					import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
 | 
				
			||||||
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
 | 
					import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
 | 
				
			||||||
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
 | 
					import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
 | 
				
			||||||
@ -247,6 +248,7 @@ apiRouter.post("/contributeToVault.php", contributeToVaultController);
 | 
				
			|||||||
apiRouter.post("/createAlliance.php", createAllianceController);
 | 
					apiRouter.post("/createAlliance.php", createAllianceController);
 | 
				
			||||||
apiRouter.post("/createGuild.php", createGuildController);
 | 
					apiRouter.post("/createGuild.php", createGuildController);
 | 
				
			||||||
apiRouter.post("/crewMembers.php", crewMembersController);
 | 
					apiRouter.post("/crewMembers.php", crewMembersController);
 | 
				
			||||||
 | 
					apiRouter.post("/crewShipFusion.php", crewShipFusionController);
 | 
				
			||||||
apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
 | 
					apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
 | 
				
			||||||
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
 | 
					apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
 | 
				
			||||||
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
 | 
					apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user