Compare commits

...

11 Commits

Author SHA1 Message Date
Blitzy
2a59918819
Merge ab75d6cbdb into 1633df75c4 2025-08-05 19:25:12 -04:00
Sirz Benjie
1633df75c4
[UI/UX] Add change password ui (#5938)
* Add change password ui

* Ensure input fields are cleared after submit or cancel

* Play select sound on successful submission or cancel

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
Co-authored-by: Wlowscha <54003515+Wlowscha@users.noreply.github.com>
2025-08-05 16:35:58 -06:00
Blitzy
ab75d6cbdb
Merge branch 'beta' into evilleaderchanges 2025-08-04 11:52:34 -05:00
Blitzy
d179894018
Merge branch 'beta' into evilleaderchanges 2025-07-25 20:51:05 -05:00
Blitzy
f73335e1f2 Misc Edits 2025-07-25 20:49:41 -05:00
Blitzy
3bfd908d60 Update trainer-config.ts 2025-07-25 20:41:24 -05:00
Blitzy
34706102ec
Update trainer-config.ts 2025-07-23 19:41:49 -05:00
Blitzy
40e9360320
Update trainer-config.ts 2025-07-23 19:34:57 -05:00
Blitzy
e199fe6808
Update trainer-config.ts 2025-07-23 19:31:43 -05:00
Blitzy
216b979636
Update trainer-config.ts 2025-07-23 19:24:06 -05:00
Blitzy
f662dad4b3
Update trainer-config.ts 2025-07-23 19:18:00 -05:00
9 changed files with 310 additions and 130 deletions

View File

@ -15,3 +15,10 @@ export interface AccountRegisterRequest {
username: string; username: string;
password: string; password: string;
} }
export interface AccountChangePwRequest {
password: string;
}
export interface AccountChangePwResponse {
success: boolean;
}

View File

