Disguise fix and changes

- Added `abilityTriggered` to pokemon battle data to not depend on hit counters.
- Ability and form change checks now depend on `abilityTriggered`.
- Instead of reducing move damage, damage is now directly modified and set to 1.
- All hits but failed and non effective are set as just effective.
- Made it so confusion damage also triggers Disguise.
- Added both ability's messages.

With these changes, for the correct functioning of the ability should be the substute interaction.
pull/205/head
Flashfyre 2024-04-19 17:19:24 -04:00 committed by NxKarim
parent 77c3a5ad78
commit f73e915ec7
3 changed files with 68 additions and 19 deletions

View File

@ -304,19 +304,28 @@ export class ReceivedTypeDamageMultiplierAbAttr extends ReceivedMoveDamageMultip
} }
} }
export class PreDefendMovePowerToOneAbAttr extends ReceivedMoveDamageMultiplierAbAttr { export class PreDefendReceivedMoveNullifierAbAttr extends PreDefendAbAttr {
protected condition: PokemonDefendCondition;
constructor(condition: PokemonDefendCondition) { constructor(condition: PokemonDefendCondition) {
super(condition, 1); super();
this.condition = condition;
} }
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean { applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if (this.condition(pokemon, attacker, move.getMove())) { if (this.condition(pokemon, attacker, move.getMove()) && (args[1] as Utils.NumberHolder).value != HitResult.NO_EFFECT && (args[1] as Utils.NumberHolder).value != HitResult.FAIL) {
(args[0] as Utils.NumberHolder).value = 1; (args[0] as Utils.NumberHolder).value = 1;
(args[1] as Utils.NumberHolder).value = HitResult.EFFECTIVE;
return true; return true;
} }
return false; return false;
} }
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
return `Its disguise served it as a decoy!`;
}
} }
export class TypeImmunityAbAttr extends PreDefendAbAttr { export class TypeImmunityAbAttr extends PreDefendAbAttr {
@ -445,19 +454,27 @@ export class PostDefendAbAttr extends AbAttr {
} }
export class PostDefendDisguiseAbAttr extends PostDefendAbAttr { export class PostDefendDisguiseAbAttr extends PostDefendAbAttr {
protected condition: PokemonDefendCondition;
constructor(condition: PokemonDefendCondition) {
super(true);
this.condition = condition;
}
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
if (pokemon.formIndex == 0 && pokemon.battleData.hitCount != 0 && (move.getMove().category == MoveCategory.SPECIAL || move.getMove().category == MoveCategory.PHYSICAL)) {
const recoilDamage = Math.ceil((pokemon.getMaxHp() / 8) - attacker.turnData.damageDealt); if (this.condition(pokemon, attacker, move.getMove()) && (hitResult == HitResult.EFFECTIVE)) {
const damageDealt = attacker.turnData.damageDealt;
let recoilDamage = Math.round(pokemon.getMaxHp() / 8 - damageDealt);
if (!recoilDamage) if (!recoilDamage)
return false; return false;
pokemon.damageAndUpdate(recoilDamage, HitResult.OTHER); pokemon.damageAndUpdate(recoilDamage, HitResult.OTHER);
pokemon.battleData.abilityTriggered = true;
pokemon.turnData.damageTaken += recoilDamage; pokemon.turnData.damageTaken += recoilDamage;
pokemon.scene.queueMessage(getPokemonMessage(pokemon, '\'s disguise was busted!')); pokemon.scene.queueMessage(getPokemonMessage(pokemon, '\'s disguise was busted!'));
return true; return true;
} }
return false; return false;
} }
} }
@ -1666,6 +1683,25 @@ export class BlockNonDirectDamageAbAttr extends AbAttr {
} }
} }
export class DisguiseConfusionDamageInteractionAbAttr extends AbAttr {
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if(pokemon.battleData.abilityTriggered == true)
return false;
cancelled.value = true;
pokemon.damageAndUpdate(Math.round(pokemon.getMaxHp() / 8), HitResult.OTHER);
pokemon.battleData.abilityTriggered = true;
pokemon.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeManualTrigger, false);
pokemon.scene.queueMessage(`Its disguise served it as a decoy!`);
return true;
}
getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string {
return `${pokemon.name}\'s disguise was busted!`;
}
}
export class BlockOneHitKOAbAttr extends AbAttr { export class BlockOneHitKOAbAttr extends AbAttr {
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
cancelled.value = true; cancelled.value = true;
@ -3143,12 +3179,13 @@ export function initAbilities() {
.attr(UnsuppressableAbilityAbAttr) .attr(UnsuppressableAbilityAbAttr)
.attr(NoFusionAbilityAbAttr), .attr(NoFusionAbilityAbAttr),
new Ability(Abilities.DISGUISE, 7) new Ability(Abilities.DISGUISE, 7)
.attr(PreDefendMovePowerToOneAbAttr, (target, user, move) => target.formIndex == 0 && target.getAttackTypeEffectiveness(move.type) > 0) .attr(DisguiseConfusionDamageInteractionAbAttr)
.attr(PostSummonFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) .attr(PreDefendReceivedMoveNullifierAbAttr, (target, user, move) => target.battleData.abilityTriggered == false)
.attr(PostBattleInitFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) .attr(PostDefendDisguiseAbAttr, (target, user, move) => target.battleData.abilityTriggered == false)
.attr(PostDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) .attr(PreDefendFormChangeAbAttr, p => p.battleData.abilityTriggered == false ? 0 : 1)
.attr(PreDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) .attr(PostSummonFormChangeAbAttr, p => p.battleData.abilityTriggered == false ? 0 : 1)
.attr(PostDefendDisguiseAbAttr) .attr(PostBattleInitFormChangeAbAttr, p => p.battleData.abilityTriggered == false ? 0 : 1)
.attr(PostDefendFormChangeAbAttr, p => p.battleData.abilityTriggered == false ? 0 : 1)
.attr(UncopiableAbilityAbAttr) .attr(UncopiableAbilityAbAttr)
.attr(UnswappableAbilityAbAttr) .attr(UnswappableAbilityAbAttr)
.attr(UnsuppressableAbilityAbAttr) .attr(UnsuppressableAbilityAbAttr)

View File

@ -8,7 +8,7 @@ import * as Utils from "../utils";
import { Moves } from "./enums/moves"; import { Moves } from "./enums/moves";
import { ChargeAttr, MoveFlags, allMoves } from "./move"; import { ChargeAttr, MoveFlags, allMoves } from "./move";
import { Type } from "./type"; import { Type } from "./type";
import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs } from "./ability"; import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs, DisguiseConfusionDamageInteractionAbAttr } from "./ability";
import { Abilities } from "./enums/abilities"; import { Abilities } from "./enums/abilities";
import { BattlerTagType } from "./enums/battler-tag-type"; import { BattlerTagType } from "./enums/battler-tag-type";
import { TerrainType } from "./terrain"; import { TerrainType } from "./terrain";
@ -226,8 +226,15 @@ export class ConfusedTag extends BattlerTag {
const def = pokemon.getBattleStat(Stat.DEF); const def = pokemon.getBattleStat(Stat.DEF);
const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100)); const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * (pokemon.randSeedInt(15, 85) / 100));
pokemon.scene.queueMessage('It hurt itself in its\nconfusion!'); pokemon.scene.queueMessage('It hurt itself in its\nconfusion!');
pokemon.damageAndUpdate(damage);
pokemon.battleData.hitCount++; const cancelled = new Utils.BooleanHolder(false);
applyAbAttrs(DisguiseConfusionDamageInteractionAbAttr, pokemon, cancelled);
if (!cancelled.value) {
pokemon.damageAndUpdate(damage);
pokemon.battleData.hitCount++;
}
(pokemon.scene.getCurrentPhase() as MovePhase).cancel(); (pokemon.scene.getCurrentPhase() as MovePhase).cancel();
} }
} }

