Compare commits

...

9 Commits

Author SHA1 Message Date
Lugiad
a286dc37fa
Update src/locales/ja/pokemon-form.json
Co-authored-by: Enoch <enoch.jwsong@gmail.com>
2024-09-20 02:09:14 +02:00
Lugiad
cacca02630
Update src/locales/ja/pokemon-form.json
Co-authored-by: Enoch <enoch.jwsong@gmail.com>
2024-09-20 02:09:03 +02:00
Lugiad
ddc794f0d0
Update src/locales/ja/pokemon-form.json
Co-authored-by: Enoch <enoch.jwsong@gmail.com>
2024-09-20 02:08:54 +02:00
Lugiad
9b74a01e29
Update src/locales/ja/pokemon-form.json
Co-authored-by: Enoch <enoch.jwsong@gmail.com>
2024-09-20 02:08:45 +02:00
Lugiad
07af8968b2
Update src/locales/ja/pokemon-form.json
Co-authored-by: Enoch <enoch.jwsong@gmail.com>
2024-09-20 02:08:06 +02:00
Lugiad
0572e60877
Update src/locales/ja/pokemon-form.json
Co-authored-by: Enoch <enoch.jwsong@gmail.com>
2024-09-20 02:03:18 +02:00
Lugiad
0cfee34143
Update src/locales/ja/pokemon-form.json
Co-authored-by: Enoch <enoch.jwsong@gmail.com>
2024-09-20 02:03:04 +02:00
Lugiad
f382dbeaa7
Merge branch 'beta' into formChangeLocale 2024-09-20 01:57:35 +02:00
flx-sta
48430c8feb
[Feature] Seasonal splash messages logic + scaffolding (#4318)
* add: seasonsl splash messages logic + scaffolding

* refactor: settin up and displaying splash messages.

They are now stored with their i18next keys and only get translated as soon as they are displayed. This also allows for better display of the `battlesWon` parameter which now supports better number formatting and the count is an interpolation

* fix: updateTitleStats not checking the namespace of battlesWon

* add tests for splash_messages

* test: always use UTC time

* fix: time-pattern to MM-DD

* fix splash_messages test

* add: const to control usage of seasonal splash messages

* fix tests (splashj)

* Update src/locales/ja/splash-messages.json

Co-authored-by: Chapybara-jp <charlie.beer@hotmail.com>

* Update src/locales/es/splash-messages.json

Add missing `number` format for battlesWon message

---------

Co-authored-by: Chapybara-jp <charlie.beer@hotmail.com>
2024-09-19 15:59:37 -07:00
16 changed files with 375 additions and 198 deletions

View File

@ -1 +1,5 @@
export const PLAYER_PARTY_MAX_SIZE = 6; /** The maximum size of the player's party */
export const PLAYER_PARTY_MAX_SIZE: number = 6;
/** Whether to use seasonal splash messages in general */
export const USE_SEASONAL_SPLASH_MESSAGES: boolean = false;

View File

@ -1,46 +1,136 @@
import i18next from "i18next"; import { USE_SEASONAL_SPLASH_MESSAGES } from "#app/constants";
export function getBattleCountSplashMessage(): string { //#region Interfaces/Types
return `{COUNT} ${i18next.t("splashMessages:battlesWon")}`;
type Month = "01" | "02" | "03" | "04" | "05" | "06" | "07" | "08" | "09" | "10" | "11" | "12";
type Day =
| Month
| "13"
| "14"
| "15"
| "16"
| "17"
| "18"
| "19"
| "20"
| "21"
| "22"
| "23"
| "24"
| "25"
| "26"
| "27"
| "28"
| "29"
| "30"
| "31";
/**
* Represents a season with its {@linkcode name},
* {@linkcode start} day+month, {@linkcode end} day+month
* and {@linkcode messages}.
*/
interface Season {
/** The name of the season (internal use only) */
name: string;
/** The start day and month of the season. Format `MM-DD` */
start: `${Month}-${Day}`;
/** The end day and month of the season. Format `MM-DD` */
end: `${Month}-${Day}`;
/** Collection of the messages to display (without the `i18next.t()` call!) */
messages: string[];
} }
//#region Constants
/** The weight multiplier for the battles-won splash message */
const BATTLES_WON_WEIGHT_MULTIPLIER = 10;
/** The weight multiplier for the seasonal splash messages */
const SEASONAL_WEIGHT_MULTIPLIER = 10;
//#region Common Messages
const commonSplashMessages = [
...Array(BATTLES_WON_WEIGHT_MULTIPLIER).fill("battlesWon"),
"joinTheDiscord",
"infiniteLevels",
"everythingStacks",
"optionalSaveScumming",
"biomes",
"openSource",
"playWithSpeed",
"liveBugTesting",
"heavyInfluence",
"pokemonRiskAndPokemonRain",
"nowWithMoreSalt",
"infiniteFusionAtHome",
"brokenEggMoves",
"magnificent",
"mubstitute",
"thatsCrazy",
"oranceJuice",
"questionableBalancing",
"coolShaders",
"aiFree",
"suddenDifficultySpikes",
"basedOnAnUnfinishedFlashGame",
"moreAddictiveThanIntended",
"mostlyConsistentSeeds",
"achievementPointsDontDoAnything",
"youDoNotStartAtLevel",
"dontTalkAboutTheManaphyEggIncident",
"alsoTryPokengine",
"alsoTryEmeraldRogue",
"alsoTryRadicalRed",
"eeveeExpo",
"ynoproject",
"breedersInSpace",
];
//#region Seasonal Messages
const seasonalSplashMessages: Season[] = [
{
name: "Halloween",
start: "09-15",
end: "10-31",
messages: ["halloween.pumpkaboosAbout", "halloween.mayContainSpiders", "halloween.spookyScaryDuskulls"],
},
{
name: "XMAS",
start: "12-01",
end: "12-26",
messages: ["xmas.happyHolidays", "xmas.delibirdSeason"],
},
{
name: "New Year's",
start: "01-01",
end: "01-31",
messages: ["newYears.happyNewYear"],
},
];
//#endregion
export function getSplashMessages(): string[] { export function getSplashMessages(): string[] {
const splashMessages = Array(10).fill(getBattleCountSplashMessage()); const splashMessages: string[] = [...commonSplashMessages];
splashMessages.push( console.log("use seasonal splash messages", USE_SEASONAL_SPLASH_MESSAGES);
i18next.t("splashMessages:joinTheDiscord"), if (USE_SEASONAL_SPLASH_MESSAGES) {
i18next.t("splashMessages:infiniteLevels"), // add seasonal splash messages if the season is active
i18next.t("splashMessages:everythingStacks"), for (const { name, start, end, messages } of seasonalSplashMessages) {
i18next.t("splashMessages:optionalSaveScumming"), const now = new Date();
i18next.t("splashMessages:biomes"), const startDate = new Date(`${start}-${now.getFullYear()}`);
i18next.t("splashMessages:openSource"), const endDate = new Date(`${end}-${now.getFullYear()}`);
i18next.t("splashMessages:playWithSpeed"),
i18next.t("splashMessages:liveBugTesting"),
i18next.t("splashMessages:heavyInfluence"),
i18next.t("splashMessages:pokemonRiskAndPokemonRain"),
i18next.t("splashMessages:nowWithMoreSalt"),
i18next.t("splashMessages:infiniteFusionAtHome"),
i18next.t("splashMessages:brokenEggMoves"),
i18next.t("splashMessages:magnificent"),
i18next.t("splashMessages:mubstitute"),
i18next.t("splashMessages:thatsCrazy"),
i18next.t("splashMessages:oranceJuice"),
i18next.t("splashMessages:questionableBalancing"),
i18next.t("splashMessages:coolShaders"),
i18next.t("splashMessages:aiFree"),
i18next.t("splashMessages:suddenDifficultySpikes"),
i18next.t("splashMessages:basedOnAnUnfinishedFlashGame"),
i18next.t("splashMessages:moreAddictiveThanIntended"),
i18next.t("splashMessages:mostlyConsistentSeeds"),
i18next.t("splashMessages:achievementPointsDontDoAnything"),
i18next.t("splashMessages:youDoNotStartAtLevel"),
i18next.t("splashMessages:dontTalkAboutTheManaphyEggIncident"),
i18next.t("splashMessages:alsoTryPokengine"),
i18next.t("splashMessages:alsoTryEmeraldRogue"),
i18next.t("splashMessages:alsoTryRadicalRed"),
i18next.t("splashMessages:eeveeExpo"),
i18next.t("splashMessages:ynoproject"),
i18next.t("splashMessages:breedersInSpace"),
);
return splashMessages; if (now >= startDate && now <= endDate) {
console.log(`Adding ${messages.length} ${name} splash messages (weight: x${SEASONAL_WEIGHT_MULTIPLIER})`);
messages.forEach((message) => {
const weightedMessage = Array(SEASONAL_WEIGHT_MULTIPLIER).fill(message);
splashMessages.push(...weightedMessage);
});
}
}
}
return splashMessages.map((message) => `splashMessages:${message}`);
} }

View File

@ -1,5 +1,5 @@
{ {
"battlesWon": "Kämpfe gewonnen!", "battlesWon": "{{count, number}} Kämpfe gewonnen!",
"joinTheDiscord": "Tritt dem Discord bei!", "joinTheDiscord": "Tritt dem Discord bei!",
"infiniteLevels": "Unendliche Level!", "infiniteLevels": "Unendliche Level!",
"everythingStacks": "Alles stapelt sich!", "everythingStacks": "Alles stapelt sich!",

View File

@ -1,5 +1,5 @@
{ {
"battlesWon": "Battles Won!", "battlesWon": "{{count, number}} Battles Won!",
"joinTheDiscord": "Join the Discord!", "joinTheDiscord": "Join the Discord!",
"infiniteLevels": "Infinite Levels!", "infiniteLevels": "Infinite Levels!",
"everythingStacks": "Everything Stacks!", "everythingStacks": "Everything Stacks!",
@ -32,5 +32,17 @@
"alsoTryRadicalRed": "Also Try Radical Red!", "alsoTryRadicalRed": "Also Try Radical Red!",
"eeveeExpo": "Eevee Expo!", "eeveeExpo": "Eevee Expo!",
"ynoproject": "YNOproject!", "ynoproject": "YNOproject!",
"breedersInSpace": "Breeders in space!" "breedersInSpace": "Breeders in space!",
"halloween": {
"pumpkaboosAbout": "Pumpkaboos about!",
"mayContainSpiders": "May contain spiders!",
"spookyScaryDuskulls": "Spooky, Scary Duskulls!"
},
"xmas": {
"happyHolidays": "Happy Holidays!",
"delibirdSeason": "Delibird Season!"
},
"newYears": {
"happyNewYear": "Happy New Year!"
}
} }

View File

@ -1,5 +1,5 @@
{ {
"battlesWon": Batallas ganadas!", "battlesWon": {{count, number}} Batallas ganadas!",
"joinTheDiscord": "¡Únete al Discord!", "joinTheDiscord": "¡Únete al Discord!",
"infiniteLevels": "¡Niveles infinitos!", "infiniteLevels": "¡Niveles infinitos!",
"everythingStacks": "¡Todo se acumula!", "everythingStacks": "¡Todo se acumula!",

View File

@ -1,5 +1,5 @@
{ {
"battlesWon": "combats gagnés !", "battlesWon": "{{count, number}} combats gagnés !",
"joinTheDiscord": "Rejoins le Discord !", "joinTheDiscord": "Rejoins le Discord !",
"infiniteLevels": "Niveaux infinis !", "infiniteLevels": "Niveaux infinis !",
"everythingStacks": "Tout se cumule !", "everythingStacks": "Tout se cumule !",

View File

@ -1,5 +1,5 @@
{ {
"battlesWon": "Battaglie Vinte!", "battlesWon": "{{count, number}} Battaglie Vinte!",
"joinTheDiscord": "Entra nel Discord!", "joinTheDiscord": "Entra nel Discord!",
"infiniteLevels": "Livelli Infiniti!", "infiniteLevels": "Livelli Infiniti!",
"everythingStacks": "Tutto si impila!", "everythingStacks": "Tutto si impila!",

View File

@ -1,5 +1,5 @@
{ {
"pikachu": "Normal", "pikachu": "一般",
"pikachuCosplay": "コスプレ", "pikachuCosplay": "コスプレ",
"pikachuCoolCosplay": "クールなコスプレ", "pikachuCoolCosplay": "クールなコスプレ",
"pikachuBeautyCosplay": "きれいなコスプレ", "pikachuBeautyCosplay": "きれいなコスプレ",
@ -7,9 +7,9 @@
"pikachuSmartCosplay": "かしこいコスプレ", "pikachuSmartCosplay": "かしこいコスプレ",
"pikachuToughCosplay": "パワフルなコスプレ", "pikachuToughCosplay": "パワフルなコスプレ",
"pikachuPartner": "パートナー", "pikachuPartner": "パートナー",
"eevee": "Normal", "eevee": "一般",
"eeveePartner": "パートナー", "eeveePartner": "パートナー",
"pichu": "Normal", "pichu": "一般",
"pichuSpiky": "ギザみみ", "pichuSpiky": "ギザみみ",
"unownA": "A", "unownA": "A",
"unownB": "B", "unownB": "B",
@ -39,65 +39,65 @@
"unownZ": "Z", "unownZ": "Z",
"unownExclamation": "!", "unownExclamation": "!",
"unownQuestion": "?", "unownQuestion": "?",
"castform": "Normal Form", "castform": "ポワルンのすがた",
"castformSunny": "たいよう", "castformSunny": "たいようのすがた",
"castformRainy": "あまみず", "castformRainy": "あまみずのすがた",
"castformSnowy": "ゆきぐも", "castformSnowy": "ゆきぐものすがた",
"deoxysNormal": "ノーマル", "deoxysNormal": "ノーマルフォルム",
"deoxysAttack": "Attack", "deoxysAttack": "アタックフォルム",
"deoxysDefense": "Defense", "deoxysDefense": "ディフェンスフォルム",
"deoxysSpeed": "Speed", "deoxysSpeed": "スピードフォルム",
"burmyPlant": "くさき", "burmyPlant": "くさき",
"burmySandy": "すなち", "burmySandy": "すなち",
"burmyTrash": "ゴミ", "burmyTrash": "ゴミ",
"cherubiOvercast": "Overcast", "cherubiOvercast": "ネガフォルム",
"cherubiSunshine": "Sunshine", "cherubiSunshine": "ポジフォルム",
"shellosEast": "ひがし", "shellosEast": "ひがし",
"shellosWest": "にし", "shellosWest": "にし",
"rotom": "Normal", "rotom": "ロトムのすがた",
"rotomHeat": "ヒート", "rotomHeat": "ヒートロトム",
"rotomWash": "ウォッシュ", "rotomWash": "ウォッシュロトム",
"rotomFrost": "フロスト", "rotomFrost": "フロストロトム",
"rotomFan": "スピン", "rotomFan": "スピンロトム",
"rotomMow": "カット", "rotomMow": "カットロトム",
"dialga": "Normal", "dialga": "アナザーフォルム",
"dialgaOrigin": "Origin", "dialgaOrigin": "オリジンフォルム",
"palkia": "Normal", "palkia": "アナザーフォルム",
"palkiaOrigin": "Origin", "palkiaOrigin": "オリジンフォルム",
"giratinaAltered": "アナザー", "giratinaAltered": "アナザーフォルム",
"giratinaOrigin": "Origin", "giratinaOrigin": "オリジンフォルム",
"shayminLand": "ランド", "shayminLand": "ランドフォルム",
"shayminSky": "Sky", "shayminSky": "スカイフォルム",
"basculinRedStriped": "赤筋", "basculinRedStriped": "赤筋",
"basculinBlueStriped": "青筋", "basculinBlueStriped": "青筋",
"basculinWhiteStriped": "白筋", "basculinWhiteStriped": "白筋",
"darumaka": "Standard Mode", "darumaka": "ノーマルモード",
"darumakaZen": "Zen", "darumakaZen": "ダルマモード",
"deerlingSpring": "春", "deerlingSpring": "春",
"deerlingSummer": "夏", "deerlingSummer": "夏",
"deerlingAutumn": "秋", "deerlingAutumn": "秋",
"deerlingWinter": "冬", "deerlingWinter": "冬",
"tornadusIncarnate": "けしん", "tornadusIncarnate": "けしんフォルム",
"tornadusTherian": "Therian", "tornadusTherian": "れいじゅうフォルム",
"thundurusIncarnate": "けしん", "thundurusIncarnate": "けしんフォルム",
"thundurusTherian": "Therian", "thundurusTherian": "れいじゅうフォルム",
"landorusIncarnate": "けしん", "landorusIncarnate": "けしんフォルム",
"landorusTherian": "Therian", "landorusTherian": "れいじゅうフォルム",
"kyurem": "Normal", "kyurem": "通常",
"kyuremBlack": "Black", "kyuremBlack": "ブラックキュレム",
"kyuremWhite": "White", "kyuremWhite": "ホワイトキュレム",
"keldeoOrdinary": "いつも", "keldeoOrdinary": "いつものすがた",
"keldeoResolute": "Resolute", "keldeoResolute": "かくごのすがた",
"meloettaAria": "ボイス", "meloettaAria": "ボイス",
"meloettaPirouette": "ステップ", "meloettaPirouette": "ステップ",
"genesect": "Normal", "genesect": "一般",
"genesectShock": "Shock Drive", "genesectShock": "ライトニング",
"genesectBurn": "Burn Drive", "genesectBurn": "ブレイズ",
"genesectChill": "Chill Drive", "genesectChill": "フリーズ",
"genesectDouse": "Douse Drive", "genesectDouse": "アクア",
"froakie": "Normal", "froakie": "通常",
"froakieBattleBond": "きずなへんげ", "froakieBattleBond": "きずなへんげ",
"froakieAsh": "Ash", "froakieAsh": "サトシゲッコウガ",
"scatterbugMeadow": "はなぞの", "scatterbugMeadow": "はなぞの",
"scatterbugIcySnow": "ひょうせつ", "scatterbugIcySnow": "ひょうせつ",
"scatterbugPolar": "ゆきぐに", "scatterbugPolar": "ゆきぐに",
@ -123,7 +123,7 @@
"flabebeOrange": "オレンジ", "flabebeOrange": "オレンジ",
"flabebeBlue": "青", "flabebeBlue": "青",
"flabebeWhite": "白", "flabebeWhite": "白",
"furfrou": "Natural Form", "furfrou": "やせいのすがた",
"furfrouHeart": "ハート", "furfrouHeart": "ハート",
"furfrouStar": "スター", "furfrouStar": "スター",
"furfrouDiamond": "ダイア", "furfrouDiamond": "ダイア",
@ -133,14 +133,14 @@
"furfrouLaReine": "クイーン", "furfrouLaReine": "クイーン",
"furfrouKabuki": "カブキ", "furfrouKabuki": "カブキ",
"furfrouPharaoh": "キングダム", "furfrouPharaoh": "キングダム",
"espurrMale": "Male", "espurrMale": "オス",
"espurrFemale": "Female", "espurrFemale": "メス",
"honedgeShiled": "Shield", "honedgeShiled": "シールドフォルム",
"honedgeBlade": "Blade", "honedgeBlade": "ブレードフォルム",
"pumpkaboo": "Average Size", "pumpkaboo": "ふつうのサイズ",
"pumpkabooSmall": "ちいさい", "pumpkabooSmall": "ちいさいサイズ",
"pumpkabooLarge": "おおきい", "pumpkabooLarge": "おおきいサイズ",
"pumpkabooSuper": "とくだい", "pumpkabooSuper": "とくだいサイズ",
"xerneasNeutral": "リラックス", "xerneasNeutral": "リラックス",
"xerneasActive": "アクティブ", "xerneasActive": "アクティブ",
"zygarde50": "50%フォルム", "zygarde50": "50%フォルム",
@ -148,37 +148,37 @@
"zygarde50Pc": "50%フォルム スワームチェンジ", "zygarde50Pc": "50%フォルム スワームチェンジ",
"zygarde10Pc": "10%フォルム スワームチェンジ", "zygarde10Pc": "10%フォルム スワームチェンジ",
"zygardeComplete": "パーフェクトフォルム", "zygardeComplete": "パーフェクトフォルム",
"hoopa": "Confined", "hoopa": "いましめられしフーパ",
"hoopaUnbound": "Unbound", "hoopaUnbound": "ときはなたれしフーパ",
"oricorioBaile": "めらめら", "oricorioBaile": "めらめら",
"oricorioPompom": "ぱちぱち", "oricorioPompom": "ぱちぱち",
"oricorioPau": "ふらふら", "oricorioPau": "ふらふら",
"oricorioSensu": "まいまい", "oricorioSensu": "まいまい",
"rockruff": "Normal", "rockruff": "一般",
"rockruffOwnTempo": "マイペース", "rockruffOwnTempo": "マイペース",
"rockruffMidday": "Midday", "rockruffMidday": "まひるのすがた",
"rockruffMidnight": "Midnight", "rockruffMidnight": "まよなかのすがた",
"rockruffDusk": "Dusk", "rockruffDusk": "たそがれのすがた",
"wishiwashi": "Solo Form", "wishiwashi": "たんどくのすがた",
"wishiwashiSchool": "School", "wishiwashiSchool": "むれたすがた",
"typeNullNormal": "Type: Normal", "typeNullNormal": "タイプ:ノーマル",
"typeNullFighting": "Type: Fighting", "typeNullFighting": "タイプ:かくとう",
"typeNullFlying": "Type: Flying", "typeNullFlying": "タイプ:ひこう",
"typeNullPoison": "Type: Poison", "typeNullPoison": "タイプ:どく",
"typeNullGround": "Type: Ground", "typeNullGround": "タイプ:じめん",
"typeNullRock": "Type: Rock", "typeNullRock": "タイプ:いわ",
"typeNullBug": "Type: Bug", "typeNullBug": "タイプ:むし",
"typeNullGhost": "Type: Ghost", "typeNullGhost": "タイプ:ゴースト",
"typeNullSteel": "Type: Steel", "typeNullSteel": "タイプ:はがね",
"typeNullFire": "Type: Fire", "typeNullFire": "タイプ:ほのお",
"typeNullWater": "Type: Water", "typeNullWater": "タイプ:みず",
"typeNullGrass": "Type: Grass", "typeNullGrass": "タイプ:くさ",
"typeNullElectric": "Type: Electric", "typeNullElectric": "タイプ:でんき",
"typeNullPsychic": "Type: Psychic", "typeNullPsychic": "タイプ:エスパー",
"typeNullIce": "Type: Ice", "typeNullIce": "タイプ:こおり",
"typeNullDragon": "Type: Dragon", "typeNullDragon": "タイプ:ドラゴン",
"typeNullDark": "Type: Dark", "typeNullDark": "タイプ:あく",
"typeNullFairy": "Type: Fairy", "typeNullFairy": "タイプ:フェアリー",
"miniorRedMeteor": "赤 りゅうせい", "miniorRedMeteor": "赤 りゅうせい",
"miniorOrangeMeteor": "オレンジ りゅうせい", "miniorOrangeMeteor": "オレンジ りゅうせい",
"miniorYellowMeteor": "黄 りゅうせい", "miniorYellowMeteor": "黄 りゅうせい",
@ -195,63 +195,63 @@
"miniorViolet": "紫", "miniorViolet": "紫",
"mimikyuDisguised": "ばけたすがた", "mimikyuDisguised": "ばけたすがた",
"mimikyuBusted": "ばれたすがた", "mimikyuBusted": "ばれたすがた",
"necrozma": "Normal", "necrozma": "ネクロズマ",
"necrozmaDuskMane": "Dusk Mane", "necrozmaDuskMane": "たそがれのたてがみ",
"necrozmaDawnWings": "Dawn Wings", "necrozmaDawnWings": "あかつきのつばさ",
"necrozmaUltra": "Ultra", "necrozmaUltra": "ウルトラネクロズマ",
"magearna": "Normal", "magearna": "通常",
"magearnaOriginal": "500ねんまえ", "magearnaOriginal": "500ねんまえのいろ",
"marshadow": "Normal", "marshadow": "通常",
"marshadowZenith": "Zパワー", "marshadowZenith": "Zパワー",
"cramorant": "Normal", "cramorant": "通常",
"cramorantGulping": "Gulping Form", "cramorantGulping": "うのみのすがた",
"cramorantGorging": "Gorging Form", "cramorantGorging": "まるのみのすがた",
"toxelAmped": "Amped Form", "toxelAmped": "ハイなすがた",
"toxelLowkey": "Low-Key Form", "toxelLowkey": "ローなすがた",
"sinisteaPhony": "がんさく", "sinisteaPhony": "がんさく",
"sinisteaAntique": "しんさく", "sinisteaAntique": "しんさく",
"milceryVanillaCream": "Vanilla Cream", "milceryVanillaCream": "ミルキィバニラ",
"milceryRubyCream": "Ruby Cream", "milceryRubyCream": "ミルキィルビー",
"milceryMatchaCream": "Matcha Cream", "milceryMatchaCream": "ミルキィまっちゃ",
"milceryMintCream": "Mint Cream", "milceryMintCream": "ミルキィミント",
"milceryLemonCream": "Lemon Cream", "milceryLemonCream": "ミルキィレモン",
"milcerySaltedCream": "Salted Cream", "milcerySaltedCream": "ミルキィソルト",
"milceryRubySwirl": "Ruby Swirl", "milceryRubySwirl": "ルビーミックス",
"milceryCaramelSwirl": "Caramel Swirl", "milceryCaramelSwirl": "キャラメルミックス",
"milceryRainbowSwirl": "Rainbow Swirl", "milceryRainbowSwirl": "トリプルミックス",
"eiscue": "Ice Face", "eiscue": "アイスフェイス",
"eiscueNoIce": "ナイスなし", "eiscueNoIce": "ナイスフェイス",
"indeedeeMale": "オス", "indeedeeMale": "オス",
"indeedeeFemale": "メス", "indeedeeFemale": "メス",
"morpekoFullBelly": "まんぷく", "morpekoFullBelly": "まんぷくもよう",
"morpekoHangry": "Hangry", "morpekoHangry": "はらぺこもよう",
"zacianHeroOfManyBattles": "れきせんのゆうしゃ", "zacianHeroOfManyBattles": "れきせんのゆうしゃ",
"zacianCrowned": "Crowned", "zacianCrowned": "けんのおう",
"zamazentaHeroOfManyBattles": "れきせんのゆうしゃ", "zamazentaHeroOfManyBattles": "れきせんのゆうしゃ",
"zamazentaCrowned": "Crowned", "zamazentaCrowned": "けんのおう",
"kubfuSingleStrike": "Single Strike", "kubfuSingleStrike": "いちげきのかた",
"kubfuRapidStrike": "Rapid Strike", "kubfuRapidStrike": "れんげきのかた",
"zarude": "Normal", "zarude": "一般",
"zarudeDada": "とうちゃん", "zarudeDada": "とうちゃん",
"calyrex": "Normal", "calyrex": "通常",
"calyrexIce": "Ice Rider", "calyrexIce": "はくばじょうのすがた",
"calyrexShadow": "Shadow Rider", "calyrexShadow": "こくばじょうのすがた",
"basculinMale": "Male", "basculinMale": "オス",
"basculinFemale": "Female", "basculinFemale": "メス",
"enamorusIncarnate": "けしん", "enamorusIncarnate": "けしんフォルム",
"enamorusTherian": "Therian", "enamorusTherian": "れいじゅうフォルム",
"lechonkMale": "Male", "lechonkMale": "オス",
"lechonkFemale": "Female", "lechonkFemale": "メス",
"tandemausFour": "Family of Four", "tandemausFour": "4ひきかぞく",
"tandemausThree": "Family of Three", "tandemausThree": "3びきかぞく",
"squawkabillyGreenPlumage": "グリーンフェザー", "squawkabillyGreenPlumage": "グリーンフェザー",
"squawkabillyBluePlumage": "ブルーフェザー", "squawkabillyBluePlumage": "ブルーフェザー",
"squawkabillyYellowPlumage": "イエローフェザー", "squawkabillyYellowPlumage": "イエローフェザー",
"squawkabillyWhitePlumage": "ホワイトフェザー", "squawkabillyWhitePlumage": "ホワイトフェザー",
"dunsparceTwo": "Two-Segment", "dunsparceTwo": "ふたふしフォルム",
"dunsparceThree": "Three-Segment", "dunsparceThree": "みつふしフォルム",
"finizenZero": "Zero", "finizenZero": "ナイーブフォルム",
"finizenHero": "Hero", "finizenHero": "マイティフォルム",
"tatsugiriCurly": "そったすがた", "tatsugiriCurly": "そったすがた",
"tatsugiriDroopy": "たれたすがた", "tatsugiriDroopy": "たれたすがた",
"tatsugiriStretchy": "のびたすがた", "tatsugiriStretchy": "のびたすがた",
@ -269,21 +269,21 @@
"miraidonGlideMode":"グライドモード", "miraidonGlideMode":"グライドモード",
"poltchageistCounterfeit": "マガイモノ", "poltchageistCounterfeit": "マガイモノ",
"poltchageistArtisan": "タカイモノ", "poltchageistArtisan": "タカイモノ",
"poltchageistUnremarkable": "Unremarkable", "poltchageistUnremarkable": "ボンサクのすがた",
"poltchageistMasterpiece": "Masterpiece", "poltchageistMasterpiece": "ケッサクのすがた",
"ogerponTealMask": "Teal Mask", "ogerponTealMask": "みどりのめん",
"ogerponTealMaskTera": "Teal Mask Terastallized", "ogerponTealMaskTera": "みどりのめん テラスタル",
"ogerponWellspringMask": "Wellspring Mask", "ogerponWellspringMask": "いどのめん",
"ogerponWellspringMaskTera": "Wellspring Mask Terastallized", "ogerponWellspringMaskTera": "いどのめん テラスタル",
"ogerponHearthflameMask": "Hearthflame Mask", "ogerponHearthflameMask": "かまどのめん",
"ogerponHearthflameMaskTera": "Hearthflame Mask Terastallized", "ogerponHearthflameMaskTera": "かまどのめん テラスタル",
"ogerponCornerstoneMask": "Cornerstone Mask", "ogerponCornerstoneMask": "いしずえのめん",
"ogerponCornerstoneMaskTera": "Cornerstone Mask Terastallized", "ogerponCornerstoneMaskTera": "いしずえのめん テラスタル",
"terpagos": "Normal Form", "terpagos": "ノーマルフォルム",
"terpagosTerastal": "Terastal", "terpagosTerastal": "テラスタルフォルム",
"terpagosStellar": "Stellar", "terpagosStellar": "ステラフォルム",
"galarDarumaka": "Standard Mode", "galarDarumaka": "ノーマルモード",
"galarDarumakaZen": "Zen", "galarDarumakaZen": "ダルマモード",
"paldeaTaurosCombat": "コンバット", "paldeaTaurosCombat": "コンバット",
"paldeaTaurosBlaze": "ブレイズ", "paldeaTaurosBlaze": "ブレイズ",
"paldeaTaurosAqua": "ウォーター" "paldeaTaurosAqua": "ウォーター"

View File

@ -1,5 +1,5 @@
{ {
"battlesWon": "Battles Won!", "battlesWon": "勝ったバトル:{{count, number}}回!",
"joinTheDiscord": "Join the Discord!", "joinTheDiscord": "Join the Discord!",
"infiniteLevels": "Infinite Levels!", "infiniteLevels": "Infinite Levels!",
"everythingStacks": "Everything Stacks!", "everythingStacks": "Everything Stacks!",

View File

@ -1,5 +1,5 @@
{ {
"battlesWon": "전투에서 승리하세요!", "battlesWon": "{{count, number}} 전투에서 승리하세요!",
"joinTheDiscord": "디스코드에 가입하세요!", "joinTheDiscord": "디스코드에 가입하세요!",
"infiniteLevels": "무한한 레벨!", "infiniteLevels": "무한한 레벨!",
"everythingStacks": "모든 것이 누적됩니다!", "everythingStacks": "모든 것이 누적됩니다!",

View File

@ -1,5 +1,5 @@
{ {
"battlesWon": "Batalhas Ganhas!", "battlesWon": "{{count, number}} Batalhas Ganhas!",
"joinTheDiscord": "Junte-se ao Discord!", "joinTheDiscord": "Junte-se ao Discord!",
"infiniteLevels": "Níveis Infinitos!", "infiniteLevels": "Níveis Infinitos!",
"everythingStacks": "Tudo Acumula!", "everythingStacks": "Tudo Acumula!",

View File

@ -1,5 +1,5 @@
{ {
"battlesWon": "场胜利!", "battlesWon": "{{count, number}} 场胜利!",
"joinTheDiscord": "加入Discord", "joinTheDiscord": "加入Discord",
"infiniteLevels": "等级无限!", "infiniteLevels": "等级无限!",
"everythingStacks": "道具全部叠加!", "everythingStacks": "道具全部叠加!",

View File

@ -1,5 +1,5 @@
{ {
"battlesWon": "勝利場數!", "battlesWon": "{{count, number}} 勝利場數!",
"joinTheDiscord": "加入Discord", "joinTheDiscord": "加入Discord",
"infiniteLevels": "無限等級!", "infiniteLevels": "無限等級!",
"everythingStacks": "所有效果都能疊加!", "everythingStacks": "所有效果都能疊加!",

View File

@ -0,0 +1,66 @@
import { getSplashMessages } from "#app/data/splash-messages";
import { describe, expect, it, vi, afterEach, beforeEach } from "vitest";
import * as Constants from "#app/constants";
describe("Data - Splash Messages", () => {
it("should contain at least 15 splash messages", () => {
expect(getSplashMessages().length).toBeGreaterThanOrEqual(15);
});
// make sure to adjust this test if the weight it changed!
it("should add contain 10 `battlesWon` splash messages", () => {
const battlesWonMessages = getSplashMessages().filter((message) => message === "splashMessages:battlesWon");
expect(battlesWonMessages).toHaveLength(10);
});
describe("Seasonal", () => {
beforeEach(() => {
vi.spyOn(Constants, "USE_SEASONAL_SPLASH_MESSAGES", "get").mockReturnValue(true);
});
afterEach(() => {
vi.useRealTimers(); // reset system time
});
it("should contain halloween messages from Sep 15 to Oct 31", () => {
testSeason(new Date("2024-09-15"), new Date("2024-10-31"), "halloween");
});
it("should contain xmas messages from Dec 1 to Dec 26", () => {
testSeason(new Date("2024-12-01"), new Date("2024-12-26"), "xmas");
});
it("should contain new years messages frm Jan 1 to Jan 31", () => {
testSeason(new Date("2024-01-01"), new Date("2024-01-31"), "newYears");
});
});
});
/**
* Helpoer method to test seasonal messages
* @param startDate The seasons start date
* @param endDate The seasons end date
* @param prefix the splash message prefix (e.g. `newYears` or `xmas`)
*/
function testSeason(startDate: Date, endDate: Date, prefix: string) {
const filterFn = (message: string) => message.startsWith(`splashMessages:${prefix}.`);
const beforeDate = new Date(startDate);
beforeDate.setDate(startDate.getDate() - 1);
const afterDate = new Date(endDate);
afterDate.setDate(endDate.getDate() + 1);
const dates: Date[] = [beforeDate, startDate, endDate, afterDate];
const [before, start, end, after] = dates.map((date) => {
vi.setSystemTime(date);
console.log("System time set to", date);
const count = getSplashMessages().filter(filterFn).length;
return count;
});
expect(before).toBe(0);
expect(start).toBeGreaterThanOrEqual(10); // make sure to adjust if weight is changed!
expect(end).toBeGreaterThanOrEqual(10); // make sure to adjust if weight is changed!
expect(after).toBe(0);
}

View File

@ -14,6 +14,8 @@ import { initStatsKeys } from "#app/ui/game-stats-ui-handler";
import { initMysteryEncounters } from "#app/data/mystery-encounters/mystery-encounters"; import { initMysteryEncounters } from "#app/data/mystery-encounters/mystery-encounters";
import { beforeAll, vi } from "vitest"; import { beforeAll, vi } from "vitest";
process.env.TZ = "UTC";
/** Mock the override import to always return default values, ignoring any custom overrides. */ /** Mock the override import to always return default values, ignoring any custom overrides. */
vi.mock("#app/overrides", async (importOriginal) => { vi.mock("#app/overrides", async (importOriginal) => {
const { defaultOverrides } = await importOriginal<typeof import("#app/overrides")>(); const { defaultOverrides } = await importOriginal<typeof import("#app/overrides")>();

View File

@ -3,11 +3,14 @@ import OptionSelectUiHandler from "./settings/option-select-ui-handler";
import { Mode } from "./ui"; import { Mode } from "./ui";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { TextStyle, addTextObject, getTextStyleOptions } from "./text"; import { TextStyle, addTextObject, getTextStyleOptions } from "./text";
import { getBattleCountSplashMessage, getSplashMessages } from "../data/splash-messages"; import { getSplashMessages } from "../data/splash-messages";
import i18next from "i18next"; import i18next from "i18next";
import { TimedEventDisplay } from "#app/timed-event-manager"; import { TimedEventDisplay } from "#app/timed-event-manager";
export default class TitleUiHandler extends OptionSelectUiHandler { export default class TitleUiHandler extends OptionSelectUiHandler {
/** If the stats can not be retrieved, use this fallback value */
private static readonly BATTLES_WON_FALLBACK: number = -99999999;
private titleContainer: Phaser.GameObjects.Container; private titleContainer: Phaser.GameObjects.Container;
private playerCountLabel: Phaser.GameObjects.Text; private playerCountLabel: Phaser.GameObjects.Text;
private splashMessage: string; private splashMessage: string;
@ -72,8 +75,8 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
.then(request => request.json()) .then(request => request.json())
.then(stats => { .then(stats => {
this.playerCountLabel.setText(`${stats.playerCount} ${i18next.t("menu:playersOnline")}`); this.playerCountLabel.setText(`${stats.playerCount} ${i18next.t("menu:playersOnline")}`);
if (this.splashMessage === getBattleCountSplashMessage()) { if (this.splashMessage === "splashMessages:battlesWon") {
this.splashMessageText.setText(getBattleCountSplashMessage().replace("{COUNT}", stats.battleCount.toLocaleString("en-US"))); this.splashMessageText.setText(i18next.t(this.splashMessage, { count: stats.battlesWon }));
} }
}) })
.catch(err => { .catch(err => {
@ -86,7 +89,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
if (ret) { if (ret) {
this.splashMessage = Utils.randItem(getSplashMessages()); this.splashMessage = Utils.randItem(getSplashMessages());
this.splashMessageText.setText(this.splashMessage.replace("{COUNT}", "?")); this.splashMessageText.setText(i18next.t(this.splashMessage, { count: TitleUiHandler.BATTLES_WON_FALLBACK }));
const ui = this.getUi(); const ui = this.getUi();