Skip to content

Commit

Permalink
Implement notransform flag
Browse files Browse the repository at this point in the history
  • Loading branch information
DaWoblefet committed Jan 1, 2024
1 parent a4807f5 commit cd231ef
Show file tree
Hide file tree
Showing 6 changed files with 103 additions and 41 deletions.
53 changes: 19 additions & 34 deletions data/abilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -592,8 +592,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onUpdate(pokemon) {
if (this.gameType !== 'doubles') return;
const ally = pokemon.allies()[0];
if (!ally || pokemon.transformed ||
pokemon.baseSpecies.baseSpecies !== 'Tatsugiri' || ally.baseSpecies.baseSpecies !== 'Dondozo') {
if (!ally || pokemon.baseSpecies.baseSpecies !== 'Tatsugiri' || ally.baseSpecies.baseSpecies !== 'Dondozo') {
// Handle any edge cases
if (pokemon.getVolatile('commanding')) pokemon.removeVolatile('commanding');
return;
Expand Down Expand Up @@ -955,18 +954,15 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
disguise: {
onDamagePriority: 1,
onDamage(damage, target, source, effect) {
if (
effect && effect.effectType === 'Move' &&
['mimikyu', 'mimikyutotem'].includes(target.species.id) && !target.transformed
) {
if (effect && effect.effectType === 'Move' && ['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
this.add('-activate', target, 'ability: Disguise');
this.effectState.busted = true;
return 0;
}
},
onCriticalHit(target, source, move) {
if (!target) return;
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id) || target.transformed) {
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
return;
}
const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
Expand All @@ -977,7 +973,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
onEffectiveness(typeMod, target, type, move) {
if (!target || move.category === 'Status') return;
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id) || target.transformed) {
if (!['mimikyu', 'mimikyutotem'].includes(target.species.id)) {
return;
}

Expand Down Expand Up @@ -1155,7 +1151,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
embodyaspectcornerstone: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Cornerstone-Tera' && !pokemon.transformed && !this.effectState.embodied) {
if (pokemon.baseSpecies.name === 'Ogerpon-Cornerstone-Tera' && !this.effectState.embodied) {
this.effectState.embodied = true;
this.boost({def: 1}, pokemon);
}
Expand All @@ -1170,7 +1166,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
embodyaspecthearthflame: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Hearthflame-Tera' && !pokemon.transformed && !this.effectState.embodied) {
if (pokemon.baseSpecies.name === 'Ogerpon-Hearthflame-Tera' && !this.effectState.embodied) {
this.effectState.embodied = true;
this.boost({atk: 1}, pokemon);
}
Expand All @@ -1185,7 +1181,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
embodyaspectteal: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Teal-Tera' && !pokemon.transformed && !this.effectState.embodied) {
if (pokemon.baseSpecies.name === 'Ogerpon-Teal-Tera' && !this.effectState.embodied) {
this.effectState.embodied = true;
this.boost({spe: 1}, pokemon);
}
Expand All @@ -1200,7 +1196,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
embodyaspectwellspring: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Wellspring-Tera' && !pokemon.transformed && !this.effectState.embodied) {
if (pokemon.baseSpecies.name === 'Ogerpon-Wellspring-Tera' && !this.effectState.embodied) {
this.effectState.embodied = true;
this.boost({spd: 1}, pokemon);
}
Expand Down Expand Up @@ -1686,7 +1682,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
gulpmissile: {
onDamagingHit(damage, target, source, move) {
if (!source.hp || !source.isActive || target.transformed || target.isSemiInvulnerable()) return;
if (!source.hp || !source.isActive || target.isSemiInvulnerable()) return;
if (['cramorantgulping', 'cramorantgorging'].includes(target.species.id)) {
this.damage(source.baseMaxhp / 4, source, target);
if (target.species.id === 'cramorantgulping') {
Expand All @@ -1699,10 +1695,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
// The Dive part of this mechanic is implemented in Dive's `onTryMove` in moves.ts
onSourceTryPrimaryHit(target, source, effect) {
if (
effect && effect.id === 'surf' && source.hasAbility('gulpmissile') &&
source.species.name === 'Cramorant' && !source.transformed
) {
if (effect && effect.id === 'surf' && source.hasAbility('gulpmissile') && source.species.name === 'Cramorant') {
const forme = source.hp <= source.maxhp / 2 ? 'cramorantgorging' : 'cramorantgulping';
source.formeChange(forme, effect);
}
Expand Down Expand Up @@ -1840,7 +1833,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
hungerswitch: {
onResidualOrder: 29,
onResidual(pokemon) {
if (pokemon.species.baseSpecies !== 'Morpeko' || pokemon.transformed || pokemon.terastallized) return;
if (pokemon.species.baseSpecies !== 'Morpeko' || pokemon.terastallized) return;
const targetForme = pokemon.species.name === 'Morpeko' ? 'Morpeko-Hangry' : 'Morpeko';
pokemon.formeChange(targetForme);
},
Expand Down Expand Up @@ -1912,34 +1905,30 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
iceface: {
onStart(pokemon) {
if (this.field.isWeather(['hail', 'snow']) &&
pokemon.species.id === 'eiscuenoice' && !pokemon.transformed) {
if (this.field.isWeather(['hail', 'snow']) && pokemon.species.id === 'eiscuenoice') {
this.add('-activate', pokemon, 'ability: Ice Face');
this.effectState.busted = false;
pokemon.formeChange('Eiscue', this.effect, true);
}
},
onDamagePriority: 1,
onDamage(damage, target, source, effect) {
if (
effect && effect.effectType === 'Move' && effect.category === 'Physical' &&
target.species.id === 'eiscue' && !target.transformed
) {
if (effect && effect.effectType === 'Move' && effect.category === 'Physical' && target.species.id === 'eiscue') {
this.add('-activate', target, 'ability: Ice Face');
this.effectState.busted = true;
return 0;
}
},
onCriticalHit(target, type, move) {
if (!target) return;
if (move.category !== 'Physical' || target.species.id !== 'eiscue' || target.transformed) return;
if (move.category !== 'Physical' || target.species.id !== 'eiscue') return;
if (target.volatiles['substitute'] && !(move.flags['bypasssub'] || move.infiltrates)) return;
if (!target.runImmunity(move.type)) return;
return false;
},
onEffectiveness(typeMod, target, type, move) {
if (!target) return;
if (move.category !== 'Physical' || target.species.id !== 'eiscue' || target.transformed) return;
if (move.category !== 'Physical' || target.species.id !== 'eiscue') return;

const hitSub = target.volatiles['substitute'] && !move.flags['bypasssub'] && !(move.infiltrates && this.gen >= 6);
if (hitSub) return;
Expand All @@ -1956,8 +1945,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
// snow/hail resuming because Cloud Nine/Air Lock ended does not trigger Ice Face
if ((sourceEffect as Ability)?.suppressWeather) return;
if (!pokemon.hp) return;
if (this.field.isWeather(['hail', 'snow']) &&
pokemon.species.id === 'eiscuenoice' && !pokemon.transformed) {
if (this.field.isWeather(['hail', 'snow']) && pokemon.species.id === 'eiscuenoice') {
this.add('-activate', pokemon, 'ability: Ice Face');
this.effectState.busted = false;
pokemon.formeChange('Eiscue', this.effect, true);
Expand Down Expand Up @@ -2846,7 +2834,6 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
neutralizinggas: {
// Ability suppression implemented in sim/pokemon.ts:Pokemon#ignoringAbility
onPreStart(pokemon) {
if (pokemon.transformed) return;
this.add('-ability', pokemon, 'Neutralizing Gas');
pokemon.abilityState.ending = false;
const strongWeathers = ['desolateland', 'primordialsea', 'deltastream'];
Expand Down Expand Up @@ -3433,7 +3420,6 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
this.singleEvent('WeatherChange', this.effect, this.effectState, pokemon);
},
onWeatherChange(pokemon) {
if (pokemon.transformed) return;
// Protosynthesis is not affected by Utility Umbrella
if (this.field.isWeather('sunnyday')) {
pokemon.addVolatile('protosynthesis');
Expand Down Expand Up @@ -3570,7 +3556,6 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
this.singleEvent('TerrainChange', this.effect, this.effectState, pokemon);
},
onTerrainChange(pokemon) {
if (pokemon.transformed) return;
if (this.field.isTerrain('electricterrain')) {
pokemon.addVolatile('quarkdrive');
} else if (!pokemon.volatiles['quarkdrive']?.fromBooster) {
Expand Down Expand Up @@ -4883,7 +4868,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
terashift: {
onPreStart(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== 'Terapagos' || pokemon.transformed) return;
if (pokemon.baseSpecies.baseSpecies !== 'Terapagos') return;
if (pokemon.species.forme !== 'Terastal') {
this.add('-activate', pokemon, 'ability: Tera Shift');
pokemon.formeChange('Terapagos-Terastal', this.effect, true);
Expand Down Expand Up @@ -5557,7 +5542,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
},
zerotohero: {
onSwitchOut(pokemon) {
if (pokemon.baseSpecies.baseSpecies !== 'Palafin' || pokemon.transformed) return;
if (pokemon.baseSpecies.baseSpecies !== 'Palafin') return;
if (pokemon.species.forme !== 'Hero') {
pokemon.formeChange('Palafin-Hero', this.effect, true);
}
Expand All @@ -5568,7 +5553,7 @@ export const Abilities: {[abilityid: string]: AbilityData} = {
onStart(pokemon) {
if (!this.effectState.switchingIn) return;
this.effectState.switchingIn = false;
if (pokemon.baseSpecies.baseSpecies !== 'Palafin' || pokemon.transformed) return;
if (pokemon.baseSpecies.baseSpecies !== 'Palafin') return;
if (!this.effectState.heroMessageDisplayed && pokemon.species.forme === 'Hero') {
this.add('-activate', pokemon, 'ability: Zero to Hero');
this.effectState.heroMessageDisplayed = true;
Expand Down
3 changes: 3 additions & 0 deletions sim/pokemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -820,6 +820,9 @@ export class Pokemon {

ignoringAbility() {
if (this.battle.gen >= 5 && !this.isActive) return true;

// Certain Abilities won't activate while Transformed, even if they ordinarily couldn't be suppressed (e.g. Disguise)
if (this.getAbility().flags['notransform'] && this.transformed) return true;
if (this.getAbility().flags['cantsuppress']) return false;
if (this.volatiles['gastroacid']) return true;

Expand Down
39 changes: 34 additions & 5 deletions test/sim/abilities/commander.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ describe('Commander', function () {
assert.cantMove(() => battle.p2.choose('move swordsdance', 'move sleeptalk'));
});

it(`should not work if either Pokemon is Transformed into Dondozo/Tatsugiri`, function () {
it(`should not work if another Pokemon is Transformed into Dondozo`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'wynaut', moves: ['sleeptalk']},
{species: 'dondozo', moves: ['sleeptalk']},
Expand All @@ -35,10 +35,26 @@ describe('Commander', function () {
assert.false(!!mewDondozo.volatiles['commanded']);
});

it(`should not work if Tatsugiri is Transformed, and should work if Dondozo is Transformed`, function () {
it(`should not work if another Pokemon is Transformed into Tatsugiri`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'wynaut', moves: ['sleeptalk']},
{species: 'tatsugiri', ability: 'commander', moves: ['sleeptalk']},
], [
{species: 'roggenrola', moves: ['sleeptalk']},
{species: 'sunkern', ability: 'commander', moves: ['transform']},
{species: 'dondozo', moves: ['transform']},
]]);

battle.makeChoices('auto', 'move sleeptalk, move transform 2');
battle.makeChoices('auto', 'switch 3, move sleeptalk');
const dondozo = battle.p2.active[0];
assert.false(!!dondozo.volatiles['commanded'], `Transformed Sunkern into another Tatsugiri should not trigger Commander`);
});

it(`should work if Tatsugiri is Transformed into another Pokemon with Commander`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'wynaut', moves: ['sleeptalk']},
{species: 'sunkern', ability: 'commander', moves: ['sleeptalk']},
], [
{species: 'roggenrola', moves: ['sleeptalk']},
{species: 'tatsugiri', ability: 'commander', moves: ['transform']},
Expand All @@ -48,11 +64,24 @@ describe('Commander', function () {
battle.makeChoices('auto', 'move sleeptalk, move transform 2');
battle.makeChoices('auto', 'switch 3, move sleeptalk');
const dondozo = battle.p2.active[0];
assert.false(!!dondozo.volatiles['commanded'], `Transformed Tatsugiri should not trigger Commander`);
assert(!!dondozo.volatiles['commanded']);
});

it(`should work if Dondozo is Transformed`, function () {
battle = common.createBattle({gameType: 'doubles'}, [[
{species: 'wynaut', moves: ['sleeptalk']},
{species: 'diglett', moves: ['sleeptalk']},
], [
{species: 'dondozo', moves: ['transform']},
{species: 'roggenrola', moves: ['sleeptalk']},
{species: 'tatsugiri', ability: 'commander', moves: ['sleeptalk']},

]]);

battle.makeChoices('auto', 'move transform 1, switch 3');
battle.makeChoices('auto', 'move transform 2, move sleeptalk');
battle.makeChoices('auto', 'move sleeptalk, switch 3');
assert(!!dondozo.volatiles['commanded'], `Transformed Dondozo should trigger Commander`);
const dondozo = battle.p2.active[0];
assert(!!dondozo.volatiles['commanded']);
});

it.skip(`should cause Tatsugiri to dodge all moves, including moves which normally bypass semi-invulnerability`, function () {
Expand Down
13 changes: 13 additions & 0 deletions test/sim/abilities/disguise.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,17 @@ describe('Disguise', function () {
battle.makeChoices();
assert(battle.log.every(line => !line.startsWith('|-crit')));
});

it(`should not work while Transformed`, function () {
battle = common.createBattle([[
{species: 'Mimikyu', ability: 'disguise', moves: ['transform']},
], [
{species: 'Mimikyu', ability: 'disguise', moves: ['sleeptalk', 'aerialace']},
]]);
battle.makeChoices();
battle.makeChoices('auto', 'move aerialace');
const transformedMimikyu = battle.p1.active[0];
assert.species(transformedMimikyu, 'Mimikyu', `Transformed Mimikyu should not have changed to Mimikyu-busted after taking damage`);
assert.false.fullHP(transformedMimikyu);
});
});
23 changes: 21 additions & 2 deletions test/sim/abilities/iceface.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,27 @@ describe('Ice Face', function () {
assert.hurts(eiscue, () => battle.makeChoices());
});

it(`should not trigger if the Pokemon was KOed`, function () {
// TODO: Make compatible with gen 9
it(`should not work while Transformed`, function () {
battle = common.createBattle([[
{species: 'Eiscue', ability: 'iceface', moves: ['transform']},
{species: 'Wynaut', moves: ['sleeptalk']},
], [
{species: 'Eiscue', ability: 'iceface', moves: ['sleeptalk', 'aerialace', 'hail']},
]]);
battle.makeChoices();
battle.makeChoices('move aerialace', 'move aerialace');
const transformedEiscue = battle.p1.active[0];
assert.species(transformedEiscue, 'Eiscue', `Transformed Eiscue should not have changed to Eiscue-Noice after taking physical damage`);
assert.false.fullHP(transformedEiscue);

battle.makeChoices('switch 2', 'auto');
battle.makeChoices('switch 2', 'auto');
battle.makeChoices('move transform', 'auto');
battle.makeChoices('move hail', 'auto');
assert.species(transformedEiscue, 'Eiscue-Noice', `Transformed Eiscue should not have changed to Eiscue after hail was set`);
});

it(`should not trigger if the Pokemon was KOed by Max Hailstorm`, function () {
battle = common.gen(8).createBattle([[
{species: 'Eiscue', level: 1, ability: 'iceface', moves: ['sleeptalk']},
], [
Expand Down
13 changes: 13 additions & 0 deletions test/sim/abilities/protosynthesis.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,17 @@ describe('Protosynthesis', function () {
battle.makeChoices('move recover', 'move venoshock');
assert.bounded(tail.maxhp - tail.hp, [84, 102]);
});

it(`should not activate while the user is Transformed`, function () {
battle = common.createBattle([[
{species: 'Torkoal', ability: 'drought', moves: ['sleeptalk']},
{species: 'Ditto', ability: 'imposter', moves: ['transform']},
], [
{species: 'Roaring Moon', ability: 'protosynthesis', moves: ['sleeptalk']},
]]);

battle.makeChoices('switch 2', 'auto');
const dittoMoon = battle.p1.active[0];
assert(!dittoMoon.volatiles['protosynthesis']);
});
});

0 comments on commit cd231ef

Please sign in to comment.