Merge pull request #6 from mareksison/move/stockpile

Added Localisation and Documentation
pull/410/head
Marek Sison 2024-05-16 02:20:07 +08:00 committed by GitHub
commit 8304abd416
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 178 additions and 5 deletions

View File

@ -56,5 +56,8 @@ export enum BattlerTagType {
CHARGED = "CHARGED", CHARGED = "CHARGED",
GROUNDED = "GROUNDED", GROUNDED = "GROUNDED",
MAGNET_RISEN = "MAGNET_RISEN", MAGNET_RISEN = "MAGNET_RISEN",
STOCKPILE_ONE = "STOCKPILE_ONE",
STOCKPILE_TWO = "STOCKPILE_TWO",
STOCKPILE_THREE = "STOCKPILE_THREE",
MINIMIZED = "MINIMIZED" MINIMIZED = "MINIMIZED"
} }

View File

@ -4,7 +4,7 @@ import { BattleEndPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, Pokemo
import { BattleStat, getBattleStatName } from "./battle-stat"; import { BattleStat, getBattleStatName } from "./battle-stat";
import { EncoreTag } from "./battler-tags"; import { EncoreTag } from "./battler-tags";
import { BattlerTagType } from "./enums/battler-tag-type"; 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 Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon";
import { StatusEffect, getStatusEffectHealText } from "./status-effect"; import { StatusEffect, getStatusEffectHealText } from "./status-effect";
import { Type } from "./type"; import { Type } from "./type";
@ -936,12 +936,42 @@ export class HealAttr extends MoveEffectAttr {
Math.max(Math.floor(target.getMaxHp() * healRatio), 1), getPokemonMessage(target, ' \nhad its HP restored.'), true, !this.showAnim)); Math.max(Math.floor(target.getMaxHp() * healRatio), 1), getPokemonMessage(target, ' \nhad its HP restored.'), true, !this.showAnim));
} }
getHealRatio(h: number = -1){
if (h > 0)
this.healRatio = h;
return this.healRatio;
}
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer { getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
let score = ((1 - (this.selfTarget ? user : target).getHpRatio()) * 20) - this.healRatio * 10; let score = ((1 - (this.selfTarget ? user : target).getHpRatio()) * 20) - this.healRatio * 10;
return Math.round(score / (1 - this.healRatio / 2)); return Math.round(score / (1 - this.healRatio / 2));
} }
} }
/** 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 {
// 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;
}
}
/** /**
* Cures the user's party of non-volatile status conditions, ie. Heal Bell, Aromatherapy * Cures the user's party of non-volatile status conditions, ie. Heal Bell, Aromatherapy
* @param {string} message Message to display after using move * @param {string} message Message to display after using move
@ -1835,6 +1865,41 @@ 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) {
super([ BattleStat.DEF, BattleStat.SPDEF ], 1, true);
this.gainStats = gainStats;
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise<boolean> {
const stock = getStockpiles(user);
if (!this.gainStats) {
/**
* 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 stocks
for (let tagType of this.tagTypes)
user.removeTag(tagType);
}
if (!super.apply(user, target, move, args))
return false;
return true;
}
}
export class HalfHpStatMaxAttr extends StatChangeAttr { export class HalfHpStatMaxAttr extends StatChangeAttr {
constructor(stat: BattleStat) { constructor(stat: BattleStat) {
super(stat, 12, true, null, false); super(stat, 12, true, null, false);
@ -2397,6 +2462,23 @@ 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;
/**
* 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;
}
}
export class VariableAtkAttr extends MoveAttr { export class VariableAtkAttr extends MoveAttr {
constructor() { constructor() {
super(); super();
@ -3082,6 +3164,9 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
case BattlerTagType.INGRAIN: case BattlerTagType.INGRAIN:
case BattlerTagType.IGNORE_ACCURACY: case BattlerTagType.IGNORE_ACCURACY:
case BattlerTagType.AQUA_RING: case BattlerTagType.AQUA_RING:
case BattlerTagType.STOCKPILE_ONE:
case BattlerTagType.STOCKPILE_TWO:
case BattlerTagType.STOCKPILE_THREE:
return 3; return 3;
case BattlerTagType.PROTECTED: case BattlerTagType.PROTECTED:
case BattlerTagType.FLYING: case BattlerTagType.FLYING:
@ -3259,6 +3344,51 @@ export class FaintCountdownAttr extends AddBattlerTagAttr {
} }
} }
/** 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);
// 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:
this.tagType = BattlerTagType.STOCKPILE_ONE;
break;
case 1:
this.tagType = BattlerTagType.STOCKPILE_TWO;
break;
default:
if (stock == 3)
willFail = true;
break;
}
if (willFail || !super.apply(user, target, move, args))
return false;
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 */ /** Attribute used when a move hits a {@link BattlerTagType} for double damage */
export class HitsTagAttr extends MoveAttr { export class HitsTagAttr extends MoveAttr {
/** The {@link BattlerTagType} this move hits */ /** The {@link BattlerTagType} this move hits */
@ -4232,12 +4362,34 @@ 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];
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 failOnGravityCondition: MoveConditionFunc = (user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY);
const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.isBossImmune(); const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.isBossImmune();
const failOnMaxCondition: MoveConditionFunc = (user, target, move) => !target.isMax(); 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 failIfDampCondition: MoveConditionFunc = (user, target, move) => {
const cancelled = new Utils.BooleanHolder(false); const cancelled = new Utils.BooleanHolder(false);
user.scene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled)); user.scene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled));
@ -5078,12 +5230,18 @@ export function initMoves() {
.target(MoveTarget.RANDOM_NEAR_ENEMY) .target(MoveTarget.RANDOM_NEAR_ENEMY)
.partial(), .partial(),
new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3) new SelfStatusMove(Moves.STOCKPILE, Type.NORMAL, -1, 20, -1, 0, 3)
.unimplemented(), .attr(StockpileAttr)
.attr(StockpileStatChangeAttr)
.condition(failOnMaxStockCondition),
new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3) new AttackMove(Moves.SPIT_UP, Type.NORMAL, MoveCategory.SPECIAL, -1, 100, 10, -1, 0, 3)
.unimplemented(), .attr(SpitUpPowerAttr)
.attr(StockpileStatChangeAttr, false)
.condition(failOnNoStockCondition),
new SelfStatusMove(Moves.SWALLOW, Type.NORMAL, -1, 10, -1, 0, 3) new SelfStatusMove(Moves.SWALLOW, Type.NORMAL, -1, 10, -1, 0, 3)
.triageMove() .attr(SwallowHealAttr)
.unimplemented(), .attr(StockpileStatChangeAttr, false)
.condition(failOnNoStockCondition)
.triageMove(),
new AttackMove(Moves.HEAT_WAVE, Type.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 10, 0, 3) new AttackMove(Moves.HEAT_WAVE, Type.FIRE, MoveCategory.SPECIAL, 95, 90, 10, 10, 0, 3)
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
.attr(StatusEffectAttr, StatusEffect.BURN) .attr(StatusEffectAttr, StatusEffect.BURN)

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{pokemonName}} wurde durch {{abilityName}}\nvor Rückstoß geschützt!`, 'blockRecoilDamage' : `{{pokemonName}} wurde durch {{abilityName}}\nvor Rückstoß geschützt!`,
'stockpile' : `{{pokemonName}}\n hat {{stockpileNumber}} gehortet!`
} as const; } as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`, 'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`,
'stockpile' : `{{pokemonName}}\n stockpiled {{stockpileNumber}}!`
} as const; } as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`, 'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`,
'stockpile' : `{{pokemonName}}\n reservo {{stockpileNumber}}!`
} as const; } as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{abilityName}}\nde {{pokemonName}} le protège du contrecoup !`, 'blockRecoilDamage' : `{{abilityName}}\nde {{pokemonName}} le protège du contrecoup !`,
'stockpile' : `{{pokemonName}}\n en a stocké {{stockpileNumber}}!`
} as const; } as const;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{abilityName}} di {{pokemonName}}\nl'ha protetto dal contraccolpo!`, 'blockRecoilDamage' : `{{abilityName}} di {{pokemonName}}\nl'ha protetto dal contraccolpo!`,
'stockpile' : `{{pokemonName}}\n ne ha accumulati {{stockpileNumber}}!`
} as const; } as const;

View File

@ -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;

View File

@ -2,4 +2,5 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const abilityTriggers: SimpleTranslationEntries = { export const abilityTriggers: SimpleTranslationEntries = {
'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`, 'blockRecoilDamage' : `{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!`,
'stockpile' : `{{pokemonName}}\n stockpiled {{stockpileNumber}}!`
} as const; } as const;