Compare commits

...

12 Commits

Author SHA1 Message Date
Matthew Olker
b95a59c094 setup more future language text configuration 2024-05-19 23:11:07 -04:00
Somod1
a32f61fbf7
update zh_CN voucher locales (#1145)
* Add files via upload

* Update zh_CN voucher locales
2024-05-19 22:05:14 -05:00
Matthew Olker
ca1ae4b556 cleanup language and candy in starter select ui handler 2024-05-19 21:40:58 -04:00
Adrian Torrano
3671fe4c2f
Prevent spamming of requests when going over scoreboard pages (#1130)
* prevent spamming of requests

* add documentations
2024-05-19 18:04:32 -05:00
arColm
80f6b62d1b
Implement Revival Blessing (#343) 2024-05-19 18:02:17 -05:00
rayanzmn
f1394307f4
Fixes recoil damage calculation (#1063)
Recoil damage previously used the total damage dealt by the user instead of using the damage dealt in the current turn.
2024-05-19 17:54:17 -05:00
arColm
f649179e24
Implement Grassy Glide (#272) 2024-05-19 17:52:51 -05:00
lucfd
9f699537bc
Implemented Bug Bite, Pluck, Teatime (#232)
* implemented pluck, bug bite

* steal blocked by sticky hold

* implemented teatime

* added stuff cheeks

* added berry pouch support

* fixed StealEatBerryAttr sometimes eating 2 stacks of a berry

* added comments & documentation

* added more comments

* added comment on stuff cheeks condition

* fixed 0 stack berry modifier  not disappearing

* stuff cheeks bug fix

* fix leppa berry logic

* removed stuff cheeks
2024-05-19 17:47:30 -05:00
Matthew Olker
a30fc9b82d Update variant palettes and masterlist 2024-05-19 18:39:21 -04:00
GhostFlys
a4f4a37e5c
add egg.ts (#1138) 2024-05-19 17:27:17 -05:00
Lugiad
7216990d87
Locales for Voucher names + Voucher rewards (#1137)
* Update voucher.ts

* Update vouchers-ui-handler.ts

* Update i18n.ts

* Update config.ts

* Update config.ts

* Update config.ts

* Update config.ts

* Update config.ts

* Update config.ts

* Update config.ts

* Add files via upload

* Add files via upload

* Add files via upload

* Add files via upload

* Add files via upload

* Add files via upload

* Add files via upload
2024-05-19 17:25:52 -05:00
Jannik Tappert
13f2cafe5e
Female Variant Trainer Class Names set explicitly in definition of trainer classes (#1126)
* Set the name for the ace trainer female class

* Wrote out the name for all females trainer classes explicitly so they are always used.

Also made some changes (added missing classes) to languages
2024-05-19 14:52:48 -05:00
45 changed files with 987 additions and 209 deletions

View File

@ -1,15 +1,15 @@
{
"0": {
"7b4a9c": "323f81",
"63197b": "142557",
"a55ace": "6265b4",
"7b4a9c": "d684ce",
"63197b": "9c528c",
"a55ace": "ffb5f7",
"101010": "101010",
"b57bce": "99a3ee",
"08426b": "277eb2",
"ce0021": "ce0021",
"ffd600": "ffc3f4",
"d69400": "ff61e2",
"216b94": "4aa6ce",
"b57bce": "ffd6ef",
"08426b": "638400",
"ce0021": "940821",
"ffd600": "ffd600",
"d69400": "d69400",
"216b94": "8ca508",
"ffffff": "ffffff",
"a5a5a5": "a5a5a5",
"6b6b6b": "6b6b6b"

View File

@ -14,26 +14,26 @@
"943a7b": "175990"
},
"1": {
"3a3a7b": "1d0f4e",
"5aadef": "3d4381",
"6384ce": "2f2a5f",
"631052": "892d03",
"ce6bb5": "f1a139",
"adceff": "666fb4",
"3a3a7b": "084a00",
"5aadef": "6b9c29",
"6384ce": "317300",
"631052": "c52931",
"ce6bb5": "ffada5",
"adceff": "84d64a",
"000000": "000000",
"ad52ad": "d5711b",
"ad52ad": "e6737b",
"636363": "636363",
"ffffff": "ffffff",
"d6d6d6": "d6d6d6",
"943a7b": "af4e0c"
"943a7b": "d6525a"
},
"2": {
"3a3a7b": "584055",
"5aadef": "c1aec0",
"6384ce": "866881",
"3a3a7b": "3d2349",
"5aadef": "cbabca",
"6384ce": "916c8b",
"631052": "54070c",
"ce6bb5": "bc3b1d",
"adceff": "dfcddd",
"adceff": "e8d2e6",
"000000": "000000",
"ad52ad": "94241c",
"636363": "636363",

View File

@ -909,6 +909,11 @@
2,
2
],
"472": [
0,
0,
0
],
"475-mega": [
0,
2,
@ -2050,6 +2055,16 @@
2,
1
],
"41": [
0,
1,
1
],
"42": [
0,
1,
1
],
"308": [
0,
1,
@ -2869,7 +2884,7 @@
],
"383": [
0,
2,
1,
1
],
"384-mega": [
@ -4143,6 +4158,16 @@
1,
1
],
"41": [
0,
1,
1
],
"42": [
0,
1,
1
],
"308": [
0,
1,
@ -4538,7 +4563,7 @@
],
"747": [
0,
1,
2,
1
],
"748": [
@ -4591,6 +4616,11 @@
1,
1
],
"770": [
0,
0,
0
],
"771": [
0,
2,

View File

@ -1,4 +1,21 @@
{
"1": {
"000000": "000000",
"7b2129": "032a10",
"9c2929": "10371a",
"ff736b": "419e49",
"ff2129": "2b5b32",
"bd3131": "0f461c",
"3a3a3a": "383540",
"736363": "625769",
"ffffff": "fff6de",
"bdbdd6": "e5d4b6",
"9c6b31": "d51b3e",
"ffce31": "ff435d",
"94848c": "72798b",
"ffbdbd": "49c74f",
"ad9ca5": "ad9ca5"
},
"2": {
"000000": "000000",
"7b2129": "123953",

View File

@ -1,19 +1,19 @@
{
"0": {
"298c8c": "1c3820",
"5aada5": "3e5d43",
"84cece": "758076",
"004a52": "102c16",
"106b63": "0d1e10",
"298c8c": "427373",
"5aada5": "6b9c94",
"84cece": "94bdbd",
"004a52": "192121",
"106b63": "21524a",
"191921": "191921",
"106b7b": "102c16",
"29848c": "224427",
"6b4200": "54190e",
"c59c52": "a65c3f",
"9c7329": "763826",
"dece94": "e46424",
"ffefa5": "ff9942",
"bdad73": "cb3000"
"106b7b": "293a42",
"29848c": "424a5a",
"6b4200": "523a10",
"c59c52": "b59463",
"9c7329": "846b3a",
"dece94": "b5de21",
"ffefa5": "d6ff42",
"bdad73": "94bd00"
},
"1": {
"298c8c": "793907",

View File

@ -0,0 +1,24 @@
{
"1": {
"101010": "101010",
"8cb5ef": "4e538f",
"4a427b": "14093b",
"637bb5": "37326f",
"73215a": "aa4c18",
"b5529c": "cc7b32",
"bdceff": "868ecc",
"ffffff": "ffffff",
"636363": "636363"
},
"2": {
"101010": "101010",
"8cb5ef": "cbabca",
"4a427b": "4d3259",
"637bb5": "916c8b",
"73215a": "670f10",
"b5529c": "94241c",
"bdceff": "e8d2e6",
"ffffff": "ffffff",
"636363": "636363"
}
}

View File

@ -0,0 +1,24 @@
{
"1": {
"3a3a7b": "1d0f4e",
"6384ce": "2f2a5f",
"adceff": "666fb4",
"5aadef": "3d4381",
"631052": "892d03",
"000000": "000000",
"ce6bb5": "f1a139",
"ad52ad": "d5711b",
"943a7b": "af4e0c"
},
"2": {
"3a3a7b": "3d2349",
"6384ce": "916c8b",
"adceff": "e8d2e6",
"5aadef": "cbabca",
"631052": "54070c",
"000000": "000000",
"ce6bb5": "bc3b1d",
"ad52ad": "94241c",
"943a7b": "6c1314"
}
}

View File

@ -0,0 +1,188 @@
{
"textures": [
{
"image": "747_2.png",
"format": "RGBA8888",
"size": {
"w": 110,
"h": 110
},
"scale": 1,
"frames": [
{
"filename": "0003.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
},
"frame": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
}
},
{
"filename": "0004.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
},
"frame": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
}
},
{
"filename": "0007.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
},
"frame": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
}
},
{
"filename": "0008.png",
"rotated": false,
"trimmed": false,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
},
"frame": {
"x": 0,
"y": 0,
"w": 55,
"h": 47
}
},
{
"filename": "0001.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 55,
"h": 46
},
"frame": {
"x": 55,
"y": 0,
"w": 55,
"h": 46
}
},
{
"filename": "0002.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 0,
"w": 55,
"h": 46
},
"frame": {
"x": 55,
"y": 0,
"w": 55,
"h": 46
}
},
{
"filename": "0005.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 55,
"h": 46
},
"frame": {
"x": 55,
"y": 46,
"w": 55,
"h": 46
}
},
{
"filename": "0006.png",
"rotated": false,
"trimmed": true,
"sourceSize": {
"w": 55,
"h": 47
},
"spriteSourceSize": {
"x": 0,
"y": 1,
"w": 55,
"h": 46
},
"frame": {
"x": 55,
"y": 46,
"w": 55,
"h": 46
}
}
]
}
],
"meta": {
"app": "https://www.codeandweb.com/texturepacker",
"version": "3.0",
"smartupdate": "$TexturePacker:SmartUpdate:e4c4f790c4f0286f608dcdb15a609059:464f7ae7db1c0d034c2a1a65612b0da8:b26f7254994561969f00f765318acf1c$"
}
}

View File

@ -0,0 +1,26 @@
{
"1": {
"101010": "101010",
"637bb5": "37326f",
"4a427b": "14093b",
"bdceff": "868ecc",
"8cb5ef": "4e538f",
"b5529c": "cc7b32",
"73215a": "aa4c18",
"d673bd": "f0ad57",
"ffffff": "ffffff",
"636363": "636363"
},
"2": {
"101010": "101010",
"637bb5": "916c8b",
"4a427b": "4d3259",
"bdceff": "e8d2e6",
"8cb5ef": "cbabca",
"b5529c": "94241c",
"73215a": "670f10",
"d673bd": "bc3b1d",
"ffffff": "ffffff",
"636363": "636363"
}
}

View File

@ -0,0 +1,30 @@
{
"1": {
"3a3a7b": "1d0f4e",
"5aadef": "3d4381",
"6384ce": "2f2a5f",
"631052": "892d03",
"ce6bb5": "f1a139",
"adceff": "666fb4",
"000000": "000000",
"ad52ad": "d5711b",
"636363": "636363",
"ffffff": "ffffff",
"d6d6d6": "d6d6d6",
"943a7b": "af4e0c"
},
"2": {
"3a3a7b": "3d2349",
"5aadef": "cbabca",
"6384ce": "916c8b",
"631052": "54070c",
"ce6bb5": "bc3b1d",
"adceff": "e8d2e6",
"000000": "000000",
"ad52ad": "94241c",
"636363": "636363",
"ffffff": "ffffff",
"d6d6d6": "d6d6d6",
"943a7b": "6c1314"
}
}

View File

@ -9,7 +9,7 @@ import { BattlerTag } from "./battler-tags";
import { BattlerTagType } from "./enums/battler-tag-type";
import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
import { Gender } from "./gender";
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves, StatusMove, VariablePowerAttr, applyMoveAttrs } from "./move";
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves, StatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr } from "./move";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { ArenaTagType } from "./enums/arena-tag-type";
import { Stat } from "./pokemon-stat";
@ -491,8 +491,13 @@ export class PostDefendFormChangeAbAttr extends PostDefendAbAttr {
export class FieldPriorityMoveImmunityAbAttr extends PreDefendAbAttr {
applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean {
const attackPriority = new Utils.IntegerHolder(move.getMove().priority);
applyMoveAttrs(IncrementMovePriorityAttr,attacker,null,move.getMove(),attackPriority);
applyAbAttrs(IncrementMovePriorityAbAttr, attacker, null, move.getMove(), attackPriority);
if(move.getMove().moveTarget===MoveTarget.USER) {
return false;
}
if(attackPriority.value > 0 && !move.getMove().isMultiTarget()) {
cancelled.value = true;
return true;

View File

@ -130,9 +130,11 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
return (pokemon: Pokemon) => {
if (pokemon.battleData)
pokemon.battleData.berriesEaten.push(berryType);
const ppRestoreMove = pokemon.getMoveset().find(m => !m.getPpRatio());
ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0);
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` restored PP to its move ${ppRestoreMove.getName()}\nusing its ${getBerryName(berryType)}!`));
const ppRestoreMove = pokemon.getMoveset().find(m => !m.getPpRatio()) ? pokemon.getMoveset().find(m => !m.getPpRatio()) : pokemon.getMoveset().find(m => m.getPpRatio() < 1);
if(ppRestoreMove !== undefined){
ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0);
pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` restored PP to its move ${ppRestoreMove.getName()}\nusing its ${getBerryName(berryType)}!`));
}
};
}
}

