Merge branch 'beta' into reviverseed
@ -170,7 +170,7 @@ input:-internal-autofill-selected {
|
|||||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleNature,
|
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleNature,
|
||||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT'], [data-ui-mode='POKEDEX_PAGE'], [data-ui-mode='RUN_INFO']) #apadCycleAbility,
|
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT'], [data-ui-mode='POKEDEX_PAGE'], [data-ui-mode='RUN_INFO']) #apadCycleAbility,
|
||||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT'], [data-ui-mode='POKEDEX_PAGE']) #apadCycleGender,
|
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT'], [data-ui-mode='POKEDEX_PAGE']) #apadCycleGender,
|
||||||
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT'], [data-ui-mode='POKEDEX']) #apadCycleVariant {
|
#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT'], [data-ui-mode='POKEDEX']) #apadCycleTera {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@
|
|||||||
<div id="apadCycleNature" class="apad-button apad-square apad-small" data-key="CYCLE_NATURE">
|
<div id="apadCycleNature" class="apad-button apad-square apad-small" data-key="CYCLE_NATURE">
|
||||||
<span class="apad-label">N</span>
|
<span class="apad-label">N</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="apadCycleVariant" class="apad-button apad-square apad-small" data-key="V">
|
<div id="apadCycleTera" class="apad-button apad-square apad-small" data-key="CYCLE_TERA">
|
||||||
<span class="apad-label">V</span>
|
<span class="apad-label">V</span>
|
||||||
</div>
|
</div>
|
||||||
<!-- buttons to display battle-specific information -->
|
<!-- buttons to display battle-specific information -->
|
||||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 3.4 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 2.9 KiB |
@ -180,9 +180,9 @@ const cfg_keyboard_qwerty = {
|
|||||||
[SettingKeyboard.Button_Cycle_Gender]: Button.CYCLE_GENDER,
|
[SettingKeyboard.Button_Cycle_Gender]: Button.CYCLE_GENDER,
|
||||||
[SettingKeyboard.Button_Cycle_Ability]: Button.CYCLE_ABILITY,
|
[SettingKeyboard.Button_Cycle_Ability]: Button.CYCLE_ABILITY,
|
||||||
[SettingKeyboard.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
[SettingKeyboard.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
[SettingKeyboard.Button_Cycle_Variant]: Button.V,
|
|
||||||
[SettingKeyboard.Button_Speed_Up]: Button.SPEED_UP,
|
[SettingKeyboard.Button_Speed_Up]: Button.SPEED_UP,
|
||||||
[SettingKeyboard.Button_Slow_Down]: Button.SLOW_DOWN,
|
[SettingKeyboard.Button_Slow_Down]: Button.SLOW_DOWN,
|
||||||
|
[SettingKeyboard.Button_Cycle_Tera]: Button.CYCLE_TERA,
|
||||||
[SettingKeyboard.Alt_Button_Up]: Button.UP,
|
[SettingKeyboard.Alt_Button_Up]: Button.UP,
|
||||||
[SettingKeyboard.Alt_Button_Down]: Button.DOWN,
|
[SettingKeyboard.Alt_Button_Down]: Button.DOWN,
|
||||||
[SettingKeyboard.Alt_Button_Left]: Button.LEFT,
|
[SettingKeyboard.Alt_Button_Left]: Button.LEFT,
|
||||||
@ -197,9 +197,9 @@ const cfg_keyboard_qwerty = {
|
|||||||
[SettingKeyboard.Alt_Button_Cycle_Gender]: Button.CYCLE_GENDER,
|
[SettingKeyboard.Alt_Button_Cycle_Gender]: Button.CYCLE_GENDER,
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Ability]: Button.CYCLE_ABILITY,
|
[SettingKeyboard.Alt_Button_Cycle_Ability]: Button.CYCLE_ABILITY,
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
[SettingKeyboard.Alt_Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Variant]: Button.V,
|
|
||||||
[SettingKeyboard.Alt_Button_Speed_Up]: Button.SPEED_UP,
|
[SettingKeyboard.Alt_Button_Speed_Up]: Button.SPEED_UP,
|
||||||
[SettingKeyboard.Alt_Button_Slow_Down]: Button.SLOW_DOWN,
|
[SettingKeyboard.Alt_Button_Slow_Down]: Button.SLOW_DOWN,
|
||||||
|
[SettingKeyboard.Alt_Button_Cycle_Tera]: Button.CYCLE_TERA,
|
||||||
},
|
},
|
||||||
default: {
|
default: {
|
||||||
KEY_ARROW_UP: SettingKeyboard.Button_Up,
|
KEY_ARROW_UP: SettingKeyboard.Button_Up,
|
||||||
@ -216,7 +216,7 @@ const cfg_keyboard_qwerty = {
|
|||||||
KEY_G: SettingKeyboard.Button_Cycle_Gender,
|
KEY_G: SettingKeyboard.Button_Cycle_Gender,
|
||||||
KEY_E: SettingKeyboard.Button_Cycle_Ability,
|
KEY_E: SettingKeyboard.Button_Cycle_Ability,
|
||||||
KEY_N: SettingKeyboard.Button_Cycle_Nature,
|
KEY_N: SettingKeyboard.Button_Cycle_Nature,
|
||||||
KEY_V: SettingKeyboard.Button_Cycle_Variant,
|
KEY_V: SettingKeyboard.Button_Cycle_Tera,
|
||||||
KEY_PLUS: -1,
|
KEY_PLUS: -1,
|
||||||
KEY_MINUS: -1,
|
KEY_MINUS: -1,
|
||||||
KEY_A: SettingKeyboard.Alt_Button_Left,
|
KEY_A: SettingKeyboard.Alt_Button_Left,
|
||||||
|
@ -53,7 +53,7 @@ const pad_dualshock = {
|
|||||||
[SettingGamepad.Button_Action]: Button.ACTION,
|
[SettingGamepad.Button_Action]: Button.ACTION,
|
||||||
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
||||||
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
[SettingGamepad.Button_Cycle_Variant]: Button.V,
|
[SettingGamepad.Button_Cycle_Tera]: Button.CYCLE_TERA,
|
||||||
[SettingGamepad.Button_Menu]: Button.MENU,
|
[SettingGamepad.Button_Menu]: Button.MENU,
|
||||||
[SettingGamepad.Button_Stats]: Button.STATS,
|
[SettingGamepad.Button_Stats]: Button.STATS,
|
||||||
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
||||||
@ -72,7 +72,7 @@ const pad_dualshock = {
|
|||||||
RC_S: SettingGamepad.Button_Action,
|
RC_S: SettingGamepad.Button_Action,
|
||||||
RC_E: SettingGamepad.Button_Cancel,
|
RC_E: SettingGamepad.Button_Cancel,
|
||||||
RC_W: SettingGamepad.Button_Cycle_Nature,
|
RC_W: SettingGamepad.Button_Cycle_Nature,
|
||||||
RC_N: SettingGamepad.Button_Cycle_Variant,
|
RC_N: SettingGamepad.Button_Cycle_Tera,
|
||||||
START: SettingGamepad.Button_Menu,
|
START: SettingGamepad.Button_Menu,
|
||||||
SELECT: SettingGamepad.Button_Stats,
|
SELECT: SettingGamepad.Button_Stats,
|
||||||
LB: SettingGamepad.Button_Cycle_Form,
|
LB: SettingGamepad.Button_Cycle_Form,
|
||||||
|
@ -51,7 +51,7 @@ const pad_generic = {
|
|||||||
[SettingGamepad.Button_Action]: Button.ACTION,
|
[SettingGamepad.Button_Action]: Button.ACTION,
|
||||||
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
||||||
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
[SettingGamepad.Button_Cycle_Variant]: Button.V,
|
[SettingGamepad.Button_Cycle_Tera]: Button.CYCLE_TERA,
|
||||||
[SettingGamepad.Button_Menu]: Button.MENU,
|
[SettingGamepad.Button_Menu]: Button.MENU,
|
||||||
[SettingGamepad.Button_Stats]: Button.STATS,
|
[SettingGamepad.Button_Stats]: Button.STATS,
|
||||||
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
||||||
@ -69,7 +69,7 @@ const pad_generic = {
|
|||||||
RC_S: SettingGamepad.Button_Action,
|
RC_S: SettingGamepad.Button_Action,
|
||||||
RC_E: SettingGamepad.Button_Cancel,
|
RC_E: SettingGamepad.Button_Cancel,
|
||||||
RC_W: SettingGamepad.Button_Cycle_Nature,
|
RC_W: SettingGamepad.Button_Cycle_Nature,
|
||||||
RC_N: SettingGamepad.Button_Cycle_Variant,
|
RC_N: SettingGamepad.Button_Cycle_Tera,
|
||||||
START: SettingGamepad.Button_Menu,
|
START: SettingGamepad.Button_Menu,
|
||||||
SELECT: SettingGamepad.Button_Stats,
|
SELECT: SettingGamepad.Button_Stats,
|
||||||
LB: SettingGamepad.Button_Cycle_Form,
|
LB: SettingGamepad.Button_Cycle_Form,
|
||||||
|
@ -52,7 +52,7 @@ const pad_procon = {
|
|||||||
[SettingGamepad.Button_Action]: Button.ACTION,
|
[SettingGamepad.Button_Action]: Button.ACTION,
|
||||||
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
||||||
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
[SettingGamepad.Button_Cycle_Variant]: Button.V,
|
[SettingGamepad.Button_Cycle_Tera]: Button.CYCLE_TERA,
|
||||||
[SettingGamepad.Button_Menu]: Button.MENU,
|
[SettingGamepad.Button_Menu]: Button.MENU,
|
||||||
[SettingGamepad.Button_Stats]: Button.STATS,
|
[SettingGamepad.Button_Stats]: Button.STATS,
|
||||||
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
||||||
@ -70,7 +70,7 @@ const pad_procon = {
|
|||||||
RC_S: SettingGamepad.Button_Action,
|
RC_S: SettingGamepad.Button_Action,
|
||||||
RC_E: SettingGamepad.Button_Cancel,
|
RC_E: SettingGamepad.Button_Cancel,
|
||||||
RC_W: SettingGamepad.Button_Cycle_Nature,
|
RC_W: SettingGamepad.Button_Cycle_Nature,
|
||||||
RC_N: SettingGamepad.Button_Cycle_Variant,
|
RC_N: SettingGamepad.Button_Cycle_Tera,
|
||||||
START: SettingGamepad.Button_Menu,
|
START: SettingGamepad.Button_Menu,
|
||||||
SELECT: SettingGamepad.Button_Stats,
|
SELECT: SettingGamepad.Button_Stats,
|
||||||
LB: SettingGamepad.Button_Cycle_Form,
|
LB: SettingGamepad.Button_Cycle_Form,
|
||||||
|
@ -43,7 +43,7 @@ const pad_unlicensedSNES = {
|
|||||||
[SettingGamepad.Button_Action]: Button.ACTION,
|
[SettingGamepad.Button_Action]: Button.ACTION,
|
||||||
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
||||||
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
[SettingGamepad.Button_Cycle_Variant]: Button.V,
|
[SettingGamepad.Button_Cycle_Tera]: Button.CYCLE_TERA,
|
||||||
[SettingGamepad.Button_Menu]: Button.MENU,
|
[SettingGamepad.Button_Menu]: Button.MENU,
|
||||||
[SettingGamepad.Button_Stats]: Button.STATS,
|
[SettingGamepad.Button_Stats]: Button.STATS,
|
||||||
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
||||||
@ -61,7 +61,7 @@ const pad_unlicensedSNES = {
|
|||||||
RC_S: SettingGamepad.Button_Action,
|
RC_S: SettingGamepad.Button_Action,
|
||||||
RC_E: SettingGamepad.Button_Cancel,
|
RC_E: SettingGamepad.Button_Cancel,
|
||||||
RC_W: SettingGamepad.Button_Cycle_Nature,
|
RC_W: SettingGamepad.Button_Cycle_Nature,
|
||||||
RC_N: SettingGamepad.Button_Cycle_Variant,
|
RC_N: SettingGamepad.Button_Cycle_Tera,
|
||||||
START: SettingGamepad.Button_Menu,
|
START: SettingGamepad.Button_Menu,
|
||||||
SELECT: SettingGamepad.Button_Stats,
|
SELECT: SettingGamepad.Button_Stats,
|
||||||
LB: SettingGamepad.Button_Cycle_Form,
|
LB: SettingGamepad.Button_Cycle_Form,
|
||||||
|
@ -51,7 +51,7 @@ const pad_xbox360 = {
|
|||||||
[SettingGamepad.Button_Action]: Button.ACTION,
|
[SettingGamepad.Button_Action]: Button.ACTION,
|
||||||
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
[SettingGamepad.Button_Cancel]: Button.CANCEL,
|
||||||
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
[SettingGamepad.Button_Cycle_Nature]: Button.CYCLE_NATURE,
|
||||||
[SettingGamepad.Button_Cycle_Variant]: Button.V,
|
[SettingGamepad.Button_Cycle_Tera]: Button.CYCLE_TERA,
|
||||||
[SettingGamepad.Button_Menu]: Button.MENU,
|
[SettingGamepad.Button_Menu]: Button.MENU,
|
||||||
[SettingGamepad.Button_Stats]: Button.STATS,
|
[SettingGamepad.Button_Stats]: Button.STATS,
|
||||||
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
[SettingGamepad.Button_Cycle_Form]: Button.CYCLE_FORM,
|
||||||
@ -69,7 +69,7 @@ const pad_xbox360 = {
|
|||||||
RC_S: SettingGamepad.Button_Action,
|
RC_S: SettingGamepad.Button_Action,
|
||||||
RC_E: SettingGamepad.Button_Cancel,
|
RC_E: SettingGamepad.Button_Cancel,
|
||||||
RC_W: SettingGamepad.Button_Cycle_Nature,
|
RC_W: SettingGamepad.Button_Cycle_Nature,
|
||||||
RC_N: SettingGamepad.Button_Cycle_Variant,
|
RC_N: SettingGamepad.Button_Cycle_Tera,
|
||||||
START: SettingGamepad.Button_Menu,
|
START: SettingGamepad.Button_Menu,
|
||||||
SELECT: SettingGamepad.Button_Stats,
|
SELECT: SettingGamepad.Button_Stats,
|
||||||
LB: SettingGamepad.Button_Cycle_Form,
|
LB: SettingGamepad.Button_Cycle_Form,
|
||||||
|
@ -1044,9 +1044,9 @@ export class PostDefendAbilitySwapAbAttr extends PostDefendAbAttr {
|
|||||||
if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)
|
if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)
|
||||||
&& !attacker.getAbility().hasAttr(UnswappableAbilityAbAttr) && !move.hitsSubstitute(attacker, pokemon)) {
|
&& !attacker.getAbility().hasAttr(UnswappableAbilityAbAttr) && !move.hitsSubstitute(attacker, pokemon)) {
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
const tempAbilityId = attacker.getAbility().id;
|
const tempAbility = attacker.getAbility();
|
||||||
attacker.summonData.ability = pokemon.getAbility().id;
|
attacker.setTempAbility(pokemon.getAbility());
|
||||||
pokemon.summonData.ability = tempAbilityId;
|
pokemon.setTempAbility(tempAbility);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1071,7 +1071,7 @@ export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr {
|
|||||||
if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.getAbility().hasAttr(UnsuppressableAbilityAbAttr)
|
if (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.getAbility().hasAttr(UnsuppressableAbilityAbAttr)
|
||||||
&& !attacker.getAbility().hasAttr(PostDefendAbilityGiveAbAttr) && !move.hitsSubstitute(attacker, pokemon)) {
|
&& !attacker.getAbility().hasAttr(PostDefendAbilityGiveAbAttr) && !move.hitsSubstitute(attacker, pokemon)) {
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
attacker.summonData.ability = this.ability;
|
attacker.setTempAbility(allAbilities[this.ability]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1908,8 +1908,8 @@ export class CopyFaintedAllyAbilityAbAttr extends PostKnockOutAbAttr {
|
|||||||
applyPostKnockOut(pokemon: Pokemon, passive: boolean, simulated: boolean, knockedOut: Pokemon, args: any[]): boolean | Promise<boolean> {
|
applyPostKnockOut(pokemon: Pokemon, passive: boolean, simulated: boolean, knockedOut: Pokemon, args: any[]): boolean | Promise<boolean> {
|
||||||
if (pokemon.isPlayer() === knockedOut.isPlayer() && !knockedOut.getAbility().hasAttr(UncopiableAbilityAbAttr)) {
|
if (pokemon.isPlayer() === knockedOut.isPlayer() && !knockedOut.getAbility().hasAttr(UncopiableAbilityAbAttr)) {
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
pokemon.summonData.ability = knockedOut.getAbility().id;
|
|
||||||
globalScene.queueMessage(i18next.t("abilityTriggers:copyFaintedAllyAbility", { pokemonNameWithAffix: getPokemonNameWithAffix(knockedOut), abilityName: allAbilities[knockedOut.getAbility().id].name }));
|
globalScene.queueMessage(i18next.t("abilityTriggers:copyFaintedAllyAbility", { pokemonNameWithAffix: getPokemonNameWithAffix(knockedOut), abilityName: allAbilities[knockedOut.getAbility().id].name }));
|
||||||
|
pokemon.setTempAbility(knockedOut.getAbility());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1993,6 +1993,21 @@ export class PostIntimidateStatStageChangeAbAttr extends AbAttr {
|
|||||||
* @see {@linkcode applyPostSummon()}
|
* @see {@linkcode applyPostSummon()}
|
||||||
*/
|
*/
|
||||||
export class PostSummonAbAttr extends AbAttr {
|
export class PostSummonAbAttr extends AbAttr {
|
||||||
|
/** Should the ability activate when gained in battle? This will almost always be true */
|
||||||
|
private activateOnGain: boolean;
|
||||||
|
|
||||||
|
constructor(showAbility: boolean = true, activateOnGain: boolean = true) {
|
||||||
|
super(showAbility);
|
||||||
|
this.activateOnGain = activateOnGain;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns Whether the ability should activate when gained in battle
|
||||||
|
*/
|
||||||
|
shouldActivateOnGain(): boolean {
|
||||||
|
return this.activateOnGain;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Applies ability post summon (after switching in)
|
* Applies ability post summon (after switching in)
|
||||||
* @param pokemon {@linkcode Pokemon} with this ability
|
* @param pokemon {@linkcode Pokemon} with this ability
|
||||||
@ -2330,7 +2345,7 @@ export class PostSummonCopyAbilityAbAttr extends PostSummonAbAttr {
|
|||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
this.target = target!;
|
this.target = target!;
|
||||||
this.targetAbilityName = allAbilities[target!.getAbility().id].name;
|
this.targetAbilityName = allAbilities[target!.getAbility().id].name;
|
||||||
pokemon.summonData.ability = target!.getAbility().id;
|
pokemon.setTempAbility(target!.getAbility());
|
||||||
setAbilityRevealed(target!);
|
setAbilityRevealed(target!);
|
||||||
pokemon.updateInfo();
|
pokemon.updateInfo();
|
||||||
}
|
}
|
||||||
@ -2427,7 +2442,7 @@ export class PostSummonCopyAllyStatsAbAttr extends PostSummonAbAttr {
|
|||||||
*/
|
*/
|
||||||
export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(true);
|
super(true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
async applyPostSummon(pokemon: Pokemon, _passive: boolean, simulated: boolean, _args: any[]): Promise<boolean> {
|
async applyPostSummon(pokemon: Pokemon, _passive: boolean, simulated: boolean, _args: any[]): Promise<boolean> {
|
||||||
@ -2462,7 +2477,6 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pokemon.summonData.speciesForm = target.getSpeciesForm();
|
pokemon.summonData.speciesForm = target.getSpeciesForm();
|
||||||
pokemon.summonData.ability = target.getAbility().id;
|
|
||||||
pokemon.summonData.gender = target.getGender();
|
pokemon.summonData.gender = target.getGender();
|
||||||
|
|
||||||
// Copy all stats (except HP)
|
// Copy all stats (except HP)
|
||||||
@ -2492,6 +2506,8 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
|
|||||||
promises.push(pokemon.loadAssets(false).then(() => {
|
promises.push(pokemon.loadAssets(false).then(() => {
|
||||||
pokemon.playAnim();
|
pokemon.playAnim();
|
||||||
pokemon.updateInfo();
|
pokemon.updateInfo();
|
||||||
|
// If the new ability activates immediately, it needs to happen after all the transform animations
|
||||||
|
pokemon.setTempAbility(target.getAbility());
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
@ -4852,13 +4868,34 @@ async function applyAbAttrsInternal<TAttr extends AbAttr>(
|
|||||||
showAbilityInstant: boolean = false,
|
showAbilityInstant: boolean = false,
|
||||||
simulated: boolean = false,
|
simulated: boolean = false,
|
||||||
messages: string[] = [],
|
messages: string[] = [],
|
||||||
|
gainedMidTurn: boolean = false
|
||||||
) {
|
) {
|
||||||
for (const passive of [ false, true ]) {
|
for (const passive of [ false, true ]) {
|
||||||
if (!pokemon?.canApplyAbility(passive) || (passive && pokemon.getPassiveAbility().id === pokemon.getAbility().id)) {
|
if (!pokemon?.canApplyAbility(passive) || (passive && (pokemon.getPassiveAbility().id === pokemon.getAbility().id))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applySingleAbAttrs(pokemon, passive, attrType, applyFunc, args, gainedMidTurn, simulated, showAbilityInstant, messages);
|
||||||
|
globalScene.clearPhaseQueueSplice();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function applySingleAbAttrs<TAttr extends AbAttr>(
|
||||||
|
pokemon: Pokemon,
|
||||||
|
passive: boolean,
|
||||||
|
attrType: Constructor<TAttr>,
|
||||||
|
applyFunc: AbAttrApplyFunc<TAttr>,
|
||||||
|
args: any[],
|
||||||
|
gainedMidTurn: boolean = false,
|
||||||
|
simulated: boolean = false,
|
||||||
|
showAbilityInstant: boolean = false,
|
||||||
|
messages: string[] = []
|
||||||
|
) {
|
||||||
const ability = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
|
const ability = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
|
||||||
|
if (gainedMidTurn && ability.getAttrs(attrType).some(attr => attr instanceof PostSummonAbAttr && !attr.shouldActivateOnGain())) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (const attr of ability.getAttrs(attrType)) {
|
for (const attr of ability.getAttrs(attrType)) {
|
||||||
const condition = attr.getCondition();
|
const condition = attr.getCondition();
|
||||||
if (condition && !condition(pokemon)) {
|
if (condition && !condition(pokemon)) {
|
||||||
@ -4895,8 +4932,6 @@ async function applyAbAttrsInternal<TAttr extends AbAttr>(
|
|||||||
messages.push(message!);
|
messages.push(message!);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
globalScene.clearPhaseQueueSplice();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class ForceSwitchOutHelper {
|
class ForceSwitchOutHelper {
|
||||||
@ -5285,6 +5320,21 @@ export function applyPostItemLostAbAttrs(attrType: Constructor<PostItemLostAbAtt
|
|||||||
return applyAbAttrsInternal<PostItemLostAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostItemLost(pokemon, simulated, args), args);
|
return applyAbAttrsInternal<PostItemLostAbAttr>(attrType, pokemon, (attr, passive) => attr.applyPostItemLost(pokemon, simulated, args), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies abilities when they become active mid-turn (ability switch)
|
||||||
|
*
|
||||||
|
* Ignores passives as they don't change and shouldn't be reapplied when main abilities change
|
||||||
|
*/
|
||||||
|
export function applyOnGainAbAttrs(pokemon: Pokemon, passive: boolean = false, simulated: boolean = false, ...args: any[]): void {
|
||||||
|
applySingleAbAttrs<PostSummonAbAttr>(pokemon, passive, PostSummonAbAttr, (attr, passive) => attr.applyPostSummon(pokemon, passive, simulated, args), args, true, simulated);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears primal weather during the turn if {@linkcode pokemon}'s ability corresponds to one
|
||||||
|
*/
|
||||||
|
export function applyOnLoseClearWeatherAbAttrs(pokemon: Pokemon, passive: boolean = false, simulated: boolean = false, ...args: any[]): void {
|
||||||
|
applySingleAbAttrs<PreLeaveFieldClearWeatherAbAttr>(pokemon, passive, PreLeaveFieldClearWeatherAbAttr, (attr, passive) => attr.applyPreLeaveField(pokemon, passive, simulated, [ ...args, true ]), args, true, simulated);
|
||||||
|
}
|
||||||
function queueShowAbility(pokemon: Pokemon, passive: boolean): void {
|
function queueShowAbility(pokemon: Pokemon, passive: boolean): void {
|
||||||
globalScene.unshiftPhase(new ShowAbilityPhase(pokemon.id, passive));
|
globalScene.unshiftPhase(new ShowAbilityPhase(pokemon.id, passive));
|
||||||
globalScene.clearPhaseQueueSplice();
|
globalScene.clearPhaseQueueSplice();
|
||||||
|
@ -708,6 +708,7 @@ export class FreshStartChallenge extends Challenge {
|
|||||||
pokemon.variant = 0; // Not shiny
|
pokemon.variant = 0; // Not shiny
|
||||||
pokemon.formIndex = 0; // Froakie should be base form
|
pokemon.formIndex = 0; // Froakie should be base form
|
||||||
pokemon.ivs = [ 15, 15, 15, 15, 15, 15 ]; // Default IVs of 15 for all stats (Updated to 15 from 10 in 1.2.0)
|
pokemon.ivs = [ 15, 15, 15, 15, 15, 15 ]; // Default IVs of 15 for all stats (Updated to 15 from 10 in 1.2.0)
|
||||||
|
pokemon.teraType = pokemon.species.type1; // Always primary tera type
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7521,11 +7521,11 @@ export class AbilityChangeAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
const moveTarget = this.selfTarget ? user : target;
|
const moveTarget = this.selfTarget ? user : target;
|
||||||
|
|
||||||
moveTarget.summonData.ability = this.ability;
|
|
||||||
globalScene.triggerPokemonFormChange(moveTarget, SpeciesFormChangeRevertWeatherFormTrigger);
|
|
||||||
|
|
||||||
globalScene.queueMessage(i18next.t("moveTriggers:acquiredAbility", { pokemonName: getPokemonNameWithAffix((this.selfTarget ? user : target)), abilityName: allAbilities[this.ability].name }));
|
globalScene.queueMessage(i18next.t("moveTriggers:acquiredAbility", { pokemonName: getPokemonNameWithAffix((this.selfTarget ? user : target)), abilityName: allAbilities[this.ability].name }));
|
||||||
|
|
||||||
|
moveTarget.setTempAbility(allAbilities[this.ability]);
|
||||||
|
globalScene.triggerPokemonFormChange(moveTarget, SpeciesFormChangeRevertWeatherFormTrigger);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7548,13 +7548,13 @@ export class AbilityCopyAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.summonData.ability = target.getAbility().id;
|
|
||||||
|
|
||||||
globalScene.queueMessage(i18next.t("moveTriggers:copiedTargetAbility", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), abilityName: allAbilities[target.getAbility().id].name }));
|
globalScene.queueMessage(i18next.t("moveTriggers:copiedTargetAbility", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), abilityName: allAbilities[target.getAbility().id].name }));
|
||||||
|
|
||||||
|
user.setTempAbility(target.getAbility());
|
||||||
|
|
||||||
if (this.copyToPartner && globalScene.currentBattle?.double && user.getAlly().hp) {
|
if (this.copyToPartner && globalScene.currentBattle?.double && user.getAlly().hp) {
|
||||||
user.getAlly().summonData.ability = target.getAbility().id;
|
|
||||||
globalScene.queueMessage(i18next.t("moveTriggers:copiedTargetAbility", { pokemonName: getPokemonNameWithAffix(user.getAlly()), targetName: getPokemonNameWithAffix(target), abilityName: allAbilities[target.getAbility().id].name }));
|
globalScene.queueMessage(i18next.t("moveTriggers:copiedTargetAbility", { pokemonName: getPokemonNameWithAffix(user.getAlly()), targetName: getPokemonNameWithAffix(target), abilityName: allAbilities[target.getAbility().id].name }));
|
||||||
|
user.getAlly().setTempAbility(target.getAbility());
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -7585,10 +7585,10 @@ export class AbilityGiveAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
target.summonData.ability = user.getAbility().id;
|
|
||||||
|
|
||||||
globalScene.queueMessage(i18next.t("moveTriggers:acquiredAbility", { pokemonName: getPokemonNameWithAffix(target), abilityName: allAbilities[user.getAbility().id].name }));
|
globalScene.queueMessage(i18next.t("moveTriggers:acquiredAbility", { pokemonName: getPokemonNameWithAffix(target), abilityName: allAbilities[user.getAbility().id].name }));
|
||||||
|
|
||||||
|
target.setTempAbility(user.getAbility());
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -7603,15 +7603,14 @@ export class SwitchAbilitiesAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tempAbilityId = user.getAbility().id;
|
const tempAbility = user.getAbility();
|
||||||
user.summonData.ability = target.getAbility().id;
|
|
||||||
target.summonData.ability = tempAbilityId;
|
|
||||||
|
|
||||||
globalScene.queueMessage(i18next.t("moveTriggers:swappedAbilitiesWithTarget", { pokemonName: getPokemonNameWithAffix(user) }));
|
globalScene.queueMessage(i18next.t("moveTriggers:swappedAbilitiesWithTarget", { pokemonName: getPokemonNameWithAffix(user) }));
|
||||||
|
|
||||||
|
user.setTempAbility(target.getAbility());
|
||||||
|
target.setTempAbility(tempAbility);
|
||||||
// Swaps Forecast/Flower Gift from Castform/Cherrim
|
// Swaps Forecast/Flower Gift from Castform/Cherrim
|
||||||
globalScene.arena.triggerWeatherBasedFormChangesToNormal();
|
globalScene.arena.triggerWeatherBasedFormChangesToNormal();
|
||||||
// Swaps Forecast/Flower Gift to Castform/Cherrim (edge case)
|
|
||||||
globalScene.arena.triggerWeatherBasedFormChanges();
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -7690,7 +7689,6 @@ export class TransformAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
const promises: Promise<void>[] = [];
|
const promises: Promise<void>[] = [];
|
||||||
user.summonData.speciesForm = target.getSpeciesForm();
|
user.summonData.speciesForm = target.getSpeciesForm();
|
||||||
user.summonData.ability = target.getAbility().id;
|
|
||||||
user.summonData.gender = target.getGender();
|
user.summonData.gender = target.getGender();
|
||||||
|
|
||||||
// Power Trick's effect will not preserved after using Transform
|
// Power Trick's effect will not preserved after using Transform
|
||||||
@ -7723,6 +7721,8 @@ export class TransformAttr extends MoveEffectAttr {
|
|||||||
promises.push(user.loadAssets(false).then(() => {
|
promises.push(user.loadAssets(false).then(() => {
|
||||||
user.playAnim();
|
user.playAnim();
|
||||||
user.updateInfo();
|
user.updateInfo();
|
||||||
|
// If the new ability activates immediately, it needs to happen after all the transform animations
|
||||||
|
user.setTempAbility(target.getAbility());
|
||||||
}));
|
}));
|
||||||
|
|
||||||
await Promise.all(promises);
|
await Promise.all(promises);
|
||||||
@ -8035,6 +8035,56 @@ export class AfterYouAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Move effect to force the target to move last, ignoring priority.
|
||||||
|
* If applied to multiple targets, they move in speed order after all other moves.
|
||||||
|
* @extends MoveEffectAttr
|
||||||
|
*/
|
||||||
|
export class ForceLastAttr extends MoveEffectAttr {
|
||||||
|
/**
|
||||||
|
* Forces the target of this move to move last.
|
||||||
|
*
|
||||||
|
* @param user {@linkcode Pokemon} that is using the move.
|
||||||
|
* @param target {@linkcode Pokemon} that will be forced to move last.
|
||||||
|
* @param move {@linkcode Move} {@linkcode Moves.QUASH}
|
||||||
|
* @param _args N/A
|
||||||
|
* @returns true
|
||||||
|
*/
|
||||||
|
override apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean {
|
||||||
|
globalScene.queueMessage(i18next.t("moveTriggers:forceLast", { targetPokemonName: getPokemonNameWithAffix(target) }));
|
||||||
|
|
||||||
|
const targetMovePhase = globalScene.findPhase<MovePhase>((phase) => phase.pokemon === target);
|
||||||
|
if (targetMovePhase && !targetMovePhase.isForcedLast() && globalScene.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) {
|
||||||
|
// Finding the phase to insert the move in front of -
|
||||||
|
// Either the end of the turn or in front of another, slower move which has also been forced last
|
||||||
|
const prependPhase = globalScene.findPhase((phase) =>
|
||||||
|
[ MovePhase, MoveEndPhase ].every(cls => !(phase instanceof cls))
|
||||||
|
|| (phase instanceof MovePhase) && phaseForcedSlower(phase, target, !!globalScene.arena.getTag(ArenaTagType.TRICK_ROOM))
|
||||||
|
);
|
||||||
|
if (prependPhase) {
|
||||||
|
globalScene.phaseQueue.splice(
|
||||||
|
globalScene.phaseQueue.indexOf(prependPhase),
|
||||||
|
0,
|
||||||
|
new MovePhase(target, [ ...targetMovePhase.targets ], targetMovePhase.move, false, false, false, true)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns whether a {@linkcode MovePhase} has been forced last and the corresponding pokemon is slower than {@linkcode target} */
|
||||||
|
const phaseForcedSlower = (phase: MovePhase, target: Pokemon, trickRoom: boolean): boolean => {
|
||||||
|
let slower: boolean;
|
||||||
|
// quashed pokemon still have speed ties
|
||||||
|
if (phase.pokemon.getEffectiveStat(Stat.SPD) === target.getEffectiveStat(Stat.SPD)) {
|
||||||
|
slower = !!target.randSeedInt(2);
|
||||||
|
} else {
|
||||||
|
slower = !trickRoom ? phase.pokemon.getEffectiveStat(Stat.SPD) < target.getEffectiveStat(Stat.SPD) : phase.pokemon.getEffectiveStat(Stat.SPD) > target.getEffectiveStat(Stat.SPD);
|
||||||
|
}
|
||||||
|
return phase.isForcedLast() && slower;
|
||||||
|
};
|
||||||
|
|
||||||
const failOnGravityCondition: MoveConditionFunc = (user, target, move) => !globalScene.arena.getTag(ArenaTagType.GRAVITY);
|
const failOnGravityCondition: MoveConditionFunc = (user, target, move) => !globalScene.arena.getTag(ArenaTagType.GRAVITY);
|
||||||
|
|
||||||
const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.isBossImmune();
|
const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.isBossImmune();
|
||||||
@ -9914,7 +9964,8 @@ export function initMoves() {
|
|||||||
.attr(RemoveHeldItemAttr, true),
|
.attr(RemoveHeldItemAttr, true),
|
||||||
new StatusMove(Moves.QUASH, Type.DARK, 100, 15, -1, 0, 5)
|
new StatusMove(Moves.QUASH, Type.DARK, 100, 15, -1, 0, 5)
|
||||||
.condition(failIfSingleBattle)
|
.condition(failIfSingleBattle)
|
||||||
.unimplemented(),
|
.condition((user, target, move) => !target.turnData.acted)
|
||||||
|
.attr(ForceLastAttr),
|
||||||
new AttackMove(Moves.ACROBATICS, Type.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, -1, 0, 5)
|
new AttackMove(Moves.ACROBATICS, Type.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, -1, 0, 5)
|
||||||
.attr(MovePowerMultiplierAttr, (user, target, move) => Math.max(1, 2 - 0.2 * user.getHeldItems().filter(i => i.isTransferable).reduce((v, m) => v + m.stackCount, 0))),
|
.attr(MovePowerMultiplierAttr, (user, target, move) => Math.max(1, 2 - 0.2 * user.getHeldItems().filter(i => i.isTransferable).reduce((v, m) => v + m.stackCount, 0))),
|
||||||
new StatusMove(Moves.REFLECT_TYPE, Type.NORMAL, -1, 15, -1, 0, 5)
|
new StatusMove(Moves.REFLECT_TYPE, Type.NORMAL, -1, 15, -1, 0, 5)
|
||||||
|
@ -13,7 +13,7 @@ export enum Button {
|
|||||||
CYCLE_GENDER,
|
CYCLE_GENDER,
|
||||||
CYCLE_ABILITY,
|
CYCLE_ABILITY,
|
||||||
CYCLE_NATURE,
|
CYCLE_NATURE,
|
||||||
V,
|
CYCLE_TERA,
|
||||||
SPEED_UP,
|
SPEED_UP,
|
||||||
SLOW_DOWN
|
SLOW_DOWN,
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoo
|
|||||||
import { WeatherType } from "#enums/weather-type";
|
import { WeatherType } from "#enums/weather-type";
|
||||||
import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag";
|
import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag";
|
||||||
import type { Ability, AbAttr } from "#app/data/ability";
|
import type { Ability, AbAttr } from "#app/data/ability";
|
||||||
import { StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, CommanderAbAttr, applyPostItemLostAbAttrs, PostItemLostAbAttr, PreLeaveFieldAbAttr, applyPreLeaveFieldAbAttrs } from "#app/data/ability";
|
import { StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, CommanderAbAttr, applyPostItemLostAbAttrs, PostItemLostAbAttr, applyOnGainAbAttrs, PreLeaveFieldAbAttr, applyPreLeaveFieldAbAttrs, applyOnLoseClearWeatherAbAttrs } from "#app/data/ability";
|
||||||
import type PokemonData from "#app/system/pokemon-data";
|
import type PokemonData from "#app/system/pokemon-data";
|
||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
import { Mode } from "#app/ui/ui";
|
import { Mode } from "#app/ui/ui";
|
||||||
@ -1481,6 +1481,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return abilityAttrs;
|
return abilityAttrs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the {@linkcode Pokemon}'s ability and activates it if it normally activates on summon
|
||||||
|
*
|
||||||
|
* Also clears primal weather if it is from the ability being changed
|
||||||
|
* @param ability New Ability
|
||||||
|
*/
|
||||||
|
public setTempAbility(ability: Ability, passive: boolean = false): void {
|
||||||
|
applyOnLoseClearWeatherAbAttrs(this, passive);
|
||||||
|
if (passive) {
|
||||||
|
this.summonData.passiveAbility = ability.id;
|
||||||
|
} else {
|
||||||
|
this.summonData.ability = ability.id;
|
||||||
|
}
|
||||||
|
applyOnGainAbAttrs(this, passive);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if a pokemon has a passive either from:
|
* Checks if a pokemon has a passive either from:
|
||||||
* - bought with starter candy
|
* - bought with starter candy
|
||||||
|
@ -1822,7 +1822,7 @@ const modifierPool: ModifierPool = {
|
|||||||
|
|
||||||
if (!isHoldingOrb) {
|
if (!isHoldingOrb) {
|
||||||
const moveset = p.getMoveset(true).filter(m => !isNullOrUndefined(m)).map(m => m.moveId);
|
const moveset = p.getMoveset(true).filter(m => !isNullOrUndefined(m)).map(m => m.moveId);
|
||||||
const canSetStatus = p.canSetStatus(StatusEffect.TOXIC, true, true, null, true);
|
const canSetStatus = p.canSetStatus(StatusEffect.BURN, true, true, null, true);
|
||||||
|
|
||||||
// Moves that take advantage of obtaining the actual status effect
|
// Moves that take advantage of obtaining the actual status effect
|
||||||
const hasStatusMoves = [ Moves.FACADE, Moves.PSYCHO_SHIFT ]
|
const hasStatusMoves = [ Moves.FACADE, Moves.PSYCHO_SHIFT ]
|
||||||
|
@ -56,6 +56,7 @@ export class MovePhase extends BattlePhase {
|
|||||||
protected _targets: BattlerIndex[];
|
protected _targets: BattlerIndex[];
|
||||||
protected followUp: boolean;
|
protected followUp: boolean;
|
||||||
protected ignorePp: boolean;
|
protected ignorePp: boolean;
|
||||||
|
protected forcedLast: boolean;
|
||||||
protected failed: boolean = false;
|
protected failed: boolean = false;
|
||||||
protected cancelled: boolean = false;
|
protected cancelled: boolean = false;
|
||||||
protected reflected: boolean = false;
|
protected reflected: boolean = false;
|
||||||
@ -90,7 +91,8 @@ export class MovePhase extends BattlePhase {
|
|||||||
* @param reflected Indicates that the move was reflected by Magic Coat or Magic Bounce.
|
* @param reflected Indicates that the move was reflected by Magic Coat or Magic Bounce.
|
||||||
* Reflected moves cannot be reflected again and will not trigger Dancer.
|
* Reflected moves cannot be reflected again and will not trigger Dancer.
|
||||||
*/
|
*/
|
||||||
constructor(pokemon: Pokemon, targets: BattlerIndex[], move: PokemonMove, followUp: boolean = false, ignorePp: boolean = false, reflected: boolean = false) {
|
|
||||||
|
constructor(pokemon: Pokemon, targets: BattlerIndex[], move: PokemonMove, followUp: boolean = false, ignorePp: boolean = false, reflected: boolean = false, forcedLast: boolean = false) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
this.pokemon = pokemon;
|
this.pokemon = pokemon;
|
||||||
@ -99,6 +101,7 @@ export class MovePhase extends BattlePhase {
|
|||||||
this.followUp = followUp;
|
this.followUp = followUp;
|
||||||
this.ignorePp = ignorePp;
|
this.ignorePp = ignorePp;
|
||||||
this.reflected = reflected;
|
this.reflected = reflected;
|
||||||
|
this.forcedLast = forcedLast;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -120,6 +123,15 @@ export class MovePhase extends BattlePhase {
|
|||||||
this.cancelled = true;
|
this.cancelled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shows whether the current move has been forced to the end of the turn
|
||||||
|
* Needed for speed order, see {@linkcode Moves.QUASH}
|
||||||
|
* */
|
||||||
|
public isForcedLast(): boolean {
|
||||||
|
return this.forcedLast;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public start(): void {
|
public start(): void {
|
||||||
super.start();
|
super.start();
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import type { Starter } from "#app/ui/starter-select-ui-handler";
|
|||||||
import { Mode } from "#app/ui/ui";
|
import { Mode } from "#app/ui/ui";
|
||||||
import type { Species } from "#enums/species";
|
import type { Species } from "#enums/species";
|
||||||
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
|
||||||
|
import * as Utils from "../utils";
|
||||||
|
|
||||||
export class SelectStarterPhase extends Phase {
|
export class SelectStarterPhase extends Phase {
|
||||||
|
|
||||||
@ -79,6 +80,12 @@ export class SelectStarterPhase extends Phase {
|
|||||||
starterPokemon.nickname = starter.nickname;
|
starterPokemon.nickname = starter.nickname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Utils.isNullOrUndefined(starter.teraType)) {
|
||||||
|
starterPokemon.teraType = starter.teraType;
|
||||||
|
} else {
|
||||||
|
starterPokemon.teraType = starterPokemon.species.type1;
|
||||||
|
}
|
||||||
|
|
||||||
if (globalScene.gameMode.isSplicedOnly || Overrides.STARTER_FUSION_OVERRIDE) {
|
if (globalScene.gameMode.isSplicedOnly || Overrides.STARTER_FUSION_OVERRIDE) {
|
||||||
starterPokemon.generateFusionSpecies(true);
|
starterPokemon.generateFusionSpecies(true);
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,7 @@ import { MysteryEncounterSaveData } from "#app/data/mystery-encounters/mystery-e
|
|||||||
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
import type { MysteryEncounterType } from "#enums/mystery-encounter-type";
|
||||||
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
|
import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
|
||||||
import { ArenaTrapTag } from "#app/data/arena-tag";
|
import { ArenaTrapTag } from "#app/data/arena-tag";
|
||||||
|
import type { Type } from "#enums/type";
|
||||||
|
|
||||||
export const defaultStarterSpecies: Species[] = [
|
export const defaultStarterSpecies: Species[] = [
|
||||||
Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE,
|
Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE,
|
||||||
@ -229,6 +230,7 @@ export interface StarterAttributes {
|
|||||||
shiny?: boolean;
|
shiny?: boolean;
|
||||||
favorite?: boolean;
|
favorite?: boolean;
|
||||||
nickname?: string;
|
nickname?: string;
|
||||||
|
tera?: Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface StarterPreferences {
|
export interface StarterPreferences {
|
||||||
|
@ -21,7 +21,7 @@ export enum SettingGamepad {
|
|||||||
Button_Cycle_Gender = "BUTTON_CYCLE_GENDER",
|
Button_Cycle_Gender = "BUTTON_CYCLE_GENDER",
|
||||||
Button_Cycle_Ability = "BUTTON_CYCLE_ABILITY",
|
Button_Cycle_Ability = "BUTTON_CYCLE_ABILITY",
|
||||||
Button_Cycle_Nature = "BUTTON_CYCLE_NATURE",
|
Button_Cycle_Nature = "BUTTON_CYCLE_NATURE",
|
||||||
Button_Cycle_Variant = "BUTTON_CYCLE_VARIANT",
|
Button_Cycle_Tera = "BUTTON_CYCLE_TERA",
|
||||||
Button_Speed_Up = "BUTTON_SPEED_UP",
|
Button_Speed_Up = "BUTTON_SPEED_UP",
|
||||||
Button_Slow_Down = "BUTTON_SLOW_DOWN",
|
Button_Slow_Down = "BUTTON_SLOW_DOWN",
|
||||||
Button_Submit = "BUTTON_SUBMIT",
|
Button_Submit = "BUTTON_SUBMIT",
|
||||||
@ -45,7 +45,7 @@ export const settingGamepadOptions = {
|
|||||||
[SettingGamepad.Button_Cycle_Gender]: [ `KEY ${Button.CYCLE_GENDER.toString()}`, pressAction ],
|
[SettingGamepad.Button_Cycle_Gender]: [ `KEY ${Button.CYCLE_GENDER.toString()}`, pressAction ],
|
||||||
[SettingGamepad.Button_Cycle_Ability]: [ `KEY ${Button.CYCLE_ABILITY.toString()}`, pressAction ],
|
[SettingGamepad.Button_Cycle_Ability]: [ `KEY ${Button.CYCLE_ABILITY.toString()}`, pressAction ],
|
||||||
[SettingGamepad.Button_Cycle_Nature]: [ `KEY ${Button.CYCLE_NATURE.toString()}`, pressAction ],
|
[SettingGamepad.Button_Cycle_Nature]: [ `KEY ${Button.CYCLE_NATURE.toString()}`, pressAction ],
|
||||||
[SettingGamepad.Button_Cycle_Variant]: [ `KEY ${Button.V.toString()}`, pressAction ],
|
[SettingGamepad.Button_Cycle_Tera]: [ `KEY ${Button.CYCLE_TERA.toString()}`, pressAction ],
|
||||||
[SettingGamepad.Button_Speed_Up]: [ `KEY ${Button.SPEED_UP.toString()}`, pressAction ],
|
[SettingGamepad.Button_Speed_Up]: [ `KEY ${Button.SPEED_UP.toString()}`, pressAction ],
|
||||||
[SettingGamepad.Button_Slow_Down]: [ `KEY ${Button.SLOW_DOWN.toString()}`, pressAction ],
|
[SettingGamepad.Button_Slow_Down]: [ `KEY ${Button.SLOW_DOWN.toString()}`, pressAction ],
|
||||||
[SettingGamepad.Button_Submit]: [ `KEY ${Button.SUBMIT.toString()}`, pressAction ],
|
[SettingGamepad.Button_Submit]: [ `KEY ${Button.SUBMIT.toString()}`, pressAction ],
|
||||||
@ -67,7 +67,7 @@ export const settingGamepadDefaults = {
|
|||||||
[SettingGamepad.Button_Cycle_Gender]: 0,
|
[SettingGamepad.Button_Cycle_Gender]: 0,
|
||||||
[SettingGamepad.Button_Cycle_Ability]: 0,
|
[SettingGamepad.Button_Cycle_Ability]: 0,
|
||||||
[SettingGamepad.Button_Cycle_Nature]: 0,
|
[SettingGamepad.Button_Cycle_Nature]: 0,
|
||||||
[SettingGamepad.Button_Cycle_Variant]: 0,
|
[SettingGamepad.Button_Cycle_Tera]: 0,
|
||||||
[SettingGamepad.Button_Speed_Up]: 0,
|
[SettingGamepad.Button_Speed_Up]: 0,
|
||||||
[SettingGamepad.Button_Slow_Down]: 0,
|
[SettingGamepad.Button_Slow_Down]: 0,
|
||||||
[SettingGamepad.Button_Submit]: 0,
|
[SettingGamepad.Button_Submit]: 0,
|
||||||
@ -96,7 +96,7 @@ export function setSettingGamepad(setting: SettingGamepad, value: number): boole
|
|||||||
case SettingGamepad.Button_Cycle_Gender:
|
case SettingGamepad.Button_Cycle_Gender:
|
||||||
case SettingGamepad.Button_Cycle_Ability:
|
case SettingGamepad.Button_Cycle_Ability:
|
||||||
case SettingGamepad.Button_Cycle_Nature:
|
case SettingGamepad.Button_Cycle_Nature:
|
||||||
case SettingGamepad.Button_Cycle_Variant:
|
case SettingGamepad.Button_Cycle_Tera:
|
||||||
case SettingGamepad.Button_Speed_Up:
|
case SettingGamepad.Button_Speed_Up:
|
||||||
case SettingGamepad.Button_Slow_Down:
|
case SettingGamepad.Button_Slow_Down:
|
||||||
case SettingGamepad.Button_Submit:
|
case SettingGamepad.Button_Submit:
|
||||||
|
@ -32,8 +32,8 @@ export enum SettingKeyboard {
|
|||||||
Alt_Button_Cycle_Ability = "ALT_BUTTON_CYCLE_ABILITY",
|
Alt_Button_Cycle_Ability = "ALT_BUTTON_CYCLE_ABILITY",
|
||||||
Button_Cycle_Nature = "BUTTON_CYCLE_NATURE",
|
Button_Cycle_Nature = "BUTTON_CYCLE_NATURE",
|
||||||
Alt_Button_Cycle_Nature = "ALT_BUTTON_CYCLE_NATURE",
|
Alt_Button_Cycle_Nature = "ALT_BUTTON_CYCLE_NATURE",
|
||||||
Button_Cycle_Variant = "BUTTON_CYCLE_VARIANT",
|
Button_Cycle_Tera = "BUTTON_CYCLE_TERA",
|
||||||
Alt_Button_Cycle_Variant = "ALT_BUTTON_CYCLE_VARIANT",
|
Alt_Button_Cycle_Tera = "ALT_BUTTON_CYCLE_TERA",
|
||||||
Button_Speed_Up = "BUTTON_SPEED_UP",
|
Button_Speed_Up = "BUTTON_SPEED_UP",
|
||||||
Alt_Button_Speed_Up = "ALT_BUTTON_SPEED_UP",
|
Alt_Button_Speed_Up = "ALT_BUTTON_SPEED_UP",
|
||||||
Button_Slow_Down = "BUTTON_SLOW_DOWN",
|
Button_Slow_Down = "BUTTON_SLOW_DOWN",
|
||||||
@ -73,8 +73,8 @@ export const settingKeyboardOptions = {
|
|||||||
[SettingKeyboard.Alt_Button_Cycle_Ability]: [ `KEY ${Button.CYCLE_ABILITY.toString()}`, pressAction ],
|
[SettingKeyboard.Alt_Button_Cycle_Ability]: [ `KEY ${Button.CYCLE_ABILITY.toString()}`, pressAction ],
|
||||||
[SettingKeyboard.Button_Cycle_Nature]: [ `KEY ${Button.CYCLE_NATURE.toString()}`, pressAction ],
|
[SettingKeyboard.Button_Cycle_Nature]: [ `KEY ${Button.CYCLE_NATURE.toString()}`, pressAction ],
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Nature]: [ `KEY ${Button.CYCLE_NATURE.toString()}`, pressAction ],
|
[SettingKeyboard.Alt_Button_Cycle_Nature]: [ `KEY ${Button.CYCLE_NATURE.toString()}`, pressAction ],
|
||||||
[SettingKeyboard.Button_Cycle_Variant]: [ `KEY ${Button.V.toString()}`, pressAction ],
|
[SettingKeyboard.Button_Cycle_Tera]: [ `KEY ${Button.CYCLE_TERA.toString()}`, pressAction ],
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Variant]: [ `KEY ${Button.V.toString()}`, pressAction ],
|
[SettingKeyboard.Alt_Button_Cycle_Tera]: [ `KEY ${Button.CYCLE_TERA.toString()}`, pressAction ],
|
||||||
[SettingKeyboard.Button_Speed_Up]: [ `KEY ${Button.SPEED_UP.toString()}`, pressAction ],
|
[SettingKeyboard.Button_Speed_Up]: [ `KEY ${Button.SPEED_UP.toString()}`, pressAction ],
|
||||||
[SettingKeyboard.Alt_Button_Speed_Up]: [ `KEY ${Button.SPEED_UP.toString()}`, pressAction ],
|
[SettingKeyboard.Alt_Button_Speed_Up]: [ `KEY ${Button.SPEED_UP.toString()}`, pressAction ],
|
||||||
[SettingKeyboard.Button_Slow_Down]: [ `KEY ${Button.SLOW_DOWN.toString()}`, pressAction ],
|
[SettingKeyboard.Button_Slow_Down]: [ `KEY ${Button.SLOW_DOWN.toString()}`, pressAction ],
|
||||||
@ -112,8 +112,8 @@ export const settingKeyboardDefaults = {
|
|||||||
[SettingKeyboard.Alt_Button_Cycle_Ability]: 0,
|
[SettingKeyboard.Alt_Button_Cycle_Ability]: 0,
|
||||||
[SettingKeyboard.Button_Cycle_Nature]: 0,
|
[SettingKeyboard.Button_Cycle_Nature]: 0,
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Nature]: 0,
|
[SettingKeyboard.Alt_Button_Cycle_Nature]: 0,
|
||||||
[SettingKeyboard.Button_Cycle_Variant]: 0,
|
[SettingKeyboard.Button_Cycle_Tera]: 0,
|
||||||
[SettingKeyboard.Alt_Button_Cycle_Variant]: 0,
|
[SettingKeyboard.Alt_Button_Cycle_Tera]: 0,
|
||||||
[SettingKeyboard.Button_Speed_Up]: 0,
|
[SettingKeyboard.Button_Speed_Up]: 0,
|
||||||
[SettingKeyboard.Alt_Button_Speed_Up]: 0,
|
[SettingKeyboard.Alt_Button_Speed_Up]: 0,
|
||||||
[SettingKeyboard.Button_Slow_Down]: 0,
|
[SettingKeyboard.Button_Slow_Down]: 0,
|
||||||
@ -148,7 +148,7 @@ export function setSettingKeyboard(setting: SettingKeyboard, value: number): boo
|
|||||||
case SettingKeyboard.Button_Cycle_Gender:
|
case SettingKeyboard.Button_Cycle_Gender:
|
||||||
case SettingKeyboard.Button_Cycle_Ability:
|
case SettingKeyboard.Button_Cycle_Ability:
|
||||||
case SettingKeyboard.Button_Cycle_Nature:
|
case SettingKeyboard.Button_Cycle_Nature:
|
||||||
case SettingKeyboard.Button_Cycle_Variant:
|
case SettingKeyboard.Button_Cycle_Tera:
|
||||||
case SettingKeyboard.Button_Speed_Up:
|
case SettingKeyboard.Button_Speed_Up:
|
||||||
case SettingKeyboard.Button_Slow_Down:
|
case SettingKeyboard.Button_Slow_Down:
|
||||||
case SettingKeyboard.Alt_Button_Up:
|
case SettingKeyboard.Alt_Button_Up:
|
||||||
@ -164,7 +164,7 @@ export function setSettingKeyboard(setting: SettingKeyboard, value: number): boo
|
|||||||
case SettingKeyboard.Alt_Button_Cycle_Gender:
|
case SettingKeyboard.Alt_Button_Cycle_Gender:
|
||||||
case SettingKeyboard.Alt_Button_Cycle_Ability:
|
case SettingKeyboard.Alt_Button_Cycle_Ability:
|
||||||
case SettingKeyboard.Alt_Button_Cycle_Nature:
|
case SettingKeyboard.Alt_Button_Cycle_Nature:
|
||||||
case SettingKeyboard.Alt_Button_Cycle_Variant:
|
case SettingKeyboard.Alt_Button_Cycle_Tera:
|
||||||
case SettingKeyboard.Alt_Button_Speed_Up:
|
case SettingKeyboard.Alt_Button_Speed_Up:
|
||||||
case SettingKeyboard.Alt_Button_Slow_Down:
|
case SettingKeyboard.Alt_Button_Slow_Down:
|
||||||
case SettingKeyboard.Alt_Button_Submit:
|
case SettingKeyboard.Alt_Button_Submit:
|
||||||
|
@ -116,4 +116,15 @@ describe("Abilities - Imposter", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should activate its ability if it copies one that activates on summon", async () => {
|
||||||
|
game.override.enemyAbility(Abilities.INTIMIDATE);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([ Species.DITTO ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.TACKLE);
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
52
src/test/abilities/mummy.test.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Abilities - Mummy", () => {
|
||||||
|
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
|
||||||
|
.moveset([ Moves.SPLASH ])
|
||||||
|
.ability(Abilities.MUMMY)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.TACKLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the enemy's ability to mummy when hit by a contact move", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(Abilities.MUMMY);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not change the enemy's ability hit by a non-contact move", async () => {
|
||||||
|
game.override.enemyMoveset(Moves.EARTHQUAKE);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(Abilities.BALL_FETCH);
|
||||||
|
});
|
||||||
|
});
|
53
src/test/abilities/trace.test.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { Stat } from "#app/enums/stat";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Abilities - Trace", () => {
|
||||||
|
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
|
||||||
|
.moveset([ Moves.SPLASH ])
|
||||||
|
.ability(Abilities.TRACE)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should copy the opponent's ability", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getPlayerPokemon()?.getAbility().id).toBe(Abilities.BALL_FETCH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should activate a copied post-summon ability", async () => {
|
||||||
|
game.override.enemyAbility(Abilities.INTIMIDATE);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||||
|
});
|
||||||
|
});
|
65
src/test/abilities/wandering_spirit.test.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import { Stat } from "#app/enums/stat";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Abilities - Wandering Spirit", () => {
|
||||||
|
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
|
||||||
|
.moveset([ Moves.SPLASH ])
|
||||||
|
.ability(Abilities.WANDERING_SPIRIT)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.TACKLE);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should exchange abilities when hit with a contact move", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getPlayerPokemon()?.getAbility().id).toBe(Abilities.BALL_FETCH);
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(Abilities.WANDERING_SPIRIT);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not exchange abilities when hit with a non-contact move", async () => {
|
||||||
|
game.override.enemyMoveset(Moves.EARTHQUAKE);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getPlayerPokemon()?.getAbility().id).toBe(Abilities.WANDERING_SPIRIT);
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(Abilities.BALL_FETCH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should activate post-summon abilities", async () => {
|
||||||
|
game.override.enemyAbility(Abilities.INTIMIDATE);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||||
|
});
|
||||||
|
});
|
67
src/test/battle/ability_swap.test.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import { allAbilities } from "#app/data/ability";
|
||||||
|
import { Stat } from "#app/enums/stat";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Test Ability Swapping", () => {
|
||||||
|
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
|
||||||
|
.moveset([ Moves.SPLASH ])
|
||||||
|
.ability(Abilities.BALL_FETCH)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should activate post-summon abilities", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
game.scene.getPlayerPokemon()?.setTempAbility(allAbilities[Abilities.INTIMIDATE]);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should remove primal weather when the setter's ability is removed", async () => {
|
||||||
|
game.override.ability(Abilities.DESOLATE_LAND);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
game.scene.getPlayerPokemon()?.setTempAbility(allAbilities[Abilities.BALL_FETCH]);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.arena.weather?.weatherType).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not activate passive abilities", async () => {
|
||||||
|
game.override.passiveAbility(Abilities.INTREPID_SWORD);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
game.scene.getPlayerPokemon()?.setTempAbility(allAbilities[Abilities.BALL_FETCH]);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.ATK)).toBe(1); // would be 2 if passive activated again
|
||||||
|
});
|
||||||
|
});
|
70
src/test/moves/doodle.test.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { Stat } from "#app/enums/stat";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Doodle", () => {
|
||||||
|
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
|
||||||
|
.moveset([ Moves.SPLASH, Moves.DOODLE ])
|
||||||
|
.ability(Abilities.ADAPTABILITY)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should copy the opponent's ability in singles", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.DOODLE);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getPlayerPokemon()?.getAbility().id).toBe(Abilities.BALL_FETCH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should copy the opponent's ability to itself and its ally in doubles", async () => {
|
||||||
|
game.override.battleType("double");
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.DOODLE, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getPlayerField()[0].getAbility().id).toBe(Abilities.BALL_FETCH);
|
||||||
|
expect(game.scene.getPlayerField()[1].getAbility().id).toBe(Abilities.BALL_FETCH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should activate post-summon abilities", async () => {
|
||||||
|
game.override.battleType("double")
|
||||||
|
.enemyAbility(Abilities.INTIMIDATE);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.DOODLE, 0, BattlerIndex.ENEMY);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
// Enemies should have been intimidated twice
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-2);
|
||||||
|
});
|
||||||
|
});
|
53
src/test/moves/entrainment.test.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { Stat } from "#app/enums/stat";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Entrainment", () => {
|
||||||
|
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
|
||||||
|
.moveset([ Moves.SPLASH, Moves.ENTRAINMENT ])
|
||||||
|
.ability(Abilities.ADAPTABILITY)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("gives its ability to the target", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.ENTRAINMENT);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(Abilities.ADAPTABILITY);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should activate post-summon abilities", async () => {
|
||||||
|
game.override.ability(Abilities.INTIMIDATE);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.ENTRAINMENT);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||||
|
});
|
||||||
|
});
|
99
src/test/moves/quash.test.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
import { Species } from "#enums/species";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Abilities } from "#app/enums/abilities";
|
||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { WeatherType } from "#enums/weather-type";
|
||||||
|
import { MoveResult } from "#app/field/pokemon";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { describe, beforeAll, afterEach, beforeEach, it, expect } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Quash", () => {
|
||||||
|
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
|
||||||
|
.battleType("double")
|
||||||
|
.enemyLevel(1)
|
||||||
|
.enemySpecies(Species.SLOWPOKE)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset([ Moves.RAIN_DANCE, Moves.SPLASH ])
|
||||||
|
.ability(Abilities.BALL_FETCH)
|
||||||
|
.moveset([ Moves.QUASH, Moves.SUNNY_DAY, Moves.RAIN_DANCE, Moves.SPLASH ]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("makes the target move last in a turn, ignoring priority", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.ACCELGOR, Species.RATTATA ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.QUASH, 0, BattlerIndex.PLAYER_2);
|
||||||
|
game.move.select(Moves.SUNNY_DAY, 1);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
await game.forceEnemyMove(Moves.RAIN_DANCE);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase", false);
|
||||||
|
// will be sunny if player_2 moved last because of quash, rainy otherwise
|
||||||
|
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SUNNY);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("fails if the target has already moved", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.ACCELGOR, Species.RATTATA ]);
|
||||||
|
game.move.select(Moves.SPLASH, 0);
|
||||||
|
game.move.select(Moves.QUASH, 1, BattlerIndex.PLAYER);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getPlayerField()[1].getLastXMoves(1)[0].result).toBe(MoveResult.FAIL);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("makes multiple quashed targets move in speed order at the end of the turn", async () => {
|
||||||
|
game.override.enemySpecies(Species.NINJASK)
|
||||||
|
.enemyLevel(100);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([ Species.ACCELGOR, Species.RATTATA ]);
|
||||||
|
|
||||||
|
// both users are quashed - rattata is slower so sun should be up at end of turn
|
||||||
|
game.move.select(Moves.RAIN_DANCE, 0);
|
||||||
|
game.move.select(Moves.SUNNY_DAY, 1);
|
||||||
|
|
||||||
|
await game.forceEnemyMove(Moves.QUASH, BattlerIndex.PLAYER);
|
||||||
|
await game.forceEnemyMove(Moves.QUASH, BattlerIndex.PLAYER_2);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase", false);
|
||||||
|
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SUNNY);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("respects trick room", async () => {
|
||||||
|
game.override.enemyMoveset([ Moves.RAIN_DANCE, Moves.SPLASH, Moves.TRICK_ROOM ]);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([ Species.ACCELGOR, Species.RATTATA ]);
|
||||||
|
game.move.select(Moves.SPLASH, 0);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
|
||||||
|
await game.forceEnemyMove(Moves.TRICK_ROOM);
|
||||||
|
await game.forceEnemyMove(Moves.SPLASH);
|
||||||
|
await game.phaseInterceptor.to("TurnInitPhase");
|
||||||
|
// both users are quashed - accelgor should move last w/ TR so rain should be up at end of turn
|
||||||
|
game.move.select(Moves.RAIN_DANCE, 0);
|
||||||
|
game.move.select(Moves.SUNNY_DAY, 1);
|
||||||
|
|
||||||
|
await game.forceEnemyMove(Moves.QUASH, BattlerIndex.PLAYER);
|
||||||
|
await game.forceEnemyMove(Moves.QUASH, BattlerIndex.PLAYER_2);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase", false);
|
||||||
|
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.RAIN);
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
53
src/test/moves/role_play.test.ts
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import { Stat } from "#app/enums/stat";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Role Play", () => {
|
||||||
|
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
|
||||||
|
.moveset([ Moves.SPLASH, Moves.ROLE_PLAY ])
|
||||||
|
.ability(Abilities.ADAPTABILITY)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should set the user's ability to the target's ability", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.ROLE_PLAY);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getPlayerPokemon()?.getAbility().id).toBe(Abilities.BALL_FETCH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should activate post-summon abilities", async () => {
|
||||||
|
game.override.enemyAbility(Abilities.INTIMIDATE);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.ROLE_PLAY);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||||
|
});
|
||||||
|
});
|
42
src/test/moves/simple_beam.test.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Simple Beam", () => {
|
||||||
|
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
|
||||||
|
.moveset([ Moves.SPLASH, Moves.SIMPLE_BEAM ])
|
||||||
|
.ability(Abilities.BALL_FETCH)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("sets the target's ability to simple", async () => {
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SIMPLE_BEAM);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(Abilities.SIMPLE);
|
||||||
|
});
|
||||||
|
});
|
56
src/test/moves/skill_swap.test.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import { Stat } from "#app/enums/stat";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
describe("Moves - Skill Swap", () => {
|
||||||
|
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
|
||||||
|
.moveset([ Moves.SPLASH, Moves.SKILL_SWAP ])
|
||||||
|
.ability(Abilities.BALL_FETCH)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should swap the two abilities", async () => {
|
||||||
|
game.override.ability(Abilities.ADAPTABILITY);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SKILL_SWAP);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getPlayerPokemon()?.getAbility().id).toBe(Abilities.BALL_FETCH);
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getAbility().id).toBe(Abilities.ADAPTABILITY);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should activate post-summon abilities", async () => {
|
||||||
|
game.override.ability(Abilities.INTIMIDATE);
|
||||||
|
await game.classicMode.startBattle([ Species.FEEBAS ]);
|
||||||
|
|
||||||
|
game.move.select(Moves.SKILL_SWAP);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
// player atk should be -1 after opponent gains intimidate and it activates
|
||||||
|
expect(game.scene.getPlayerPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||||
|
});
|
||||||
|
});
|
@ -116,4 +116,16 @@ describe("Moves - Transform", () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should activate its ability if it copies one that activates on summon", async () => {
|
||||||
|
game.override.enemyAbility(Abilities.INTIMIDATE)
|
||||||
|
.ability(Abilities.BALL_FETCH);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([ Species.DITTO ]);
|
||||||
|
game.move.select(Moves.TRANSFORM);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -406,9 +406,9 @@ describe("Test Rebinding", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("check to delete all the binds of an action", () => {
|
it("check to delete all the binds of an action", () => {
|
||||||
inGame.whenWePressOnKeyboard("V").weShouldTriggerTheButton("Button_Cycle_Variant");
|
inGame.whenWePressOnKeyboard("V").weShouldTriggerTheButton("Button_Cycle_Tera");
|
||||||
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Cycle_Variant").thereShouldBeNoIcon().weWantThisBindInstead("K").confirm();
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Cycle_Tera").thereShouldBeNoIcon().weWantThisBindInstead("K").confirm();
|
||||||
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Cycle_Variant").iconDisplayedIs("KEY_K").whenWeDelete().thereShouldBeNoIconAnymore();
|
inTheSettingMenu.whenCursorIsOnSetting("Alt_Button_Cycle_Tera").iconDisplayedIs("KEY_K").whenWeDelete().thereShouldBeNoIconAnymore();
|
||||||
inTheSettingMenu.whenCursorIsOnSetting("Button_Cycle_Variant").iconDisplayedIs("KEY_V").whenWeDelete().thereShouldBeNoIconAnymore();
|
inTheSettingMenu.whenCursorIsOnSetting("Button_Cycle_Tera").iconDisplayedIs("KEY_V").whenWeDelete().thereShouldBeNoIconAnymore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -35,7 +35,7 @@
|
|||||||
<div id="apadCycleShiny" class="apad-button apad-square apad-small" data-key="CYCLE_SHINY">
|
<div id="apadCycleShiny" class="apad-button apad-square apad-small" data-key="CYCLE_SHINY">
|
||||||
<span class="apad-label">R</span>
|
<span class="apad-label">R</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="apadCycleVariant" class="apad-button apad-square apad-small" data-key="V">
|
<div id="apadCycleTera" class="apad-button apad-square apad-small" data-key="CYCLE_TERA">
|
||||||
<span class="apad-label">V</span>
|
<span class="apad-label">V</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="apadStats" class="apad-button apad-rectangle apad-small" data-key="STATS">
|
<div id="apadStats" class="apad-button apad-rectangle apad-small" data-key="STATS">
|
||||||
@ -59,7 +59,7 @@
|
|||||||
<div id="apadCycleNature" class="apad-button apad-square apad-small" data-key="CYCLE_NATURE">
|
<div id="apadCycleNature" class="apad-button apad-square apad-small" data-key="CYCLE_NATURE">
|
||||||
<span class="apad-label">N</span>
|
<span class="apad-label">N</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="apadInfo" class="apad-button apad-rectangle apad-small" data-key="V">
|
<div id="apadInfo" class="apad-button apad-rectangle apad-small" data-key="CYCLE_TERA">
|
||||||
<span class="apad-label">V</span>
|
<span class="apad-label">V</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -86,7 +86,7 @@ export class UiInputs {
|
|||||||
[Button.CYCLE_GENDER]: () => this.buttonCycleOption(Button.CYCLE_GENDER),
|
[Button.CYCLE_GENDER]: () => this.buttonCycleOption(Button.CYCLE_GENDER),
|
||||||
[Button.CYCLE_ABILITY]: () => this.buttonCycleOption(Button.CYCLE_ABILITY),
|
[Button.CYCLE_ABILITY]: () => this.buttonCycleOption(Button.CYCLE_ABILITY),
|
||||||
[Button.CYCLE_NATURE]: () => this.buttonCycleOption(Button.CYCLE_NATURE),
|
[Button.CYCLE_NATURE]: () => this.buttonCycleOption(Button.CYCLE_NATURE),
|
||||||
[Button.V]: () => this.buttonCycleOption(Button.V),
|
[Button.CYCLE_TERA]: () => this.buttonCycleOption(Button.CYCLE_TERA),
|
||||||
[Button.SPEED_UP]: () => this.buttonSpeedChange(),
|
[Button.SPEED_UP]: () => this.buttonSpeedChange(),
|
||||||
[Button.SLOW_DOWN]: () => this.buttonSpeedChange(false),
|
[Button.SLOW_DOWN]: () => this.buttonSpeedChange(false),
|
||||||
};
|
};
|
||||||
@ -109,7 +109,7 @@ export class UiInputs {
|
|||||||
[Button.CYCLE_GENDER]: () => undefined,
|
[Button.CYCLE_GENDER]: () => undefined,
|
||||||
[Button.CYCLE_ABILITY]: () => undefined,
|
[Button.CYCLE_ABILITY]: () => undefined,
|
||||||
[Button.CYCLE_NATURE]: () => undefined,
|
[Button.CYCLE_NATURE]: () => undefined,
|
||||||
[Button.V]: () => this.buttonInfo(false),
|
[Button.CYCLE_TERA]: () => undefined,
|
||||||
[Button.SPEED_UP]: () => undefined,
|
[Button.SPEED_UP]: () => undefined,
|
||||||
[Button.SLOW_DOWN]: () => undefined,
|
[Button.SLOW_DOWN]: () => undefined,
|
||||||
};
|
};
|
||||||
@ -197,7 +197,7 @@ export class UiInputs {
|
|||||||
const uiHandler = globalScene.ui?.getHandler();
|
const uiHandler = globalScene.ui?.getHandler();
|
||||||
if (whitelist.some(handler => uiHandler instanceof handler)) {
|
if (whitelist.some(handler => uiHandler instanceof handler)) {
|
||||||
globalScene.ui.processInput(button);
|
globalScene.ui.processInput(button);
|
||||||
} else if (button === Button.V) {
|
} else if (button === Button.CYCLE_TERA) {
|
||||||
this.buttonInfo(true);
|
this.buttonInfo(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { globalScene } from "#app/global-scene";
|
import { globalScene } from "#app/global-scene";
|
||||||
import type Pokemon from "../field/pokemon";
|
import type Pokemon from "../field/pokemon";
|
||||||
import { TextStyle, addTextObject } from "./text";
|
import { TextStyle, addTextObject } from "./text";
|
||||||
|
import i18next from "i18next";
|
||||||
|
|
||||||
export default class PartyExpBar extends Phaser.GameObjects.Container {
|
export default class PartyExpBar extends Phaser.GameObjects.Container {
|
||||||
private bg: Phaser.GameObjects.NineSlice;
|
private bg: Phaser.GameObjects.NineSlice;
|
||||||
@ -43,9 +44,9 @@ export default class PartyExpBar extends Phaser.GameObjects.Container {
|
|||||||
// if we want to only display the level in the small frame
|
// if we want to only display the level in the small frame
|
||||||
if (showOnlyLevelUp) {
|
if (showOnlyLevelUp) {
|
||||||
if (newLevel > 200) { // if the level is greater than 200, we only display Lv. UP
|
if (newLevel > 200) { // if the level is greater than 200, we only display Lv. UP
|
||||||
this.expText.setText("Lv. UP");
|
this.expText.setText(i18next.t("battleScene:levelUp"));
|
||||||
} else { // otherwise we display Lv. Up and the new level
|
} else { // otherwise we display Lv. Up and the new level
|
||||||
this.expText.setText(`Lv. UP: ${newLevel.toString()}`);
|
this.expText.setText(i18next.t("battleScene:levelUpWithLevel", { level: newLevel }));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// if we want to display the exp
|
// if we want to display the exp
|
||||||
|
@ -919,7 +919,7 @@ export default class PokedexUiHandler extends MessageUiHandler {
|
|||||||
} else {
|
} else {
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
} else if (button === Button.V) {
|
} else if (button === Button.CYCLE_TERA) {
|
||||||
if (!this.filterTextMode && !this.showingTray) {
|
if (!this.filterTextMode && !this.showingTray) {
|
||||||
this.cursorObj.setVisible(false);
|
this.cursorObj.setVisible(false);
|
||||||
this.setSpecies(null);
|
this.setSpecies(null);
|
||||||
@ -1170,9 +1170,6 @@ export default class PokedexUiHandler extends MessageUiHandler {
|
|||||||
case SettingKeyboard.Button_Cycle_Shiny:
|
case SettingKeyboard.Button_Cycle_Shiny:
|
||||||
iconPath = "R.png";
|
iconPath = "R.png";
|
||||||
break;
|
break;
|
||||||
case SettingKeyboard.Button_Cycle_Variant:
|
|
||||||
iconPath = "V.png";
|
|
||||||
break;
|
|
||||||
case SettingKeyboard.Button_Cycle_Form:
|
case SettingKeyboard.Button_Cycle_Form:
|
||||||
iconPath = "F.png";
|
iconPath = "F.png";
|
||||||
break;
|
break;
|
||||||
|
@ -56,6 +56,8 @@ import { getPassiveCandyCount, getValueReductionCandyCounts, getSameSpeciesEggCa
|
|||||||
import { BooleanHolder, fixedInt, getLocalizedSpriteKey, isNullOrUndefined, NumberHolder, padInt, randIntRange, rgbHexToRgba, toReadableString } from "#app/utils";
|
import { BooleanHolder, fixedInt, getLocalizedSpriteKey, isNullOrUndefined, NumberHolder, padInt, randIntRange, rgbHexToRgba, toReadableString } from "#app/utils";
|
||||||
import type { Nature } from "#enums/nature";
|
import type { Nature } from "#enums/nature";
|
||||||
import { PLAYER_PARTY_MAX_SIZE } from "#app/constants";
|
import { PLAYER_PARTY_MAX_SIZE } from "#app/constants";
|
||||||
|
import { achvs } from "#app/system/achv";
|
||||||
|
import * as Utils from "../utils";
|
||||||
|
|
||||||
export type StarterSelectCallback = (starters: Starter[]) => void;
|
export type StarterSelectCallback = (starters: Starter[]) => void;
|
||||||
|
|
||||||
@ -68,6 +70,7 @@ export interface Starter {
|
|||||||
moveset?: StarterMoveset;
|
moveset?: StarterMoveset;
|
||||||
pokerus: boolean;
|
pokerus: boolean;
|
||||||
nickname?: string;
|
nickname?: string;
|
||||||
|
teraType?: Type;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LanguageSetting {
|
interface LanguageSetting {
|
||||||
@ -212,6 +215,7 @@ interface SpeciesDetails {
|
|||||||
abilityIndex?: number,
|
abilityIndex?: number,
|
||||||
natureIndex?: number,
|
natureIndex?: number,
|
||||||
forSeen?: boolean, // default = false
|
forSeen?: boolean, // default = false
|
||||||
|
teraType?: Type,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class StarterSelectUiHandler extends MessageUiHandler {
|
export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||||
@ -262,6 +266,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
private pokemonShinyIcon: Phaser.GameObjects.Sprite;
|
private pokemonShinyIcon: Phaser.GameObjects.Sprite;
|
||||||
private pokemonPassiveDisabledIcon: Phaser.GameObjects.Sprite;
|
private pokemonPassiveDisabledIcon: Phaser.GameObjects.Sprite;
|
||||||
private pokemonPassiveLockedIcon: Phaser.GameObjects.Sprite;
|
private pokemonPassiveLockedIcon: Phaser.GameObjects.Sprite;
|
||||||
|
private teraIcon: Phaser.GameObjects.Sprite;
|
||||||
|
|
||||||
private activeTooltip: "ABILITY" | "PASSIVE" | "CANDY" | undefined;
|
private activeTooltip: "ABILITY" | "PASSIVE" | "CANDY" | undefined;
|
||||||
private instructionsContainer: Phaser.GameObjects.Container;
|
private instructionsContainer: Phaser.GameObjects.Container;
|
||||||
@ -271,12 +276,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
private abilityIconElement: Phaser.GameObjects.Sprite;
|
private abilityIconElement: Phaser.GameObjects.Sprite;
|
||||||
private genderIconElement: Phaser.GameObjects.Sprite;
|
private genderIconElement: Phaser.GameObjects.Sprite;
|
||||||
private natureIconElement: Phaser.GameObjects.Sprite;
|
private natureIconElement: Phaser.GameObjects.Sprite;
|
||||||
|
private teraIconElement: Phaser.GameObjects.Sprite;
|
||||||
private goFilterIconElement: Phaser.GameObjects.Sprite;
|
private goFilterIconElement: Phaser.GameObjects.Sprite;
|
||||||
private shinyLabel: Phaser.GameObjects.Text;
|
private shinyLabel: Phaser.GameObjects.Text;
|
||||||
private formLabel: Phaser.GameObjects.Text;
|
private formLabel: Phaser.GameObjects.Text;
|
||||||
private genderLabel: Phaser.GameObjects.Text;
|
private genderLabel: Phaser.GameObjects.Text;
|
||||||
private abilityLabel: Phaser.GameObjects.Text;
|
private abilityLabel: Phaser.GameObjects.Text;
|
||||||
private natureLabel: Phaser.GameObjects.Text;
|
private natureLabel: Phaser.GameObjects.Text;
|
||||||
|
private teraLabel: Phaser.GameObjects.Text;
|
||||||
private goFilterLabel: Phaser.GameObjects.Text;
|
private goFilterLabel: Phaser.GameObjects.Text;
|
||||||
|
|
||||||
private starterSelectMessageBox: Phaser.GameObjects.NineSlice;
|
private starterSelectMessageBox: Phaser.GameObjects.NineSlice;
|
||||||
@ -292,6 +299,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
private dexAttrCursor: bigint = 0n;
|
private dexAttrCursor: bigint = 0n;
|
||||||
private abilityCursor: number = -1;
|
private abilityCursor: number = -1;
|
||||||
private natureCursor: number = -1;
|
private natureCursor: number = -1;
|
||||||
|
private teraCursor: Type = Type.UNKNOWN;
|
||||||
private filterBarCursor: number = 0;
|
private filterBarCursor: number = 0;
|
||||||
private starterMoveset: StarterMoveset | null;
|
private starterMoveset: StarterMoveset | null;
|
||||||
private scrollCursor: number;
|
private scrollCursor: number;
|
||||||
@ -304,6 +312,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
private starterAttr: bigint[] = [];
|
private starterAttr: bigint[] = [];
|
||||||
private starterAbilityIndexes: number[] = [];
|
private starterAbilityIndexes: number[] = [];
|
||||||
private starterNatures: Nature[] = [];
|
private starterNatures: Nature[] = [];
|
||||||
|
private starterTeras: Type[] = [];
|
||||||
private starterMovesets: StarterMoveset[] = [];
|
private starterMovesets: StarterMoveset[] = [];
|
||||||
private speciesStarterDexEntry: DexEntry | null;
|
private speciesStarterDexEntry: DexEntry | null;
|
||||||
private speciesStarterMoves: Moves[];
|
private speciesStarterMoves: Moves[];
|
||||||
@ -312,6 +321,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
private canCycleGender: boolean;
|
private canCycleGender: boolean;
|
||||||
private canCycleAbility: boolean;
|
private canCycleAbility: boolean;
|
||||||
private canCycleNature: boolean;
|
private canCycleNature: boolean;
|
||||||
|
private canCycleTera: boolean;
|
||||||
|
|
||||||
private assetLoadCancelled: BooleanHolder | null;
|
private assetLoadCancelled: BooleanHolder | null;
|
||||||
public cursorObj: Phaser.GameObjects.Image;
|
public cursorObj: Phaser.GameObjects.Image;
|
||||||
@ -823,6 +833,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
this.starterSelectContainer.add(this.pokemonEggMovesContainer);
|
this.starterSelectContainer.add(this.pokemonEggMovesContainer);
|
||||||
|
|
||||||
|
this.teraIcon = globalScene.add.sprite(85, 63, "button_tera");
|
||||||
|
this.teraIcon.setName("terrastallize-icon");
|
||||||
|
this.teraIcon.setFrame("fire");
|
||||||
|
this.starterSelectContainer.add(this.teraIcon);
|
||||||
|
|
||||||
// The font size should be set per language
|
// The font size should be set per language
|
||||||
const instructionTextSize = textSettings.instructionTextSize;
|
const instructionTextSize = textSettings.instructionTextSize;
|
||||||
|
|
||||||
@ -867,6 +882,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.natureLabel = addTextObject(this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY, i18next.t("starterSelectUiHandler:cycleNature"), TextStyle.PARTY, { fontSize: instructionTextSize });
|
this.natureLabel = addTextObject(this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY, i18next.t("starterSelectUiHandler:cycleNature"), TextStyle.PARTY, { fontSize: instructionTextSize });
|
||||||
this.natureLabel.setName("text-nature-label");
|
this.natureLabel.setName("text-nature-label");
|
||||||
|
|
||||||
|
this.teraIconElement = new Phaser.GameObjects.Sprite(globalScene, this.instructionRowX, this.instructionRowY, "keyboard", "V.png");
|
||||||
|
this.teraIconElement.setName("sprite-tera-icon-element");
|
||||||
|
this.teraIconElement.setScale(0.675);
|
||||||
|
this.teraIconElement.setOrigin(0.0, 0.0);
|
||||||
|
this.teraLabel = addTextObject(this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY, i18next.t("starterSelectUiHandler:cycleTera"), TextStyle.PARTY, { fontSize: instructionTextSize });
|
||||||
|
this.teraLabel.setName("text-tera-label");
|
||||||
|
|
||||||
this.goFilterIconElement = new Phaser.GameObjects.Sprite(globalScene, this.filterInstructionRowX, this.filterInstructionRowY, "keyboard", "C.png");
|
this.goFilterIconElement = new Phaser.GameObjects.Sprite(globalScene, this.filterInstructionRowX, this.filterInstructionRowY, "keyboard", "C.png");
|
||||||
this.goFilterIconElement.setName("sprite-goFilter-icon-element");
|
this.goFilterIconElement.setName("sprite-goFilter-icon-element");
|
||||||
this.goFilterIconElement.setScale(0.675);
|
this.goFilterIconElement.setScale(0.675);
|
||||||
@ -1497,6 +1519,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
const props = globalScene.gameData.getSpeciesDexAttrProps(randomSpecies, dexAttr);
|
const props = globalScene.gameData.getSpeciesDexAttrProps(randomSpecies, dexAttr);
|
||||||
const abilityIndex = this.abilityCursor;
|
const abilityIndex = this.abilityCursor;
|
||||||
const nature = this.natureCursor as unknown as Nature;
|
const nature = this.natureCursor as unknown as Nature;
|
||||||
|
const teraType = this.teraCursor;
|
||||||
const moveset = this.starterMoveset?.slice(0) as StarterMoveset;
|
const moveset = this.starterMoveset?.slice(0) as StarterMoveset;
|
||||||
const starterCost = globalScene.gameData.getSpeciesStarterValue(randomSpecies.speciesId);
|
const starterCost = globalScene.gameData.getSpeciesStarterValue(randomSpecies.speciesId);
|
||||||
const speciesForm = getPokemonSpeciesForm(randomSpecies.speciesId, props.formIndex);
|
const speciesForm = getPokemonSpeciesForm(randomSpecies.speciesId, props.formIndex);
|
||||||
@ -1505,7 +1528,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
.loadAssets(props.female, props.formIndex, props.shiny, props.variant, true)
|
.loadAssets(props.female, props.formIndex, props.shiny, props.variant, true)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
if (this.tryUpdateValue(starterCost, true)) {
|
if (this.tryUpdateValue(starterCost, true)) {
|
||||||
this.addToParty(randomSpecies, dexAttr, abilityIndex, nature, moveset, true);
|
this.addToParty(randomSpecies, dexAttr, abilityIndex, nature, moveset, teraType, true);
|
||||||
ui.playSelect();
|
ui.playSelect();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -1585,7 +1608,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
const cursorObj = this.starterCursorObjs[this.starterSpecies.length];
|
const cursorObj = this.starterCursorObjs[this.starterSpecies.length];
|
||||||
cursorObj.setVisible(true);
|
cursorObj.setVisible(true);
|
||||||
cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y);
|
cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y);
|
||||||
this.addToParty(this.lastSpecies, this.dexAttrCursor, this.abilityCursor, this.natureCursor as unknown as Nature, this.starterMoveset?.slice(0) as StarterMoveset);
|
this.addToParty(this.lastSpecies, this.dexAttrCursor, this.abilityCursor, this.natureCursor as unknown as Nature, this.starterMoveset?.slice(0) as StarterMoveset, this.teraCursor);
|
||||||
ui.playSelect();
|
ui.playSelect();
|
||||||
} else {
|
} else {
|
||||||
ui.playError(); // this should be redundant as there is now a trigger for when a pokemon can't be added to party
|
ui.playError(); // this should be redundant as there is now a trigger for when a pokemon can't be added to party
|
||||||
@ -2066,7 +2089,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
} while (newFormIndex !== props.formIndex);
|
} while (newFormIndex !== props.formIndex);
|
||||||
starterAttributes.form = newFormIndex; // store the selected form
|
starterAttributes.form = newFormIndex; // store the selected form
|
||||||
this.setSpeciesDetails(this.lastSpecies, { formIndex: newFormIndex });
|
starterAttributes.tera = this.lastSpecies.forms[newFormIndex].type1;
|
||||||
|
this.setSpeciesDetails(this.lastSpecies, { formIndex: newFormIndex, teraType: starterAttributes.tera });
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -2125,6 +2149,19 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Button.CYCLE_TERA:
|
||||||
|
if (this.canCycleTera) {
|
||||||
|
const speciesForm = getPokemonSpeciesForm(this.lastSpecies.speciesId, starterAttributes.form ?? 0);
|
||||||
|
if (speciesForm.type1 === this.teraCursor && !Utils.isNullOrUndefined(speciesForm.type2)) {
|
||||||
|
starterAttributes.tera = speciesForm.type2!;
|
||||||
|
this.setSpeciesDetails(this.lastSpecies, { teraType: speciesForm.type2! });
|
||||||
|
} else {
|
||||||
|
starterAttributes.tera = speciesForm.type1;
|
||||||
|
this.setSpeciesDetails(this.lastSpecies, { teraType: speciesForm.type1 });
|
||||||
|
}
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Button.UP:
|
case Button.UP:
|
||||||
if (!this.starterIconsCursorObj.visible) {
|
if (!this.starterIconsCursorObj.visible) {
|
||||||
if (currentRow > 0) {
|
if (currentRow > 0) {
|
||||||
@ -2289,7 +2326,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
return [ isDupe, removeIndex ];
|
return [ isDupe, removeIndex ];
|
||||||
}
|
}
|
||||||
|
|
||||||
addToParty(species: PokemonSpecies, dexAttr: bigint, abilityIndex: number, nature: Nature, moveset: StarterMoveset, randomSelection: boolean = false) {
|
addToParty(species: PokemonSpecies, dexAttr: bigint, abilityIndex: number, nature: Nature, moveset: StarterMoveset, teraType: Type, randomSelection: boolean = false) {
|
||||||
const props = globalScene.gameData.getSpeciesDexAttrProps(species, dexAttr);
|
const props = globalScene.gameData.getSpeciesDexAttrProps(species, dexAttr);
|
||||||
this.starterIcons[this.starterSpecies.length].setTexture(species.getIconAtlasKey(props.formIndex, props.shiny, props.variant));
|
this.starterIcons[this.starterSpecies.length].setTexture(species.getIconAtlasKey(props.formIndex, props.shiny, props.variant));
|
||||||
this.starterIcons[this.starterSpecies.length].setFrame(species.getIconId(props.female, props.formIndex, props.shiny, props.variant));
|
this.starterIcons[this.starterSpecies.length].setFrame(species.getIconId(props.female, props.formIndex, props.shiny, props.variant));
|
||||||
@ -2299,6 +2336,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.starterAttr.push(dexAttr);
|
this.starterAttr.push(dexAttr);
|
||||||
this.starterAbilityIndexes.push(abilityIndex);
|
this.starterAbilityIndexes.push(abilityIndex);
|
||||||
this.starterNatures.push(nature);
|
this.starterNatures.push(nature);
|
||||||
|
this.starterTeras.push(teraType);
|
||||||
this.starterMovesets.push(moveset);
|
this.starterMovesets.push(moveset);
|
||||||
if (this.speciesLoaded.get(species.speciesId) || randomSelection ) {
|
if (this.speciesLoaded.get(species.speciesId) || randomSelection ) {
|
||||||
getPokemonSpeciesForm(species.speciesId, props.formIndex).cry();
|
getPokemonSpeciesForm(species.speciesId, props.formIndex).cry();
|
||||||
@ -2379,6 +2417,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
case SettingKeyboard.Button_Cycle_Nature:
|
case SettingKeyboard.Button_Cycle_Nature:
|
||||||
iconPath = "N.png";
|
iconPath = "N.png";
|
||||||
break;
|
break;
|
||||||
|
case SettingKeyboard.Button_Cycle_Tera:
|
||||||
|
iconPath = "V.png";
|
||||||
|
break;
|
||||||
case SettingKeyboard.Button_Stats:
|
case SettingKeyboard.Button_Stats:
|
||||||
iconPath = "C.png";
|
iconPath = "C.png";
|
||||||
break;
|
break;
|
||||||
@ -2459,6 +2500,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
if (this.canCycleNature) {
|
if (this.canCycleNature) {
|
||||||
this.updateButtonIcon(SettingKeyboard.Button_Cycle_Nature, gamepadType, this.natureIconElement, this.natureLabel);
|
this.updateButtonIcon(SettingKeyboard.Button_Cycle_Nature, gamepadType, this.natureIconElement, this.natureLabel);
|
||||||
}
|
}
|
||||||
|
if (this.canCycleTera) {
|
||||||
|
this.updateButtonIcon(SettingKeyboard.Button_Cycle_Tera, gamepadType, this.teraIconElement, this.teraLabel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if filter mode is inactivated and gamepadType is not undefined, update the button icons
|
// if filter mode is inactivated and gamepadType is not undefined, update the button icons
|
||||||
@ -2876,6 +2920,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.dexAttrCursor = species ? this.getCurrentDexProps(species.speciesId) : 0n;
|
this.dexAttrCursor = species ? this.getCurrentDexProps(species.speciesId) : 0n;
|
||||||
this.abilityCursor = species ? globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species) : 0;
|
this.abilityCursor = species ? globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species) : 0;
|
||||||
this.natureCursor = species ? globalScene.gameData.getSpeciesDefaultNature(species) : 0;
|
this.natureCursor = species ? globalScene.gameData.getSpeciesDefaultNature(species) : 0;
|
||||||
|
this.teraCursor = species ? species.type1 : Type.UNKNOWN;
|
||||||
|
|
||||||
if (!species && globalScene.ui.getTooltip().visible) {
|
if (!species && globalScene.ui.getTooltip().visible) {
|
||||||
globalScene.ui.hideTooltip();
|
globalScene.ui.hideTooltip();
|
||||||
@ -2894,6 +2939,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
// load default ability from stater save data, if set
|
// load default ability from stater save data, if set
|
||||||
this.abilityCursor = starterAttributes.ability;
|
this.abilityCursor = starterAttributes.ability;
|
||||||
}
|
}
|
||||||
|
if (starterAttributes?.tera) {
|
||||||
|
// load default tera from starter save data, if set
|
||||||
|
this.teraCursor = starterAttributes.tera;
|
||||||
|
}
|
||||||
|
|
||||||
if (this.statsMode) {
|
if (this.statsMode) {
|
||||||
if (this.speciesStarterDexEntry?.caughtAttr) {
|
if (this.speciesStarterDexEntry?.caughtAttr) {
|
||||||
@ -3035,7 +3084,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
female: props.female,
|
female: props.female,
|
||||||
variant: props.variant,
|
variant: props.variant,
|
||||||
abilityIndex: this.starterAbilityIndexes[starterIndex],
|
abilityIndex: this.starterAbilityIndexes[starterIndex],
|
||||||
natureIndex: this.starterNatures[starterIndex]
|
natureIndex: this.starterNatures[starterIndex],
|
||||||
|
teraType: this.starterTeras[starterIndex]
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const defaultDexAttr = this.getCurrentDexProps(species.speciesId);
|
const defaultDexAttr = this.getCurrentDexProps(species.speciesId);
|
||||||
@ -3083,6 +3133,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonCaughtHatchedContainer.setVisible(false);
|
this.pokemonCaughtHatchedContainer.setVisible(false);
|
||||||
this.pokemonCandyContainer.setVisible(false);
|
this.pokemonCandyContainer.setVisible(false);
|
||||||
this.pokemonFormText.setVisible(false);
|
this.pokemonFormText.setVisible(false);
|
||||||
|
this.teraIcon.setVisible(false);
|
||||||
|
|
||||||
const defaultDexAttr = globalScene.gameData.getSpeciesDefaultDexAttr(species, true, true);
|
const defaultDexAttr = globalScene.gameData.getSpeciesDefaultDexAttr(species, true, true);
|
||||||
const defaultAbilityIndex = globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
const defaultAbilityIndex = globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
||||||
@ -3117,6 +3168,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonCaughtHatchedContainer.setVisible(false);
|
this.pokemonCaughtHatchedContainer.setVisible(false);
|
||||||
this.pokemonCandyContainer.setVisible(false);
|
this.pokemonCandyContainer.setVisible(false);
|
||||||
this.pokemonFormText.setVisible(false);
|
this.pokemonFormText.setVisible(false);
|
||||||
|
this.teraIcon.setVisible(false);
|
||||||
|
|
||||||
this.setSpeciesDetails(species!, { // TODO: is this bang correct?
|
this.setSpeciesDetails(species!, { // TODO: is this bang correct?
|
||||||
shiny: false,
|
shiny: false,
|
||||||
@ -3131,7 +3183,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setSpeciesDetails(species: PokemonSpecies, options: SpeciesDetails = {}): void {
|
setSpeciesDetails(species: PokemonSpecies, options: SpeciesDetails = {}): void {
|
||||||
let { shiny, formIndex, female, variant, abilityIndex, natureIndex } = options;
|
let { shiny, formIndex, female, variant, abilityIndex, natureIndex, teraType } = options;
|
||||||
const forSeen: boolean = options.forSeen ?? false;
|
const forSeen: boolean = options.forSeen ?? false;
|
||||||
const oldProps = species ? globalScene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor) : null;
|
const oldProps = species ? globalScene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor) : null;
|
||||||
const oldAbilityIndex = this.abilityCursor > -1 ? this.abilityCursor : globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
const oldAbilityIndex = this.abilityCursor > -1 ? this.abilityCursor : globalScene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
||||||
@ -3139,6 +3191,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.dexAttrCursor = 0n;
|
this.dexAttrCursor = 0n;
|
||||||
this.abilityCursor = -1;
|
this.abilityCursor = -1;
|
||||||
this.natureCursor = -1;
|
this.natureCursor = -1;
|
||||||
|
this.teraCursor = Type.UNKNOWN;
|
||||||
// We will only update the sprite if there is a change to form, shiny/variant
|
// We will only update the sprite if there is a change to form, shiny/variant
|
||||||
// or gender for species with gender sprite differences
|
// or gender for species with gender sprite differences
|
||||||
const shouldUpdateSprite = (species?.genderDiffs && !isNullOrUndefined(female))
|
const shouldUpdateSprite = (species?.genderDiffs && !isNullOrUndefined(female))
|
||||||
@ -3168,6 +3221,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.dexAttrCursor |= globalScene.gameData.getFormAttr(formIndex !== undefined ? formIndex : (formIndex = oldProps!.formIndex)); // TODO: is this bang correct?
|
this.dexAttrCursor |= globalScene.gameData.getFormAttr(formIndex !== undefined ? formIndex : (formIndex = oldProps!.formIndex)); // TODO: is this bang correct?
|
||||||
this.abilityCursor = abilityIndex !== undefined ? abilityIndex : (abilityIndex = oldAbilityIndex);
|
this.abilityCursor = abilityIndex !== undefined ? abilityIndex : (abilityIndex = oldAbilityIndex);
|
||||||
this.natureCursor = natureIndex !== undefined ? natureIndex : (natureIndex = oldNatureIndex);
|
this.natureCursor = natureIndex !== undefined ? natureIndex : (natureIndex = oldNatureIndex);
|
||||||
|
this.teraCursor = !Utils.isNullOrUndefined(teraType) ? teraType : (teraType = species.type1);
|
||||||
const [ isInParty, partyIndex ]: [boolean, number] = this.isInParty(species); // we use this to firstly check if the pokemon is in the party, and if so, to get the party index in order to update the icon image
|
const [ isInParty, partyIndex ]: [boolean, number] = this.isInParty(species); // we use this to firstly check if the pokemon is in the party, and if so, to get the party index in order to update the icon image
|
||||||
if (isInParty) {
|
if (isInParty) {
|
||||||
this.updatePartyIcon(species, partyIndex);
|
this.updatePartyIcon(species, partyIndex);
|
||||||
@ -3179,6 +3233,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonPassiveText.setVisible(false);
|
this.pokemonPassiveText.setVisible(false);
|
||||||
this.pokemonPassiveDisabledIcon.setVisible(false);
|
this.pokemonPassiveDisabledIcon.setVisible(false);
|
||||||
this.pokemonPassiveLockedIcon.setVisible(false);
|
this.pokemonPassiveLockedIcon.setVisible(false);
|
||||||
|
this.teraIcon.setVisible(false);
|
||||||
|
|
||||||
if (this.assetLoadCancelled) {
|
if (this.assetLoadCancelled) {
|
||||||
this.assetLoadCancelled.value = true;
|
this.assetLoadCancelled.value = true;
|
||||||
@ -3230,6 +3285,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.starterAttr[starterIndex] = this.dexAttrCursor;
|
this.starterAttr[starterIndex] = this.dexAttrCursor;
|
||||||
this.starterAbilityIndexes[starterIndex] = this.abilityCursor;
|
this.starterAbilityIndexes[starterIndex] = this.abilityCursor;
|
||||||
this.starterNatures[starterIndex] = this.natureCursor;
|
this.starterNatures[starterIndex] = this.natureCursor;
|
||||||
|
this.starterTeras[starterIndex] = this.teraCursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
const assetLoadCancelled = new BooleanHolder(false);
|
const assetLoadCancelled = new BooleanHolder(false);
|
||||||
@ -3288,7 +3344,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.canCycleForm = species.forms.filter(f => f.isStarterSelectable || !pokemonFormChanges[species.speciesId]?.find(fc => fc.formKey))
|
this.canCycleForm = species.forms.filter(f => f.isStarterSelectable || !pokemonFormChanges[species.speciesId]?.find(fc => fc.formKey))
|
||||||
.map((_, f) => dexEntry.caughtAttr & globalScene.gameData.getFormAttr(f)).filter(f => f).length > 1;
|
.map((_, f) => dexEntry.caughtAttr & globalScene.gameData.getFormAttr(f)).filter(f => f).length > 1;
|
||||||
this.canCycleNature = globalScene.gameData.getNaturesForAttr(dexEntry.natureAttr).length > 1;
|
this.canCycleNature = globalScene.gameData.getNaturesForAttr(dexEntry.natureAttr).length > 1;
|
||||||
|
this.canCycleTera = globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id) && !Utils.isNullOrUndefined(getPokemonSpeciesForm(species.speciesId, formIndex ?? 0).type2);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dexEntry.caughtAttr && species.malePercent !== null) {
|
if (dexEntry.caughtAttr && species.malePercent !== null) {
|
||||||
@ -3412,10 +3468,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonFormText.setText(formText);
|
this.pokemonFormText.setText(formText);
|
||||||
|
|
||||||
this.setTypeIcons(speciesForm.type1, speciesForm.type2);
|
this.setTypeIcons(speciesForm.type1, speciesForm.type2);
|
||||||
|
|
||||||
|
this.teraIcon.setFrame(Type[this.teraCursor].toLowerCase());
|
||||||
|
this.teraIcon.setVisible(!this.statsMode && globalScene.gameData.achvUnlocks.hasOwnProperty(achvs.TERASTALLIZE.id));
|
||||||
} else {
|
} else {
|
||||||
this.pokemonAbilityText.setText("");
|
this.pokemonAbilityText.setText("");
|
||||||
this.pokemonPassiveText.setText("");
|
this.pokemonPassiveText.setText("");
|
||||||
this.pokemonNatureText.setText("");
|
this.pokemonNatureText.setText("");
|
||||||
|
this.teraIcon.setVisible(false);
|
||||||
this.setTypeIcons(null, null);
|
this.setTypeIcons(null, null);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -3426,6 +3486,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonAbilityText.setText("");
|
this.pokemonAbilityText.setText("");
|
||||||
this.pokemonPassiveText.setText("");
|
this.pokemonPassiveText.setText("");
|
||||||
this.pokemonNatureText.setText("");
|
this.pokemonNatureText.setText("");
|
||||||
|
this.teraIcon.setVisible(false);
|
||||||
this.setTypeIcons(null, null);
|
this.setTypeIcons(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3479,6 +3540,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.starterAttr.splice(index, 1);
|
this.starterAttr.splice(index, 1);
|
||||||
this.starterAbilityIndexes.splice(index, 1);
|
this.starterAbilityIndexes.splice(index, 1);
|
||||||
this.starterNatures.splice(index, 1);
|
this.starterNatures.splice(index, 1);
|
||||||
|
this.starterTeras.splice(index, 1);
|
||||||
this.starterMovesets.splice(index, 1);
|
this.starterMovesets.splice(index, 1);
|
||||||
|
|
||||||
for (let s = 0; s < this.starterSpecies.length; s++) {
|
for (let s = 0; s < this.starterSpecies.length; s++) {
|
||||||
@ -3690,6 +3752,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
abilityIndex: thisObj.starterAbilityIndexes[i],
|
abilityIndex: thisObj.starterAbilityIndexes[i],
|
||||||
passive: !(globalScene.gameData.starterData[starterSpecies.speciesId].passiveAttr ^ (PassiveAttr.ENABLED | PassiveAttr.UNLOCKED)),
|
passive: !(globalScene.gameData.starterData[starterSpecies.speciesId].passiveAttr ^ (PassiveAttr.ENABLED | PassiveAttr.UNLOCKED)),
|
||||||
nature: thisObj.starterNatures[i] as Nature,
|
nature: thisObj.starterNatures[i] as Nature,
|
||||||
|
teraType: thisObj.starterTeras[i] as Type,
|
||||||
moveset: thisObj.starterMovesets[i],
|
moveset: thisObj.starterMovesets[i],
|
||||||
pokerus: thisObj.pokerusSpecies.includes(starterSpecies),
|
pokerus: thisObj.pokerusSpecies.includes(starterSpecies),
|
||||||
nickname: thisObj.starterPreferences[starterSpecies.speciesId]?.nickname,
|
nickname: thisObj.starterPreferences[starterSpecies.speciesId]?.nickname,
|
||||||
@ -3816,6 +3879,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.abilityLabel.setVisible(false);
|
this.abilityLabel.setVisible(false);
|
||||||
this.natureIconElement.setVisible(false);
|
this.natureIconElement.setVisible(false);
|
||||||
this.natureLabel.setVisible(false);
|
this.natureLabel.setVisible(false);
|
||||||
|
this.teraIconElement.setVisible(false);
|
||||||
|
this.teraLabel.setVisible(false);
|
||||||
this.goFilterIconElement.setVisible(false);
|
this.goFilterIconElement.setVisible(false);
|
||||||
this.goFilterLabel.setVisible(false);
|
this.goFilterLabel.setVisible(false);
|
||||||
}
|
}
|
||||||
|
@ -225,7 +225,7 @@ export default class SummaryUiHandler extends UiHandler {
|
|||||||
this.summaryContainer.add(this.championRibbon);
|
this.summaryContainer.add(this.championRibbon);
|
||||||
this.championRibbon.setVisible(false);
|
this.championRibbon.setVisible(false);
|
||||||
|
|
||||||
this.levelText = addTextObject(36, -17, "", TextStyle.SUMMARY_ALT);
|
this.levelText = addTextObject(24, -17, "", TextStyle.SUMMARY_ALT);
|
||||||
this.levelText.setOrigin(0, 1);
|
this.levelText.setOrigin(0, 1);
|
||||||
this.summaryContainer.add(this.levelText);
|
this.summaryContainer.add(this.levelText);
|
||||||
|
|
||||||
@ -413,7 +413,7 @@ export default class SummaryUiHandler extends UiHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.pokeball.setFrame(getPokeballAtlasKey(this.pokemon.pokeball));
|
this.pokeball.setFrame(getPokeballAtlasKey(this.pokemon.pokeball));
|
||||||
this.levelText.setText(this.pokemon.level.toString());
|
this.levelText.setText(`${i18next.t("pokemonSummary:lv")}${this.pokemon.level.toString()}`);
|
||||||
this.genderText.setText(getGenderSymbol(this.pokemon.getGender(true)));
|
this.genderText.setText(getGenderSymbol(this.pokemon.getGender(true)));
|
||||||
this.genderText.setColor(getGenderColor(this.pokemon.getGender(true)));
|
this.genderText.setColor(getGenderColor(this.pokemon.getGender(true)));
|
||||||
this.genderText.setShadowColor(getGenderColor(this.pokemon.getGender(true), true));
|
this.genderText.setShadowColor(getGenderColor(this.pokemon.getGender(true), true));
|
||||||
@ -756,7 +756,7 @@ export default class SummaryUiHandler extends UiHandler {
|
|||||||
trainerText.setOrigin(0, 0);
|
trainerText.setOrigin(0, 0);
|
||||||
profileContainer.add(trainerText);
|
profileContainer.add(trainerText);
|
||||||
|
|
||||||
const trainerIdText = addTextObject(174, 12, globalScene.gameData.trainerId.toString(), TextStyle.SUMMARY_ALT);
|
const trainerIdText = addTextObject(141, 12, `${i18next.t("pokemonSummary:idNo")}${globalScene.gameData.trainerId.toString()}`, TextStyle.SUMMARY_ALT);
|
||||||
trainerIdText.setOrigin(0, 0);
|
trainerIdText.setOrigin(0, 0);
|
||||||
profileContainer.add(trainerIdText);
|
profileContainer.add(trainerIdText);
|
||||||
|
|
||||||
|