XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFESpaceNinjaServer

A simple server for a small space ninja game

公开
关注 0 Fork 0 Star 0
返回提交历史

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
Sainan <63328889+Sainan@users.noreply.github.com>
提交于

代码差异

8 个文件 +94 -35
Modified .eslintrc +9 -9
@@ -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",
Modified src/controllers/api/claimCompletedRecipeController.ts +5 -1
@@ -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,
Modified src/controllers/api/startRecipeController.ts +6 -2
@@ -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,
Modified src/models/inventoryModels/inventoryModel.ts +26 -2
@@ -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
Modified src/services/inventoryService.ts +34 -10
@@ -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,
Modified src/services/missionInventoryUpdateService.ts +0 -1
@@ -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()
Modified src/types/inventoryTypes/inventoryTypes.ts +11 -9
@@ -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;
Modified src/types/purchaseTypes.ts +3 -1
@@ -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,