Skip to content

Commit

Permalink
Merge branch 'beta' into betterTargetSelect
Browse files Browse the repository at this point in the history
  • Loading branch information
MokaStitcher authored Nov 14, 2024
2 parents c35e635 + 640ac23 commit 04985fc
Show file tree
Hide file tree
Showing 26 changed files with 665 additions and 239 deletions.
2 changes: 1 addition & 1 deletion public/locales
Submodule locales updated 45 files
+1 −1 de/dialogue.json
+1 −1 de/modifier-type.json
+2 −1 de/move-trigger.json
+13 −13 de/move.json
+8 −8 de/mystery-encounters/bug-type-superfan-dialogue.json
+6 −6 de/mystery-encounters/lost-at-sea-dialogue.json
+1 −1 en/modifier-type.json
+2 −1 en/move-trigger.json
+0 −3 es-ES/modifier-type.json
+1 −1 fr/modifier-type.json
+2 −1 fr/move-trigger.json
+1 −1 fr/mystery-encounters/uncommon-breed-dialogue.json
+3 −0 he/dialogue-final-boss.json
+7 −3 he/mystery-encounters/an-offer-you-cant-refuse-dialogue.json
+81 −1 he/pokemon.json
+2 −1 it/arena-flyout.json
+2 −1 it/arena-tag.json
+2 −0 it/battle.json
+3 −1 it/battler-tags.json
+27 −14 it/modifier-type.json
+2 −1 it/move-trigger.json
+18 −0 it/status-effect.json
+2 −0 ja/battle.json
+3 −1 ja/battler-tags.json
+4 −3 ja/modifier-type.json
+2 −1 ja/move-trigger.json
+1 −0 ja/splash-texts.json
+1 −1 ko/modifier-type.json
+2 −1 pt-BR/arena-flyout.json
+2 −1 pt-BR/arena-tag.json
+2 −0 pt-BR/battle.json
+3 −1 pt-BR/battler-tags.json
+4 −3 pt-BR/modifier-type.json
+2 −1 pt-BR/move-trigger.json
+1 −0 pt-BR/mystery-encounters/fun-and-games-dialogue.json
+1 −1 pt-BR/mystery-encounters/part-timer-dialogue.json
+1 −1 pt-BR/mystery-encounters/shady-vitamin-dealer-dialogue.json
+1 −1 pt-BR/mystery-encounters/training-session-dialogue.json
+2 −1 zh-CN/arena-flyout.json
+2 −1 zh-CN/arena-tag.json
+2 −0 zh-CN/battle.json
+3 −1 zh-CN/battler-tags.json
+5 −1 zh-CN/modifier-type.json
+2 −1 zh-CN/move-trigger.json
+1 −1 zh-TW/modifier-type.json
34 changes: 28 additions & 6 deletions src/battle-scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1233,12 +1233,34 @@ export default class BattleScene extends SceneBase {
newDouble = !!double;
}

