From 161ceb4daa19a82d039caf8a96b6b462e4115a4c Mon Sep 17 00:00:00 2001 From: Alvin Zou Date: Tue, 7 May 2024 02:59:03 -0700 Subject: [PATCH] Implement Beat Up --- src/data/move.ts | 50 +++++++++++++++++++++++++++++++++++-- src/data/pokemon-species.ts | 10 ++++++++ 2 files changed, 58 insertions(+), 2 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 36254320f..38875ee4a 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -804,6 +804,7 @@ export enum MultiHitType { _3, _3_INCR, _1_TO_10, + BEAT_UP, } export class HealAttr extends MoveEffectAttr { @@ -1069,6 +1070,11 @@ export class MultiHitAttr extends MoveAttr { hitTimes = 10; } break; + case MultiHitType.BEAT_UP: + // No status means the ally pokemon can contribute to Beat Up + hitTimes = user.scene.getParty().reduce((total, pokemon) => { + return total + (pokemon.id === user.id ? 1 : pokemon?.status && pokemon.status.effect !== StatusEffect.NONE ? 0 : 1) + }, 0); } (args[0] as Utils.IntegerHolder).value = hitTimes; return true; @@ -1866,6 +1872,45 @@ export class MovePowerMultiplierAttr extends VariablePowerAttr { } } +/** + * Helper function to calculate the the base power of an ally's hit when using Beat Up. + * @param user The Pokemon that used Beat Up. + * @param allyIndex The party position of the ally contributing to Beat Up. + * @returns The base power of the Beat Up hit. + */ +const beatUpFunc = (user: Pokemon, allyIndex: number): number => { + const party = user.scene.getParty(); + + for (let i = allyIndex; i < party.length; i++) { + const pokemon = party[i]; + + // The user contributes to Beat Up regardless of status condition. + // Allies can contribute only if they do not have a non-volatile status condition. + if (pokemon.id !== user.id && pokemon?.status && pokemon.status.effect !== StatusEffect.NONE) { + continue; + } + return (pokemon.species.getBaseStat(Stat.ATK) / 10) + 5; + } +} + +export class BeatUpAttr extends VariablePowerAttr { + + /** + * Gets the next party member to contribute to a Beat Up hit, and calculates the base power for it. + * @param user Pokemon that used the move + * @param _target N/A + * @param _move Move with this attribute + * @param args N/A + * @returns true if the function succeeds + */ + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + const power = args[0] as Utils.NumberHolder; + const allyIndex = user.turnData.hitCount - user.turnData.hitsLeft; + power.value = beatUpFunc(user, allyIndex); + return true; + } +} + const doublePowerChanceMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => { let message: string = null; user.scene.executeWithSeedOffset(() => { @@ -4831,8 +4876,9 @@ export function initMoves() { .attr(TrapAttr, BattlerTagType.WHIRLPOOL) .attr(HitsTagAttr, BattlerTagType.UNDERWATER, true), new AttackMove(Moves.BEAT_UP, Type.DARK, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 2) - .makesContact(false) - .unimplemented(), + .attr(MultiHitAttr, MultiHitType.BEAT_UP) + .attr(BeatUpAttr) + .makesContact(false), new AttackMove(Moves.FAKE_OUT, Type.NORMAL, MoveCategory.PHYSICAL, 40, 100, 10, 100, 3, 3) .attr(FlinchAttr) .condition(new FirstMoveCondition()), diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index bd9250bad..902a24ccc 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -16,6 +16,7 @@ import { GameMode } from '../game-mode'; import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from "@material/material-color-utilities"; import { VariantSet } from './variant'; import i18next, { Localizable } from '../plugins/i18n'; +import { Stat } from "./pokemon-stat"; export enum Region { NORMAL, @@ -192,6 +193,15 @@ export abstract class PokemonSpeciesForm { return false; } + /** + * Gets the species' base stat amount for the given stat. + * @param stat The desired stat. + * @returns The species' base stat amount. + */ + getBaseStat(stat: Stat): integer { + return this.baseStats[stat] + } + getBaseExp(): integer { let ret = this.baseExp; switch (this.getFormSpriteKey()) {