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: belly of the beast / eight claw (#2621)

Re #1103 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2621 Reviewed-by: Sainan <63328889+sainan@users.noreply.github.com> Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com> Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>

bf04755c
AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
提交于

代码差异

21 个文件 +320 -20
Modified config-vanilla.json +4 -0
@@ -79,6 +79,10 @@
79 79 "starDaysOverride": null,
80 80 "dogDaysOverride": null,
81 81 "dogDaysRewardsOverride": null,
82 "bellyOfTheBeast": false,
83 "bellyOfTheBeastProgressOverride": 0,
84 "eightClaw": false,
85 "eightClawProgressOverride": 0,
82 86 "eidolonOverride": "",
83 87 "vallisOverride": "",
84 88 "duviriOverride": "",
Added src/controllers/api/getGuildEventScore.ts +25 -0
@@ -0,0 +1,25 @@
1 import { RequestHandler } from "express";
2 import { getAccountForRequest } from "@/src/services/loginService";
3 import { getInventory } from "@/src/services/inventoryService";
4 import { Guild } from "@/src/models/guildModel";
5
6 export const getGuildEventScoreController: RequestHandler = async (req, res) => {
7 const account = await getAccountForRequest(req);
8 const inventory = await getInventory(account._id.toString(), "GuildId");
9 const guild = await Guild.findById(inventory.GuildId);
10 const goalId = req.query.goalId as string;
11 if (guild && guild.GoalProgress && goalId) {
12 const goal = guild.GoalProgress.find(x => x.goalId.toString() == goalId);
13 if (goal) {
14 return res.json({
15 Tier: guild.Tier,
16 GoalProgress: {
17 Count: goal.Count,
18 Tag: goal.Tag,
19 _id: { $oid: goal.goalId }
20 }
21 });
22 }
23 }
24 return res.json({});
25 };
Modified src/models/guildModel.ts +26 -1
@@ -19,6 +19,8 @@ import {
19 19 import { Document, Model, model, Schema, Types } from "mongoose";
20 20 import { fusionTreasuresSchema, typeCountSchema } from "@/src/models/inventoryModels/inventoryModel";
21 21 import { pictureFrameInfoSchema } from "@/src/models/personalRoomsModel";
22 import { IGoalProgressClient, IGoalProgressDatabase } from "@/src/types/inventoryTypes/inventoryTypes";
23 import { toOid } from "@/src/helpers/inventoryHelpers";
22 24
23 25 const dojoDecoSchema = new Schema<IDojoDecoDatabase>({
24 26 Type: String,
@@ -174,6 +176,28 @@ const guildLogEntryNumberSchema = new Schema<IGuildLogEntryNumber>(
174 176 { _id: false }
175 177 );
176 178
179 const goalProgressSchema = new Schema<IGoalProgressDatabase>(
180 {
181 Count: Number,
182 Tag: String,
183 goalId: Types.ObjectId
184 },
185 { _id: false }
186 );
187
188 goalProgressSchema.set("toJSON", {
189 virtuals: true,
190 transform(_doc, obj: Record<string, any>) {
191 const db = obj as IGoalProgressDatabase;
192 const client = obj as IGoalProgressClient;
193
194 client._id = toOid(db.goalId);
195
196 delete obj.goalId;
197 delete obj.__v;
198 }
199 });
200
177 201 const guildSchema = new Schema<IGuildDatabase>(
178 202 {
179 203 Name: { type: String, required: true, unique: true },
@@ -206,7 +230,8 @@ const guildSchema = new Schema<IGuildDatabase>(
206 230 RoomChanges: { type: [guildLogRoomChangeSchema], default: undefined },
207 231 TechChanges: { type: [guildLogEntryContributableSchema], default: undefined },
208 232 RosterActivity: { type: [guildLogEntryRosterSchema], default: undefined },
209 ClassChanges: { type: [guildLogEntryNumberSchema], default: undefined }
233 ClassChanges: { type: [guildLogEntryNumberSchema], default: undefined },
234 GoalProgress: { type: [goalProgressSchema], default: undefined }
210 235 },
211 236 { id: false }
212 237 );
Modified src/models/inventoryModels/inventoryModel.ts +5 -5
@@ -85,8 +85,8 @@ import {
85 85 IAccolades,
86 86 IHubNpcCustomization,
87 87 IEndlessXpReward,
88 IPersonalGoalProgressDatabase,
89 IPersonalGoalProgressClient,
88 IGoalProgressDatabase,
89 IGoalProgressClient,
90 90 IKubrowPetPrintClient,
91 91 IKubrowPetPrintDatabase
92 92 } from "@/src/types/inventoryTypes/inventoryTypes";
@@ -445,7 +445,7 @@ const discoveredMarkerSchema = new Schema<IDiscoveredMarker>(
445 445 { _id: false }
446 446 );
447 447
448 const personalGoalProgressSchema = new Schema<IPersonalGoalProgressDatabase>(
448 const personalGoalProgressSchema = new Schema<IGoalProgressDatabase>(
449 449 {
450 450 Best: Number,
451 451 Count: Number,
@@ -458,8 +458,8 @@ const personalGoalProgressSchema = new Schema<IPersonalGoalProgressDatabase>(
458 458 personalGoalProgressSchema.set("toJSON", {
459 459 virtuals: true,
460 460 transform(_doc, obj: Record<string, any>) {
461 const db = obj as IPersonalGoalProgressDatabase;
462 const client = obj as IPersonalGoalProgressClient;
461 const db = obj as IGoalProgressDatabase;
462 const client = obj as IGoalProgressClient;
463 463
464 464 client._id = toOid(db.goalId);
465 465
Modified src/routes/api.ts +2 -0
@@ -62,6 +62,7 @@ import { getFriendsController } from "@/src/controllers/api/getFriendsController
62 62 import { getGuildContributionsController } from "@/src/controllers/api/getGuildContributionsController";
63 63 import { getGuildController } from "@/src/controllers/api/getGuildController";
64 64 import { getGuildDojoController } from "@/src/controllers/api/getGuildDojoController";
65 import { getGuildEventScoreController } from "@/src/controllers/api/getGuildEventScore";
65 66 import { getGuildLogController } from "@/src/controllers/api/getGuildLogController";
66 67 import { getIgnoredUsersController } from "@/src/controllers/api/getIgnoredUsersController";
67 68 import { getNewRewardSeedController } from "@/src/controllers/api/getNewRewardSeedController";
@@ -192,6 +193,7 @@ apiRouter.get("/getFriends.php", getFriendsController);
192 193 apiRouter.get("/getGuild.php", getGuildController);
193 194 apiRouter.get("/getGuildContributions.php", getGuildContributionsController);
194 195 apiRouter.get("/getGuildDojo.php", getGuildDojoController);
196 apiRouter.get("/getGuildEventScore.php", getGuildEventScoreController);
195 197 apiRouter.get("/getGuildLog.php", getGuildLogController);
196 198 apiRouter.get("/getIgnoredUsers.php", getIgnoredUsersController);
197 199 apiRouter.get("/getMessages.php", inboxController); // unsure if this is correct, but needed for U17
Modified src/services/configService.ts +4 -0
@@ -91,6 +91,10 @@ export interface IConfig {
91 91 starDaysOverride?: boolean;
92 92 dogDaysOverride?: boolean;
93 93 dogDaysRewardsOverride?: number;
94 bellyOfTheBeast?: boolean;
95 bellyOfTheBeastProgressOverride?: number;
96 eightClaw?: boolean;
97 eightClawProgressOverride?: number;
94 98 eidolonOverride?: string;
95 99 vallisOverride?: string;
96 100 duviriOverride?: string;
Modified src/services/guildService.ts +90 -1
@@ -115,7 +115,14 @@ export const getGuildClient = async (
115 115 NumContributors: guild.CeremonyContributors?.length ?? 0,
116 116 CeremonyResetDate: guild.CeremonyResetDate ? toMongoDate(guild.CeremonyResetDate) : undefined,
117 117 AutoContributeFromVault: guild.AutoContributeFromVault,
118 AllianceId: guild.AllianceId ? toOid2(guild.AllianceId, account.BuildLabel) : undefined
118 AllianceId: guild.AllianceId ? toOid2(guild.AllianceId, account.BuildLabel) : undefined,
119 GoalProgress: guild.GoalProgress
120 ? guild.GoalProgress.map(gp => ({
121 Count: gp.Count,
122 Tag: gp.Tag,
123 _id: { $oid: gp.goalId.toString() }
124 }))
125 : undefined
119 126 };
120 127 };
121 128
@@ -809,3 +816,85 @@ export const getAllianceClient = async (
809 816 }
810 817 };
811 818 };
819
820 export const handleGuildGoalProgress = async (
821 guild: TGuildDatabaseDocument,
822 upload: { Count: number; Tag: string; goalId: Types.ObjectId }
823 ): Promise<void> => {
824 guild.GoalProgress ??= [];
825 const goalProgress = guild.GoalProgress.find(x => x.goalId.equals(upload.goalId));
826 if (!goalProgress) {
827 guild.GoalProgress.push({
828 Count: upload.Count,
829 Tag: upload.Tag,
830 goalId: upload.goalId
831 });
832 }
833 const totalCount = (goalProgress?.Count ?? 0) + upload.Count;
834 const guildRewards = goalGuildRewardByTag[upload.Tag].rewards;
835 const tierGoals = goalGuildRewardByTag[upload.Tag].guildGoals[guild.Tier - 1];
836 const rewards = [];
837 if (tierGoals.length && guildRewards.length) {
838 for (let i = 0; i < tierGoals.length; i++) {
839 if (
840 tierGoals[i] &&
841 tierGoals[i] <= totalCount &&
842 (!goalProgress || goalProgress.Count < tierGoals[i]) &&
843 guildRewards[i]
844 ) {
845 rewards.push(guildRewards[i]);
846 }
847 }
848
849 if (rewards.length) {
850 logger.debug(`guild goal rewards`, rewards);
851 guild.VaultDecoRecipes ??= [];
852 rewards.forEach(type => {
853 guild.VaultDecoRecipes!.push({
854 ItemType: type,
855 ItemCount: 1
856 });
857 });
858 }
859 }
860
861 if (goalProgress) {
862 goalProgress.Count += upload.Count;
863 }
864 await guild.save();
865 };
866
867 export const goalGuildRewardByTag: Record<string, { guildGoals: number[][]; rewards: string[] }> = {
868 JadeShadowsEvent: {
869 guildGoals: [
870 // I don't know what ClanGoal means
871 [15, 30, 45, 60],
872 [45, 90, 135, 180],
873 [150, 300, 450, 600],
874 [450, 900, 1350, 1800],
875 [1500, 3000, 4500, 6000]
876 ],
877 rewards: [
878 "/Lotus/Levels/ClanDojo/ComponentPropRecipes/JadeShadowsEventPewterTrophyRecipe",
879 "/Lotus/Levels/ClanDojo/ComponentPropRecipes/JadeShadowsEventBronzeTrophyRecipe",
880 "/Lotus/Levels/ClanDojo/ComponentPropRecipes/JadeShadowsEventSilverTrophyRecipe",
881 "/Lotus/Levels/ClanDojo/ComponentPropRecipes/JadeShadowsEventGoldTrophyRecipe"
882 ]
883 },
884 DuviriMurmurEvent: {
885 guildGoals: [
886 // I don't know what ClanGoal means
887 [260, 519, 779, 1038],
888 [779, 1557, 2336, 3114],
889 [2595, 5190, 7785, 10380],
890 [7785, 15570, 23355, 31140],
891 [29950, 51900, 77850, 103800]
892 ],
893 rewards: [
894 "/Lotus/Levels/ClanDojo/ComponentPropRecipes/DuviriMurmurEventClayTrophyRecipe",
895 "/Lotus/Levels/ClanDojo/ComponentPropRecipes/DuviriMurmurEventBronzeTrophyRecipe",
896 "/Lotus/Levels/ClanDojo/ComponentPropRecipes/DuviriMurmurEventSilverTrophyRecipe",
897 "/Lotus/Levels/ClanDojo/ComponentPropRecipes/DuviriMurmurEventGoldTrophyRecipe"
898 ]
899 }
900 };
Modified src/services/missionInventoryUpdateService.ts +13 -1
@@ -81,6 +81,8 @@ import { fromOid } from "@/src/helpers/inventoryHelpers";
81 81 import { TAccountDocument } from "@/src/services/loginService";
82 82 import { ITypeCount } from "@/src/types/commonTypes";
83 83 import { IEquipmentClient } from "@/src/types/equipmentTypes";
84 import { Guild } from "@/src/models/guildModel";
85 import { handleGuildGoalProgress } from "@/src/services/guildService";
84 86
85 87 const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[] => {
86 88 // Disruption missions just tell us (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/2599)
@@ -712,10 +714,20 @@ export const addMissionInventoryUpdates = async (
712 714 }
713 715
714 716 if (goalProgress) {
715 goalProgress.Best = Math.max(goalProgress.Best, uploadProgress.Best);
717 goalProgress.Best = Math.max(goalProgress.Best!, uploadProgress.Best);
716 718 goalProgress.Count += uploadProgress.Count;
717 719 }
718 720 }
721 if (goal && goal.ClanGoal && inventory.GuildId) {
722 const guild = await Guild.findById(inventory.GuildId, "GoalProgress Tier VaultDecoRecipes");
723 if (guild) {
724 await handleGuildGoalProgress(guild, {
725 Count: uploadProgress.Count,
726 Tag: goal.Tag,
727 goalId: new Types.ObjectId(goal._id.$oid)
728 });
729 }
730 }
719 731 }
720 732 break;
721 733 }
Modified src/services/purchaseService.ts +19 -0
@@ -36,6 +36,9 @@ import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/invento
36 36 import { fromStoreItem, toStoreItem } from "@/src/services/itemDataService";
37 37 import { DailyDeal } from "@/src/models/worldStateModel";
38 38 import { fromMongoDate, toMongoDate } from "@/src/helpers/inventoryHelpers";
39 import { Guild } from "@/src/models/guildModel";
40 import { handleGuildGoalProgress } from "@/src/services/guildService";
41 import { Types } from "mongoose";
39 42
40 43 export const getStoreItemCategory = (storeItem: string): string => {
41 44 const storeItemString = getSubstringFromKeyword(storeItem, "StoreItems/");
@@ -137,6 +140,22 @@ export const handlePurchase = async (
137 140 updateCurrency(inventory, offer.PremiumPrice[0], true, prePurchaseInventoryChanges);
138 141 }
139 142 }
143 if (
144 inventory.GuildId &&
145 offer.ItemPrices &&
146 manifest.VendorInfo.TypeName ==
147 "/Lotus/Types/Game/VendorManifests/Events/DuviriMurmurInvasionVendorManifest"
148 ) {
149 const guild = await Guild.findById(inventory.GuildId, "GoalProgress Tier VaultDecoRecipes");
150 const goal = getWorldState().Goals.find(x => x.Tag == "DuviriMurmurEvent");
151 if (guild && goal) {
152 await handleGuildGoalProgress(guild, {
153 Count: offer.ItemPrices[0].ItemCount * purchaseRequest.PurchaseParams.Quantity,
154 Tag: goal.Tag,
155 goalId: new Types.ObjectId(goal._id.$oid)
156 });
157 }
158 }
140 159 if (!config.dontSubtractPurchaseItemCost) {
141 160 if (offer.ItemPrices) {
142 161 handleItemPrices(
Modified src/services/worldStateService.ts +43 -0
@@ -2265,6 +2265,49 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
2265 2265 BonusReward: { items: ["/Lotus/StoreItems/Upgrades/Skins/Clan/BountyHunterBadgeItem"] }
2266 2266 });
2267 2267 }
2268 if (config.worldState?.bellyOfTheBeast) {
2269 worldState.Goals.push({
2270 _id: { $oid: "67a5035c2a198564d62e165e" },
2271 Activation: { $date: { $numberLong: "1738868400000" } },
2272 Expiry: { $date: { $numberLong: "2000000000000" } },
2273 Count: config.worldState.bellyOfTheBeastProgressOverride ?? 0,
2274 HealthPct: (config.worldState.bellyOfTheBeastProgressOverride ?? 0) / 100,
2275 Goal: 0,
2276 Personal: true,
2277 Community: true,
2278 ClanGoal: [72, 216, 648, 1944, 5832],
2279 Tag: "JadeShadowsEvent",
2280 Faction: "FC_MITW",
2281 Desc: "/Lotus/Language/JadeShadows/JadeShadowsEventName",
2282 ToolTip: "/Lotus/Language/JadeShadows/JadeShadowsShortEventDesc",
2283 Icon: "/Lotus/Interface/Icons/WorldStatePanel/JadeShadowsEventBadge.png",
2284 ScoreLocTag: "/Lotus/Language/JadeShadows/JadeShadowsEventScore",
2285 Node: "SolNode723",
2286 MissionKeyName: "/Lotus/Types/Keys/JadeShadowsEventMission",
2287 ItemType: "/Lotus/Types/Gameplay/JadeShadows/Resources/AscensionEventResourceItem"
2288 });
2289 }
2290 if (config.worldState?.eightClaw) {
2291 worldState.Goals.push({
2292 _id: { $oid: "685c15f80000000000000000" },
2293 Activation: { $date: { $numberLong: "1750865400000" } },
2294 Expiry: { $date: { $numberLong: "2000000000000" } },
2295 Count: config.worldState.eightClawProgressOverride ?? 0,
2296 HealthPct: (config.worldState.eightClawProgressOverride ?? 0) / 100,
2297 Goal: 0,
2298 Personal: true,
2299 Community: true,
2300 ClanGoal: [72, 216, 648, 1944, 5832],
2301 Tag: "DuviriMurmurEvent",
2302 Faction: "FC_MITW",
2303 Desc: "/Lotus/Language/Isleweaver/DuviriMurmurEventTitle",
2304 ToolTip: "/Lotus/Language/Isleweaver/DuviriMurmurEventDescription",
2305 Icon: "/Lotus/Interface/Icons/WorldStatePanel/EightClawEventBadge.png",
2306 ScoreLocTag: "/Lotus/Language/Isleweaver/DuviriMurmurEventScore",
2307 Node: "SolNode236",
2308 MissionKeyName: "/Lotus/Types/Keys/DuviriMITW/DuviriMITWEventKey"
2309 });
2310 }
2268 2311
2269 2312 // Nightwave Challenges
2270 2313 const nightwaveSyndicateTag = getNightwaveSyndicateTag(buildLabel);
Modified src/types/guildTypes.ts +10 -1
@@ -1,6 +1,11 @@
1 1 import { Types } from "mongoose";
2 2 import { IOid, IMongoDate, IOidWithLegacySupport, ITypeCount } from "@/src/types/commonTypes";
3 import { IFusionTreasure, IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
3 import {
4 IFusionTreasure,
5 IMiscItem,
6 IGoalProgressDatabase,
7 IGoalProgressClient
8 } from "@/src/types/inventoryTypes/inventoryTypes";
4 9 import { IPictureFrameInfo } from "@/src/types/personalRoomsTypes";
5 10 import { IFriendInfo } from "@/src/types/friendTypes";
6 11
@@ -23,6 +28,8 @@ export interface IGuildClient {
23 28 CrossPlatformEnabled?: boolean;
24 29 AutoContributeFromVault?: boolean;
25 30 AllianceId?: IOidWithLegacySupport;
31
32 GoalProgress?: IGoalProgressClient[];
26 33 }
27 34
28 35 export interface IGuildDatabase {
@@ -63,6 +70,8 @@ export interface IGuildDatabase {
63 70 TechChanges?: IGuildLogEntryContributable[];
64 71 RosterActivity?: IGuildLogEntryRoster[];
65 72 ClassChanges?: IGuildLogEntryNumber[];
73
74 GoalProgress?: IGoalProgressDatabase[];
66 75 }
67 76
68 77 export interface ILongMOTD {
Modified src/types/inventoryTypes/inventoryTypes.ts +5 -5
@@ -109,7 +109,7 @@ export interface IInventoryDatabase
109 109 QualifyingInvasions: IInvasionProgressDatabase[];
110 110 LastInventorySync?: Types.ObjectId;
111 111 EndlessXP?: IEndlessXpProgressDatabase[];
112 PersonalGoalProgress?: IPersonalGoalProgressDatabase[];
112 PersonalGoalProgress?: IGoalProgressDatabase[];
113 113 }
114 114
115 115 export interface IQuestKeyDatabase {
@@ -318,7 +318,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
318 318 HWIDProtectEnabled?: boolean;
319 319 KubrowPetPrints: IKubrowPetPrintClient[];
320 320 AlignmentReplay?: IAlignment;
321 PersonalGoalProgress?: IPersonalGoalProgressClient[];
321 PersonalGoalProgress?: IGoalProgressClient[];
322 322 ThemeStyle: string;
323 323 ThemeBackground: string;
324 324 ThemeSounds: string;
@@ -895,8 +895,8 @@ export interface IPeriodicMissionCompletionResponse extends Omit<IPeriodicMissio
895 895 date: IMongoDate;
896 896 }
897 897
898 export interface IPersonalGoalProgressClient {
899 Best: number;
898 export interface IGoalProgressClient {
899 Best?: number;
900 900 Count: number;
901 901 Tag: string;
902 902 _id: IOid;
@@ -904,7 +904,7 @@ export interface IPersonalGoalProgressClient {
904 904 //ReceivedClanReward1?: boolean;
905 905 }
906 906
907 export interface IPersonalGoalProgressDatabase extends Omit<IPersonalGoalProgressClient, "_id"> {
907 export interface IGoalProgressDatabase extends Omit<IGoalProgressClient, "_id"> {
908 908 goalId: Types.ObjectId;
909 909 }
910 910
Modified src/types/worldStateTypes.ts +20 -6
Modified static/webui/index.html +26 -0
Modified static/webui/translations/de.js +4 -0
Modified static/webui/translations/en.js +4 -0
Modified static/webui/translations/es.js +4 -0
Modified static/webui/translations/fr.js +4 -0
Modified static/webui/translations/ru.js +4 -0
Modified static/webui/translations/uk.js +4 -0
Modified static/webui/translations/zh.js +4 -0