forked from OpenWF/SpaceNinjaServer
feat: acquisition of CrewMembers (#1705)
Reviewed-on: OpenWF/SpaceNinjaServer#1705 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
379f57be2c
commit
196182f9a8
@ -88,7 +88,11 @@ import {
|
||||
IPersonalTechProjectDatabase,
|
||||
IPersonalTechProjectClient,
|
||||
ILastSortieRewardDatabase,
|
||||
ILastSortieRewardClient
|
||||
ILastSortieRewardClient,
|
||||
ICrewMemberSkill,
|
||||
ICrewMemberSkillEfficiency,
|
||||
ICrewMemberDatabase,
|
||||
ICrewMemberClient
|
||||
} from "../../types/inventoryTypes/inventoryTypes";
|
||||
import { IOid } from "../../types/commonTypes";
|
||||
import {
|
||||
@ -294,6 +298,55 @@ upgradeSchema.set("toJSON", {
|
||||
}
|
||||
});
|
||||
|
||||
const crewMemberSkillSchema = new Schema<ICrewMemberSkill>(
|
||||
{
|
||||
Assigned: Number
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
const crewMemberSkillEfficiencySchema = new Schema<ICrewMemberSkillEfficiency>(
|
||||
{
|
||||
PILOTING: crewMemberSkillSchema,
|
||||
GUNNERY: crewMemberSkillSchema,
|
||||
ENGINEERING: crewMemberSkillSchema,
|
||||
COMBAT: crewMemberSkillSchema,
|
||||
SURVIVABILITY: crewMemberSkillSchema
|
||||
},
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
const crewMemberSchema = new Schema<ICrewMemberDatabase>(
|
||||
{
|
||||
ItemType: { type: String, required: true },
|
||||
NemesisFingerprint: { type: BigInt, default: 0n },
|
||||
Seed: { type: BigInt, default: 0n },
|
||||
AssignedRole: Number,
|
||||
SkillEfficiency: crewMemberSkillEfficiencySchema,
|
||||
WeaponConfigIdx: Number,
|
||||
WeaponId: { type: Schema.Types.ObjectId, default: "000000000000000000000000" },
|
||||
XP: { type: Number, default: 0 },
|
||||
PowersuitType: { type: String, required: true },
|
||||
Configs: [ItemConfigSchema],
|
||||
SecondInCommand: { type: Boolean, default: false }
|
||||
},
|
||||
{ id: false }
|
||||
);
|
||||
|
||||
crewMemberSchema.set("toJSON", {
|
||||
virtuals: true,
|
||||
transform(_doc, obj) {
|
||||
const db = obj as ICrewMemberDatabase;
|
||||
const client = obj as ICrewMemberClient;
|
||||
|
||||
client.WeaponId = toOid(db.WeaponId);
|
||||
client.ItemId = toOid(db._id);
|
||||
|
||||
delete obj._id;
|
||||
delete obj.__v;
|
||||
}
|
||||
});
|
||||
|
||||
const slotsBinSchema = new Schema<ISlots>(
|
||||
{
|
||||
Slots: Number,
|
||||
@ -1363,7 +1416,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
||||
CrewShipSalvagedWeaponSkins: [upgradeSchema],
|
||||
|
||||
//RailJack Crew
|
||||
CrewMembers: [Schema.Types.Mixed],
|
||||
CrewMembers: [crewMemberSchema],
|
||||
|
||||
//Complete Mission\Quests
|
||||
Missions: [missionSchema],
|
||||
@ -1645,6 +1698,7 @@ export type InventoryDocumentProps = {
|
||||
CrewShipWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
|
||||
CrewShipSalvagedWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
|
||||
PersonalTechProjects: Types.DocumentArray<IPersonalTechProjectDatabase>;
|
||||
CrewMembers: Types.DocumentArray<ICrewMemberDatabase>;
|
||||
} & { [K in TEquipmentKey]: Types.DocumentArray<IEquipmentDatabase> };
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||
|
@ -22,7 +22,8 @@ import {
|
||||
IDroneClient,
|
||||
IUpgradeClient,
|
||||
TPartialStartingGear,
|
||||
ILoreFragmentScan
|
||||
ILoreFragmentScan,
|
||||
ICrewMemberClient
|
||||
} from "@/src/types/inventoryTypes/inventoryTypes";
|
||||
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
|
||||
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
|
||||
@ -713,6 +714,15 @@ export const addItem = async (
|
||||
return {
|
||||
MiscItems: miscItemChanges
|
||||
};
|
||||
} else if (typeName.startsWith("/Lotus/Types/Game/CrewShip/CrewMember/")) {
|
||||
if (!seed) {
|
||||
throw new Error(`Expected crew member to have a seed`);
|
||||
}
|
||||
seed |= 0x33b81en << 32n;
|
||||
return {
|
||||
...addCrewMember(inventory, typeName, seed),
|
||||
...occupySlot(inventory, InventorySlot.CREWMEMBERS, premiumPurchase)
|
||||
};
|
||||
} else if (typeName == "/Lotus/Types/Game/CrewShip/RailJack/DefaultHarness") {
|
||||
return addCrewShipHarness(inventory, typeName);
|
||||
}
|
||||
@ -1212,6 +1222,78 @@ const addDrone = (
|
||||
return inventoryChanges;
|
||||
};
|
||||
|
||||
/*const getCrewMemberSkills = (seed: bigint, skillPointsToAssign: number): Record<string, number> => {
|
||||
const rng = new SRng(seed);
|
||||
|
||||
const skills = ["PILOTING", "GUNNERY", "ENGINEERING", "COMBAT", "SURVIVABILITY"];
|
||||
for (let i = 1; i != 5; ++i) {
|
||||
const swapIndex = rng.randomInt(0, i);
|
||||
if (swapIndex != i) {
|
||||
const tmp = skills[i];
|
||||
skills[i] = skills[swapIndex];
|
||||
skills[swapIndex] = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
rng.randomFloat(); // unused afaict
|
||||
|
||||
const skillAssignments = [0, 0, 0, 0, 0];
|
||||
for (let skill = 0; skillPointsToAssign; skill = (skill + 1) % 5) {
|
||||
const maxIncrease = Math.min(5 - skillAssignments[skill], skillPointsToAssign);
|
||||
const increase = rng.randomInt(0, maxIncrease);
|
||||
skillAssignments[skill] += increase;
|
||||
skillPointsToAssign -= increase;
|
||||
}
|
||||
|
||||
skillAssignments.sort((a, b) => b - a);
|
||||
|
||||
const combined: Record<string, number> = {};
|
||||
for (let i = 0; i != 5; ++i) {
|
||||
combined[skills[i]] = skillAssignments[i];
|
||||
}
|
||||
return combined;
|
||||
};*/
|
||||
|
||||
const addCrewMember = (
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
itemType: string,
|
||||
seed: bigint,
|
||||
inventoryChanges: IInventoryChanges = {}
|
||||
): IInventoryChanges => {
|
||||
// SkillEfficiency is additional to the base stats, so we don't need to compute this
|
||||
//const skillPointsToAssign = itemType.endsWith("Strong") ? 12 : itemType.indexOf("Medium") != -1 ? 10 : 8;
|
||||
//const skills = getCrewMemberSkills(seed, skillPointsToAssign);
|
||||
|
||||
// Arbiters = male
|
||||
// CephalonSuda = female
|
||||
// NewLoka = female
|
||||
// Perrin = male
|
||||
// RedVeil = male
|
||||
// SteelMeridian = female
|
||||
const powersuitType =
|
||||
itemType.indexOf("Arbiters") != -1 || itemType.indexOf("Perrin") != -1 || itemType.indexOf("RedVeil") != -1
|
||||
? "/Lotus/Powersuits/NpcPowersuits/CrewMemberMaleSuit"
|
||||
: "/Lotus/Powersuits/NpcPowersuits/CrewMemberFemaleSuit";
|
||||
|
||||
const index =
|
||||
inventory.CrewMembers.push({
|
||||
ItemType: itemType,
|
||||
NemesisFingerprint: 0n,
|
||||
Seed: seed,
|
||||
SkillEfficiency: {
|
||||
PILOTING: { Assigned: 0 },
|
||||
GUNNERY: { Assigned: 0 },
|
||||
ENGINEERING: { Assigned: 0 },
|
||||
COMBAT: { Assigned: 0 },
|
||||
SURVIVABILITY: { Assigned: 0 }
|
||||
},
|
||||
PowersuitType: powersuitType
|
||||
}) - 1;
|
||||
inventoryChanges.CrewMembers ??= [];
|
||||
inventoryChanges.CrewMembers.push(inventory.CrewMembers[index].toJSON<ICrewMemberClient>());
|
||||
return inventoryChanges;
|
||||
};
|
||||
|
||||
export const addEmailItem = async (
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
typeName: string,
|
||||
|
@ -141,7 +141,8 @@ export const handlePurchase = async (
|
||||
inventory,
|
||||
purchaseRequest.PurchaseParams.Quantity,
|
||||
undefined,
|
||||
undefined,
|
||||
false,
|
||||
purchaseRequest.PurchaseParams.UsePremium,
|
||||
seed
|
||||
);
|
||||
combineInventoryChanges(purchaseResponse.InventoryChanges, prePurchaseInventoryChanges);
|
||||
@ -331,6 +332,7 @@ export const handleStoreItemAcquisition = async (
|
||||
quantity: number = 1,
|
||||
durability: TRarity = "COMMON",
|
||||
ignorePurchaseQuantity: boolean = false,
|
||||
premiumPurchase: boolean = true,
|
||||
seed?: bigint
|
||||
): Promise<IPurchaseResponse> => {
|
||||
let purchaseResponse = {
|
||||
@ -352,11 +354,20 @@ export const handleStoreItemAcquisition = async (
|
||||
}
|
||||
switch (storeCategory) {
|
||||
default: {
|
||||
purchaseResponse = { InventoryChanges: await addItem(inventory, internalName, quantity, true, seed) };
|
||||
purchaseResponse = {
|
||||
InventoryChanges: await addItem(inventory, internalName, quantity, premiumPurchase, seed)
|
||||
};
|
||||
break;
|
||||
}
|
||||
case "Types":
|
||||
purchaseResponse = await handleTypesPurchase(internalName, inventory, quantity, ignorePurchaseQuantity);
|
||||
purchaseResponse = await handleTypesPurchase(
|
||||
internalName,
|
||||
inventory,
|
||||
quantity,
|
||||
ignorePurchaseQuantity,
|
||||
premiumPurchase,
|
||||
seed
|
||||
);
|
||||
break;
|
||||
case "Boosters":
|
||||
purchaseResponse = handleBoostersPurchase(storeItemName, inventory, durability);
|
||||
@ -478,13 +489,15 @@ const handleTypesPurchase = async (
|
||||
typesName: string,
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
quantity: number,
|
||||
ignorePurchaseQuantity: boolean
|
||||
ignorePurchaseQuantity: boolean,
|
||||
premiumPurchase: boolean = true,
|
||||
seed?: bigint
|
||||
): Promise<IPurchaseResponse> => {
|
||||
const typeCategory = getStoreItemTypesCategory(typesName);
|
||||
logger.debug(`type category ${typeCategory}`);
|
||||
switch (typeCategory) {
|
||||
default:
|
||||
return { InventoryChanges: await addItem(inventory, typesName, quantity) };
|
||||
return { InventoryChanges: await addItem(inventory, typesName, quantity, premiumPurchase, seed) };
|
||||
case "BoosterPacks":
|
||||
return handleBoosterPackPurchase(typesName, inventory, quantity);
|
||||
case "SlotItems":
|
||||
|
@ -49,6 +49,7 @@ export interface IInventoryDatabase
|
||||
| "PersonalTechProjects"
|
||||
| "LastSortieReward"
|
||||
| "LastLiteSortieReward"
|
||||
| "CrewMembers"
|
||||
| TEquipmentKey
|
||||
>,
|
||||
InventoryDatabaseEquipment {
|
||||
@ -83,6 +84,7 @@ export interface IInventoryDatabase
|
||||
PersonalTechProjects: IPersonalTechProjectDatabase[];
|
||||
LastSortieReward?: ILastSortieRewardDatabase[];
|
||||
LastLiteSortieReward?: ILastSortieRewardDatabase[];
|
||||
CrewMembers: ICrewMemberDatabase[];
|
||||
}
|
||||
|
||||
export interface IQuestKeyDatabase {
|
||||
@ -324,7 +326,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
||||
InfestedFoundry?: IInfestedFoundryClient;
|
||||
BlessingCooldown?: IMongoDate;
|
||||
CrewShipRawSalvage: ITypeCount[];
|
||||
CrewMembers: ICrewMember[];
|
||||
CrewMembers: ICrewMemberClient[];
|
||||
LotusCustomization: ILotusCustomization;
|
||||
UseAdultOperatorLoadout?: boolean;
|
||||
NemesisAbandonedRewards: string[];
|
||||
@ -461,13 +463,24 @@ export interface ICompletedJob {
|
||||
StageCompletions: number[];
|
||||
}
|
||||
|
||||
export interface ICrewMember {
|
||||
export interface ICrewMemberSkill {
|
||||
Assigned: number;
|
||||
}
|
||||
|
||||
export interface ICrewMemberSkillEfficiency {
|
||||
PILOTING: ICrewMemberSkill;
|
||||
GUNNERY: ICrewMemberSkill;
|
||||
ENGINEERING: ICrewMemberSkill;
|
||||
COMBAT: ICrewMemberSkill;
|
||||
SURVIVABILITY: ICrewMemberSkill;
|
||||
}
|
||||
|
||||
export interface ICrewMemberClient {
|
||||
ItemType: string;
|
||||
NemesisFingerprint: number;
|
||||
Seed: number;
|
||||
HireDate: IMongoDate;
|
||||
AssignedRole: number;
|
||||
SkillEfficiency: ISkillEfficiency;
|
||||
NemesisFingerprint: bigint;
|
||||
Seed: bigint;
|
||||
AssignedRole?: number;
|
||||
SkillEfficiency: ICrewMemberSkillEfficiency;
|
||||
WeaponConfigIdx: number;
|
||||
WeaponId: IOid;
|
||||
XP: number;
|
||||
@ -477,16 +490,9 @@ export interface ICrewMember {
|
||||
ItemId: IOid;
|
||||
}
|
||||
|
||||
export interface ISkillEfficiency {
|
||||
PILOTING: ICombat;
|
||||
GUNNERY: ICombat;
|
||||
ENGINEERING: ICombat;
|
||||
COMBAT: ICombat;
|
||||
SURVIVABILITY: ICombat;
|
||||
}
|
||||
|
||||
export interface ICombat {
|
||||
Assigned: number;
|
||||
export interface ICrewMemberDatabase extends Omit<ICrewMemberClient, "WeaponId" | "ItemId"> {
|
||||
WeaponId: Types.ObjectId;
|
||||
_id: Types.ObjectId;
|
||||
}
|
||||
|
||||
export enum InventorySlot {
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
INemesisClient,
|
||||
ITypeCount,
|
||||
IRecentVendorPurchaseClient,
|
||||
TEquipmentKey
|
||||
TEquipmentKey,
|
||||
ICrewMemberClient
|
||||
} from "./inventoryTypes/inventoryTypes";
|
||||
|
||||
export interface IPurchaseRequest {
|
||||
@ -47,6 +48,7 @@ export type IInventoryChanges = {
|
||||
Nemesis?: Partial<INemesisClient>;
|
||||
NewVendorPurchase?: IRecentVendorPurchaseClient; // >= 38.5.0
|
||||
RecentVendorPurchases?: IRecentVendorPurchaseClient; // < 38.5.0
|
||||
CrewMembers?: ICrewMemberClient[];
|
||||
} & Record<
|
||||
Exclude<
|
||||
string,
|
||||
|
Loading…
x
Reference in New Issue
Block a user