@ -4974,21 +4974,21 @@ export const trainerConfigs: TrainerConfigs = {
.setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.NIDOQUEEN, SpeciesId.NIDOKING])) .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.NIDOQUEEN, SpeciesId.NIDOKING]))
.setPartyMemberFunc( .setPartyMemberFunc(
4, 4,
getRandomPartyMemberFunc([SpeciesId.RHYPERIOR], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
p.abilityIndex = 1; // Solid Rock
}),
)
.setPartyMemberFunc(
5,
getRandomPartyMemberFunc([SpeciesId.KANGASKHAN], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.KANGASKHAN], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
p.formIndex = 1; // Mega Kangaskhan p.formIndex = 1; // Mega Kangaskhan
p.generateName(); p.generateName();
}), }),
)
.setPartyMemberFunc(
5,
getRandomPartyMemberFunc([SpeciesId.RHYPERIOR], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
p.abilityIndex = 1; // Solid Rock
p.setBoss(true, 2);
}),
), ),
[TrainerType.ROCKET_BOSS_GIOVANNI_2]: new TrainerConfig(++t) [TrainerType.ROCKET_BOSS_GIOVANNI_2]: new TrainerConfig(++t)
.setName("Giovanni") .setName("Giovanni")
@ -4997,52 +4997,53 @@ export const trainerConfigs: TrainerConfigs = {
.setVictoryBgm("victory_team_plasma") .setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc( .setPartyMemberFunc(
0, 0,
getRandomPartyMemberFunc([SpeciesId.TYRANITAR], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.RHYPERIOR], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2); p.setBoss(true, 2);
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.abilityIndex = 1; // Solid Rock
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(
1, 1,
getRandomPartyMemberFunc([SpeciesId.GASTRODON, SpeciesId.SEISMITOAD], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.NIDOKING, SpeciesId.NIDOQUEEN], TrainerSlot.TRAINER, true, p => {
if (p.species.speciesId === SpeciesId.GASTRODON) { p.generateAndPopulateMoveset();
p.abilityIndex = 0; // Storm Drain p.abilityIndex = 2; // Sheer Force
} else if (p.species.speciesId === SpeciesId.SEISMITOAD) {
p.abilityIndex = 2; // Water Absorb
}
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(
2, 2,
getRandomPartyMemberFunc([SpeciesId.GARCHOMP, SpeciesId.EXCADRILL], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.HONCHKROW], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === MoveId.SUCKER_PUNCH)) {
if (p.species.speciesId === SpeciesId.GARCHOMP) { // Check if Sucker Punch is in the moveset, if not, replace the third move with Sucker Punch.
p.abilityIndex = 2; // Rough Skin p.moveset[2] = new PokemonMove(MoveId.SUCKER_PUNCH);
} else if (p.species.speciesId === SpeciesId.EXCADRILL) {
p.abilityIndex = 0; // Sand Rush
} }
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(
3, 3,
getRandomPartyMemberFunc([SpeciesId.RHYPERIOR], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
p.abilityIndex = 1; // Solid Rock
}),
)
.setPartyMemberFunc(
4,
getRandomPartyMemberFunc([SpeciesId.KANGASKHAN], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.KANGASKHAN], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
p.formIndex = 1; // Mega Kangaskhan p.formIndex = 1; // Mega Kangaskhan
p.generateName(); p.generateName();
}), }),
) )
.setPartyMemberFunc(
4,
getRandomPartyMemberFunc(
[SpeciesId.ARTICUNO, SpeciesId.ZAPDOS, SpeciesId.MOLTRES],
TrainerSlot.TRAINER,
true,
p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
p.abilityIndex = 2; // Snow Cloak Articuno, Static Zapdos, Flame Body Moltres
p.setBoss(true, 2);
},
),
)
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.MEWTWO], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.MEWTWO], TrainerSlot.TRAINER, true, p => {
@ -5056,16 +5057,22 @@ export const trainerConfigs: TrainerConfigs = {
.initForEvilTeamLeader("Magma Boss", []) .initForEvilTeamLeader("Magma Boss", [])
.setMixedBattleBgm("battle_aqua_magma_boss") .setMixedBattleBgm("battle_aqua_magma_boss")
.setVictoryBgm("victory_team_plasma") .setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([SpeciesId.SOLROCK]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.TALONFLAME]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.WEEZING, SpeciesId.GALAR_WEEZING]))
.setPartyMemberFunc( .setPartyMemberFunc(
3, 0,
getRandomPartyMemberFunc([SpeciesId.TORKOAL], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.TORKOAL], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.abilityIndex = 1; // Drought p.abilityIndex = 1; // Drought
}), }),
) )
.setPartyMemberFunc(
1,
getRandomPartyMemberFunc([SpeciesId.SCOVILLAIN], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 0; // Chlorophyll
}),
)
.setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.WEEZING, SpeciesId.GALAR_WEEZING]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.SOLROCK]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.DONPHAN])) .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.DONPHAN]))
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
@ -5140,14 +5147,14 @@ export const trainerConfigs: TrainerConfigs = {
.initForEvilTeamLeader("Aqua Boss", []) .initForEvilTeamLeader("Aqua Boss", [])
.setMixedBattleBgm("battle_aqua_magma_boss") .setMixedBattleBgm("battle_aqua_magma_boss")
.setVictoryBgm("victory_team_plasma") .setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([SpeciesId.LUDICOLO]))
.setPartyMemberFunc( .setPartyMemberFunc(
1, 0,
getRandomPartyMemberFunc([SpeciesId.PELIPPER], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.PELIPPER], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.abilityIndex = 1; // Drizzle p.abilityIndex = 1; // Drizzle
}), }),
) )
.setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.LUDICOLO]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.MUK, SpeciesId.ALOLA_MUK])) .setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.MUK, SpeciesId.ALOLA_MUK]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.WAILORD])) .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.WAILORD]))
.setPartyMemberFunc( .setPartyMemberFunc(
@ -5225,18 +5232,16 @@ export const trainerConfigs: TrainerConfigs = {
.setMixedBattleBgm("battle_galactic_boss") .setMixedBattleBgm("battle_galactic_boss")
.setVictoryBgm("victory_team_plasma") .setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([SpeciesId.GYARADOS])) .setPartyMemberFunc(0, getRandomPartyMemberFunc([SpeciesId.GYARADOS]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.HONCHKROW, SpeciesId.HISUI_BRAVIARY])) .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.HONCHKROW, SpeciesId.CROBAT]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.MAGNEZONE]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.UXIE, SpeciesId.MESPRIT, SpeciesId.AZELF]))
.setPartyMemberFunc( .setPartyMemberFunc(
4, 2,
getRandomPartyMemberFunc([SpeciesId.HOUNDOOM], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.MAGNEZONE, SpeciesId.PROBOPASS], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL; p.abilityIndex = p.species.speciesId === SpeciesId.MAGNEZONE ? 1 : 0; // Sturdy
p.formIndex = 1; // Mega Houndoom
p.generateName();
}), }),
) )
.setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.UXIE, SpeciesId.MESPRIT, SpeciesId.AZELF]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.HOUNDOOM]))
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.WEAVILE], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.WEAVILE], TrainerSlot.TRAINER, true, p => {
@ -5258,7 +5263,13 @@ export const trainerConfigs: TrainerConfigs = {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
}), }),
) )
.setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.MAGNEZONE])) .setPartyMemberFunc(
1,
getRandomPartyMemberFunc([SpeciesId.MAGNEZONE, SpeciesId.PROBOPASS], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = p.species.speciesId === SpeciesId.MAGNEZONE ? 1 : 0; // Sturdy
}),
)
.setPartyMemberFunc( .setPartyMemberFunc(
2, 2,
getRandomPartyMemberFunc([SpeciesId.UXIE, SpeciesId.MESPRIT, SpeciesId.AZELF], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.UXIE, SpeciesId.MESPRIT, SpeciesId.AZELF], TrainerSlot.TRAINER, true, p => {
@ -5374,24 +5385,8 @@ export const trainerConfigs: TrainerConfigs = {
p.gender = Gender.MALE; p.gender = Gender.MALE;
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.MALAMAR]))
3, .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.AEGISLASH, SpeciesId.HISUI_GOODRA]))
getRandomPartyMemberFunc([SpeciesId.DRAGALGE, SpeciesId.CLAWITZER], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
if (p.species.speciesId === SpeciesId.DRAGALGE) {
p.abilityIndex = 2; // Adaptability
} else if (p.species.speciesId === SpeciesId.CLAWITZER) {
p.abilityIndex = 0; // Mega Launcher
}
}),
)
.setPartyMemberFunc(
4,
getRandomPartyMemberFunc([SpeciesId.GALLADE], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.abilityIndex = 1; // Sharpness
}),
)
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.GYARADOS], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.GYARADOS], TrainerSlot.TRAINER, true, p => {
@ -5416,21 +5411,11 @@ export const trainerConfigs: TrainerConfigs = {
p.gender = Gender.MALE; p.gender = Gender.MALE;
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.MIENSHAO]))
1,
getRandomPartyMemberFunc([SpeciesId.DRAGALGE, SpeciesId.CLAWITZER], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
if (p.species.speciesId === SpeciesId.DRAGALGE) {
p.abilityIndex = 2; // Adaptability
} else if (p.species.speciesId === SpeciesId.CLAWITZER) {
p.abilityIndex = 0; // Mega Launcher
}
}),
)
.setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.AEGISLASH, SpeciesId.HISUI_GOODRA])) .setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.AEGISLASH, SpeciesId.HISUI_GOODRA]))
.setPartyMemberFunc( .setPartyMemberFunc(
3, 3,
getRandomPartyMemberFunc([SpeciesId.IRON_VALIANT], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.VOLCANION], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL; p.pokeball = PokeballType.ROGUE_BALL;
}), }),
@ -5467,10 +5452,10 @@ export const trainerConfigs: TrainerConfigs = {
p.gender = Gender.FEMALE; p.gender = Gender.FEMALE;
}), }),
) )
.setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.LILLIGANT, SpeciesId.HISUI_LILLIGANT])) .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.LILLIGANT]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.MILOTIC, SpeciesId.PRIMARINA])) .setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.MILOTIC]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.GALAR_SLOWBRO, SpeciesId.GALAR_SLOWKING])) .setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.GALAR_SLOWBRO, SpeciesId.GALAR_SLOWKING]))
.setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.BEWEAR])) .setPartyMemberFunc(4, getRandomPartyMemberFunc([SpeciesId.BEWEAR, SpeciesId.LOPUNNY]))
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.NIHILEGO], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.NIHILEGO], TrainerSlot.TRAINER, true, p => {
@ -5492,7 +5477,7 @@ export const trainerConfigs: TrainerConfigs = {
p.gender = Gender.FEMALE; p.gender = Gender.FEMALE;
}), }),
) )
.setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.MILOTIC, SpeciesId.PRIMARINA])) .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.MILOTIC, SpeciesId.LILLIGANT]))
.setPartyMemberFunc( .setPartyMemberFunc(
2, 2,
getRandomPartyMemberFunc([SpeciesId.SILVALLY], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.SILVALLY], TrainerSlot.TRAINER, true, p => {
@ -5572,7 +5557,11 @@ export const trainerConfigs: TrainerConfigs = {
getRandomPartyMemberFunc([SpeciesId.GOLISOPOD], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.GOLISOPOD], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2); p.setBoss(true, 2);
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === MoveId.FIRST_IMPRESSION)) {
// Check if First Impression is in the moveset, if not, replace the third move with First Impression.
p.moveset[2] = new PokemonMove(MoveId.FIRST_IMPRESSION);
p.gender = Gender.MALE; p.gender = Gender.MALE;
}
}), }),
), ),
[TrainerType.GUZMA_2]: new TrainerConfig(++t) [TrainerType.GUZMA_2]: new TrainerConfig(++t)
@ -5585,8 +5574,12 @@ export const trainerConfigs: TrainerConfigs = {
getRandomPartyMemberFunc([SpeciesId.GOLISOPOD], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.GOLISOPOD], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2); p.setBoss(true, 2);
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === MoveId.FIRST_IMPRESSION)) {
// Check if First Impression is in the moveset, if not, replace the third move with First Impression.
p.moveset[2] = new PokemonMove(MoveId.FIRST_IMPRESSION);
p.abilityIndex = 2; // Anticipation p.abilityIndex = 2; // Anticipation
p.gender = Gender.MALE; p.gender = Gender.MALE;
}
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(
@ -5697,13 +5690,7 @@ export const trainerConfigs: TrainerConfigs = {
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.CORVIKNIGHT]))
1,
getRandomPartyMemberFunc([SpeciesId.AEGISLASH, SpeciesId.GHOLDENGO], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
}),
)
.setPartyMemberFunc( .setPartyMemberFunc(
2, 2,
getRandomPartyMemberFunc([SpeciesId.DRACOZOLT, SpeciesId.DRACOVISH], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.DRACOZOLT, SpeciesId.DRACOVISH], TrainerSlot.TRAINER, true, p => {
@ -5721,19 +5708,6 @@ export const trainerConfigs: TrainerConfigs = {
) )
.setPartyMemberFunc( .setPartyMemberFunc(
4, 4,
getRandomPartyMemberFunc(
[SpeciesId.GALAR_ARTICUNO, SpeciesId.GALAR_ZAPDOS, SpeciesId.GALAR_MOLTRES],
TrainerSlot.TRAINER,
true,
p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
},
),
)
.setPartyMemberFunc(
5,
getRandomPartyMemberFunc([SpeciesId.COPPERAJAH], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.COPPERAJAH], TrainerSlot.TRAINER, true, p => {
p.setBoss(true, 2); p.setBoss(true, 2);
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
@ -5742,24 +5716,48 @@ export const trainerConfigs: TrainerConfigs = {
p.pokeball = PokeballType.ULTRA_BALL; p.pokeball = PokeballType.ULTRA_BALL;
p.gender = Gender.FEMALE; p.gender = Gender.FEMALE;
}), }),
)
.setPartyMemberFunc(
5,
getRandomPartyMemberFunc(
[SpeciesId.GALAR_ARTICUNO, SpeciesId.GALAR_ZAPDOS, SpeciesId.GALAR_MOLTRES],
TrainerSlot.TRAINER,
true,
p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ROGUE_BALL;
},
),
), ),
[TrainerType.PENNY]: new TrainerConfig(++t) [TrainerType.PENNY]: new TrainerConfig(++t)
.setName("Cassiopeia") .setName("Cassiopeia")
.initForEvilTeamLeader("Star Boss", []) .initForEvilTeamLeader("Star Boss", [])
.setMixedBattleBgm("battle_star_boss") .setMixedBattleBgm("battle_star_boss")
.setVictoryBgm("victory_team_plasma") .setVictoryBgm("victory_team_plasma")
.setPartyMemberFunc(0, getRandomPartyMemberFunc([SpeciesId.JOLTEON, SpeciesId.LEAFEON])) .setPartyMemberFunc(0, getRandomPartyMemberFunc([SpeciesId.ESPEON]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.VAPOREON, SpeciesId.UMBREON])) .setPartyMemberFunc(1, getRandomPartyMemberFunc([SpeciesId.UMBREON]))
.setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.ESPEON, SpeciesId.GLACEON])) .setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.LEAFEON, SpeciesId.GLACEON]))
.setPartyMemberFunc(3, getRandomPartyMemberFunc([SpeciesId.FLAREON]))
.setPartyMemberFunc( .setPartyMemberFunc(
4, 3,
getRandomPartyMemberFunc([SpeciesId.SYLVEON], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.SYLVEON], TrainerSlot.TRAINER, true, p => {
p.abilityIndex = 2; // Pixilate p.abilityIndex = 2; // Pixilate
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.gender = Gender.FEMALE; p.gender = Gender.FEMALE;
}), }),
) )
.setPartyMemberFunc(
4,
getRandomPartyMemberFunc(
[SpeciesId.VAPOREON, SpeciesId.FLAREON, SpeciesId.JOLTEON],
TrainerSlot.TRAINER,
true,
p => {
p.setBoss(true, 2);
p.generateAndPopulateMoveset();
},
),
)
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
getRandomPartyMemberFunc([SpeciesId.EEVEE], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.EEVEE], TrainerSlot.TRAINER, true, p => {
@ -5770,7 +5768,7 @@ export const trainerConfigs: TrainerConfigs = {
p.generateName(); p.generateName();
}), }),
) )
.setInstantTera(4), // Tera Fairy Sylveon .setInstantTera(3), // Tera Fairy Sylveon
[TrainerType.PENNY_2]: new TrainerConfig(++t) [TrainerType.PENNY_2]: new TrainerConfig(++t)
.setName("Cassiopeia") .setName("Cassiopeia")
.initForEvilTeamLeader("Star Boss", [], true) .initForEvilTeamLeader("Star Boss", [], true)
@ -5782,7 +5780,11 @@ export const trainerConfigs: TrainerConfigs = {
p.setBoss(true, 2); p.setBoss(true, 2);
p.abilityIndex = 2; // Pixilate p.abilityIndex = 2; // Pixilate
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
if (!p.moveset.some(move => !isNullOrUndefined(move) && move.moveId === MoveId.HYPER_VOICE)) {
// Check if Hyper Voice is in the moveset, if not, replace the second move with Hyper Voice.
p.moveset[1] = new PokemonMove(MoveId.HYPER_VOICE);
p.gender = Gender.FEMALE; p.gender = Gender.FEMALE;
}
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(
@ -5792,13 +5794,7 @@ export const trainerConfigs: TrainerConfigs = {
p.formIndex = randSeedInt(5, 1); // Heat, Wash, Frost, Fan, or Mow p.formIndex = randSeedInt(5, 1); // Heat, Wash, Frost, Fan, or Mow
}), }),
) )
.setPartyMemberFunc( .setPartyMemberFunc(2, getRandomPartyMemberFunc([SpeciesId.UMBREON, SpeciesId.ESPEON]))
2,
getRandomPartyMemberFunc([SpeciesId.RAIKOU, SpeciesId.ENTEI, SpeciesId.SUICUNE], TrainerSlot.TRAINER, true, p => {
p.generateAndPopulateMoveset();
p.pokeball = PokeballType.ULTRA_BALL;
}),
)
.setPartyMemberFunc( .setPartyMemberFunc(
3, 3,
getRandomPartyMemberFunc([SpeciesId.REVAVROOM], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc([SpeciesId.REVAVROOM], TrainerSlot.TRAINER, true, p => {
@ -5809,11 +5805,16 @@ export const trainerConfigs: TrainerConfigs = {
) )
.setPartyMemberFunc( .setPartyMemberFunc(
4, 4,
getRandomPartyMemberFunc([SpeciesId.ZAMAZENTA], TrainerSlot.TRAINER, true, p => { getRandomPartyMemberFunc(
p.setBoss(true, 2); [SpeciesId.WALKING_WAKE, SpeciesId.GOUGING_FIRE, SpeciesId.RAGING_BOLT],
TrainerSlot.TRAINER,
true,
p => {
p.generateAndPopulateMoveset(); p.generateAndPopulateMoveset();
p.pokeball = PokeballType.MASTER_BALL; p.pokeball = PokeballType.ROGUE_BALL;
}), p.setBoss(true, 2);
},
),
) )
.setPartyMemberFunc( .setPartyMemberFunc(
5, 5,
@ -5826,6 +5827,7 @@ export const trainerConfigs: TrainerConfigs = {
}), }),
) )
.setInstantTera(0), // Tera Fairy Sylveon .setInstantTera(0), // Tera Fairy Sylveon
[TrainerType.BUCK]: new TrainerConfig(++t) [TrainerType.BUCK]: new TrainerConfig(++t)
.setName("Buck") .setName("Buck")
.initForStatTrainer(true) .initForStatTrainer(true)

View File

@ -43,5 +43,6 @@ export enum UiMode {
TEST_DIALOGUE, TEST_DIALOGUE,
AUTO_COMPLETE, AUTO_COMPLETE,
ADMIN, ADMIN,
MYSTERY_ENCOUNTER MYSTERY_ENCOUNTER,
CHANGE_PASSWORD_FORM,
} }

