diff --git a/README.md b/README.md index b2955f8c4..d08107867 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ If you have the motivation and experience with Typescript/Javascript (or are wil ### ❔ FAQ **How do I test a new _______?** -- In the `battle-scene.ts` file there are overrides for most values you'll need to change for testing +- In the `src/overrides.ts` file there are overrides for most values you'll need to change for testing ## 🪧 To Do diff --git a/public/images/ui/candy.png b/public/images/ui/candy.png new file mode 100644 index 000000000..6b633a195 Binary files /dev/null and b/public/images/ui/candy.png differ diff --git a/public/images/ui/candy_overlay.png b/public/images/ui/candy_overlay.png new file mode 100644 index 000000000..835cfccb0 Binary files /dev/null and b/public/images/ui/candy_overlay.png differ diff --git a/public/images/ui/legacy/candy.png b/public/images/ui/legacy/candy.png new file mode 100644 index 000000000..6b633a195 Binary files /dev/null and b/public/images/ui/legacy/candy.png differ diff --git a/public/images/ui/legacy/candy_overlay.png b/public/images/ui/legacy/candy_overlay.png new file mode 100644 index 000000000..835cfccb0 Binary files /dev/null and b/public/images/ui/legacy/candy_overlay.png differ diff --git a/public/images/ui/pbinfo_player_type.png b/public/images/ui/pbinfo_player_type.png index ad8895039..b78d078de 100644 Binary files a/public/images/ui/pbinfo_player_type.png and b/public/images/ui/pbinfo_player_type.png differ diff --git a/src/data/ability.ts b/src/data/ability.ts index 7ac3e7218..3245b26f6 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -9,7 +9,7 @@ import { BattlerTag } from "./battler-tags"; import { BattlerTagType } from "./enums/battler-tag-type"; import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect"; import { Gender } from "./gender"; -import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves } from "./move"; +import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves, StatusMove } from "./move"; import { ArenaTagSide, ArenaTrapTag } from "./arena-tag"; import { ArenaTagType } from "./enums/arena-tag-type"; import { Stat } from "./pokemon-stat"; @@ -827,13 +827,16 @@ export class PostDefendAbilitySwapAbAttr extends PostDefendAbAttr { } export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr { - constructor() { + private ability: Abilities; + + constructor(ability: Abilities) { super(); + this.ability = ability; } applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean { if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.getAbility().hasAttr(UnsuppressableAbilityAbAttr) && !attacker.getAbility().hasAttr(PostDefendAbilityGiveAbAttr)) { - attacker.summonData.ability = pokemon.getAbility().id; + attacker.summonData.ability = this.ability; return true; } @@ -1785,6 +1788,53 @@ function getAnticipationCondition(): AbAttrCondition { }; } +export class ForewarnAbAttr extends PostSummonAbAttr { + constructor() { + super(true); + } + + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + let maxPowerSeen = 0; + let maxMove = ""; + let movePower = 0; + for (let opponent of pokemon.getOpponents()) { + for (let move of opponent.moveset) { + if (move.getMove() instanceof StatusMove) { + movePower = 1; + } else if (move.getMove().findAttr(attr => attr instanceof OneHitKOAttr)) { + movePower = 150; + } else if (move.getMove().id === Moves.COUNTER || move.getMove().id === Moves.MIRROR_COAT || move.getMove().id === Moves.METAL_BURST) { + movePower = 120; + } else if (move.getMove().power === -1) { + movePower = 80; + } else { + movePower = move.getMove().power; + } + + if (movePower > maxPowerSeen) { + maxPowerSeen = movePower; + maxMove = move.getName(); + } + } + } + pokemon.scene.queueMessage(getPokemonMessage(pokemon, " was forewarned about " + maxMove + "!")); + return true; + } +} + +export class FriskAbAttr extends PostSummonAbAttr { + constructor() { + super(true); + } + + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean { + for (let opponent of pokemon.getOpponents()) { + pokemon.scene.queueMessage(getPokemonMessage(pokemon, " frisked " + opponent.name + "\'s " + opponent.getAbility().name + "!")); + } + return true; + } +} + export class PostWeatherChangeAbAttr extends AbAttr { applyPostWeatherChange(pokemon: Pokemon, passive: boolean, weather: WeatherType, args: any[]): boolean { return false; @@ -1935,13 +1985,19 @@ export class MoodyAbAttr extends PostTurnAbAttr { } applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { - // TODO: Edge case of not choosing to buff or debuff a stat that's already maxed let selectableStats = [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD]; - let increaseStat = selectableStats[Utils.randInt(selectableStats.length)]; - selectableStats = selectableStats.filter(s => s !== increaseStat); - let decreaseStat = selectableStats[Utils.randInt(selectableStats.length)]; - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [increaseStat], 2)); - pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [decreaseStat], -1)); + let increaseStatArray = selectableStats.filter(s => pokemon.summonData.battleStats[s] < 6); + let decreaseStatArray = selectableStats.filter(s => pokemon.summonData.battleStats[s] > -6); + + if (increaseStatArray.length > 0) { + let increaseStat = increaseStatArray[Utils.randInt(increaseStatArray.length)]; + decreaseStatArray = decreaseStatArray.filter(s => s !== increaseStat); + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [increaseStat], 2)); + } + if (decreaseStatArray.length > 0) { + let decreaseStat = selectableStats[Utils.randInt(selectableStats.length)]; + pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [decreaseStat], -1)); + } return true; } } @@ -2854,7 +2910,7 @@ export function initAbilities() { new Ability(Abilities.ANTICIPATION, 4) .conditionalAttr(getAnticipationCondition(), PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, ' shuddered!')), new Ability(Abilities.FOREWARN, 4) - .unimplemented(), + .attr(ForewarnAbAttr), new Ability(Abilities.UNAWARE, 4) .attr(IgnoreOpponentStatChangesAbAttr) .ignorable(), @@ -2883,7 +2939,7 @@ export function initAbilities() { new Ability(Abilities.HONEY_GATHER, 4) .unimplemented(), new Ability(Abilities.FRISK, 4) - .unimplemented(), + .attr(FriskAbAttr), new Ability(Abilities.RECKLESS, 4) .attr(MovePowerBoostAbAttr, (user, target, move) => move.getAttrs(RecoilAttr).length && move.id !== Moves.STRUGGLE, 1.2), new Ability(Abilities.MULTITYPE, 4) @@ -2976,7 +3032,7 @@ export function initAbilities() { new Ability(Abilities.INFILTRATOR, 5) .unimplemented(), new Ability(Abilities.MUMMY, 5) - .attr(PostDefendAbilityGiveAbAttr) + .attr(PostDefendAbilityGiveAbAttr, Abilities.MUMMY) .bypassFaint(), new Ability(Abilities.MOXIE, 5) .attr(PostVictoryStatChangeAbAttr, BattleStat.ATK, 1), @@ -3309,6 +3365,7 @@ export function initAbilities() { .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) .attr(NoTransformAbilityAbAttr) + .attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, '\'s Neutralizing Gas filled the area!')) .partial(), new Ability(Abilities.PASTEL_VEIL, 8) .attr(StatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC) @@ -3347,7 +3404,7 @@ export function initAbilities() { .attr(UnswappableAbilityAbAttr) .attr(UnsuppressableAbilityAbAttr), new Ability(Abilities.LINGERING_AROMA, 9) - .attr(PostDefendAbilityGiveAbAttr) + .attr(PostDefendAbilityGiveAbAttr, Abilities.LINGERING_AROMA) .bypassFaint(), new Ability(Abilities.SEED_SOWER, 9) .attr(PostDefendTerrainChangeAbAttr, TerrainType.GRASSY), diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 8ff684394..183306d50 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -984,6 +984,19 @@ export class HideSpriteTag extends BattlerTag { } } +export class TypeImmuneTag extends BattlerTag { + public immuneType: Type; + constructor(tagType: BattlerTagType, sourceMove: Moves, immuneType: Type, length: number) { + super(tagType, BattlerTagLapseType.TURN_END, 1, sourceMove); + } +} + +export class MagnetRisenTag extends TypeImmuneTag { + constructor(tagType: BattlerTagType, sourceMove: Moves) { + super(tagType, sourceMove, Type.GROUND, 5); + } +} + export class TypeBoostTag extends BattlerTag { public boostedType: Type; public boostValue: number; @@ -1211,6 +1224,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc return new CursedTag(sourceId); case BattlerTagType.CHARGED: return new TypeBoostTag(tagType, sourceMove, Type.ELECTRIC, 2, true); + case BattlerTagType.MAGNET_RISEN: + return new MagnetRisenTag(tagType, sourceMove); case BattlerTagType.NONE: default: return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId); diff --git a/src/data/biomes.ts b/src/data/biomes.ts index 3dc124918..61da0410d 100644 --- a/src/data/biomes.ts +++ b/src/data/biomes.ts @@ -4391,8 +4391,8 @@ export const biomeTrainerPools: BiomeTrainerPools = { ] ], [ Species.SHAYMIN, Type.GRASS, -1, [ - [ Biome.MEADOW, BiomePoolTier.BOSS_ULTRA_RARE ] - ] + [ Biome.MEADOW, BiomePoolTier.BOSS_ULTRA_RARE ] + ] ], [ Species.ARCEUS, Type.NORMAL, -1, [ ] ], diff --git a/src/data/egg.ts b/src/data/egg.ts index 08982cd4a..f0d6de26a 100644 --- a/src/data/egg.ts +++ b/src/data/egg.ts @@ -77,8 +77,6 @@ export function getEggHatchWavesMessage(hatchWaves: integer): string { } export function getEggGachaTypeDescriptor(scene: BattleScene, egg: Egg): string { - if (egg.isManaphyEgg()) - return ''; switch (egg.gachaType) { case GachaType.LEGENDARY: return `Legendary Rate Up (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(scene, egg.timestamp)).getName()})`; diff --git a/src/data/enums/battler-tag-type.ts b/src/data/enums/battler-tag-type.ts index 7a9f6ba8b..d18ccf1c5 100644 --- a/src/data/enums/battler-tag-type.ts +++ b/src/data/enums/battler-tag-type.ts @@ -54,5 +54,6 @@ export enum BattlerTagType { SALT_CURED = "SALT_CURED", CURSED = "CURSED", CHARGED = "CHARGED", - GROUNDED = "GROUNDED" + GROUNDED = "GROUNDED", + MAGNET_RISEN = "MAGNET_RISEN" } diff --git a/src/data/move.ts b/src/data/move.ts index 958588f7a..f3a1c0494 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1496,6 +1496,23 @@ export class StatChangeAttr extends MoveEffectAttr { } } +export class AcupressureStatChangeAttr extends MoveEffectAttr { + constructor() { + super(); + } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise { + let randStats = [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD, BattleStat.ACC, BattleStat.EVA ]; + randStats = randStats.filter(s => target.summonData.battleStats[s] < 6); + if (randStats.length > 0) { + let boostStat = [randStats[Utils.randInt(randStats.length)]]; + user.scene.unshiftPhase(new StatChangePhase(user.scene, target.getBattlerIndex(), this.selfTarget, boostStat, 2)); + return true; + } + return false; + } +} + export class GrowthStatChangeAttr extends StatChangeAttr { constructor() { super([ BattleStat.ATK, BattleStat.SPATK ], 1, true); @@ -3690,6 +3707,22 @@ export class LastResortAttr extends MoveAttr { } } +export class VariableTargetAttr extends MoveAttr { + private targetChangeFunc: (user: Pokemon, target: Pokemon, move: Move) => number; + + constructor(targetChange: (user: Pokemon, target: Pokemon, move: Move) => number) { + super(); + + this.targetChangeFunc = targetChange; + } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + const targetVal = args[0] as Utils.NumberHolder; + targetVal.value = this.targetChangeFunc(user, target, move); + return true; + } +} + const failOnGravityCondition: MoveConditionFunc = (user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY); const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.isBossImmune(); @@ -3770,7 +3803,10 @@ export type MoveTargetSet = { } export function getMoveTargets(user: Pokemon, move: Moves): MoveTargetSet { - const moveTarget = move ? allMoves[move].moveTarget : move === undefined ? MoveTarget.NEAR_ENEMY : []; + const variableTarget = new Utils.NumberHolder(0); + user.getOpponents().forEach(p => applyMoveAttrs(VariableTargetAttr, user, p, allMoves[move], variableTarget)); + + const moveTarget = allMoves[move].getAttrs(VariableTargetAttr).length ? variableTarget.value : move ? allMoves[move].moveTarget : move === undefined ? MoveTarget.NEAR_ENEMY : []; const opponents = user.getOpponents(); let set: Pokemon[] = []; @@ -4700,8 +4736,7 @@ export function initMoves() { .attr(StatusEffectAttr, StatusEffect.SLEEP) .soundBased(), new StatusMove(Moves.TICKLE, Type.NORMAL, 100, 20, -1, 0, 3) - .attr(StatChangeAttr, BattleStat.ATK, -1) - .attr(StatChangeAttr, BattleStat.DEF, -1), + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1), new SelfStatusMove(Moves.COSMIC_POWER, Type.PSYCHIC, -1, 20, -1, 0, 3) .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, true), new AttackMove(Moves.WATER_SPOUT, Type.WATER, MoveCategory.SPECIAL, 150, 100, 5, -1, 0, 3) @@ -4823,7 +4858,7 @@ export function initMoves() { .attr(AddArenaTagAttr, ArenaTagType.TAILWIND, 4, true) .target(MoveTarget.USER_SIDE), new StatusMove(Moves.ACUPRESSURE, Type.NORMAL, -1, 30, -1, 0, 4) - .attr(StatChangeAttr, BattleStat.RAND, 2) + .attr(AcupressureStatChangeAttr) .target(MoveTarget.USER_OR_NEAR_ALLY), new AttackMove(Moves.METAL_BURST, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 4) .attr(CounterDamageAttr, (move: Move) => (move.category === MoveCategory.PHYSICAL || move.category === MoveCategory.SPECIAL), 1.5) @@ -4895,6 +4930,10 @@ export function initMoves() { new SelfStatusMove(Moves.AQUA_RING, Type.WATER, -1, 20, -1, 0, 4) .attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true), new SelfStatusMove(Moves.MAGNET_RISE, Type.ELECTRIC, -1, 10, -1, 0, 4) + .attr(AddBattlerTagAttr, BattlerTagType.MAGNET_RISEN, true, true) + .condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) && + !user.getTag(BattlerTagType.IGNORE_FLYING) && !user.getTag(BattlerTagType.INGRAIN) && + !user.getTag(BattlerTagType.MAGNET_RISEN)) .unimplemented(), new AttackMove(Moves.FLARE_BLITZ, Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 10, 0, 4) .attr(RecoilAttr, false, 0.33) @@ -5737,8 +5776,7 @@ export function initMoves() { .ignoresAbilities() .partial(), new StatusMove(Moves.TEARFUL_LOOK, Type.NORMAL, -1, 20, 100, 0, 7) - .attr(StatChangeAttr, BattleStat.ATK, -1) - .attr(StatChangeAttr, BattleStat.SPATK, -1), + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1), new AttackMove(Moves.ZING_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 80, 100, 10, 30, 0, 7) .attr(FlinchAttr), new AttackMove(Moves.NATURES_MADNESS, Type.FAIRY, MoveCategory.SPECIAL, -1, 90, 10, -1, 0, 7) @@ -5917,8 +5955,7 @@ export function initMoves() { new AttackMove(Moves.BODY_PRESS, Type.FIGHTING, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 8) .attr(DefAtkAttr), new StatusMove(Moves.DECORATE, Type.FAIRY, -1, 15, 100, 0, 8) - .attr(StatChangeAttr, BattleStat.ATK, 2) - .attr(StatChangeAttr, BattleStat.SPATK, 2), + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 2), new AttackMove(Moves.DRUM_BEATING, Type.GRASS, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 8) .attr(StatChangeAttr, BattleStat.SPD, -1) .makesContact(false), @@ -5968,7 +6005,8 @@ export function initMoves() { new AttackMove(Moves.STEEL_BEAM, Type.STEEL, MoveCategory.SPECIAL, 140, 95, 5, -1, 0, 8) .attr(HalfSacrificialAttr), new AttackMove(Moves.EXPANDING_FORCE, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 8) - .partial(), + .attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.PSYCHIC && user.isGrounded() ? 1.5 : 1) + .attr(VariableTargetAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.PSYCHIC && user.isGrounded() ? 6 : 3), new AttackMove(Moves.STEEL_ROLLER, Type.STEEL, MoveCategory.PHYSICAL, 130, 100, 5, -1, 0, 8) .attr(ClearTerrainAttr) .condition((user, target, move) => !!user.scene.arena.terrain), diff --git a/src/data/pokemon-level-moves.ts b/src/data/pokemon-level-moves.ts index 0b545d1bd..c67e917b3 100644 --- a/src/data/pokemon-level-moves.ts +++ b/src/data/pokemon-level-moves.ts @@ -30,7 +30,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 24, Moves.SWEET_SCENT ], [ 27, Moves.SYNTHESIS ], [ 30, Moves.WORRY_SEED ], - [ 33, Moves.DOUBLE_EDGE ], + [ 33, Moves.POWER_WHIP ], [ 36, Moves.SOLAR_BEAM ], ], [Species.IVYSAUR]: [ @@ -47,16 +47,16 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 30, Moves.SWEET_SCENT ], [ 35, Moves.SYNTHESIS ], [ 40, Moves.WORRY_SEED ], - [ 45, Moves.DOUBLE_EDGE ], + [ 45, Moves.POWER_WHIP ], [ 50, Moves.SOLAR_BEAM ], ], [Species.VENUSAUR]: [ [ 0, Moves.PETAL_BLIZZARD ], + [ 1, Moves.GROWTH ], + [ 1, Moves.PETAL_DANCE ], [ 1, Moves.VINE_WHIP ], [ 1, Moves.TACKLE ], [ 1, Moves.GROWL ], - [ 1, Moves.GROWTH ], - [ 1, Moves.PETAL_DANCE ], [ 9, Moves.LEECH_SEED ], [ 12, Moves.RAZOR_LEAF ], [ 15, Moves.POISON_POWDER ], @@ -66,7 +66,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 30, Moves.SWEET_SCENT ], [ 37, Moves.SYNTHESIS ], [ 44, Moves.WORRY_SEED ], - [ 51, Moves.DOUBLE_EDGE ], + [ 51, Moves.POWER_WHIP ], [ 58, Moves.SOLAR_BEAM ], ], [Species.CHARMANDER]: [ @@ -127,7 +127,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 27, Moves.SHELL_SMASH ], [ 30, Moves.IRON_DEFENSE ], [ 33, Moves.HYDRO_PUMP ], - [ 36, Moves.SKULL_BASH ], + [ 36, Moves.WAVE_CRASH ], ], [Species.WARTORTLE]: [ [ 1, Moves.TACKLE ], @@ -143,7 +143,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 35, Moves.SHELL_SMASH ], [ 40, Moves.IRON_DEFENSE ], [ 45, Moves.HYDRO_PUMP ], - [ 50, Moves.SKULL_BASH ], + [ 50, Moves.WAVE_CRASH ], ], [Species.BLASTOISE]: [ [ 0, Moves.FLASH_CANNON ], @@ -160,7 +160,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 35, Moves.SHELL_SMASH ], [ 42, Moves.IRON_DEFENSE ], [ 49, Moves.HYDRO_PUMP ], - [ 56, Moves.SKULL_BASH ], + [ 56, Moves.WAVE_CRASH ], ], [Species.CATERPIE]: [ [ 1, Moves.TACKLE ], @@ -341,9 +341,9 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 12, Moves.GLARE ], [ 17, Moves.SCREECH ], [ 20, Moves.ACID ], + [ 25, Moves.SWALLOW ], [ 25, Moves.STOCKPILE ], [ 25, Moves.SPIT_UP ], - [ 25, Moves.SWALLOW ], [ 28, Moves.ACID_SPRAY ], [ 33, Moves.SLUDGE_BOMB ], [ 36, Moves.GASTRO_ACID ], @@ -1780,14 +1780,15 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 4, Moves.DOUBLE_KICK ], [ 8, Moves.LOW_KICK ], [ 12, Moves.ENDURE ], - [ 16, Moves.REVENGE ], + [ 16, Moves.SUCKER_PUNCH ], [ 21, Moves.WIDE_GUARD ], [ 24, Moves.BLAZE_KICK ], - [ 28, Moves.MIND_READER ], + [ 28, Moves.FEINT ], [ 32, Moves.MEGA_KICK ], [ 36, Moves.CLOSE_COMBAT ], [ 40, Moves.REVERSAL ], [ 44, Moves.HIGH_JUMP_KICK ], + [ 50, Moves.AXE_KICK ], ], [Species.HITMONCHAN]: [ [ 0, Moves.DRAIN_PUNCH ], @@ -1796,16 +1797,14 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 1, Moves.FAKE_OUT ], [ 1, Moves.HELPING_HAND ], [ 1, Moves.FEINT ], - [ 1, Moves.VACUUM_WAVE ], - [ 1, Moves.BULLET_PUNCH ], [ 4, Moves.MACH_PUNCH ], - [ 8, Moves.POWER_UP_PUNCH ], + [ 8, Moves.VACUUM_WAVE ], [ 12, Moves.DETECT ], - [ 16, Moves.REVENGE ], + [ 16, Moves.BULLET_PUNCH ], [ 21, Moves.QUICK_GUARD ], - [ 24, Moves.FIRE_PUNCH ], - [ 24, Moves.ICE_PUNCH ], [ 24, Moves.THUNDER_PUNCH ], + [ 24, Moves.ICE_PUNCH ], + [ 24, Moves.FIRE_PUNCH ], [ 28, Moves.AGILITY ], [ 32, Moves.MEGA_PUNCH ], [ 36, Moves.CLOSE_COMBAT ], diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index 57bb9230c..d118adc0f 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -3209,7 +3209,7 @@ export const starterPassiveAbilities = { [Species.BELLSPROUT]: Abilities.CORROSION, [Species.TENTACOOL]: Abilities.INNARDS_OUT, [Species.GEODUDE]: Abilities.ROCKY_PAYLOAD, - [Species.PONYTA]: Abilities.PIXILATE, + [Species.PONYTA]: Abilities.MAGIC_GUARD, [Species.SLOWPOKE]: Abilities.UNAWARE, [Species.MAGNEMITE]: Abilities.MOTOR_DRIVE, [Species.FARFETCHD]: Abilities.PURE_POWER, @@ -3235,7 +3235,7 @@ export const starterPassiveAbilities = { [Species.SCYTHER]: Abilities.SPEED_BOOST, [Species.PINSIR]: Abilities.SAP_SIPPER, [Species.TAUROS]: Abilities.ROCK_HEAD, - [Species.MAGIKARP]: Abilities.BERSERK, + [Species.MAGIKARP]: Abilities.MULTISCALE, [Species.LAPRAS]: Abilities.LIQUID_VOICE, [Species.DITTO]: Abilities.GOOEY, [Species.EEVEE]: Abilities.PROTEAN, @@ -3249,16 +3249,16 @@ export const starterPassiveAbilities = { [Species.DRATINI]: Abilities.DELTA_STREAM, [Species.MEWTWO]: Abilities.NEUROFORCE, [Species.MEW]: Abilities.PROTEAN, - [Species.CHIKORITA]: Abilities.RIPEN, + [Species.CHIKORITA]: Abilities.THICK_FAT, [Species.CYNDAQUIL]: Abilities.TURBOBLAZE, [Species.TOTODILE]: Abilities.TOUGH_CLAWS, [Species.SENTRET]: Abilities.FLUFFY, [Species.HOOTHOOT]: Abilities.CURSED_BODY, - [Species.LEDYBA]: Abilities.SCREEN_CLEANER, + [Species.LEDYBA]: Abilities.PRANKSTER, [Species.SPINARAK]: Abilities.PRANKSTER, [Species.CHINCHOU]: Abilities.REGENERATOR, [Species.PICHU]: Abilities.TRANSISTOR, - [Species.CLEFFA]: Abilities.MISTY_SURGE, + [Species.CLEFFA]: Abilities.MAGIC_BOUNCE, [Species.IGGLYBUFF]: Abilities.SERENE_GRACE, [Species.TOGEPI]: Abilities.OPPORTUNIST, [Species.NATU]: Abilities.TINTED_LENS, @@ -3276,7 +3276,7 @@ export const starterPassiveAbilities = { [Species.DUNSPARCE]: Abilities.MARVEL_SCALE, [Species.GLIGAR]: Abilities.MERCILESS, [Species.SNUBBULL]: Abilities.BALL_FETCH, - [Species.QWILFISH]: Abilities.LIQUID_OOZE, + [Species.QWILFISH]: Abilities.TOXIC_DEBRIS, [Species.SHUCKLE]: Abilities.WELL_BAKED_BODY, [Species.HERACROSS]: Abilities.QUICK_FEET, [Species.SNEASEL]: Abilities.MOXIE, @@ -3292,7 +3292,7 @@ export const starterPassiveAbilities = { [Species.STANTLER]: Abilities.MAGIC_GUARD, [Species.SMEARGLE]: Abilities.QUICK_DRAW, [Species.TYROGUE]: Abilities.STAMINA, - [Species.SMOOCHUM]: Abilities.CUTE_CHARM, + [Species.SMOOCHUM]: Abilities.DAZZLING, [Species.ELEKID]: Abilities.IRON_FIST, [Species.MAGBY]: Abilities.CONTRARY, [Species.MILTANK]: Abilities.GLUTTONY, @@ -3303,7 +3303,7 @@ export const starterPassiveAbilities = { [Species.LUGIA]: Abilities.DELTA_STREAM, [Species.HO_OH]: Abilities.MAGIC_GUARD, [Species.CELEBI]: Abilities.GRASSY_SURGE, - [Species.TREECKO]: Abilities.GRASSY_SURGE, + [Species.TREECKO]: Abilities.TINTED_LENS, [Species.TORCHIC]: Abilities.RECKLESS, [Species.MUDKIP]: Abilities.REGENERATOR, [Species.POOCHYENA]: Abilities.STRONG_JAW, @@ -3320,7 +3320,7 @@ export const starterPassiveAbilities = { [Species.NINCADA]: Abilities.OVERCOAT, [Species.WHISMUR]: Abilities.PUNK_ROCK, [Species.MAKUHITA]: Abilities.STAMINA, - [Species.AZURILL]: Abilities.UNNERVE, + [Species.AZURILL]: Abilities.MISTY_SURGE, [Species.NOSEPASS]: Abilities.LEVITATE, [Species.SKITTY]: Abilities.SCRAPPY, [Species.SABLEYE]: Abilities.UNNERVE, @@ -3351,7 +3351,7 @@ export const starterPassiveAbilities = { [Species.BALTOY]: Abilities.OWN_TEMPO, [Species.LILEEP]: Abilities.WATER_ABSORB, [Species.ANORITH]: Abilities.WATER_ABSORB, - [Species.FEEBAS]: Abilities.PASTEL_VEIL, + [Species.FEEBAS]: Abilities.MAGIC_GUARD, [Species.CASTFORM]: Abilities.ADAPTABILITY, [Species.KECLEON]: Abilities.ADAPTABILITY, [Species.SHUPPET]: Abilities.MUMMY, @@ -3372,7 +3372,7 @@ export const starterPassiveAbilities = { [Species.LATIAS]: Abilities.SOUL_HEART, [Species.LATIOS]: Abilities.TINTED_LENS, [Species.KYOGRE]: Abilities.HYDRATION, - [Species.GROUDON]: Abilities.FLAME_BODY, + [Species.GROUDON]: Abilities.PROTOSYNTHESIS, [Species.RAYQUAZA]: Abilities.UNNERVE, [Species.JIRACHI]: Abilities.COMATOSE, [Species.DEOXYS]: Abilities.PROTEAN, @@ -3431,7 +3431,7 @@ export const starterPassiveAbilities = { [Species.VICTINI]: Abilities.SUPER_LUCK, [Species.SNIVY]: Abilities.MULTISCALE, [Species.TEPIG]: Abilities.ROCK_HEAD, - [Species.OSHAWOTT]: Abilities.MOLD_BREAKER, + [Species.OSHAWOTT]: Abilities.QUICK_DRAW, [Species.PATRAT]: Abilities.STAKEOUT, [Species.LILLIPUP]: Abilities.BALL_FETCH, [Species.PURRLOIN]: Abilities.DEFIANT, @@ -3444,14 +3444,14 @@ export const starterPassiveAbilities = { [Species.ROGGENROLA]: Abilities.SOLID_ROCK, [Species.WOOBAT]: Abilities.SOUL_HEART, [Species.DRILBUR]: Abilities.SAND_STREAM, - [Species.AUDINO]: Abilities.SERENE_GRACE, + [Species.AUDINO]: Abilities.FRIEND_GUARD, [Species.TIMBURR]: Abilities.STAMINA, [Species.TYMPOLE]: Abilities.MOODY, [Species.THROH]: Abilities.SIMPLE, [Species.SAWK]: Abilities.DEFIANT, [Species.SEWADDLE]: Abilities.SHARPNESS, [Species.VENIPEDE]: Abilities.INTIMIDATE, - [Species.COTTONEE]: Abilities.MISTY_SURGE, + [Species.COTTONEE]: Abilities.FLUFFY, [Species.PETILIL]: Abilities.DANCER, [Species.BASCULIN]: Abilities.OPPORTUNIST, [Species.SANDILE]: Abilities.STRONG_JAW, @@ -3460,7 +3460,7 @@ export const starterPassiveAbilities = { [Species.DWEBBLE]: Abilities.STAMINA, [Species.SCRAGGY]: Abilities.ROCK_HEAD, [Species.SIGILYPH]: Abilities.MAGICIAN, - [Species.YAMASK]: Abilities.GOOD_AS_GOLD, + [Species.YAMASK]: Abilities.PURIFYING_SALT, [Species.TIRTOUGA]: Abilities.SHELL_ARMOR, [Species.ARCHEN]: Abilities.ROCKY_PAYLOAD, [Species.TRUBBISH]: Abilities.GOOEY, @@ -3521,7 +3521,7 @@ export const starterPassiveAbilities = { [Species.SKIDDO]: Abilities.GRASSY_SURGE, [Species.PANCHAM]: Abilities.FLUFFY, [Species.FURFROU]: Abilities.BALL_FETCH, - [Species.ESPURR]: Abilities.PSYCHIC_SURGE, + [Species.ESPURR]: Abilities.FUR_COAT, [Species.HONEDGE]: Abilities.SHARPNESS, [Species.SPRITZEE]: Abilities.MISTY_SURGE, [Species.SWIRLIX]: Abilities.WELL_BAKED_BODY, @@ -3548,7 +3548,7 @@ export const starterPassiveAbilities = { [Species.HOOPA]: Abilities.OPPORTUNIST, [Species.VOLCANION]: Abilities.FILTER, [Species.ROWLET]: Abilities.SNIPER, - [Species.LITTEN]: Abilities.PRANKSTER, + [Species.LITTEN]: Abilities.FLAME_BODY, [Species.POPPLIO]: Abilities.PUNK_ROCK, [Species.PIKIPEK]: Abilities.ANGER_POINT, [Species.YUNGOOS]: Abilities.HUGE_POWER, @@ -3577,7 +3577,7 @@ export const starterPassiveAbilities = { [Species.KOMALA]: Abilities.GUTS, [Species.TURTONATOR]: Abilities.ANGER_SHELL, [Species.TOGEDEMARU]: Abilities.STATIC, - [Species.MIMIKYU]: Abilities.CURSED_BODY, + [Species.MIMIKYU]: Abilities.TOUGH_CLAWS, [Species.BRUXISH]: Abilities.MULTISCALE, [Species.DRAMPA]: Abilities.FLASH_FIRE, [Species.DHELMISE]: Abilities.INFILTRATOR, @@ -3607,9 +3607,9 @@ export const starterPassiveAbilities = { [Species.SOBBLE]: Abilities.SUPER_LUCK, [Species.SKWOVET]: Abilities.HONEY_GATHER, [Species.ROOKIDEE]: Abilities.IRON_BARBS, - [Species.BLIPBUG]: Abilities.TINTED_LENS, + [Species.BLIPBUG]: Abilities.PSYCHIC_SURGE, [Species.NICKIT]: Abilities.INTIMIDATE, - [Species.GOSSIFLEUR]: Abilities.STORM_DRAIN, + [Species.GOSSIFLEUR]: Abilities.GRASSY_SURGE, [Species.WOOLOO]: Abilities.ROCK_HEAD, [Species.CHEWTLE]: Abilities.ROCK_HEAD, [Species.YAMPER]: Abilities.STAKEOUT, @@ -3624,7 +3624,7 @@ export const starterPassiveAbilities = { [Species.SINISTEA]: Abilities.WATER_ABSORB, [Species.HATENNA]: Abilities.MAGIC_GUARD, [Species.IMPIDIMP]: Abilities.TANGLING_HAIR, - [Species.MILCERY]: Abilities.WELL_BAKED_BODY, + [Species.MILCERY]: Abilities.MISTY_SURGE, [Species.FALINKS]: Abilities.MOXIE, [Species.PINCURCHIN]: Abilities.IRON_BARBS, [Species.SNOM]: Abilities.SNOW_WARNING, @@ -3674,9 +3674,9 @@ export const starterPassiveAbilities = { [Species.RELLOR]: Abilities.MAGIC_GUARD, [Species.FLITTLE]: Abilities.COMPETITIVE, [Species.TINKATINK]: Abilities.HUGE_POWER, - [Species.WIGLETT]: Abilities.STORM_DRAIN, + [Species.WIGLETT]: Abilities.STURDY, [Species.BOMBIRDIER]: Abilities.UNAWARE, - [Species.FINIZEN]: Abilities.LIQUID_VOICE, + [Species.FINIZEN]: Abilities.IRON_FIST, [Species.VAROOM]: Abilities.SPEED_BOOST, [Species.CYCLIZAR]: Abilities.PROTEAN, [Species.ORTHWORM]: Abilities.HEATPROOF, @@ -3725,13 +3725,13 @@ export const starterPassiveAbilities = { [Species.ALOLA_RATTATA]: Abilities.CHEEK_POUCH, [Species.ALOLA_SANDSHREW]: Abilities.ICE_BODY, [Species.ALOLA_VULPIX]: Abilities.ICE_BODY, - [Species.ALOLA_DIGLETT]: Abilities.CUTE_CHARM, + [Species.ALOLA_DIGLETT]: Abilities.STURDY, [Species.ALOLA_MEOWTH]: Abilities.UNNERVE, [Species.ALOLA_GEODUDE]: Abilities.ELECTROMORPHOSIS, [Species.ALOLA_GRIMER]: Abilities.MERCILESS, [Species.ETERNAL_FLOETTE]: Abilities.MAGIC_GUARD, [Species.GALAR_MEOWTH]: Abilities.SUPER_LUCK, - [Species.GALAR_PONYTA]: Abilities.MAGIC_GUARD, + [Species.GALAR_PONYTA]: Abilities.PIXILATE, [Species.GALAR_SLOWPOKE]: Abilities.POISON_TOUCH, [Species.GALAR_FARFETCHD]: Abilities.SUPER_LUCK, [Species.GALAR_ARTICUNO]: Abilities.SERENE_GRACE, diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 909d255ee..adbe8a8d8 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -4,7 +4,7 @@ import { Variant, VariantSet, variantColorCache } from '#app/data/variant'; import { variantData } from '#app/data/variant'; import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from '../ui/battle-info'; import { Moves } from "../data/enums/moves"; -import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr, VariableMoveCategoryAttr } from "../data/move"; +import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariableAtkAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget, VariableDefAttr, AttackMove, ModifiedDamageAttr, VariableMoveTypeMultiplierAttr, IgnoreOpponentStatChangesAttr, SacrificialAttr, VariableMoveTypeAttr, VariableMoveCategoryAttr, CounterDamageAttr } from "../data/move"; import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from '../data/pokemon-species'; import * as Utils from '../utils'; import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from '../data/type'; @@ -43,8 +43,8 @@ import { Nature, getNatureStatMultiplier } from '../data/nature'; import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangeStatusEffectTrigger } from '../data/pokemon-forms'; import { TerrainType } from '../data/terrain'; import { TrainerSlot } from '../data/trainer-config'; +import { ABILITY_OVERRIDE, MOVE_OVERRIDE, MOVE_OVERRIDE_2, OPP_ABILITY_OVERRIDE, OPP_MOVE_OVERRIDE, OPP_MOVE_OVERRIDE_2, OPP_SHINY_OVERRIDE, OPP_VARIANT_OVERRIDE } from '../overrides'; import { BerryType } from '../data/berry'; -import { ABILITY_OVERRIDE, MOVE_OVERRIDE, OPP_ABILITY_OVERRIDE, OPP_MOVE_OVERRIDE, OPP_SHINY_OVERRIDE, OPP_VARIANT_OVERRIDE } from '../overrides'; import i18next from '../plugins/i18n'; export enum FieldPosition { @@ -725,6 +725,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.moveset[0] = new PokemonMove(MOVE_OVERRIDE, Math.min(this.moveset[0].ppUsed, allMoves[MOVE_OVERRIDE].pp)); else if (OPP_MOVE_OVERRIDE && !this.isPlayer()) this.moveset[0] = new PokemonMove(OPP_MOVE_OVERRIDE, Math.min(this.moveset[0].ppUsed, allMoves[OPP_MOVE_OVERRIDE].pp)); + if (MOVE_OVERRIDE_2 && this.isPlayer()) + this.moveset[1] = new PokemonMove(MOVE_OVERRIDE_2, Math.min(this.moveset[1].ppUsed, allMoves[MOVE_OVERRIDE_2].pp)); + else if (OPP_MOVE_OVERRIDE_2 && !this.isPlayer()) + this.moveset[1] = new PokemonMove(OPP_MOVE_OVERRIDE_2, Math.min(this.moveset[1].ppUsed, allMoves[OPP_MOVE_OVERRIDE_2].pp)); + return ret; } @@ -2474,9 +2479,10 @@ export class PlayerPokemon extends Pokemon { if (newEvolution.condition.predicate(this)) { const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, undefined, this.shiny, this.variant, this.ivs, this.nature); newPokemon.natureOverride = this.natureOverride; + newPokemon.passive = this.passive; + newPokemon.moveset = this.moveset.slice(); newPokemon.moveset = this.copyMoveset(); newPokemon.luck = this.luck; - newPokemon.fusionSpecies = this.fusionSpecies; newPokemon.fusionFormIndex = this.fusionFormIndex; newPokemon.fusionAbilityIndex = this.fusionAbilityIndex; @@ -2731,6 +2737,10 @@ export class EnemyPokemon extends Pokemon { let targetScores: integer[] = []; for (let mt of moveTargets[move.id]) { + // Prevent a target score from being calculated when the target is whoever attacks the user + if (mt === BattlerIndex.ATTACKER) + break; + const target = this.scene.getField()[mt]; let targetScore = move.getUserBenefitScore(this, target, move) + move.getTargetBenefitScore(this, target, move) * (mt < BattlerIndex.ENEMY === this.isPlayer() ? 1 : -1); if (move.name.endsWith(' (N)') || !move.applyConditions(this, target, move)) @@ -2801,8 +2811,14 @@ export class EnemyPokemon extends Pokemon { return scoreA < scoreB ? 1 : scoreA > scoreB ? -1 : 0; }); - if (!sortedBenefitScores.length) + if (!sortedBenefitScores.length) { + // Set target to BattlerIndex.ATTACKER when using a counter move + // This is the same as when the player does so + if (!!move.findAttr(attr => attr instanceof CounterDamageAttr)) + return [BattlerIndex.ATTACKER]; + return []; + } let targetWeights = sortedBenefitScores.map(s => s[1]); const lowestWeight = targetWeights[targetWeights.length - 1]; diff --git a/src/loading-scene.ts b/src/loading-scene.ts index 05b6c9f50..88e60fb9c 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -31,6 +31,8 @@ export class LoadingScene extends SceneBase { this.loadAtlas('bg', 'ui'); this.loadImage('command_fight_labels', 'ui'); this.loadAtlas('prompt', 'ui'); + this.loadImage('candy', 'ui'); + this.loadImage('candy_overlay', 'ui'); this.loadImage('cursor', 'ui'); this.loadImage('cursor_reverse', 'ui'); for (let wv of Utils.getEnumValues(WindowVariant)) { diff --git a/src/locales/fr/battle.ts b/src/locales/fr/battle.ts index 742a8f63d..a4abf5239 100644 --- a/src/locales/fr/battle.ts +++ b/src/locales/fr/battle.ts @@ -9,7 +9,7 @@ export const battle: SimpleTranslationEntries = { "trainerComeBack": "{{trainerName}} retire {{pokemonName}} !", "playerGo": "{{pokemonName}} ! Go !", "trainerGo": "{{pokemonName}} est envoyé par\n{{trainerName}} !", - "switchQuestion": "Voulez-vous changer\n{{pokemonName}} ?", + "switchQuestion": "Voulez-vous changer\nvotre {{pokemonName}} ?", "trainerDefeated": `Vous avez battu\n{{trainerName}} !`, "pokemonCaught": "Vous avez attrapé {{pokemonName}} !", "pokemon": "Pokémon", diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 4229b8be3..2e18cd917 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1151,7 +1151,7 @@ const enemyBuffModifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.ENEMY_ATTACK_FREEZE_CHANCE, 2), new WeightedModifierType(modifierTypes.ENEMY_ATTACK_BURN_CHANCE, 2), new WeightedModifierType(modifierTypes.ENEMY_STATUS_EFFECT_HEAL_CHANCE, 10), - new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 10000), + new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 5), new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 1) ].map(m => { m.setTier(ModifierTier.COMMON); return m; }), [ModifierTier.GREAT]: [ @@ -1162,12 +1162,12 @@ const enemyBuffModifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 1) ].map(m => { m.setTier(ModifierTier.GREAT); return m; }), [ModifierTier.ULTRA]: [ - new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_BOOSTER, 5), - new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_REDUCTION, 5), - new WeightedModifierType(modifierTypes.ENEMY_HEAL, 5), - new WeightedModifierType(modifierTypes.ENEMY_STATUS_EFFECT_HEAL_CHANCE, 5), - new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 5), - new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 300) + new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_BOOSTER, 10), + new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_REDUCTION, 10), + new WeightedModifierType(modifierTypes.ENEMY_HEAL, 10), + new WeightedModifierType(modifierTypes.ENEMY_STATUS_EFFECT_HEAL_CHANCE, 10), + new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 10), + new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 5) ].map(m => { m.setTier(ModifierTier.ULTRA); return m; }), [ModifierTier.ROGUE]: [ ].map(m => { m.setTier(ModifierTier.ROGUE); return m; }), [ModifierTier.MASTER]: [ ].map(m => { m.setTier(ModifierTier.MASTER); return m; }) diff --git a/src/overrides.ts b/src/overrides.ts index 732b1a5a4..4b9bcaa0b 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -15,9 +15,11 @@ export const WEATHER_OVERRIDE = WeatherType.NONE; export const ABILITY_OVERRIDE = Abilities.NONE; export const MOVE_OVERRIDE = Moves.NONE; +export const MOVE_OVERRIDE_2 = Moves.NONE; export const OPP_SPECIES_OVERRIDE = 0; export const OPP_ABILITY_OVERRIDE = Abilities.NONE; export const OPP_MOVE_OVERRIDE = Moves.NONE; +export const OPP_MOVE_OVERRIDE_2 = Moves.NONE; export const OPP_SHINY_OVERRIDE = false; export const OPP_VARIANT_OVERRIDE = 0; diff --git a/src/phases.ts b/src/phases.ts index e4ed8d293..a3b66edf0 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2,7 +2,7 @@ import BattleScene, { bypassLogin, startingWave } from "./battle-scene"; import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon"; import * as Utils from './utils'; import { Moves } from "./data/enums/moves"; -import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, DelayedAttackAttr, RechargeAttr, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, FixedDamageAttr, OneHitKOAccuracyAttr, ForceSwitchOutAttr } from "./data/move"; +import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, DelayedAttackAttr, RechargeAttr, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, FixedDamageAttr, OneHitKOAccuracyAttr, ForceSwitchOutAttr, VariableTargetAttr } from "./data/move"; import { Mode } from './ui/ui'; import { Command } from "./ui/command-ui-handler"; import { Stat } from "./data/pokemon-stat"; @@ -57,6 +57,7 @@ import { fetchDailyRunSeed, getDailyRunStarters } from "./data/daily-run"; import { GameModes, gameModes } from "./game-mode"; import { getPokemonSpecies, speciesStarters } from "./data/pokemon-species"; import i18next from './plugins/i18n'; +import { Abilities } from "./data/enums/abilities"; import { STARTER_FORM_OVERRIDE, STARTER_SPECIES_OVERRIDE } from './overrides'; export class LoginPhase extends Phase { @@ -1729,7 +1730,7 @@ export class CommandPhase extends FieldPhase { }, null, true); } else if (cursor < 5) { const targetPokemon = this.scene.getEnemyField().find(p => p.isActive(true)); - if (targetPokemon.isBoss() && targetPokemon.bossSegmentIndex >= 1 && cursor < PokeballType.MASTER_BALL) { + if (targetPokemon.isBoss() && targetPokemon.bossSegmentIndex >= 1 && !targetPokemon.hasAbility(Abilities.WONDER_GUARD, false, true) && cursor < PokeballType.MASTER_BALL) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.showText(i18next.t('battle:noPokeballStrong'), null, () => { @@ -2399,7 +2400,7 @@ export class MoveEffectPhase extends PokemonPhase { const targetHitChecks = Object.fromEntries(targets.map(p => [ p.getBattlerIndex(), this.hitCheck(p) ])); const activeTargets = targets.map(t => t.isActive(true)); - if (!activeTargets.length || (!this.move.getMove().isMultiTarget() && !targetHitChecks[this.targets[0]])) { + if (!activeTargets.length || (!this.move.getMove().getAttrs(VariableTargetAttr).length && !this.move.getMove().isMultiTarget() && !targetHitChecks[this.targets[0]])) { user.turnData.hitCount = 1; user.turnData.hitsLeft = 1; if (activeTargets.length) { @@ -3219,19 +3220,22 @@ export class VictoryPhase extends PokemonPhase { const expShareModifier = this.scene.findModifier(m => m instanceof ExpShareModifier) as ExpShareModifier; const expBalanceModifier = this.scene.findModifier(m => m instanceof ExpBalanceModifier) as ExpBalanceModifier; const multipleParticipantExpBonusModifier = this.scene.findModifier(m => m instanceof MultipleParticipantExpBonusModifier) as MultipleParticipantExpBonusModifier; - const expPartyMembers = party.filter(p => p.hp && p.level < this.scene.getMaxExpLevel()); + const nonFaintedPartyMembers = party.filter(p => p.hp); + const expPartyMembers = nonFaintedPartyMembers.filter(p => p.level < this.scene.getMaxExpLevel()); const partyMemberExp = []; if (participantIds.size) { let expValue = this.getPokemon().getExpValue(); if (this.scene.currentBattle.battleType === BattleType.TRAINER) expValue = Math.floor(expValue * 1.5); - for (let partyMember of expPartyMembers) { + for (let partyMember of nonFaintedPartyMembers) { const pId = partyMember.id; const participated = participantIds.has(pId); if (participated) partyMember.addFriendship(2); - else if (!expShareModifier) { + if (!expPartyMembers.includes(partyMember)) + continue; + if (!participated && !expShareModifier) { partyMemberExp.push(0); continue; } diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 05b2ac59d..f887fe69c 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -129,6 +129,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private starterSelectMessageBox: Phaser.GameObjects.NineSlice; private starterSelectMessageBoxContainer: Phaser.GameObjects.Container; private statsContainer: StatsContainer; + private pokemonFormText: Phaser.GameObjects.Text; private genMode: boolean; private statsMode: boolean; @@ -435,6 +436,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonCandyIcon.setOrigin(0, 0); this.starterSelectContainer.add(this.pokemonCandyIcon); + this.pokemonFormText = addTextObject(this.scene, 6, 42, 'Form', TextStyle.WINDOW_ALT, { fontSize: '42px' }); + this.pokemonFormText.setOrigin(0, 0); + this.starterSelectContainer.add(this.pokemonFormText); + this.pokemonCandyOverlayIcon = this.scene.add.sprite(1, 12, 'items', 'candy_overlay'); this.pokemonCandyOverlayIcon.setScale(0.5); this.pokemonCandyOverlayIcon.setOrigin(0, 0); @@ -1289,6 +1294,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonCandyOverlayIcon.setVisible(true); this.pokemonCandyCountText.setText(`x${this.scene.gameData.starterData[species.speciesId].candyCount}`); this.pokemonCandyCountText.setVisible(true); + this.pokemonFormText.setVisible(true); } this.iconAnimHandler.addOrUpdate(this.starterSelectGenIconContainers[species.generation - 1].getAt(this.genSpecies[species.generation - 1].indexOf(species)) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.PASSIVE); @@ -1338,6 +1344,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonCandyIcon.setVisible(false); this.pokemonCandyOverlayIcon.setVisible(false); this.pokemonCandyCountText.setVisible(false); + this.pokemonFormText.setVisible(false); const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, true, true); const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); @@ -1364,6 +1371,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonCandyIcon.setVisible(false); this.pokemonCandyOverlayIcon.setVisible(false); this.pokemonCandyCountText.setVisible(false); + this.pokemonFormText.setVisible(false); this.setSpeciesDetails(species, false, 0, false, 0, 0, 0); this.pokemonSprite.clearTint(); @@ -1523,6 +1531,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.starterMoveset.push(...availableStarterMoves.filter(sm => this.starterMoveset.indexOf(sm) === -1).slice(0, 4 - this.starterMoveset.length)); const speciesForm = getPokemonSpeciesForm(species.speciesId, formIndex); + + const formText = species?.forms[formIndex]?.formKey.split('-'); + for (let i = 0; i < formText?.length; i++) + formText[i] = formText[i].charAt(0).toUpperCase() + formText[i].substring(1); + + this.pokemonFormText.setText(formText?.join(' ')); + this.setTypeIcons(speciesForm.type1, speciesForm.type2); } else { this.pokemonAbilityText.setText(''); diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index d048328f3..ac04d41be 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -1,8 +1,10 @@ -import BattleScene from "../battle-scene"; +import BattleScene, { starterColors } from "../battle-scene"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import * as Utils from "../utils"; import { PlayerPokemon } from "../field/pokemon"; +import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from '../data/pokemon-species'; +import { argbFromRgba } from "@material/material-color-utilities"; import { Type, getTypeRgb } from "../data/type"; import { TextStyle, addBBCodeTextObject, addTextObject, getBBCodeFrag, getTextColor } from "./text"; import Move, { MoveCategory } from "../data/move"; @@ -45,6 +47,9 @@ export default class SummaryUiHandler extends UiHandler { private genderText: Phaser.GameObjects.Text; private shinyIcon: Phaser.GameObjects.Image; private fusionShinyIcon: Phaser.GameObjects.Image; + private candyShadow: Phaser.GameObjects.Sprite; + private candyIcon: Phaser.GameObjects.Sprite; + private candyOverlay: Phaser.GameObjects.Sprite; private statusContainer: Phaser.GameObjects.Container; private status: Phaser.GameObjects.Image; private summaryPageContainer: Phaser.GameObjects.Container; @@ -137,6 +142,20 @@ export default class SummaryUiHandler extends UiHandler { this.pokeball.setOrigin(0, 1); this.summaryContainer.add(this.pokeball); + this.candyShadow = this.scene.add.sprite(13, -140, 'candy'); + this.candyShadow.setTint(0x141414) + this.candyShadow.setScale(0.8); + this.candyShadow.setInteractive(new Phaser.Geom.Rectangle(0, 0, 16, 16), Phaser.Geom.Rectangle.Contains); + this.summaryContainer.add(this.candyShadow); + + this.candyIcon = this.scene.add.sprite(13, -140, 'candy'); + this.candyIcon.setScale(0.8); + this.summaryContainer.add(this.candyIcon); + + this.candyOverlay = this.scene.add.sprite(13, -140, 'candy_overlay'); + this.candyOverlay.setScale(0.8); + this.summaryContainer.add(this.candyOverlay); + this.levelText = addTextObject(this.scene, 36, -17, '', TextStyle.SUMMARY_ALT); this.levelText.setOrigin(0, 1); this.summaryContainer.add(this.levelText); @@ -223,6 +242,10 @@ export default class SummaryUiHandler extends UiHandler { this.shinyOverlay.setVisible(this.pokemon.isShiny()); + const colorScheme = starterColors[this.pokemon.species.getRootSpeciesId()]; + this.candyIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[0]))); + this.candyOverlay.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[1]))); + this.numberText.setText(Utils.padInt(this.pokemon.species.speciesId, 4)); this.numberText.setColor(this.getTextColor(!this.pokemon.isShiny() ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD)); this.numberText.setShadowColor(this.getTextColor(!this.pokemon.isShiny() ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD, true)); @@ -252,6 +275,21 @@ export default class SummaryUiHandler extends UiHandler { this.splicedIcon.on('pointerout', () => (this.scene as BattleScene).ui.hideTooltip()); } + var currentFriendship = this.scene.gameData.starterData[this.pokemon.species.getRootSpeciesId()].friendship; + if (!currentFriendship || currentFriendship === undefined) + currentFriendship = 0; + + const friendshipCap = getStarterValueFriendshipCap(speciesStarters[this.pokemon.species.getRootSpeciesId()]); + const candyCropY = 16 - (16 * (currentFriendship / friendshipCap)); + + if (this.candyShadow.visible) { + this.candyShadow.on('pointerover', () => (this.scene as BattleScene).ui.showTooltip(null, `${currentFriendship}/${friendshipCap}`, true)); + this.candyShadow.on('pointerout', () => (this.scene as BattleScene).ui.hideTooltip()); + } + + this.candyIcon.setCrop(0,candyCropY,16, 16); + this.candyOverlay.setCrop(0,candyCropY,16, 16); + const doubleShiny = isFusion && this.pokemon.shiny && this.pokemon.fusionShiny; const baseVariant = !doubleShiny ? this.pokemon.getVariant() : this.pokemon.variant;