Compare commits

...

16 Commits

Author SHA1 Message Date
Inês Simões
2dc39c41db
Merge 8d1e5f1200 into 4edcdc9192 2025-08-06 05:55:50 -07:00
thisPieonFire
4edcdc9192
[Bug] [Move] Court Change now swaps Safeguard and Pledge Effects (#6069)
* Add unit test for the "Court Change" move

* Update test/moves/court-change.test.ts

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Update test/moves/court-change.test.ts

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Add unit test for the "Court Change" move

* Improve formatting in the "Court Change" move unit test

* Update test/moves/court-change.test.ts

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Update test/moves/court-change.test.ts

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Update test/moves/court-change.test.ts

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Update test/moves/court-change.test.ts

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Update test/moves/court-change.test.ts

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Update test/moves/court-change.test.ts

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Update test/moves/court-change.test.ts

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Update test/moves/court-change.test.ts

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>

* Added missing import

* Added missing import (ArenaTagSide)

* Update court-change.test.ts

---------

Co-authored-by: PieonFire <purpledream96@hotmail.com>
Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
2025-08-06 08:48:11 -04:00
damocleas
bb86bdd2a6
[Balance] Add Scientist to Lab, Swimmer to Seabed to account for ME's
https://github.com/pagefaultgames/pokerogue/pull/6217
2025-08-05 19:57:51 -07:00
Matheus Alves
8d1e5f1200 Format name respected 2025-08-05 10:59:20 +01:00
Matheus Alves
a6007cef10 Dependency resolved 2025-08-05 10:46:15 +01:00
Matheus Rabello Noya Alves
9bb0c57b92
Merge branch 'beta' into BothSaves 2025-08-05 10:37:19 +01:00
Matheus Alves
b74849d3e2 Minor compile fix 2025-07-22 23:11:13 +01:00
Matheus Alves
f5b44036e5 Lint fix
Signed-off-by: Matheus Alves <matheus.r.noya.alves@tecnico.ulisboa.pt>
Co-authored-by: Inês Simões <ines.p.simoes@tecnico.ulisboa.pt>
2025-07-22 23:04:42 +01:00
Matheus Alves
8594614e64 Rebasing and conflict resolution
Signed-off-by: Matheus Alves <matheus.r.noya.alves@tecnico.ulisboa.pt>
Co-authored-by: Inês Simões <ines.p.simoes@tecnico.ulisboa.pt>
2025-07-22 22:47:11 +01:00
Matheus Alves
428c175cb5 Replace fallback name logic: use first active challenge instead
of game mode

Previously used game mode as the fallback name, updated to use the
first active challenge instead (e.g. Monogen or Mono Type), which
better reflects the run's theme.
Signed-off-by: Matheus Alves <matheus.r.noya.alves@tecnico.ulisboa.pt>
Co-authored-by: Inês Simões <ines.p.simoes@tecnico.ulisboa.pt>
2025-07-22 22:27:55 +01:00
Matheus Alves
116daa4baa Implemented Default Name Logic
Altered logic in save-slot-select-ui-handler.ts to
support default naming of runs based on the run
game mode with decideFallback function.

In game-data.ts, to prevent inconsistent naming,
added check for unfilled input, ignoring empty
rename requests.

Signed-off-by: Matheus Alves matheus.r.noya.alves@tecnico.ulisboa.pt
Co-authored-by: Inês Simões ines.p.simoes@tecnico.ulisboa.pt
2025-07-22 22:27:53 +01:00
Inês Simões
b25b8bde6a Fixed minor rebase alterations.
Signed-off-by: Matheus Alves matheus.r.noya.alves@tecnico.ulisboa.pt
Co-authored-by: Inês Simões ines.p.simoes@tecnico.ulisboa.pt
2025-07-22 22:26:46 +01:00
Matheus Alves
8dc3591c9e Minor Sanitization for aesthetics
Deleting the input when closing the overlay for
aesthetics purpose

Signed-off-by: Matheus Alves <matheus.r.noya.alves@tecnico.ulisboa.pt>
Co-authored-by: Inês Simões <ines.p.simoes@tecnico.ulisboa.pt>
2025-07-22 22:26:46 +01:00
Matheus Alves
e5cd77016f Fixed formating and best practices issues:
Rewrote renameSession to be more inline with other
API call funtions, removed debugging comments and
whitespaces.

Signed-off-by: Matheus Alves <matheus.r.noya.alves@tecnico.ulisboa.pt>
Co-authored-by: Inês Simões <ines.p.simoes@tecnico.ulisboa.pt>
2025-07-22 22:26:46 +01:00
Matheus Alves
034de5d307 Implement Rename Input Design and Tests for Name Run Feat
Created a test to verify Name Run Feature behaviour in the
backend (rename_run.test.ts), checking possible errors and
 expected behaviours.

Created a UiHandler RenameRunFormUiHandler
(rename-run-ui-handler.ts), creating a frontend input
overlay for the Name Run Feature.

Signed-off-by: Matheus Alves <matheus.r.noya.alves@tecnico.ulisboa.pt>
Co-authored-by: Inês Simões <ines.p.simoes@tecnico.ulisboa.pt>
2025-07-22 22:26:36 +01:00
Matheus Alves
75cb8b22b9 Implement Name Run Feat
Modified load session ui component, adding a submenu when selecting a 3
slot. This menu has 4 options:
Load Game -> Behaves as before, allowing the player to continue
progress from the last saved state in the slot.

Rename Run -> Overlays a rename form, allowing the player to type a
name for the run, checking for string validity, with the option to
cancel or confirm (Rename).

Delete Run -> Prompts user confirmation to delete save data, removing
the current save slot from the users save data.

Cancel -> Hides menu overlay.

Modified game data to implement a function to accept and store
runNameText to the users data.

Modified run info ui component, to display the chosen name when
viewing run information.

Example: When loading the game, the user can choose the Load Game
menu option, then select a save slot, prompting the menu, then choose
"Rename Run" and type the name "Monotype Water Run" then confirm,
thus being able to better organize their save files.

Signed-off-by: Matheus Alves <matheus.r.noya.alves@tecnico.ulisboa.pt>
Co-authored-by: Inês Simões <ines.p.simoes@tecnico.ulisboa.pt>
2025-07-22 22:25:38 +01:00
11 changed files with 478 additions and 167 deletions

View File

@ -1641,10 +1641,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: []
},
[BiomeId.PLAINS]: {
[BiomePoolTier.COMMON]: [ TrainerType.BREEDER, TrainerType.TWINS ],
@ -1652,10 +1649,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.CILAN, TrainerType.CHILI, TrainerType.CRESS, TrainerType.CHEREN ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.CILAN, TrainerType.CHILI, TrainerType.CRESS, TrainerType.CHEREN ]
},
[BiomeId.GRASS]: {
[BiomePoolTier.COMMON]: [ TrainerType.BREEDER, TrainerType.SCHOOL_KID ],
@ -1663,10 +1657,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.ERIKA ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.ERIKA ]
},
[BiomeId.TALL_GRASS]: {
[BiomePoolTier.COMMON]: [],
@ -1674,10 +1665,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.GARDENIA, TrainerType.VIOLA, TrainerType.BRASSIUS ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.GARDENIA, TrainerType.VIOLA, TrainerType.BRASSIUS ]
},
[BiomeId.METROPOLIS]: {
[BiomePoolTier.COMMON]: [ TrainerType.BEAUTY, TrainerType.CLERK, TrainerType.CYCLIST, TrainerType.OFFICER, TrainerType.WAITER ],
@ -1685,10 +1673,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [ TrainerType.ARTIST, TrainerType.RICH_KID ],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.WHITNEY, TrainerType.NORMAN, TrainerType.IONO, TrainerType.LARRY ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.WHITNEY, TrainerType.NORMAN, TrainerType.IONO, TrainerType.LARRY ]
},
[BiomeId.FOREST]: {
[BiomePoolTier.COMMON]: [ TrainerType.RANGER ],
@ -1696,10 +1681,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.BUGSY, TrainerType.BURGH, TrainerType.KATY ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.BUGSY, TrainerType.BURGH, TrainerType.KATY ]
},
[BiomeId.SEA]: {
[BiomePoolTier.COMMON]: [ TrainerType.SAILOR, TrainerType.SWIMMER ],
@ -1707,10 +1689,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.MARLON ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.MARLON ]
},
[BiomeId.SWAMP]: {
[BiomePoolTier.COMMON]: [ TrainerType.PARASOL_LADY ],
@ -1718,10 +1697,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.JANINE, TrainerType.ROXIE ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.JANINE, TrainerType.ROXIE ]
},
[BiomeId.BEACH]: {
[BiomePoolTier.COMMON]: [ TrainerType.FISHERMAN, TrainerType.SAILOR ],
@ -1729,10 +1705,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.MISTY, TrainerType.KOFU ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.MISTY, TrainerType.KOFU ]
},
[BiomeId.LAKE]: {
[BiomePoolTier.COMMON]: [ TrainerType.BREEDER, TrainerType.FISHERMAN, TrainerType.PARASOL_LADY ],
@ -1740,21 +1713,15 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.CRASHER_WAKE ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.CRASHER_WAKE ]
},
[BiomeId.SEABED]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.COMMON]: [ TrainerType.SWIMMER ],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.JUAN ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.JUAN ]
},
[BiomeId.MOUNTAIN]: {
[BiomePoolTier.COMMON]: [ TrainerType.BACKPACKER, TrainerType.BLACK_BELT, TrainerType.HIKER ],
@ -1762,10 +1729,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.FALKNER, TrainerType.WINONA, TrainerType.SKYLA ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.FALKNER, TrainerType.WINONA, TrainerType.SKYLA ]
},
[BiomeId.BADLANDS]: {
[BiomePoolTier.COMMON]: [ TrainerType.BACKPACKER, TrainerType.HIKER ],
@ -1773,10 +1737,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.CLAY, TrainerType.GRANT ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.CLAY, TrainerType.GRANT ]
},
[BiomeId.CAVE]: {
[BiomePoolTier.COMMON]: [ TrainerType.BACKPACKER, TrainerType.HIKER ],
@ -1784,10 +1745,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.BROCK, TrainerType.ROXANNE, TrainerType.ROARK ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.BROCK, TrainerType.ROXANNE, TrainerType.ROARK ]
},
[BiomeId.DESERT]: {
[BiomePoolTier.COMMON]: [ TrainerType.BACKPACKER, TrainerType.SCIENTIST ],
@ -1795,10 +1753,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.GORDIE ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.GORDIE ]
},
[BiomeId.ICE_CAVE]: {
[BiomePoolTier.COMMON]: [ TrainerType.SNOW_WORKER ],
@ -1806,10 +1761,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.PRYCE, TrainerType.BRYCEN, TrainerType.WULFRIC, TrainerType.GRUSHA ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.PRYCE, TrainerType.BRYCEN, TrainerType.WULFRIC, TrainerType.GRUSHA ]
},
[BiomeId.MEADOW]: {
[BiomePoolTier.COMMON]: [ TrainerType.BEAUTY, TrainerType.MUSICIAN, TrainerType.PARASOL_LADY ],
@ -1817,10 +1769,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.LENORA, TrainerType.MILO ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.LENORA, TrainerType.MILO ]
},
[BiomeId.POWER_PLANT]: {
[BiomePoolTier.COMMON]: [ TrainerType.GUITARIST, TrainerType.WORKER ],
@ -1828,10 +1777,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.VOLKNER, TrainerType.ELESA, TrainerType.CLEMONT ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.VOLKNER, TrainerType.ELESA, TrainerType.CLEMONT ]
},
[BiomeId.VOLCANO]: {
[BiomePoolTier.COMMON]: [ TrainerType.FIREBREATHER ],
@ -1839,10 +1785,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.BLAINE, TrainerType.FLANNERY, TrainerType.KABU ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.BLAINE, TrainerType.FLANNERY, TrainerType.KABU ]
},
[BiomeId.GRAVEYARD]: {
[BiomePoolTier.COMMON]: [ TrainerType.PSYCHIC ],
@ -1850,10 +1793,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.MORTY, TrainerType.ALLISTER, TrainerType.RYME ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.MORTY, TrainerType.ALLISTER, TrainerType.RYME ]
},
[BiomeId.DOJO]: {
[BiomePoolTier.COMMON]: [ TrainerType.BLACK_BELT ],
@ -1861,10 +1801,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.BRAWLY, TrainerType.MAYLENE, TrainerType.KORRINA, TrainerType.BEA ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.BRAWLY, TrainerType.MAYLENE, TrainerType.KORRINA, TrainerType.BEA ]
},
[BiomeId.FACTORY]: {
[BiomePoolTier.COMMON]: [ TrainerType.WORKER ],
@ -1872,10 +1809,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.JASMINE, TrainerType.BYRON ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.JASMINE, TrainerType.BYRON ]
},
[BiomeId.RUINS]: {
[BiomePoolTier.COMMON]: [ TrainerType.PSYCHIC, TrainerType.SCIENTIST ],
@ -1883,10 +1817,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.SABRINA, TrainerType.TATE, TrainerType.LIZA, TrainerType.TULIP ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.SABRINA, TrainerType.TATE, TrainerType.LIZA, TrainerType.TULIP ]
},
[BiomeId.WASTELAND]: {
[BiomePoolTier.COMMON]: [ TrainerType.VETERAN ],
@ -1894,10 +1825,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.CLAIR, TrainerType.DRAYDEN, TrainerType.RAIHAN ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.CLAIR, TrainerType.DRAYDEN, TrainerType.RAIHAN ]
},
[BiomeId.ABYSS]: {
[BiomePoolTier.COMMON]: [],
@ -1905,10 +1833,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.MARNIE ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.MARNIE ]
},
[BiomeId.SPACE]: {
[BiomePoolTier.COMMON]: [],
@ -1916,10 +1841,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.OLYMPIA ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.OLYMPIA ]
},
[BiomeId.CONSTRUCTION_SITE]: {
[BiomePoolTier.COMMON]: [ TrainerType.OFFICER, TrainerType.WORKER ],
@ -1927,10 +1849,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.LT_SURGE, TrainerType.CHUCK, TrainerType.WATTSON ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.LT_SURGE, TrainerType.CHUCK, TrainerType.WATTSON ]
},
[BiomeId.JUNGLE]: {
[BiomePoolTier.COMMON]: [ TrainerType.BACKPACKER, TrainerType.RANGER ],
@ -1938,10 +1857,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.RAMOS ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.RAMOS ]
},
[BiomeId.FAIRY_CAVE]: {
[BiomePoolTier.COMMON]: [ TrainerType.BEAUTY ],
@ -1949,10 +1865,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.VALERIE, TrainerType.OPAL, TrainerType.BEDE ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.VALERIE, TrainerType.OPAL, TrainerType.BEDE ]
},
[BiomeId.TEMPLE]: {
[BiomePoolTier.COMMON]: [],
@ -1960,10 +1873,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.FANTINA ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.FANTINA ]
},
[BiomeId.SLUM]: {
[BiomePoolTier.COMMON]: [ TrainerType.BIKER, TrainerType.OFFICER, TrainerType.ROUGHNECK ],
@ -1971,10 +1881,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.PIERS ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.PIERS ]
},
[BiomeId.SNOWY_FOREST]: {
[BiomePoolTier.COMMON]: [ TrainerType.SNOW_WORKER ],
@ -1982,10 +1889,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.CANDICE, TrainerType.MELONY ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.CANDICE, TrainerType.MELONY ]
},
[BiomeId.ISLAND]: {
[BiomePoolTier.COMMON]: [ TrainerType.RICH_KID ],
@ -1993,21 +1897,15 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.NESSA ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.NESSA ]
},
[BiomeId.LABORATORY]: {
[BiomePoolTier.COMMON]: [],
[BiomePoolTier.COMMON]: [ TrainerType.SCIENTIST ],
[BiomePoolTier.UNCOMMON]: [],
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [ TrainerType.GIOVANNI ],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: [ TrainerType.GIOVANNI ]
},
[BiomeId.END]: {
[BiomePoolTier.COMMON]: [],
@ -2015,13 +1913,9 @@ export const biomeTrainerPools: BiomeTrainerPools = {
[BiomePoolTier.RARE]: [],
[BiomePoolTier.SUPER_RARE]: [],
[BiomePoolTier.ULTRA_RARE]: [],
[BiomePoolTier.BOSS]: [],
[BiomePoolTier.BOSS_RARE]: [],
[BiomePoolTier.BOSS_SUPER_RARE]: [],
[BiomePoolTier.BOSS_ULTRA_RARE]: []
[BiomePoolTier.BOSS]: []
}
};
export function initBiomes() {
const pokemonBiomes = [
[ SpeciesId.BULBASAUR, PokemonType.GRASS, PokemonType.POISON, [

View File

@ -10888,7 +10888,7 @@ export function initMoves() {
.attr(MovePowerMultiplierAttr, (_user, target) => target.turnData.acted ? 1 : 2)
.bitingMove(),
new StatusMove(MoveId.COURT_CHANGE, PokemonType.NORMAL, 100, 10, -1, 0, 8)
.attr(SwapArenaTagsAttr, [ ArenaTagType.AURORA_VEIL, ArenaTagType.LIGHT_SCREEN, ArenaTagType.MIST, ArenaTagType.REFLECT, ArenaTagType.SPIKES, ArenaTagType.STEALTH_ROCK, ArenaTagType.STICKY_WEB, ArenaTagType.TAILWIND, ArenaTagType.TOXIC_SPIKES ]),
.attr(SwapArenaTagsAttr, [ ArenaTagType.AURORA_VEIL, ArenaTagType.LIGHT_SCREEN, ArenaTagType.MIST, ArenaTagType.REFLECT, ArenaTagType.SPIKES, ArenaTagType.STEALTH_ROCK, ArenaTagType.STICKY_WEB, ArenaTagType.TAILWIND, ArenaTagType.TOXIC_SPIKES, ArenaTagType.SAFEGUARD, ArenaTagType.FIRE_GRASS_PLEDGE, ArenaTagType.WATER_FIRE_PLEDGE, ArenaTagType.GRASS_WATER_PLEDGE ]),
/* Unused */
new AttackMove(MoveId.MAX_FLARE, PokemonType.FIRE, MoveCategory.PHYSICAL, 10, -1, 10, -1, 0, 8)
.target(MoveTarget.NEAR_ENEMY)

View File

@ -38,6 +38,7 @@ export enum UiMode {
UNAVAILABLE,
CHALLENGE_SELECT,
RENAME_POKEMON,
RENAME_RUN,
RUN_HISTORY,
RUN_INFO,
TEST_DIALOGUE,

View File

@ -145,7 +145,7 @@ export class Arena {
? BiomePoolTier.BOSS_SUPER_RARE
: BiomePoolTier.BOSS_ULTRA_RARE;
console.log(BiomePoolTier[tier]);
while (!this.pokemonPool[tier].length) {
while (!this.pokemonPool[tier]?.length) {
console.log(`Downgraded rarity tier from ${BiomePoolTier[tier]} to ${BiomePoolTier[tier - 1]}`);
tier--;
}

View File

@ -127,6 +127,7 @@ export interface SessionSaveData {
battleType: BattleType;
trainer: TrainerData;
gameVersion: string;
runNameText: string;
timestamp: number;
challenges: ChallengeData[];
mysteryEncounterType: MysteryEncounterType | -1; // Only defined when current wave is ME,
@ -979,6 +980,54 @@ export class GameData {
});
}
async renameSession(slotId: number, newName: string): Promise<boolean> {
return new Promise(async resolve => {
if (slotId < 0) {
return resolve(false);
}
const sessionData: SessionSaveData | null = await this.getSession(slotId);
if (!sessionData) {
return resolve(false);
}
if (newName === "") {
return resolve(true);
}
sessionData.runNameText = newName;
const updatedDataStr = JSON.stringify(sessionData);
const encrypted = encrypt(updatedDataStr, bypassLogin);
const secretId = this.secretId;
const trainerId = this.trainerId;
if (bypassLogin) {
localStorage.setItem(
`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`,
encrypt(updatedDataStr, bypassLogin),
);
resolve(true);
return;
}
pokerogueApi.savedata.session
.update({ slot: slotId, trainerId, secretId, clientSessionId }, encrypted)
.then(error => {
if (error) {
console.error("Failed to update session name:", error);
resolve(false);
} else {
localStorage.setItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`, encrypted);
updateUserInfo().then(success => {
if (success !== null && !success) {
return resolve(false);
}
});
resolve(true);
}
});
});
}
loadSession(slotId: number, sessionData?: SessionSaveData): Promise<boolean> {
// biome-ignore lint/suspicious/noAsyncPromiseExecutor: TODO: fix this
return new Promise(async (resolve, reject) => {

View File

@ -0,0 +1,54 @@
import i18next from "i18next";
import type { InputFieldConfig } from "./form-modal-ui-handler";
import { FormModalUiHandler } from "./form-modal-ui-handler";
import type { ModalConfig } from "./modal-ui-handler";
export default class RenameRunFormUiHandler extends FormModalUiHandler {
getModalTitle(_config?: ModalConfig): string {
return i18next.t("menu:renamerun");
}
getWidth(_config?: ModalConfig): number {
return 160;
}
getMargin(_config?: ModalConfig): [number, number, number, number] {
return [0, 0, 48, 0];
}
getButtonLabels(_config?: ModalConfig): string[] {
return [i18next.t("menu:rename"), i18next.t("menu:cancel")];
}
getReadableErrorMessage(error: string): string {
const colonIndex = error?.indexOf(":");
if (colonIndex > 0) {
error = error.slice(0, colonIndex);
}
return super.getReadableErrorMessage(error);
}
override getInputFieldConfigs(): InputFieldConfig[] {
return [{ label: i18next.t("menu:runName") }];
}
show(args: any[]): boolean {
if (!super.show(args)) {
return false;
}
if (this.inputs?.length) {
this.inputs.forEach(input => {
input.text = "";
});
}
const config = args[0] as ModalConfig;
this.submitAction = _ => {
this.sanitizeInputs();
const sanitizedName = btoa(encodeURIComponent(this.inputs[0].text));
config.buttonActions[0](sanitizedName);
return true;
};
return true;
}
}

View File

@ -207,6 +207,10 @@ export class RunInfoUiHandler extends UiHandler {
headerText.setOrigin(0, 0);
headerText.setPositionRelative(headerBg, 8, 4);
this.runContainer.add(headerText);
const runName = addTextObject(0, 0, this.runInfo.runNameText, TextStyle.WINDOW);
runName.setOrigin(0, 0);
runName.setPositionRelative(headerBg, 60, 4);
this.runContainer.add(runName);
}
/**

View File

@ -1,6 +1,8 @@
import { GameMode } from "#app/game-mode";
import { globalScene } from "#app/global-scene";
import type { OptionSelectConfig } from "#app/ui/abstact-option-select-ui-handler";
import { Button } from "#enums/buttons";
import { GameModes } from "#enums/game-modes";
import { TextStyle } from "#enums/text-style";
import { UiMode } from "#enums/ui-mode";
// biome-ignore lint/performance/noNamespaceImport: See `src/system/game-data.ts`
@ -15,7 +17,7 @@ import { fixedInt, formatLargeNumber, getPlayTimeString, isNullOrUndefined } fro
import i18next from "i18next";
const SESSION_SLOTS_COUNT = 5;
const SLOTS_ON_SCREEN = 3;
const SLOTS_ON_SCREEN = 2;
export enum SaveSlotUiMode {
LOAD,
@ -33,6 +35,7 @@ export class SaveSlotSelectUiHandler extends MessageUiHandler {
private uiMode: SaveSlotUiMode;
private saveSlotSelectCallback: SaveSlotSelectCallback | null;
protected manageDataConfig: OptionSelectConfig;
private scrollCursor = 0;
@ -101,6 +104,7 @@ export class SaveSlotSelectUiHandler extends MessageUiHandler {
processInput(button: Button): boolean {
const ui = this.getUi();
const manageDataOptions: any[] = [];
let success = false;
let error = false;
@ -114,9 +118,107 @@ export class SaveSlotSelectUiHandler extends MessageUiHandler {
} else {
switch (this.uiMode) {
case SaveSlotUiMode.LOAD:
this.saveSlotSelectCallback = null;
originalCallback?.(cursor);
manageDataOptions.push({
label: i18next.t("menu:loadGame"),
handler: () => {
globalScene.ui.revertMode();
originalCallback?.(cursor);
return true;
},
keepOpen: false,
});
manageDataOptions.push({
label: i18next.t("saveSlotSelectUiHandler:renameRun"),
handler: () => {
globalScene.ui.revertMode();
ui.setOverlayMode(
UiMode.RENAME_RUN,
{
buttonActions: [
(sanitizedName: string) => {
const name = decodeURIComponent(atob(sanitizedName));
globalScene.gameData.renameSession(cursor, name).then(response => {
if (response[0] === false) {
globalScene.reset(true);
} else {
this.clearSessionSlots();
this.cursorObj = null;
this.populateSessionSlots();
this.setScrollCursor(0);
this.setCursor(0);
ui.revertMode();
ui.showText("", 0);
}
});
},
() => {
ui.revertMode();
},
],
},
"",
);
return true;
},
});
this.manageDataConfig = {
xOffset: 0,
yOffset: 48,
options: manageDataOptions,
maxOptions: 4,
};
manageDataOptions.push({
label: i18next.t("saveSlotSelectUiHandler:deleteRun"),
handler: () => {
globalScene.ui.revertMode();
ui.showText(i18next.t("saveSlotSelectUiHandler:deleteData"), null, () => {
ui.setOverlayMode(
UiMode.CONFIRM,
() => {
globalScene.gameData.tryClearSession(cursor).then(response => {
if (response[0] === false) {
globalScene.reset(true);
} else {
this.clearSessionSlots();
this.cursorObj = null;
this.populateSessionSlots();
this.setScrollCursor(0);
this.setCursor(0);
ui.revertMode();
ui.showText("", 0);
}
});
},
() => {
ui.revertMode();
ui.showText("", 0);
},
false,
0,
19,
import.meta.env.DEV ? 300 : 2000,
);
});
return true;
},
keepOpen: false,
});
manageDataOptions.push({
label: i18next.t("menuUiHandler:cancel"),
handler: () => {
globalScene.ui.revertMode();
return true;
},
keepOpen: true,
});
ui.setOverlayMode(UiMode.MENU_OPTION_SELECT, this.manageDataConfig);
break;
case SaveSlotUiMode.SAVE: {
const saveAndCallback = () => {
const originalCallback = this.saveSlotSelectCallback;
@ -161,6 +263,7 @@ export class SaveSlotSelectUiHandler extends MessageUiHandler {
}
} else {
this.saveSlotSelectCallback = null;
ui.showText("", 0);
originalCallback?.(-1);
success = true;
}
@ -267,33 +370,33 @@ export class SaveSlotSelectUiHandler extends MessageUiHandler {
this.cursorObj = globalScene.add.container(0, 0);
const cursorBox = globalScene.add.nineslice(
0,
0,
15,
"select_cursor_highlight_thick",
undefined,
296,
44,
294,
this.sessionSlots[prevSlotIndex ?? 0]?.saveData?.runNameText ? 50 : 60,
6,
6,
6,
6,
);
const rightArrow = globalScene.add.image(0, 0, "cursor");
rightArrow.setPosition(160, 0);
rightArrow.setPosition(160, 15);
rightArrow.setName("rightArrow");
this.cursorObj.add([cursorBox, rightArrow]);
this.sessionSlotsContainer.add(this.cursorObj);
}
const cursorPosition = cursor + this.scrollCursor;
const cursorIncrement = cursorPosition * 56;
const cursorIncrement = cursorPosition * 76;
if (this.sessionSlots[cursorPosition] && this.cursorObj) {
const hasData = this.sessionSlots[cursorPosition].hasData;
// If the session slot lacks session data, it does not move from its default, central position.
// Only session slots with session data will move leftwards and have a visible arrow.
if (!hasData) {
this.cursorObj.setPosition(151, 26 + cursorIncrement);
this.cursorObj.setPosition(151, 20 + cursorIncrement);
this.sessionSlots[cursorPosition].setPosition(0, cursorIncrement);
} else {
this.cursorObj.setPosition(145, 26 + cursorIncrement);
this.cursorObj.setPosition(145, 20 + cursorIncrement);
this.sessionSlots[cursorPosition].setPosition(-6, cursorIncrement);
}
this.setArrowVisibility(hasData);
@ -311,7 +414,8 @@ export class SaveSlotSelectUiHandler extends MessageUiHandler {
revertSessionSlot(slotIndex: number): void {
const sessionSlot = this.sessionSlots[slotIndex];
if (sessionSlot) {
sessionSlot.setPosition(0, slotIndex * 56);
const valueHeight = 76;
sessionSlot.setPosition(0, slotIndex * valueHeight);
}
}
@ -340,7 +444,7 @@ export class SaveSlotSelectUiHandler extends MessageUiHandler {
this.setCursor(this.cursor, prevSlotIndex);
globalScene.tweens.add({
targets: this.sessionSlotsContainer,
y: this.sessionSlotsContainerInitialY - 56 * scrollCursor,
y: this.sessionSlotsContainerInitialY - 76 * scrollCursor,
duration: fixedInt(325),
ease: "Sine.easeInOut",
});
@ -374,12 +478,12 @@ export class SaveSlotSelectUiHandler extends MessageUiHandler {
class SessionSlot extends Phaser.GameObjects.Container {
public slotId: number;
public hasData: boolean;
private slotWindow: Phaser.GameObjects.NineSlice;
private loadingLabel: Phaser.GameObjects.Text;
public saveData: SessionSaveData;
constructor(slotId: number) {
super(globalScene, 0, slotId * 56);
super(globalScene, 0, slotId * 76);
this.slotId = slotId;
@ -387,32 +491,67 @@ class SessionSlot extends Phaser.GameObjects.Container {
}
setup() {
const slotWindow = addWindow(0, 0, 304, 52);
this.add(slotWindow);
this.slotWindow = addWindow(0, 0, 304, 70);
this.add(this.slotWindow);
this.loadingLabel = addTextObject(152, 26, i18next.t("saveSlotSelectUiHandler:loading"), TextStyle.WINDOW);
this.loadingLabel = addTextObject(152, 33, i18next.t("saveSlotSelectUiHandler:loading"), TextStyle.WINDOW);
this.loadingLabel.setOrigin(0.5, 0.5);
this.add(this.loadingLabel);
}
decideFallback(data: SessionSaveData) {
let fallbackName;
switch (data.gameMode) {
case GameModes.CLASSIC:
fallbackName = `${GameMode.getModeName(data.gameMode)} (${globalScene.gameData.gameStats.classicSessionsPlayed + 1})`;
break;
case GameModes.ENDLESS:
case GameModes.SPLICED_ENDLESS:
fallbackName = `${GameMode.getModeName(data.gameMode)} (${globalScene.gameData.gameStats.endlessSessionsPlayed + 1})`;
break;
case GameModes.DAILY: {
const runDay = new Date(data.timestamp).toLocaleDateString();
fallbackName = `${GameMode.getModeName(data.gameMode)} (${runDay})`;
break;
}
case GameModes.CHALLENGE:
fallbackName = data.challenges
.find(c => c.value !== 0)
?.toChallenge()
.getName();
break;
}
return fallbackName;
}
async setupWithData(data: SessionSaveData) {
const hasName = data?.runNameText;
this.remove(this.loadingLabel, true);
if (hasName) {
const nameLabel = addTextObject(8, 5, data.runNameText, TextStyle.WINDOW);
this.add(nameLabel);
} else {
const fallbackName = this.decideFallback(data);
await globalScene.gameData.renameSession(this.slotId, fallbackName);
const nameLabel = addTextObject(8, 5, fallbackName, TextStyle.WINDOW);
this.add(nameLabel);
}
const gameModeLabel = addTextObject(
8,
5,
19,
`${GameMode.getModeName(data.gameMode) || i18next.t("gameMode:unkown")} - ${i18next.t("saveSlotSelectUiHandler:wave")} ${data.waveIndex}`,
TextStyle.WINDOW,
);
this.add(gameModeLabel);
const timestampLabel = addTextObject(8, 19, new Date(data.timestamp).toLocaleString(), TextStyle.WINDOW);
const timestampLabel = addTextObject(8, 33, new Date(data.timestamp).toLocaleString(), TextStyle.WINDOW);
this.add(timestampLabel);
const playTimeLabel = addTextObject(8, 33, getPlayTimeString(data.playTime), TextStyle.WINDOW);
const playTimeLabel = addTextObject(8, 47, getPlayTimeString(data.playTime), TextStyle.WINDOW);
this.add(playTimeLabel);
const pokemonIconsContainer = globalScene.add.container(144, 4);
const pokemonIconsContainer = globalScene.add.container(144, 16);
data.party.forEach((p: PokemonData, i: number) => {
const iconContainer = globalScene.add.container(26 * i, 0);
iconContainer.setScale(0.75);
@ -441,7 +580,7 @@ class SessionSlot extends Phaser.GameObjects.Container {
this.add(pokemonIconsContainer);
const modifierIconsContainer = globalScene.add.container(148, 30);
const modifierIconsContainer = globalScene.add.container(148, 38);
modifierIconsContainer.setScale(0.5);
let visibleModifierIndex = 0;
for (const m of data.modifiers) {

View File

@ -60,6 +60,7 @@ import { addWindow } from "#ui/ui-theme";
import { UnavailableModalUiHandler } from "#ui/unavailable-modal-ui-handler";
import { executeIf } from "#utils/common";
import i18next from "i18next";
import RenameRunFormUiHandler from "./rename-run-ui-handler";
const transitionModes = [
UiMode.SAVE_SLOT,
@ -98,6 +99,7 @@ const noTransitionModes = [
UiMode.SESSION_RELOAD,
UiMode.UNAVAILABLE,
UiMode.RENAME_POKEMON,
UiMode.RENAME_RUN,
UiMode.TEST_DIALOGUE,
UiMode.AUTO_COMPLETE,
UiMode.ADMIN,
@ -168,6 +170,7 @@ export class UI extends Phaser.GameObjects.Container {
new UnavailableModalUiHandler(),
new GameChallengesUiHandler(),
new RenameFormUiHandler(),
new RenameRunFormUiHandler(),
new RunHistoryUiHandler(),
new RunInfoUiHandler(),
new TestDialogueUiHandler(UiMode.TEST_DIALOGUE),

View File

@ -0,0 +1,85 @@
import { AbilityId } from "#enums/ability-id";
import { ArenaTagSide } from "#enums/arena-tag-side";
import { ArenaTagType } from "#enums/arena-tag-type";
import { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id";
import { Stat } from "#enums/stat";
import { StatusEffect } from "#enums/status-effect";
import { GameManager } from "#test/test-utils/game-manager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
describe("Move - Court Change", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.ability(AbilityId.BALL_FETCH)
.criticalHits(false)
.enemyAbility(AbilityId.STURDY)
.startingLevel(100)
.battleStyle("single")
.enemySpecies(SpeciesId.MAGIKARP)
.enemyMoveset(MoveId.SPLASH);
});
it("should swap combined Pledge effects to the opposite side", async () => {
game.override.battleStyle("double");
await game.classicMode.startBattle([SpeciesId.REGIELEKI, SpeciesId.SHUCKLE]);
const regieleki = game.field.getPlayerPokemon();
const enemyPokemon = game.field.getEnemyPokemon();
game.move.use(MoveId.WATER_PLEDGE);
game.move.use(MoveId.GRASS_PLEDGE, 1);
await game.toNextTurn();
// enemy team will be in the swamp and slowed
expect(game.scene.arena.getTagOnSide(ArenaTagType.GRASS_WATER_PLEDGE, ArenaTagSide.ENEMY)).toBeDefined();
expect(enemyPokemon.getEffectiveStat(Stat.SPD)).toBe(enemyPokemon.getStat(Stat.SPD) / 4);
game.move.use(MoveId.COURT_CHANGE);
game.move.use(MoveId.SPLASH, 1);
await game.toEndOfTurn();
// own team should now be in the swamp and slowed
expect(game.scene.arena.getTagOnSide(ArenaTagType.GRASS_WATER_PLEDGE, ArenaTagSide.ENEMY)).toBeUndefined();
expect(game.scene.arena.getTagOnSide(ArenaTagType.GRASS_WATER_PLEDGE, ArenaTagSide.PLAYER)).toBeDefined();
expect(regieleki.getEffectiveStat(Stat.SPD)).toBe(regieleki.getStat(Stat.SPD) / 4);
});
it("should swap safeguard to the enemy side ", async () => {
game.override.enemyMoveset(MoveId.TOXIC_THREAD);
await game.classicMode.startBattle([SpeciesId.NINJASK]);
const ninjask = game.field.getPlayerPokemon();
game.move.use(MoveId.SAFEGUARD);
await game.move.forceEnemyMove(MoveId.TOXIC_THREAD);
await game.toNextTurn();
// Ninjask will not be poisoned because of Safeguard
expect(game.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, ArenaTagSide.PLAYER)).toBeDefined();
expect(ninjask.status?.effect).toBeUndefined();
game.move.use(MoveId.COURT_CHANGE);
await game.toEndOfTurn();
// Ninjask should now be poisoned due to lack of Safeguard
expect(game.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, ArenaTagSide.PLAYER)).toBeUndefined();
expect(game.scene.arena.getTagOnSide(ArenaTagType.SAFEGUARD, ArenaTagSide.ENEMY)).toBeDefined();
expect(ninjask.status?.effect).toBe(StatusEffect.POISON);
});
});

View File

@ -0,0 +1,82 @@
import * as account from "#app/account";
import * as bypassLoginModule from "#app/global-vars/bypass-login";
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
import type { SessionSaveData } from "#app/system/game-data";
import { AbilityId } from "#enums/ability-id";
import { MoveId } from "#enums/move-id";
import { GameManager } from "#test/test-utils/game-manager";
import Phaser from "phaser";
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
describe("System - Rename Run", () => {
let phaserGame: Phaser.Game;
let game: GameManager;
beforeAll(() => {
phaserGame = new Phaser.Game({
type: Phaser.HEADLESS,
});
});
beforeEach(() => {
game = new GameManager(phaserGame);
game.override
.moveset([MoveId.SPLASH])
.battleStyle("single")
.enemyAbility(AbilityId.BALL_FETCH)
.enemyMoveset(MoveId.SPLASH);
});
afterEach(() => {
game.phaseInterceptor.restoreOg();
});
describe("renameSession", () => {
beforeEach(() => {
vi.spyOn(bypassLoginModule, "bypassLogin", "get").mockReturnValue(false);
vi.spyOn(account, "updateUserInfo").mockImplementation(async () => [true, 1]);
});
it("should return false if slotId < 0", async () => {
const result = await game.scene.gameData.renameSession(-1, "Named Run");
expect(result).toEqual(false);
});
it("should return false if getSession returns null", async () => {
vi.spyOn(game.scene.gameData, "getSession").mockResolvedValue(null as unknown as SessionSaveData);
const result = await game.scene.gameData.renameSession(-1, "Named Run");
expect(result).toEqual(false);
});
it("should return true if bypassLogin is true", async () => {
vi.spyOn(bypassLoginModule, "bypassLogin", "get").mockReturnValue(true);
vi.spyOn(game.scene.gameData, "getSession").mockResolvedValue({} as SessionSaveData);
const result = await game.scene.gameData.renameSession(0, "Named Run");
expect(result).toEqual(true);
});
it("should return false if api returns error", async () => {
vi.spyOn(game.scene.gameData, "getSession").mockResolvedValue({} as SessionSaveData);
vi.spyOn(pokerogueApi.savedata.session, "update").mockResolvedValue("Unknown Error!");
const result = await game.scene.gameData.renameSession(0, "Named Run");
expect(result).toEqual(false);
});
it("should return true if api is succesfull", async () => {
vi.spyOn(game.scene.gameData, "getSession").mockResolvedValue({} as SessionSaveData);
vi.spyOn(pokerogueApi.savedata.session, "update").mockResolvedValue("");
const result = await game.scene.gameData.renameSession(0, "Named Run");
expect(result).toEqual(true);
expect(account.updateUserInfo).toHaveBeenCalled();
});
});
});