Skip to content

Commit

Permalink
Refactor Disguise to work like Ice Face
Browse files Browse the repository at this point in the history
  • Loading branch information
DayKev committed Jun 28, 2024
1 parent d5b1459 commit 56325b2
Show file tree
Hide file tree
Showing 7 changed files with 299 additions and 156 deletions.
5 changes: 5 additions & 0 deletions src/battle-scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1127,6 +1127,11 @@ export default class BattleScene extends SceneBase {
if (pokemon.species.speciesId === Species.EISCUE && pokemon.hasAbility(Abilities.ICE_FACE) && pokemon.formIndex === 1) {
this.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
}
// Only trigger form change when Mimikyu is in Busted form
// Hardcoded Mimikyu for now in case it is fused with another pokemon
if (pokemon.species.speciesId === Species.MIMIKYU && pokemon.hasAbility(Abilities.DISGUISE) && pokemon.formIndex === 1) {
this.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
}

pokemon.resetBattleData();
applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon);
Expand Down
134 changes: 52 additions & 82 deletions src/data/ability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -245,25 +245,6 @@ export class PreDefendAbAttr extends AbAttr {
}
}

export class PreDefendFormChangeAbAttr extends PreDefendAbAttr {
private formFunc: (p: Pokemon) => integer;

constructor(formFunc: ((p: Pokemon) => integer)) {
super(true);

this.formFunc = formFunc;
}

applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
const formIndex = this.formFunc(pokemon);
if (formIndex !== pokemon.formIndex) {
pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
return true;
}

return false;
}
}
export class PreDefendFullHpEndureAbAttr extends PreDefendAbAttr {
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if (pokemon.hp === pokemon.getMaxHp() &&
Expand Down Expand Up @@ -327,21 +308,6 @@ export class ReceivedTypeDamageMultiplierAbAttr extends ReceivedMoveDamageMultip
}
}

export class PreDefendMoveDamageToOneAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
constructor(condition: PokemonDefendCondition) {
super(condition, 1);
}

applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if (this.condition(pokemon, attacker, move)) {
(args[0] as Utils.NumberHolder).value = Math.floor(pokemon.getMaxHp() / 8);
return true;
}

return false;
}
}

/**
* Determines whether a Pokemon is immune to a move because of an ability.
* @extends PreDefendAbAttr
Expand Down Expand Up @@ -490,45 +456,6 @@ export class PostDefendAbAttr extends AbAttr {
}
}

export class PostDefendDisguiseAbAttr extends PostDefendAbAttr {

applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
if (pokemon.formIndex === 0 && pokemon.battleData.hitCount !== 0 && (move.category === MoveCategory.SPECIAL || move.category === MoveCategory.PHYSICAL)) {

const recoilDamage = Math.ceil((pokemon.getMaxHp() / 8) - attacker.turnData.damageDealt);
if (!recoilDamage) {
return false;
}
pokemon.damageAndUpdate(recoilDamage, HitResult.OTHER);
pokemon.turnData.damageTaken += recoilDamage;
pokemon.scene.queueMessage(getPokemonMessage(pokemon, "'s disguise was busted!"));
return true;
}

return false;
}
}

export class PostDefendFormChangeAbAttr extends PostDefendAbAttr {
private formFunc: (p: Pokemon) => integer;

constructor(formFunc: ((p: Pokemon) => integer)) {
super(true);

this.formFunc = formFunc;
}

applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean {
const formIndex = this.formFunc(pokemon);
if (formIndex !== pokemon.formIndex) {
pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
return true;
}

return false;
}
}

export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr {
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
const attackPriority = new Utils.IntegerHolder(move.priority);
Expand Down Expand Up @@ -3861,6 +3788,54 @@ export class IceFaceBlockPhysicalAbAttr extends ReceivedMoveDamageMultiplierAbAt
}
}

/**
* Takes no damage from the first hit of a damaging move.
* This is used in the Disguise ability.
*/
export class DisguiseBlockDamageAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
private multiplier: number;

constructor(condition: PokemonDefendCondition, multiplier: number) {
super(condition, multiplier);

this.multiplier = multiplier;
}

/**
* Applies the Disguise pre-defense ability to the Pokémon.
* Removes BattlerTagType.DISGUISE when hit by an attack and is in its Disguised form.
*
* @param {Pokemon} pokemon - The Pokémon with the Disguise ability.
* @param {boolean} passive - Whether the ability is passive.
* @param {Pokemon} attacker - The attacking Pokémon.
* @param {PokemonMove} move - The move being used.
* @param {Utils.BooleanHolder} cancelled - A holder for whether the move was cancelled.
* @param {any[]} args - Additional arguments.
* @returns {boolean} - Whether the immunity was applied.
*/
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if (this.condition(pokemon, attacker, move)) {
(args[0] as Utils.NumberHolder).value = this.multiplier;
pokemon.removeTag(BattlerTagType.DISGUISE);
pokemon.damageAndUpdate(Math.floor(pokemon.getMaxHp() / 8), HitResult.OTHER);
return true;
}

return false;
}

/**
* Gets the message triggered when the Pokémon avoids damage using the Disguise ability.
* @param {Pokemon} pokemon - The Pokémon with the Disguise ability.
* @param {string} abilityName - The name of the ability.
* @param {...any} args - Additional arguments.
* @returns {string} - The trigger message.
*/
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
return i18next.t("abilityTriggers:disguiseAvoidedDamage", { pokemonName: pokemon.name, abilityName: abilityName });
}
}

