diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 9e4ff703ade..764541a1422 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -215,9 +215,12 @@ export class TrappedTag extends BattlerTag { } canAdd(pokemon: Pokemon): boolean { + const source = pokemon.scene.getPokemonById(this.sourceId!)!; + const move = allMoves[this.sourceMove]; + const isGhost = pokemon.isOfType(Type.GHOST); const isTrapped = pokemon.getTag(BattlerTagType.TRAPPED); - const hasSubstitute = pokemon.getTag(BattlerTagType.SUBSTITUTE); + const hasSubstitute = move.hitsSubstitute(source, pokemon); return !isTrapped && !isGhost && !hasSubstitute; } diff --git a/src/data/move.ts b/src/data/move.ts index 5880fc352a7..2310aeb61cd 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1495,10 +1495,24 @@ export class AddSubstituteAttr extends MoveEffectAttr { } getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { - if (user.isBoss() || user.getHpRatio() < 0.25) { + if (user.isBoss()) { return -10; } - return Math.ceil(user.getHpRatio() * 10); + return 5; + } + + getCondition(): MoveConditionFunc { + return (user, target, move) => !user.getTag(SubstituteTag) && user.hp > Math.floor(user.getMaxHp() / 4) && user.getMaxHp() > 1; + } + + getFailedText(user: Pokemon, target: Pokemon, move: Move, cancelled: Utils.BooleanHolder): string | null { + if (user.getTag(SubstituteTag)) { + return i18next.t("moveTriggers:substituteOnOverlap", { pokemonName: getPokemonNameWithAffix(user) }); + } else if (user.hp <= Math.floor(user.getMaxHp() / 4) || user.getMaxHp() === 1) { + return i18next.t("moveTriggers:substituteNotEnoughHp"); + } else { + return i18next.t("battle:attackFailed"); + } } } @@ -6914,8 +6928,7 @@ export function initMoves() { .attr(HighCritAttr) .slicingMove(), new SelfStatusMove(Moves.SUBSTITUTE, Type.NORMAL, -1, 10, -1, 0, 1) - .attr(AddSubstituteAttr) - .condition((user, target, move) => !user.getTag(SubstituteTag) && user.getHpRatio() > 0.25 && user.getMaxHp() > 1), + .attr(AddSubstituteAttr), new AttackMove(Moves.STRUGGLE, Type.NORMAL, MoveCategory.PHYSICAL, 50, -1, 1, -1, 0, 1) .attr(RecoilAttr, true, 0.25, true) .attr(TypelessAttr) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index b0625b88d44..9d48a0c6fdb 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2296,13 +2296,17 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.scene.gameData.gameStats.highestDamage = damage.value; } } - source.turnData.damageDealt += damage.value; - source.turnData.currDamageDealt = damage.value; - this.battleData.hitCount++; - const attackResult = { move: move.id, result: result as DamageResult, damage: damage.value, critical: isCritical, sourceId: source.id, sourceBattlerIndex: source.getBattlerIndex() }; - this.turnData.attacksReceived.unshift(attackResult); - if (source.isPlayer() && !this.isPlayer()) { - this.scene.applyModifiers(DamageMoneyRewardModifier, true, source, damage); + + if (damage.value > 0) { + source.turnData.damageDealt += damage.value; + source.turnData.currDamageDealt = damage.value; + this.battleData.hitCount++; + const attackResult = { move: move.id, result: result as DamageResult, damage: damage.value, critical: isCritical, sourceId: source.id, sourceBattlerIndex: source.getBattlerIndex() }; + this.turnData.attacksReceived.unshift(attackResult); + + if (source.isPlayer() && !this.isPlayer()) { + this.scene.applyModifiers(DamageMoneyRewardModifier, true, source, damage); + } } } diff --git a/src/locales/en/move-trigger.json b/src/locales/en/move-trigger.json index baddbaa34bf..50a073b42ae 100644 --- a/src/locales/en/move-trigger.json +++ b/src/locales/en/move-trigger.json @@ -61,5 +61,7 @@ "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", "revivalBlessing": "{{pokemonName}} was revived!", "swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!", - "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!" + "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", + "substituteOnOverlap": "{{pokemonName}} already\nhas a substitute!", + "substituteNotEnoughHp": "But it does not have enough HP\nleft to make a substitute!" }