View File

@ -1,6 +1,7 @@
import { ApiBase } from "#api/api-base"; import { ApiBase } from "#api/api-base";
import { SESSION_ID_COOKIE_NAME } from "#app/constants"; import { SESSION_ID_COOKIE_NAME } from "#app/constants";
import type { import type {
AccountChangePwRequest,
AccountInfoResponse, AccountInfoResponse,
AccountLoginRequest, AccountLoginRequest,
AccountLoginResponse, AccountLoginResponse,
@ -95,4 +96,19 @@ export class PokerogueAccountApi extends ApiBase {
removeCookie(SESSION_ID_COOKIE_NAME); // we are always clearing the cookie. removeCookie(SESSION_ID_COOKIE_NAME); // we are always clearing the cookie.
} }
public async changePassword(changePwData: AccountChangePwRequest) {
try {
const response = await this.doPost("/account/changepw", changePwData, "form-urlencoded");
if (response.ok) {
return null;
}
console.warn("Change password failed!", response.status, response.statusText);
return response.text();
} catch (err) {
console.warn("Change password failed!", err);
}
return "Unknown error!";
}
} }

View File

@ -0,0 +1,124 @@
import { globalScene } from "#app/global-scene";
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
import { UiMode } from "#enums/ui-mode";
import type { InputFieldConfig } from "#ui/form-modal-ui-handler";
import { FormModalUiHandler } from "#ui/form-modal-ui-handler";
import type { ModalConfig } from "#ui/modal-ui-handler";
import i18next from "i18next";
export class ChangePasswordFormUiHandler extends FormModalUiHandler {
private readonly ERR_PASSWORD: string = "invalid password";
private readonly ERR_ACCOUNT_EXIST: string = "account doesn't exist";
private readonly ERR_PASSWORD_MISMATCH: string = "password doesn't match";
constructor(mode: UiMode | null = null) {
super(mode);
}
setup(): void {
super.setup();
}
override getModalTitle(_config?: ModalConfig): string {
return i18next.t("menu:changePassword");
}
override getWidth(_config?: ModalConfig): number {
return 160;
}
override getMargin(_config?: ModalConfig): [number, number, number, number] {
return [0, 0, 48, 0];
}
override getButtonLabels(_config?: ModalConfig): string[] {
return [i18next.t("settings:buttonSubmit"), i18next.t("menu:cancel")];
}
override getReadableErrorMessage(error: string): string {
const colonIndex = error?.indexOf(":");
if (colonIndex > 0) {
error = error.slice(0, colonIndex);
}
switch (error) {
case this.ERR_PASSWORD:
return i18next.t("menu:invalidRegisterPassword");
case this.ERR_ACCOUNT_EXIST:
return i18next.t("menu:accountNonExistent");
case this.ERR_PASSWORD_MISMATCH:
return i18next.t("menu:passwordNotMatchingConfirmPassword");
}
return super.getReadableErrorMessage(error);
}
override getInputFieldConfigs(): InputFieldConfig[] {
const inputFieldConfigs: InputFieldConfig[] = [];
inputFieldConfigs.push({
label: i18next.t("menu:password"),
isPassword: true,
});
inputFieldConfigs.push({
label: i18next.t("menu:confirmPassword"),
isPassword: true,
});
return inputFieldConfigs;
}
override show(args: [ModalConfig, ...any]): boolean {
if (super.show(args)) {
const config = args[0];
const originalSubmitAction = this.submitAction;
this.submitAction = () => {
if (globalScene.tweens.getTweensOf(this.modalContainer).length === 0) {
// Prevent overlapping overrides on action modification
this.submitAction = originalSubmitAction;
this.sanitizeInputs();
globalScene.ui.setMode(UiMode.LOADING, { buttonActions: [] });
const onFail = (error: string | null) => {
globalScene.ui.setMode(UiMode.CHANGE_PASSWORD_FORM, Object.assign(config, { errorMessage: error?.trim() }));
globalScene.ui.playError();
};
const [passwordInput, confirmPasswordInput] = this.inputs;
if (!passwordInput?.text) {
return onFail(this.getReadableErrorMessage("invalid password"));
}
if (passwordInput.text !== confirmPasswordInput.text) {
return onFail(this.ERR_PASSWORD_MISMATCH);
}
pokerogueApi.account.changePassword({ password: passwordInput.text }).then(error => {
if (!error && originalSubmitAction) {
globalScene.ui.playSelect();
originalSubmitAction();
// Only clear inputs if the action was successful
for (const input of this.inputs) {
input.setText("");
}
} else {
onFail(error);
}
});
}
};
// Upon pressing cancel, the inputs should be cleared
const originalCancelAction = this.cancelAction;
this.cancelAction = () => {
globalScene.ui.playSelect();
for (const input of this.inputs) {
input.setText("");
}
originalCancelAction?.();
};
return true;
}
return false;
}
override clear() {
super.clear();
this.setMouseCursorStyle("default"); //reset cursor
}
}