/**
* If a Pokémon with this Ability selects a damaging move, it has a 30% chance of going first in its priority bracket. If the Ability activates, this is announced at the start of the turn (after move selection).
*
Expand Down Expand Up @@ -4796,20 +4771,15 @@ export function initAbilities() {
.attr(NoFusionAbilityAbAttr)
.bypassFaint(),
new Ability(Abilities.DISGUISE, 7)
.attr(PreDefendMoveDamageToOneAbAttr, (target, user, move) => target.formIndex === 0 && target.getAttackTypeEffectiveness(move.type, user) > 0)
.attr(PostSummonFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
.attr(PostBattleInitFormChangeAbAttr, () => 0)
.attr(PostDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
.attr(PreDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
.attr(PostDefendDisguiseAbAttr)
.attr(UncopiableAbilityAbAttr)
.attr(UnswappableAbilityAbAttr)
.attr(UnsuppressableAbilityAbAttr)
.attr(NoTransformAbilityAbAttr)
.attr(NoFusionAbilityAbAttr)
.bypassFaint()
.ignorable()
.partial(),
// Add BattlerTagType.DISGUISE if the pokemon is in its disguised form
.conditionalAttr(pokemon => pokemon.formIndex === 0, PostSummonAddBattlerTagAbAttr, BattlerTagType.DISGUISE, 0, false)
.attr(DisguiseBlockDamageAbAttr, (target, user, move) => (move.category === MoveCategory.PHYSICAL || move.category === MoveCategory.SPECIAL) && !!target.getTag(BattlerTagType.DISGUISE), 0)
.ignorable(),
new Ability(Abilities.BATTLE_BOND, 7)
.attr(PostVictoryFormChangeAbAttr, () => 2)
.attr(PostBattleInitFormChangeAbAttr, () => 1)
Expand Down
50 changes: 50 additions & 0 deletions src/data/battler-tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1535,6 +1535,54 @@ export class IceFaceTag extends BattlerTag {
}
}

/**
* Provides the Disguise ability's effects.
*/
export class DisguiseTag extends BattlerTag {
constructor(sourceMove: Moves) {
super(BattlerTagType.DISGUISE, BattlerTagLapseType.CUSTOM, 1, sourceMove);
}

/**
* Determines if the Disguise tag can be added to the Pokémon.
* @param {Pokemon} pokemon - The Pokémon to which the tag might be added.
* @returns {boolean} - True if the tag can be added, false otherwise.
*/
canAdd(pokemon: Pokemon): boolean {
const isFormDisguised = pokemon.formIndex === 0;

// Hard code Mimikyu for now, this is to prevent the game from crashing if fused pokemon has Disguise
if (pokemon.species.speciesId === Species.MIMIKYU && isFormDisguised) {
return true;
}
return false;
}

/**
* Applies the Disguise tag to the Pokémon.
* Triggers a form change to Disguised if the Pokémon is not in its Disguised form.
* @param {Pokemon} pokemon - The Pokémon to which the tag is added.
*/
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);

if (pokemon.formIndex !== 0) {
pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
}
}

/**
* Removes the Disguise tag from the Pokémon.
* Triggers a form change to Busted when the tag is removed.
* @param {Pokemon} pokemon - The Pokémon from which the tag is removed.
*/
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);

pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger);
}
}

export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourceMove: Moves, sourceId: integer): BattlerTag {
switch (tagType) {
case BattlerTagType.RECHARGING:
Expand Down Expand Up @@ -1652,6 +1700,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
return new DestinyBondTag(sourceMove, sourceId);
case BattlerTagType.ICE_FACE:
return new IceFaceTag(sourceMove);
case BattlerTagType.DISGUISE:
return new DisguiseTag(sourceMove);
case BattlerTagType.NONE:
default:
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
Expand Down
3 changes: 3 additions & 0 deletions src/data/pokemon-forms.ts
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,9 @@ export function getSpeciesFormChangeMessage(pokemon: Pokemon, formChange: Specie
if (isRevert) {
return `${prefix}${pokemon.name} reverted\nto its original form!`;
}
if (pokemon.species.speciesId === Species.MIMIKYU) {
return "Its disguise served it as a decoy!";
}
return `${prefix}${preName} changed form!`;
}

Expand Down
3 changes: 2 additions & 1 deletion src/enums/battler-tag-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,6 @@ export enum BattlerTagType {
MINIMIZED = "MINIMIZED",
DESTINY_BOND = "DESTINY_BOND",
CENTER_OF_ATTENTION = "CENTER_OF_ATTENTION",
ICE_FACE = "ICE_FACE"
ICE_FACE = "ICE_FACE",
DISGUISE = "DISGUISE"
}
1 change: 1 addition & 0 deletions src/locales/en/ability-trigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ export const abilityTriggers: SimpleTranslationEntries = {
"trace": "{{pokemonName}} copied {{targetName}}'s\n{{abilityName}}!",
"windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!",
"quickDraw": "{{pokemonName}} can act faster than normal, thanks to its Quick Draw!",
"disguiseAvoidedDamage" : "{{pokemonName}}'s disguise was busted!",
} as const;
Loading

0 comments on commit 56325b2

Please sign in to comment.