From 08a4a2d7f82072d2aa9c9cae5db039b33e1d0aab Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Thu, 2 May 2024 16:57:49 +0800 Subject: [PATCH 01/14] MINOR: beginning work on Stockpile, Spit Up, and Swallow --- src/data/move.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/data/move.ts b/src/data/move.ts index e1694ede8..490c07789 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4508,6 +4508,7 @@ export function initMoves() { .soundBased() .target(MoveTarget.RANDOM_NEAR_ENEMY) .partial(), + // mareksison/redmaverick616 starts working here new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3) .unimplemented(), new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) @@ -4515,6 +4516,7 @@ export function initMoves() { new SelfStatusMove(Moves.SWALLOW, Type.NORMAL, -1, 10, -1, 0, 3) .triageMove() .unimplemented(), + // mareksison/redmaverick616 ends working here new AttackMove(Moves.HEAT_WAVE, Type.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 10, 0, 3) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE) .attr(StatusEffectAttr, StatusEffect.BURN) From 3aac0e73855ebd26b6da891f4e49e523dffaee96 Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Thu, 2 May 2024 21:30:54 +0800 Subject: [PATCH 02/14] FEAT: partially implemented stockpile --- src/data/enums/battler-tag-type.ts | 3 ++- src/data/move.ts | 10 +++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/data/enums/battler-tag-type.ts b/src/data/enums/battler-tag-type.ts index 4d810b737..2e94e5b77 100644 --- a/src/data/enums/battler-tag-type.ts +++ b/src/data/enums/battler-tag-type.ts @@ -52,5 +52,6 @@ export enum BattlerTagType { SALT_CURED = "SALT_CURED", CURSED = "CURSED", CHARGED = "CHARGED", - GROUNDED = "GROUNDED" + GROUNDED = "GROUNDED", + STOCKPILE = "STOCKPILE" } diff --git a/src/data/move.ts b/src/data/move.ts index 490c07789..1d0515465 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2582,6 +2582,7 @@ export class AddBattlerTagAttr extends MoveEffectAttr { case BattlerTagType.INGRAIN: case BattlerTagType.IGNORE_ACCURACY: case BattlerTagType.AQUA_RING: + case BattlerTagType.STOCKPILE: return 3; case BattlerTagType.PROTECTED: case BattlerTagType.FLYING: @@ -4509,8 +4510,15 @@ export function initMoves() { .target(MoveTarget.RANDOM_NEAR_ENEMY) .partial(), // mareksison/redmaverick616 starts working here + /** + * need to find a way to remove stat changes when stockpile is used + * need to find a way to remove stockpile when the relevant moves are used + */ new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3) - .unimplemented(), + .attr(AddBattlerTagAttr, BattlerTagType.STOCKPILE, true, false, 0, 10) + .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, true) + .target(MoveTarget.USER) + .partial(), new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) .unimplemented(), new SelfStatusMove(Moves.SWALLOW, Type.NORMAL, -1, 10, -1, 0, 3) From 03c88c9516e58fea956c3ae2ebd9511f6c0b3e90 Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Fri, 3 May 2024 16:02:32 +0800 Subject: [PATCH 03/14] FEAT: Stockpile partially implemented --- src/data/move.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index 1d0515465..ee14a0df8 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2767,6 +2767,21 @@ export class FaintCountdownAttr extends AddBattlerTagAttr { } } +export class StockpileAttr extends AddBattlerTagAttr { + constructor() { + super(BattlerTagType.STOCKPILE, true, false, 0, 10) + } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!super.apply(user, target, move, args)) + return false; + + user.scene.queueMessage(getPokemonMessage(target, `\nstockpiled resources.`)); + + return true; + } +} + export class HitsTagAttr extends MoveAttr { public tagType: BattlerTagType; public doubleDamage: boolean; @@ -4517,7 +4532,6 @@ export function initMoves() { new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3) .attr(AddBattlerTagAttr, BattlerTagType.STOCKPILE, true, false, 0, 10) .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, true) - .target(MoveTarget.USER) .partial(), new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) .unimplemented(), From 531ec358e0e0aaf62ff6998635b0148ac7d89fa0 Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Mon, 6 May 2024 13:35:05 +0800 Subject: [PATCH 04/14] UPDATE: Stockpile has been fully implemented. Still marked as partial for testing --- src/data/enums/battler-tag-type.ts | 4 +- src/data/move.ts | 126 ++++++++++++++++++++++++++++- src/field/pokemon.ts | 1 + 3 files changed, 126 insertions(+), 5 deletions(-) diff --git a/src/data/enums/battler-tag-type.ts b/src/data/enums/battler-tag-type.ts index 2e94e5b77..b20febe57 100644 --- a/src/data/enums/battler-tag-type.ts +++ b/src/data/enums/battler-tag-type.ts @@ -53,5 +53,7 @@ export enum BattlerTagType { CURSED = "CURSED", CHARGED = "CHARGED", GROUNDED = "GROUNDED", - STOCKPILE = "STOCKPILE" + STOCKPILE_ONE = "STOCKPILE_ONE", + STOCKPILE_TWO = "STOCKPILE_TWO", + STOCKPILE_THREE = "STOCKPILE_THREE" } diff --git a/src/data/move.ts b/src/data/move.ts index ee14a0df8..977e7540f 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -407,6 +407,14 @@ export class SelfStatusMove extends Move { } } +export class StockpileMove extends SelfStatusMove { + constructor(id: Moves, type: Type, accuracy: integer, pp: integer, chance: integer, priority: integer, generation: integer) { + super(id, type, accuracy, pp, chance, priority, generation); + } + + // add a function for shifting conditions +} + export abstract class MoveAttr { public selfTarget: boolean; @@ -2582,7 +2590,9 @@ export class AddBattlerTagAttr extends MoveEffectAttr { case BattlerTagType.INGRAIN: case BattlerTagType.IGNORE_ACCURACY: case BattlerTagType.AQUA_RING: - case BattlerTagType.STOCKPILE: + case BattlerTagType.STOCKPILE_ONE: + case BattlerTagType.STOCKPILE_TWO: + case BattlerTagType.STOCKPILE_THREE: return 3; case BattlerTagType.PROTECTED: case BattlerTagType.FLYING: @@ -2767,9 +2777,117 @@ export class FaintCountdownAttr extends AddBattlerTagAttr { } } -export class StockpileAttr extends AddBattlerTagAttr { +export class StockpileOneAttr extends AddBattlerTagAttr { constructor() { - super(BattlerTagType.STOCKPILE, true, false, 0, 10) + super(BattlerTagType.STOCKPILE_ONE, true, true, 20, 20); + } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!super.apply(user, target, move, args)) + return false; + + user.scene.queueMessage(getPokemonMessage(target, `\nstockpiled 1.`)); + + return true; + } +} + +export class StockpileTwoAttr extends AddBattlerTagAttr { + constructor() { + super(BattlerTagType.STOCKPILE_TWO, true, true, 20, 20); + } + + getCondition(): MoveConditionFunc { + return (user, target, move) => (!user.getTag(this.tagType) && !!user.getTag(BattlerTagType.STOCKPILE_ONE)); + } + + canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) { + if (!super.canApply(user, target, move, args)) + return false; + + const canApplyStockpileTwo = this.getCondition(); + + return canApplyStockpileTwo(user, target, move); + } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!super.apply(user, target, move, args)) + return false; + + if (!this.canApply(user, target, move, args)) + return false; + + user.scene.queueMessage(getPokemonMessage(target, `\nstockpiled 2.`)); + + return true; + } +} + +export class StockpileThreeAttr extends AddBattlerTagAttr { + constructor() { + super(BattlerTagType.STOCKPILE_THREE, true, true, 20, 20); + } + + getCondition(): MoveConditionFunc { + return (user, target, move) => (!user.getTag(this.tagType) && !!user.getTag(BattlerTagType.STOCKPILE_TWO)); + } + + canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) { + if (!super.canApply(user, target, move, args)) + return false; + + const canApplyStockpileThree = this.getCondition(); + + return canApplyStockpileThree(user, target, move); + } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!super.apply(user, target, move, args)) + return false; + + if (!this.canApply(user, target, move, args)) + return false; + + user.scene.queueMessage(getPokemonMessage(target, `\nstockpiled 3.`)); + + return true; + } +} + +export class StockpileAttr extends AddBattlerTagAttr { + + constructor() { + super(BattlerTagType.STOCKPILE_THREE, true, true, 0, 10); + } + + getStockpile(stacks: integer = 1): MoveConditionFunc { + let stockpileType = BattlerTagType.STOCKPILE_ONE; + switch (stacks) { + case 2: + stockpileType = BattlerTagType.STOCKPILE_TWO; + break; + case 3: + stockpileType = BattlerTagType.STOCKPILE_THREE; + break; + default: + } + return (user, target, move) => !user.getTag(stockpileType); + }; + + setStockpile(user: Pokemon, target: Pokemon, move: Move){ + const getStockpileOne = this.getStockpile(1); + const getStockpileTwo = this.getStockpile(2); + if (getStockpileOne(user, target, move) && !getStockpileTwo(user, target, move)) { + // if there's only 1 stockpile, give 2nd stockpile + this.tagType = BattlerTagType.STOCKPILE_TWO; + } else if (!getStockpileOne(user, target, move)) { + // if there's no stockpile, give 1st stockpile + this.tagType = BattlerTagType.STOCKPILE_ONE; + } else { + // tagType stays as STOCKPILE_THREE + // if there's 2 stockpile, then we give 3rd stockpile + // if there's 3 stockpile, then move fails + } } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -4530,7 +4648,7 @@ export function initMoves() { * need to find a way to remove stockpile when the relevant moves are used */ new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3) - .attr(AddBattlerTagAttr, BattlerTagType.STOCKPILE, true, false, 0, 10) + .attr(StockpileAttr) .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, true) .partial(), new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index a966a2430..fa7334f88 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -81,6 +81,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public luck: integer; public pauseEvolutions: boolean; public pokerus: boolean; + public stockpile: integer; public fusionSpecies: PokemonSpecies; public fusionFormIndex: integer; From 3fc2d433f52e7eb4bcef94a26f0c19026bf638f2 Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Mon, 6 May 2024 16:12:26 +0800 Subject: [PATCH 05/14] FEAT: Spit Up partially implemented along with StockpileDamageAttr --- src/data/move.ts | 104 ++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 55 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 977e7540f..95ec3de51 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -407,14 +407,6 @@ export class SelfStatusMove extends Move { } } -export class StockpileMove extends SelfStatusMove { - constructor(id: Moves, type: Type, accuracy: integer, pp: integer, chance: integer, priority: integer, generation: integer) { - super(id, type, accuracy, pp, chance, priority, generation); - } - - // add a function for shifting conditions -} - export abstract class MoveAttr { public selfTarget: boolean; @@ -640,6 +632,52 @@ export class RandomLevelDamageAttr extends FixedDamageAttr { return Math.max(Math.floor(user.level * (user.randSeedIntRange(50, 150) * 0.01)), 1); } } +export class StockpileDamageAttr extends FixedDamageAttr { + constructor() { + super(0); + } + + getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer { + let ret = super.getTargetBenefitScore(user, target, move); + + let attackScore = 0; + + const effectiveness = target.getAttackTypeEffectiveness(Type.NORMAL); + attackScore = Math.pow(effectiveness - 1, 2) * effectiveness < 1 ? -2 : 2; + if (attackScore) { + const spAtk = new Utils.IntegerHolder(user.getBattleStat(Stat.SPATK, target)); + applyMoveAttrs(VariableAtkAttr, user, target, move, spAtk); + if (spAtk.value > user.getBattleStat(Stat.ATK, target)) { + const statRatio = user.getBattleStat(Stat.ATK, target) / spAtk.value; + if (statRatio <= 0.75) + attackScore *= 2; + else if (statRatio <= 0.875) + attackScore *= 1.5; + } + + const power = new Utils.NumberHolder(this.getPower(user, target, move)); + applyMoveAttrs(VariablePowerAttr, user, target, move, power); + + attackScore += Math.floor(power.value / 5); + } + + ret -= attackScore; + + return ret; + } + + getPower(user: Pokemon, target: Pokemon, move: Move): number { + if (!!user.getTag(BattlerTagType.STOCKPILE_THREE)){ + return 300; + } else if (!!user.getTag(BattlerTagType.STOCKPILE_TWO)){ + return 200; + } else if (!!user.getTag(BattlerTagType.STOCKPILE_ONE)){ + return 100; + } else { + return 0; + } + } +} export class ModifiedDamageAttr extends MoveAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -2854,52 +2892,6 @@ export class StockpileThreeAttr extends AddBattlerTagAttr { } } -export class StockpileAttr extends AddBattlerTagAttr { - - constructor() { - super(BattlerTagType.STOCKPILE_THREE, true, true, 0, 10); - } - - getStockpile(stacks: integer = 1): MoveConditionFunc { - let stockpileType = BattlerTagType.STOCKPILE_ONE; - switch (stacks) { - case 2: - stockpileType = BattlerTagType.STOCKPILE_TWO; - break; - case 3: - stockpileType = BattlerTagType.STOCKPILE_THREE; - break; - default: - } - return (user, target, move) => !user.getTag(stockpileType); - }; - - setStockpile(user: Pokemon, target: Pokemon, move: Move){ - const getStockpileOne = this.getStockpile(1); - const getStockpileTwo = this.getStockpile(2); - if (getStockpileOne(user, target, move) && !getStockpileTwo(user, target, move)) { - // if there's only 1 stockpile, give 2nd stockpile - this.tagType = BattlerTagType.STOCKPILE_TWO; - } else if (!getStockpileOne(user, target, move)) { - // if there's no stockpile, give 1st stockpile - this.tagType = BattlerTagType.STOCKPILE_ONE; - } else { - // tagType stays as STOCKPILE_THREE - // if there's 2 stockpile, then we give 3rd stockpile - // if there's 3 stockpile, then move fails - } - } - - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - if (!super.apply(user, target, move, args)) - return false; - - user.scene.queueMessage(getPokemonMessage(target, `\nstockpiled resources.`)); - - return true; - } -} - export class HitsTagAttr extends MoveAttr { public tagType: BattlerTagType; public doubleDamage: boolean; @@ -4648,7 +4640,9 @@ export function initMoves() { * need to find a way to remove stockpile when the relevant moves are used */ new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3) - .attr(StockpileAttr) + .attr(StockpileOneAttr) + .attr(StockpileTwoAttr) + .attr(StockpileThreeAttr) .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, true) .partial(), new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) From c3e9229eb8e7966d0f5dd3821fcab1119852a83a Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Mon, 6 May 2024 16:13:37 +0800 Subject: [PATCH 06/14] HOTFIX: StockpileDamageAttr adjusted --- src/data/move.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 95ec3de51..5578436c1 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -637,7 +637,7 @@ export class StockpileDamageAttr extends FixedDamageAttr { super(0); } - getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer { + getDamage(user: Pokemon, target: Pokemon, move: Move): integer { let ret = super.getTargetBenefitScore(user, target, move); let attackScore = 0; @@ -661,9 +661,7 @@ export class StockpileDamageAttr extends FixedDamageAttr { attackScore += Math.floor(power.value / 5); } - ret -= attackScore; - - return ret; + return attackScore; } getPower(user: Pokemon, target: Pokemon, move: Move): number { @@ -4646,7 +4644,9 @@ export function initMoves() { .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, true) .partial(), new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) - .unimplemented(), + .attr(StockpileDamageAttr) + .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true) + .partial(), new SelfStatusMove(Moves.SWALLOW, Type.NORMAL, -1, 10, -1, 0, 3) .triageMove() .unimplemented(), From cfe9e9885ca7f1eccf726c8e64f687718b72dbe2 Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Mon, 6 May 2024 19:02:29 +0800 Subject: [PATCH 07/14] HOTFIX: changed StockpileDamageAttr to StockpilePowerAttr --- src/data/move.ts | 98 +++++++++++++++++++++++++----------------------- 1 file changed, 51 insertions(+), 47 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 1957aa931..7d2425cd5 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -647,50 +647,6 @@ export class RandomLevelDamageAttr extends FixedDamageAttr { return Math.max(Math.floor(user.level * (user.randSeedIntRange(50, 150) * 0.01)), 1); } } -export class StockpileDamageAttr extends FixedDamageAttr { - constructor() { - super(0); - } - - getDamage(user: Pokemon, target: Pokemon, move: Move): integer { - let ret = super.getTargetBenefitScore(user, target, move); - - let attackScore = 0; - - const effectiveness = target.getAttackTypeEffectiveness(Type.NORMAL); - attackScore = Math.pow(effectiveness - 1, 2) * effectiveness < 1 ? -2 : 2; - if (attackScore) { - const spAtk = new Utils.IntegerHolder(user.getBattleStat(Stat.SPATK, target)); - applyMoveAttrs(VariableAtkAttr, user, target, move, spAtk); - if (spAtk.value > user.getBattleStat(Stat.ATK, target)) { - const statRatio = user.getBattleStat(Stat.ATK, target) / spAtk.value; - if (statRatio <= 0.75) - attackScore *= 2; - else if (statRatio <= 0.875) - attackScore *= 1.5; - } - - const power = new Utils.NumberHolder(this.getPower(user, target, move)); - applyMoveAttrs(VariablePowerAttr, user, target, move, power); - - attackScore += Math.floor(power.value / 5); - } - - return attackScore; - } - - getPower(user: Pokemon, target: Pokemon, move: Move): number { - if (!!user.getTag(BattlerTagType.STOCKPILE_THREE)){ - return 300; - } else if (!!user.getTag(BattlerTagType.STOCKPILE_TWO)){ - return 200; - } else if (!!user.getTag(BattlerTagType.STOCKPILE_ONE)){ - return 100; - } else { - return 0; - } - } -} export class ModifiedDamageAttr extends MoveAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { @@ -1620,6 +1576,31 @@ export class GrowthStatChangeAttr extends StatChangeAttr { } } +export class StockpileStatChangeAttr extends StatChangeAttr { + constructor(move: string = "Stockpile") { + let l = 1; + + if (move === "Spit-Up" || move === "Swallow"){ + l = -1; + } + + super([ BattleStat.ATK, BattleStat.SPATK ], l, true); + } + + // apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise { + // if (!super.apply(user, target, move, args) || (this.condition && !this.condition(user, target, move))) + // return false; + + // if (move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance) { + // const levels = this.getLevels(user); + // user.scene.unshiftPhase(new StatChangePhase(user.scene, (this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, levels, this.showMessage)); + // return true; + // } + + // return false; + // } +} + export class HalfHpStatMaxAttr extends StatChangeAttr { constructor(stat: BattleStat) { super(stat, 12, true, null, false); @@ -2151,6 +2132,28 @@ export class WaterShurikenPowerAttr extends VariablePowerAttr { } } +export class StockpilePowerAttr extends VariablePowerAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + const power = args[0] as Utils.NumberHolder; + + power.value = this.getPower(user, target, move); + + return true; + } + + getPower(user: Pokemon, target: Pokemon, move: Move): number { + if (!!user.getTag(BattlerTagType.STOCKPILE_THREE)){ + return 300; + } else if (!!user.getTag(BattlerTagType.STOCKPILE_TWO)){ + return 200; + } else if (!!user.getTag(BattlerTagType.STOCKPILE_ONE)){ + return 100; + } else { + return 0; + } + } +} + export class VariableAtkAttr extends MoveAttr { constructor() { super(); @@ -4779,14 +4782,15 @@ export function initMoves() { .attr(StockpileOneAttr) .attr(StockpileTwoAttr) .attr(StockpileThreeAttr) - .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, true) + .attr(StockpileStatChangeAttr, 'Stockpile') .partial(), new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) - .attr(StockpileDamageAttr) - .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true) + .attr(StockpilePowerAttr) + .attr(StockpileStatChangeAttr, 'Spit-Up') .partial(), new SelfStatusMove(Moves.SWALLOW, Type.NORMAL, -1, 10, -1, 0, 3) .triageMove() + .attr(StockpileStatChangeAttr, 'Swallow') .unimplemented(), // mareksison/redmaverick616 ends working here new AttackMove(Moves.HEAT_WAVE, Type.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 10, 0, 3) From bc2d232edb793e17b16211576f041bcece8fb94d Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Mon, 6 May 2024 23:35:55 +0800 Subject: [PATCH 08/14] FEAT: Swallow implemented. Marked partial for testing --- src/data/move.ts | 76 ++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 61 insertions(+), 15 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 7d2425cd5..4ab5d83b2 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -809,12 +809,43 @@ export class HealAttr extends MoveEffectAttr { Math.max(Math.floor(target.getMaxHp() * healRatio), 1), getPokemonMessage(target, ' regained\nhealth!'), true, !this.showAnim)); } + getHealRatio(h: number = -1){ + if (h > 0) + this.healRatio = h; + + return this.healRatio; + } + getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer { let score = ((1 - (this.selfTarget ? user : target).getHpRatio()) * 20) - this.healRatio * 10; return Math.round(score / (1 - this.healRatio / 2)); } } +export class StockpileHealAttr extends HealAttr { + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + const s = this.getStockpiles(user); + + this.getHealRatio(s > 2 ? 1 : (s * 0.25)); + + super.apply(user, target, move, args); + return true; + } + + getStockpiles(user: Pokemon): integer { + let s = 0; + const stock = [BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE]; + + for (let x = 0 ; x < stock.length ; x++){ + if (user.getTag(stock[x])){ + s++; + } + } + + return s; + } +} + export class SacrificialFullRestoreAttr extends SacrificialAttr { constructor() { super(); @@ -1587,18 +1618,26 @@ export class StockpileStatChangeAttr extends StatChangeAttr { super([ BattleStat.ATK, BattleStat.SPATK ], l, true); } - // apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise { - // if (!super.apply(user, target, move, args) || (this.condition && !this.condition(user, target, move))) - // return false; + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise { + if (!super.apply(user, target, move, args)) + return false; + + this.levels = this.levels < 0 ? (this.getStockpiles(user) * -1) : 1; + return true; + } - // if (move.chance < 0 || move.chance === 100 || user.randSeedInt(100) < move.chance) { - // const levels = this.getLevels(user); - // user.scene.unshiftPhase(new StatChangePhase(user.scene, (this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, levels, this.showMessage)); - // return true; - // } + getStockpiles(user: Pokemon): integer { + let s = 0; + const stock = [BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE]; - // return false; - // } + for (let x = 0 ; x < stock.length ; x++){ + if (user.getTag(stock[x])){ + s++; + } + } + + return s; + } } export class HalfHpStatMaxAttr extends StatChangeAttr { @@ -4774,10 +4813,6 @@ export function initMoves() { .target(MoveTarget.RANDOM_NEAR_ENEMY) .partial(), // mareksison/redmaverick616 starts working here - /** - * need to find a way to remove stat changes when stockpile is used - * need to find a way to remove stockpile when the relevant moves are used - */ new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3) .attr(StockpileOneAttr) .attr(StockpileTwoAttr) @@ -4787,11 +4822,22 @@ export function initMoves() { new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) .attr(StockpilePowerAttr) .attr(StockpileStatChangeAttr, 'Spit-Up') + .attr(RemoveBattlerTagAttr, [ + BattlerTagType.STOCKPILE_ONE, + BattlerTagType.STOCKPILE_TWO, + BattlerTagType.STOCKPILE_THREE, + ], true) .partial(), new SelfStatusMove(Moves.SWALLOW, Type.NORMAL, -1, 10, -1, 0, 3) .triageMove() + .attr(StockpileHealAttr, 1) .attr(StockpileStatChangeAttr, 'Swallow') - .unimplemented(), + .attr(RemoveBattlerTagAttr, [ + BattlerTagType.STOCKPILE_ONE, + BattlerTagType.STOCKPILE_TWO, + BattlerTagType.STOCKPILE_THREE, + ], true) + .partial(), // mareksison/redmaverick616 ends working here new AttackMove(Moves.HEAT_WAVE, Type.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 10, 0, 3) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE) From 37507322ec13cf5cba7dd108cc0e84bc8d7d975e Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Mon, 6 May 2024 23:37:31 +0800 Subject: [PATCH 09/14] HOTFIX: removed stockpile from the pokemon class --- src/field/pokemon.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 519981100..36dc4265e 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -81,7 +81,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public luck: integer; public pauseEvolutions: boolean; public pokerus: boolean; - public stockpile: integer; public fusionSpecies: PokemonSpecies; public fusionFormIndex: integer; From 4653c2d33e36d77b90d9d0047b056bfddf43ba8b Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Mon, 6 May 2024 23:38:13 +0800 Subject: [PATCH 10/14] HOTFIX: removed marking comments --- src/data/move.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 4ab5d83b2..a841faf68 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4812,7 +4812,6 @@ export function initMoves() { .soundBased() .target(MoveTarget.RANDOM_NEAR_ENEMY) .partial(), - // mareksison/redmaverick616 starts working here new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3) .attr(StockpileOneAttr) .attr(StockpileTwoAttr) @@ -4838,7 +4837,6 @@ export function initMoves() { BattlerTagType.STOCKPILE_THREE, ], true) .partial(), - // mareksison/redmaverick616 ends working here new AttackMove(Moves.HEAT_WAVE, Type.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 10, 0, 3) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE) .attr(StatusEffectAttr, StatusEffect.BURN) From 8cf8d2d68cd3bf135e5a51523afa19ed83e2911a Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Tue, 7 May 2024 00:17:03 +0800 Subject: [PATCH 11/14] UPDATE: condensed StockpileAttr --- src/data/move.ts | 104 +++++++++++++++-------------------------------- 1 file changed, 32 insertions(+), 72 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index fdc7f4dd0..34611a1e9 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -822,7 +822,7 @@ export class HealAttr extends MoveEffectAttr { } } -export class StockpileHealAttr extends HealAttr { +export class SwallowHealAttr extends HealAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const s = this.getStockpiles(user); @@ -2171,7 +2171,7 @@ export class WaterShurikenPowerAttr extends VariablePowerAttr { } } -export class StockpilePowerAttr extends VariablePowerAttr { +export class SpitUpPowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const power = args[0] as Utils.NumberHolder; @@ -2988,81 +2988,43 @@ export class FaintCountdownAttr extends AddBattlerTagAttr { } } -export class StockpileOneAttr extends AddBattlerTagAttr { - constructor() { - super(BattlerTagType.STOCKPILE_ONE, true, true, 20, 20); - } - - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - if (!super.apply(user, target, move, args)) - return false; - - user.scene.queueMessage(getPokemonMessage(target, `\nstockpiled 1.`)); - - return true; - } -} - -export class StockpileTwoAttr extends AddBattlerTagAttr { - constructor() { - super(BattlerTagType.STOCKPILE_TWO, true, true, 20, 20); - } - - getCondition(): MoveConditionFunc { - return (user, target, move) => (!user.getTag(this.tagType) && !!user.getTag(BattlerTagType.STOCKPILE_ONE)); - } - - canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) { - if (!super.canApply(user, target, move, args)) - return false; - - const canApplyStockpileTwo = this.getCondition(); - - return canApplyStockpileTwo(user, target, move); - } - - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - if (!super.apply(user, target, move, args)) - return false; - - if (!this.canApply(user, target, move, args)) - return false; - - user.scene.queueMessage(getPokemonMessage(target, `\nstockpiled 2.`)); - - return true; - } -} - -export class StockpileThreeAttr extends AddBattlerTagAttr { +export class StockpileAttr extends AddBattlerTagAttr { constructor() { super(BattlerTagType.STOCKPILE_THREE, true, true, 20, 20); } - getCondition(): MoveConditionFunc { - return (user, target, move) => (!user.getTag(this.tagType) && !!user.getTag(BattlerTagType.STOCKPILE_TWO)); - } - - canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) { - if (!super.canApply(user, target, move, args)) - return false; - - const canApplyStockpileThree = this.getCondition(); - - return canApplyStockpileThree(user, target, move); - } - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + const stock = this.getStockpiles(user); + let stockType = BattlerTagType.STOCKPILE_THREE; + + switch (stock){ + case 0: + stockType = BattlerTagType.STOCKPILE_ONE; + break; + case 1: + stockType = BattlerTagType.STOCKPILE_TWO; + } + if (!super.apply(user, target, move, args)) return false; - if (!this.canApply(user, target, move, args)) - return false; - - user.scene.queueMessage(getPokemonMessage(target, `\nstockpiled 3.`)); + user.scene.queueMessage(getPokemonMessage(target, `\nstockpiled ${stock+1}.`)); return true; } + + getStockpiles(user: Pokemon): integer { + let s = 0; + const stock = [BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE]; + + for (let x = 0 ; x < stock.length ; x++){ + if (user.getTag(stock[x])){ + s++; + } + } + + return s; + } } export class HitsTagAttr extends MoveAttr { @@ -4834,13 +4796,11 @@ export function initMoves() { .target(MoveTarget.RANDOM_NEAR_ENEMY) .partial(), new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3) - .attr(StockpileOneAttr) - .attr(StockpileTwoAttr) - .attr(StockpileThreeAttr) + .attr(StockpileAttr) .attr(StockpileStatChangeAttr, 'Stockpile') .partial(), new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) - .attr(StockpilePowerAttr) + .attr(SpitUpPowerAttr) .attr(StockpileStatChangeAttr, 'Spit-Up') .attr(RemoveBattlerTagAttr, [ BattlerTagType.STOCKPILE_ONE, @@ -4849,14 +4809,14 @@ export function initMoves() { ], true) .partial(), new SelfStatusMove(Moves.SWALLOW, Type.NORMAL, -1, 10, -1, 0, 3) - .triageMove() - .attr(StockpileHealAttr, 1) + .attr(SwallowHealAttr, 1) .attr(StockpileStatChangeAttr, 'Swallow') .attr(RemoveBattlerTagAttr, [ BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE, ], true) + .triageMove() .partial(), new AttackMove(Moves.HEAT_WAVE, Type.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 10, 0, 3) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE) From 81628e634fcf222ef2875b570dbee4e0e0308398 Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Wed, 8 May 2024 23:00:58 +0800 Subject: [PATCH 12/14] HOTFIX: squashed bugs with stockpiles not properly being detected --- src/data/move.ts | 96 +++++++++++++++++++++++--------------------- src/field/pokemon.ts | 4 +- src/overrides.ts | 1 + 3 files changed, 54 insertions(+), 47 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index b98e2c899..f35903ba7 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1608,35 +1608,32 @@ export class GrowthStatChangeAttr extends StatChangeAttr { } export class StockpileStatChangeAttr extends StatChangeAttr { - constructor(move: string = "Stockpile") { + tagTypes = [BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE]; + + constructor(move: Moves = Moves.STOCKPILE) { let l = 1; - if (move === "Spit-Up" || move === "Swallow"){ + if (move === Moves.SPIT_UP || move === Moves.SWALLOW){ l = -1; } - super([ BattleStat.ATK, BattleStat.SPATK ], l, true); + super([ BattleStat.DEF, BattleStat.SPDEF ], l, true); } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise { - if (!super.apply(user, target, move, args)) - return false; - - this.levels = this.levels < 0 ? (this.getStockpiles(user) * -1) : 1; - return true; - } + const stock = getStockpiles(user); - getStockpiles(user: Pokemon): integer { - let s = 0; - const stock = [BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE]; + if (this.levels < 0) { + this.levels = stock * -1; - for (let x = 0 ; x < stock.length ; x++){ - if (user.getTag(stock[x])){ - s++; - } + for (let tagType of this.tagTypes) + (this.selfTarget ? user : target).removeTag(tagType); } - return s; + if (!super.apply(user, target, move, args)) + return false; + + return true; } } @@ -2990,12 +2987,13 @@ export class FaintCountdownAttr extends AddBattlerTagAttr { export class StockpileAttr extends AddBattlerTagAttr { constructor() { - super(BattlerTagType.STOCKPILE_THREE, true, true, 20, 20); + super(BattlerTagType.STOCKPILE_THREE, true, false, 20, 20); } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const stock = this.getStockpiles(user); + const stock = getStockpiles(user); let stockType = BattlerTagType.STOCKPILE_THREE; + let willFail = false; switch (stock){ case 0: @@ -3003,28 +3001,24 @@ export class StockpileAttr extends AddBattlerTagAttr { break; case 1: stockType = BattlerTagType.STOCKPILE_TWO; + break; + case 3: + willFail = true; + break + default: + // keep it at STOCKPILE_THREE + break; } - if (!super.apply(user, target, move, args)) + this.tagType = stockType; + + if (!super.apply(user, target, move, args) || willFail) return false; user.scene.queueMessage(getPokemonMessage(target, `\nstockpiled ${stock+1}.`)); return true; } - - getStockpiles(user: Pokemon): integer { - let s = 0; - const stock = [BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE]; - - for (let x = 0 ; x < stock.length ; x++){ - if (user.getTag(stock[x])){ - s++; - } - } - - return s; - } } export class HitsTagAttr extends MoveAttr { @@ -3961,12 +3955,29 @@ export class VariableTargetAttr extends MoveAttr { } } +function getStockpiles(user: Pokemon) : integer { + let s = 0; + const stock = [BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE]; + + for (let x = 0 ; x < stock.length ; x++){ + if (user.getTag(stock[x])){ + s++; + } + } + + return s; +} + const failOnGravityCondition: MoveConditionFunc = (user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY); const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.isBossImmune(); const failOnMaxCondition: MoveConditionFunc = (user, target, move) => !target.isMax(); +const failOnMaxStockCondition: MoveConditionFunc = (user, target, move) => getStockpiles(user) != 3; + +const failOnNoStockCondition: MoveConditionFunc = (user, target, move) => getStockpiles(user) != 0; + const failIfDampCondition: MoveConditionFunc = (user, target, move) => { const cancelled = new Utils.BooleanHolder(false); user.scene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled)); @@ -4797,25 +4808,18 @@ export function initMoves() { .partial(), new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3) .attr(StockpileAttr) - .attr(StockpileStatChangeAttr, 'Stockpile') + .attr(StockpileStatChangeAttr, Moves.STOCKPILE) + .condition(failOnMaxStockCondition) .partial(), new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) .attr(SpitUpPowerAttr) - .attr(StockpileStatChangeAttr, 'Spit-Up') - .attr(RemoveBattlerTagAttr, [ - BattlerTagType.STOCKPILE_ONE, - BattlerTagType.STOCKPILE_TWO, - BattlerTagType.STOCKPILE_THREE, - ], true) + .attr(StockpileStatChangeAttr, Moves.SPIT_UP) + .condition(failOnNoStockCondition) .partial(), new SelfStatusMove(Moves.SWALLOW, Type.NORMAL, -1, 10, -1, 0, 3) .attr(SwallowHealAttr, 1) - .attr(StockpileStatChangeAttr, 'Swallow') - .attr(RemoveBattlerTagAttr, [ - BattlerTagType.STOCKPILE_ONE, - BattlerTagType.STOCKPILE_TWO, - BattlerTagType.STOCKPILE_THREE, - ], true) + .attr(StockpileStatChangeAttr, Moves.SWALLOW) + .condition(failOnNoStockCondition) .triageMove() .partial(), new AttackMove(Moves.HEAT_WAVE, Type.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 10, 0, 3) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 2242b1ee6..ca122c2b2 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -43,7 +43,7 @@ import { Nature, getNatureStatMultiplier } from '../data/nature'; import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangeStatusEffectTrigger } from '../data/pokemon-forms'; import { TerrainType } from '../data/terrain'; import { TrainerSlot } from '../data/trainer-config'; -import { ABILITY_OVERRIDE, MOVE_OVERRIDE, MOVE_OVERRIDE_2, OPP_ABILITY_OVERRIDE, OPP_MOVE_OVERRIDE, OPP_MOVE_OVERRIDE_2, OPP_SHINY_OVERRIDE, OPP_VARIANT_OVERRIDE } from '../overrides'; +import { ABILITY_OVERRIDE, MOVE_OVERRIDE, MOVE_OVERRIDE_2, MOVE_OVERRIDE_3, OPP_ABILITY_OVERRIDE, OPP_MOVE_OVERRIDE, OPP_MOVE_OVERRIDE_2, OPP_SHINY_OVERRIDE, OPP_VARIANT_OVERRIDE } from '../overrides'; import { BerryType } from '../data/berry'; import i18next from '../plugins/i18n'; @@ -733,6 +733,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.moveset[1] = new PokemonMove(MOVE_OVERRIDE_2, Math.min(this.moveset[1].ppUsed, allMoves[MOVE_OVERRIDE_2].pp)); else if (OPP_MOVE_OVERRIDE_2 && !this.isPlayer()) this.moveset[1] = new PokemonMove(OPP_MOVE_OVERRIDE_2, Math.min(this.moveset[1].ppUsed, allMoves[OPP_MOVE_OVERRIDE_2].pp)); + if (MOVE_OVERRIDE_3 && this.isPlayer()) + this.moveset[2] = new PokemonMove(MOVE_OVERRIDE_3, Math.min(this.moveset[2].ppUsed, allMoves[MOVE_OVERRIDE_3].pp)); return ret; diff --git a/src/overrides.ts b/src/overrides.ts index 4b9bcaa0b..ddbb8176e 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -16,6 +16,7 @@ export const WEATHER_OVERRIDE = WeatherType.NONE; export const ABILITY_OVERRIDE = Abilities.NONE; export const MOVE_OVERRIDE = Moves.NONE; export const MOVE_OVERRIDE_2 = Moves.NONE; +export const MOVE_OVERRIDE_3 = Moves.NONE; export const OPP_SPECIES_OVERRIDE = 0; export const OPP_ABILITY_OVERRIDE = Abilities.NONE; export const OPP_MOVE_OVERRIDE = Moves.NONE; From a317d2fb7e25f8a3cf728efbf49f25f798bad51d Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Fri, 10 May 2024 12:17:59 +0800 Subject: [PATCH 13/14] UPDATE: cleaned StockpileStatChangeAttr --- src/data/move.ts | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index 74c5d46de..5fab974b4 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1648,24 +1648,23 @@ export class GrowthStatChangeAttr extends StatChangeAttr { } export class StockpileStatChangeAttr extends StatChangeAttr { - tagTypes = [BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE]; + private tagTypes = [BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE]; + private gainStats:boolean; - constructor(move: Moves = Moves.STOCKPILE) { - let l = 1; + constructor(gainStats:boolean = true) { + super([ BattleStat.DEF, BattleStat.SPDEF ], 1, true); - if (move === Moves.SPIT_UP || move === Moves.SWALLOW){ - l = -1; - } - - super([ BattleStat.DEF, BattleStat.SPDEF ], l, true); + this.gainStats = gainStats; } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise { const stock = getStockpiles(user); - - if (this.levels < 0) { + + if (!this.gainStats) { + // levels become equal to the negative of stock this.levels = stock * -1; + // remove the stats equal to the number of stock for (let tagType of this.tagTypes) (this.selfTarget ? user : target).removeTag(tagType); } @@ -3052,7 +3051,7 @@ export class StockpileAttr extends AddBattlerTagAttr { this.tagType = stockType; - if (!super.apply(user, target, move, args) || willFail) + if (willFail || !super.apply(user, target, move, args)) return false; user.scene.queueMessage(getPokemonMessage(target, `\nstockpiled ${stock+1}.`)); @@ -4889,17 +4888,17 @@ export function initMoves() { .partial(), new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3) .attr(StockpileAttr) - .attr(StockpileStatChangeAttr, Moves.STOCKPILE) + .attr(StockpileStatChangeAttr) .condition(failOnMaxStockCondition) .partial(), new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) .attr(SpitUpPowerAttr) - .attr(StockpileStatChangeAttr, Moves.SPIT_UP) + .attr(StockpileStatChangeAttr, false) .condition(failOnNoStockCondition) .partial(), new SelfStatusMove(Moves.SWALLOW, Type.NORMAL, -1, 10, -1, 0, 3) .attr(SwallowHealAttr, 1) - .attr(StockpileStatChangeAttr, Moves.SWALLOW) + .attr(StockpileStatChangeAttr, false) .condition(failOnNoStockCondition) .triageMove() .partial(), From bb7493aa8182413dc55b66268190d6bcd6bad3e7 Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Thu, 16 May 2024 02:17:19 +0800 Subject: [PATCH 14/14] UPDATE: Added localisation to the trigger message --- src/data/enums/battler-tag-type.ts | 5 +- src/data/move.ts | 110 ++++++++++++++------------- src/locales/de/ability-trigger.ts | 1 + src/locales/en/ability-trigger.ts | 1 + src/locales/es/ability-trigger.ts | 1 + src/locales/fr/ability-trigger.ts | 1 + src/locales/it/ability-trigger.ts | 1 + src/locales/pt_BR/ability-trigger.ts | 6 ++ src/locales/zh_CN/ability-trigger.ts | 1 + 9 files changed, 72 insertions(+), 55 deletions(-) create mode 100644 src/locales/pt_BR/ability-trigger.ts diff --git a/src/data/enums/battler-tag-type.ts b/src/data/enums/battler-tag-type.ts index d3ab6fc48..1a0a3272f 100644 --- a/src/data/enums/battler-tag-type.ts +++ b/src/data/enums/battler-tag-type.ts @@ -56,11 +56,8 @@ export enum BattlerTagType { CHARGED = "CHARGED", GROUNDED = "GROUNDED", MAGNET_RISEN = "MAGNET_RISEN", -<<<<<<< HEAD STOCKPILE_ONE = "STOCKPILE_ONE", STOCKPILE_TWO = "STOCKPILE_TWO", - STOCKPILE_THREE = "STOCKPILE_THREE" -======= + STOCKPILE_THREE = "STOCKPILE_THREE", MINIMIZED = "MINIMIZED" ->>>>>>> 78f79653049baff0ec6514b743e5f602d43ad391 } diff --git a/src/data/move.ts b/src/data/move.ts index 915625e62..45afec61b 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4,7 +4,7 @@ import { BattleEndPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, Pokemo import { BattleStat, getBattleStatName } from "./battle-stat"; import { EncoreTag } from "./battler-tags"; import { BattlerTagType } from "./enums/battler-tag-type"; -import { getPokemonMessage } from "../messages"; +import { getPokemonMessage, getPokemonPrefix } from "../messages"; import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon"; import { StatusEffect, getStatusEffectHealText } from "./status-effect"; import { Type } from "./type"; @@ -949,28 +949,27 @@ export class HealAttr extends MoveEffectAttr { } } +/** Attribute used by the {@link Moves.STOCKPILE} to heal based on STOCKPILE stored*/ export class SwallowHealAttr extends HealAttr { + constructor() { + super(1, true, true); + } + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const stock = this.getStockpiles(user); + // uses the getStockpiles function to get number of STOCKPILE's stored + const stock = getStockpiles(user); + /** + * if stock is: + * 1, then healing is 0.25 of health + * 2, then healing is 0.50 of health + * 3, then healing is 1.00 of health + */ this.getHealRatio(stock >= 3 ? 1 : (stock * 0.25)); super.apply(user, target, move, args); return true; } - - getStockpiles(user: Pokemon): integer { - let stock = 0; - const tagList = [BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE]; - - for (let x = 0 ; x < tagList.length ; x++){ - if (user.getTag(tagList[x])){ - stock++; - } - } - - return stock; - } } /** @@ -1866,8 +1865,11 @@ export class GrowthStatChangeAttr extends StatChangeAttr { } } +/** Attribute for the stat changes for {@link Move.STOCKPILE}, {@link Move.SPIT_UP}, and {@link Move.SWALLOW}*/ export class StockpileStatChangeAttr extends StatChangeAttr { private tagTypes = [BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE]; + // this will show if we will gain 1 stack of stats with Stockpile + // or lose stacks of stats with Spit Up or Swallow private gainStats:boolean; constructor(gainStats:boolean = true) { @@ -1880,12 +1882,15 @@ export class StockpileStatChangeAttr extends StatChangeAttr { const stock = getStockpiles(user); if (!this.gainStats) { - // levels become equal to the negative of stock + /** + * since the Pokemon will be losing stats in this if statement, + * {@link this.levels} become equal to the negative of stock + */ this.levels = stock * -1; - // remove the stats equal to the number of stock + // remove the stats equal to the number of stocks for (let tagType of this.tagTypes) - (this.selfTarget ? user : target).removeTag(tagType); + user.removeTag(tagType); } if (!super.apply(user, target, move, args)) @@ -2457,26 +2462,21 @@ export class WaterShurikenPowerAttr extends VariablePowerAttr { } } +/** Attribute used by the {@link Moves.SPIT_UP} based on the number of stored STOCKPILE BattlerTagTypes*/ export class SpitUpPowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const power = args[0] as Utils.NumberHolder; - power.value = this.getPower(user, target, move); + /** + * if stock is: + * 1, then power is 100 + * 2, then power is 100 + * 3, then power is 100 + */ + power.value = getStockpiles(user)*100; return true; } - - getPower(user: Pokemon, target: Pokemon, move: Move): number { - if (!!user.getTag(BattlerTagType.STOCKPILE_THREE)){ - return 300; - } else if (!!user.getTag(BattlerTagType.STOCKPILE_TWO)){ - return 200; - } else if (!!user.getTag(BattlerTagType.STOCKPILE_ONE)){ - return 100; - } else { - return 0; - } - } } export class VariableAtkAttr extends MoveAttr { @@ -3344,46 +3344,52 @@ export class FaintCountdownAttr extends AddBattlerTagAttr { } } -<<<<<<< HEAD +/** Attribute used by the {@link Moves.STOCKPILE} to add the STOCKPILE BattlerTagTypes*/ export class StockpileAttr extends AddBattlerTagAttr { constructor() { super(BattlerTagType.STOCKPILE_THREE, true, false, 20, 20); } + /** + * This changes {@link this.tagType} based on the {@link stock} of the user + * @param user is needed to retrieve how much stockpile the Pokemon has + * as well as its name for the message + */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + // uses the getStockpiles() method to see how many stock the Pokemon has right now const stock = getStockpiles(user); - let stockType = BattlerTagType.STOCKPILE_THREE; + // boolean failsafe that the tag will not apply when inappropriate let willFail = false; + // check how many stock the user has then change the tag based on that + // keep the STOCKPILE_THREE tag if the stock is 2 or more switch (stock){ case 0: - stockType = BattlerTagType.STOCKPILE_ONE; + this.tagType = BattlerTagType.STOCKPILE_ONE; break; case 1: - stockType = BattlerTagType.STOCKPILE_TWO; + this.tagType = BattlerTagType.STOCKPILE_TWO; break; - case 3: - willFail = true; - break default: - // keep it at STOCKPILE_THREE + if (stock == 3) + willFail = true; break; } - this.tagType = stockType; - if (willFail || !super.apply(user, target, move, args)) return false; - user.scene.queueMessage(getPokemonMessage(target, `\nstockpiled ${stock+1}.`)); + user.scene.queueMessage(this.getTriggerMessage(user, (stock+1))); return true; } + + getTriggerMessage(pokemon: Pokemon, stockpileNumber: integer, ...args: any[]) { + return i18next.t('abilityTriggers:stockpile', {pokemonName: `${getPokemonPrefix(pokemon)}${pokemon.name}`, stockpileNumber: stockpileNumber}); + } } -======= /** Attribute used when a move hits a {@link BattlerTagType} for double damage */ ->>>>>>> 78f79653049baff0ec6514b743e5f602d43ad391 export class HitsTagAttr extends MoveAttr { /** The {@link BattlerTagType} this move hits */ public tagType: BattlerTagType; @@ -4356,6 +4362,11 @@ export class VariableTargetAttr extends MoveAttr { } } +/** + * Used to get how many stockpiles a Pokemon has + * @param user to retrieve the BattlerTagTypes + * @returns number of stockpile BattleTagTypes on the Pokemon + */ function getStockpiles(user: Pokemon) : integer { let s = 0; const stock = [BattlerTagType.STOCKPILE_ONE, BattlerTagType.STOCKPILE_TWO, BattlerTagType.STOCKPILE_THREE]; @@ -5221,19 +5232,16 @@ export function initMoves() { new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3) .attr(StockpileAttr) .attr(StockpileStatChangeAttr) - .condition(failOnMaxStockCondition) - .partial(), + .condition(failOnMaxStockCondition), new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) .attr(SpitUpPowerAttr) .attr(StockpileStatChangeAttr, false) - .condition(failOnNoStockCondition) - .partial(), + .condition(failOnNoStockCondition), new SelfStatusMove(Moves.SWALLOW, Type.NORMAL, -1, 10, -1, 0, 3) - .attr(SwallowHealAttr, 1) + .attr(SwallowHealAttr) .attr(StockpileStatChangeAttr, false) .condition(failOnNoStockCondition) - .triageMove() - .partial(), + .triageMove(), new AttackMove(Moves.HEAT_WAVE, Type.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 10, 0, 3) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE) .attr(StatusEffectAttr, StatusEffect.BURN) diff --git a/src/locales/de/ability-trigger.ts b/src/locales/de/ability-trigger.ts index 27d2053b6..6c2beba4e 100644 --- a/src/locales/de/ability-trigger.ts +++ b/src/locales/de/ability-trigger.ts @@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { 'blockRecoilDamage' : `{{pokemonName}} wurde durch {{abilityName}}\nvor Rückstoß geschützt!`, + 'stockpile' : `{{pokemonName}}\n hat {{stockpileNumber}} gehortet!` } as const; diff --git a/src/locales/en/ability-trigger.ts b/src/locales/en/ability-trigger.ts index 889007412..f1dddb423 100644 --- a/src/locales/en/ability-trigger.ts +++ b/src/locales/en/ability-trigger.ts @@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { 'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`, + 'stockpile' : `{{pokemonName}}\n stockpiled {{stockpileNumber}}!` } as const; \ No newline at end of file diff --git a/src/locales/es/ability-trigger.ts b/src/locales/es/ability-trigger.ts index 889007412..71a8f8f3d 100644 --- a/src/locales/es/ability-trigger.ts +++ b/src/locales/es/ability-trigger.ts @@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { 'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`, + 'stockpile' : `{{pokemonName}}\n reservo {{stockpileNumber}}!` } as const; \ No newline at end of file diff --git a/src/locales/fr/ability-trigger.ts b/src/locales/fr/ability-trigger.ts index f668ee5e8..073379caa 100644 --- a/src/locales/fr/ability-trigger.ts +++ b/src/locales/fr/ability-trigger.ts @@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { 'blockRecoilDamage' : `{{abilityName}}\nde {{pokemonName}} le protège du contrecoup !`, + 'stockpile' : `{{pokemonName}}\n en a stocké {{stockpileNumber}}!` } as const; diff --git a/src/locales/it/ability-trigger.ts b/src/locales/it/ability-trigger.ts index de41e0872..bc15677b5 100644 --- a/src/locales/it/ability-trigger.ts +++ b/src/locales/it/ability-trigger.ts @@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { 'blockRecoilDamage' : `{{abilityName}} di {{pokemonName}}\nl'ha protetto dal contraccolpo!`, + 'stockpile' : `{{pokemonName}}\n ne ha accumulati {{stockpileNumber}}!` } as const; \ No newline at end of file diff --git a/src/locales/pt_BR/ability-trigger.ts b/src/locales/pt_BR/ability-trigger.ts new file mode 100644 index 000000000..f1dddb423 --- /dev/null +++ b/src/locales/pt_BR/ability-trigger.ts @@ -0,0 +1,6 @@ +import { SimpleTranslationEntries } from "#app/plugins/i18n"; + +export const abilityTriggers: SimpleTranslationEntries = { + 'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`, + 'stockpile' : `{{pokemonName}}\n stockpiled {{stockpileNumber}}!` +} as const; \ No newline at end of file diff --git a/src/locales/zh_CN/ability-trigger.ts b/src/locales/zh_CN/ability-trigger.ts index 889007412..f1dddb423 100644 --- a/src/locales/zh_CN/ability-trigger.ts +++ b/src/locales/zh_CN/ability-trigger.ts @@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n"; export const abilityTriggers: SimpleTranslationEntries = { 'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`, + 'stockpile' : `{{pokemonName}}\n stockpiled {{stockpileNumber}}!` } as const; \ No newline at end of file