Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Terastallize Ogerpon and Terapagos with different Tera types #10814

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
8 changes: 4 additions & 4 deletions data/abilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1167,7 +1167,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
embodyaspectcornerstone: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Cornerstone-Tera' &&
if (pokemon.baseSpecies.name === 'Ogerpon-Cornerstone-Tera' && pokemon.terastallized &&
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({def: 1}, pokemon);
Expand All @@ -1180,7 +1180,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
embodyaspecthearthflame: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Hearthflame-Tera' &&
if (pokemon.baseSpecies.name === 'Ogerpon-Hearthflame-Tera' && pokemon.terastallized &&
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({atk: 1}, pokemon);
Expand All @@ -1193,7 +1193,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
embodyaspectteal: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Teal-Tera' &&
if (pokemon.baseSpecies.name === 'Ogerpon-Teal-Tera' && pokemon.terastallized &&
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({spe: 1}, pokemon);
Expand All @@ -1206,7 +1206,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = {
},
embodyaspectwellspring: {
onStart(pokemon) {
if (pokemon.baseSpecies.name === 'Ogerpon-Wellspring-Tera' &&
if (pokemon.baseSpecies.name === 'Ogerpon-Wellspring-Tera' && pokemon.terastallized &&
this.effectState.embodied !== pokemon.previouslySwitchedIn) {
this.effectState.embodied = pokemon.previouslySwitchedIn;
this.boost({spd: 1}, pokemon);
Expand Down
6 changes: 3 additions & 3 deletions data/cg-teams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -346,8 +346,8 @@ export default class TeamGenerator {
const hasTeraBlast = moves.some(m => m.id === 'terablast');
const hasRevelationDance = moves.some(m => m.id === 'revelationdance');
let teraType;
if (species.forceTeraType) {
teraType = species.forceTeraType;
if (species.requiredTeraType) {
teraType = species.requiredTeraType;
} else if (item === 'blacksludge' && this.prng.randomChance(2, 3)) {
teraType = 'Poison';
} else if (hasTeraBlast && ability === 'Contrary' && this.prng.randomChance(2, 3)) {
Expand Down Expand Up @@ -728,7 +728,7 @@ export default class TeamGenerator {

// Oricorio should rarely get Tera Blast, as Revelation Dance is strictly better
// Tera Blast is also bad on species with forced Tera types, a.k.a. Ogerpon and Terapagos
if (move.id === 'terablast' && (species.baseSpecies === 'Oricorio' || species.forceTeraType)) weight *= 0.5;
if (move.id === 'terablast' && (species.baseSpecies === 'Oricorio' || species.requiredTeraType)) weight *= 0.5;

return weight;
}
Expand Down
2 changes: 1 addition & 1 deletion data/mods/mixandmega/scripts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ export const Scripts: ModdedBattleScriptsData = {

let type = pokemon.teraType;
if (pokemon.species.baseSpecies !== 'Ogerpon' && pokemon.getItem().name.endsWith('Mask')) {
type = this.dex.species.get(pokemon.getItem().forcedForme).forceTeraType!;
type = this.dex.species.get(pokemon.getItem().forcedForme).requiredTeraType!;
}
this.battle.add('-terastallize', pokemon, type);
pokemon.terastallized = type;
Expand Down
22 changes: 11 additions & 11 deletions data/pokedex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18195,7 +18195,7 @@ export const Pokedex: import('../sim/dex-species').SpeciesDataTable = {
eggGroups: ["Undiscovered"],
otherFormes: ["Ogerpon-Wellspring", "Ogerpon-Hearthflame", "Ogerpon-Cornerstone", "Ogerpon-Teal-Tera", "Ogerpon-Wellspring-Tera", "Ogerpon-Hearthflame-Tera", "Ogerpon-Cornerstone-Tera"],
formeOrder: ["Ogerpon", "Ogerpon-Wellspring", "Ogerpon-Hearthflame", "Ogerpon-Cornerstone", "Ogerpon-Teal-Tera", "Ogerpon-Wellspring-Tera", "Ogerpon-Hearthflame-Tera", "Ogerpon-Cornerstone-Tera"],
forceTeraType: "Grass",
requiredTeraType: "Grass",
},
ogerponwellspring: {
num: 1017,
Expand All @@ -18212,7 +18212,7 @@ export const Pokedex: import('../sim/dex-species').SpeciesDataTable = {
eggGroups: ["Undiscovered"],
requiredItem: "Wellspring Mask",
changesFrom: "Ogerpon",
forceTeraType: "Water",
requiredTeraType: "Water",
},
ogerponhearthflame: {
num: 1017,
Expand All @@ -18229,7 +18229,7 @@ export const Pokedex: import('../sim/dex-species').SpeciesDataTable = {
eggGroups: ["Undiscovered"],
requiredItem: "Hearthflame Mask",
changesFrom: "Ogerpon",
forceTeraType: "Fire",
requiredTeraType: "Fire",
},
ogerponcornerstone: {
num: 1017,
Expand All @@ -18246,7 +18246,7 @@ export const Pokedex: import('../sim/dex-species').SpeciesDataTable = {
eggGroups: ["Undiscovered"],
requiredItem: "Cornerstone Mask",
changesFrom: "Ogerpon",
forceTeraType: "Rock",
requiredTeraType: "Rock",
},
ogerpontealtera: {
num: 1017,
Expand All @@ -18262,7 +18262,7 @@ export const Pokedex: import('../sim/dex-species').SpeciesDataTable = {
color: "Green",
eggGroups: ["Undiscovered"],
battleOnly: "Ogerpon",
forceTeraType: "Grass",
requiredTeraType: "Grass",
},
ogerponwellspringtera: {
num: 1017,
Expand All @@ -18279,7 +18279,7 @@ export const Pokedex: import('../sim/dex-species').SpeciesDataTable = {
eggGroups: ["Undiscovered"],
requiredItem: "Wellspring Mask",
battleOnly: "Ogerpon-Wellspring",
forceTeraType: "Water",
requiredTeraType: "Water",
},
ogerponhearthflametera: {
num: 1017,
Expand All @@ -18296,7 +18296,7 @@ export const Pokedex: import('../sim/dex-species').SpeciesDataTable = {
eggGroups: ["Undiscovered"],
requiredItem: "Hearthflame Mask",
battleOnly: "Ogerpon-Hearthflame",
forceTeraType: "Fire",
requiredTeraType: "Fire",
},
ogerponcornerstonetera: {
num: 1017,
Expand All @@ -18313,7 +18313,7 @@ export const Pokedex: import('../sim/dex-species').SpeciesDataTable = {
eggGroups: ["Undiscovered"],
requiredItem: "Cornerstone Mask",
battleOnly: "Ogerpon-Cornerstone",
forceTeraType: "Rock",
requiredTeraType: "Rock",
},
archaludon: {
num: 1018,
Expand Down Expand Up @@ -18404,7 +18404,7 @@ export const Pokedex: import('../sim/dex-species').SpeciesDataTable = {
eggGroups: ["Undiscovered"],
otherFormes: ["Terapagos-Terastal", "Terapagos-Stellar"],
formeOrder: ["Terapagos", "Terapagos-Terastal", "Terapagos-Stellar"],
forceTeraType: "Stellar",
requiredTeraType: "Stellar",
},
terapagosterastal: {
num: 1024,
Expand All @@ -18419,7 +18419,7 @@ export const Pokedex: import('../sim/dex-species').SpeciesDataTable = {
color: "Blue",
eggGroups: ["Undiscovered"],
battleOnly: "Terapagos",
forceTeraType: "Stellar",
requiredTeraType: "Stellar",
},
terapagosstellar: {
num: 1024,
Expand All @@ -18434,7 +18434,7 @@ export const Pokedex: import('../sim/dex-species').SpeciesDataTable = {
color: "Blue",
eggGroups: ["Undiscovered"],
battleOnly: "Terapagos",
forceTeraType: "Stellar",
requiredTeraType: "Stellar",
},
pecharunt: {
num: 1025,
Expand Down
12 changes: 9 additions & 3 deletions sim/battle-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1932,6 +1932,11 @@ export class BattleActions {
}

terastallize(pokemon: Pokemon) {
if (pokemon.species.baseSpecies === 'Ogerpon' && !['Fire', 'Grass', 'Rock', 'Water'].includes(pokemon.teraType)) {
this.battle.hint("If Ogerpon Terastallizes into a type other than Fire, Grass, Rock, or Water, the game softlocks.");
return;
}

if (pokemon.illusion && ['Ogerpon', 'Terapagos'].includes(pokemon.illusion.species.baseSpecies)) {
this.battle.singleEvent('End', this.dex.abilities.get('Illusion'), pokemon.abilityState, pokemon);
}
Expand All @@ -1946,10 +1951,11 @@ export class BattleActions {
pokemon.knownType = true;
pokemon.apparentType = type;
if (pokemon.species.baseSpecies === 'Ogerpon') {
const tera = pokemon.species.id === 'ogerpon' ? 'tealtera' : 'tera';
pokemon.formeChange(pokemon.species.id + tera, null, true);
let ogerponSpecies = toID(pokemon.species.battleOnly || pokemon.species.id);
ogerponSpecies += ogerponSpecies === 'ogerpon' ? 'tealtera' : 'tera';
pokemon.formeChange(ogerponSpecies, null, true);
}
if (pokemon.species.name === 'Terapagos-Terastal' && type === 'Stellar') {
if (pokemon.species.name === 'Terapagos-Terastal') {
pokemon.formeChange('Terapagos-Stellar', null, true);
pokemon.baseMaxhp = Math.floor(Math.floor(
2 * pokemon.species.baseStats['hp'] + pokemon.set.ivs['hp'] + Math.floor(pokemon.set.evs['hp'] / 4) + 100
Expand Down
2 changes: 1 addition & 1 deletion sim/dex-species.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ export class Species extends BasicEffect implements Readonly<BasicEffect & Speci
/** True if a Pokemon species is incapable of dynamaxing */
readonly cannotDynamax?: boolean;
/** The Tera Type this Pokemon is forced to use */
readonly forceTeraType?: string;
readonly requiredTeraType?: string;
/** What it transforms from, if a pokemon is a forme that is only accessible in battle. */
readonly battleOnly?: string | string[];
/** Required item. Do not use this directly; see requiredItems. */
Expand Down
14 changes: 13 additions & 1 deletion sim/pokemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1387,14 +1387,26 @@ export class Pokemon {
this.illusion ? this.illusion.species.name : species.baseSpecies;
if (isPermanent) {
this.baseSpecies = rawSpecies;
this.details = species.name + (this.level === 100 ? '' : ', L' + this.level) +
let displayedSpeciesName = species.name;
if (species.baseSpecies === 'Ogerpon' && this.terastallized && this.teraType !== species.requiredTeraType) {
switch (this.teraType) {
andrebastosdias marked this conversation as resolved.
Show resolved Hide resolved
case 'Grass': displayedSpeciesName = 'Ogerpon-Teal-Tera'; break;
case 'Water': displayedSpeciesName = 'Ogerpon-Wellspring-Tera'; break;
case 'Fire': displayedSpeciesName = 'Ogerpon-Hearthflame-Tera'; break;
case 'Rock': displayedSpeciesName = 'Ogerpon-Cornerstone-Tera'; break;
}
}
this.details = displayedSpeciesName + (this.level === 100 ? '' : ', L' + this.level) +
(this.gender === '' ? '' : ', ' + this.gender) + (this.set.shiny ? ', shiny' : '');
let details = (this.illusion || this).details;
if (this.terastallized) details += `, tera:${this.terastallized}`;
this.battle.add('detailschange', this, details);
if (!source) {
// Tera forme
// Ogerpon/Terapagos text goes here
if (species.baseSpecies === 'Ogerpon' && this.terastallized && this.teraType !== species.requiredTeraType) {
this.battle.hint(`Ogerpon terastallized into ${species.name}, but it has taken the appearance of ${displayedSpeciesName} due to its tera type being ${this.teraType}.`);
}
} else if (source.effectType === 'Item') {
this.canTerastallize = null; // National Dex behavior
if (source.zMove) {
Expand Down
13 changes: 4 additions & 9 deletions sim/team-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -582,10 +582,6 @@ export class TeamValidator {
name = `${set.name} (${set.species})`;
}

if (!set.teraType && this.gen === 9) {
set.teraType = species.types[0];
}

if (!set.level) set.level = ruleTable.defaultLevel;

let adjustLevel = ruleTable.adjustLevel;
Expand Down Expand Up @@ -682,13 +678,12 @@ export class TeamValidator {
set.hpType = type.name;
}
}
if (species.forceTeraType) {
set.teraType = species.forceTeraType;
}
if (set.teraType) {
const type = dex.types.get(set.teraType);
if (set.teraType || this.gen === 9) {
const type = dex.types.get(set.teraType || species.requiredTeraType || species.types[0]);
if (!type.exists || type.isNonstandard) {
problems.push(`${name}'s Terastal type (${set.teraType}) is invalid.`);
} else if (species.requiredTeraType && species.requiredTeraType !== type.name && ruleTable.has('obtainablemisc')) {
problems.push(`${species.name}'s Terastal type needs to be ${species.requiredTeraType}, please fix it.`);
} else {
set.teraType = type.name;
}
Expand Down
104 changes: 104 additions & 0 deletions test/sim/misc/ogerpon.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,108 @@ describe(`[Hackmons] Ogerpon`, function () {
battle.makeChoices('switch 2', 'auto');
assert.equal(ogerpon.ability, 'embodyaspectteal', `Ogerpon's ability should be Embody Aspect after switching out`);
});

it(`won't Terastallize into a type other than Fire, Grass, Rock or Water`, function () {
battle = common.gen(9).createBattle([[
{species: 'ogerponwellspringtera', ability: 'embodyaspectwellspring', moves: ['sleeptalk'], teraType: 'Electric'},
], [
{species: 'silicobra', moves: ['stealthrock']},
]]);
const ogerpon = battle.p1.active[0];
battle.makeChoices('move sleeptalk terastallize', 'auto');
assert.false(!!ogerpon.terastallized);
});

// https://www.smogon.com/forums/threads/ogerpon-teal-tera-tera-can-exist.3742851/post-10132811
it(`can Terastallize into the type of another mask`, function () {
battle = common.gen(9).createBattle([[
{species: 'ogerponwellspring', ability: 'waterabsorb', moves: ['ivycudgel'], teraType: 'Rock'},
], [
{species: 'seismitoad', ability: 'waterabsorb', moves: ['stealthrock']},
]]);
const ogerpon = battle.p1.active[0];
battle.makeChoices('move ivycudgel terastallize', 'auto');
assert.species(ogerpon, 'Ogerpon-Wellspring-Tera');
assert.equal(ogerpon.ability, 'embodyaspectwellspring');
assert.statStage(ogerpon, 'spd', 1);
assert.equal(ogerpon.getTypes().join(''), 'Rock');
assert.fullHP(battle.p2.active[0]);
assert(battle.log.includes('|detailschange|p1a: Ogerpon|Ogerpon-Cornerstone-Tera, F, tera:Rock'));
});

// https://www.smogon.com/forums/threads/ogerpon-teal-tera-tera-can-exist.3742851/post-10132811
it(`Tera form can Terastallize`, function () {
battle = common.gen(9).createBattle([[
{species: 'ogerponwellspringtera', ability: 'embodyaspectwellspring', moves: ['ivycudgel'], teraType: 'Water'},
], [
{species: 'seismitoad', ability: 'waterabsorb', moves: ['stealthrock']},
]]);
const ogerpon = battle.p1.active[0];
battle.makeChoices('move ivycudgel terastallize', 'auto');
assert.species(ogerpon, 'Ogerpon-Wellspring-Tera');
assert.equal(ogerpon.ability, 'embodyaspectwellspring');
assert.statStage(ogerpon, 'spd', 1);
assert.equal(ogerpon.getTypes().join(''), 'Water');
assert.fullHP(battle.p2.active[0]);
assert(battle.log.includes('|detailschange|p1a: Ogerpon|Ogerpon-Wellspring-Tera, F, tera:Water'));
});

// https://www.smogon.com/forums/threads/ogerpon-teal-tera-tera-can-exist.3742851/post-10132811
it(`Tera form can Terastallize into the type of another mask`, function () {
battle = common.gen(9).createBattle([[
{species: 'ogerponwellspringtera', ability: 'embodyaspectwellspring', moves: ['ivycudgel'], teraType: 'Rock'},
], [
{species: 'seismitoad', ability: 'waterabsorb', moves: ['stealthrock']},
]]);
const ogerpon = battle.p1.active[0];
battle.makeChoices('move ivycudgel terastallize', 'auto');
assert.species(ogerpon, 'Ogerpon-Wellspring-Tera');
assert.equal(ogerpon.ability, 'embodyaspectwellspring');
assert.statStage(ogerpon, 'spd', 1);
assert.equal(ogerpon.getTypes().join(''), 'Rock');
assert.fullHP(battle.p2.active[0]);
assert(battle.log.includes('|detailschange|p1a: Ogerpon|Ogerpon-Cornerstone-Tera, F, tera:Rock'));
});

// https://www.smogon.com/forums/threads/scarlet-violet-battle-mechanics-research.3709545/post-10404934
it(`can Terastallize into any type if transformed, but it won't change form`, function () {
battle = common.gen(9).createBattle([[
{species: 'ogerponwellspring', ability: 'waterabsorb', moves: ['transform', 'ivycudgel'], teraType: 'Fairy'},
{species: 'silicobra', moves: ['stealthrock']},
], [
{species: 'seismitoad', ability: 'waterabsorb', moves: ['sleeptalk']},
]]);
const ogerpon = battle.p1.active[0];
battle.makeChoices('move transform', 'auto');
battle.makeChoices('move sleeptalk terastallize', 'auto');
assert.equal(ogerpon.baseSpecies.name, 'Ogerpon-Wellspring');
assert.species(ogerpon, 'Seismitoad');
assert.equal(ogerpon.getTypes().join(''), 'Fairy');

battle.makeChoices('switch 2', 'auto');
battle.makeChoices('switch 2', 'auto');
battle.makeChoices('move ivycudgel', 'auto');
assert.species(ogerpon, 'Ogerpon-Wellspring');
assert.equal(ogerpon.ability, 'waterabsorb');
assert.statStage(ogerpon, 'spd', 0);
assert.equal(ogerpon.getTypes().join(''), 'Fairy');
assert.fullHP(battle.p2.active[0]);
assert.false(battle.log.includes('|detailschange|'));
});

// https://www.smogon.com/forums/threads/ogerpon-teal-tera-tera-can-exist.3742851/post-10132811
it(`Embody Aspect should not activate unless the user is Terastallized`, function () {
battle = common.gen(9).createBattle([[
{species: 'ogerponwellspringtera', ability: 'embodyaspectwellspring', moves: ['sleeptalk'], teraType: 'Water'},
], [
{species: 'silicobra', moves: ['stealthrock']},
]]);
const ogerpon = battle.p1.active[0];
battle.makeChoices();
assert.species(ogerpon, 'Ogerpon-Wellspring-Tera');
assert.statStage(ogerpon, 'spd', 0);
battle.makeChoices('move sleeptalk terastallize', 'auto');
assert.species(ogerpon, 'Ogerpon-Wellspring-Tera');
assert.statStage(ogerpon, 'spd', 1);
});
});
Loading