Skip to content

Commit

Permalink
[P2] Fix various charge move bugs (#4595)
Browse files Browse the repository at this point in the history
* Add charge move classes and phase

* Integrate `MoveChargePhase` in battle phase sequence

* Fix Protean + charge move interaction

* Fix effect chance applying to semi-invulnerability

* Remove `ChargeAttr` and fix ChargeAnim loading

* Restore move history entry for charge phases

* Gravity now cancels Fly, etc. after charge turn

* Dig integration tests

* Fly integration tests

* Dive integration test + fix Dive in Harsh Sun bug

* Solar Beam integration tests + `CHARGING` tag fixes

* Fix dive test

* Electro Shot integration tests

* fix import in MoveChargePhase

* Electro Shot Multi Lens test

* Geomancy integration tests

* Fix duplicate move queue

* Update import

* Docs + Fix Meteor Beam being boosted by Sheer Force

* Fix volt absorb test

* Apply PigeonBar's suggested move-phase changes

Co-authored-by: PigeonBar <[email protected]>

* Make Electro Shot Sheer Force boosted again

* Apply PigeonBar's feedback pt. 2

* Apply suggestions from code review

Co-authored-by: NightKev <[email protected]>

* Fix mistimed/dupe showMoveText and leftover TODO

---------

Co-authored-by: NightKev <[email protected]>
Co-authored-by: PigeonBar <[email protected]>
  • Loading branch information
3 people authored Oct 23, 2024
1 parent 16b7194 commit 03025b2
Show file tree
Hide file tree
Showing 18 changed files with 1,178 additions and 295 deletions.
8 changes: 5 additions & 3 deletions src/data/ability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { Weather, WeatherType } from "./weather";
import { BattlerTag, GroundedTag } from "./battler-tags";
import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
import { Gender } from "./gender";
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, ChargeAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move";
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, SacrificialAttr, SacrificialAttrOnHit, NeutralDamageAgainstFlyingTypeMultiplierAttr, FixedDamageAttr } from "./move";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { BerryModifier, PokemonHeldItemModifier } from "../modifier/modifier";
import { TerrainType } from "./terrain";
Expand Down Expand Up @@ -1139,7 +1139,9 @@ export class MoveEffectChanceMultiplierAbAttr extends AbAttr {
apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
// Disable showAbility during getTargetBenefitScore
this.showAbility = args[4];
if ((args[0] as Utils.NumberHolder).value <= 0 || (args[1] as Move).id === Moves.ORDER_UP) {

const exceptMoves = [ Moves.ORDER_UP, Moves.ELECTRO_SHOT ];
if ((args[0] as Utils.NumberHolder).value <= 0 || exceptMoves.includes((args[1] as Move).id)) {
return false;
}

Expand Down Expand Up @@ -1329,7 +1331,6 @@ export class AddSecondStrikeAbAttr extends PreAttackAbAttr {
*/
const exceptAttrs: Constructor<MoveAttr>[] = [
MultiHitAttr,
ChargeAttr,
SacrificialAttr,
SacrificialAttrOnHit
];
Expand All @@ -1345,6 +1346,7 @@ export class AddSecondStrikeAbAttr extends PreAttackAbAttr {

/** 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;
Expand Down
3 changes: 3 additions & 0 deletions src/data/arena-tag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -970,6 +970,9 @@ export class GravityTag extends ArenaTag {
if (pokemon !== null) {
pokemon.removeTag(BattlerTagType.FLOATING);
pokemon.removeTag(BattlerTagType.TELEKINESIS);
if (pokemon.getTag(BattlerTagType.FLYING)) {
pokemon.addTag(BattlerTagType.INTERRUPTED);
}
}
});
}
Expand Down
31 changes: 18 additions & 13 deletions src/data/battle-anims.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
//import { battleAnimRawData } from "./battle-anim-raw-data";
import BattleScene from "../battle-scene";
import { AttackMove, BeakBlastHeaderAttr, ChargeAttr, DelayedAttackAttr, MoveFlags, SelfStatusMove, allMoves } from "./move";
import { AttackMove, BeakBlastHeaderAttr, DelayedAttackAttr, MoveFlags, SelfStatusMove, allMoves } from "./move";
import Pokemon from "../field/pokemon";
import * as Utils from "../utils";
import { BattlerIndex } from "../battle";
Expand Down Expand Up @@ -476,8 +476,11 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
} else {
const loadedCheckTimer = setInterval(() => {
if (moveAnims.get(move) !== null) {
const chargeAttr = allMoves[move].getAttrs(ChargeAttr)[0] || allMoves[move].getAttrs(DelayedAttackAttr)[0];
if (chargeAttr && chargeAnims.get(chargeAttr.chargeAnim) === null) {
const chargeAnimSource = (allMoves[move].isChargingMove())
? allMoves[move]
: (allMoves[move].getAttrs(DelayedAttackAttr)[0]
?? allMoves[move].getAttrs(BeakBlastHeaderAttr)[0]);
if (chargeAnimSource && chargeAnims.get(chargeAnimSource.chargeAnim) === null) {
return;
}
clearInterval(loadedCheckTimer);
Expand Down Expand Up @@ -507,11 +510,12 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise<void> {
} else {
populateMoveAnim(move, ba);
}
const chargeAttr = allMoves[move].getAttrs(ChargeAttr)[0]
|| allMoves[move].getAttrs(DelayedAttackAttr)[0]
|| allMoves[move].getAttrs(BeakBlastHeaderAttr)[0];
if (chargeAttr) {
initMoveChargeAnim(scene, chargeAttr.chargeAnim).then(() => resolve());
const chargeAnimSource = (allMoves[move].isChargingMove())
? allMoves[move]
: (allMoves[move].getAttrs(DelayedAttackAttr)[0]
?? allMoves[move].getAttrs(BeakBlastHeaderAttr)[0]);
if (chargeAnimSource) {
initMoveChargeAnim(scene, chargeAnimSource.chargeAnim).then(() => resolve());
} else {
resolve();
}
Expand Down Expand Up @@ -638,11 +642,12 @@ export function loadMoveAnimAssets(scene: BattleScene, moveIds: Moves[], startLo
return new Promise(resolve => {
const moveAnimations = moveIds.map(m => moveAnims.get(m) as AnimConfig).flat();
for (const moveId of moveIds) {
const chargeAttr = allMoves[moveId].getAttrs(ChargeAttr)[0]
|| allMoves[moveId].getAttrs(DelayedAttackAttr)[0]
|| allMoves[moveId].getAttrs(BeakBlastHeaderAttr)[0];
if (chargeAttr) {
const moveChargeAnims = chargeAnims.get(chargeAttr.chargeAnim);
const chargeAnimSource = (allMoves[moveId].isChargingMove())
? allMoves[moveId]
: (allMoves[moveId].getAttrs(DelayedAttackAttr)[0]
?? allMoves[moveId].getAttrs(BeakBlastHeaderAttr)[0]);
if (chargeAnimSource) {
const moveChargeAnims = chargeAnims.get(chargeAnimSource.chargeAnim);
moveAnimations.push(moveChargeAnims instanceof AnimConfig ? moveChargeAnims : moveChargeAnims![0]); // TODO: is the bang correct?
if (Array.isArray(moveChargeAnims)) {
moveAnimations.push(moveChargeAnims[1]);
Expand Down
7 changes: 1 addition & 6 deletions src/data/battler-tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import { ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim } from "#app/d
import Move, {
allMoves,
applyMoveAttrs,
ChargeAttr,
ConsecutiveUseDoublePowerAttr,
HealOnAllyAttr,
MoveCategory,
Expand Down Expand Up @@ -949,10 +948,6 @@ export class EncoreTag extends BattlerTag {
return false;
}

if (allMoves[repeatableMove.move].hasAttr(ChargeAttr) && repeatableMove.result === MoveResult.OTHER) {
return false;
}

this.moveId = repeatableMove.move;

return true;
Expand Down Expand Up @@ -2591,7 +2586,7 @@ export class TormentTag extends MoveRestrictionBattlerTag {
// This checks for locking / momentum moves like Rollout and Hydro Cannon + if the user is under the influence of BattlerTagType.FRENZY
// Because Uproar's unique behavior is not implemented, it does not check for Uproar. Torment has been marked as partial in moves.ts
const moveObj = allMoves[lastMove.move];
const isUnaffected = moveObj.hasAttr(ConsecutiveUseDoublePowerAttr) || user.getTag(BattlerTagType.FRENZY) || moveObj.hasAttr(ChargeAttr);
const isUnaffected = moveObj.hasAttr(ConsecutiveUseDoublePowerAttr) || user.getTag(BattlerTagType.FRENZY);
const validLastMoveResult = (lastMove.result === MoveResult.SUCCESS) || (lastMove.result === MoveResult.MISS);
if (lastMove.move === move && validLastMoveResult && lastMove.move !== Moves.STRUGGLE && !isUnaffected) {
return true;
Expand Down
Loading

0 comments on commit 03025b2

Please sign in to comment.