返回提交历史
Modified
.eslintrc
+9
-9
Modified
src/controllers/api/claimCompletedRecipeController.ts
+5
-1
Modified
src/controllers/api/startRecipeController.ts
+6
-2
Modified
src/models/inventoryModels/inventoryModel.ts
+26
-2
Modified
src/services/inventoryService.ts
+34
-10
Modified
src/services/missionInventoryUpdateService.ts
+0
-1
Modified
src/types/inventoryTypes/inventoryTypes.ts
+11
-9
Modified
src/types/purchaseTypes.ts
+3
-1
XFEstudio/XFESpaceNinjaServer
feat: create genetic imprint (#2337)
Re #2212 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2337 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
44a129ab
代码差异
8 个文件
+94
-35
@@ -11,17 +11,17 @@
11
11
"node": true
12
12
},
13
13
"rules": {
14
"@typescript-eslint/explicit-function-return-type": "warn",
15
"@typescript-eslint/restrict-template-expressions": "warn",
16
"@typescript-eslint/restrict-plus-operands": "warn",
17
"@typescript-eslint/no-unsafe-member-access": "warn",
14
"@typescript-eslint/explicit-function-return-type": "error",
15
"@typescript-eslint/restrict-template-expressions": "error",
16
"@typescript-eslint/restrict-plus-operands": "error",
17
"@typescript-eslint/no-unsafe-member-access": "error",
18
18
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "caughtErrors": "none" }],
19
19
"@typescript-eslint/no-unsafe-argument": "error",
20
"@typescript-eslint/no-unsafe-call": "warn",
21
"@typescript-eslint/no-unsafe-assignment": "warn",
22
"@typescript-eslint/no-explicit-any": "warn",
23
"no-loss-of-precision": "warn",
24
"@typescript-eslint/no-unnecessary-condition": "warn",
20
"@typescript-eslint/no-unsafe-call": "error",
21
"@typescript-eslint/no-unsafe-assignment": "error",
22
"@typescript-eslint/no-explicit-any": "error",
23
"no-loss-of-precision": "error",
24
"@typescript-eslint/no-unnecessary-condition": "error",
25
25
"@typescript-eslint/no-base-to-string": "off",
26
26
"no-case-declarations": "error",
27
27
"prettier/prettier": "error",
@@ -13,7 +13,8 @@ import {
13
13
addItem,
14
14
addRecipes,
15
15
occupySlot,
16
combineInventoryChanges
16
combineInventoryChanges,
17
addKubrowPetPrint
17
18
} from "@/src/services/inventoryService";
18
19
import { IInventoryChanges } from "@/src/types/purchaseTypes";
19
20
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
@@ -119,6 +120,9 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
119
120
}
120
121
}
121
122
pet.Details!.Status = canSetActive ? Status.StatusAvailable : Status.StatusStasis;
123
} else if (recipe.secretIngredientAction == "SIA_DISTILL_PRINT") {
124
const pet = inventory.KubrowPets.id(pendingRecipe.KubrowPet!)!;
125
addKubrowPetPrint(inventory, pet, InventoryChanges);
122
126
} else if (recipe.secretIngredientAction != "SIA_UNBRAND") {
123
127
InventoryChanges = {
124
128
...InventoryChanges,
@@ -45,9 +45,9 @@ export const startRecipeController: RequestHandler = async (req, res) => {
45
45
for (let i = 0; i != recipe.ingredients.length; ++i) {
46
46
if (startRecipeRequest.Ids[i] && startRecipeRequest.Ids[i][0] != "/") {
47
47
if (recipe.ingredients[i].ItemType == "/Lotus/Types/Game/KubrowPet/Eggs/KubrowPetEggItem") {
48
const index = inventory.KubrowPetEggs!.findIndex(x => x._id.equals(startRecipeRequest.Ids[i]));
48
const index = inventory.KubrowPetEggs.findIndex(x => x._id.equals(startRecipeRequest.Ids[i]));
49
49
if (index != -1) {
50
inventory.KubrowPetEggs!.splice(index, 1);
50
inventory.KubrowPetEggs.splice(index, 1);
51
51
}
52
52
} else {
53
53
const category = ExportWeapons[recipe.ingredients[i].ItemType].productCategory;
@@ -72,6 +72,10 @@ export const startRecipeController: RequestHandler = async (req, res) => {
72
72
if (recipe.secretIngredientAction == "SIA_CREATE_KUBROW") {
73
73
inventoryChanges = addKubrowPet(inventory, getRandomElement(recipe.secretIngredients!)!.ItemType);
74
74
pr.KubrowPet = new Types.ObjectId(fromOid(inventoryChanges.KubrowPets![0].ItemId));
75
} else if (recipe.secretIngredientAction == "SIA_DISTILL_PRINT") {
76
pr.KubrowPet = new Types.ObjectId(startRecipeRequest.Ids[recipe.ingredients.length]);
77
const pet = inventory.KubrowPets.id(pr.KubrowPet)!;
78
pet.Details!.PrintsRemaining -= 1;
75
79
} else if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
76
80
const spectreLoadout: ISpectreLoadout = {
77
81
ItemType: recipe.resultType,
@@ -99,7 +99,9 @@ import {
99
99
ILotusCustomization,
100
100
IEndlessXpReward,
101
101
IPersonalGoalProgressDatabase,
102
IPersonalGoalProgressClient
102
IPersonalGoalProgressClient,
103
IKubrowPetPrintClient,
104
IKubrowPetPrintDatabase
103
105
} from "../../types/inventoryTypes/inventoryTypes";
104
106
import { IOid } from "../../types/commonTypes";
105
107
import {
@@ -1008,6 +1010,27 @@ const traitsSchema = new Schema<ITraits>(
1008
1010
{ _id: false }
1009
1011
);
1010
1012
1013
const kubrowPetPrintSchema = new Schema<IKubrowPetPrintDatabase>({
1014
ItemType: String,
1015
Name: String,
1016
IsMale: Boolean,
1017
Size: Number,
1018
DominantTraits: traitsSchema,
1019
RecessiveTraits: traitsSchema
1020
});
1021
kubrowPetPrintSchema.set("toJSON", {
1022
virtuals: true,
1023
transform(_doc, obj) {
1024
const db = obj as IKubrowPetPrintDatabase;
1025
const client = obj as IKubrowPetPrintClient;
1026
1027
client.ItemId = toOid(db._id);
1028
1029
delete obj._id;
1030
delete obj.__v;
1031
}
1032
});
1033
1011
1034
const detailsSchema = new Schema<IKubrowPetDetailsDatabase>(
1012
1035
{
1013
1036
Name: String,
@@ -1511,7 +1534,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
1511
1534
1512
1535
KubrowPetEggs: [kubrowPetEggSchema],
1513
1536
//Prints Cat(3 Prints)\Kubrow(2 Prints) Pets
1514
//KubrowPetPrints: [Schema.Types.Mixed],
1537
KubrowPetPrints: [kubrowPetPrintSchema],
1515
1538
1516
1539
//Item for EquippedGear example:Scaner,LoadoutTechSummon etc
1517
1540
Consumables: [typeCountSchema],
@@ -1852,6 +1875,7 @@ export type InventoryDocumentProps = {
1852
1875
CrewShipSalvagedWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
1853
1876
PersonalTechProjects: Types.DocumentArray<IPersonalTechProjectDatabase>;
1854
1877
CrewMembers: Types.DocumentArray<ICrewMemberDatabase>;
1878
KubrowPetPrints: Types.DocumentArray<IKubrowPetPrintDatabase>;
1855
1879
} & { [K in TEquipmentKey]: Types.DocumentArray<IEquipmentDatabase> };
1856
1880
1857
1881
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
@@ -29,7 +29,8 @@ import {
29
29
ICalendarProgress,
30
30
INemesisWeaponTargetFingerprint,
31
31
INemesisPetTargetFingerprint,
32
IDialogueDatabase
32
IDialogueDatabase,
33
IKubrowPetPrintClient
33
34
} from "@/src/types/inventoryTypes/inventoryTypes";
34
35
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
35
36
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
@@ -424,7 +425,6 @@ export const addItem = async (
424
425
ItemType: "/Lotus/Types/Game/KubrowPet/Eggs/KubrowEgg",
425
426
_id: new Types.ObjectId()
426
427
};
427
inventory.KubrowPetEggs ??= [];
428
428
inventory.KubrowPetEggs.push(egg);
429
429
changes.push({
430
430
ItemType: egg.ItemType,
@@ -784,7 +784,11 @@ export const addItem = async (
784
784
typeName.substr(1).split("/")[3] == "CatbrowPet" ||
785
785
typeName.substr(1).split("/")[3] == "KubrowPet"
786
786
) {
787
if (typeName != "/Lotus/Types/Game/KubrowPet/Eggs/KubrowPetEggItem") {
787
if (
788
typeName != "/Lotus/Types/Game/KubrowPet/Eggs/KubrowPetEggItem" &&
789
typeName != "/Lotus/Types/Game/KubrowPet/BlankTraitPrint" &&
790
typeName != "/Lotus/Types/Game/KubrowPet/ImprintedTraitPrint"
791
) {
788
792
return addKubrowPet(inventory, typeName, undefined, premiumPurchase);
789
793
}
790
794
} else if (typeName.startsWith("/Lotus/Types/Game/CrewShip/CrewMember/")) {
@@ -1048,8 +1052,13 @@ export const addKubrowPet = (
1048
1052
const configs: IItemConfig[] = applyDefaultUpgrades(inventory, kubrowPet?.defaultUpgrades);
1049
1053
1050
1054
if (!details) {
1051
let traits: ITraits;
1055
const isCatbrow = [
1056
"/Lotus/Types/Game/CatbrowPet/CheshireCatbrowPetPowerSuit",
1057
"/Lotus/Types/Game/CatbrowPet/MirrorCatbrowPetPowerSuit",
1058
"/Lotus/Types/Game/CatbrowPet/VampireCatbrowPetPowerSuit"
1059
].includes(kubrowPetName);
1052
1060
1061
let traits: ITraits;
1053
1062
if (kubrowPetName == "/Lotus/Types/Game/CatbrowPet/VampireCatbrowPetPowerSuit") {
1054
1063
traits = {
1055
1064
BaseColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseVampire",
@@ -1064,12 +1073,7 @@ export const addKubrowPet = (
1064
1073
Tail: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailVampire"
1065
1074
};
1066
1075
} else {
1067
const isCatbrow = [
1068
"/Lotus/Types/Game/CatbrowPet/MirrorCatbrowPetPowerSuit",
1069
"/Lotus/Types/Game/CatbrowPet/CheshireCatbrowPetPowerSuit"
1070
].includes(kubrowPetName);
1071
1076
const traitsPool = isCatbrow ? catbrowDetails : kubrowDetails;
1072
1073
1077
traits = {
1074
1078
BaseColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type,
1075
1079
SecondaryColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type,
@@ -1088,7 +1092,7 @@ export const addKubrowPet = (
1088
1092
Name: "",
1089
1093
IsPuppy: !premiumPurchase,
1090
1094
HasCollar: true,
1091
PrintsRemaining: 3,
1095
PrintsRemaining: isCatbrow ? 3 : 2,
1092
1096
Status: premiumPurchase ? Status.StatusStasis : Status.StatusIncubating,
1093
1097
HatchDate: premiumPurchase ? new Date() : new Date(Date.now() + 10 * unixTimesInMs.hour), // On live, this seems to be somewhat randomised so that the pet hatches 9~11 hours after start.
1094
1098
IsMale: !!getRandomInt(0, 1),
@@ -1112,6 +1116,26 @@ export const addKubrowPet = (
1112
1116
return inventoryChanges;
1113
1117
};
1114
1118
1119
export const addKubrowPetPrint = (
1120
inventory: TInventoryDatabaseDocument,
1121
pet: IEquipmentDatabase,
1122
inventoryChanges: IInventoryChanges
1123
): void => {
1124
inventoryChanges.KubrowPetPrints ??= [];
1125
inventoryChanges.KubrowPetPrints.push(
1126
inventory.KubrowPetPrints[
1127
inventory.KubrowPetPrints.push({
1128
ItemType: "/Lotus/Types/Game/KubrowPet/ImprintedTraitPrint",
1129
Name: pet.Details!.Name,
1130
IsMale: pet.Details!.IsMale,
1131
Size: pet.Details!.Size,
1132
DominantTraits: pet.Details!.DominantTraits,
1133
RecessiveTraits: pet.Details!.RecessiveTraits
1134
}) - 1
1135
].toJSON<IKubrowPetPrintClient>()
1136
);
1137
};
1138
1115
1139
export const updateSlots = (
1116
1140
inventory: TInventoryDatabaseDocument,
1117
1141
slotName: SlotNames,
@@ -525,7 +525,6 @@ export const addMissionInventoryUpdates = async (
525
525
}
526
526
case "KubrowPetEggs": {
527
527
for (const egg of value) {
528
inventory.KubrowPetEggs ??= [];
529
528
inventory.KubrowPetEggs.push({
530
529
ItemType: egg.ItemType,
531
530
_id: new Types.ObjectId()
@@ -40,6 +40,7 @@ export interface IInventoryDatabase
40
40
| "InfestedFoundry"
41
41
| "DialogueHistory"
42
42
| "KubrowPetEggs"
43
| "KubrowPetPrints"
43
44
| "PendingCoupon"
44
45
| "Drones"
45
46
| "RecentVendorPurchases"
@@ -79,7 +80,8 @@ export interface IInventoryDatabase
79
80
KahlLoadOuts: IOperatorConfigDatabase[];
80
81
InfestedFoundry?: IInfestedFoundryDatabase;
81
82
DialogueHistory?: IDialogueHistoryDatabase;
82
KubrowPetEggs?: IKubrowPetEggDatabase[];
83
KubrowPetEggs: IKubrowPetEggDatabase[];
84
KubrowPetPrints: IKubrowPetPrintDatabase[];
83
85
PendingCoupon?: IPendingCouponDatabase;
84
86
Drones: IDroneDatabase[];
85
87
RecentVendorPurchases?: IRecentVendorPurchaseDatabase[];
@@ -307,7 +309,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
307
309
FocusUpgrades: IFocusUpgrade[];
308
310
HasContributedToDojo?: boolean;
309
311
HWIDProtectEnabled?: boolean;
310
//KubrowPetPrints: IKubrowPetPrint[];
312
KubrowPetPrints: IKubrowPetPrintClient[];
311
313
AlignmentReplay?: IAlignment;
312
314
PersonalGoalProgress?: IPersonalGoalProgressClient[];
313
315
ThemeStyle: string;
@@ -722,8 +724,8 @@ export interface IKubrowPetEggDatabase {
722
724
_id: Types.ObjectId;
723
725
}
724
726
725
export interface IKubrowPetPrint {
726
ItemType: KubrowPetPrintItemType;
727
export interface IKubrowPetPrintClient {
728
ItemType: "/Lotus/Types/Game/KubrowPet/ImprintedTraitPrint";
727
729
Name: string;
728
730
IsMale: boolean;
729
731
Size: number; // seems to be 0.7 to 1.0
@@ -733,6 +735,10 @@ export interface IKubrowPetPrint {
733
735
InheritedModularParts?: any[];
734
736
}
735
737
738
export interface IKubrowPetPrintDatabase extends Omit<IKubrowPetPrintClient, "ItemId" | "InheritedModularParts"> {
739
_id: Types.ObjectId;
740
}
741
736
742
export interface ITraits {
737
743
BaseColor: string;
738
744
SecondaryColor: string;
@@ -746,15 +752,11 @@ export interface ITraits {
746
752
Tail?: string;
747
753
}
748
754
749
export enum KubrowPetPrintItemType {
750
LotusTypesGameKubrowPetImprintedTraitPrint = "/Lotus/Types/Game/KubrowPet/ImprintedTraitPrint"
751
}
752
753
755
export interface IKubrowPetDetailsDatabase {
754
756
Name?: string;
755
757
IsPuppy?: boolean;
756
758
HasCollar: boolean;
757
PrintsRemaining?: number;
759
PrintsRemaining: number;
758
760
Status: Status;
759
761
HatchDate?: Date;
760
762
DominantTraits: ITraits;
@@ -7,7 +7,8 @@ import {
7
7
ITypeCount,
8
8
IRecentVendorPurchaseClient,
9
9
TEquipmentKey,
10
ICrewMemberClient
10
ICrewMemberClient,
11
IKubrowPetPrintClient
11
12
} from "./inventoryTypes/inventoryTypes";
12
13
13
14
export enum PurchaseSource {
@@ -78,6 +79,7 @@ export type IInventoryChanges = {
78
79
NewVendorPurchase?: IRecentVendorPurchaseClient; // >= 38.5.0
79
80
RecentVendorPurchases?: IRecentVendorPurchaseClient; // < 38.5.0
80
81
CrewMembers?: ICrewMemberClient[];
82
KubrowPetPrints?: IKubrowPetPrintClient[];
81
83
} & Record<
82
84
Exclude<
83
85
string,