[Move][Mirror] Update HitTagAttr attributes v2 (#4297)
* [Move] Updated HitAttr tags Affects Whirlwind/Fly, Steamroller/Minimize, and Malicious Moonsault/Minimize * [Move] Update for MinimizeAccuracyAttr Affects Steamroller and Malicious Moonsault * add: whirlwind test * add: steamroller test * rename: `AlwaysHitMinimizeAttr` (from `MinimizeAccuracyAttr`) * rename: `DealsDoubleDamageToTagAttr` (from `HitsTagAttr`) --------- Co-authored-by: chaosgrimmon <31082757+chaosgrimmon@users.noreply.github.com>
This commit is contained in:
parent
e386504977
commit
6030b780f2
|
@ -3839,7 +3839,7 @@ export class StormAccuracyAttr extends VariableAccuracyAttr {
|
|||
* @extends VariableAccuracyAttr
|
||||
* @see {@linkcode apply}
|
||||
*/
|
||||
export class MinimizeAccuracyAttr extends VariableAccuracyAttr {
|
||||
export class AlwaysHitMinimizeAttr extends VariableAccuracyAttr {
|
||||
/**
|
||||
* @see {@linkcode apply}
|
||||
* @param user N/A
|
||||
|
@ -4855,10 +4855,10 @@ export class RemoveAllSubstitutesAttr extends MoveEffectAttr {
|
|||
* Attribute used when a move hits a {@linkcode BattlerTagType} for double damage
|
||||
* @extends MoveAttr
|
||||
*/
|
||||
export class HitsTagAttr extends MoveAttr {
|
||||
export class DealsDoubleDamageToTagAttr extends MoveAttr {
|
||||
/** The {@linkcode BattlerTagType} this move hits */
|
||||
public tagType: BattlerTagType;
|
||||
/** Should this move deal double damage against {@linkcode HitsTagAttr.tagType}? */
|
||||
/** Should this move deal double damage against {@linkcode DealsDoubleDamageToTagAttr.tagType}? */
|
||||
public doubleDamage: boolean;
|
||||
|
||||
constructor(tagType: BattlerTagType, doubleDamage?: boolean) {
|
||||
|
@ -6752,12 +6752,11 @@ export function initMoves() {
|
|||
new AttackMove(Moves.CUT, Type.NORMAL, MoveCategory.PHYSICAL, 50, 95, 30, -1, 0, 1)
|
||||
.slicingMove(),
|
||||
new AttackMove(Moves.GUST, Type.FLYING, MoveCategory.SPECIAL, 40, 100, 35, -1, 0, 1)
|
||||
.attr(HitsTagAttr, BattlerTagType.FLYING, true)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, true)
|
||||
.windMove(),
|
||||
new AttackMove(Moves.WING_ATTACK, Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 35, -1, 0, 1),
|
||||
new StatusMove(Moves.WHIRLWIND, Type.NORMAL, -1, 20, -1, -6, 1)
|
||||
.attr(ForceSwitchOutAttr)
|
||||
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
|
||||
.ignoresSubstitute()
|
||||
.hidesTarget()
|
||||
.windMove(),
|
||||
|
@ -6770,8 +6769,8 @@ export function initMoves() {
|
|||
new AttackMove(Moves.SLAM, Type.NORMAL, MoveCategory.PHYSICAL, 80, 75, 20, -1, 0, 1),
|
||||
new AttackMove(Moves.VINE_WHIP, Type.GRASS, MoveCategory.PHYSICAL, 45, 100, 25, -1, 0, 1),
|
||||
new AttackMove(Moves.STOMP, Type.NORMAL, MoveCategory.PHYSICAL, 65, 100, 20, 30, 0, 1)
|
||||
.attr(MinimizeAccuracyAttr)
|
||||
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true)
|
||||
.attr(AlwaysHitMinimizeAttr)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
|
||||
.attr(FlinchAttr),
|
||||
new AttackMove(Moves.DOUBLE_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 30, 100, 30, -1, 0, 1)
|
||||
.attr(MultiHitAttr, MultiHitType._2),
|
||||
|
@ -6795,8 +6794,8 @@ export function initMoves() {
|
|||
.attr(OneHitKOAccuracyAttr),
|
||||
new AttackMove(Moves.TACKLE, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 35, -1, 0, 1),
|
||||
new AttackMove(Moves.BODY_SLAM, Type.NORMAL, MoveCategory.PHYSICAL, 85, 100, 15, 30, 0, 1)
|
||||
.attr(MinimizeAccuracyAttr)
|
||||
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true)
|
||||
.attr(AlwaysHitMinimizeAttr)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
|
||||
.attr(StatusEffectAttr, StatusEffect.PARALYSIS),
|
||||
new AttackMove(Moves.WRAP, Type.NORMAL, MoveCategory.PHYSICAL, 15, 90, 20, -1, 0, 1)
|
||||
.attr(TrapAttr, BattlerTagType.WRAP),
|
||||
|
@ -6864,7 +6863,7 @@ export function initMoves() {
|
|||
new AttackMove(Moves.HYDRO_PUMP, Type.WATER, MoveCategory.SPECIAL, 110, 80, 5, -1, 0, 1),
|
||||
new AttackMove(Moves.SURF, Type.WATER, MoveCategory.SPECIAL, 90, 100, 15, -1, 0, 1)
|
||||
.target(MoveTarget.ALL_NEAR_OTHERS)
|
||||
.attr(HitsTagAttr, BattlerTagType.UNDERWATER, true)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERWATER, true)
|
||||
.attr(GulpMissileTagAttr),
|
||||
new AttackMove(Moves.ICE_BEAM, Type.ICE, MoveCategory.SPECIAL, 90, 100, 10, 10, 0, 1)
|
||||
.attr(StatusEffectAttr, StatusEffect.FREEZE),
|
||||
|
@ -6947,18 +6946,18 @@ export function initMoves() {
|
|||
new AttackMove(Moves.THUNDER, Type.ELECTRIC, MoveCategory.SPECIAL, 110, 70, 10, 30, 0, 1)
|
||||
.attr(StatusEffectAttr, StatusEffect.PARALYSIS)
|
||||
.attr(ThunderAccuracyAttr)
|
||||
.attr(HitsTagAttr, BattlerTagType.FLYING, false),
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, false),
|
||||
new AttackMove(Moves.ROCK_THROW, Type.ROCK, MoveCategory.PHYSICAL, 50, 90, 15, -1, 0, 1)
|
||||
.makesContact(false),
|
||||
new AttackMove(Moves.EARTHQUAKE, Type.GROUND, MoveCategory.PHYSICAL, 100, 100, 10, -1, 0, 1)
|
||||
.attr(HitsTagAttr, BattlerTagType.UNDERGROUND, true)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERGROUND, true)
|
||||
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.GRASSY && target.isGrounded() ? 0.5 : 1)
|
||||
.makesContact(false)
|
||||
.target(MoveTarget.ALL_NEAR_OTHERS),
|
||||
new AttackMove(Moves.FISSURE, Type.GROUND, MoveCategory.PHYSICAL, 200, 30, 5, -1, 0, 1)
|
||||
.attr(OneHitKOAttr)
|
||||
.attr(OneHitKOAccuracyAttr)
|
||||
.attr(HitsTagAttr, BattlerTagType.UNDERGROUND, false)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERGROUND, false)
|
||||
.makesContact(false),
|
||||
new AttackMove(Moves.DIG, Type.GROUND, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 1)
|
||||
.attr(ChargeAttr, ChargeAnim.DIG_CHARGING, i18next.t("moveTriggers:dugAHole", {pokemonName: "{USER}"}), BattlerTagType.UNDERGROUND)
|
||||
|
@ -7347,7 +7346,7 @@ export function initMoves() {
|
|||
.attr(PreMoveMessageAttr, magnitudeMessageFunc)
|
||||
.attr(MagnitudePowerAttr)
|
||||
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.GRASSY && target.isGrounded() ? 0.5 : 1)
|
||||
.attr(HitsTagAttr, BattlerTagType.UNDERGROUND, true)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERGROUND, true)
|
||||
.makesContact(false)
|
||||
.target(MoveTarget.ALL_NEAR_OTHERS),
|
||||
new AttackMove(Moves.DYNAMIC_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 50, 5, 100, 0, 2)
|
||||
|
@ -7403,7 +7402,7 @@ export function initMoves() {
|
|||
new AttackMove(Moves.CROSS_CHOP, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 80, 5, -1, 0, 2)
|
||||
.attr(HighCritAttr),
|
||||
new AttackMove(Moves.TWISTER, Type.DRAGON, MoveCategory.SPECIAL, 40, 100, 20, 20, 0, 2)
|
||||
.attr(HitsTagAttr, BattlerTagType.FLYING, true)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, true)
|
||||
.attr(FlinchAttr)
|
||||
.windMove()
|
||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||
|
@ -7435,7 +7434,7 @@ export function initMoves() {
|
|||
.attr(StatStageChangeAttr, [ Stat.DEF ], -1),
|
||||
new AttackMove(Moves.WHIRLPOOL, Type.WATER, MoveCategory.SPECIAL, 35, 85, 15, -1, 0, 2)
|
||||
.attr(TrapAttr, BattlerTagType.WHIRLPOOL)
|
||||
.attr(HitsTagAttr, BattlerTagType.UNDERWATER, true),
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.UNDERWATER, true),
|
||||
new AttackMove(Moves.BEAT_UP, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 2)
|
||||
.attr(MultiHitAttr, MultiHitType.BEAT_UP)
|
||||
.attr(BeatUpAttr)
|
||||
|
@ -7658,7 +7657,7 @@ export function initMoves() {
|
|||
new AttackMove(Moves.EXTRASENSORY, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 20, 10, 0, 3)
|
||||
.attr(FlinchAttr),
|
||||
new AttackMove(Moves.SKY_UPPERCUT, Type.FIGHTING, MoveCategory.PHYSICAL, 85, 90, 15, -1, 0, 3)
|
||||
.attr(HitsTagAttr, BattlerTagType.FLYING)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING)
|
||||
.punchingMove(),
|
||||
new AttackMove(Moves.SAND_TOMB, Type.GROUND, MoveCategory.PHYSICAL, 35, 85, 15, -1, 0, 3)
|
||||
.attr(TrapAttr, BattlerTagType.SAND_TOMB)
|
||||
|
@ -7889,8 +7888,8 @@ export function initMoves() {
|
|||
new AttackMove(Moves.DRAGON_PULSE, Type.DRAGON, MoveCategory.SPECIAL, 85, 100, 10, -1, 0, 4)
|
||||
.pulseMove(),
|
||||
new AttackMove(Moves.DRAGON_RUSH, Type.DRAGON, MoveCategory.PHYSICAL, 100, 75, 10, 20, 0, 4)
|
||||
.attr(MinimizeAccuracyAttr)
|
||||
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true)
|
||||
.attr(AlwaysHitMinimizeAttr)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
|
||||
.attr(FlinchAttr),
|
||||
new AttackMove(Moves.POWER_GEM, Type.ROCK, MoveCategory.SPECIAL, 80, 100, 20, -1, 0, 4),
|
||||
new AttackMove(Moves.DRAIN_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 75, 100, 10, -1, 0, 4)
|
||||
|
@ -8087,7 +8086,7 @@ export function initMoves() {
|
|||
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true)
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
|
||||
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
|
||||
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, false)
|
||||
.makesContact(false),
|
||||
new AttackMove(Moves.STORM_THROW, Type.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 5)
|
||||
.attr(CritOnlyAttr),
|
||||
|
@ -8100,9 +8099,9 @@ export function initMoves() {
|
|||
.attr(StatStageChangeAttr, [ Stat.SPATK, Stat.SPDEF, Stat.SPD ], 1, true)
|
||||
.danceMove(),
|
||||
new AttackMove(Moves.HEAVY_SLAM, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 5)
|
||||
.attr(MinimizeAccuracyAttr)
|
||||
.attr(AlwaysHitMinimizeAttr)
|
||||
.attr(CompareWeightPowerAttr)
|
||||
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true),
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true),
|
||||
new AttackMove(Moves.SYNCHRONOISE, Type.PSYCHIC, MoveCategory.SPECIAL, 120, 100, 10, -1, 0, 5)
|
||||
.target(MoveTarget.ALL_NEAR_OTHERS)
|
||||
.condition(unknownTypeCondition)
|
||||
|
@ -8253,12 +8252,14 @@ export function initMoves() {
|
|||
.attr(StatStageChangeAttr, [ Stat.DEF ], -1)
|
||||
.slicingMove(),
|
||||
new AttackMove(Moves.HEAT_CRASH, Type.FIRE, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 5)
|
||||
.attr(MinimizeAccuracyAttr)
|
||||
.attr(AlwaysHitMinimizeAttr)
|
||||
.attr(CompareWeightPowerAttr)
|
||||
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true),
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true),
|
||||
new AttackMove(Moves.LEAF_TORNADO, Type.GRASS, MoveCategory.SPECIAL, 65, 90, 10, 50, 0, 5)
|
||||
.attr(StatStageChangeAttr, [ Stat.ACC ], -1),
|
||||
new AttackMove(Moves.STEAMROLLER, Type.BUG, MoveCategory.PHYSICAL, 65, 100, 20, 30, 0, 5)
|
||||
.attr(AlwaysHitMinimizeAttr)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
|
||||
.attr(FlinchAttr),
|
||||
new SelfStatusMove(Moves.COTTON_GUARD, Type.GRASS, -1, 10, -1, 0, 5)
|
||||
.attr(StatStageChangeAttr, [ Stat.DEF ], 3, true),
|
||||
|
@ -8271,7 +8272,7 @@ export function initMoves() {
|
|||
new AttackMove(Moves.HURRICANE, Type.FLYING, MoveCategory.SPECIAL, 110, 70, 10, 30, 0, 5)
|
||||
.attr(ThunderAccuracyAttr)
|
||||
.attr(ConfuseAttr)
|
||||
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, false)
|
||||
.windMove(),
|
||||
new AttackMove(Moves.HEAD_CHARGE, Type.NORMAL, MoveCategory.PHYSICAL, 120, 100, 15, -1, 0, 5)
|
||||
.attr(RecoilAttr)
|
||||
|
@ -8325,9 +8326,9 @@ export function initMoves() {
|
|||
.attr(LastMoveDoublePowerAttr, Moves.FUSION_FLARE)
|
||||
.makesContact(false),
|
||||
new AttackMove(Moves.FLYING_PRESS, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 95, 10, -1, 0, 6)
|
||||
.attr(MinimizeAccuracyAttr)
|
||||
.attr(AlwaysHitMinimizeAttr)
|
||||
.attr(FlyingTypeMultiplierAttr)
|
||||
.attr(HitsTagAttr, BattlerTagType.MINIMIZED, true)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
|
||||
.condition(failOnGravityCondition),
|
||||
new StatusMove(Moves.MAT_BLOCK, Type.FIGHTING, -1, 10, -1, 0, 6)
|
||||
.target(MoveTarget.USER_SIDE)
|
||||
|
@ -8498,8 +8499,8 @@ export function initMoves() {
|
|||
new AttackMove(Moves.THOUSAND_ARROWS, Type.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6)
|
||||
.attr(NeutralDamageAgainstFlyingTypeMultiplierAttr)
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.IGNORE_FLYING, false, false, 1, 1, true)
|
||||
.attr(HitsTagAttr, BattlerTagType.FLYING, false)
|
||||
.attr(HitsTagAttr, BattlerTagType.MAGNET_RISEN, false)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.FLYING, false)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MAGNET_RISEN, false)
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
|
||||
.attr(RemoveBattlerTagAttr, [BattlerTagType.FLYING, BattlerTagType.MAGNET_RISEN])
|
||||
.makesContact(false)
|
||||
|
@ -8756,6 +8757,8 @@ export function initMoves() {
|
|||
.partial()
|
||||
.ignoresVirtual(),
|
||||
new AttackMove(Moves.MALICIOUS_MOONSAULT, Type.DARK, MoveCategory.PHYSICAL, 180, -1, 1, -1, 0, 7)
|
||||
.attr(AlwaysHitMinimizeAttr)
|
||||
.attr(DealsDoubleDamageToTagAttr, BattlerTagType.MINIMIZED, true)
|
||||
.partial()
|
||||
.ignoresVirtual(),
|
||||
new AttackMove(Moves.OCEANIC_OPERETTA, Type.WATER, MoveCategory.SPECIAL, 195, -1, 1, -1, 0, 7)
|
||||
|
|
|
@ -3,7 +3,7 @@ import BattleScene, { AnySound } from "../battle-scene";
|
|||
import { Variant, VariantSet, variantColorCache } from "#app/data/variant";
|
||||
import { variantData } from "#app/data/variant";
|
||||
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from "../ui/battle-info";
|
||||
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, VariableMoveTypeAttr, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatStagesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatStageChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, OneHitKOAccuracyAttr, RespectAttackTypeImmunityAttr, MoveTarget } from "../data/move";
|
||||
import Move, { HighCritAttr, DealsDoubleDamageToTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, VariableMoveTypeAttr, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatStagesAttr, SacrificialAttr, VariableMoveCategoryAttr, CounterDamageAttr, StatStageChangeAttr, RechargeAttr, ChargeAttr, IgnoreWeatherTypeDebuffAttr, BypassBurnDamageReductionAttr, SacrificialAttrOnHit, OneHitKOAccuracyAttr, RespectAttackTypeImmunityAttr, MoveTarget } from "../data/move";
|
||||
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from "../data/pokemon-species";
|
||||
import { Constructor, isNullOrUndefined, randSeedInt } from "#app/utils";
|
||||
import * as Utils from "../utils";
|
||||
|
@ -1513,7 +1513,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
|
||||
const immuneTags = this.findTags(tag => tag instanceof TypeImmuneTag && tag.immuneType === moveType);
|
||||
for (const tag of immuneTags) {
|
||||
if (move && !move.getAttrs(HitsTagAttr).some(attr => attr.tagType === tag.tagType)) {
|
||||
if (move && !move.getAttrs(DealsDoubleDamageToTagAttr).some(attr => attr.tagType === tag.tagType)) {
|
||||
typeMultiplier.value = 0;
|
||||
break;
|
||||
}
|
||||
|
@ -2489,13 +2489,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
this.scene.arena.applyTagsForSide(WeakenMoveScreenTag, defendingSide, move.category, this.scene.currentBattle.double, screenMultiplier);
|
||||
|
||||
/**
|
||||
* For each {@linkcode HitsTagAttr} the move has, doubles the damage of the move if:
|
||||
* For each {@linkcode DealsDoubleDamageToTagAttr} the move has, doubles the damage of the move if:
|
||||
* The target has a {@linkcode BattlerTagType} that this move interacts with
|
||||
* AND
|
||||
* The move doubles damage when used against that tag
|
||||
*/
|
||||
const hitsTagMultiplier = new Utils.NumberHolder(1);
|
||||
move.getAttrs(HitsTagAttr).filter(hta => hta.doubleDamage).forEach(hta => {
|
||||
move.getAttrs(DealsDoubleDamageToTagAttr).filter(hta => hta.doubleDamage).forEach(hta => {
|
||||
if (this.getTag(hta.tagType)) {
|
||||
hitsTagMultiplier.value *= 2;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import { applyPreAttackAbAttrs, AddSecondStrikeAbAttr, IgnoreMoveEffectsAbAttr,
|
|||
import { ArenaTagSide, ConditionalProtectTag } from "#app/data/arena-tag";
|
||||
import { MoveAnim } from "#app/data/battle-anims";
|
||||
import { BattlerTagLapseType, DamageProtectedTag, ProtectedTag, SemiInvulnerableTag, SubstituteTag } from "#app/data/battler-tags";
|
||||
import { MoveTarget, applyMoveAttrs, OverrideMoveEffectAttr, MultiHitAttr, AttackMove, FixedDamageAttr, VariableTargetAttr, MissEffectAttr, MoveFlags, applyFilteredMoveAttrs, MoveAttr, MoveEffectAttr, MoveEffectTrigger, ChargeAttr, MoveCategory, NoEffectAttr, HitsTagAttr } from "#app/data/move";
|
||||
import { MoveTarget, applyMoveAttrs, OverrideMoveEffectAttr, MultiHitAttr, AttackMove, FixedDamageAttr, VariableTargetAttr, MissEffectAttr, MoveFlags, applyFilteredMoveAttrs, MoveAttr, MoveEffectAttr, MoveEffectTrigger, ChargeAttr, MoveCategory, NoEffectAttr, DealsDoubleDamageToTagAttr } from "#app/data/move";
|
||||
import { SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms";
|
||||
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
||||
import { Moves } from "#app/enums/moves";
|
||||
|
@ -394,7 +394,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||
}
|
||||
|
||||
const semiInvulnerableTag = target.getTag(SemiInvulnerableTag);
|
||||
if (semiInvulnerableTag && !this.move.getMove().getAttrs(HitsTagAttr).some(hta => hta.tagType === semiInvulnerableTag.tagType)) {
|
||||
if (semiInvulnerableTag && !this.move.getMove().getAttrs(DealsDoubleDamageToTagAttr).some(hta => hta.tagType === semiInvulnerableTag.tagType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
import { BattlerIndex } from "#app/battle";
|
||||
import { allMoves } from "#app/data/move";
|
||||
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
||||
import { DamageCalculationResult } from "#app/field/pokemon";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
describe("Moves - Steamroller", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override.moveset([Moves.STEAMROLLER]).battleType("single").enemyAbility(Abilities.BALL_FETCH);
|
||||
});
|
||||
|
||||
it("should always hit a minimzed target with double damage", async () => {
|
||||
game.override.enemySpecies(Species.DITTO).enemyMoveset(Moves.MINIMIZE);
|
||||
await game.classicMode.startBattle([Species.IRON_BOULDER]);
|
||||
|
||||
const ditto = game.scene.getEnemyPokemon()!;
|
||||
vi.spyOn(ditto, "getAttackDamage");
|
||||
ditto.hp = 5000;
|
||||
const steamroller = allMoves[Moves.STEAMROLLER];
|
||||
vi.spyOn(steamroller, "calculateBattleAccuracy");
|
||||
const ironBoulder = game.scene.getPlayerPokemon()!;
|
||||
vi.spyOn(ironBoulder, "getAccuracyMultiplier");
|
||||
// Turn 1
|
||||
game.move.select(Moves.STEAMROLLER);
|
||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||
await game.toNextTurn();
|
||||
// Turn 2
|
||||
game.move.select(Moves.STEAMROLLER);
|
||||
await game.toNextTurn();
|
||||
|
||||
const [dmgCalcTurn1, dmgCalcTurn2]: DamageCalculationResult[] = vi
|
||||
.mocked(ditto.getAttackDamage)
|
||||
.mock.results.map((r) => r.value);
|
||||
|
||||
expect(dmgCalcTurn2.damage).toBeGreaterThanOrEqual(dmgCalcTurn1.damage * 2);
|
||||
expect(ditto.getTag(BattlerTagType.MINIMIZED)).toBeDefined();
|
||||
expect(steamroller.calculateBattleAccuracy).toHaveReturnedWith(-1);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,53 @@
|
|||
import { BattlerIndex } from "#app/battle";
|
||||
import { allMoves } from "#app/data/move";
|
||||
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, it, expect, vi } from "vitest";
|
||||
|
||||
describe("Moves - Whirlwind", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
let game: GameManager;
|
||||
|
||||
beforeAll(() => {
|
||||
phaserGame = new Phaser.Game({
|
||||
type: Phaser.HEADLESS,
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.battleType("single")
|
||||
.enemyAbility(Abilities.BALL_FETCH)
|
||||
.enemyMoveset(Moves.WHIRLWIND)
|
||||
.enemySpecies(Species.PIDGEY);
|
||||
});
|
||||
|
||||
it.each([
|
||||
{ move: Moves.FLY, name: "Fly" },
|
||||
{ move: Moves.BOUNCE, name: "Bounce" },
|
||||
{ move: Moves.SKY_DROP, name: "Sky Drop" },
|
||||
])("should not hit a flying target: $name (=$move)", async ({ move }) => {
|
||||
game.override.moveset([move]);
|
||||
await game.classicMode.startBattle([Species.STARAPTOR]);
|
||||
|
||||
const staraptor = game.scene.getPlayerPokemon()!;
|
||||
const whirlwind = allMoves[Moves.WHIRLWIND];
|
||||
vi.spyOn(whirlwind, "getFailedText");
|
||||
|
||||
game.move.select(move);
|
||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(staraptor.findTag((t) => t.tagType === BattlerTagType.FLYING)).toBeDefined();
|
||||
expect(whirlwind.getFailedText).toHaveBeenCalledOnce();
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue