Merge branch 'pagefaultgames:main' into Explosion-testing

This commit is contained in:
Douglas Marchione de Souza 2024-05-06 11:36:00 -03:00 committed by GitHub
commit ecb9d5b4e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 95 additions and 62 deletions

View File

@ -146,14 +146,14 @@
"spriteSourceSize": { "spriteSourceSize": {
"x": 0, "x": 0,
"y": 0, "y": 0,
"w": 3, "w": 66,
"h": 3 "h": 55
}, },
"frame": { "frame": {
"x": 132, "x": 0,
"y": 0, "y": 112,
"w": 3, "w": 66,
"h": 3 "h": 55
} }
}, },
{ {

View File

@ -426,7 +426,7 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr {
} }
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 (move.getMove() instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move.getMove().type) < 2) { if (move.getMove() instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move.getMove().type, attacker) < 2) {
cancelled.value = true; cancelled.value = true;
(args[0] as Utils.NumberHolder).value = 0; (args[0] as Utils.NumberHolder).value = 0;
return true; return true;
@ -1794,7 +1794,7 @@ function getAnticipationCondition(): AbAttrCondition {
for (let opponent of pokemon.getOpponents()) { for (let opponent of pokemon.getOpponents()) {
for (let move of opponent.moveset) { for (let move of opponent.moveset) {
// move is super effective // move is super effective
if (move.getMove() instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move.getMove().type) >= 2) { if (move.getMove() instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move.getMove().type, opponent) >= 2) {
return true; return true;
} }
// move is a OHKO // move is a OHKO
@ -1816,7 +1816,7 @@ function getAnticipationCondition(): AbAttrCondition {
Type.FIRE, Type.WATER, Type.GRASS, Type.ELECTRIC, Type.FIRE, Type.WATER, Type.GRASS, Type.ELECTRIC,
Type.PSYCHIC, Type.ICE, Type.DRAGON, Type.DARK][iv_val]; Type.PSYCHIC, Type.ICE, Type.DRAGON, Type.DARK][iv_val];
if (pokemon.getAttackTypeEffectiveness(type) >= 2) { if (pokemon.getAttackTypeEffectiveness(type, opponent) >= 2) {
return true; return true;
} }
} }
@ -2472,6 +2472,25 @@ export class NoFusionAbilityAbAttr extends AbAttr {
} }
} }
export class IgnoreTypeImmunityAbAttr extends AbAttr {
defenderType: Type;
allowedMoveTypes: Type[];
constructor(defenderType: Type, allowedMoveTypes: Type[]) {
super(true);
this.defenderType = defenderType;
this.allowedMoveTypes = allowedMoveTypes;
}
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
if (this.defenderType !== (args[1] as Type)) {
return false;
}
return this.allowedMoveTypes.some(type => type === (args[0] as Type));
}
}
function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any[]): TAttr }, function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any[]): TAttr },
pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise<void> { pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, args: any[], isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false, passive: boolean = false): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
@ -2973,15 +2992,15 @@ export function initAbilities() {
.attr(IgnoreOpponentStatChangesAbAttr) .attr(IgnoreOpponentStatChangesAbAttr)
.ignorable(), .ignorable(),
new Ability(Abilities.TINTED_LENS, 4) new Ability(Abilities.TINTED_LENS, 4)
.attr(MovePowerBoostAbAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type) <= 0.5, 2), .attr(MovePowerBoostAbAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) <= 0.5, 2),
new Ability(Abilities.FILTER, 4) new Ability(Abilities.FILTER, 4)
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type) >= 2, 0.75) .attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75)
.ignorable(), .ignorable(),
new Ability(Abilities.SLOW_START, 4) new Ability(Abilities.SLOW_START, 4)
.attr(PostSummonAddBattlerTagAbAttr, BattlerTagType.SLOW_START, 5), .attr(PostSummonAddBattlerTagAbAttr, BattlerTagType.SLOW_START, 5),
new Ability(Abilities.SCRAPPY, 4) new Ability(Abilities.SCRAPPY, 4)
.attr(IntimidateImmunityAbAttr) .attr(IgnoreTypeImmunityAbAttr, Type.GHOST, [Type.NORMAL, Type.FIGHTING])
.partial(), .attr(IntimidateImmunityAbAttr),
new Ability(Abilities.STORM_DRAIN, 4) new Ability(Abilities.STORM_DRAIN, 4)
.attr(RedirectTypeMoveAbAttr, Type.WATER) .attr(RedirectTypeMoveAbAttr, Type.WATER)
.attr(TypeImmunityStatChangeAbAttr, Type.WATER, BattleStat.SPATK, 1) .attr(TypeImmunityStatChangeAbAttr, Type.WATER, BattleStat.SPATK, 1)
@ -2990,7 +3009,7 @@ export function initAbilities() {
.attr(BlockWeatherDamageAttr, WeatherType.HAIL) .attr(BlockWeatherDamageAttr, WeatherType.HAIL)
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.HAIL, WeatherType.SNOW), .attr(PostWeatherLapseHealAbAttr, 1, WeatherType.HAIL, WeatherType.SNOW),
new Ability(Abilities.SOLID_ROCK, 4) new Ability(Abilities.SOLID_ROCK, 4)
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type) >= 2, 0.75) .attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75)
.ignorable(), .ignorable(),
new Ability(Abilities.SNOW_WARNING, 4) new Ability(Abilities.SNOW_WARNING, 4)
.attr(PostSummonWeatherChangeAbAttr, WeatherType.SNOW) .attr(PostSummonWeatherChangeAbAttr, WeatherType.SNOW)
@ -3258,7 +3277,7 @@ 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(PreDefendMovePowerToOneAbAttr, (target, user, move) => target.formIndex == 0 && target.getAttackTypeEffectiveness(move.type, user) > 0)
.attr(PostSummonFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) .attr(PostSummonFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
.attr(PostBattleInitFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) .attr(PostBattleInitFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
.attr(PostDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1) .attr(PostDefendFormChangeAbAttr, p => p.battleData.hitCount === 0 ? 0 : 1)
@ -3356,9 +3375,9 @@ export function initAbilities() {
new Ability(Abilities.SHADOW_SHIELD, 7) new Ability(Abilities.SHADOW_SHIELD, 7)
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getHpRatio() === 1, 0.5), .attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getHpRatio() === 1, 0.5),
new Ability(Abilities.PRISM_ARMOR, 7) new Ability(Abilities.PRISM_ARMOR, 7)
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type) >= 2, 0.75), .attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75),
new Ability(Abilities.NEUROFORCE, 7) new Ability(Abilities.NEUROFORCE, 7)
.attr(MovePowerBoostAbAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type) >= 2, 1.25), .attr(MovePowerBoostAbAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 1.25),
new Ability(Abilities.INTREPID_SWORD, 8) new Ability(Abilities.INTREPID_SWORD, 8)
.attr(PostSummonStatChangeAbAttr, BattleStat.ATK, 1, true), .attr(PostSummonStatChangeAbAttr, BattleStat.ATK, 1, true),
new Ability(Abilities.DAUNTLESS_SHIELD, 8) new Ability(Abilities.DAUNTLESS_SHIELD, 8)
@ -3434,7 +3453,8 @@ export function initAbilities() {
.attr(UncopiableAbilityAbAttr) .attr(UncopiableAbilityAbAttr)
.attr(UnswappableAbilityAbAttr) .attr(UnswappableAbilityAbAttr)
.attr(NoTransformAbilityAbAttr) .attr(NoTransformAbilityAbAttr)
.attr(NoFusionAbilityAbAttr), .attr(NoFusionAbilityAbAttr)
.condition((pokemon) => !pokemon.isTerastallized()),
new Ability(Abilities.QUICK_DRAW, 8) new Ability(Abilities.QUICK_DRAW, 8)
.unimplemented(), .unimplemented(),
new Ability(Abilities.UNSEEN_FIST, 8) new Ability(Abilities.UNSEEN_FIST, 8)
@ -3567,8 +3587,8 @@ export function initAbilities() {
.attr(MoveAbilityBypassAbAttr, (pokemon, move: Move) => move.category === MoveCategory.STATUS) .attr(MoveAbilityBypassAbAttr, (pokemon, move: Move) => move.category === MoveCategory.STATUS)
.partial(), .partial(),
new Ability(Abilities.MINDS_EYE, 9) new Ability(Abilities.MINDS_EYE, 9)
.ignorable() .attr(IgnoreTypeImmunityAbAttr, Type.GHOST, [Type.NORMAL, Type.FIGHTING])
.unimplemented(), .ignorable(), // TODO: evasiveness bypass should not be ignored, but accuracy immunity should
new Ability(Abilities.SUPERSWEET_SYRUP, 9) new Ability(Abilities.SUPERSWEET_SYRUP, 9)
.unimplemented(), .unimplemented(),
new Ability(Abilities.HOSPITALITY, 9) new Ability(Abilities.HOSPITALITY, 9)

View File

@ -114,7 +114,8 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
pokemon.scene.queueMessage(getPokemonMessage(pokemon, getStatusEffectHealText(pokemon.status.effect))); pokemon.scene.queueMessage(getPokemonMessage(pokemon, getStatusEffectHealText(pokemon.status.effect)));
pokemon.resetStatus(); pokemon.resetStatus();
pokemon.updateInfo(); pokemon.updateInfo();
} else if (pokemon.getTag(BattlerTagType.CONFUSED)) }
if (pokemon.getTag(BattlerTagType.CONFUSED))
pokemon.lapseTag(BattlerTagType.CONFUSED); pokemon.lapseTag(BattlerTagType.CONFUSED);
}; };
case BerryType.LIECHI: case BerryType.LIECHI:

