Skip to content

Commit

Permalink
Fix Protean / Embody Aspect + Neutralizing Gas interaction (#10805)
Browse files Browse the repository at this point in the history
  • Loading branch information
andrebastosdias authored Jan 10, 2025
1 parent 328e20d commit 639b930
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 32 deletions.
46 changes: 16 additions & 30 deletions data/abilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1167,59 +1167,51 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
embodyaspectcornerstone: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Cornerstone-Tera' && !this.effectState.embodied) {
this.effectState.embodied = true;
if (pokemon.baseSpecies.name === 'Ogerpon-Cornerstone-Tera' &&
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({def: 1}, pokemon);
}
},
onSwitchIn() {
delete this.effectState.embodied;
},
flags: {failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1},
name: "Embody Aspect (Cornerstone)",
rating: 3.5,
num: 304,
},
embodyaspecthearthflame: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Hearthflame-Tera' && !this.effectState.embodied) {
this.effectState.embodied = true;
if (pokemon.baseSpecies.name === 'Ogerpon-Hearthflame-Tera' &&
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({atk: 1}, pokemon);
}
},
onSwitchIn() {
delete this.effectState.embodied;
},
flags: {failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1},
name: "Embody Aspect (Hearthflame)",
rating: 3.5,
num: 303,
},
embodyaspectteal: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Teal-Tera' && !this.effectState.embodied) {
this.effectState.embodied = true;
if (pokemon.baseSpecies.name === 'Ogerpon-Teal-Tera' &&
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({spe: 1}, pokemon);
}
},
onSwitchIn() {
delete this.effectState.embodied;
},
flags: {failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1},
name: "Embody Aspect (Teal)",
rating: 3.5,
num: 301,
},
embodyaspectwellspring: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Wellspring-Tera' && !this.effectState.embodied) {
this.effectState.embodied = true;
if (pokemon.baseSpecies.name === 'Ogerpon-Wellspring-Tera' &&
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({spd: 1}, pokemon);
}
},
onSwitchIn() {
delete this.effectState.embodied;
},
flags: {failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1, failskillswap: 1, notransform: 1},
name: "Embody Aspect (Wellspring)",
rating: 3.5,
Expand Down Expand Up @@ -2272,18 +2264,15 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
libero: {
onPrepareHit(source, target, move) {
if (this.effectState.libero) return;
if (this.effectState.libero === source.previouslySwitchedIn) return;
if (move.hasBounced || move.flags['futuremove'] || move.sourceEffect === 'snatch' || move.callsMove) return;
const type = move.type;
if (type && type !== '???' && source.getTypes().join() !== type) {
if (!source.setType(type)) return;
this.effectState.libero = true;
this.effectState.libero = source.previouslySwitchedIn;
this.add('-start', source, 'typechange', type, '[from] ability: Libero');
}
},
onSwitchIn() {
delete this.effectState.libero;
},
flags: {},
name: "Libero",
rating: 4,
Expand Down Expand Up @@ -3416,18 +3405,15 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
protean: {
onPrepareHit(source, target, move) {
if (this.effectState.protean) return;
if (this.effectState.protean === source.previouslySwitchedIn) return;
if (move.hasBounced || move.flags['futuremove'] || move.sourceEffect === 'snatch' || move.callsMove) return;
const type = move.type;
if (type && type !== '???' && source.getTypes().join() !== type) {
if (!source.setType(type)) return;
this.effectState.protean = true;
this.effectState.protean = source.previouslySwitchedIn;
this.add('-start', source, 'typechange', type, '[from] ability: Protean');
}
},
onSwitchIn(pokemon) {
delete this.effectState.protean;
},
flags: {},
name: "Protean",
rating: 4,
Expand Down
2 changes: 0 additions & 2 deletions data/mods/gen8/abilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
this.add('-start', source, 'typechange', type, '[from] ability: Libero');
}
},
onSwitchIn() {},
rating: 4.5,
},
lightmetal: {
Expand Down Expand Up @@ -780,7 +779,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa
this.add('-start', source, 'typechange', type, '[from] ability: Protean');
}
},
onSwitchIn() {},
rating: 4.5,
},
psychicsurge: {
Expand Down
67 changes: 67 additions & 0 deletions test/sim/abilities/protean.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,73 @@ describe('Protean', function () {
// More examples: https://www.smogon.com/forums/threads/sword-shield-battle-mechanics-research.3655528/post-8548957
});

it(`should not allow the user to change its typing twice`, function () {
battle = common.createBattle([[
{species: 'Cinderace', ability: 'protean', moves: ['tackle', 'watergun']},
], [
{species: 'Gengar', moves: ['sleeptalk']},
]]);

battle.makeChoices();
const cinder = battle.p1.active[0];
assert(cinder.hasType('Normal'));

battle.makeChoices('move watergun', 'auto');
assert.false(cinder.hasType('Water'));
});

it(`should not allow the user to change its typing twice if the Ability was suppressed`, function () {
battle = common.createBattle([[
{species: 'Cinderace', ability: 'protean', moves: ['tackle', 'watergun']},
], [
{species: 'Gengar', moves: ['sleeptalk']},
{species: 'Weezing', ability: 'neutralizinggas', moves: ['sleeptalk']},
]]);

battle.makeChoices('move tackle', 'auto');
const cinder = battle.p1.active[0];
assert(cinder.hasType('Normal'));

battle.makeChoices('move watergun', 'switch 2');
battle.makeChoices('move watergun', 'switch 2');

assert.false(cinder.hasType('Water'));
});

it(`should allow the user to change its typing twice if it lost and regained the Ability`, function () {
battle = common.createBattle([[
{species: 'Cinderace', ability: 'protean', moves: ['tackle', 'watergun']},
], [
{species: 'Gengar', ability: 'protean', moves: ['sleeptalk', 'skillswap']},
]]);

battle.makeChoices('move tackle', 'move skillswap');
const cinder = battle.p1.active[0];
assert(cinder.hasType('Normal'));

battle.makeChoices('move watergun', 'auto');
assert(cinder.hasType('Water'));
});

it(`should not be prevented from resetting its effectState by Ability suppression`, function () {
battle = common.createBattle([[
{species: 'Cinderace', ability: 'protean', moves: ['tackle']},
{species: 'Wynaut', moves: ['sleeptalk']},
], [
{species: 'Gengar', ability: 'protean', moves: ['sleeptalk']},
{species: 'Weezing', ability: 'neutralizinggas', moves: ['sleeptalk']},
]]);

battle.makeChoices('move tackle', 'auto');
battle.makeChoices('move tackle', 'switch 2'); // Weezing comes in
battle.makeChoices('switch 2', 'auto'); // Cinderace switches out and back in
battle.makeChoices('switch 2', 'auto');
battle.makeChoices('move tackle', 'switch 2'); // Weezing switches out

const cinder = battle.p1.active[0];
assert(cinder.hasType('Normal'));
});

describe('Gen 6-8', function () {
it(`should activate on both turns of a charge move`, function () {
battle = common.gen(8).createBattle([[
Expand Down

0 comments on commit 639b930

Please sign in to comment.