forked from OpenWF/SpaceNinjaServer
		
	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 { creditsController } from "@/src/controllers/api/creditsController";
 | 
			
		||||
import { crewMembersController } from "@/src/controllers/api/crewMembersController";
 | 
			
		||||
import { crewShipFusionController } from "@/src/controllers/api/crewShipFusionController";
 | 
			
		||||
import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
 | 
			
		||||
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
 | 
			
		||||
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
 | 
			
		||||
@ -247,6 +248,7 @@ apiRouter.post("/contributeToVault.php", contributeToVaultController);
 | 
			
		||||
apiRouter.post("/createAlliance.php", createAllianceController);
 | 
			
		||||
apiRouter.post("/createGuild.php", createGuildController);
 | 
			
		||||
apiRouter.post("/crewMembers.php", crewMembersController);
 | 
			
		||||
apiRouter.post("/crewShipFusion.php", crewShipFusionController);
 | 
			
		||||
apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
 | 
			
		||||
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
 | 
			
		||||
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user