Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Ability] [Move] Implement Magic Bounce and Magic Coat #5225

Open
wants to merge 22 commits into
base: beta
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
d603e80
Add unit tests for magic bounce
SirzBenjie Jan 31, 2025
e820c58
Add reflectable tag and apply to moves
SirzBenjie Jan 31, 2025
80048ec
Add BattlerTagType for Magic Coat
SirzBenjie Jan 31, 2025
8badfe7
Add more magic bounce tests
SirzBenjie Jan 31, 2025
9e8d485
Add magic bounce test for sticky web source
SirzBenjie Jan 31, 2025
a3db6d5
Mostly working magic bounce and magic coat
SirzBenjie Feb 1, 2025
a4156d7
Fix improperly written magic bounce tests
SirzBenjie Feb 1, 2025
1c8b2a7
Fix improperly written magic bounce tests
SirzBenjie Feb 1, 2025
fd64db3
Fix improperly written magic bounce tests
SirzBenjie Feb 1, 2025
7843932
Fix missing negation on mayBounce check
SirzBenjie Feb 1, 2025
ee4a216
Move onto the next target after bouncing
SirzBenjie Feb 1, 2025
79fefa9
Fix magic bounce accuracy check test
SirzBenjie Feb 1, 2025
acd27eb
Finish magic bounce impl
SirzBenjie Feb 2, 2025
23b6ba8
Make spikes use leftmost magic bounce target
SirzBenjie Feb 2, 2025
0193d7e
Add magic coat tests
SirzBenjie Feb 2, 2025
5277230
Add MagicCoatTag to battler-tags.ts
SirzBenjie Feb 2, 2025
2dc5b8a
Add final set of tests for Magic Coat / Bounce
SirzBenjie Feb 2, 2025
c3283e3
Fix semi invulnerbale check in hitCheck
SirzBenjie Feb 2, 2025
726179a
Fix magic bounce semi-invulnerable interaction
SirzBenjie Feb 2, 2025
4b61766
Magic bounce should not bounce anything during semi-invulnerable state
SirzBenjie Feb 5, 2025
dcc4ce5
Magic bounce should not bounce anything during semi-invulnerable state
SirzBenjie Feb 5, 2025
8855a0c
Merge branch 'beta' into magic-bounce
SirzBenjie Feb 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions src/battle-scene.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2352,14 +2352,14 @@ export default class BattleScene extends SceneBase {
}