if (Overrides.BATTLE_TYPE_OVERRIDE === "double") {
newDouble = true;
}
/* Override battles into single only if not fighting with trainers */
if (newBattleType !== BattleType.TRAINER && Overrides.BATTLE_TYPE_OVERRIDE === "single") {
newDouble = false;
if (!isNullOrUndefined(Overrides.BATTLE_TYPE_OVERRIDE)) {
let doubleOverrideForWave: "single" | "double" | null = null;

switch (Overrides.BATTLE_TYPE_OVERRIDE) {
case "double":
doubleOverrideForWave = "double";
break;
case "single":
doubleOverrideForWave = "single";
break;
case "even-doubles":
doubleOverrideForWave = (newWaveIndex % 2) ? "single" : "double";
break;
case "odd-doubles":
doubleOverrideForWave = (newWaveIndex % 2) ? "double" : "single";
break;
}

if (doubleOverrideForWave === "double") {
newDouble = true;
}
/**
* Override battles into single only if not fighting with trainers.
* @see {@link https://github.com/pagefaultgames/pokerogue/issues/1948 | GitHub Issue #1948}
*/
if (newBattleType !== BattleType.TRAINER && doubleOverrideForWave === "single") {
newDouble = false;
}
}

const lastBattle = this.currentBattle;
Expand Down
61 changes: 13 additions & 48 deletions src/data/ability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Weather } from "#app/data/weather";
import { BattlerTag, BattlerTagLapseType, GroundedTag } from "./battler-tags";
import { getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "#app/data/status-effect";
import { Gender } from "./gender";
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move";
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "../modifier/modifier";
import { TerrainType } from "./terrain";
Expand Down Expand Up @@ -1351,65 +1351,30 @@ export class AddSecondStrikeAbAttr extends PreAttackAbAttr {
this.damageMultiplier = damageMultiplier;
}

/**
* Determines whether this attribute can apply to a given move.
* @param {Move} move the move to which this attribute may apply
* @param numTargets the number of {@linkcode Pokemon} targeted by this move
* @returns true if the attribute can apply to the move, false otherwise
*/
canApplyPreAttack(move: Move, numTargets: integer): boolean {
/**
* Parental Bond cannot apply to multi-hit moves, charging moves, or
* moves that cause the user to faint.
*/
const exceptAttrs: Constructor<MoveAttr>[] = [
MultiHitAttr,
SacrificialAttr,
SacrificialAttrOnHit
];

/** Parental Bond cannot apply to these specific moves */
const exceptMoves: Moves[] = [
Moves.FLING,
Moves.UPROAR,
Moves.ROLLOUT,
Moves.ICE_BALL,
Moves.ENDEAVOR
];

/** Also check if this move is an Attack move and if it's only targeting one Pokemon */
return numTargets === 1
&& !move.isChargingMove()
&& !exceptAttrs.some(attr => move.hasAttr(attr))
&& !exceptMoves.some(id => move.id === id)
&& move.category !== MoveCategory.STATUS;
}

/**
* If conditions are met, this doubles the move's hit count (via args[1])
* or multiplies the damage of secondary strikes (via args[2])
* @param {Pokemon} pokemon the Pokemon using the move
* @param pokemon the {@linkcode Pokemon} using the move
* @param passive n/a
* @param defender n/a
* @param {Move} move the move used by the ability source
* @param args\[0\] the number of Pokemon this move is targeting
* @param {Utils.IntegerHolder} args\[1\] the number of strikes with this move
* @param {Utils.NumberHolder} args\[2\] the damage multiplier for the current strike
* @param move the {@linkcode Move} used by the ability source
* @param args Additional arguments:
* - `[0]` the number of strikes this move currently has ({@linkcode Utils.NumberHolder})
* - `[1]` the damage multiplier for the current strike ({@linkcode Utils.NumberHolder})
* @returns
*/
applyPreAttack(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, args: any[]): boolean {
const numTargets = args[0] as integer;
const hitCount = args[1] as Utils.IntegerHolder;
const multiplier = args[2] as Utils.NumberHolder;
const hitCount = args[0] as Utils.NumberHolder;
const multiplier = args[1] as Utils.NumberHolder;

if (this.canApplyPreAttack(move, numTargets)) {
if (move.canBeMultiStrikeEnhanced(pokemon, true)) {
this.showAbility = !!hitCount?.value;
if (!!hitCount?.value) {
hitCount.value *= 2;
if (hitCount?.value) {
hitCount.value += 1;
}

if (!!multiplier?.value && pokemon.turnData.hitsLeft % 2 === 1 && pokemon.turnData.hitsLeft !== pokemon.turnData.hitCount) {
multiplier.value *= this.damageMultiplier;
if (multiplier?.value && pokemon.turnData.hitsLeft === 1) {
multiplier.value = this.damageMultiplier;
}
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/data/challenge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,7 @@ export class FreshStartChallenge extends Challenge {
pokemon.shiny = false; // Not shiny
pokemon.variant = 0; // Not shiny
pokemon.formIndex = 0; // Froakie should be base form
pokemon.ivs = [ 10, 10, 10, 10, 10, 10 ]; // Default IVs of 10 for all stats
pokemon.ivs = [ 15, 15, 15, 15, 15, 15 ]; // Default IVs of 15 for all stats (Updated to 15 from 10 in 1.2.0)
return true;
}

Expand Down
85 changes: 74 additions & 11 deletions src/data/move.ts
Original file line number Diff line number Diff line change
Expand Up @@ -668,12 +668,12 @@ export default class Move implements Localizable {
}

/**
* Sees if, given the target pokemon, a move fails on it (by looking at each {@linkcode MoveAttr} of this move
* Sees if a move has a custom failure text (by looking at each {@linkcode MoveAttr} of this move)
* @param user {@linkcode Pokemon} using the move
* @param target {@linkcode Pokemon} receiving the move
* @param move {@linkcode Move} using the move
* @param cancelled {@linkcode Utils.BooleanHolder} to hold boolean value
* @returns string of the failed text, or null
* @returns string of the custom failure text, or `null` if it uses the default text ("But it failed!")
*/
getFailedText(user: Pokemon, target: Pokemon, move: Move, cancelled: Utils.BooleanHolder): string | null {
for (const attr of this.attrs) {
Expand Down Expand Up @@ -818,8 +818,6 @@ export default class Move implements Localizable {

applyMoveAttrs(VariablePowerAttr, source, target, this, power);

source.scene.applyModifiers(PokemonMultiHitModifier, source.isPlayer(), source, new Utils.IntegerHolder(0), power);

if (!this.hasAttr(TypelessAttr)) {
source.scene.arena.applyTags(WeakenMoveTypeTag, simulated, this.type, power);
source.scene.applyModifiers(AttackTypeBoosterModifier, source.isPlayer(), source, this.type, power);
Expand All @@ -840,6 +838,45 @@ export default class Move implements Localizable {

return priority.value;
}

/**
* Returns `true` if this move can be given additional strikes
* by enhancing effects.
* Currently used for {@link https://bulbapedia.bulbagarden.net/wiki/Parental_Bond_(Ability) | Parental Bond}
* and {@linkcode PokemonMultiHitModifier | Multi-Lens}.
* @param user The {@linkcode Pokemon} using the move
* @param restrictSpread `true` if the enhancing effect
* should not affect multi-target moves (default `false`)
*/
canBeMultiStrikeEnhanced(user: Pokemon, restrictSpread: boolean = false): boolean {
// Multi-strike enhancers...

// ...cannot enhance moves that hit multiple targets
const { targets, multiple } = getMoveTargets(user, this.id);
const isMultiTarget = multiple && targets.length > 1;

// ...cannot enhance multi-hit or sacrificial moves
const exceptAttrs: Constructor<MoveAttr>[] = [
MultiHitAttr,
SacrificialAttr,
SacrificialAttrOnHit
];

// ...and cannot enhance these specific moves.
const exceptMoves: Moves[] = [
Moves.FLING,
Moves.UPROAR,
Moves.ROLLOUT,
Moves.ICE_BALL,
Moves.ENDEAVOR
];

return (!restrictSpread || !isMultiTarget)
&& !this.isChargingMove()
&& !exceptAttrs.some(attr => this.hasAttr(attr))
&& !exceptMoves.some(id => this.id === id)
&& this.category !== MoveCategory.STATUS;
}
}

export class AttackMove extends Move {
Expand Down Expand Up @@ -4934,16 +4971,42 @@ export class NeutralDamageAgainstFlyingTypeMultiplierAttr extends VariableMoveTy
}
}

export class WaterSuperEffectTypeMultiplierAttr extends VariableMoveTypeMultiplierAttr {
/**
* This class forces Freeze-Dry to be super effective against Water Type.
* It considers if target is Mono or Dual Type and calculates the new Multiplier accordingly.
* @see {@linkcode apply}
*/
export class FreezeDryAttr extends VariableMoveTypeMultiplierAttr {
/**
* If the target is Mono Type (Water only) then a 2x Multiplier is always forced.
* If target is Dual Type (containing Water) then only a 2x Multiplier is forced for the Water Type.
*
* Additionally Freeze-Dry's effectiveness against water is always forced during {@linkcode InverseBattleChallenge}.
* The multiplier is recalculated for the non-Water Type in case of Dual Type targets containing Water Type.
*
* @param user The {@linkcode Pokemon} applying the move
* @param target The {@linkcode Pokemon} targeted by the move
* @param move The move used by the user
* @param args `[0]` a {@linkcode Utils.NumberHolder | NumberHolder} containing a type effectiveness multiplier
* @returns `true` if super effectiveness on water type is forced; `false` otherwise
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const multiplier = args[0] as Utils.NumberHolder;
if (target.isOfType(Type.WATER)) {
const effectivenessAgainstWater = new Utils.NumberHolder(getTypeDamageMultiplier(move.type, Type.WATER));
applyChallenges(user.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, effectivenessAgainstWater);
if (effectivenessAgainstWater.value !== 0) {
multiplier.value *= 2 / effectivenessAgainstWater.value;
if (target.isOfType(Type.WATER) && multiplier.value !== 0) {
const multipleTypes = (target.getTypes().length > 1);

if (multipleTypes) {
const nonWaterType = target.getTypes().filter(type => type !== Type.WATER)[0];
const effectivenessAgainstTarget = new Utils.NumberHolder(getTypeDamageMultiplier(user.getMoveType(move), nonWaterType));

applyChallenges(user.scene.gameMode, ChallengeType.TYPE_EFFECTIVENESS, effectivenessAgainstTarget);

multiplier.value = effectivenessAgainstTarget.value * 2;
return true;
}

multiplier.value = 2;
return true;
}

return false;
Expand Down Expand Up @@ -9385,7 +9448,7 @@ export function initMoves() {
.target(MoveTarget.ALL_NEAR_OTHERS),
new AttackMove(Moves.FREEZE_DRY, Type.ICE, MoveCategory.SPECIAL, 70, 100, 20, 10, 0, 6)
.attr(StatusEffectAttr, StatusEffect.FREEZE)
.attr(WaterSuperEffectTypeMultiplierAttr)
.attr(FreezeDryAttr)
.edgeCase(), // This currently just multiplies the move's power instead of changing its effectiveness. It also doesn't account for abilities that modify type effectiveness such as tera shell.
new AttackMove(Moves.DISARMING_VOICE, Type.FAIRY, MoveCategory.SPECIAL, 40, -1, 15, -1, 0, 6)
.soundBased()
Expand Down
9 changes: 5 additions & 4 deletions src/field/pokemon.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2642,10 +2642,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const numTargets = multiple ? targets.length : 1;
const targetMultiplier = (numTargets > 1) ? 0.75 : 1;

/** 0.25x multiplier if this is an added strike from the attacker's Parental Bond */
const parentalBondMultiplier = new Utils.NumberHolder(1);
/** Multiplier for moves enhanced by Multi-Lens and/or Parental Bond */
const multiStrikeEnhancementMultiplier = new Utils.NumberHolder(1);
source.scene.applyModifiers(PokemonMultiHitModifier, source.isPlayer(), source, move.id, null, multiStrikeEnhancementMultiplier);
if (!ignoreSourceAbility) {
applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, simulated, numTargets, new Utils.IntegerHolder(0), parentalBondMultiplier);
applyPreAttackAbAttrs(AddSecondStrikeAbAttr, source, this, move, simulated, null, multiStrikeEnhancementMultiplier);
}

/** Doubles damage if this Pokemon's last move was Glaive Rush */
Expand Down Expand Up @@ -2722,7 +2723,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
damage.value = Utils.toDmgValue(
baseDamage
* targetMultiplier
* parentalBondMultiplier.value
* multiStrikeEnhancementMultiplier.value
* arenaAttackTypeMultiplier.value
* glaiveRushMultiplier.value
* criticalMultiplier.value
Expand Down
62 changes: 44 additions & 18 deletions src/modifier/modifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import { allMoves } from "#app/data/move";
import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball";
import { type FormChangeItem, SpeciesFormChangeItemTrigger, SpeciesFormChangeLapseTeraTrigger, SpeciesFormChangeTeraTrigger } from "#app/data/pokemon-forms";
import { getStatusEffectHealText } from "#app/data/status-effect";
import { Type } from "#enums/type";
import Pokemon, { type PlayerPokemon } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages";
import Overrides from "#app/overrides";
Expand All @@ -22,11 +21,13 @@ import { BooleanHolder, hslToHex, isNullOrUndefined, NumberHolder, toDmgValue }
import { Abilities } from "#enums/abilities";
import { BattlerTagType } from "#enums/battler-tag-type";
import { BerryType } from "#enums/berry-type";
import { Moves } from "#enums/moves";
import type { Nature } from "#enums/nature";
import type { PokeballType } from "#enums/pokeball";
import { Species } from "#enums/species";
import { type PermanentStat, type TempBattleStat, BATTLE_STATS, Stat, TEMP_BATTLE_STATS } from "#enums/stat";
import { StatusEffect } from "#enums/status-effect";
import { Type } from "#enums/type";
import i18next from "i18next";
import { type DoubleBattleChanceBoosterModifierType, type EvolutionItemModifierType, type FormChangeItemModifierType, type ModifierOverride, type ModifierType, type PokemonBaseStatTotalModifierType, type PokemonExpBoosterModifierType, type PokemonFriendshipBoosterModifierType, type PokemonMoveAccuracyBoosterModifierType, type PokemonMultiHitModifierType, type TerastallizeModifierType, type TmModifierType, getModifierType, ModifierPoolType, ModifierTypeGenerator, modifierTypes, PokemonHeldItemModifierType } from "./modifier-type";
import { Color, ShadowColor } from "#enums/color";
Expand Down Expand Up @@ -2689,32 +2690,57 @@ export class PokemonMultiHitModifier extends PokemonHeldItemModifier {
}

/**
* Applies {@linkcode PokemonMultiHitModifier}
* @param _pokemon The {@linkcode Pokemon} using the move
* @param count {@linkcode NumberHolder} holding the number of items
* @param power {@linkcode NumberHolder} holding the power of the move
* For each stack, converts 25 percent of attack damage into an additional strike.
* @param pokemon The {@linkcode Pokemon} using the move
* @param moveId The {@linkcode Moves | identifier} for the move being used
* @param count {@linkcode NumberHolder} holding the move's hit count for this turn
* @param damageMultiplier {@linkcode NumberHolder} holding a damage multiplier applied to a strike of this move
* @returns always `true`
*/
override apply(_pokemon: Pokemon, count: NumberHolder, power: NumberHolder): boolean {
count.value *= (this.getStackCount() + 1);
override apply(pokemon: Pokemon, moveId: Moves, count: NumberHolder | null = null, damageMultiplier: NumberHolder | null = null): boolean {
const move = allMoves[moveId];
/**
* The move must meet Parental Bond's restrictions for this item
* to apply. This means
* - Only attacks are boosted
* - Multi-strike moves, charge moves, and self-sacrificial moves are not boosted
* (though Multi-Lens can still affect moves boosted by Parental Bond)
* - Multi-target moves are not boosted *unless* they can only hit a single Pokemon
* - Fling, Uproar, Rollout, Ice Ball, and Endeavor are not boosted
*/
if (!move.canBeMultiStrikeEnhanced(pokemon)) {
return false;
}

switch (this.getStackCount()) {
case 1:
power.value *= 0.4;
break;
case 2:
power.value *= 0.25;
break;
case 3:
power.value *= 0.175;
break;
if (!isNullOrUndefined(count)) {
return this.applyHitCountBoost(count);
} else if (!isNullOrUndefined(damageMultiplier)) {
return this.applyDamageModifier(pokemon, damageMultiplier);
}

return false;
}

/** Adds strikes to a move equal to the number of stacked Multi-Lenses */
private applyHitCountBoost(count: NumberHolder): boolean {
count.value += this.getStackCount();
return true;
}

/**
* If applied to the first hit of a move, sets the damage multiplier
* equal to (1 - the number of stacked Multi-Lenses).
* Additional strikes beyond that are given a 0.25x damage multiplier
*/
private applyDamageModifier(pokemon: Pokemon, damageMultiplier: NumberHolder): boolean {
damageMultiplier.value = (pokemon.turnData.hitsLeft === pokemon.turnData.hitCount)
? (1 - (0.25 * this.getStackCount()))
: 0.25;
return true;
}

getMaxHeldItemCount(pokemon: Pokemon): number {
return 3;
return 2;
}
}

Expand Down
Loading

0 comments on commit 04985fc

Please sign in to comment.