View File

@ -19,6 +19,7 @@ export abstract class FormModalUiHandler extends ModalUiHandler {
protected inputs: InputText[]; protected inputs: InputText[];
protected errorMessage: Phaser.GameObjects.Text; protected errorMessage: Phaser.GameObjects.Text;
protected submitAction: Function | null; protected submitAction: Function | null;
protected cancelAction: (() => void) | null;
protected tween: Phaser.Tweens.Tween; protected tween: Phaser.Tweens.Tween;
protected formLabels: Phaser.GameObjects.Text[]; protected formLabels: Phaser.GameObjects.Text[];
@ -126,22 +127,37 @@ export abstract class FormModalUiHandler extends ModalUiHandler {
}); });
} }
show(args: any[]): boolean { override show(args: any[]): boolean {
if (super.show(args)) { if (super.show(args)) {
this.inputContainers.map(ic => ic.setVisible(true)); this.inputContainers.map(ic => ic.setVisible(true));
const config = args[0] as FormModalConfig; const config = args[0] as FormModalConfig;
this.submitAction = config.buttonActions.length ? config.buttonActions[0] : null; this.submitAction = config.buttonActions.length ? config.buttonActions[0] : null;
this.cancelAction = config.buttonActions[1] ?? null;
// #region: Override button pointerDown
// Override the pointerDown event for the buttonBgs to call the `submitAction` and `cancelAction`
// properties that we set above, allowing their behavior to change after this method terminates
// Some subclasses use this to add behavior to the submit and cancel action
if (this.buttonBgs.length) {
this.buttonBgs[0].off("pointerdown"); this.buttonBgs[0].off("pointerdown");
this.buttonBgs[0].on("pointerdown", () => { this.buttonBgs[0].on("pointerdown", () => {
if (this.submitAction && globalScene.tweens.getTweensOf(this.modalContainer).length === 0) { if (this.submitAction && globalScene.tweens.getTweensOf(this.modalContainer).length === 0) {
this.submitAction(); this.submitAction();
} }
}); });
const cancelBg = this.buttonBgs[1];
if (cancelBg) {
cancelBg.off("pointerdown");
cancelBg.on("pointerdown", () => {
// The seemingly redundant cancelAction check is intentionally left in as a defensive programming measure
if (this.cancelAction && globalScene.tweens.getTweensOf(this.modalContainer).length === 0) {
this.cancelAction();
} }
});
}
//#endregion: Override pointerDown events
this.modalContainer.y += 24; this.modalContainer.y += 24;
this.modalContainer.setAlpha(0); this.modalContainer.setAlpha(0);

View File

@ -311,6 +311,17 @@ export class MenuUiHandler extends MessageUiHandler {
}, },
keepOpen: true, keepOpen: true,
}, },
{
// Note: i18n key is under `menu`, not `menuUiHandler` to avoid duplication
label: i18next.t("menu:changePassword"),
handler: () => {
ui.setOverlayMode(UiMode.CHANGE_PASSWORD_FORM, {
buttonActions: [() => ui.revertMode(), () => ui.revertMode()],
});
return true;
},
keepOpen: true,
},
{ {
label: i18next.t("menuUiHandler:consentPreferences"), label: i18next.t("menuUiHandler:consentPreferences"),
handler: () => { handler: () => {

View File

@ -7,7 +7,7 @@ import { UiHandler } from "#ui/ui-handler";
import { addWindow, WindowVariant } from "#ui/ui-theme"; import { addWindow, WindowVariant } from "#ui/ui-theme";
export interface ModalConfig { export interface ModalConfig {
buttonActions: Function[]; buttonActions: ((...args: any[]) => any)[];
} }
export abstract class ModalUiHandler extends UiHandler { export abstract class ModalUiHandler extends UiHandler {

View File

@ -13,6 +13,7 @@ import { BallUiHandler } from "#ui/ball-ui-handler";
import { BattleMessageUiHandler } from "#ui/battle-message-ui-handler"; import { BattleMessageUiHandler } from "#ui/battle-message-ui-handler";
import type { BgmBar } from "#ui/bgm-bar"; import type { BgmBar } from "#ui/bgm-bar";
import { GameChallengesUiHandler } from "#ui/challenges-select-ui-handler"; import { GameChallengesUiHandler } from "#ui/challenges-select-ui-handler";
import { ChangePasswordFormUiHandler } from "#ui/change-password-form-ui-handler";
import { CommandUiHandler } from "#ui/command-ui-handler"; import { CommandUiHandler } from "#ui/command-ui-handler";
import { ConfirmUiHandler } from "#ui/confirm-ui-handler"; import { ConfirmUiHandler } from "#ui/confirm-ui-handler";
import { EggGachaUiHandler } from "#ui/egg-gacha-ui-handler"; import { EggGachaUiHandler } from "#ui/egg-gacha-ui-handler";
@ -102,6 +103,7 @@ const noTransitionModes = [
UiMode.ADMIN, UiMode.ADMIN,
UiMode.MYSTERY_ENCOUNTER, UiMode.MYSTERY_ENCOUNTER,
UiMode.RUN_INFO, UiMode.RUN_INFO,
UiMode.CHANGE_PASSWORD_FORM,
]; ];
export class UI extends Phaser.GameObjects.Container { export class UI extends Phaser.GameObjects.Container {
@ -172,6 +174,7 @@ export class UI extends Phaser.GameObjects.Container {
new AutoCompleteUiHandler(), new AutoCompleteUiHandler(),
new AdminUiHandler(), new AdminUiHandler(),
new MysteryEncounterUiHandler(), new MysteryEncounterUiHandler(),
new ChangePasswordFormUiHandler(),
]; ];
} }