View File

@ -27,7 +27,7 @@ import { TempBattleStat } from '../data/temp-battle-stat';
import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag'; import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag';
import { ArenaTagType } from "../data/enums/arena-tag-type"; import { ArenaTagType } from "../data/enums/arena-tag-type";
import { Biome } from "../data/enums/biome"; import { Biome } from "../data/enums/biome";
import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr } from '../data/ability'; import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, PreDefendReceivedMoveNullifierAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr } from '../data/ability';
import { Abilities } from "#app/data/enums/abilities"; import { Abilities } from "#app/data/enums/abilities";
import PokemonData from '../system/pokemon-data'; import PokemonData from '../system/pokemon-data';
import Battle, { BattlerIndex } from '../battle'; import Battle, { BattlerIndex } from '../battle';
@ -1412,6 +1412,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
damage.value = 0; damage.value = 0;
} }
let preResult = new Utils.NumberHolder(result);
applyPreDefendAbAttrs(PreDefendReceivedMoveNullifierAbAttr, this, source, battlerMove, cancelled, damage , preResult);
result = (preResult as Utils.NumberHolder).value;
console.log('damage', damage.value, move.name, power.value, sourceAtk, targetDef); console.log('damage', damage.value, move.name, power.value, sourceAtk, targetDef);
if (damage.value) { if (damage.value) {
@ -3054,6 +3058,7 @@ export class PokemonBattleData {
public hitCount: integer = 0; public hitCount: integer = 0;
public endured: boolean = false; public endured: boolean = false;
public berriesEaten: BerryType[] = []; public berriesEaten: BerryType[] = [];
public abilityTriggered: boolean = false;
} }
export class PokemonBattleSummonData { export class PokemonBattleSummonData {