View File

@ -1,6 +1,6 @@
import { Moves } from "./enums/moves";
import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims";
import { BattleEndPhase, MoveEffectPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase } from "../phases";
import { BattleEndPhase, MoveEffectPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase, ToggleDoublePositionPhase } from "../phases";
import { BattleStat, getBattleStatName } from "./battle-stat";
import { EncoreTag } from "./battler-tags";
import { BattlerTagType } from "./enums/battler-tag-type";
@ -12,10 +12,10 @@ import * as Utils from "../utils";
import { WeatherType } from "./weather";
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
import { ArenaTagType } from "./enums/arena-tag-type";
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, NoTransformAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr } from "./ability";
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, NoTransformAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, PreventBerryUseAbAttr, BlockItemTheftAbAttr } from "./ability";
import { Abilities } from "./enums/abilities";
import { allAbilities } from './ability';
import { PokemonHeldItemModifier } from "../modifier/modifier";
import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier";
import { BattlerIndex } from "../battle";
import { Stat } from "./pokemon-stat";
import { TerrainType } from "./terrain";
@ -25,6 +25,7 @@ import { ModifierPoolType } from "#app/modifier/modifier-type";
import { Command } from "../ui/command-ui-handler";
import { Biome } from "./enums/biome";
import i18next, { Localizable } from '../plugins/i18n';
import { BerryType, BerryEffectFunc, getBerryEffectFunc } from './berry';
export enum MoveCategory {
PHYSICAL,
@ -781,8 +782,8 @@ export class RecoilAttr extends MoveEffectAttr {
if (cancelled.value)
return false;
const recoilDamage = Math.max(Math.floor((!this.useHp ? user.turnData.damageDealt : user.getMaxHp()) * this.damageRatio),
user.turnData.damageDealt ? 1 : 0);
const recoilDamage = Math.max(Math.floor((!this.useHp ? user.turnData.currDamageDealt : user.getMaxHp()) * this.damageRatio),
user.turnData.currDamageDealt ? 1 : 0);
if (!recoilDamage)
return false;
@ -1168,6 +1169,42 @@ export class StrengthSapHealAttr extends MoveEffectAttr {
return true;
}
}
/**
* Attribute used for moves that change priority in a turn given a condition,
* e.g. Grassy Glide
* Called when move order is calculated in {@linkcode TurnStartPhase}.
* @extends MoveAttr
* @see {@linkcode apply}
*/
export class IncrementMovePriorityAttr extends MoveAttr {
/** The condition for a move's priority being incremented */
private moveIncrementFunc: (pokemon: Pokemon, target:Pokemon, move: Move) => boolean;
/** The amount to increment priority by, if condition passes. */
private increaseAmount: integer;
constructor(moveIncrementFunc: (pokemon: Pokemon, target:Pokemon, move: Move) => boolean, increaseAmount = 1) {
super();
this.moveIncrementFunc = moveIncrementFunc;
this.increaseAmount = increaseAmount;
}
/**
* Increments move priority by set amount if condition passes
* @param user {@linkcode Pokemon} using this move
* @param target {@linkcode Pokemon} target of this move
* @param move {@linkcode Move} being used
* @param args [0] {@linkcode Utils.IntegerHolder} for move priority.
* @returns true if function succeeds
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!this.moveIncrementFunc(user, target, move))
return false;
(args[0] as Utils.IntegerHolder).value += this.increaseAmount;
return true;
}
}
export class MultiHitAttr extends MoveAttr {
private multiHitType: MultiHitType;
@ -1443,6 +1480,95 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
}
}
/**
* Attribute that causes targets of the move to eat a berry. If chosenBerry is not overriden, a random berry will be picked from the target's inventory.
*/
export class EatBerryAttr extends MoveEffectAttr {
protected chosenBerry: BerryModifier;
constructor() {
super(true, MoveEffectTrigger.HIT);
this.chosenBerry = undefined;
}
/**
* Causes the target to eat a berry.
* @param user {@linkcode Pokemon} Pokemon that used the move
* @param target {@linkcode Pokemon} Pokemon that will eat a berry
* @param move {@linkcode Move} The move being used
* @param args Unused
* @returns {boolean} true if the function succeeds
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.apply(user, target, move, args))
return false;
if(this.chosenBerry === undefined) { // if no berry has been provided, pick a random berry from their inventory
const heldBerries = this.getTargetHeldBerries(target);
if(heldBerries.length <= 0)
return false;
this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)];
}
getBerryEffectFunc(this.chosenBerry.berryType)(target); // target eats the berry
const preserve = new Utils.BooleanHolder(false);
target.scene.applyModifiers(PreserveBerryModifier, target.isPlayer(), target, preserve);
if (!preserve.value){ // remove the eaten berry if not preserved
if (!--this.chosenBerry.stackCount)
target.scene.removeModifier(this.chosenBerry, !target.isPlayer());
target.scene.updateModifiers(target.isPlayer());
}
this.chosenBerry = undefined;
return true;
}
getTargetHeldBerries(target: Pokemon): BerryModifier[] {
return target.scene.findModifiers(m => m instanceof BerryModifier
&& (m as BerryModifier).pokemonId === target.id, target.isPlayer()) as BerryModifier[];
}
}
/**
* Attribute used for moves that steal a random berry from the target. The user then eats the stolen berry.
* Used for Pluck & Bug Bite.
*/
export class StealEatBerryAttr extends EatBerryAttr {
constructor() {
super();
}
/**
* User steals a random berry from the target and then eats it.
* @param {Pokemon} user Pokemon that used the move and will eat the stolen berry
* @param {Pokemon} target Pokemon that will have its berry stolen
* @param {Move} move Move being used
* @param {any[]} args Unused
* @returns {boolean} true if the function succeeds
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const cancelled = new Utils.BooleanHolder(false);
applyAbAttrs(BlockItemTheftAbAttr, target, cancelled); // check for abilities that block item theft
if(cancelled.value == true)
return false;
const heldBerries = this.getTargetHeldBerries(target).filter(i => i.getTransferrable(false));
if (heldBerries.length) { // if the target has berries, pick a random berry and steal it
this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)];
if (this.chosenBerry.stackCount == 1) // remove modifier if its the last berry
target.scene.removeModifier(this.chosenBerry, !target.isPlayer());
target.scene.updateModifiers(target.isPlayer());
user.scene.queueMessage(getPokemonMessage(user, ` stole and ate\n${target.name}'s ${this.chosenBerry.type.name}!`));
return super.apply(user, user, move, args);
}
return false;
}
}
export class HealStatusEffectAttr extends MoveEffectAttr {
private effects: StatusEffect[];
@ -3568,6 +3694,67 @@ export class RemoveScreensAttr extends MoveEffectAttr {
}
}
/**
* Attribute used for Revival Blessing.
* @extends MoveEffectAttr
* @see {@linkcode apply}
*/
export class RevivalBlessingAttr extends MoveEffectAttr {
constructor(user?: boolean) {
super(true);
}
/**
*
* @param user {@linkcode Pokemon} using this move
* @param target {@linkcode Pokemon} target of this move
* @param move {@linkcode Move} being used
* @param args N/A
* @returns Promise, true if function succeeds.
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
return new Promise(resolve => {
// If user is player, checks if the user has fainted pokemon
if(user instanceof PlayerPokemon
&& user.scene.getParty().findIndex(p => p.isFainted())>-1) {
(user as PlayerPokemon).revivalBlessing().then(() => {
resolve(true)
});
// If user is enemy, checks that it is a trainer, and it has fainted non-boss pokemon in party
} else if(user instanceof EnemyPokemon
&& user.hasTrainer()
&& user.scene.getEnemyParty().findIndex(p => p.isFainted() && !p.isBoss()) > -1) {
// Selects a random fainted pokemon
const faintedPokemon = user.scene.getEnemyParty().filter(p => p.isFainted() && !p.isBoss());
const pokemon = faintedPokemon[user.randSeedInt(faintedPokemon.length)];
const slotIndex = user.scene.getEnemyParty().findIndex(p => pokemon.id === p.id);
pokemon.resetStatus();
pokemon.heal(Math.min(Math.max(Math.ceil(Math.floor(0.5 * pokemon.getMaxHp())), 1), pokemon.getMaxHp()));
user.scene.queueMessage(`${pokemon.name} was revived!`,0,true);
if(user.scene.currentBattle.double && user.scene.getEnemyParty().length > 1) {
const allyPokemon = user.getAlly();
if(slotIndex<=1) {
user.scene.unshiftPhase(new SwitchSummonPhase(user.scene, pokemon.getFieldIndex(), slotIndex, false, false, false));
} else if(allyPokemon.isFainted()){
user.scene.unshiftPhase(new SwitchSummonPhase(user.scene, allyPokemon.getFieldIndex(), slotIndex, false, false,false));
}
}
resolve(true);
} else {
user.scene.queueMessage(`But it failed!`);
resolve(false);
}
})
}
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer {
if(user.hasTrainer() && user.scene.getEnemyParty().findIndex(p => p.isFainted() && !p.isBoss()) > -1)
return 20;
return -20;
}
}
export class ForceSwitchOutAttr extends MoveEffectAttr {
private user: boolean;
@ -5556,7 +5743,7 @@ export function initMoves() {
.makesContact(false)
.ignoresProtect(),
new AttackMove(Moves.PLUCK, Type.FLYING, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 4)
.partial(),
.attr(StealEatBerryAttr),
new StatusMove(Moves.TAILWIND, Type.FLYING, -1, 15, -1, 0, 4)
.windMove()
.attr(AddArenaTagAttr, ArenaTagType.TAILWIND, 4, true)
@ -5793,7 +5980,7 @@ export function initMoves() {
new AttackMove(Moves.JUDGMENT, Type.NORMAL, MoveCategory.SPECIAL, 100, 100, 10, -1, 0, 4)
.partial(),
new AttackMove(Moves.BUG_BITE, Type.BUG, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 4)
.partial(),
.attr(StealEatBerryAttr),
new AttackMove(Moves.CHARGE_BEAM, Type.ELECTRIC, MoveCategory.SPECIAL, 50, 90, 10, 70, 0, 4)
.attr(StatChangeAttr, BattleStat.SPATK, 1, true),
new AttackMove(Moves.WOOD_HAMMER, Type.GRASS, MoveCategory.PHYSICAL, 120, 100, 15, -1, 0, 4)
@ -6655,8 +6842,8 @@ export function initMoves() {
.makesContact(false)
.partial(),
new StatusMove(Moves.TEATIME, Type.NORMAL, -1, 10, -1, 0, 8)
.target(MoveTarget.ALL)
.unimplemented(),
.attr(EatBerryAttr)
.target(MoveTarget.ALL),
new StatusMove(Moves.OCTOLOCK, Type.FIGHTING, 100, 15, -1, 0, 8)
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, true, 1)
.partial(),
@ -6826,7 +7013,7 @@ export function initMoves() {
.condition(failIfDampCondition)
.makesContact(false),
new AttackMove(Moves.GRASSY_GLIDE, Type.GRASS, MoveCategory.PHYSICAL, 55, 100, 20, -1, 0, 8)
.partial(),
.attr(IncrementMovePriorityAttr,(user,target,move) =>user.scene.arena.getTerrainType()===TerrainType.GRASSY&&user.isGrounded()),
new AttackMove(Moves.RISING_VOLTAGE, Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 20, -1, 0, 8)
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.ELECTRIC && target.isGrounded() ? 2 : 1),
new AttackMove(Moves.TERRAIN_PULSE, Type.NORMAL, MoveCategory.SPECIAL, 50, 100, 10, -1, 0, 8)
@ -7109,7 +7296,8 @@ export function initMoves() {
.partial(),
new StatusMove(Moves.REVIVAL_BLESSING, Type.NORMAL, -1, 1, -1, 0, 9)
.triageMove()
.unimplemented(),
.attr(RevivalBlessingAttr)
.target(MoveTarget.USER),
new AttackMove(Moves.SALT_CURE, Type.ROCK, MoveCategory.PHYSICAL, 40, 100, 15, -1, 0, 9)
.attr(AddBattlerTagAttr, BattlerTagType.SALT_CURED)
.makesContact(false),

View File

@ -687,12 +687,12 @@ function getRandomTeraModifiers(party: EnemyPokemon[], count: integer, types?: T
export const trainerConfigs: TrainerConfigs = {
[TrainerType.UNKNOWN]: new TrainerConfig(0).setHasGenders(),
[TrainerType.ACE_TRAINER]: new TrainerConfig(++t).setHasGenders().setHasDouble('Ace Duo').setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.ACE_TRAINER)
[TrainerType.ACE_TRAINER]: new TrainerConfig(++t).setHasGenders('Ace Trainer Female').setHasDouble('Ace Duo').setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.ACE_TRAINER)
.setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.THREE_WEAK_BALANCED, trainerPartyTemplates.FOUR_WEAK_BALANCED, trainerPartyTemplates.FIVE_WEAK_BALANCED, trainerPartyTemplates.SIX_WEAK_BALANCED)),
[TrainerType.ARTIST]: new TrainerConfig(++t).setEncounterBgm(TrainerType.RICH).setPartyTemplates(trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.THREE_AVG)
.setSpeciesPools([ Species.SMEARGLE ]),
[TrainerType.BACKERS]: new TrainerConfig(++t).setHasGenders().setDoubleOnly().setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.BACKPACKER]: new TrainerConfig(++t).setHasGenders().setHasDouble('Backpackers').setSpeciesFilter(s => s.isOfType(Type.FLYING) || s.isOfType(Type.ROCK)).setEncounterBgm(TrainerType.BACKPACKER)
[TrainerType.BACKERS]: new TrainerConfig(++t).setHasGenders("Backers").setDoubleOnly().setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.BACKPACKER]: new TrainerConfig(++t).setHasGenders("Backpacker Female").setHasDouble('Backpackers').setSpeciesFilter(s => s.isOfType(Type.FLYING) || s.isOfType(Type.ROCK)).setEncounterBgm(TrainerType.BACKPACKER)
.setPartyTemplates(trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.ONE_WEAK_ONE_STRONG, trainerPartyTemplates.ONE_AVG_ONE_STRONG)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.RHYHORN, Species.AIPOM, Species.MAKUHITA, Species.MAWILE, Species.NUMEL, Species.LILLIPUP, Species.SANDILE, Species.WOOLOO ],
@ -712,17 +712,17 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.SUPER_RARE]: [ Species.HITMONTOP, Species.INFERNAPE, Species.GALLADE, Species.HAWLUCHA, Species.HAKAMO_O ],
[TrainerPoolTier.ULTRA_RARE]: [ Species.KUBFU ]
}),
[TrainerType.BREEDER]: new TrainerConfig(++t).setMoneyMultiplier(1.325).setEncounterBgm(TrainerType.POKEFAN).setHasGenders().setHasDouble('Breeders')
[TrainerType.BREEDER]: new TrainerConfig(++t).setMoneyMultiplier(1.325).setEncounterBgm(TrainerType.POKEFAN).setHasGenders("Breeder Female").setHasDouble('Breeders')
.setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.FOUR_WEAKER, trainerPartyTemplates.FIVE_WEAKER, trainerPartyTemplates.SIX_WEAKER))
.setSpeciesFilter(s => s.baseTotal < 450),
[TrainerType.CLERK]: new TrainerConfig(++t).setHasGenders().setHasDouble('Colleagues').setEncounterBgm(TrainerType.CLERK)
[TrainerType.CLERK]: new TrainerConfig(++t).setHasGenders("Clerk Female").setHasDouble('Colleagues').setEncounterBgm(TrainerType.CLERK)
.setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.THREE_WEAK, trainerPartyTemplates.ONE_AVG, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_ONE_AVG)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.MEOWTH, Species.PSYDUCK, Species.BUDEW, Species.PIDOVE, Species.CINCCINO, Species.LITLEO ],
[TrainerPoolTier.UNCOMMON]: [ Species.JIGGLYPUFF, Species.MAGNEMITE, Species.MARILL, Species.COTTONEE, Species.SKIDDO ],
[TrainerPoolTier.RARE]: [ Species.BUIZEL, Species.SNEASEL, Species.KLEFKI, Species.INDEEDEE ]
}),
[TrainerType.CYCLIST]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setHasGenders().setHasDouble('Cyclists').setEncounterBgm(TrainerType.CYCLIST)
[TrainerType.CYCLIST]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setHasGenders("Cyclist Female").setHasDouble('Cyclists').setEncounterBgm(TrainerType.CYCLIST)
.setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.ONE_AVG)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.PICHU, Species.STARLY, Species.TAILLOW, Species.BOLTUND ],
@ -781,9 +781,9 @@ export const trainerConfigs: TrainerConfigs = {
}),
[TrainerType.PARASOL_LADY]: new TrainerConfig(++t).setMoneyMultiplier(1.55).setEncounterBgm(TrainerType.PARASOL_LADY).setSpeciesFilter(s => s.isOfType(Type.WATER)),
[TrainerType.PILOT]: new TrainerConfig(++t).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => tmSpecies[Moves.FLY].indexOf(s.speciesId) > -1),
[TrainerType.POKEFAN]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setName('Poké Fan').setHasGenders().setHasDouble('Poké Fan Family').setEncounterBgm(TrainerType.POKEFAN)
[TrainerType.POKEFAN]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setName('PokéFan').setHasGenders("PokéFan Female").setHasDouble('PokéFan Family').setEncounterBgm(TrainerType.POKEFAN)
.setPartyTemplates(trainerPartyTemplates.SIX_WEAKER, trainerPartyTemplates.FOUR_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.ONE_STRONG, trainerPartyTemplates.FOUR_WEAK_SAME, trainerPartyTemplates.FIVE_WEAK, trainerPartyTemplates.SIX_WEAKER_SAME),
[TrainerType.PRESCHOOLER]: new TrainerConfig(++t).setMoneyMultiplier(0.2).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders(undefined, 'lass').setHasDouble('Preschoolers')
[TrainerType.PRESCHOOLER]: new TrainerConfig(++t).setMoneyMultiplier(0.2).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders("Preschooler Female", 'lass').setHasDouble('Preschoolers')
.setPartyTemplates(trainerPartyTemplates.THREE_WEAK, trainerPartyTemplates.FOUR_WEAKER, trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG, trainerPartyTemplates.FIVE_WEAKER)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.CATERPIE, Species.PICHU, Species.SANDSHREW, Species.LEDYBA, Species.BUDEW, Species.BURMY, Species.WOOLOO, Species.PAWMI, Species.SMOLIV ],
@ -791,7 +791,7 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.RARE]: [ Species.RALTS, Species.RIOLU, Species.JOLTIK, Species.TANDEMAUS ],
[TrainerPoolTier.SUPER_RARE]: [ Species.DARUMAKA, Species.TINKATINK ],
}),
[TrainerType.PSYCHIC]: new TrainerConfig(++t).setHasGenders().setHasDouble('Psychics').setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.PSYCHIC)
[TrainerType.PSYCHIC]: new TrainerConfig(++t).setHasGenders("Psychic Female").setHasDouble('Psychics').setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.PSYCHIC)
.setPartyTemplates(trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG, trainerPartyTemplates.TWO_WEAK_SAME_TWO_WEAK_SAME, trainerPartyTemplates.ONE_STRONGER)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.ABRA, Species.DROWZEE, Species.RALTS, Species.SPOINK, Species.GOTHITA, Species.SOLOSIS, Species.BLIPBUG, Species.ESPURR, Species.HATENNA ],
@ -799,7 +799,7 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.RARE]: [ Species.ELGYEM, Species.SIGILYPH, Species.BALTOY, Species.GIRAFARIG, Species.MEOWSTIC ],
[TrainerPoolTier.SUPER_RARE]: [ Species.BELDUM, Species.ESPEON, Species.STANTLER ],
}),
[TrainerType.RANGER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setName('Pokémon Ranger').setEncounterBgm(TrainerType.BACKPACKER).setHasGenders().setHasDouble('Pokémon Rangers')
[TrainerType.RANGER]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setName('Pokémon Ranger').setEncounterBgm(TrainerType.BACKPACKER).setHasGenders("Pokémon Ranger Female").setHasDouble('Pokémon Rangers')
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.PICHU, Species.GROWLITHE, Species.PONYTA, Species.ZIGZAGOON, Species.SEEDOT, Species.BIDOOF, Species.RIOLU, Species.SEWADDLE, Species.SKIDDO, Species.SALANDIT, Species.YAMPER ],
[TrainerPoolTier.UNCOMMON]: [ Species.AZURILL, Species.TAUROS, Species.MAREEP, Species.FARFETCHD, Species.TEDDIURSA, Species.SHROOMISH, Species.ELECTRIKE, Species.BUDEW, Species.BUIZEL, Species.MUDBRAY, Species.STUFFUL ],
@ -809,7 +809,7 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerType.RICH]: new TrainerConfig(++t).setMoneyMultiplier(5).setName('Gentleman').setHasGenders('Madame').setHasDouble('Rich Couple'),
[TrainerType.RICH_KID]: new TrainerConfig(++t).setMoneyMultiplier(3.75).setName('Rich Boy').setHasGenders('Lady').setHasDouble('Rich Kids').setEncounterBgm(TrainerType.RICH),
[TrainerType.ROUGHNECK]: new TrainerConfig(++t).setMoneyMultiplier(1.4).setEncounterBgm(TrainerType.ROUGHNECK).setSpeciesFilter(s => s.isOfType(Type.DARK)),
[TrainerType.SCIENTIST]: new TrainerConfig(++t).setHasGenders().setHasDouble('Scientists').setMoneyMultiplier(1.7).setEncounterBgm(TrainerType.SCIENTIST)
[TrainerType.SCIENTIST]: new TrainerConfig(++t).setHasGenders("Scientist Female").setHasDouble('Scientists').setMoneyMultiplier(1.7).setEncounterBgm(TrainerType.SCIENTIST)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.MAGNEMITE, Species.GRIMER, Species.DROWZEE, Species.VOLTORB, Species.KOFFING ],
[TrainerPoolTier.UNCOMMON]: [ Species.BALTOY, Species.BRONZOR, Species.FERROSEED, Species.KLINK, Species.CHARJABUG, Species.BLIPBUG, Species.HELIOPTILE ],
@ -818,29 +818,29 @@ export const trainerConfigs: TrainerConfigs = {
[TrainerPoolTier.ULTRA_RARE]: [ Species.ROTOM, Species.MELTAN ]
}),
[TrainerType.SMASHER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.SNOW_WORKER]: new TrainerConfig(++t).setName('Worker').setHasGenders().setHasDouble('Workers').setMoneyMultiplier(1.7).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => s.isOfType(Type.ICE) || s.isOfType(Type.STEEL)),
[TrainerType.SNOW_WORKER]: new TrainerConfig(++t).setName('Worker').setHasGenders("Worker Female").setHasDouble('Workers').setMoneyMultiplier(1.7).setEncounterBgm(TrainerType.CLERK).setSpeciesFilter(s => s.isOfType(Type.ICE) || s.isOfType(Type.STEEL)),
[TrainerType.STRIKER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST),
[TrainerType.SCHOOL_KID]: new TrainerConfig(++t).setMoneyMultiplier(0.75).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders(undefined, 'lass').setHasDouble('School Kids')
[TrainerType.SCHOOL_KID]: new TrainerConfig(++t).setMoneyMultiplier(0.75).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders("School Kid Female", 'lass').setHasDouble('School Kids')
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.ODDISH, Species.EXEGGCUTE, Species.TEDDIURSA, Species.WURMPLE, Species.RALTS, Species.SHROOMISH, Species.FLETCHLING ],
[TrainerPoolTier.UNCOMMON]: [ Species.VOLTORB, Species.WHISMUR, Species.MEDITITE, Species.MIME_JR, Species.NYMBLE ],
[TrainerPoolTier.RARE]: [ Species.TANGELA, Species.EEVEE, Species.YANMA ],
[TrainerPoolTier.SUPER_RARE]: [ Species.TADBULB ]
}),
[TrainerType.SWIMMER]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm(TrainerType.PARASOL_LADY).setHasGenders().setHasDouble('Swimmers').setSpecialtyTypes(Type.WATER).setSpeciesFilter(s => s.isOfType(Type.WATER)),
[TrainerType.SWIMMER]: new TrainerConfig(++t).setMoneyMultiplier(1.3).setEncounterBgm(TrainerType.PARASOL_LADY).setHasGenders("Swimmer Female").setHasDouble('Swimmers').setSpecialtyTypes(Type.WATER).setSpeciesFilter(s => s.isOfType(Type.WATER)),
[TrainerType.TWINS]: new TrainerConfig(++t).setDoubleOnly().setMoneyMultiplier(0.65).setUseSameSeedForAllMembers()
.setPartyTemplateFunc(scene => getWavePartyTemplate(scene, trainerPartyTemplates.TWO_WEAK, trainerPartyTemplates.TWO_AVG, trainerPartyTemplates.TWO_STRONG))
.setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PLUSLE, Species.VOLBEAT, Species.PACHIRISU, Species.SILCOON, Species.METAPOD, Species.IGGLYBUFF, Species.PETILIL, Species.EEVEE ]))
.setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.MINUN, Species.ILLUMISE, Species.EMOLGA, Species.CASCOON, Species.KAKUNA, Species.CLEFFA, Species.COTTONEE, Species.EEVEE ], TrainerSlot.TRAINER_PARTNER))
.setEncounterBgm(TrainerType.TWINS),
[TrainerType.VETERAN]: new TrainerConfig(++t).setHasGenders().setHasDouble('Veteran Duo').setMoneyMultiplier(2.5).setEncounterBgm(TrainerType.ACE_TRAINER).setSpeciesFilter(s => s.isOfType(Type.DRAGON)),
[TrainerType.VETERAN]: new TrainerConfig(++t).setHasGenders("Veteran Female").setHasDouble('Veteran Duo').setMoneyMultiplier(2.5).setEncounterBgm(TrainerType.ACE_TRAINER).setSpeciesFilter(s => s.isOfType(Type.DRAGON)),
[TrainerType.WAITER]: new TrainerConfig(++t).setHasGenders('Waitress').setHasDouble('Restaurant Staff').setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.CLERK)
.setSpeciesPools({
[TrainerPoolTier.COMMON]: [ Species.CLEFFA, Species.CHATOT, Species.PANSAGE, Species.PANSEAR, Species.PANPOUR, Species.MINCCINO ],
[TrainerPoolTier.UNCOMMON]: [ Species.TROPIUS, Species.PETILIL, Species.BOUNSWEET, Species.INDEEDEE ],
[TrainerPoolTier.RARE]: [ Species.APPLIN, Species.SINISTEA, Species.POLTCHAGEIST ]
}),
[TrainerType.WORKER]: new TrainerConfig(++t).setHasGenders().setHasDouble('Workers').setEncounterBgm(TrainerType.CLERK).setMoneyMultiplier(1.7).setSpeciesFilter(s => s.isOfType(Type.ROCK) || s.isOfType(Type.STEEL)),
[TrainerType.WORKER]: new TrainerConfig(++t).setHasGenders("Worker Female").setHasDouble('Workers').setEncounterBgm(TrainerType.CLERK).setMoneyMultiplier(1.7).setSpeciesFilter(s => s.isOfType(Type.ROCK) || s.isOfType(Type.STEEL)),
[TrainerType.YOUNGSTER]: new TrainerConfig(++t).setMoneyMultiplier(0.5).setEncounterBgm(TrainerType.YOUNGSTER).setHasGenders('Lass', 'lass').setHasDouble('Beginners').setPartyTemplates(trainerPartyTemplates.TWO_WEAKER)
.setSpeciesPools(
[ Species.CATERPIE, Species.WEEDLE, Species.RATTATA, Species.SENTRET, Species.POOCHYENA, Species.ZIGZAGOON, Species.WURMPLE, Species.BIDOOF, Species.PATRAT, Species.LILLIPUP ]

View File

@ -17,7 +17,7 @@ import { initMoveAnim, loadMoveAnimAssets } from '../data/battle-anims';
import { Status, StatusEffect, getRandomStatus } from '../data/status-effect';
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from '../data/pokemon-evolutions';
import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from '../data/tms';
import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase } from '../phases';
import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchPhase, SwitchSummonPhase, ToggleDoublePositionPhase } from '../phases';
import { BattleStat } from '../data/battle-stat';
import { BattlerTag, BattlerTagLapseType, EncoreTag, HelpingHandTag, HighestStatBoostTag, TypeBoostTag, getBattlerTag } from '../data/battler-tags';
import { BattlerTagType } from "../data/enums/battler-tag-type";
@ -1659,6 +1659,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.gameData.gameStats.highestDamage = damage.value;
}
source.turnData.damageDealt += damage.value;
source.turnData.currDamageDealt = damage.value;
this.battleData.hitCount++;
const attackResult = { move: move.id, result: result as DamageResult, damage: damage.value, critical: isCritical, sourceId: source.id };
this.turnData.attacksReceived.unshift(attackResult);
@ -2680,6 +2681,42 @@ export class PlayerPokemon extends Pokemon {
sd.friendship = Math.max((sd.friendship || 0) + starterAmount.value, 0);
}
}
/**
* Handles Revival Blessing when used by player.
* @returns Promise to revive a pokemon.
* @see {@linkcode RevivalBlessingAttr}
*/
revivalBlessing(): Promise<void> {
return new Promise(resolve => {
this.scene.ui.setMode(Mode.PARTY, PartyUiMode.REVIVAL_BLESSING, this.getFieldIndex(), (slotIndex:integer, option: PartyOption) => {
if(slotIndex >= 0 && slotIndex<6) {
const pokemon = this.scene.getParty()[slotIndex];
if(!pokemon || !pokemon.isFainted())
resolve();
pokemon.resetTurnData();
pokemon.resetStatus();
pokemon.heal(Math.min(Math.max(Math.ceil(Math.floor(0.5 * pokemon.getMaxHp())), 1), pokemon.getMaxHp()));
this.scene.queueMessage(`${pokemon.name} was revived!`,0,true);
if(this.scene.currentBattle.double && this.scene.getParty().length > 1) {
const allyPokemon = this.getAlly();
if(slotIndex<=1) {
// Revived ally pokemon
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, pokemon.getFieldIndex(), slotIndex, false, false, true));
this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true));
} else if(allyPokemon.isFainted()) {
// Revived party pokemon, and ally pokemon is fainted
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, allyPokemon.getFieldIndex(), slotIndex, false, false, true));
this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true));
}
}
}
this.scene.ui.setMode(Mode.MESSAGE).then(() => resolve());
}, PartyUiHandler.FilterFainted)
})
}
getPossibleEvolution(evolution: SpeciesFormEvolution): Promise<Pokemon> {
return new Promise(resolve => {
@ -3381,6 +3418,7 @@ export class PokemonTurnData {
public hitCount: integer;
public hitsLeft: integer;
public damageDealt: integer = 0;
public currDamageDealt: integer = 0;
public damageTaken: integer = 0;
public attacksReceived: AttackMoveResult[] = [];
}

View File

@ -20,6 +20,7 @@ import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const deConfig = {
ability: ability,
@ -46,4 +47,5 @@ export const deConfig = {
weather: weather,
battleMessageUiHandler: battleMessageUiHandler,
berry: berry,
}
voucher: voucher,
}

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "Polizist",
"parasol_lady": "Schirmdame",
"pilot": "Pilot",
"pokefan": "Pokéfan",
"pokefan_family": "Pokéfan-Pärchen",
"pokéfan": "Pokéfan",
"pokéfan_female": "Pokéfan",
"pokéfan_family": "Pokéfan-Pärchen",
"preschooler": "Vorschüler",
"preschooler_female": "Vorschülerin",
"preschoolers": "Vorschüler",
@ -77,6 +78,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"psychic_female": "Seherin",
"psychics": "Seher",
"pokémon_ranger": "Pokémon-Ranger",
"pokémon_ranger_female": "Pokémon-Ranger",
"pokémon_rangers": "Pokémon-Ranger",
"ranger": "Ranger",
"restaurant_staff": "Restaurant Angestellte",

11
src/locales/de/voucher.ts Normal file
View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "Vouchers",
"eggVoucher": "Egg Voucher",
"eggVoucherPlus": "Egg Voucher Plus",
"eggVoucherPremium": "Egg Voucher Premium",
"eggVoucherGold": "Egg Voucher Gold",
"locked": "Locked",
"defeatTrainer": "Defeat {{trainerName}}"
} as const;

View File

@ -20,6 +20,7 @@ import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const enConfig = {
ability: ability,
@ -46,4 +47,5 @@ export const enConfig = {
weather: weather,
battleMessageUiHandler: battleMessageUiHandler,
berry: berry,
}
voucher: voucher,
}

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "Officer",
"parasol_lady": "Parasol Lady",
"pilot": "Pilot",
"pokefan": "Poké Fan",
"pokefan_family": "Poké Fan Family",
"pokéfan": "Poké Fan",
"pokéfan_female": "Poké Fan",
"pokéfan_family": "Poké Fan Family",
"preschooler": "Preschooler",
"preschooler_female": "Preschooler",
"preschoolers": "Preschoolers",
@ -77,6 +78,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"psychic_female": "Psychic",
"psychics": "Psychics",
"pokémon_ranger": "Pokémon Ranger",
"pokémon_ranger_female": "Pokémon Ranger",
"pokémon_rangers": "Pokémon Ranger",
"ranger": "Ranger",
"restaurant_staff": "Restaurant Staff",

11
src/locales/en/voucher.ts Normal file
View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "Vouchers",
"eggVoucher": "Egg Voucher",
"eggVoucherPlus": "Egg Voucher Plus",
"eggVoucherPremium": "Egg Voucher Premium",
"eggVoucherGold": "Egg Voucher Gold",
"locked": "Locked",
"defeatTrainer": "Defeat {{trainerName}}"
} as const;

View File

@ -20,6 +20,7 @@ import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const esConfig = {
ability: ability,
@ -46,4 +47,5 @@ export const esConfig = {
weather: weather,
battleMessageUiHandler: battleMessageUiHandler,
berry: berry,
}
voucher: voucher,
}

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "Officer",
"parasol_lady": "Parasol Lady",
"pilot": "Pilot",
"pokefan": "Poké Fan",
"pokefan_family": "Poké Fan Family",
"pokéfan": "Poké Fan",
"pokéfan_female": "Poké Fan",
"pokéfan_family": "Poké Fan Family",
"preschooler": "Preschooler",
"preschooler_female": "Preschooler",
"preschoolers": "Preschoolers",

11
src/locales/es/voucher.ts Normal file
View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "Vouchers",
"eggVoucher": "Egg Voucher",
"eggVoucherPlus": "Egg Voucher Plus",
"eggVoucherPremium": "Egg Voucher Premium",
"eggVoucherGold": "Egg Voucher Gold",
"locked": "Locked",
"defeatTrainer": "Defeat {{trainerName}}"
} as const;

View File

@ -20,6 +20,7 @@ import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const frConfig = {
ability: ability,
@ -46,4 +47,5 @@ export const frConfig = {
weather: weather,
battleMessageUiHandler: battleMessageUiHandler,
berry: berry,
}
voucher: voucher,
}

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "Policier",
"parasol_lady": "Sœur Parasol",
"pilot": "Pilote",
"pokefan": "Poké Fan",
"pokefan_family": "Couple de Pokéfans",
"pokéfan": "Poké Fan",
"pokéfan_female": "Poké Fan",
"pokéfan_family": "Couple de Pokéfans",
"preschooler": "Petit",
"preschooler_female": "Petite",
"preschoolers": "Petits",
@ -77,6 +78,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"psychic_female": "Kinésiste",
"psychics": "Kinésistes",
"pokémon_ranger": "Pokémon Ranger",
"pokémon_ranger_female": "Pokémon Ranger",
"pokémon_rangers": "Pokémon Rangers",
"ranger": "Ranger",
"restaurant_staff": "Serveurs",

11
src/locales/fr/voucher.ts Normal file
View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "Coupons",
"eggVoucher": "Coupon Œuf",
"eggVoucherPlus": "Coupon Œuf +",
"eggVoucherPremium": "Coupon Œuf Premium",
"eggVoucherGold": "Coupon Œuf Or",
"locked": "Verrouillé",
"defeatTrainer": "Vaincre {{trainerName}}"
} as const;

View File

@ -20,6 +20,7 @@ import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const itConfig = {
ability: ability,
@ -46,4 +47,5 @@ export const itConfig = {
weather: weather,
battleMessageUiHandler: battleMessageUiHandler,
berry: berry,
}
voucher: voucher,
}

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "Officer",
"parasol_lady": "Parasol Lady",
"pilot": "Pilot",
"pokefan": "Poké Fan",
"pokefan_family": "Poké Fan Family",
"pokéfan": "Poké Fan",
"pokéfan_female": "Poké Fan",
"pokéfan_family": "Poké Fan Family",
"preschooler": "Preschooler",
"preschooler_female": "Preschooler",
"preschoolers": "Preschoolers",
@ -77,6 +78,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"psychic_female": "Psychic",
"psychics": "Psychics",
"pokémon_ranger": "Pokémon Ranger",
"pokémon_ranger_female": "Pokémon Ranger",
"pokémon_rangers": "Pokémon Ranger",
"ranger": "Ranger",
"restaurant_staff": "Restaurant Staff",

11
src/locales/it/voucher.ts Normal file
View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "Vouchers",
"eggVoucher": "Egg Voucher",
"eggVoucherPlus": "Egg Voucher Plus",
"eggVoucherPremium": "Egg Voucher Premium",
"eggVoucherGold": "Egg Voucher Gold",
"locked": "Locked",
"defeatTrainer": "Defeat {{trainerName}}"
} as const;

View File

@ -19,6 +19,7 @@ import { titles, trainerClasses, trainerNames } from "./trainers";
import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const ptBrConfig = {
@ -45,4 +46,5 @@ export const ptBrConfig = {
weather: weather,
modifierType: modifierType,
berry: berry,
voucher: voucher,
}

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "Policial",
"parasol_lady": "Moça de Sombrinha",
"pilot": "Piloto",
"poké_fan": "Pokefã",
"poké_fan_family": "Família Pokefã",
"pokéfan": "Pokefã",
"pokéfan_female": "Pokéfã",
"pokéfan_family": "Família Pokefã",
"preschooler": "Menino do Prezinho",
"preschooler_female": "Menina do Prezinho",
"preschoolers": "Alunos do Prezinho",
@ -77,6 +78,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"psychic_female": "Médium",
"psychics": "Médiuns",
"pokémon_ranger": "Guarda Pokémon",
"pokémon_ranger_female": "Guarda Pokémon",
"pokémon_rangers": "Guardas Pokémon",
"ranger": "Guarda",
"restaurant_staff": "Equipe do Restaurante",

View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "Vouchers",
"eggVoucher": "Egg Voucher",
"eggVoucherPlus": "Egg Voucher Plus",
"eggVoucherPremium": "Egg Voucher Premium",
"eggVoucherGold": "Egg Voucher Gold",
"locked": "Locked",
"defeatTrainer": "Defeat {{trainerName}}"
} as const;

View File

@ -20,6 +20,7 @@ import { tutorial } from "./tutorial";
import { weather } from "./weather";
import { battleMessageUiHandler } from "./battle-message-ui-handler";
import { berry } from "./berry";
import { voucher } from "./voucher";
export const zhCnConfig = {
@ -47,4 +48,5 @@ export const zhCnConfig = {
weather: weather,
battleMessageUiHandler: battleMessageUiHandler,
berry: berry,
}
voucher: voucher,
}

21
src/locales/zh_CN/egg.ts Normal file
View File

@ -0,0 +1,21 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const egg: SimpleTranslationEntries = {
"egg": "蛋",
"greatTier": "稀有",
"ultraTier": "史诗",
"masterTier": "传说",
"defaultTier": "普通",
"hatchWavesMessageSoon": "里面传来声音!似乎快要孵化了!",
"hatchWavesMessageClose": "有时好像会动一下。就快孵化了吧?",
"hatchWavesMessageNotClose": "会孵化出什么呢?看来还需要很长时间才能孵化。",
"hatchWavesMessageLongTime": "这个蛋需要很长时间才能孵化。",
"gachaTypeLegendary": "传说概率上升",
"gachaTypeMove": "稀有概率上升",
"gachaTypeShiny": "闪光概率上升",
"selectMachine": "选择一个机器。",
"notEnoughVouchers": "你没有足够的兑换券!",
"tooManyEggs": "你的蛋太多啦!",
"pull": "抽",
"pulls": "连抽"
} as const;

View File

@ -68,8 +68,9 @@ export const trainerClasses: SimpleTranslationEntries = {
"officer": "警察",
"parasol_lady": "阳伞姐姐",
"pilot": "飞行员",
"poké_fan": "发烧友俱乐部",
"poké_fan_family": "同好夫妇",
"pokéfan": "发烧友俱乐部",
"pokéfan_female": "发烧友俱乐部",
"pokéfan_family": "同好夫妇",
"preschooler": "幼儿园小朋友",
"preschooler_female": "幼儿园小朋友",
"preschoolers": "幼儿园小朋友组合",
@ -77,6 +78,7 @@ export const trainerClasses: SimpleTranslationEntries = {
"psychic_female": "超能力者",
"psychics": "超能力者组合",
"pokémon_ranger": "宝可梦巡护员",
"pokémon_ranger_female": "宝可梦巡护员",
"pokémon_rangers": "宝可梦巡护员组合",
"ranger": "巡护员",
"restaurant_staff": "服务生组合",

View File

@ -0,0 +1,11 @@
import { SimpleTranslationEntries } from "#app/plugins/i18n";
export const voucher: SimpleTranslationEntries = {
"vouchers": "兑换券",
"eggVoucher": "初级扭蛋券",
"eggVoucherPlus": "中级扭蛋券",
"eggVoucherPremium": "高级扭蛋券",
"eggVoucherGold": "黄金扭蛋券",
"locked": "锁定",
"defeatTrainer": "你打败了{{trainerName}}"
} as const;

View File

@ -2,7 +2,7 @@ import BattleScene, { AnySound, bypassLogin, startingWave } from "./battle-scene
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon";
import * as Utils from './utils';
import { Moves } from "./data/enums/moves";
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, DelayedAttackAttr, RechargeAttr, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, BypassRedirectAttr, FixedDamageAttr, PostVictoryStatChangeAttr, OneHitKOAccuracyAttr, ForceSwitchOutAttr, VariableTargetAttr, SacrificialAttr } from "./data/move";
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, DelayedAttackAttr, RechargeAttr, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, BypassRedirectAttr, FixedDamageAttr, PostVictoryStatChangeAttr, OneHitKOAccuracyAttr, ForceSwitchOutAttr, VariableTargetAttr, SacrificialAttr, IncrementMovePriorityAttr } from "./data/move";
import { Mode } from './ui/ui';
import { Command } from "./ui/command-ui-handler";
import { Stat } from "./data/pokemon-stat";
@ -2012,6 +2012,9 @@ export class TurnStartPhase extends FieldPhase {
const aPriority = new Utils.IntegerHolder(aMove.priority);
const bPriority = new Utils.IntegerHolder(bMove.priority);
applyMoveAttrs(IncrementMovePriorityAttr,this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a),null,aMove,aPriority);
applyMoveAttrs(IncrementMovePriorityAttr,this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b),null,bMove,bPriority);
applyAbAttrs(IncrementMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a), null, aMove, aPriority);
applyAbAttrs(IncrementMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b), null, bMove, bPriority);
@ -3841,6 +3844,10 @@ export class SwitchPhase extends BattlePhase {
if (this.isModal && !this.scene.getParty().filter(p => !p.isFainted() && !p.isActive(true)).length)
return super.end();
// Check if there is any space still in field
if (this.isModal && this.scene.getPlayerField().filter(p => !p.isFainted() && p.isActive(true)).length >= this.scene.currentBattle.getBattlerCount())
return super.end();
// Override field index to 0 in case of double battle where 2/3 remaining party members fainted at once
const fieldIndex = this.scene.currentBattle.getBattlerCount() === 1 || this.scene.getParty().filter(p => !p.isFainted()).length > 1 ? this.fieldIndex : 0;

View File

@ -153,6 +153,7 @@ declare module 'i18next' {
modifierType: ModifierTypeTranslationEntries;
battleMessageUiHandler: SimpleTranslationEntries;
berry: BerryTranslationEntries;
voucher: SimpleTranslationEntries;
};
}
}

View File

@ -2,6 +2,7 @@ import BattleScene from "../battle-scene";
import { TrainerType } from "../data/enums/trainer-type";
import { ModifierTier } from "../modifier/modifier-tier";
import { Achv, AchvTier, achvs } from "./achv";
import i18next from '../plugins/i18n';
export enum VoucherType {
REGULAR,
@ -52,13 +53,13 @@ export class Voucher {
export function getVoucherTypeName(voucherType: VoucherType): string {
switch (voucherType) {
case VoucherType.REGULAR:
return 'Egg Voucher';
return i18next.t("voucher:eggVoucher");
case VoucherType.PLUS:
return 'Egg Voucher Plus';
return i18next.t("voucher:eggVoucherPlus");
case VoucherType.PREMIUM:
return 'Egg Voucher Premium';
return i18next.t("voucher:eggVoucherPremium");
case VoucherType.GOLDEN:
return 'Egg Voucher Gold';
return i18next.t("voucher:eggVoucherGold");
}
}
@ -75,9 +76,8 @@ export function getVoucherTypeIcon(voucherType: VoucherType): string {
}
}
export interface Vouchers {
[key: string]: Voucher
[key: string]: Voucher;
}
export const vouchers: Vouchers = {};
@ -87,6 +87,8 @@ const voucherAchvs: Achv[] = [ achvs.CLASSIC_VICTORY ];
{
(function() {
import('../data/trainer-config').then(tc => {
const trainerConfigs = tc.trainerConfigs;
for (let achv of voucherAchvs) {
const voucherType = achv.score >= 150
? VoucherType.GOLDEN
@ -98,7 +100,6 @@ const voucherAchvs: Achv[] = [ achvs.CLASSIC_VICTORY ];
vouchers[achv.id] = new Voucher(voucherType, achv.description);
}
const trainerConfigs = tc.trainerConfigs;
const bossTrainerTypes = Object.keys(trainerConfigs)
.filter(tt => trainerConfigs[tt].isBoss && trainerConfigs[tt].getDerivedType() !== TrainerType.RIVAL);
@ -107,12 +108,17 @@ const voucherAchvs: Achv[] = [ achvs.CLASSIC_VICTORY ];
? VoucherType.PLUS
: VoucherType.PREMIUM;
const key = TrainerType[trainerType];
vouchers[key] = new Voucher(voucherType, `Defeat ${trainerConfigs[trainerType].name}`);
const trainerName = trainerConfigs[trainerType].name;
vouchers[key] = new Voucher(
voucherType,
i18next.t("voucher:defeatTrainer", { trainerName })
);
}
const voucherKeys = Object.keys(vouchers);
for (let k of voucherKeys)
for (let k of voucherKeys) {
vouchers[k].id = k;
}
});
})();
}
}

View File

@ -30,13 +30,34 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container {
private pageCount: integer;
private page: integer;
private category: ScoreboardCategory;
private _isUpdating: boolean;
constructor(scene: BattleScene, x: number, y: number) {
super(scene, x, y);
this._isUpdating = false;
this.setup();
}
/**
* Sets the updating state and updates button states accordingly.
* If value is true (updating), disables the buttons; if false, enables the buttons.
* @param {boolean} value - The new updating state.
*/
set isUpdating(value) {
this._isUpdating = value;
this.setButtonsState(!value);
}
/**
* Gets the current updating state.
* @returns {boolean} - The current updating state.
*/
get isUpdating() {
return this._isUpdating;
}
setup() {
const titleWindow = addWindow(this.scene, 0, 0, 114, 18, false, false, null, null, WindowVariant.THIN);
this.add(titleWindow);
@ -140,7 +161,24 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container {
});
}
/**
* Updates the scoreboard rankings based on the selected category and page.
*
* If the update process is already ongoing, the method exits early. Otherwise, it begins the update process by clearing
* the current rankings and showing a loading label. If the category changes, the page is reset to 1.
*
* The method fetches the total page count if necessary, followed by fetching the rankings for the specified category
* and page. It updates the UI with the fetched rankings or shows an appropriate message if no rankings are found.
*
* @param {ScoreboardCategory} [category=this.category] - The category to fetch rankings for. Defaults to the current category.
* @param {number} [page=this.page] - The page number to fetch. Defaults to the current page.
*/
update(category: ScoreboardCategory = this.category, page: integer = this.page) {
if (this.isUpdating) {
return;
}
this.isUpdating = true;
this.rankingsContainer.removeAll(true);
this.loadingLabel.setText(i18next.t('menu:loading'));
@ -150,7 +188,7 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container {
this.page = page = 1;
Utils.executeIf(category !== this.category || this.pageCount === undefined,
() => Utils.apiFetch(`daily/rankingpagecount?category=${category}`).then(response => response.json()).then(count => this.pageCount = count)
() => Utils.apiFetch(`daily/rankingpagecount?category=${category}`).then(response => response.json()).then(count => this.pageCount = count)
).then(() => {
Utils.apiFetch(`daily/rankings?category=${category}&page=${page}`)
.then(response => response.json())
@ -158,16 +196,40 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container {
this.page = page;
this.category = category;
this.titleLabel.setText(`${i18next.t(`menu:${ScoreboardCategory[category].toLowerCase()}Rankings`)}`);
this.prevPageButton.setAlpha(page > 1 ? 1 : 0.5);
this.nextPageButton.setAlpha(page < this.pageCount ? 1 : 0.5);
this.pageNumberLabel.setText(page.toString());
if (jsonResponse) {
this.loadingLabel.setVisible(false);
this.updateRankings(jsonResponse);
} else
this.loadingLabel.setText(i18next.t('menu:noRankings'));
}).finally(() => {
this.isUpdating = false;
});
}).catch(err => { console.error("Failed to load daily rankings:\n", err) });
}).catch(err => {
console.error("Failed to load daily rankings:\n", err)
})
}
/**
* Sets the state of the navigation buttons.
* @param {boolean} [enabled=true] - Whether the buttons should be enabled or disabled.
*/
setButtonsState(enabled: boolean = true) {
const buttons = [
{ button: this.prevPageButton, alphaValue: enabled ? (this.page > 1 ? 1 : 0.5) : 0.5 },
{ button: this.nextPageButton, alphaValue: enabled ? (this.page < this.pageCount ? 1 : 0.5) : 0.5 },
{ button: this.nextCategoryButton, alphaValue: enabled ? 1 : 0.5 },
{ button: this.prevCategoryButton, alphaValue: enabled ? 1 : 0.5 }
];
buttons.forEach(({ button, alphaValue }) => {
if (enabled) {
button.setInteractive();
} else {
button.disableInteractive();
}
button.setAlpha(alphaValue);
});
}
}

View File

@ -24,6 +24,7 @@ export enum PartyUiMode {
SWITCH,
FAINT_SWITCH,
POST_BATTLE_SWITCH,
REVIVAL_BLESSING,
MODIFIER,
MOVE_MODIFIER,
TM_MODIFIER,
@ -37,6 +38,7 @@ export enum PartyOption {
CANCEL = -1,
SEND_OUT,
PASS_BATON,
REVIVE,
APPLY,
TEACH,
TRANSFER,
@ -103,6 +105,12 @@ export default class PartyUiHandler extends MessageUiHandler {
return null;
};
public static FilterFainted = (pokemon: PlayerPokemon) => {
if(!pokemon.isFainted())
return `${pokemon.name} still has energy\nto battle!`;
return null;
}
private static FilterAllMoves = (_pokemonMove: PokemonMove) => null;
public static FilterItemMaxStacks = (pokemon: PlayerPokemon, modifier: PokemonHeldItemModifier) => {
@ -361,7 +369,7 @@ export default class PartyUiHandler extends MessageUiHandler {
if (this.cursor < 6) {
this.showOptions();
ui.playSelect();
} else if (this.partyUiMode === PartyUiMode.FAINT_SWITCH)
} else if (this.partyUiMode === PartyUiMode.FAINT_SWITCH || this.partyUiMode === PartyUiMode.REVIVAL_BLESSING)
ui.playError();
else
return this.processInput(Button.CANCEL);
@ -370,7 +378,7 @@ export default class PartyUiHandler extends MessageUiHandler {
if ((this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER || this.partyUiMode === PartyUiMode.SPLICE) && this.transferMode) {
this.clearTransfer();
ui.playSelect();
} else if (this.partyUiMode !== PartyUiMode.FAINT_SWITCH) {
} else if (this.partyUiMode !== PartyUiMode.FAINT_SWITCH && this.partyUiMode !== PartyUiMode.REVIVAL_BLESSING) {
if (this.selectCallback) {
const selectCallback = this.selectCallback;
this.selectCallback = null;
@ -580,6 +588,9 @@ export default class PartyUiHandler extends MessageUiHandler {
this.options.push(PartyOption.FORM_CHANGE_ITEM + i);
}
break;
case PartyUiMode.REVIVAL_BLESSING:
this.options.push(PartyOption.REVIVE);
break;
case PartyUiMode.MODIFIER:
this.options.push(PartyOption.APPLY);
break;

View File

@ -42,48 +42,65 @@ export interface Starter {
pokerus: boolean;
}
interface LanguageSetting {
starterInfoTextSize: string,
instructionTextSize: string,
starterInfoXPos?: integer,
starterInfoYOffset?: integer
}
const languageSettings: { [key: string]: LanguageSetting } = {
"en":{
starterInfoTextSize: '56px',
instructionTextSize: '42px',
},
"de":{
starterInfoTextSize: '56px',
instructionTextSize: '35px',
},
"es":{
starterInfoTextSize: '56px',
instructionTextSize: '35px',
},
"it":{
starterInfoTextSize: '56px',
instructionTextSize: '38px',
},
"fr":{
starterInfoTextSize: '54px',
instructionTextSize: '42px',
},
"zh_CN":{
starterInfoTextSize: '40px',
instructionTextSize: '42px',
starterInfoYOffset: 2
},
"pt_BR":{
starterInfoTextSize: '47px',
instructionTextSize: '38px',
starterInfoXPos: 32,
},
}
const starterCandyCosts: { passive: integer, costReduction: [integer, integer] }[] = [
{ passive: 50, costReduction: [30, 75] }, // 1
{ passive: 45, costReduction: [25, 60] }, // 2
{ passive: 30, costReduction: [20, 50] }, // 3
{ passive: 25, costReduction: [15, 40] }, // 4
{ passive: 20, costReduction: [12, 35] }, // 5
{ passive: 15, costReduction: [10, 30] }, // 6
{ passive: 10, costReduction: [8, 20] }, // 7
{ passive: 10, costReduction: [5, 15] }, // 8
{ passive: 10, costReduction: [3, 10] }, // 9
{ passive: 10, costReduction: [3, 10] }, // 10
]
function getPassiveCandyCount(baseValue: integer): integer {
switch (baseValue) {
case 1:
return 50;
case 2:
return 45;
case 3:
return 40;
case 4:
return 30;
case 5:
return 25;
case 6:
return 20;
case 7:
return 15;
default:
return 10;
}
return starterCandyCosts[baseValue - 1].passive;
}
function getValueReductionCandyCounts(baseValue: integer): [integer, integer] {
switch (baseValue) {
case 1:
return [ 30, 75];
case 2:
return [ 25, 60 ];
case 3:
return [ 20, 50 ];
case 4:
return [ 15, 40 ];
case 5:
return [ 12, 35 ];
case 6:
return [ 10, 30 ];
case 7:
return [ 8, 20 ];
case 8:
return [ 5, 15 ];
default:
return [ 3, 10 ];
}
return starterCandyCosts[baseValue - 1].costReduction;
}
const gens = [
@ -199,6 +216,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
setup() {
const ui = this.getUi();
const currentLanguage = i18next.language;
const textSettings = languageSettings[currentLanguage];
this.starterSelectContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6);
this.starterSelectContainer.setVisible(false);
@ -255,57 +274,38 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.pokemonUncaughtText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonUncaughtText);
let starterInfoXPosition = 31; // Only text
// The position should be set per language
const currentLanguage = i18next.language;
switch (currentLanguage) {
case 'pt_BR':
starterInfoXPosition = 32;
break;
default:
starterInfoXPosition = 31;
break
}
let starterInfoXPos = textSettings?.starterInfoXPos || 31;
let starterInfoYOffset = textSettings?.starterInfoYOffset || 0;
let starterInfoTextSize = '56px'; // Labels and text
// The font size should be set per language
// currentLanguage is already defined
switch (currentLanguage) {
case 'fr':
starterInfoTextSize = '54px';
break;
case 'pt_BR':
starterInfoTextSize = '47px';
break;
default:
starterInfoTextSize = '56px';
break
}
let starterInfoTextSize = textSettings.starterInfoTextSize;
this.pokemonAbilityLabelText = addTextObject(this.scene, 6, 127, i18next.t("starterSelectUiHandler:ability"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonAbilityLabelText = addTextObject(this.scene, 6, 127 + starterInfoYOffset, i18next.t("starterSelectUiHandler:ability"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonAbilityLabelText.setOrigin(0, 0);
this.pokemonAbilityLabelText.setVisible(false);
this.starterSelectContainer.add(this.pokemonAbilityLabelText);
this.pokemonAbilityText = addTextObject(this.scene, starterInfoXPosition, 127, '', TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonAbilityText = addTextObject(this.scene, starterInfoXPos, 127 + starterInfoYOffset, '', TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonAbilityText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonAbilityText);
this.pokemonPassiveLabelText = addTextObject(this.scene, 6, 136, i18next.t("starterSelectUiHandler:passive"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonPassiveLabelText = addTextObject(this.scene, 6, 136 + starterInfoYOffset, i18next.t("starterSelectUiHandler:passive"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonPassiveLabelText.setOrigin(0, 0);
this.pokemonPassiveLabelText.setVisible(false);
this.starterSelectContainer.add(this.pokemonPassiveLabelText);
this.pokemonPassiveText = addTextObject(this.scene, starterInfoXPosition, 136, '', TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonPassiveText = addTextObject(this.scene, starterInfoXPos, 136 + starterInfoYOffset, '', TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonPassiveText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonPassiveText);
this.pokemonNatureLabelText = addTextObject(this.scene, 6, 145, i18next.t("starterSelectUiHandler:nature"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonNatureLabelText = addTextObject(this.scene, 6, 145 + starterInfoYOffset, i18next.t("starterSelectUiHandler:nature"), TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonNatureLabelText.setOrigin(0, 0);
this.pokemonNatureLabelText.setVisible(false);
this.starterSelectContainer.add(this.pokemonNatureLabelText);
this.pokemonNatureText = addBBCodeTextObject(this.scene, starterInfoXPosition, 145, '', TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonNatureText = addBBCodeTextObject(this.scene, starterInfoXPos, 145 + starterInfoYOffset, '', TextStyle.SUMMARY_ALT, { fontSize: starterInfoTextSize });
this.pokemonNatureText.setOrigin(0, 0);
this.starterSelectContainer.add(this.pokemonNatureText);
@ -589,36 +589,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.starterSelectContainer.add(this.pokemonEggMovesContainer);
let instructionTextSize = '42px';
// The font size should be set per language
// currentLanguage is already defined in the previous code block
switch (currentLanguage) {
case 'de':
instructionTextSize = '35px';
break;
case 'en':
instructionTextSize = '42px';
break;
case 'es':
instructionTextSize = '35px';
break;
case 'fr':
instructionTextSize = '42px';
break;
case 'it':
instructionTextSize = '38px';
break;
case 'pt_BR':
instructionTextSize = '38px';
break;
case 'zh_CN':
instructionTextSize = '42px';
break;
}
let instructionTextSize = textSettings.instructionTextSize;
this.instructionsText = addTextObject(this.scene, 4, 156, '', TextStyle.PARTY, { fontSize: instructionTextSize });
this.starterSelectContainer.add(this.instructionsText);

View File

@ -4,6 +4,7 @@ import { ModifierTier } from "../modifier/modifier-tier";
import { EggTier } from "../data/enums/egg-type";
import BattleScene from "../battle-scene";
import { UiTheme } from "../enums/ui-theme";
import i18next from "i18next";
export enum TextStyle {
MESSAGE,
@ -28,6 +29,25 @@ export enum TextStyle {
MOVE_INFO_CONTENT
};
interface LanguageSetting {
summaryFontSize?: string,
battleInfoFontSize?: string,
partyFontSize?: string,
tooltipContentFontSize?: string,
moveInfoFontSize?: string,
textScale?: number
}
const languageSettings: { [key: string]: LanguageSetting } = {
"en":{},
"de":{},
"es":{},
"it":{},
"fr":{},
"zh_CN":{},
"pt_BR":{},
}
export function addTextObject(scene: Phaser.Scene, x: number, y: number, content: string, style: TextStyle, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): Phaser.GameObjects.Text {
const [ styleOptions, shadowColor, shadowSize ] = getTextStyleOptions(style, (scene as BattleScene).uiTheme, extraStyleOptions);
@ -64,6 +84,7 @@ export function addTextInputObject(scene: Phaser.Scene, x: number, y: number, wi
}
function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): [ Phaser.Types.GameObjects.Text.TextStyle | InputText.IConfig, string, integer ] {
const lang = i18next.language;
let shadowColor: string;
let shadowSize = 6;
@ -90,25 +111,25 @@ function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptio
case TextStyle.MESSAGE:
case TextStyle.SETTINGS_LABEL:
case TextStyle.SETTINGS_SELECTED:
styleOptions.fontSize = '96px';
styleOptions.fontSize = languageSettings[lang]?.summaryFontSize || '96px';
break;
case TextStyle.BATTLE_INFO:
case TextStyle.MONEY:
case TextStyle.TOOLTIP_TITLE:
styleOptions.fontSize = '72px';
styleOptions.fontSize = languageSettings[lang]?.battleInfoFontSize || '72px';
shadowSize = 4.5;
break;
case TextStyle.PARTY:
case TextStyle.PARTY_RED:
styleOptions.fontSize = languageSettings[lang]?.partyFontSize || '66px';
styleOptions.fontFamily = 'pkmnems';
styleOptions.fontSize = '66px';
break;
case TextStyle.TOOLTIP_CONTENT:
styleOptions.fontSize = '64px';
styleOptions.fontSize = languageSettings[lang]?.tooltipContentFontSize || '64px';
shadowSize = 4;
break;
case TextStyle.MOVE_INFO_CONTENT:
styleOptions.fontSize = '56px';
styleOptions.fontSize = languageSettings[lang]?.moveInfoFontSize || '56px';
shadowSize = 3;
break;
}

View File

@ -5,6 +5,7 @@ import { TextStyle, addTextObject } from "./text";
import { Mode } from "./ui";
import { addWindow } from "./ui-theme";
import {Button} from "../enums/buttons";
import i18next from '../plugins/i18n';
const itemRows = 4;
const itemCols = 17;
@ -40,7 +41,7 @@ export default class VouchersUiHandler extends MessageUiHandler {
const headerBg = addWindow(this.scene, 0, 0, (this.scene.game.canvas.width / 6) - 2, 24);
headerBg.setOrigin(0, 0);
const headerText = addTextObject(this.scene, 0, 0, 'Vouchers', TextStyle.SETTINGS_LABEL);
const headerText = addTextObject(this.scene, 0, 0, i18next.t("voucher:vouchers"), TextStyle.SETTINGS_LABEL);
headerText.setOrigin(0, 0);
headerText.setPositionRelative(headerBg, 8, 4);
@ -127,7 +128,7 @@ export default class VouchersUiHandler extends MessageUiHandler {
this.titleText.setText(getVoucherTypeName(voucher.voucherType));
this.showText(voucher.description);
this.unlockText.setText(unlocked ? new Date(voucherUnlocks[voucher.id]).toLocaleDateString() : 'Locked');
this.unlockText.setText(unlocked ? new Date(voucherUnlocks[voucher.id]).toLocaleDateString() : i18next.t("voucher:locked"));
}
processInput(button: Button): boolean {
@ -246,4 +247,4 @@ export default class VouchersUiHandler extends MessageUiHandler {
this.cursorObj.destroy();
this.cursorObj = null;
}
}
}