View File

@ -137,7 +137,7 @@ export const speciesEggMoves = {
[Species.SEEDOT]: [ Moves.SWORDS_DANCE, Moves.GRASSY_GLIDE, Moves.KOWTOW_CLEAVE, Moves.IVY_CUDGEL ], [Species.SEEDOT]: [ Moves.SWORDS_DANCE, Moves.GRASSY_GLIDE, Moves.KOWTOW_CLEAVE, Moves.IVY_CUDGEL ],
[Species.TAILLOW]: [ Moves.SWORDS_DANCE, Moves.FACADE, Moves.DRILL_RUN, Moves.EXTREME_SPEED ], [Species.TAILLOW]: [ Moves.SWORDS_DANCE, Moves.FACADE, Moves.DRILL_RUN, Moves.EXTREME_SPEED ],
[Species.WINGULL]: [ Moves.THUNDER, Moves.FLIP_TURN, Moves.DEFOG, Moves.STEAM_ERUPTION ], [Species.WINGULL]: [ Moves.THUNDER, Moves.FLIP_TURN, Moves.DEFOG, Moves.STEAM_ERUPTION ],
[Species.RALTS]: [ Moves.BOOMBURST, Moves.BITTER_BLADE, Moves.PSYBLADE, Moves.VICTORY_DANCE ], [Species.RALTS]: [ Moves.BOOMBURST, Moves.BITTER_BLADE, Moves.QUIVER_DANCE, Moves.VICTORY_DANCE ],
[Species.SURSKIT]: [ Moves.ROOST, Moves.FIERY_DANCE, Moves.STICKY_WEB, Moves.BLEAKWIND_STORM ], [Species.SURSKIT]: [ Moves.ROOST, Moves.FIERY_DANCE, Moves.STICKY_WEB, Moves.BLEAKWIND_STORM ],
[Species.SHROOMISH]: [ Moves.ACCELEROCK, Moves.TRAILBLAZE, Moves.STORM_THROW, Moves.SAPPY_SEED ], [Species.SHROOMISH]: [ Moves.ACCELEROCK, Moves.TRAILBLAZE, Moves.STORM_THROW, Moves.SAPPY_SEED ],
[Species.SLAKOTH]: [ Moves.FACADE, Moves.JUMP_KICK, Moves.KNOCK_OFF, Moves.SKILL_SWAP ], [Species.SLAKOTH]: [ Moves.FACADE, Moves.JUMP_KICK, Moves.KNOCK_OFF, Moves.SKILL_SWAP ],
@ -346,7 +346,7 @@ export const speciesEggMoves = {
[Species.PANCHAM]: [ Moves.DRAIN_PUNCH, Moves.FAKE_OUT, Moves.BULLET_PUNCH, Moves.WICKED_BLOW ], [Species.PANCHAM]: [ Moves.DRAIN_PUNCH, Moves.FAKE_OUT, Moves.BULLET_PUNCH, Moves.WICKED_BLOW ],
[Species.FURFROU]: [ Moves.TIDY_UP, Moves.CRUNCH, Moves.COVET, Moves.MULTI_ATTACK ], [Species.FURFROU]: [ Moves.TIDY_UP, Moves.CRUNCH, Moves.COVET, Moves.MULTI_ATTACK ],
[Species.ESPURR]: [ Moves.GLARE, Moves.MOONBLAST, Moves.FLAMETHROWER, Moves.PSYSTRIKE ], [Species.ESPURR]: [ Moves.GLARE, Moves.MOONBLAST, Moves.FLAMETHROWER, Moves.PSYSTRIKE ],
[Species.HONEDGE]: [ Moves.RECOVER, Moves.POLTERGEIST, Moves.BITTER_BLADE, Moves.BEHEMOTH_BLADE ], [Species.HONEDGE]: [ Moves.TACHYON_CUTTER, Moves.POLTERGEIST, Moves.BITTER_BLADE, Moves.BEHEMOTH_BLADE ],
[Species.SPRITZEE]: [ Moves.TRICK_ROOM, Moves.FOUL_PLAY, Moves.WISH, Moves.REVIVAL_BLESSING ], [Species.SPRITZEE]: [ Moves.TRICK_ROOM, Moves.FOUL_PLAY, Moves.WISH, Moves.REVIVAL_BLESSING ],
[Species.SWIRLIX]: [ Moves.BELLY_DRUM, Moves.SUCKER_PUNCH, Moves.SPIRIT_BREAK, Moves.SIZZLY_SLIDE ], [Species.SWIRLIX]: [ Moves.BELLY_DRUM, Moves.SUCKER_PUNCH, Moves.SPIRIT_BREAK, Moves.SIZZLY_SLIDE ],
[Species.INKAY]: [ Moves.POWER_TRIP, Moves.STORED_POWER, Moves.RECOVER, Moves.PSYCHO_BOOST ], [Species.INKAY]: [ Moves.POWER_TRIP, Moves.STORED_POWER, Moves.RECOVER, Moves.PSYCHO_BOOST ],
@ -485,7 +485,7 @@ export const speciesEggMoves = {
[Species.SMOLIV]: [ Moves.STRENGTH_SAP, Moves.EARTH_POWER, Moves.CALM_MIND, Moves.BOOMBURST ], [Species.SMOLIV]: [ Moves.STRENGTH_SAP, Moves.EARTH_POWER, Moves.CALM_MIND, Moves.BOOMBURST ],
[Species.SQUAWKABILLY]: [ Moves.PARTING_SHOT, Moves.BULK_UP, Moves.FLARE_BLITZ, Moves.HEAD_CHARGE ], [Species.SQUAWKABILLY]: [ Moves.PARTING_SHOT, Moves.BULK_UP, Moves.FLARE_BLITZ, Moves.HEAD_CHARGE ],
[Species.NACLI]: [ Moves.BODY_PRESS, Moves.SPIKES, Moves.CURSE, Moves.DIAMOND_STORM ], [Species.NACLI]: [ Moves.BODY_PRESS, Moves.SPIKES, Moves.CURSE, Moves.DIAMOND_STORM ],
[Species.CHARCADET]: [ Moves.SACRED_SWORD, Moves.PHOTON_GEYSER, Moves.RECOVER, Moves.SPECTRAL_THIEF ], [Species.CHARCADET]: [ Moves.SACRED_SWORD, Moves.PHOTON_GEYSER, Moves.MOONBLAST, Moves.SPECTRAL_THIEF ],
[Species.TADBULB]: [ Moves.PARABOLIC_CHARGE, Moves.SCALD, Moves.EARTH_POWER, Moves.ELECTRO_SHOT ], [Species.TADBULB]: [ Moves.PARABOLIC_CHARGE, Moves.SCALD, Moves.EARTH_POWER, Moves.ELECTRO_SHOT ],
[Species.WATTREL]: [ Moves.NASTY_PLOT, Moves.TAILWIND, Moves.HEAT_WAVE, Moves.AEROBLAST ], [Species.WATTREL]: [ Moves.NASTY_PLOT, Moves.TAILWIND, Moves.HEAT_WAVE, Moves.AEROBLAST ],
[Species.MASCHIFF]: [ Moves.PARTING_SHOT, Moves.KNOCK_OFF, Moves.NUZZLE, Moves.COLLISION_COURSE ], [Species.MASCHIFF]: [ Moves.PARTING_SHOT, Moves.KNOCK_OFF, Moves.NUZZLE, Moves.COLLISION_COURSE ],

View File

@ -367,7 +367,7 @@ export class AttackMove extends Move {
let attackScore = 0; let attackScore = 0;
const effectiveness = target.getAttackTypeEffectiveness(this.type); const effectiveness = target.getAttackTypeEffectiveness(this.type, user);
attackScore = Math.pow(effectiveness - 1, 2) * effectiveness < 1 ? -2 : 2; attackScore = Math.pow(effectiveness - 1, 2) * effectiveness < 1 ? -2 : 2;
if (attackScore) { if (attackScore) {
if (this.category === MoveCategory.PHYSICAL) { if (this.category === MoveCategory.PHYSICAL) {
@ -738,7 +738,7 @@ export class SacrificialAttr extends MoveEffectAttr {
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer { getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
if (user.isBoss()) if (user.isBoss())
return -20; return -20;
return Math.ceil(((1 - user.getHpRatio()) * 10 - 10) * (target.getAttackTypeEffectiveness(move.type) - 0.5)); return Math.ceil(((1 - user.getHpRatio()) * 10 - 10) * (target.getAttackTypeEffectiveness(move.type, user) - 0.5));
} }
} }
@ -776,7 +776,7 @@ export class HalfSacrificialAttr extends MoveEffectAttr {
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer { getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
if (user.isBoss()) if (user.isBoss())
return -10; return -10;
return Math.ceil(((1 - user.getHpRatio()/2) * 10 - 10) * (target.getAttackTypeEffectiveness(move.type) - 0.5)); return Math.ceil(((1 - user.getHpRatio()/2) * 10 - 10) * (target.getAttackTypeEffectiveness(move.type, user) - 0.5));
} }
} }
@ -2476,7 +2476,7 @@ export class WaterSuperEffectTypeMultiplierAttr extends VariableMoveTypeMultipli
export class FlyingTypeMultiplierAttr extends VariableMoveTypeMultiplierAttr { export class FlyingTypeMultiplierAttr extends VariableMoveTypeMultiplierAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const multiplier = args[0] as Utils.NumberHolder; const multiplier = args[0] as Utils.NumberHolder;
multiplier.value *= target.getAttackTypeEffectiveness(Type.FLYING); multiplier.value *= target.getAttackTypeEffectiveness(Type.FLYING, user);
return true; return true;
} }
} }
@ -6471,9 +6471,9 @@ export function initMoves() {
new AttackMove(Moves.RUINATION, Type.DARK, MoveCategory.SPECIAL, -1, 90, 10, -1, 0, 9) new AttackMove(Moves.RUINATION, Type.DARK, MoveCategory.SPECIAL, -1, 90, 10, -1, 0, 9)
.attr(TargetHalfHpDamageAttr), .attr(TargetHalfHpDamageAttr),
new AttackMove(Moves.COLLISION_COURSE, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9) new AttackMove(Moves.COLLISION_COURSE, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9)
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type) >= 2 ? 5461/4096 : 1), .attr(MovePowerMultiplierAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2 ? 5461/4096 : 1),
new AttackMove(Moves.ELECTRO_DRIFT, Type.ELECTRIC, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 9) new AttackMove(Moves.ELECTRO_DRIFT, Type.ELECTRIC, MoveCategory.SPECIAL, 100, 100, 5, -1, 0, 9)
.attr(MovePowerMultiplierAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type) >= 2 ? 5461/4096 : 1) .attr(MovePowerMultiplierAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2 ? 5461/4096 : 1)
.makesContact(), .makesContact(),
new SelfStatusMove(Moves.SHED_TAIL, Type.NORMAL, -1, 10, -1, 0, 9) new SelfStatusMove(Moves.SHED_TAIL, Type.NORMAL, -1, 10, -1, 0, 9)
.unimplemented(), .unimplemented(),

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, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr } 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';
@ -880,7 +880,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
getAttackMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier { getAttackMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier {
const typeless = !!move.getMove().getAttrs(TypelessAttr).length; const typeless = !!move.getMove().getAttrs(TypelessAttr).length;
const typeMultiplier = new Utils.NumberHolder(this.getAttackTypeEffectiveness(move.getMove().type)); const typeMultiplier = new Utils.NumberHolder(this.getAttackTypeEffectiveness(move.getMove().type, source));
const cancelled = new Utils.BooleanHolder(false); const cancelled = new Utils.BooleanHolder(false);
if (!typeless) if (!typeless)
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true); applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true);
@ -889,11 +889,20 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return (!cancelled.value ? typeMultiplier.value : 0) as TypeDamageMultiplier; return (!cancelled.value ? typeMultiplier.value : 0) as TypeDamageMultiplier;
} }
getAttackTypeEffectiveness(moveType: Type): TypeDamageMultiplier { getAttackTypeEffectiveness(moveType: Type, source?: Pokemon): TypeDamageMultiplier {
if (moveType === Type.STELLAR) if (moveType === Type.STELLAR)
return this.isTerastallized() ? 2 : 1; return this.isTerastallized() ? 2 : 1;
const types = this.getTypes(true, true); const types = this.getTypes(true, true);
let multiplier = getTypeDamageMultiplier(moveType, types[0]) * (types.length > 1 ? getTypeDamageMultiplier(moveType, types[1]) : 1) * (types.length > 2 ? getTypeDamageMultiplier(moveType, types[2]) : 1) as TypeDamageMultiplier;
const ignorableImmunities = source?.getAbility()?.getAttrs(IgnoreTypeImmunityAbAttr) || [];
const cancelled = new Utils.BooleanHolder(false);
let multiplier = types.map(defType =>
ignorableImmunities.some(attr => attr.apply(source, false, cancelled, [moveType, defType]))
? 1
: getTypeDamageMultiplier(moveType, defType)
).reduce((acc, cur) => acc * cur, 1) as TypeDamageMultiplier;
// Handle strong winds lowering effectiveness of types super effective against pure flying // Handle strong winds lowering effectiveness of types super effective against pure flying
if (this.scene.arena.weather?.weatherType === WeatherType.STRONG_WINDS && !this.scene.arena.weather.isEffectSuppressed(this.scene) && multiplier >= 2 && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2) if (this.scene.arena.weather?.weatherType === WeatherType.STRONG_WINDS && !this.scene.arena.weather.isEffectSuppressed(this.scene) && multiplier >= 2 && this.isOfType(Type.FLYING) && getTypeDamageMultiplier(moveType, Type.FLYING) === 2)
multiplier /= 2; multiplier /= 2;
@ -904,12 +913,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const types = this.getTypes(true); const types = this.getTypes(true);
const enemyTypes = pokemon.getTypes(true, true); const enemyTypes = pokemon.getTypes(true, true);
const outspeed = (this.isActive(true) ? this.getBattleStat(Stat.SPD, pokemon) : this.getStat(Stat.SPD)) <= pokemon.getBattleStat(Stat.SPD, this); const outspeed = (this.isActive(true) ? this.getBattleStat(Stat.SPD, pokemon) : this.getStat(Stat.SPD)) <= pokemon.getBattleStat(Stat.SPD, this);
let atkScore = pokemon.getAttackTypeEffectiveness(types[0]) * (outspeed ? 1.25 : 1); let atkScore = pokemon.getAttackTypeEffectiveness(types[0], this) * (outspeed ? 1.25 : 1);
let defScore = 1 / Math.max(this.getAttackTypeEffectiveness(enemyTypes[0]), 0.25); let defScore = 1 / Math.max(this.getAttackTypeEffectiveness(enemyTypes[0], pokemon), 0.25);
if (types.length > 1) if (types.length > 1)
atkScore *= pokemon.getAttackTypeEffectiveness(types[1]); atkScore *= pokemon.getAttackTypeEffectiveness(types[1], this);
if (enemyTypes.length > 1) if (enemyTypes.length > 1)
defScore *= (1 / Math.max(this.getAttackTypeEffectiveness(enemyTypes[1]), 0.25)); defScore *= (1 / Math.max(this.getAttackTypeEffectiveness(enemyTypes[1], pokemon), 0.25));
let hpDiffRatio = this.getHpRatio() + (1 - pokemon.getHpRatio()); let hpDiffRatio = this.getHpRatio() + (1 - pokemon.getHpRatio());
if (outspeed) if (outspeed)
hpDiffRatio = Math.min(hpDiffRatio * 1.5, 1); hpDiffRatio = Math.min(hpDiffRatio * 1.5, 1);
@ -1262,7 +1271,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const cancelled = new Utils.BooleanHolder(false); const cancelled = new Utils.BooleanHolder(false);
const typeless = !!move.getAttrs(TypelessAttr).length; const typeless = !!move.getAttrs(TypelessAttr).length;
const typeMultiplier = new Utils.NumberHolder(!typeless && (moveCategory !== MoveCategory.STATUS || move.getAttrs(StatusMoveTypeImmunityAttr).find(attr => types.includes((attr as StatusMoveTypeImmunityAttr).immuneType))) const typeMultiplier = new Utils.NumberHolder(!typeless && (moveCategory !== MoveCategory.STATUS || move.getAttrs(StatusMoveTypeImmunityAttr).find(attr => types.includes((attr as StatusMoveTypeImmunityAttr).immuneType)))
? this.getAttackTypeEffectiveness(type) ? this.getAttackTypeEffectiveness(type, source)
: 1); : 1);
applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier); applyMoveAttrs(VariableMoveTypeMultiplierAttr, source, this, move, typeMultiplier);
if (typeless) if (typeless)
@ -3172,7 +3181,7 @@ export class PokemonMove {
isUsable(pokemon: Pokemon, ignorePp?: boolean): boolean { isUsable(pokemon: Pokemon, ignorePp?: boolean): boolean {
if (this.moveId && pokemon.summonData?.disabledMove === this.moveId) if (this.moveId && pokemon.summonData?.disabledMove === this.moveId)
return false; return false;
return ignorePp || this.ppUsed < this.getMovePp() || this.getMove().pp === -1; return (ignorePp || this.ppUsed < this.getMovePp() || this.getMove().pp === -1) && !this.getMove().name.endsWith(' (N)');
} }
getMove(): Move { getMove(): Move {

View File

@ -33,6 +33,7 @@ export const battle: SimpleTranslationEntries = {
"learnMoveForgetSuccess": "{{pokemonName}} forgot how to\nuse {{moveName}}.", "learnMoveForgetSuccess": "{{pokemonName}} forgot how to\nuse {{moveName}}.",
"levelCapUp": "Das Levellimit\nhat sich zu {{levelCap}} erhöht!", "levelCapUp": "Das Levellimit\nhat sich zu {{levelCap}} erhöht!",
"moveNotImplemented": "{{moveName}} ist noch nicht implementiert und kann nicht ausgewählt werden.", "moveNotImplemented": "{{moveName}} ist noch nicht implementiert und kann nicht ausgewählt werden.",
"moveNoPP": "There's no PP left for\nthis move!",
"moveDisabled": "{{moveName}} ist deaktiviert!", "moveDisabled": "{{moveName}} ist deaktiviert!",
"noPokeballForce": "Eine unsichtbare Kraft\nverhindert die Nutzung von Pokébällen.", "noPokeballForce": "Eine unsichtbare Kraft\nverhindert die Nutzung von Pokébällen.",
"noPokeballTrainer": "Du kannst das Pokémon\neines anderen Trainers nicht fangen!", "noPokeballTrainer": "Du kannst das Pokémon\neines anderen Trainers nicht fangen!",

View File

@ -33,6 +33,7 @@ export const battle: SimpleTranslationEntries = {
"learnMoveForgetSuccess": "{{pokemonName}} forgot how to\nuse {{moveName}}.", "learnMoveForgetSuccess": "{{pokemonName}} forgot how to\nuse {{moveName}}.",
"levelCapUp": "The level cap\nhas increased to {{levelCap}}!", "levelCapUp": "The level cap\nhas increased to {{levelCap}}!",
"moveNotImplemented": "{{moveName}} is not yet implemented and cannot be selected.", "moveNotImplemented": "{{moveName}} is not yet implemented and cannot be selected.",
"moveNoPP": "There's no PP left for\nthis move!",
"moveDisabled": "{{moveName}} is disabled!", "moveDisabled": "{{moveName}} is disabled!",
"noPokeballForce": "An unseen force\nprevents using Poké Balls.", "noPokeballForce": "An unseen force\nprevents using Poké Balls.",
"noPokeballTrainer": "You can't catch\nanother trainer's Pokémon!", "noPokeballTrainer": "You can't catch\nanother trainer's Pokémon!",

View File

@ -33,6 +33,7 @@ export const battle: SimpleTranslationEntries = {
"learnMoveForgetSuccess": "{{pokemonName}} ha olvidado cómo utilizar {{moveName}}.", "learnMoveForgetSuccess": "{{pokemonName}} ha olvidado cómo utilizar {{moveName}}.",
"levelCapUp": "¡Se ha incrementado el\nnivel máximo a {{levelCap}}!", "levelCapUp": "¡Se ha incrementado el\nnivel máximo a {{levelCap}}!",
"moveNotImplemented": "{{moveName}} aún no está implementado y no se puede seleccionar.", "moveNotImplemented": "{{moveName}} aún no está implementado y no se puede seleccionar.",
"moveNoPP": "There's no PP left for\nthis move!",
"moveDisabled": "!No puede usar {{moveName}} porque ha sido anulado!", "moveDisabled": "!No puede usar {{moveName}} porque ha sido anulado!",
"noPokeballForce": "Una fuerza misteriosa\nte impide usar Poké Balls.", "noPokeballForce": "Una fuerza misteriosa\nte impide usar Poké Balls.",
"noPokeballTrainer": "¡No puedes atrapar a los\nPokémon de los demás!", "noPokeballTrainer": "¡No puedes atrapar a los\nPokémon de los demás!",

View File

@ -23,7 +23,7 @@ export const battle: SimpleTranslationEntries = {
"attackHitsCount": `Touché {{count}} fois !`, "attackHitsCount": `Touché {{count}} fois !`,
"expGain": "{{pokemonName}} gagne\n{{exp}} Points dExp !", "expGain": "{{pokemonName}} gagne\n{{exp}} Points dExp !",
"levelUp": "{{pokemonName}} monte au\nN. {{level}} !", "levelUp": "{{pokemonName}} monte au\nN. {{level}} !",
"learnMove": "{{pokemonName}} apprend \n{{moveName}} !", "learnMove": "{{pokemonName}} apprend\n{{moveName}} !",
"learnMovePrompt": "{{pokemonName}} veut apprendre\n{{moveName}}.", "learnMovePrompt": "{{pokemonName}} veut apprendre\n{{moveName}}.",
"learnMoveLimitReached": "Cependant, {{pokemonName}} connait\ndéjà quatre capacités.", "learnMoveLimitReached": "Cependant, {{pokemonName}} connait\ndéjà quatre capacités.",
"learnMoveReplaceQuestion": "Voulez-vous oublier une capacité\net la remplacer par {{moveName}} ?", "learnMoveReplaceQuestion": "Voulez-vous oublier une capacité\net la remplacer par {{moveName}} ?",
@ -33,6 +33,7 @@ export const battle: SimpleTranslationEntries = {
"learnMoveForgetSuccess": "{{pokemonName}} oublie comment\nutiliser {{moveName}}.", "learnMoveForgetSuccess": "{{pokemonName}} oublie comment\nutiliser {{moveName}}.",
"levelCapUp": "La limite de niveau\na été augmentée à {{levelCap}} !", "levelCapUp": "La limite de niveau\na été augmentée à {{levelCap}} !",
"moveNotImplemented": "{{moveName}} nest pas encore implémenté et ne peut pas être sélectionné.", "moveNotImplemented": "{{moveName}} nest pas encore implémenté et ne peut pas être sélectionné.",
"moveNoPP": "Il ny a plus de PP pour\ncette capacité !",
"moveDisabled": "{{moveName}} est sous entrave !", "moveDisabled": "{{moveName}} est sous entrave !",
"noPokeballForce": "Une force mystérieuse\nempêche lutilisation des Poké Balls.", "noPokeballForce": "Une force mystérieuse\nempêche lutilisation des Poké Balls.",
"noPokeballTrainer": "Le Dresseur détourne la Ball\nVoler, cest mal !", "noPokeballTrainer": "Le Dresseur détourne la Ball\nVoler, cest mal !",

View File

@ -33,6 +33,7 @@ export const battle: SimpleTranslationEntries = {
"learnMoveForgetSuccess": "{{pokemonName}} ha dimenticato la mossa\n{{moveName}}.", "learnMoveForgetSuccess": "{{pokemonName}} ha dimenticato la mossa\n{{moveName}}.",
"levelCapUp": "Il livello massimo\nè aumentato a {{levelCap}}!", "levelCapUp": "Il livello massimo\nè aumentato a {{levelCap}}!",
"moveNotImplemented": "{{moveName}} non è ancora implementata e non può essere selezionata.", "moveNotImplemented": "{{moveName}} non è ancora implementata e non può essere selezionata.",
"moveNoPP": "There's no PP left for\nthis move!",
"moveDisabled": "{{moveName}} è disabilitata!", "moveDisabled": "{{moveName}} è disabilitata!",
"noPokeballForce": "Una forza misteriosa\nimpedisce l'uso dell Poké Ball.", "noPokeballForce": "Una forza misteriosa\nimpedisce l'uso dell Poké Ball.",
"noPokeballTrainer": "Non puoi catturare\nPokémon di altri allenatori!", "noPokeballTrainer": "Non puoi catturare\nPokémon di altri allenatori!",

View File

@ -1680,21 +1680,13 @@ export class CommandPhase extends FieldPhase {
switch (command) { switch (command) {
case Command.FIGHT: case Command.FIGHT:
let useStruggle = false; let useStruggle = false;
if (cursor === -1 || playerPokemon.trySelectMove(cursor, args[0] as boolean) || (useStruggle = cursor > -1 && !playerPokemon.getMoveset().filter(m => m.isUsable(playerPokemon)).length)) { if (cursor === -1 ||
playerPokemon.trySelectMove(cursor, args[0] as boolean) ||
(useStruggle = cursor > -1 && !playerPokemon.getMoveset().filter(m => m.isUsable(playerPokemon)).length)) {
const moveId = !useStruggle ? cursor > -1 ? playerPokemon.getMoveset()[cursor].moveId : Moves.NONE : Moves.STRUGGLE; const moveId = !useStruggle ? cursor > -1 ? playerPokemon.getMoveset()[cursor].moveId : Moves.NONE : Moves.STRUGGLE;
const turnCommand: TurnCommand = { command: Command.FIGHT, cursor: cursor, move: { move: moveId, targets: [], ignorePP: args[0] }, args: args }; const turnCommand: TurnCommand = { command: Command.FIGHT, cursor: cursor, move: { move: moveId, targets: [], ignorePP: args[0] }, args: args };
const moveTargets: MoveTargetSet = args.length < 3 ? getMoveTargets(playerPokemon, moveId) : args[2]; const moveTargets: MoveTargetSet = args.length < 3 ? getMoveTargets(playerPokemon, moveId) : args[2];
if (moveId) { if (!moveId)
const move = playerPokemon.getMoveset()[cursor];
if (move.getName().endsWith(' (N)')) {
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.showText(i18next.t('battle:moveNotImplemented', { moveName: move.getName().slice(0, -4) }), null, () => {
this.scene.ui.clearText();
this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex);
}, null, true);
return;
}
} else
turnCommand.targets = [ this.fieldIndex ]; turnCommand.targets = [ this.fieldIndex ];
console.log(moveTargets, playerPokemon.name); console.log(moveTargets, playerPokemon.name);
if (moveTargets.targets.length <= 1 || moveTargets.multiple) if (moveTargets.targets.length <= 1 || moveTargets.multiple)
@ -1705,15 +1697,21 @@ export class CommandPhase extends FieldPhase {
this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex)); this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex));
this.scene.currentBattle.turnCommands[this.fieldIndex] = turnCommand; this.scene.currentBattle.turnCommands[this.fieldIndex] = turnCommand;
success = true; success = true;
} else if (cursor < playerPokemon.getMoveset().length) { }
else if (cursor < playerPokemon.getMoveset().length) {
const move = playerPokemon.getMoveset()[cursor]; const move = playerPokemon.getMoveset()[cursor];
if (playerPokemon.summonData.disabledMove === move.moveId) { this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.showText(i18next.t('battle:moveDisabled', { moveName: move.getName() }), null, () => { // Decides between a Disabled, Not Implemented, or No PP translation message
this.scene.ui.clearText(); const errorMessage =
this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex); playerPokemon.summonData.disabledMove === move.moveId ? 'battle:moveDisabled' :
}, null, true); move.getName().endsWith(' (N)') ? 'battle:moveNotImplemented' : 'battle:moveNoPP';
} const moveName = move.getName().replace(' (N)', ''); // Trims off the indicator
this.scene.ui.showText(i18next.t(errorMessage, { moveName: moveName }), null, () => {
this.scene.ui.clearText();
this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex);
}, null, true);
} }
break; break;
case Command.BALL: case Command.BALL: