From 3aac0e73855ebd26b6da891f4e49e523dffaee96 Mon Sep 17 00:00:00 2001 From: Marek Sison Date: Thu, 2 May 2024 21:30:54 +0800 Subject: [PATCH 1/5] 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 2/5] 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 3/5] 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 4/5] 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 5/5] 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(),