/**
* Adds Phase to the end of phaseQueuePrepend, or at phaseQueuePrependSpliceIndex
* @param phase {@linkcode Phase} the phase to add
* Adds Phase(s) to the end of phaseQueuePrepend, or at phaseQueuePrependSpliceIndex
* @param phases {@linkcode Phase} the phase(s) to add
*/
unshiftPhase(phase: Phase): void {
unshiftPhase(...phases: Phase[]): void {
if (this.phaseQueuePrependSpliceIndex === -1) {
this.phaseQueuePrepend.push(phase);
this.phaseQueuePrepend.push(...phases);
} else {
this.phaseQueuePrepend.splice(this.phaseQueuePrependSpliceIndex, 0, phase);
this.phaseQueuePrepend.splice(this.phaseQueuePrependSpliceIndex, 0, ...phases);
}
}

Expand Down Expand Up @@ -2497,32 +2497,38 @@ export default class BattleScene extends SceneBase {
* @param targetPhase {@linkcode Phase} the type of phase to search for in phaseQueue
* @returns boolean if a targetPhase was found and added
*/
prependToPhase(phase: Phase, targetPhase: Constructor<Phase>): boolean {
prependToPhase(phase: Phase | Phase [], targetPhase: Constructor<Phase>): boolean {
if (!Array.isArray(phase)) {
phase = [ phase ];
}
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof targetPhase);

if (targetIndex !== -1) {
this.phaseQueue.splice(targetIndex, 0, phase);
this.phaseQueue.splice(targetIndex, 0, ...phase);
return true;
} else {
this.unshiftPhase(phase);
this.unshiftPhase(...phase);
return false;
}
}

/**
* Tries to add the input phase to index after target phase in the {@linkcode phaseQueue}, else simply calls {@linkcode unshiftPhase()}
* @param phase {@linkcode Phase} the phase to be added
* Tries to add the input phase(s) to index after target phase in the {@linkcode phaseQueue}, else simply calls {@linkcode unshiftPhase()}
* @param phase {@linkcode Phase} the phase(s) to be added
* @param targetPhase {@linkcode Phase} the type of phase to search for in {@linkcode phaseQueue}
* @returns `true` if a `targetPhase` was found to append to
*/
appendToPhase(phase: Phase, targetPhase: Constructor<Phase>): boolean {
appendToPhase(phase: Phase | Phase[], targetPhase: Constructor<Phase>): boolean {
if (!Array.isArray(phase)) {
phase = [ phase ];
}
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof targetPhase);

if (targetIndex !== -1 && this.phaseQueue.length > targetIndex) {
this.phaseQueue.splice(targetIndex + 1, 0, phase);
this.phaseQueue.splice(targetIndex + 1, 0, ...phase);
return true;
} else {
this.unshiftPhase(phase);
this.unshiftPhase(...phase);
return false;
}
}
Expand Down
12 changes: 11 additions & 1 deletion src/data/ability.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4493,6 +4493,13 @@ export class InfiltratorAbAttr extends AbAttr {
}
}

/**
* Attribute implementing the effects of {@link https://bulbapedia.bulbagarden.net/wiki/Magic_Bounce_(ability) | Magic Bounce}.
* Allows the source to bounce back {@linkcode MoveFlags.REFLECTABLE | Reflectable}
* moves as if the user had used {@linkcode Moves.MAGIC_COAT | Magic Coat}.
*/
export class ReflectStatusMoveAbAttr extends AbAttr { }

export class UncopiableAbilityAbAttr extends AbAttr {
constructor() {
super(false);
Expand Down Expand Up @@ -5809,8 +5816,11 @@ export function initAbilities() {
}, Stat.SPD, 1)
.attr(PostIntimidateStatStageChangeAbAttr, [ Stat.SPD ], 1),
new Ability(Abilities.MAGIC_BOUNCE, 5)
.attr(ReflectStatusMoveAbAttr)
.ignorable()
.unimplemented(),
// Interactions with stomping tantrum, instruct, encore, and probably other moves that
// rely on move history
.edgeCase(),
new Ability(Abilities.SAP_SIPPER, 5)
.attr(TypeImmunityStatStageChangeAbAttr, Type.GRASS, Stat.ATK, 1)
.ignorable(),
Expand Down
20 changes: 20 additions & 0 deletions src/data/battler-tags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2983,6 +2983,24 @@ export class PsychoShiftTag extends BattlerTag {
}
}

/**
* Tag associated with the move Magic Coat.
*/
export class MagicCoatTag extends BattlerTag {
constructor() {
super(BattlerTagType.MAGIC_COAT, BattlerTagLapseType.TURN_END, 1, Moves.MAGIC_COAT);
}

/**
* Queues the "[PokemonName] shrouded itself with Magic Coat" message when the tag is added.
* @param pokemon - The target {@linkcode Pokemon}
*/
override onAdd(pokemon: Pokemon) {
// "{pokemonNameWithAffix} shrouded itself with Magic Coat!"
globalScene.queueMessage(i18next.t("battlerTags:magicCoatOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
}
}

/**
* Retrieves a {@linkcode BattlerTag} based on the provided tag type, turn count, source move, and source ID.
* @param sourceId - The ID of the pokemon adding the tag
Expand Down Expand Up @@ -3172,6 +3190,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source
return new GrudgeTag();
case BattlerTagType.PSYCHO_SHIFT:
return new PsychoShiftTag();
case BattlerTagType.MAGIC_COAT:
return new MagicCoatTag();
case BattlerTagType.NONE:
default:
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
Expand Down
Loading