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: St. Patrick’s Day FlashSales (#3446)

Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/3446 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>

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

代码差异

12 个文件 +128 -126
Modified config-vanilla.json +1 -0
@@ -72,6 +72,7 @@
72 72 "ghoulEmergenceOverride": null,
73 73 "plagueStarOverride": null,
74 74 "starDaysOverride": null,
75 "saintPatrickOverride": null,
75 76 "dogDaysOverride": null,
76 77 "dogDaysRewardsOverride": null,
77 78 "bellyOfTheBeast": false,
Modified src/services/configService.ts +1 -0
@@ -84,6 +84,7 @@ export interface IConfig {
84 84 ghoulEmergenceOverride?: boolean;
85 85 plagueStarOverride?: boolean;
86 86 starDaysOverride?: boolean;
87 saintPatrickOverride?: boolean;
87 88 dogDaysOverride?: boolean;
88 89 dogDaysRewardsOverride?: number;
89 90 bellyOfTheBeast?: boolean;
Modified src/services/worldStateService.ts +103 -123
@@ -1897,16 +1897,16 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
1897 1897 }
1898 1898
1899 1899 if (config.worldState?.qtccAlerts) {
1900 const activationTimeStamp = "1759327200000";
1901 const expiryTimeStamp = "2000000000000";
1900 const activation = 1759327200000;
1901 const expiry = 2000000000000;
1902 1902
1903 1903 worldState.Alerts.push(
1904 1904 {
1905 1905 _id: {
1906 1906 $oid: "68dc23c42e9d3acfa708ff3b"
1907 1907 },
1908 Activation: { $date: { $numberLong: activationTimeStamp } },
1909 Expiry: { $date: { $numberLong: expiryTimeStamp } },
1908 Activation: { $date: { $numberLong: activation.toString() } },
1909 Expiry: { $date: { $numberLong: expiry.toString() } },
1910 1910 MissionInfo: {
1911 1911 location: "SolNode123",
1912 1912 missionType: "MT_SURVIVAL",
@@ -1930,8 +1930,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
1930 1930 _id: {
1931 1931 $oid: "68dc2466e298b4f04206687a"
1932 1932 },
1933 Activation: { $date: { $numberLong: activationTimeStamp } },
1934 Expiry: { $date: { $numberLong: expiryTimeStamp } },
1933 Activation: { $date: { $numberLong: activation.toString() } },
1934 Expiry: { $date: { $numberLong: expiry.toString() } },
1935 1935 MissionInfo: {
1936 1936 location: "SolNode149",
1937 1937 missionType: "MT_DEFENSE",
@@ -1955,8 +1955,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
1955 1955 _id: {
1956 1956 $oid: "68dc26865e7cb56b820b4252"
1957 1957 },
1958 Activation: { $date: { $numberLong: activationTimeStamp } },
1959 Expiry: { $date: { $numberLong: expiryTimeStamp } },
1958 Activation: { $date: { $numberLong: activation.toString() } },
1959 Expiry: { $date: { $numberLong: expiry.toString() } },
1960 1960 MissionInfo: {
1961 1961 location: "SolNode39",
1962 1962 missionType: "MT_EXCAVATE",
@@ -2007,42 +2007,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
2007 2007 { TypeName: "/Lotus/Types/Items/ShipDecos/Plushies/PlushyProtectorStalker", PremiumOverride: 35 }
2008 2008 ];
2009 2009
2010 worldState.FlashSales.push(
2011 ...storeItems.map(item => ({
2012 ...{
2013 StartDate: { $date: { $numberLong: activationTimeStamp } },
2014 EndDate: { $date: { $numberLong: expiryTimeStamp } },
2015 ProductExpiryOverride: { $date: { $numberLong: expiryTimeStamp } },
2016 ShowInMarket: item.ShowInMarket ?? true,
2017 HideFromMarket: item.HideFromMarket ?? false,
2018 SupporterPack: item.SupporterPack ?? false,
2019 Discount: item.Discount ?? 0,
2020 BogoBuy: item.BogoBuy ?? 0,
2021 BogoGet: item.BogoGet ?? 0,
2022 RegularOverride: item.RegularOverride ?? 0,
2023 PremiumOverride: item.PremiumOverride ?? 0
2024 },
2025 ...item
2026 }))
2027 );
2028
2029 const seasonalItems = storeItems.map(item => item.TypeName);
2030
2031 const seasonalCategory = worldState.InGameMarket.LandingPage.Categories.find(
2032 c => c.CategoryName == "COMMUNITY"
2033 );
2034 if (seasonalCategory) {
2035 seasonalCategory.Items ??= [];
2036 seasonalCategory.Items.push(...seasonalItems);
2037 } else {
2038 worldState.InGameMarket.LandingPage.Categories.push({
2039 CategoryName: "COMMUNITY",
2040 Name: "/Lotus/Language/Store/CommunityCategoryTitle",
2041 Icon: "community",
2042 AddToMenu: true,
2043 Items: seasonalItems
2044 });
2045 }
2010 pushFlashSales(worldState, storeItems, activation, expiry, "COMMUNITY", buildLabel);
2046 2011 }
2047 2012
2048 2013 const isFebruary = date.getUTCMonth() == 1;
@@ -2238,8 +2203,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
2238 2203 buildLabel &&
2239 2204 version_compare(buildLabel, gameToBuildVersion["25.7.0"]) >= 0
2240 2205 ) {
2241 const activationTimeStamp = config.worldState?.dogDaysOverride ? "1699372800000" : dogDaysStart.toString();
2242 const expiryTimeStamp = config.worldState?.dogDaysOverride ? "2000000000000" : dogDaysEnd.toString();
2206 const activation = config.worldState?.dogDaysOverride ? 1699372800000 : dogDaysStart;
2207 const expiry = config.worldState?.dogDaysOverride ? 2000000000000 : dogDaysEnd;
2243 2208 const rewards = [
2244 2209 [
2245 2210 {
@@ -2396,8 +2361,8 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
2396 2361 "c57487c3768936d" +
2397 2362 year.toString(16)
2398 2363 },
2399 Activation: { $date: { $numberLong: activationTimeStamp } },
2400 Expiry: { $date: { $numberLong: expiryTimeStamp } },
2364 Activation: { $date: { $numberLong: activation.toString() } },
2365 Expiry: { $date: { $numberLong: expiry.toString() } },
2401 2366 Count: 0,
2402 2367 Goal: 100,
2403 2368 InterimGoals: [25, 50],
@@ -2441,43 +2406,30 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
2441 2406 { TypeName: "/Lotus/Types/StoreItems/SuitCustomizations/ColourPickerRollers", PremiumOverride: 75 }
2442 2407 ];
2443 2408
2444 worldState.FlashSales.push(
2445 ...storeItems.map(item => ({
2446 ...{
2447 StartDate: { $date: { $numberLong: activationTimeStamp } },
2448 EndDate: { $date: { $numberLong: expiryTimeStamp } },
2449 ProductExpiryOverride: { $date: { $numberLong: expiryTimeStamp } },
2450 ShowInMarket: item.ShowInMarket ?? true,
2451 HideFromMarket: item.HideFromMarket ?? false,
2452 SupporterPack: item.SupporterPack ?? false,
2453 Discount: item.Discount ?? 0,
2454 BogoBuy: item.BogoBuy ?? 0,
2455 BogoGet: item.BogoGet ?? 0,
2456 RegularOverride: item.RegularOverride ?? 0,
2457 PremiumOverride: item.PremiumOverride ?? 0
2458 },
2459 ...item
2460 }))
2461 );
2409 pushFlashSales(worldState, storeItems, activation, expiry, "SEASONAL", buildLabel);
2410 }
2462 2411
2463 const seasonalItems = storeItems.map(item => item.TypeName);
2412 // there no strict start day so lets pick first march monday
2413 const firstMarchWeekday = new Date(Date.UTC(date.getUTCFullYear(), 2, 1)).getUTCDay();
2414 const firstMarchMondayOffset = (8 - firstMarchWeekday) % 7;
2464 2415
2465 const seasonalCategory = worldState.InGameMarket.LandingPage.Categories.find(c => c.CategoryName == "SEASONAL");
2416 const saintPatrickStart = Date.UTC(date.getUTCFullYear(), 2, firstMarchMondayOffset + 1, 16);
2417 const saintPatrickEnd = Date.UTC(date.getUTCFullYear(), 2, firstMarchMondayOffset + 22, 16);
2466 2418
2467 if (seasonalCategory) {
2468 seasonalCategory.Items ??= [];
2469 seasonalCategory.Items.push(...seasonalItems);
2470 } else {
2471 worldState.InGameMarket.LandingPage.Categories.push({
2472 CategoryName: "SEASONAL",
2473 Name: "/Lotus/Language/Store/SeasonalCategoryTitle",
2474 Icon: "seasonal",
2475 AddToMenu: true,
2476 Items: seasonalItems
2477 });
2478 }
2479 }
2419 const isSaintPatrickActive = timeMs >= saintPatrickStart && timeMs < saintPatrickEnd;
2420 if (
2421 (config.worldState?.saintPatrickOverride ?? isSaintPatrickActive) &&
2422 buildLabel &&
2423 version_compare(buildLabel, gameToBuildVersion["13.0.0"]) >= 0
2424 ) {
2425 const activation = config.worldState?.saintPatrickOverride ? 1772467200000 : saintPatrickStart;
2426 const expiry = config.worldState?.saintPatrickOverride ? 2000000000000 : saintPatrickEnd;
2427 const storeItems: (Partial<IFlashSale> & { TypeName: string })[] = [
2428 { TypeName: "/Lotus/Types/StoreItems/SuitCustomizations/ColourPickerShamrockItem", RegularOverride: 1 }
2429 ];
2480 2430
2431 pushFlashSales(worldState, storeItems, activation, expiry, "SEASONAL", buildLabel);
2432 }
2481 2433 if (config.worldState?.anniversary != undefined) {
2482 2434 // Incompatible with: Use Tag from Warframe Anniversary for old Events, Wolf Hunt, Galleon Of Ghouls, Hallowed Flame, Hallowed Nightmares, Dog Days, Proxy Rebellion, Long Shadow
2483 2435 const goalsByWeek: Partial<IGoal>[][] = [
@@ -3121,18 +3073,18 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
3121 3073 buildLabel &&
3122 3074 version_compare(buildLabel, gameToBuildVersion["29.3.1"]) >= 0
3123 3075 ) {
3124 const activationTimeStamp = config.worldState?.naberusNightsOverride
3125 ? "1727881200000"
3126 : Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1).toString();
3076 const activation = config.worldState?.naberusNightsOverride
3077 ? 1727881200000
3078 : Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), 1);
3127 3079
3128 const expiryTimeStamp = config.worldState?.naberusNightsOverride
3129 ? "2000000000000"
3130 : Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1).toString();
3080 const expiry = config.worldState?.naberusNightsOverride
3081 ? 2000000000000
3082 : Date.UTC(date.getUTCFullYear(), date.getUTCMonth() + 1, 1);
3131 3083
3132 3084 worldState.Goals.push({
3133 3085 _id: { $oid: "66fd602de1778d583419e8e7" },
3134 Activation: { $date: { $numberLong: activationTimeStamp } },
3135 Expiry: { $date: { $numberLong: expiryTimeStamp } },
3086 Activation: { $date: { $numberLong: activation.toString() } },
3087 Expiry: { $date: { $numberLong: expiry.toString() } },
3136 3088 Count: 0,
3137 3089 Goal: 0,
3138 3090 Success: 0,
@@ -3284,40 +3236,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
3284 3236 { TypeName: "/Lotus/Types/StoreItems/Packages/HalloweenSkinPackD", PremiumOverride: 180 }
3285 3237 ];
3286 3238
3287 worldState.FlashSales.push(
3288 ...storeItems.map(item => ({
3289 ...{
3290 StartDate: { $date: { $numberLong: activationTimeStamp } },
3291 EndDate: { $date: { $numberLong: expiryTimeStamp } },
3292 ProductExpiryOverride: { $date: { $numberLong: expiryTimeStamp } },
3293 ShowInMarket: item.ShowInMarket ?? true,
3294 HideFromMarket: item.HideFromMarket ?? false,
3295 SupporterPack: item.SupporterPack ?? false,
3296 Discount: item.Discount ?? 0,
3297 BogoBuy: item.BogoBuy ?? 0,
3298 BogoGet: item.BogoGet ?? 0,
3299 RegularOverride: item.RegularOverride ?? 0,
3300 PremiumOverride: item.PremiumOverride ?? 0
3301 },
3302 ...item
3303 }))
3304 );
3305
3306 const seasonalItems = storeItems.map(item => item.TypeName);
3307 const seasonalCategory = worldState.InGameMarket.LandingPage.Categories.find(c => c.CategoryName == "SEASONAL");
3308
3309 if (seasonalCategory) {
3310 seasonalCategory.Items ??= [];
3311 seasonalCategory.Items.push(...seasonalItems);
3312 } else {
3313 worldState.InGameMarket.LandingPage.Categories.push({
3314 CategoryName: "SEASONAL",
3315 Name: "/Lotus/Language/Store/SeasonalCategoryTitle",
3316 Icon: "seasonal",
3317 AddToMenu: true,
3318 Items: seasonalItems
3319 });
3320 }
3239 pushFlashSales(worldState, storeItems, activation, expiry, "SEASONAL", buildLabel);
3321 3240 }
3322 3241
3323 3242 if (config.worldState?.bellyOfTheBeast && buildLabel && version_compare(buildLabel, "2024.06.12.18.42") >= 0) {
@@ -4668,3 +4587,64 @@ export const populateFeaturedGuilds = async (worldState: IWorldState): Promise<v
4668 4587 });
4669 4588 }
4670 4589 };
4590
4591 const storeCategories: Record<string, { Name: string; Icon: string; AddToMenu?: boolean }> = {
4592 NEW_PLAYER: { Name: "/Lotus/Language/Store/NewPlayerCategoryTitle", Icon: "newplayer", AddToMenu: true },
4593 POPULAR: { Name: "/Lotus/Language/Menu/StorePopular", Icon: "popular", AddToMenu: true },
4594 HEIRLOOM: { Name: "/Lotus/Language/Store/HeirloomCategoryTitle", Icon: "heirloom", AddToMenu: true },
4595 SEASONAL: { Name: "/Lotus/Language/Store/SeasonalCategoryTitle", Icon: "seasonal", AddToMenu: true },
4596 SALE: { Name: "/Lotus/Language/Menu/Store_Sale", Icon: "sale", AddToMenu: true },
4597 WISH_LIST: { Name: "/Lotus/Language/Menu/Store_Wishlist", Icon: "wishlist" },
4598 PREMIUM_BUNDLES: { Name: "/Lotus/Language/Store/Store_PremiumBundles", Icon: "premiumbundles" },
4599 QUICK_BUY: { Name: "/Lotus/Language/Store/TopSeller_Title", Icon: "quickbuy" }
4600 };
4601
4602 const pushFlashSales = (
4603 ws: IWorldState,
4604 storeItems: (Partial<IFlashSale> & { TypeName: string })[],
4605 startDate: number | Date,
4606 endDate: number | Date,
4607 category: string,
4608 buildLabel?: string
4609 ): void => {
4610 ws.FlashSales.push(
4611 ...storeItems.map(item => ({
4612 ...{
4613 StartDate: toMongoDate2(startDate, buildLabel),
4614 EndDate: toMongoDate2(endDate, buildLabel),
4615 ProductExpiryOverride: toMongoDate2(endDate, buildLabel),
4616 ShowInMarket: item.ShowInMarket ?? true,
4617 HideFromMarket: item.HideFromMarket ?? false,
4618 SupporterPack: item.SupporterPack ?? false,
4619 Discount: item.Discount ?? 0,
4620 BogoBuy: item.BogoBuy ?? 0,
4621 BogoGet: item.BogoGet ?? 0,
4622 RegularOverride: item.RegularOverride ?? 0,
4623 PremiumOverride: item.PremiumOverride ?? 0,
4624 Featured: item.Featured ?? category != "POPULAR",
4625 Popular: item.Popular ?? category == "POPULAR",
4626 BannerIndex: item.BannerIndex ?? 10
4627 },
4628 ...item
4629 }))
4630 );
4631
4632 if (category in storeCategories) {
4633 const categoryData = storeCategories[category];
4634 const seasonalCategory = ws.InGameMarket.LandingPage.Categories.find(c => c.CategoryName == category);
4635 const seasonalItems = storeItems.map(item => item.TypeName);
4636
4637 if (seasonalCategory) {
4638 seasonalCategory.Items ??= [];
4639 seasonalCategory.Items.push(...seasonalItems);
4640 } else {
4641 ws.InGameMarket.LandingPage.Categories.push({
4642 ...{
4643 CategoryName: category,
4644 Items: seasonalItems
4645 },
4646 ...categoryData
4647 });
4648 }
4649 }
4650 };
Modified src/types/worldStateTypes.ts +8 -3
@@ -459,9 +459,14 @@ export interface IFlashSale {
459 459 BogoGet: number;
460 460 PremiumOverride: number;
461 461 RegularOverride: number;
462 ProductExpiryOverride?: IMongoDate;
463 StartDate: IMongoDate;
464 EndDate: IMongoDate;
462 ProductExpiryOverride?: IMongoDateWithLegacySupport;
463 StartDate: IMongoDateWithLegacySupport;
464 EndDate: IMongoDateWithLegacySupport;
465
466 // Pre-U22.9 fields
467 Featured?: boolean;
468 Popular?: boolean;
469 BannerIndex?: number;
465 470 }
466 471
467 472 export interface IInGameMarket {
Modified static/webui/index.html +8 -0
@@ -1483,6 +1483,14 @@
1483 1483 <option value="false" data-loc="disabled"></option>
1484 1484 </select>
1485 1485 </div>
1486 <div class="form-group mt-2">
1487 <label class="form-label" for="worldState.saintPatrickOverride" data-loc="worldState_saintPatrick"></label>
1488 <select class="form-control" id="worldState.saintPatrickOverride" data-default="null">
1489 <option value="null" data-loc="normal"></option>
1490 <option value="true" data-loc="enabled"></option>
1491 <option value="false" data-loc="disabled"></option>
1492 </select>
1493 </div>
1486 1494 <div class="form-group mt-2 d-flex gap-2">
1487 1495 <div class="flex-fill">
1488 1496 <label class="form-label" for="worldState.dogDaysOverride" data-loc="worldState_dogDays"></label>
Modified static/webui/translations/de.js +1 -0
@@ -307,6 +307,7 @@ dict = {
307 307 worldState_tennoLiveRelay: `TennoLive Relais`,
308 308 worldState_baroTennoConRelay: `Baros TennoCon-Relais`,
309 309 worldState_starDays: `Sternen-Tage`,
310 worldState_saintPatrick: `St. Patrick’s Day`,
310 311 worldState_galleonOfGhouls: `Galeone der Ghule`,
311 312 worldState_anniversary: `Warframe Jubiläum`,
312 313 worldState_useAnniversaryTagForOldGoals: `Verwende <code>Tag</code> vom Warframe Jubiläum für alte Events`,
Modified static/webui/translations/en.js +1 -0
@@ -306,6 +306,7 @@ dict = {
306 306 worldState_tennoLiveRelay: `TennoLive Relay`,
307 307 worldState_baroTennoConRelay: `Baro's TennoCon Relay`,
308 308 worldState_starDays: `Star Days`,
309 worldState_saintPatrick: `St. Patrick’s Day`,
309 310 worldState_galleonOfGhouls: `Galleon of Ghouls`,
310 311 worldState_anniversary: `Warframe Anniversary`,
311 312 worldState_useAnniversaryTagForOldGoals: `Use <code>Tag</code> from Warframe Anniversary for old Events`,
Modified static/webui/translations/es.js +1 -0
@@ -307,6 +307,7 @@ dict = {
307 307 worldState_tennoLiveRelay: `Repetidor de TennoLive`,
308 308 worldState_baroTennoConRelay: `Repetidor de Baro de la TennoCon`,
309 309 worldState_starDays: `Días estelares`,
310 worldState_saintPatrick: `Día de San Patricio`,
310 311 worldState_galleonOfGhouls: `Galeón de Gules`,
311 312 worldState_anniversary: `Aniversario de Warframe`,
312 313 worldState_useAnniversaryTagForOldGoals: `Usa <code>Tag</code> del Aniversario de Warframe para eventos pasados`,
Modified static/webui/translations/fr.js +1 -0
@@ -307,6 +307,7 @@ dict = {
307 307 worldState_tennoLiveRelay: `Relais TennoLive`,
308 308 worldState_baroTennoConRelay: `Relais Baro TennoCon`,
309 309 worldState_starDays: `Jours Stellaires`,
310 worldState_saintPatrick: `Saint-Patrick`,
310 311 worldState_galleonOfGhouls: `Galion des Goules`,
311 312 worldState_anniversary: `Anniversaire de Warframe`,
312 313 worldState_useAnniversaryTagForOldGoals: `Utiliser <code>Tag</code> de l'Anniversaire de Warframe pour les anciens événements`,
Modified static/webui/translations/ru.js +1 -0
@@ -307,6 +307,7 @@ dict = {
307 307 worldState_tennoLiveRelay: `Реле TennoLive`,
308 308 worldState_baroTennoConRelay: `Реле Баро TennoCon`,
309 309 worldState_starDays: `Звёздные дни`,
310 worldState_saintPatrick: `День Святого Патрика`,
310 311 worldState_galleonOfGhouls: `Галеон Гулей`,
311 312 worldState_anniversary: `Годовщина Warframe`,
312 313 worldState_useAnniversaryTagForOldGoals: `Использовать <code>Tag</code> из Годовщины Warframe для старых событий`,
Modified static/webui/translations/uk.js +1 -0
@@ -307,6 +307,7 @@ dict = {
307 307 worldState_tennoLiveRelay: `Реле TennoLive`,
308 308 worldState_baroTennoConRelay: `Реле Баро TennoCon`,
309 309 worldState_starDays: `Зоряні дні`,
310 worldState_saintPatrick: `День святого Патрика`,
310 311 worldState_galleonOfGhouls: `Гульський галеон`,
311 312 worldState_anniversary: `Річниця Warframe`,
312 313 worldState_useAnniversaryTagForOldGoals: `Використати <code>Tag</code> з річниці Warframe для старих подій`,
Modified static/webui/translations/zh.js +1 -0
@@ -307,6 +307,7 @@ dict = {
307 307 worldState_tennoLiveRelay: `TennoLive中继站`,
308 308 worldState_baroTennoConRelay: `Baro的TennoCon中继站`,
309 309 worldState_starDays: `活动:星日`,
310 worldState_saintPatrick: `圣帕特里克节`,
310 311 worldState_galleonOfGhouls: `战术警报:尸鬼的帆船战舰`,
311 312 worldState_anniversary: `12周年纪念活动`,
312 313 worldState_useAnniversaryTagForOldGoals: `使用纪念活动<code>Tag</code>解决旧活动不显示问题`,