返回提交历史
Modified
config-vanilla.json
+4
-0
Added
src/controllers/api/getGuildEventScore.ts
+25
-0
Modified
src/models/guildModel.ts
+26
-1
Modified
src/models/inventoryModels/inventoryModel.ts
+5
-5
Modified
src/routes/api.ts
+2
-0
Modified
src/services/configService.ts
+4
-0
Modified
src/services/guildService.ts
+90
-1
Modified
src/services/missionInventoryUpdateService.ts
+13
-1
Modified
src/services/purchaseService.ts
+19
-0
Modified
src/services/worldStateService.ts
+43
-0
Modified
src/types/guildTypes.ts
+10
-1
Modified
src/types/inventoryTypes/inventoryTypes.ts
+5
-5
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
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
代码差异
21 个文件
+320
-20
@@ -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": "",
@@ -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
};
@@ -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
);
@@ -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
@@ -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
@@ -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;
@@ -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
};
@@ -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
}
@@ -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(
@@ -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);
@@ -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 {
@@ -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