mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-03 23:12:20 +02:00
Merge branch 'beta' into hebrew-pr
This commit is contained in:
commit
3d03da1051
Binary file not shown.
Before Width: | Height: | Size: 441 B After Width: | Height: | Size: 2.2 KiB |
440
public/images/types_ca-ES.json
Normal file
440
public/images/types_ca-ES.json
Normal file
@ -0,0 +1,440 @@
|
|||||||
|
{
|
||||||
|
"textures": [
|
||||||
|
{
|
||||||
|
"image": "types_ca-ES.png",
|
||||||
|
"format": "RGBA8888",
|
||||||
|
"size": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 280
|
||||||
|
},
|
||||||
|
"scale": 1,
|
||||||
|
"frames": [
|
||||||
|
{
|
||||||
|
"filename": "unknown",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "bug",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 14,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "dark",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 28,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "dragon",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 42,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "electric",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 56,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "fairy",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 70,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "fighting",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 84,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "fire",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 98,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "flying",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 112,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "ghost",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 126,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "grass",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 140,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "ground",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 154,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "ice",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 168,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "normal",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 182,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "poison",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 196,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "psychic",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 210,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "rock",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 224,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "steel",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 238,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "water",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 252,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename": "stellar",
|
||||||
|
"rotated": false,
|
||||||
|
"trimmed": false,
|
||||||
|
"sourceSize": {
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"spriteSourceSize": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 0,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
},
|
||||||
|
"frame": {
|
||||||
|
"x": 0,
|
||||||
|
"y": 266,
|
||||||
|
"w": 32,
|
||||||
|
"h": 14
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meta": {
|
||||||
|
"app": "https://www.codeandweb.com/texturepacker",
|
||||||
|
"version": "3.0",
|
||||||
|
"smartupdate": "$TexturePacker:SmartUpdate:f14cf47d9a8f1d40c8e03aa6ba00fff3:6fc4227b57a95d429a1faad4280f7ec8:5961efbfbf4c56b8745347e7a663a32f$"
|
||||||
|
}
|
||||||
|
}
|
BIN
public/images/types_ca-ES.png
Normal file
BIN
public/images/types_ca-ES.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.2 KiB |
@ -1 +1 @@
|
|||||||
Subproject commit 6b3f37cb351552721232f4dabefa17bddb5b9004
|
Subproject commit cd4057af258b659ba2c1ed2778bb2793fa1f6141
|
@ -1064,7 +1064,7 @@ export class PostDefendContactDamageAbAttr extends PostDefendAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
|
||||||
attacker.damageAndUpdate(Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER);
|
attacker.damageAndUpdate(Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), { result: HitResult.INDIRECT });
|
||||||
attacker.turnData.damageTaken += Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio));
|
attacker.turnData.damageTaken += Utils.toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3792,7 +3792,7 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr {
|
|||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
|
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
|
||||||
globalScene.queueMessage(i18next.t("abilityTriggers:postWeatherLapseDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }));
|
globalScene.queueMessage(i18next.t("abilityTriggers:postWeatherLapseDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }));
|
||||||
pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / (16 / this.damageFactor)), HitResult.OTHER);
|
pokemon.damageAndUpdate(Utils.toDmgValue(pokemon.getMaxHp() / (16 / this.damageFactor)), { result: HitResult.INDIRECT });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4084,7 +4084,7 @@ export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr {
|
|||||||
for (const opp of pokemon.getOpponents()) {
|
for (const opp of pokemon.getOpponents()) {
|
||||||
if ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(Abilities.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr) && !opp.switchOutStatus) {
|
if ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(Abilities.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr) && !opp.switchOutStatus) {
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
opp.damageAndUpdate(Utils.toDmgValue(opp.getMaxHp() / 8), HitResult.OTHER);
|
opp.damageAndUpdate(Utils.toDmgValue(opp.getMaxHp() / 8), { result: HitResult.INDIRECT });
|
||||||
globalScene.queueMessage(i18next.t("abilityTriggers:badDreams", { pokemonName: getPokemonNameWithAffix(opp) }));
|
globalScene.queueMessage(i18next.t("abilityTriggers:badDreams", { pokemonName: getPokemonNameWithAffix(opp) }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4567,7 +4567,7 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr {
|
|||||||
|
|
||||||
override applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): void {
|
override applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): void {
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
attacker!.damageAndUpdate(Utils.toDmgValue(attacker!.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER);
|
attacker!.damageAndUpdate(Utils.toDmgValue(attacker!.getMaxHp() * (1 / this.damageRatio)), { result: HitResult.INDIRECT });
|
||||||
attacker!.turnData.damageTaken += Utils.toDmgValue(attacker!.getMaxHp() * (1 / this.damageRatio));
|
attacker!.turnData.damageTaken += Utils.toDmgValue(attacker!.getMaxHp() * (1 / this.damageRatio));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4588,7 +4588,7 @@ export class PostFaintHPDamageAbAttr extends PostFaintAbAttr {
|
|||||||
override applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): void {
|
override applyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): void {
|
||||||
if (move !== undefined && attacker !== undefined && !simulated) { //If the mon didn't die to indirect damage
|
if (move !== undefined && attacker !== undefined && !simulated) { //If the mon didn't die to indirect damage
|
||||||
const damage = pokemon.turnData.attacksReceived[0].damage;
|
const damage = pokemon.turnData.attacksReceived[0].damage;
|
||||||
attacker.damageAndUpdate((damage), HitResult.OTHER);
|
attacker.damageAndUpdate((damage), { result: HitResult.INDIRECT });
|
||||||
attacker.turnData.damageTaken += damage;
|
attacker.turnData.damageTaken += damage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4989,7 +4989,7 @@ export class FormBlockDamageAbAttr extends ReceivedMoveDamageMultiplierAbAttr {
|
|||||||
(args[0] as Utils.NumberHolder).value = this.multiplier;
|
(args[0] as Utils.NumberHolder).value = this.multiplier;
|
||||||
pokemon.removeTag(this.tagType);
|
pokemon.removeTag(this.tagType);
|
||||||
if (this.recoilDamageFunc) {
|
if (this.recoilDamageFunc) {
|
||||||
pokemon.damageAndUpdate(this.recoilDamageFunc(pokemon), HitResult.OTHER, false, false, true, true);
|
pokemon.damageAndUpdate(this.recoilDamageFunc(pokemon), { result: HitResult.INDIRECT, ignoreSegments: true, ignoreFaintPhase: true });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -788,7 +788,7 @@ class SpikesTag extends ArenaTrapTag {
|
|||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
pokemon.damageAndUpdate(damage, HitResult.OTHER);
|
pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT });
|
||||||
if (pokemon.turnData) {
|
if (pokemon.turnData) {
|
||||||
pokemon.turnData.damageTaken += damage;
|
pokemon.turnData.damageTaken += damage;
|
||||||
}
|
}
|
||||||
@ -982,7 +982,7 @@ class StealthRockTag extends ArenaTrapTag {
|
|||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
pokemon.damageAndUpdate(damage, HitResult.OTHER);
|
pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT });
|
||||||
if (pokemon.turnData) {
|
if (pokemon.turnData) {
|
||||||
pokemon.turnData.damageTaken += damage;
|
pokemon.turnData.damageTaken += damage;
|
||||||
}
|
}
|
||||||
@ -1327,7 +1327,7 @@ class FireGrassPledgeTag extends ArenaTag {
|
|||||||
globalScene.unshiftPhase(
|
globalScene.unshiftPhase(
|
||||||
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.MAGMA_STORM),
|
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.MAGMA_STORM),
|
||||||
);
|
);
|
||||||
pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8));
|
pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8), { result: HitResult.INDIRECT });
|
||||||
});
|
});
|
||||||
|
|
||||||
return super.lapse(arena);
|
return super.lapse(arena);
|
||||||
|
@ -1659,7 +1659,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
|||||||
},
|
},
|
||||||
[Biome.GRASS]: {
|
[Biome.GRASS]: {
|
||||||
[BiomePoolTier.COMMON]: [ TrainerType.BREEDER, TrainerType.SCHOOL_KID ],
|
[BiomePoolTier.COMMON]: [ TrainerType.BREEDER, TrainerType.SCHOOL_KID ],
|
||||||
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ],
|
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.POKEFAN ],
|
||||||
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
|
[BiomePoolTier.RARE]: [ TrainerType.BLACK_BELT ],
|
||||||
[BiomePoolTier.SUPER_RARE]: [],
|
[BiomePoolTier.SUPER_RARE]: [],
|
||||||
[BiomePoolTier.ULTRA_RARE]: [],
|
[BiomePoolTier.ULTRA_RARE]: [],
|
||||||
@ -1680,9 +1680,9 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
|||||||
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
||||||
},
|
},
|
||||||
[Biome.METROPOLIS]: {
|
[Biome.METROPOLIS]: {
|
||||||
[BiomePoolTier.COMMON]: [ TrainerType.CLERK, TrainerType.CYCLIST, TrainerType.OFFICER, TrainerType.WAITER, TrainerType.BEAUTY ],
|
[BiomePoolTier.COMMON]: [ TrainerType.BEAUTY, TrainerType.CLERK, TrainerType.CYCLIST, TrainerType.OFFICER, TrainerType.WAITER ],
|
||||||
[BiomePoolTier.UNCOMMON]: [ TrainerType.BREEDER, TrainerType.DEPOT_AGENT, TrainerType.GUITARIST ],
|
[BiomePoolTier.UNCOMMON]: [ TrainerType.BREEDER, TrainerType.DEPOT_AGENT, TrainerType.GUITARIST ],
|
||||||
[BiomePoolTier.RARE]: [ TrainerType.ARTIST ],
|
[BiomePoolTier.RARE]: [ TrainerType.ARTIST, TrainerType.RICH_KID ],
|
||||||
[BiomePoolTier.SUPER_RARE]: [],
|
[BiomePoolTier.SUPER_RARE]: [],
|
||||||
[BiomePoolTier.ULTRA_RARE]: [],
|
[BiomePoolTier.ULTRA_RARE]: [],
|
||||||
[BiomePoolTier.BOSS]: [ TrainerType.WHITNEY, TrainerType.NORMAN, TrainerType.IONO, TrainerType.LARRY ],
|
[BiomePoolTier.BOSS]: [ TrainerType.WHITNEY, TrainerType.NORMAN, TrainerType.IONO, TrainerType.LARRY ],
|
||||||
@ -1702,7 +1702,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
|||||||
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
||||||
},
|
},
|
||||||
[Biome.SEA]: {
|
[Biome.SEA]: {
|
||||||
[BiomePoolTier.COMMON]: [ TrainerType.SWIMMER, TrainerType.SAILOR ],
|
[BiomePoolTier.COMMON]: [ TrainerType.SAILOR, TrainerType.SWIMMER ],
|
||||||
[BiomePoolTier.UNCOMMON]: [],
|
[BiomePoolTier.UNCOMMON]: [],
|
||||||
[BiomePoolTier.RARE]: [],
|
[BiomePoolTier.RARE]: [],
|
||||||
[BiomePoolTier.SUPER_RARE]: [],
|
[BiomePoolTier.SUPER_RARE]: [],
|
||||||
@ -1758,7 +1758,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
|||||||
},
|
},
|
||||||
[Biome.MOUNTAIN]: {
|
[Biome.MOUNTAIN]: {
|
||||||
[BiomePoolTier.COMMON]: [ TrainerType.BACKPACKER, TrainerType.BLACK_BELT, TrainerType.HIKER ],
|
[BiomePoolTier.COMMON]: [ TrainerType.BACKPACKER, TrainerType.BLACK_BELT, TrainerType.HIKER ],
|
||||||
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER ],
|
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.PILOT ],
|
||||||
[BiomePoolTier.RARE]: [],
|
[BiomePoolTier.RARE]: [],
|
||||||
[BiomePoolTier.SUPER_RARE]: [],
|
[BiomePoolTier.SUPER_RARE]: [],
|
||||||
[BiomePoolTier.ULTRA_RARE]: [],
|
[BiomePoolTier.ULTRA_RARE]: [],
|
||||||
@ -1790,7 +1790,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
|||||||
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
||||||
},
|
},
|
||||||
[Biome.DESERT]: {
|
[Biome.DESERT]: {
|
||||||
[BiomePoolTier.COMMON]: [ TrainerType.SCIENTIST, TrainerType.BACKPACKER ],
|
[BiomePoolTier.COMMON]: [ TrainerType.BACKPACKER, TrainerType.SCIENTIST ],
|
||||||
[BiomePoolTier.UNCOMMON]: [],
|
[BiomePoolTier.UNCOMMON]: [],
|
||||||
[BiomePoolTier.RARE]: [],
|
[BiomePoolTier.RARE]: [],
|
||||||
[BiomePoolTier.SUPER_RARE]: [],
|
[BiomePoolTier.SUPER_RARE]: [],
|
||||||
@ -1812,8 +1812,8 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
|||||||
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
||||||
},
|
},
|
||||||
[Biome.MEADOW]: {
|
[Biome.MEADOW]: {
|
||||||
[BiomePoolTier.COMMON]: [ TrainerType.PARASOL_LADY, TrainerType.BEAUTY ],
|
[BiomePoolTier.COMMON]: [ TrainerType.BEAUTY, TrainerType.MUSICIAN, TrainerType.PARASOL_LADY ],
|
||||||
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BREEDER, TrainerType.BAKER ],
|
[BiomePoolTier.UNCOMMON]: [ TrainerType.ACE_TRAINER, TrainerType.BAKER, TrainerType.BREEDER, TrainerType.POKEFAN ],
|
||||||
[BiomePoolTier.RARE]: [],
|
[BiomePoolTier.RARE]: [],
|
||||||
[BiomePoolTier.SUPER_RARE]: [],
|
[BiomePoolTier.SUPER_RARE]: [],
|
||||||
[BiomePoolTier.ULTRA_RARE]: [],
|
[BiomePoolTier.ULTRA_RARE]: [],
|
||||||
@ -1967,7 +1967,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
|||||||
},
|
},
|
||||||
[Biome.SLUM]: {
|
[Biome.SLUM]: {
|
||||||
[BiomePoolTier.COMMON]: [ TrainerType.BIKER, TrainerType.OFFICER, TrainerType.ROUGHNECK ],
|
[BiomePoolTier.COMMON]: [ TrainerType.BIKER, TrainerType.OFFICER, TrainerType.ROUGHNECK ],
|
||||||
[BiomePoolTier.UNCOMMON]: [ TrainerType.BAKER ],
|
[BiomePoolTier.UNCOMMON]: [ TrainerType.BAKER, TrainerType.HOOLIGANS ],
|
||||||
[BiomePoolTier.RARE]: [],
|
[BiomePoolTier.RARE]: [],
|
||||||
[BiomePoolTier.SUPER_RARE]: [],
|
[BiomePoolTier.SUPER_RARE]: [],
|
||||||
[BiomePoolTier.ULTRA_RARE]: [],
|
[BiomePoolTier.ULTRA_RARE]: [],
|
||||||
@ -1988,8 +1988,8 @@ export const biomeTrainerPools: BiomeTrainerPools = {
|
|||||||
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
[BiomePoolTier.BOSS_ULTRA_RARE]: []
|
||||||
},
|
},
|
||||||
[Biome.ISLAND]: {
|
[Biome.ISLAND]: {
|
||||||
[BiomePoolTier.COMMON]: [],
|
[BiomePoolTier.COMMON]: [ TrainerType.RICH_KID ],
|
||||||
[BiomePoolTier.UNCOMMON]: [],
|
[BiomePoolTier.UNCOMMON]: [ TrainerType.RICH ],
|
||||||
[BiomePoolTier.RARE]: [],
|
[BiomePoolTier.RARE]: [],
|
||||||
[BiomePoolTier.SUPER_RARE]: [],
|
[BiomePoolTier.SUPER_RARE]: [],
|
||||||
[BiomePoolTier.ULTRA_RARE]: [],
|
[BiomePoolTier.ULTRA_RARE]: [],
|
||||||
@ -7178,7 +7178,8 @@ export function initBiomes() {
|
|||||||
[ Biome.METROPOLIS, BiomePoolTier.COMMON ],
|
[ Biome.METROPOLIS, BiomePoolTier.COMMON ],
|
||||||
[ Biome.MEADOW, BiomePoolTier.COMMON ],
|
[ Biome.MEADOW, BiomePoolTier.COMMON ],
|
||||||
[ Biome.FAIRY_CAVE, BiomePoolTier.COMMON ]
|
[ Biome.FAIRY_CAVE, BiomePoolTier.COMMON ]
|
||||||
]],
|
]
|
||||||
|
],
|
||||||
[ TrainerType.BIKER, [
|
[ TrainerType.BIKER, [
|
||||||
[ Biome.SLUM, BiomePoolTier.COMMON ]
|
[ Biome.SLUM, BiomePoolTier.COMMON ]
|
||||||
]
|
]
|
||||||
@ -7208,7 +7209,8 @@ export function initBiomes() {
|
|||||||
],
|
],
|
||||||
[ TrainerType.CLERK, [
|
[ TrainerType.CLERK, [
|
||||||
[ Biome.METROPOLIS, BiomePoolTier.COMMON ]
|
[ Biome.METROPOLIS, BiomePoolTier.COMMON ]
|
||||||
]],
|
]
|
||||||
|
],
|
||||||
[ TrainerType.CYCLIST, [
|
[ TrainerType.CYCLIST, [
|
||||||
[ Biome.PLAINS, BiomePoolTier.UNCOMMON ],
|
[ Biome.PLAINS, BiomePoolTier.UNCOMMON ],
|
||||||
[ Biome.METROPOLIS, BiomePoolTier.COMMON ]
|
[ Biome.METROPOLIS, BiomePoolTier.COMMON ]
|
||||||
@ -7217,18 +7219,23 @@ export function initBiomes() {
|
|||||||
[ TrainerType.DANCER, []],
|
[ TrainerType.DANCER, []],
|
||||||
[ TrainerType.DEPOT_AGENT, [
|
[ TrainerType.DEPOT_AGENT, [
|
||||||
[ Biome.METROPOLIS, BiomePoolTier.UNCOMMON ]
|
[ Biome.METROPOLIS, BiomePoolTier.UNCOMMON ]
|
||||||
]],
|
]
|
||||||
|
],
|
||||||
[ TrainerType.DOCTOR, []],
|
[ TrainerType.DOCTOR, []],
|
||||||
|
[ TrainerType.FIREBREATHER, [
|
||||||
|
[ Biome.VOLCANO, BiomePoolTier.COMMON ]
|
||||||
|
]
|
||||||
|
],
|
||||||
[ TrainerType.FISHERMAN, [
|
[ TrainerType.FISHERMAN, [
|
||||||
[ Biome.LAKE, BiomePoolTier.COMMON ],
|
[ Biome.LAKE, BiomePoolTier.COMMON ],
|
||||||
[ Biome.BEACH, BiomePoolTier.COMMON ]
|
[ Biome.BEACH, BiomePoolTier.COMMON ]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ TrainerType.RICH, []],
|
|
||||||
[ TrainerType.GUITARIST, [
|
[ TrainerType.GUITARIST, [
|
||||||
[ Biome.METROPOLIS, BiomePoolTier.UNCOMMON ],
|
[ Biome.METROPOLIS, BiomePoolTier.UNCOMMON ],
|
||||||
[ Biome.POWER_PLANT, BiomePoolTier.COMMON ]
|
[ Biome.POWER_PLANT, BiomePoolTier.COMMON ]
|
||||||
]],
|
]
|
||||||
|
],
|
||||||
[ TrainerType.HARLEQUIN, []],
|
[ TrainerType.HARLEQUIN, []],
|
||||||
[ TrainerType.HIKER, [
|
[ TrainerType.HIKER, [
|
||||||
[ Biome.MOUNTAIN, BiomePoolTier.COMMON ],
|
[ Biome.MOUNTAIN, BiomePoolTier.COMMON ],
|
||||||
@ -7236,13 +7243,24 @@ export function initBiomes() {
|
|||||||
[ Biome.BADLANDS, BiomePoolTier.COMMON ]
|
[ Biome.BADLANDS, BiomePoolTier.COMMON ]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ TrainerType.HOOLIGANS, []],
|
[ TrainerType.HOOLIGANS, [
|
||||||
|
[ Biome.SLUM, BiomePoolTier.UNCOMMON ]
|
||||||
|
]
|
||||||
|
],
|
||||||
[ TrainerType.HOOPSTER, []],
|
[ TrainerType.HOOPSTER, []],
|
||||||
[ TrainerType.INFIELDER, []],
|
[ TrainerType.INFIELDER, []],
|
||||||
[ TrainerType.JANITOR, []],
|
[ TrainerType.JANITOR, []],
|
||||||
[ TrainerType.LINEBACKER, []],
|
[ TrainerType.LINEBACKER, []],
|
||||||
[ TrainerType.MAID, []],
|
[ TrainerType.MAID, []],
|
||||||
[ TrainerType.MUSICIAN, []],
|
[ TrainerType.MUSICIAN, [
|
||||||
|
[ Biome.MEADOW, BiomePoolTier.COMMON ]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[ TrainerType.HEX_MANIAC, [
|
||||||
|
[ Biome.RUINS, BiomePoolTier.UNCOMMON ],
|
||||||
|
[ Biome.GRAVEYARD, BiomePoolTier.UNCOMMON ]
|
||||||
|
]
|
||||||
|
],
|
||||||
[ TrainerType.NURSERY_AIDE, []],
|
[ TrainerType.NURSERY_AIDE, []],
|
||||||
[ TrainerType.OFFICER, [
|
[ TrainerType.OFFICER, [
|
||||||
[ Biome.METROPOLIS, BiomePoolTier.COMMON ],
|
[ Biome.METROPOLIS, BiomePoolTier.COMMON ],
|
||||||
@ -7256,8 +7274,15 @@ export function initBiomes() {
|
|||||||
[ Biome.MEADOW, BiomePoolTier.COMMON ]
|
[ Biome.MEADOW, BiomePoolTier.COMMON ]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ TrainerType.PILOT, []],
|
[ TrainerType.PILOT, [
|
||||||
[ TrainerType.POKEFAN, []],
|
[ Biome.MOUNTAIN, BiomePoolTier.UNCOMMON ]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[ TrainerType.POKEFAN, [
|
||||||
|
[ Biome.GRASS, BiomePoolTier.UNCOMMON ],
|
||||||
|
[ Biome.MEADOW, BiomePoolTier.UNCOMMON ]
|
||||||
|
]
|
||||||
|
],
|
||||||
[ TrainerType.PRESCHOOLER, []],
|
[ TrainerType.PRESCHOOLER, []],
|
||||||
[ TrainerType.PSYCHIC, [
|
[ TrainerType.PSYCHIC, [
|
||||||
[ Biome.GRAVEYARD, BiomePoolTier.COMMON ],
|
[ Biome.GRAVEYARD, BiomePoolTier.COMMON ],
|
||||||
@ -7270,11 +7295,24 @@ export function initBiomes() {
|
|||||||
[ Biome.JUNGLE, BiomePoolTier.COMMON ]
|
[ Biome.JUNGLE, BiomePoolTier.COMMON ]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ TrainerType.RICH_KID, []],
|
[ TrainerType.RICH, [
|
||||||
|
[ Biome.ISLAND, BiomePoolTier.UNCOMMON ]
|
||||||
|
]
|
||||||
|
],
|
||||||
|
[ TrainerType.RICH_KID, [
|
||||||
|
[ Biome.METROPOLIS, BiomePoolTier.RARE ],
|
||||||
|
[ Biome.ISLAND, BiomePoolTier.COMMON ]
|
||||||
|
]
|
||||||
|
],
|
||||||
[ TrainerType.ROUGHNECK, [
|
[ TrainerType.ROUGHNECK, [
|
||||||
[ Biome.SLUM, BiomePoolTier.COMMON ]
|
[ Biome.SLUM, BiomePoolTier.COMMON ]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
|
[ TrainerType.SAILOR, [
|
||||||
|
[ Biome.SEA, BiomePoolTier.COMMON ],
|
||||||
|
[ Biome.BEACH, BiomePoolTier.COMMON ]
|
||||||
|
]
|
||||||
|
],
|
||||||
[ TrainerType.SCIENTIST, [
|
[ TrainerType.SCIENTIST, [
|
||||||
[ Biome.DESERT, BiomePoolTier.COMMON ],
|
[ Biome.DESERT, BiomePoolTier.COMMON ],
|
||||||
[ Biome.RUINS, BiomePoolTier.COMMON ]
|
[ Biome.RUINS, BiomePoolTier.COMMON ]
|
||||||
@ -7317,20 +7355,6 @@ export function initBiomes() {
|
|||||||
[ Biome.TOWN, BiomePoolTier.COMMON ]
|
[ Biome.TOWN, BiomePoolTier.COMMON ]
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
[ TrainerType.HEX_MANIAC, [
|
|
||||||
[ Biome.RUINS, BiomePoolTier.UNCOMMON ],
|
|
||||||
[ Biome.GRAVEYARD, BiomePoolTier.UNCOMMON ]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[ TrainerType.FIREBREATHER, [
|
|
||||||
[ Biome.VOLCANO, BiomePoolTier.COMMON ]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[ TrainerType.SAILOR, [
|
|
||||||
[ Biome.SEA, BiomePoolTier.COMMON ],
|
|
||||||
[ Biome.BEACH, BiomePoolTier.COMMON ]
|
|
||||||
]
|
|
||||||
],
|
|
||||||
[ TrainerType.BROCK, [
|
[ TrainerType.BROCK, [
|
||||||
[ Biome.CAVE, BiomePoolTier.BOSS ]
|
[ Biome.CAVE, BiomePoolTier.BOSS ]
|
||||||
]
|
]
|
||||||
|
@ -757,7 +757,7 @@ export class ConfusedTag extends BattlerTag {
|
|||||||
((((2 * pokemon.level) / 5 + 2) * 40 * atk) / def / 50 + 2) * (pokemon.randSeedIntRange(85, 100) / 100),
|
((((2 * pokemon.level) / 5 + 2) * 40 * atk) / def / 50 + 2) * (pokemon.randSeedIntRange(85, 100) / 100),
|
||||||
);
|
);
|
||||||
globalScene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself"));
|
globalScene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself"));
|
||||||
pokemon.damageAndUpdate(damage);
|
pokemon.damageAndUpdate(damage, { result: HitResult.CONFUSION });
|
||||||
pokemon.battleData.hitCount++;
|
pokemon.battleData.hitCount++;
|
||||||
(globalScene.getCurrentPhase() as MovePhase).cancel();
|
(globalScene.getCurrentPhase() as MovePhase).cancel();
|
||||||
}
|
}
|
||||||
@ -818,7 +818,7 @@ export class DestinyBondTag extends BattlerTag {
|
|||||||
pokemonNameWithAffix2: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix2: getPokemonNameWithAffix(pokemon),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
pokemon.damageAndUpdate(pokemon.hp, HitResult.ONE_HIT_KO, false, false, true);
|
pokemon.damageAndUpdate(pokemon.hp, { result: HitResult.INDIRECT_KO, ignoreSegments: true });
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -952,7 +952,7 @@ export class SeedTag extends BattlerTag {
|
|||||||
new CommonAnimPhase(source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED),
|
new CommonAnimPhase(source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED),
|
||||||
);
|
);
|
||||||
|
|
||||||
const damage = pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8));
|
const damage = pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8), { result: HitResult.INDIRECT });
|
||||||
const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr, false);
|
const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr, false);
|
||||||
globalScene.unshiftPhase(
|
globalScene.unshiftPhase(
|
||||||
new PokemonHealPhase(
|
new PokemonHealPhase(
|
||||||
@ -1029,7 +1029,7 @@ export class PowderTag extends BattlerTag {
|
|||||||
const cancelDamage = new BooleanHolder(false);
|
const cancelDamage = new BooleanHolder(false);
|
||||||
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelDamage);
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelDamage);
|
||||||
if (!cancelDamage.value) {
|
if (!cancelDamage.value) {
|
||||||
pokemon.damageAndUpdate(Math.floor(pokemon.getMaxHp() / 4), HitResult.OTHER);
|
pokemon.damageAndUpdate(Math.floor(pokemon.getMaxHp() / 4), { result: HitResult.INDIRECT });
|
||||||
}
|
}
|
||||||
|
|
||||||
// "When the flame touched the powder\non the Pokémon, it exploded!"
|
// "When the flame touched the powder\non the Pokémon, it exploded!"
|
||||||
@ -1082,7 +1082,7 @@ export class NightmareTag extends BattlerTag {
|
|||||||
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||||
|
|
||||||
if (!cancelled.value) {
|
if (!cancelled.value) {
|
||||||
pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 4));
|
pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 4), { result: HitResult.INDIRECT });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1440,7 +1440,7 @@ export abstract class DamagingTrapTag extends TrappedTag {
|
|||||||
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||||
|
|
||||||
if (!cancelled.value) {
|
if (!cancelled.value) {
|
||||||
pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8));
|
pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8), { result: HitResult.INDIRECT });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1644,7 +1644,7 @@ export class ContactDamageProtectedTag extends ProtectedTag {
|
|||||||
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) {
|
if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) {
|
||||||
const attacker = effectPhase.getPokemon();
|
const attacker = effectPhase.getPokemon();
|
||||||
if (!attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
|
if (!attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {
|
||||||
attacker.damageAndUpdate(toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER);
|
attacker.damageAndUpdate(toDmgValue(attacker.getMaxHp() * (1 / this.damageRatio)), { result: HitResult.INDIRECT });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1810,7 +1810,7 @@ export class PerishSongTag extends BattlerTag {
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
pokemon.damageAndUpdate(pokemon.hp, HitResult.ONE_HIT_KO, false, true, true);
|
pokemon.damageAndUpdate(pokemon.hp, { result: HitResult.INDIRECT_KO, ignoreSegments: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@ -2240,7 +2240,7 @@ export class SaltCuredTag extends BattlerTag {
|
|||||||
|
|
||||||
if (!cancelled.value) {
|
if (!cancelled.value) {
|
||||||
const pokemonSteelOrWater = pokemon.isOfType(PokemonType.STEEL) || pokemon.isOfType(PokemonType.WATER);
|
const pokemonSteelOrWater = pokemon.isOfType(PokemonType.STEEL) || pokemon.isOfType(PokemonType.WATER);
|
||||||
pokemon.damageAndUpdate(toDmgValue(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8));
|
pokemon.damageAndUpdate(toDmgValue(pokemonSteelOrWater ? pokemon.getMaxHp() / 4 : pokemon.getMaxHp() / 8), { result: HitResult.INDIRECT });
|
||||||
|
|
||||||
globalScene.queueMessage(
|
globalScene.queueMessage(
|
||||||
i18next.t("battlerTags:saltCuredLapse", {
|
i18next.t("battlerTags:saltCuredLapse", {
|
||||||
@ -2288,7 +2288,7 @@ export class CursedTag extends BattlerTag {
|
|||||||
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
|
||||||
|
|
||||||
if (!cancelled.value) {
|
if (!cancelled.value) {
|
||||||
pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 4));
|
pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 4), { result: HitResult.INDIRECT });
|
||||||
globalScene.queueMessage(
|
globalScene.queueMessage(
|
||||||
i18next.t("battlerTags:cursedLapse", {
|
i18next.t("battlerTags:cursedLapse", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
@ -2611,7 +2611,7 @@ export class GulpMissileTag extends BattlerTag {
|
|||||||
applyAbAttrs(BlockNonDirectDamageAbAttr, attacker, cancelled);
|
applyAbAttrs(BlockNonDirectDamageAbAttr, attacker, cancelled);
|
||||||
|
|
||||||
if (!cancelled.value) {
|
if (!cancelled.value) {
|
||||||
attacker.damageAndUpdate(Math.max(1, Math.floor(attacker.getMaxHp() / 4)), HitResult.OTHER);
|
attacker.damageAndUpdate(Math.max(1, Math.floor(attacker.getMaxHp() / 4)), { result: HitResult.INDIRECT });
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) {
|
if (this.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) {
|
||||||
|
@ -18,9 +18,10 @@ import { TrainerType } from "#enums/trainer-type";
|
|||||||
import { Nature } from "#enums/nature";
|
import { Nature } from "#enums/nature";
|
||||||
import type { Moves } from "#enums/moves";
|
import type { Moves } from "#enums/moves";
|
||||||
import { TypeColor, TypeShadow } from "#enums/color";
|
import { TypeColor, TypeShadow } from "#enums/color";
|
||||||
import { pokemonEvolutions } from "#app/data/balance/pokemon-evolutions";
|
|
||||||
import { pokemonFormChanges } from "#app/data/pokemon-forms";
|
|
||||||
import { ModifierTier } from "#app/modifier/modifier-tier";
|
import { ModifierTier } from "#app/modifier/modifier-tier";
|
||||||
|
import { globalScene } from "#app/global-scene";
|
||||||
|
import { pokemonFormChanges } from "./pokemon-forms";
|
||||||
|
import { pokemonEvolutions } from "./balance/pokemon-evolutions";
|
||||||
|
|
||||||
/** A constant for the default max cost of the starting party before a run */
|
/** A constant for the default max cost of the starting party before a run */
|
||||||
const DEFAULT_PARTY_MAX_COST = 10;
|
const DEFAULT_PARTY_MAX_COST = 10;
|
||||||
@ -285,15 +286,9 @@ export abstract class Challenge {
|
|||||||
* @param _pokemon {@link PokemonSpecies} The pokemon to check the validity of.
|
* @param _pokemon {@link PokemonSpecies} The pokemon to check the validity of.
|
||||||
* @param _valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
|
* @param _valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
|
||||||
* @param _dexAttr {@link DexAttrProps} The dex attributes of the pokemon.
|
* @param _dexAttr {@link DexAttrProps} The dex attributes of the pokemon.
|
||||||
* @param _soft {@link boolean} If true, allow it if it could become a valid pokemon.
|
|
||||||
* @returns {@link boolean} Whether this function did anything.
|
* @returns {@link boolean} Whether this function did anything.
|
||||||
*/
|
*/
|
||||||
applyStarterChoice(
|
applyStarterChoice(_pokemon: PokemonSpecies, _valid: Utils.BooleanHolder, _dexAttr: DexAttrProps): boolean {
|
||||||
_pokemon: PokemonSpecies,
|
|
||||||
_valid: Utils.BooleanHolder,
|
|
||||||
_dexAttr: DexAttrProps,
|
|
||||||
_soft = false,
|
|
||||||
): boolean {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,27 +440,8 @@ export class SingleGenerationChallenge extends Challenge {
|
|||||||
super(Challenges.SINGLE_GENERATION, 9);
|
super(Challenges.SINGLE_GENERATION, 9);
|
||||||
}
|
}
|
||||||
|
|
||||||
applyStarterChoice(
|
applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder): boolean {
|
||||||
pokemon: PokemonSpecies,
|
if (pokemon.generation !== this.value) {
|
||||||
valid: Utils.BooleanHolder,
|
|
||||||
_dexAttr: DexAttrProps,
|
|
||||||
soft = false,
|
|
||||||
): boolean {
|
|
||||||
const generations = [pokemon.generation];
|
|
||||||
if (soft) {
|
|
||||||
const speciesToCheck = [pokemon.speciesId];
|
|
||||||
while (speciesToCheck.length) {
|
|
||||||
const checking = speciesToCheck.pop();
|
|
||||||
if (checking && pokemonEvolutions.hasOwnProperty(checking)) {
|
|
||||||
pokemonEvolutions[checking].forEach(e => {
|
|
||||||
speciesToCheck.push(e.speciesId);
|
|
||||||
generations.push(getPokemonSpecies(e.speciesId).generation);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!generations.includes(this.value)) {
|
|
||||||
valid.value = false;
|
valid.value = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -739,41 +715,14 @@ export class SingleTypeChallenge extends Challenge {
|
|||||||
{ species: Species.CASTFORM, type: PokemonType.NORMAL, fusion: false },
|
{ species: Species.CASTFORM, type: PokemonType.NORMAL, fusion: false },
|
||||||
];
|
];
|
||||||
// TODO: Find a solution for all Pokemon with this ssui issue, including Basculin and Burmy
|
// TODO: Find a solution for all Pokemon with this ssui issue, including Basculin and Burmy
|
||||||
private static SPECIES_OVERRIDES: Species[] = [Species.MELOETTA];
|
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(Challenges.SINGLE_TYPE, 18);
|
super(Challenges.SINGLE_TYPE, 18);
|
||||||
}
|
}
|
||||||
|
|
||||||
override applyStarterChoice(
|
override applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps): boolean {
|
||||||
pokemon: PokemonSpecies,
|
|
||||||
valid: Utils.BooleanHolder,
|
|
||||||
dexAttr: DexAttrProps,
|
|
||||||
soft = false,
|
|
||||||
): boolean {
|
|
||||||
const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex);
|
const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex);
|
||||||
const types = [speciesForm.type1, speciesForm.type2];
|
const types = [speciesForm.type1, speciesForm.type2];
|
||||||
if (soft && !SingleTypeChallenge.SPECIES_OVERRIDES.includes(pokemon.speciesId)) {
|
|
||||||
const speciesToCheck = [pokemon.speciesId];
|
|
||||||
while (speciesToCheck.length) {
|
|
||||||
const checking = speciesToCheck.pop();
|
|
||||||
if (checking && pokemonEvolutions.hasOwnProperty(checking)) {
|
|
||||||
pokemonEvolutions[checking].forEach(e => {
|
|
||||||
speciesToCheck.push(e.speciesId);
|
|
||||||
types.push(getPokemonSpecies(e.speciesId).type1, getPokemonSpecies(e.speciesId).type2);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (checking && pokemonFormChanges.hasOwnProperty(checking)) {
|
|
||||||
pokemonFormChanges[checking].forEach(f1 => {
|
|
||||||
getPokemonSpecies(checking).forms.forEach(f2 => {
|
|
||||||
if (f1.formKey === f2.formKey) {
|
|
||||||
types.push(f2.type1, f2.type2);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!types.includes(this.value - 1)) {
|
if (!types.includes(this.value - 1)) {
|
||||||
valid.value = false;
|
valid.value = false;
|
||||||
return true;
|
return true;
|
||||||
@ -1030,7 +979,6 @@ export class LowerStarterPointsChallenge extends Challenge {
|
|||||||
* @param pokemon {@link PokemonSpecies} The pokemon to check the validity of.
|
* @param pokemon {@link PokemonSpecies} The pokemon to check the validity of.
|
||||||
* @param valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
|
* @param valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed.
|
||||||
* @param dexAttr {@link DexAttrProps} The dex attributes of the pokemon.
|
* @param dexAttr {@link DexAttrProps} The dex attributes of the pokemon.
|
||||||
* @param soft {@link boolean} If true, allow it if it could become a valid pokemon.
|
|
||||||
* @returns True if any challenge was successfully applied.
|
* @returns True if any challenge was successfully applied.
|
||||||
*/
|
*/
|
||||||
export function applyChallenges(
|
export function applyChallenges(
|
||||||
@ -1039,7 +987,6 @@ export function applyChallenges(
|
|||||||
pokemon: PokemonSpecies,
|
pokemon: PokemonSpecies,
|
||||||
valid: Utils.BooleanHolder,
|
valid: Utils.BooleanHolder,
|
||||||
dexAttr: DexAttrProps,
|
dexAttr: DexAttrProps,
|
||||||
soft: boolean,
|
|
||||||
): boolean;
|
): boolean;
|
||||||
/**
|
/**
|
||||||
* Apply all challenges that modify available total starter points.
|
* Apply all challenges that modify available total starter points.
|
||||||
@ -1222,7 +1169,7 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType
|
|||||||
if (c.value !== 0) {
|
if (c.value !== 0) {
|
||||||
switch (challengeType) {
|
switch (challengeType) {
|
||||||
case ChallengeType.STARTER_CHOICE:
|
case ChallengeType.STARTER_CHOICE:
|
||||||
ret ||= c.applyStarterChoice(args[0], args[1], args[2], args[3]);
|
ret ||= c.applyStarterChoice(args[0], args[1], args[2]);
|
||||||
break;
|
break;
|
||||||
case ChallengeType.STARTER_POINTS:
|
case ChallengeType.STARTER_POINTS:
|
||||||
ret ||= c.applyStarterPoints(args[0]);
|
ret ||= c.applyStarterPoints(args[0]);
|
||||||
@ -1305,3 +1252,87 @@ export function initChallenges() {
|
|||||||
new FlipStatChallenge(),
|
new FlipStatChallenge(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges to the given starter (and form) to check its validity.
|
||||||
|
* Differs from {@linkcode checkSpeciesValidForChallenge} which only checks form changes.
|
||||||
|
* @param species - The {@linkcode PokemonSpecies} to check the validity of.
|
||||||
|
* @param dexAttr - The {@linkcode DexAttrProps | dex attributes} of the species, including its form index.
|
||||||
|
* @param soft - If `true`, allow it if it could become valid through evolution or form change.
|
||||||
|
* @returns `true` if the species is considered valid.
|
||||||
|
*/
|
||||||
|
export function checkStarterValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) {
|
||||||
|
if (!soft) {
|
||||||
|
const isValidForChallenge = new Utils.BooleanHolder(true);
|
||||||
|
applyChallenges(globalScene.gameMode, ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props);
|
||||||
|
return isValidForChallenge.value;
|
||||||
|
}
|
||||||
|
// We check the validity of every evolution and form change, and require that at least one is valid
|
||||||
|
const speciesToCheck = [species.speciesId];
|
||||||
|
while (speciesToCheck.length) {
|
||||||
|
const checking = speciesToCheck.pop();
|
||||||
|
// Linter complains if we don't handle this
|
||||||
|
if (!checking) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const checkingSpecies = getPokemonSpecies(checking);
|
||||||
|
if (checkSpeciesValidForChallenge(checkingSpecies, props, true)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (checking && pokemonEvolutions.hasOwnProperty(checking)) {
|
||||||
|
pokemonEvolutions[checking].forEach(e => {
|
||||||
|
// Form check to deal with cases such as Basculin -> Basculegion
|
||||||
|
// TODO: does this miss anything if checking forms of a stage 2 Pokémon?
|
||||||
|
if (!e?.preFormKey || e.preFormKey === species.forms[props.formIndex].formKey) {
|
||||||
|
speciesToCheck.push(e.speciesId);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply all challenges to the given species (and form) to check its validity.
|
||||||
|
* Differs from {@linkcode checkStarterValidForChallenge} which also checks evolutions.
|
||||||
|
* @param species - The {@linkcode PokemonSpecies} to check the validity of.
|
||||||
|
* @param dexAttr - The {@linkcode DexAttrProps | dex attributes} of the species, including its form index.
|
||||||
|
* @param soft - If `true`, allow it if it could become valid through a form change.
|
||||||
|
* @returns `true` if the species is considered valid.
|
||||||
|
*/
|
||||||
|
function checkSpeciesValidForChallenge(species: PokemonSpecies, props: DexAttrProps, soft: boolean) {
|
||||||
|
const isValidForChallenge = new Utils.BooleanHolder(true);
|
||||||
|
applyChallenges(globalScene.gameMode, ChallengeType.STARTER_CHOICE, species, isValidForChallenge, props);
|
||||||
|
if (!soft || !pokemonFormChanges.hasOwnProperty(species.speciesId)) {
|
||||||
|
return isValidForChallenge.value;
|
||||||
|
}
|
||||||
|
// If the form in props is valid, return true before checking other form changes
|
||||||
|
if (soft && isValidForChallenge.value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
pokemonFormChanges[species.speciesId].forEach(f1 => {
|
||||||
|
// Exclude form changes that require the mon to be on the field to begin with,
|
||||||
|
// such as Castform
|
||||||
|
if (!("item" in f1)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
species.forms.forEach((f2, formIndex) => {
|
||||||
|
if (f1.formKey === f2.formKey) {
|
||||||
|
const formProps = { ...props };
|
||||||
|
formProps.formIndex = formIndex;
|
||||||
|
const isFormValidForChallenge = new Utils.BooleanHolder(true);
|
||||||
|
applyChallenges(
|
||||||
|
globalScene.gameMode,
|
||||||
|
ChallengeType.STARTER_CHOICE,
|
||||||
|
species,
|
||||||
|
isFormValidForChallenge,
|
||||||
|
formProps,
|
||||||
|
);
|
||||||
|
if (isFormValidForChallenge.value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
@ -312,6 +312,113 @@ export const trainerTypeDialogue: TrainerTypeDialogue = {
|
|||||||
victory: ["dialogue:sailor.victory.1", "dialogue:sailor.victory.2", "dialogue:sailor.victory.3"],
|
victory: ["dialogue:sailor.victory.1", "dialogue:sailor.victory.2", "dialogue:sailor.victory.3"],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
[TrainerType.CLERK]: [
|
||||||
|
{
|
||||||
|
encounter: ["dialogue:clerk.encounter.1", "dialogue:clerk.encounter.2", "dialogue:clerk.encounter.3"],
|
||||||
|
victory: ["dialogue:clerk.victory.1", "dialogue:clerk.victory.2", "dialogue:clerk.victory.3"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:clerk_female.encounter.1",
|
||||||
|
"dialogue:clerk_female.encounter.2",
|
||||||
|
"dialogue:clerk_female.encounter.3",
|
||||||
|
],
|
||||||
|
victory: [
|
||||||
|
"dialogue:clerk_female.victory.1",
|
||||||
|
"dialogue:clerk_female.victory.2",
|
||||||
|
"dialogue:clerk_female.victory.3",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[TrainerType.HOOLIGANS]: [
|
||||||
|
{
|
||||||
|
encounter: ["dialogue:hooligans.encounter.1", "dialogue:hooligans.encounter.2"],
|
||||||
|
victory: ["dialogue:hooligans.victory.1", "dialogue:hooligans.victory.2"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[TrainerType.MUSICIAN]: [
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:musician.encounter.1",
|
||||||
|
"dialogue:musician.encounter.2",
|
||||||
|
"dialogue:musician.encounter.3",
|
||||||
|
"dialogue:musician.encounter.4",
|
||||||
|
],
|
||||||
|
victory: ["dialogue:musician.victory.1", "dialogue:musician.victory.2", "dialogue:musician.victory.3"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[TrainerType.PILOT]: [
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:pilot.encounter.1",
|
||||||
|
"dialogue:pilot.encounter.2",
|
||||||
|
"dialogue:pilot.encounter.3",
|
||||||
|
"dialogue:pilot.encounter.4",
|
||||||
|
],
|
||||||
|
victory: [
|
||||||
|
"dialogue:pilot.victory.1",
|
||||||
|
"dialogue:pilot.victory.2",
|
||||||
|
"dialogue:pilot.victory.3",
|
||||||
|
"dialogue:pilot.victory.4",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[TrainerType.POKEFAN]: [
|
||||||
|
{
|
||||||
|
encounter: ["dialogue:pokefan.encounter.1", "dialogue:pokefan.encounter.2", "dialogue:pokefan.encounter.3"],
|
||||||
|
victory: ["dialogue:pokefan.victory.1", "dialogue:pokefan.victory.2", "dialogue:pokefan.victory.3"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:pokefan_female.encounter.1",
|
||||||
|
"dialogue:pokefan_female.encounter.2",
|
||||||
|
"dialogue:pokefan_female.encounter.3",
|
||||||
|
],
|
||||||
|
victory: [
|
||||||
|
"dialogue:pokefan_female.victory.1",
|
||||||
|
"dialogue:pokefan_female.victory.2",
|
||||||
|
"dialogue:pokefan_female.victory.3",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[TrainerType.RICH]: [
|
||||||
|
{
|
||||||
|
encounter: ["dialogue:rich.encounter.1", "dialogue:rich.encounter.2", "dialogue:rich.encounter.3"],
|
||||||
|
victory: ["dialogue:rich.victory.1", "dialogue:rich.victory.2", "dialogue:rich.victory.3"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:rich_female.encounter.1",
|
||||||
|
"dialogue:rich_female.encounter.2",
|
||||||
|
"dialogue:rich_female.encounter.3",
|
||||||
|
],
|
||||||
|
victory: ["dialogue:rich_female.victory.1", "dialogue:rich_female.victory.2", "dialogue:rich_female.victory.3"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[TrainerType.RICH_KID]: [
|
||||||
|
{
|
||||||
|
encounter: ["dialogue:rich_kid.encounter.1", "dialogue:rich_kid.encounter.2", "dialogue:rich_kid.encounter.3"],
|
||||||
|
victory: [
|
||||||
|
"dialogue:rich_kid.victory.1",
|
||||||
|
"dialogue:rich_kid.victory.2",
|
||||||
|
"dialogue:rich_kid.victory.3",
|
||||||
|
"dialogue:rich_kid.victory.4",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
encounter: [
|
||||||
|
"dialogue:rich_kid_female.encounter.1",
|
||||||
|
"dialogue:rich_kid_female.encounter.2",
|
||||||
|
"dialogue:rich_kid_female.encounter.3",
|
||||||
|
],
|
||||||
|
victory: [
|
||||||
|
"dialogue:rich_kid_female.victory.1",
|
||||||
|
"dialogue:rich_kid_female.victory.2",
|
||||||
|
"dialogue:rich_kid_female.victory.3",
|
||||||
|
"dialogue:rich_kid_female.victory.4",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
[TrainerType.ROCKET_GRUNT]: [
|
[TrainerType.ROCKET_GRUNT]: [
|
||||||
{
|
{
|
||||||
encounter: [
|
encounter: [
|
||||||
|
@ -3,144 +3,46 @@ import { Moves } from "#enums/moves";
|
|||||||
/** Set of moves that cannot be called by {@linkcode Moves.METRONOME Metronome} */
|
/** Set of moves that cannot be called by {@linkcode Moves.METRONOME Metronome} */
|
||||||
export const invalidMetronomeMoves: ReadonlySet<Moves> = new Set([
|
export const invalidMetronomeMoves: ReadonlySet<Moves> = new Set([
|
||||||
Moves.AFTER_YOU,
|
Moves.AFTER_YOU,
|
||||||
Moves.APPLE_ACID,
|
|
||||||
Moves.ARMOR_CANNON,
|
|
||||||
Moves.ASSIST,
|
Moves.ASSIST,
|
||||||
Moves.ASTRAL_BARRAGE,
|
|
||||||
Moves.AURA_WHEEL,
|
|
||||||
Moves.BANEFUL_BUNKER,
|
Moves.BANEFUL_BUNKER,
|
||||||
Moves.BEAK_BLAST,
|
Moves.BEAK_BLAST,
|
||||||
Moves.BEHEMOTH_BASH,
|
|
||||||
Moves.BEHEMOTH_BLADE,
|
|
||||||
Moves.BELCH,
|
Moves.BELCH,
|
||||||
Moves.BESTOW,
|
Moves.BESTOW,
|
||||||
Moves.BLAZING_TORQUE,
|
|
||||||
Moves.BODY_PRESS,
|
|
||||||
Moves.BRANCH_POKE,
|
|
||||||
Moves.BREAKING_SWIPE,
|
|
||||||
Moves.CELEBRATE,
|
|
||||||
Moves.CHATTER,
|
|
||||||
Moves.CHILLING_WATER,
|
|
||||||
Moves.CHILLY_RECEPTION,
|
|
||||||
Moves.CLANGOROUS_SOUL,
|
|
||||||
Moves.COLLISION_COURSE,
|
|
||||||
Moves.COMBAT_TORQUE,
|
|
||||||
Moves.COMEUPPANCE,
|
Moves.COMEUPPANCE,
|
||||||
Moves.COPYCAT,
|
Moves.COPYCAT,
|
||||||
Moves.COUNTER,
|
Moves.COUNTER,
|
||||||
Moves.COVET,
|
|
||||||
Moves.CRAFTY_SHIELD,
|
Moves.CRAFTY_SHIELD,
|
||||||
Moves.DECORATE,
|
|
||||||
Moves.DESTINY_BOND,
|
Moves.DESTINY_BOND,
|
||||||
Moves.DETECT,
|
Moves.DETECT,
|
||||||
Moves.DIAMOND_STORM,
|
|
||||||
Moves.DOODLE,
|
|
||||||
Moves.DOUBLE_IRON_BASH,
|
|
||||||
Moves.DOUBLE_SHOCK,
|
|
||||||
Moves.DRAGON_ASCENT,
|
|
||||||
Moves.DRAGON_ENERGY,
|
|
||||||
Moves.DRUM_BEATING,
|
|
||||||
Moves.DYNAMAX_CANNON,
|
|
||||||
Moves.ELECTRO_DRIFT,
|
|
||||||
Moves.ENDURE,
|
Moves.ENDURE,
|
||||||
Moves.ETERNABEAM,
|
|
||||||
Moves.FALSE_SURRENDER,
|
|
||||||
Moves.FEINT,
|
Moves.FEINT,
|
||||||
Moves.FIERY_WRATH,
|
|
||||||
Moves.FILLET_AWAY,
|
|
||||||
Moves.FLEUR_CANNON,
|
|
||||||
Moves.FOCUS_PUNCH,
|
Moves.FOCUS_PUNCH,
|
||||||
Moves.FOLLOW_ME,
|
Moves.FOLLOW_ME,
|
||||||
Moves.FREEZE_SHOCK,
|
|
||||||
Moves.FREEZING_GLARE,
|
|
||||||
Moves.GLACIAL_LANCE,
|
|
||||||
Moves.GRAV_APPLE,
|
|
||||||
Moves.HELPING_HAND,
|
Moves.HELPING_HAND,
|
||||||
Moves.HOLD_HANDS,
|
|
||||||
Moves.HYPER_DRILL,
|
|
||||||
Moves.HYPERSPACE_FURY,
|
|
||||||
Moves.HYPERSPACE_HOLE,
|
|
||||||
Moves.ICE_BURN,
|
|
||||||
Moves.INSTRUCT,
|
Moves.INSTRUCT,
|
||||||
Moves.JET_PUNCH,
|
|
||||||
Moves.JUNGLE_HEALING,
|
|
||||||
Moves.KINGS_SHIELD,
|
Moves.KINGS_SHIELD,
|
||||||
Moves.LIFE_DEW,
|
|
||||||
Moves.LIGHT_OF_RUIN,
|
|
||||||
Moves.MAKE_IT_RAIN,
|
|
||||||
Moves.MAGICAL_TORQUE,
|
|
||||||
Moves.MAT_BLOCK,
|
Moves.MAT_BLOCK,
|
||||||
Moves.ME_FIRST,
|
Moves.ME_FIRST,
|
||||||
Moves.METEOR_ASSAULT,
|
|
||||||
Moves.METRONOME,
|
Moves.METRONOME,
|
||||||
Moves.MIMIC,
|
Moves.MIMIC,
|
||||||
Moves.MIND_BLOWN,
|
|
||||||
Moves.MIRROR_COAT,
|
Moves.MIRROR_COAT,
|
||||||
Moves.MIRROR_MOVE,
|
Moves.MIRROR_MOVE,
|
||||||
Moves.MOONGEIST_BEAM,
|
|
||||||
Moves.NATURE_POWER,
|
|
||||||
Moves.NATURES_MADNESS,
|
|
||||||
Moves.NOXIOUS_TORQUE,
|
|
||||||
Moves.OBSTRUCT,
|
Moves.OBSTRUCT,
|
||||||
Moves.ORDER_UP,
|
|
||||||
Moves.ORIGIN_PULSE,
|
|
||||||
Moves.OVERDRIVE,
|
|
||||||
Moves.PHOTON_GEYSER,
|
|
||||||
Moves.PLASMA_FISTS,
|
|
||||||
Moves.POPULATION_BOMB,
|
|
||||||
Moves.POUNCE,
|
|
||||||
Moves.POWER_SHIFT,
|
|
||||||
Moves.PRECIPICE_BLADES,
|
|
||||||
Moves.PROTECT,
|
Moves.PROTECT,
|
||||||
Moves.PYRO_BALL,
|
|
||||||
Moves.QUASH,
|
Moves.QUASH,
|
||||||
Moves.QUICK_GUARD,
|
Moves.QUICK_GUARD,
|
||||||
Moves.RAGE_FIST,
|
|
||||||
Moves.RAGE_POWDER,
|
Moves.RAGE_POWDER,
|
||||||
Moves.RAGING_BULL,
|
|
||||||
Moves.RAGING_FURY,
|
|
||||||
Moves.RELIC_SONG,
|
|
||||||
Moves.REVIVAL_BLESSING,
|
Moves.REVIVAL_BLESSING,
|
||||||
Moves.RUINATION,
|
|
||||||
Moves.SALT_CURE,
|
|
||||||
Moves.SECRET_SWORD,
|
|
||||||
Moves.SHED_TAIL,
|
|
||||||
Moves.SHELL_TRAP,
|
Moves.SHELL_TRAP,
|
||||||
Moves.SILK_TRAP,
|
Moves.SILK_TRAP,
|
||||||
Moves.SKETCH,
|
Moves.SKETCH,
|
||||||
Moves.SLEEP_TALK,
|
Moves.SLEEP_TALK,
|
||||||
Moves.SNAP_TRAP,
|
|
||||||
Moves.SNARL,
|
|
||||||
Moves.SNATCH,
|
Moves.SNATCH,
|
||||||
Moves.SNORE,
|
Moves.SNORE,
|
||||||
Moves.SNOWSCAPE,
|
|
||||||
Moves.SPECTRAL_THIEF,
|
|
||||||
Moves.SPICY_EXTRACT,
|
|
||||||
Moves.SPIKY_SHIELD,
|
Moves.SPIKY_SHIELD,
|
||||||
Moves.SPIRIT_BREAK,
|
|
||||||
Moves.SPOTLIGHT,
|
Moves.SPOTLIGHT,
|
||||||
Moves.STEAM_ERUPTION,
|
|
||||||
Moves.STEEL_BEAM,
|
|
||||||
Moves.STRANGE_STEAM,
|
|
||||||
Moves.STRUGGLE,
|
Moves.STRUGGLE,
|
||||||
Moves.SUNSTEEL_STRIKE,
|
|
||||||
Moves.SURGING_STRIKES,
|
|
||||||
Moves.SWITCHEROO,
|
|
||||||
Moves.TECHNO_BLAST,
|
|
||||||
Moves.TERA_STARSTORM,
|
|
||||||
Moves.THIEF,
|
|
||||||
Moves.THOUSAND_ARROWS,
|
|
||||||
Moves.THOUSAND_WAVES,
|
|
||||||
Moves.THUNDER_CAGE,
|
|
||||||
Moves.THUNDEROUS_KICK,
|
|
||||||
Moves.TIDY_UP,
|
|
||||||
Moves.TRAILBLAZE,
|
|
||||||
Moves.TRANSFORM,
|
Moves.TRANSFORM,
|
||||||
Moves.TRICK,
|
|
||||||
Moves.TWIN_BEAM,
|
|
||||||
Moves.V_CREATE,
|
|
||||||
Moves.WICKED_BLOW,
|
|
||||||
Moves.WICKED_TORQUE,
|
|
||||||
Moves.WIDE_GUARD,
|
Moves.WIDE_GUARD,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@ -157,7 +59,6 @@ export const invalidAssistMoves: ReadonlySet<Moves> = new Set([
|
|||||||
Moves.CIRCLE_THROW,
|
Moves.CIRCLE_THROW,
|
||||||
Moves.COPYCAT,
|
Moves.COPYCAT,
|
||||||
Moves.COUNTER,
|
Moves.COUNTER,
|
||||||
Moves.COVET,
|
|
||||||
Moves.DESTINY_BOND,
|
Moves.DESTINY_BOND,
|
||||||
Moves.DETECT,
|
Moves.DETECT,
|
||||||
Moves.DIG,
|
Moves.DIG,
|
||||||
@ -192,7 +93,6 @@ export const invalidAssistMoves: ReadonlySet<Moves> = new Set([
|
|||||||
Moves.SPOTLIGHT,
|
Moves.SPOTLIGHT,
|
||||||
Moves.STRUGGLE,
|
Moves.STRUGGLE,
|
||||||
Moves.SWITCHEROO,
|
Moves.SWITCHEROO,
|
||||||
Moves.THIEF,
|
|
||||||
Moves.TRANSFORM,
|
Moves.TRANSFORM,
|
||||||
Moves.TRICK,
|
Moves.TRICK,
|
||||||
Moves.WHIRLWIND,
|
Moves.WHIRLWIND,
|
||||||
@ -208,7 +108,6 @@ export const invalidSleepTalkMoves: ReadonlySet<Moves> = new Set([
|
|||||||
Moves.COPYCAT,
|
Moves.COPYCAT,
|
||||||
Moves.DIG,
|
Moves.DIG,
|
||||||
Moves.DIVE,
|
Moves.DIVE,
|
||||||
Moves.DYNAMAX_CANNON,
|
|
||||||
Moves.FREEZE_SHOCK,
|
Moves.FREEZE_SHOCK,
|
||||||
Moves.FLY,
|
Moves.FLY,
|
||||||
Moves.FOCUS_PUNCH,
|
Moves.FOCUS_PUNCH,
|
||||||
@ -238,15 +137,12 @@ export const invalidCopycatMoves: ReadonlySet<Moves> = new Set([
|
|||||||
Moves.ASSIST,
|
Moves.ASSIST,
|
||||||
Moves.BANEFUL_BUNKER,
|
Moves.BANEFUL_BUNKER,
|
||||||
Moves.BEAK_BLAST,
|
Moves.BEAK_BLAST,
|
||||||
Moves.BEHEMOTH_BASH,
|
|
||||||
Moves.BEHEMOTH_BLADE,
|
|
||||||
Moves.BESTOW,
|
Moves.BESTOW,
|
||||||
Moves.CELEBRATE,
|
Moves.CELEBRATE,
|
||||||
Moves.CHATTER,
|
Moves.CHATTER,
|
||||||
Moves.CIRCLE_THROW,
|
Moves.CIRCLE_THROW,
|
||||||
Moves.COPYCAT,
|
Moves.COPYCAT,
|
||||||
Moves.COUNTER,
|
Moves.COUNTER,
|
||||||
Moves.COVET,
|
|
||||||
Moves.DESTINY_BOND,
|
Moves.DESTINY_BOND,
|
||||||
Moves.DETECT,
|
Moves.DETECT,
|
||||||
Moves.DRAGON_TAIL,
|
Moves.DRAGON_TAIL,
|
||||||
@ -274,8 +170,73 @@ export const invalidCopycatMoves: ReadonlySet<Moves> = new Set([
|
|||||||
Moves.SPOTLIGHT,
|
Moves.SPOTLIGHT,
|
||||||
Moves.STRUGGLE,
|
Moves.STRUGGLE,
|
||||||
Moves.SWITCHEROO,
|
Moves.SWITCHEROO,
|
||||||
Moves.THIEF,
|
|
||||||
Moves.TRANSFORM,
|
Moves.TRANSFORM,
|
||||||
Moves.TRICK,
|
Moves.TRICK,
|
||||||
Moves.WHIRLWIND,
|
Moves.WHIRLWIND,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
export const invalidMirrorMoveMoves: ReadonlySet<Moves> = new Set([
|
||||||
|
Moves.ACUPRESSURE,
|
||||||
|
Moves.AFTER_YOU,
|
||||||
|
Moves.AROMATIC_MIST,
|
||||||
|
Moves.BEAK_BLAST,
|
||||||
|
Moves.BELCH,
|
||||||
|
Moves.CHILLY_RECEPTION,
|
||||||
|
Moves.COACHING,
|
||||||
|
Moves.CONVERSION_2,
|
||||||
|
Moves.COUNTER,
|
||||||
|
Moves.CRAFTY_SHIELD,
|
||||||
|
Moves.CURSE,
|
||||||
|
Moves.DECORATE,
|
||||||
|
Moves.DOODLE,
|
||||||
|
Moves.DOOM_DESIRE,
|
||||||
|
Moves.DRAGON_CHEER,
|
||||||
|
Moves.ELECTRIC_TERRAIN,
|
||||||
|
Moves.FINAL_GAMBIT,
|
||||||
|
Moves.FLORAL_HEALING,
|
||||||
|
Moves.FLOWER_SHIELD,
|
||||||
|
Moves.FOCUS_PUNCH,
|
||||||
|
Moves.FUTURE_SIGHT,
|
||||||
|
Moves.GEAR_UP,
|
||||||
|
Moves.GRASSY_TERRAIN,
|
||||||
|
Moves.GRAVITY,
|
||||||
|
Moves.GUARD_SPLIT,
|
||||||
|
Moves.HAIL,
|
||||||
|
Moves.HAZE,
|
||||||
|
Moves.HEAL_PULSE,
|
||||||
|
Moves.HELPING_HAND,
|
||||||
|
Moves.HOLD_HANDS,
|
||||||
|
Moves.INSTRUCT,
|
||||||
|
Moves.ION_DELUGE,
|
||||||
|
Moves.MAGNETIC_FLUX,
|
||||||
|
Moves.MAT_BLOCK,
|
||||||
|
Moves.ME_FIRST,
|
||||||
|
Moves.MIMIC,
|
||||||
|
Moves.MIRROR_COAT,
|
||||||
|
Moves.MIRROR_MOVE,
|
||||||
|
Moves.MIST,
|
||||||
|
Moves.MISTY_TERRAIN,
|
||||||
|
Moves.MUD_SPORT,
|
||||||
|
Moves.PERISH_SONG,
|
||||||
|
Moves.POWER_SPLIT,
|
||||||
|
Moves.PSYCH_UP,
|
||||||
|
Moves.PSYCHIC_TERRAIN,
|
||||||
|
Moves.PURIFY,
|
||||||
|
Moves.QUICK_GUARD,
|
||||||
|
Moves.RAIN_DANCE,
|
||||||
|
Moves.REFLECT_TYPE,
|
||||||
|
Moves.ROLE_PLAY,
|
||||||
|
Moves.ROTOTILLER,
|
||||||
|
Moves.SANDSTORM,
|
||||||
|
Moves.SHELL_TRAP,
|
||||||
|
Moves.SKETCH,
|
||||||
|
Moves.SNOWSCAPE,
|
||||||
|
Moves.SPIT_UP,
|
||||||
|
Moves.SPOTLIGHT,
|
||||||
|
Moves.STRUGGLE,
|
||||||
|
Moves.SUNNY_DAY,
|
||||||
|
Moves.TEATIME,
|
||||||
|
Moves.TRANSFORM,
|
||||||
|
Moves.WATER_SPORT,
|
||||||
|
Moves.WIDE_GUARD,
|
||||||
|
]);
|
||||||
|
@ -16,6 +16,7 @@ import type { AttackMoveResult, TurnMove } from "../../field/pokemon";
|
|||||||
import type Pokemon from "../../field/pokemon";
|
import type Pokemon from "../../field/pokemon";
|
||||||
import {
|
import {
|
||||||
EnemyPokemon,
|
EnemyPokemon,
|
||||||
|
FieldPosition,
|
||||||
HitResult,
|
HitResult,
|
||||||
MoveResult,
|
MoveResult,
|
||||||
PlayerPokemon,
|
PlayerPokemon,
|
||||||
@ -125,7 +126,7 @@ import { MoveTarget } from "#enums/MoveTarget";
|
|||||||
import { MoveFlags } from "#enums/MoveFlags";
|
import { MoveFlags } from "#enums/MoveFlags";
|
||||||
import { MoveEffectTrigger } from "#enums/MoveEffectTrigger";
|
import { MoveEffectTrigger } from "#enums/MoveEffectTrigger";
|
||||||
import { MultiHitType } from "#enums/MultiHitType";
|
import { MultiHitType } from "#enums/MultiHitType";
|
||||||
import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidSleepTalkMoves } from "./invalid-moves";
|
import { invalidAssistMoves, invalidCopycatMoves, invalidMetronomeMoves, invalidMirrorMoveMoves, invalidSleepTalkMoves } from "./invalid-moves";
|
||||||
|
|
||||||
type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
|
type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
|
||||||
type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean;
|
type UserMoveConditionFunc = (user: Pokemon, move: Move) => boolean;
|
||||||
@ -1646,7 +1647,7 @@ export class RecoilAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.damageAndUpdate(recoilDamage, HitResult.OTHER, false, true, true);
|
user.damageAndUpdate(recoilDamage, { result: HitResult.INDIRECT, ignoreSegments: true });
|
||||||
globalScene.queueMessage(i18next.t("moveTriggers:hitWithRecoil", { pokemonName: getPokemonNameWithAffix(user) }));
|
globalScene.queueMessage(i18next.t("moveTriggers:hitWithRecoil", { pokemonName: getPokemonNameWithAffix(user) }));
|
||||||
user.turnData.damageTaken += recoilDamage;
|
user.turnData.damageTaken += recoilDamage;
|
||||||
|
|
||||||
@ -1678,7 +1679,7 @@ export class SacrificialAttr extends MoveEffectAttr {
|
|||||||
* @returns true if the function succeeds
|
* @returns true if the function succeeds
|
||||||
**/
|
**/
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
user.damageAndUpdate(user.hp, HitResult.OTHER, false, true, true);
|
user.damageAndUpdate(user.hp, { result: HitResult.INDIRECT, ignoreSegments: true });
|
||||||
user.turnData.damageTaken += user.hp;
|
user.turnData.damageTaken += user.hp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1716,7 +1717,7 @@ export class SacrificialAttrOnHit extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.damageAndUpdate(user.hp, HitResult.OTHER, false, true, true);
|
user.damageAndUpdate(user.hp, { result: HitResult.INDIRECT, ignoreSegments: true });
|
||||||
user.turnData.damageTaken += user.hp;
|
user.turnData.damageTaken += user.hp;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -1758,7 +1759,7 @@ export class HalfSacrificialAttr extends MoveEffectAttr {
|
|||||||
// Check to see if the Pokemon has an ability that blocks non-direct damage
|
// Check to see if the Pokemon has an ability that blocks non-direct damage
|
||||||
applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
|
applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
|
||||||
if (!cancelled.value) {
|
if (!cancelled.value) {
|
||||||
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), HitResult.OTHER, false, true, true);
|
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), { result: HitResult.INDIRECT, ignoreSegments: true });
|
||||||
globalScene.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", { pokemonName: getPokemonNameWithAffix(user) })); // Queue recoil message
|
globalScene.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", { pokemonName: getPokemonNameWithAffix(user) })); // Queue recoil message
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -1805,7 +1806,7 @@ export class AddSubstituteAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const damageTaken = this.roundUp ? Math.ceil(user.getMaxHp() * this.hpCost) : Math.floor(user.getMaxHp() * this.hpCost);
|
const damageTaken = this.roundUp ? Math.ceil(user.getMaxHp() * this.hpCost) : Math.floor(user.getMaxHp() * this.hpCost);
|
||||||
user.damageAndUpdate(damageTaken, HitResult.OTHER, false, true, true);
|
user.damageAndUpdate(damageTaken, { result: HitResult.INDIRECT, ignoreSegments: true, ignoreFaintPhase: true });
|
||||||
user.addTag(BattlerTagType.SUBSTITUTE, 0, move.id, user.id);
|
user.addTag(BattlerTagType.SUBSTITUTE, 0, move.id, user.id);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1955,7 +1956,7 @@ export class FlameBurstAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
targetAlly.damageAndUpdate(Math.max(1, Math.floor(1 / 16 * targetAlly.getMaxHp())), HitResult.OTHER);
|
targetAlly.damageAndUpdate(Math.max(1, Math.floor(1 / 16 * targetAlly.getMaxHp())), { result: HitResult.INDIRECT });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3434,9 +3435,8 @@ export class CutHpStatStageBoostAttr extends StatStageChangeAttr {
|
|||||||
this.cutRatio = cutRatio;
|
this.cutRatio = cutRatio;
|
||||||
this.messageCallback = messageCallback;
|
this.messageCallback = messageCallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / this.cutRatio), HitResult.OTHER, false, true);
|
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / this.cutRatio), { result: HitResult.INDIRECT });
|
||||||
user.updateInfo();
|
user.updateInfo();
|
||||||
const ret = super.apply(user, target, move, args);
|
const ret = super.apply(user, target, move, args);
|
||||||
if (this.messageCallback) {
|
if (this.messageCallback) {
|
||||||
@ -5328,7 +5328,7 @@ const crashDamageFunc = (user: Pokemon, move: Move) => {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), HitResult.OTHER, false, true);
|
user.damageAndUpdate(Utils.toDmgValue(user.getMaxHp() / 2), { result: HitResult.INDIRECT });
|
||||||
globalScene.queueMessage(i18next.t("moveTriggers:keptGoingAndCrashed", { pokemonName: getPokemonNameWithAffix(user) }));
|
globalScene.queueMessage(i18next.t("moveTriggers:keptGoingAndCrashed", { pokemonName: getPokemonNameWithAffix(user) }));
|
||||||
user.turnData.damageTaken += Utils.toDmgValue(user.getMaxHp() / 2);
|
user.turnData.damageTaken += Utils.toDmgValue(user.getMaxHp() / 2);
|
||||||
|
|
||||||
@ -5649,7 +5649,7 @@ export class CurseAttr extends MoveEffectAttr {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2));
|
const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2));
|
||||||
user.damageAndUpdate(curseRecoilDamage, HitResult.OTHER, false, true, true);
|
user.damageAndUpdate(curseRecoilDamage, { result: HitResult.INDIRECT, ignoreSegments: true });
|
||||||
globalScene.queueMessage(
|
globalScene.queueMessage(
|
||||||
i18next.t("battlerTags:cursedOnAdd", {
|
i18next.t("battlerTags:cursedOnAdd", {
|
||||||
pokemonNameWithAffix: getPokemonNameWithAffix(user),
|
pokemonNameWithAffix: getPokemonNameWithAffix(user),
|
||||||
@ -6158,9 +6158,16 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
|
|||||||
|
|
||||||
if (globalScene.currentBattle.double && globalScene.getEnemyParty().length > 1) {
|
if (globalScene.currentBattle.double && globalScene.getEnemyParty().length > 1) {
|
||||||
const allyPokemon = user.getAlly();
|
const allyPokemon = user.getAlly();
|
||||||
if (slotIndex <= 1) {
|
// Handle cases where revived pokemon needs to get switched in on same turn
|
||||||
globalScene.unshiftPhase(new SwitchSummonPhase(SwitchType.SWITCH, pokemon.getFieldIndex(), slotIndex, false, false));
|
if (allyPokemon.isFainted() || allyPokemon === pokemon) {
|
||||||
} else if (allyPokemon.isFainted()) {
|
// Enemy switch phase should be removed and replaced with the revived pkmn switching in
|
||||||
|
globalScene.tryRemovePhase((phase: SwitchSummonPhase) => phase instanceof SwitchSummonPhase && phase.getPokemon() === pokemon);
|
||||||
|
// If the pokemon being revived was alive earlier in the turn, cancel its move
|
||||||
|
// (revived pokemon can't move in the turn they're brought back)
|
||||||
|
globalScene.findPhase((phase: MovePhase) => phase.pokemon === pokemon)?.cancel();
|
||||||
|
if (user.fieldPosition === FieldPosition.CENTER) {
|
||||||
|
user.setFieldPosition(FieldPosition.LEFT);
|
||||||
|
}
|
||||||
globalScene.unshiftPhase(new SwitchSummonPhase(SwitchType.SWITCH, allyPokemon.getFieldIndex(), slotIndex, false, false));
|
globalScene.unshiftPhase(new SwitchSummonPhase(SwitchType.SWITCH, allyPokemon.getFieldIndex(), slotIndex, false, false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6966,7 +6973,8 @@ export class CopyMoveAttr extends CallMoveAttr {
|
|||||||
getCondition(): MoveConditionFunc {
|
getCondition(): MoveConditionFunc {
|
||||||
return (user, target, move) => {
|
return (user, target, move) => {
|
||||||
if (this.mirrorMove) {
|
if (this.mirrorMove) {
|
||||||
return target.getMoveHistory().length !== 0;
|
const lastMove = target.getLastXMoves()[0]?.move;
|
||||||
|
return !!lastMove && !this.invalidMoves.has(lastMove);
|
||||||
} else {
|
} else {
|
||||||
const lastMove = globalScene.currentBattle.lastMove;
|
const lastMove = globalScene.currentBattle.lastMove;
|
||||||
return lastMove !== undefined && !this.invalidMoves.has(lastMove);
|
return lastMove !== undefined && !this.invalidMoves.has(lastMove);
|
||||||
@ -8562,7 +8570,7 @@ export function initMoves() {
|
|||||||
new SelfStatusMove(Moves.METRONOME, PokemonType.NORMAL, -1, 10, -1, 0, 1)
|
new SelfStatusMove(Moves.METRONOME, PokemonType.NORMAL, -1, 10, -1, 0, 1)
|
||||||
.attr(RandomMoveAttr, invalidMetronomeMoves),
|
.attr(RandomMoveAttr, invalidMetronomeMoves),
|
||||||
new StatusMove(Moves.MIRROR_MOVE, PokemonType.FLYING, -1, 20, -1, 0, 1)
|
new StatusMove(Moves.MIRROR_MOVE, PokemonType.FLYING, -1, 20, -1, 0, 1)
|
||||||
.attr(CopyMoveAttr, true),
|
.attr(CopyMoveAttr, true, invalidMirrorMoveMoves),
|
||||||
new AttackMove(Moves.SELF_DESTRUCT, PokemonType.NORMAL, MoveCategory.PHYSICAL, 200, 100, 5, -1, 0, 1)
|
new AttackMove(Moves.SELF_DESTRUCT, PokemonType.NORMAL, MoveCategory.PHYSICAL, 200, 100, 5, -1, 0, 1)
|
||||||
.attr(SacrificialAttr)
|
.attr(SacrificialAttr)
|
||||||
.makesContact(false)
|
.makesContact(false)
|
||||||
|
@ -2141,7 +2141,15 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
}),
|
}),
|
||||||
[TrainerType.HOOLIGANS]: new TrainerConfig(++t)
|
[TrainerType.HOOLIGANS]: new TrainerConfig(++t)
|
||||||
.setDoubleOnly()
|
.setDoubleOnly()
|
||||||
|
.setMoneyMultiplier(1.5)
|
||||||
.setEncounterBgm(TrainerType.ROUGHNECK)
|
.setEncounterBgm(TrainerType.ROUGHNECK)
|
||||||
|
.setPartyTemplateFunc(() =>
|
||||||
|
getWavePartyTemplate(
|
||||||
|
trainerPartyTemplates.TWO_WEAK,
|
||||||
|
trainerPartyTemplates.TWO_AVG,
|
||||||
|
trainerPartyTemplates.ONE_AVG_ONE_STRONG,
|
||||||
|
),
|
||||||
|
)
|
||||||
.setSpeciesFilter(s => s.isOfType(PokemonType.POISON) || s.isOfType(PokemonType.DARK)),
|
.setSpeciesFilter(s => s.isOfType(PokemonType.POISON) || s.isOfType(PokemonType.DARK)),
|
||||||
[TrainerType.HOOPSTER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST),
|
[TrainerType.HOOPSTER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST),
|
||||||
[TrainerType.INFIELDER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST),
|
[TrainerType.INFIELDER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST),
|
||||||
@ -2149,7 +2157,14 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
[TrainerType.LINEBACKER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST),
|
[TrainerType.LINEBACKER]: new TrainerConfig(++t).setMoneyMultiplier(1.2).setEncounterBgm(TrainerType.CYCLIST),
|
||||||
[TrainerType.MAID]: new TrainerConfig(++t).setMoneyMultiplier(1.6).setEncounterBgm(TrainerType.RICH),
|
[TrainerType.MAID]: new TrainerConfig(++t).setMoneyMultiplier(1.6).setEncounterBgm(TrainerType.RICH),
|
||||||
[TrainerType.MUSICIAN]: new TrainerConfig(++t)
|
[TrainerType.MUSICIAN]: new TrainerConfig(++t)
|
||||||
.setEncounterBgm(TrainerType.ROUGHNECK)
|
.setMoneyMultiplier(1.1)
|
||||||
|
.setEncounterBgm(TrainerType.POKEFAN)
|
||||||
|
.setPartyTemplates(
|
||||||
|
trainerPartyTemplates.FOUR_WEAKER,
|
||||||
|
trainerPartyTemplates.THREE_WEAK,
|
||||||
|
trainerPartyTemplates.TWO_WEAK_ONE_AVG,
|
||||||
|
trainerPartyTemplates.TWO_AVG,
|
||||||
|
)
|
||||||
.setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.SING)),
|
.setSpeciesFilter(s => !!s.getLevelMoves().find(plm => plm[1] === Moves.SING)),
|
||||||
[TrainerType.HEX_MANIAC]: new TrainerConfig(++t)
|
[TrainerType.HEX_MANIAC]: new TrainerConfig(++t)
|
||||||
.setMoneyMultiplier(1.5)
|
.setMoneyMultiplier(1.5)
|
||||||
@ -2214,7 +2229,14 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
) || s.getLevelMoves().some(plm => plm[1] === Moves.RAIN_DANCE),
|
) || s.getLevelMoves().some(plm => plm[1] === Moves.RAIN_DANCE),
|
||||||
), // Mons with rain abilities or who learn Rain Dance by level
|
), // Mons with rain abilities or who learn Rain Dance by level
|
||||||
[TrainerType.PILOT]: new TrainerConfig(++t)
|
[TrainerType.PILOT]: new TrainerConfig(++t)
|
||||||
|
.setMoneyMultiplier(1.75)
|
||||||
.setEncounterBgm(TrainerType.CLERK)
|
.setEncounterBgm(TrainerType.CLERK)
|
||||||
|
.setPartyTemplates(
|
||||||
|
trainerPartyTemplates.THREE_WEAK,
|
||||||
|
trainerPartyTemplates.TWO_WEAK_ONE_AVG,
|
||||||
|
trainerPartyTemplates.TWO_AVG,
|
||||||
|
trainerPartyTemplates.THREE_AVG,
|
||||||
|
)
|
||||||
.setSpeciesFilter(s => tmSpecies[Moves.FLY].indexOf(s.speciesId) > -1),
|
.setSpeciesFilter(s => tmSpecies[Moves.FLY].indexOf(s.speciesId) > -1),
|
||||||
[TrainerType.POKEFAN]: new TrainerConfig(++t)
|
[TrainerType.POKEFAN]: new TrainerConfig(++t)
|
||||||
.setMoneyMultiplier(1.4)
|
.setMoneyMultiplier(1.4)
|
||||||
@ -2230,7 +2252,8 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
trainerPartyTemplates.FOUR_WEAK_SAME,
|
trainerPartyTemplates.FOUR_WEAK_SAME,
|
||||||
trainerPartyTemplates.FIVE_WEAK,
|
trainerPartyTemplates.FIVE_WEAK,
|
||||||
trainerPartyTemplates.SIX_WEAKER_SAME,
|
trainerPartyTemplates.SIX_WEAKER_SAME,
|
||||||
),
|
)
|
||||||
|
.setSpeciesFilter(s => tmSpecies[Moves.HELPING_HAND].indexOf(s.speciesId) > -1),
|
||||||
[TrainerType.PRESCHOOLER]: new TrainerConfig(++t)
|
[TrainerType.PRESCHOOLER]: new TrainerConfig(++t)
|
||||||
.setMoneyMultiplier(0.2)
|
.setMoneyMultiplier(0.2)
|
||||||
.setEncounterBgm(TrainerType.YOUNGSTER)
|
.setEncounterBgm(TrainerType.YOUNGSTER)
|
||||||
@ -2352,16 +2375,29 @@ export const trainerConfigs: TrainerConfigs = {
|
|||||||
[TrainerPoolTier.SUPER_RARE]: [Species.LARVESTA],
|
[TrainerPoolTier.SUPER_RARE]: [Species.LARVESTA],
|
||||||
}),
|
}),
|
||||||
[TrainerType.RICH]: new TrainerConfig(++t)
|
[TrainerType.RICH]: new TrainerConfig(++t)
|
||||||
.setMoneyMultiplier(5)
|
.setMoneyMultiplier(3.25)
|
||||||
.setName("Gentleman")
|
.setName("Gentleman")
|
||||||
.setHasGenders("Madame")
|
.setHasGenders("Madame")
|
||||||
.setHasDouble("Rich Couple"),
|
.setHasDouble("Rich Couple")
|
||||||
|
.setPartyTemplates(
|
||||||
|
trainerPartyTemplates.THREE_WEAK,
|
||||||
|
trainerPartyTemplates.FOUR_WEAK,
|
||||||
|
trainerPartyTemplates.TWO_WEAK_ONE_AVG,
|
||||||
|
trainerPartyTemplates.THREE_AVG,
|
||||||
|
)
|
||||||
|
.setSpeciesFilter(s => s.isOfType(PokemonType.NORMAL) || s.isOfType(PokemonType.ELECTRIC)),
|
||||||
[TrainerType.RICH_KID]: new TrainerConfig(++t)
|
[TrainerType.RICH_KID]: new TrainerConfig(++t)
|
||||||
.setMoneyMultiplier(3.75)
|
.setMoneyMultiplier(2.5)
|
||||||
.setName("Rich Boy")
|
.setName("Rich Boy")
|
||||||
.setHasGenders("Lady")
|
.setHasGenders("Lady")
|
||||||
.setHasDouble("Rich Kids")
|
.setHasDouble("Rich Kids")
|
||||||
.setEncounterBgm(TrainerType.RICH),
|
.setEncounterBgm(TrainerType.RICH)
|
||||||
|
.setPartyTemplates(
|
||||||
|
trainerPartyTemplates.FOUR_WEAKER,
|
||||||
|
trainerPartyTemplates.THREE_WEAK_SAME,
|
||||||
|
trainerPartyTemplates.TWO_WEAK_SAME_ONE_AVG,
|
||||||
|
)
|
||||||
|
.setSpeciesFilter(s => s.baseTotal <= 460),
|
||||||
[TrainerType.ROUGHNECK]: new TrainerConfig(++t)
|
[TrainerType.ROUGHNECK]: new TrainerConfig(++t)
|
||||||
.setMoneyMultiplier(1.4)
|
.setMoneyMultiplier(1.4)
|
||||||
.setEncounterBgm(TrainerType.ROUGHNECK)
|
.setEncounterBgm(TrainerType.ROUGHNECK)
|
||||||
|
@ -46,6 +46,7 @@ export default class DamageNumberHandler {
|
|||||||
case HitResult.NOT_VERY_EFFECTIVE:
|
case HitResult.NOT_VERY_EFFECTIVE:
|
||||||
[textColor, shadowColor] = ["#f08030", "#c03028"];
|
[textColor, shadowColor] = ["#f08030", "#c03028"];
|
||||||
break;
|
break;
|
||||||
|
case HitResult.INDIRECT_KO:
|
||||||
case HitResult.ONE_HIT_KO:
|
case HitResult.ONE_HIT_KO:
|
||||||
[textColor, shadowColor] = ["#a040a0", "#483850"];
|
[textColor, shadowColor] = ["#a040a0", "#483850"];
|
||||||
break;
|
break;
|
||||||
|
@ -4469,8 +4469,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
const destinyTag = this.getTag(BattlerTagType.DESTINY_BOND);
|
const destinyTag = this.getTag(BattlerTagType.DESTINY_BOND);
|
||||||
const grudgeTag = this.getTag(BattlerTagType.GRUDGE);
|
const grudgeTag = this.getTag(BattlerTagType.GRUDGE);
|
||||||
|
|
||||||
const isOneHitKo = result === HitResult.ONE_HIT_KO;
|
|
||||||
|
|
||||||
if (dmg) {
|
if (dmg) {
|
||||||
this.lapseTags(BattlerTagLapseType.HIT);
|
this.lapseTags(BattlerTagLapseType.HIT);
|
||||||
|
|
||||||
@ -4488,15 +4486,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
* We explicitly require to ignore the faint phase here, as we want to show the messages
|
* We explicitly require to ignore the faint phase here, as we want to show the messages
|
||||||
* about the critical hit and the super effective/not very effective messages before the faint phase.
|
* about the critical hit and the super effective/not very effective messages before the faint phase.
|
||||||
*/
|
*/
|
||||||
const damage = this.damageAndUpdate(
|
const damage = this.damageAndUpdate(isBlockedBySubstitute ? 0 : dmg,
|
||||||
isBlockedBySubstitute ? 0 : dmg,
|
{
|
||||||
result as DamageResult,
|
result: result as DamageResult,
|
||||||
isCritical,
|
isCritical,
|
||||||
isOneHitKo,
|
ignoreFaintPhase: true,
|
||||||
isOneHitKo,
|
source
|
||||||
true,
|
});
|
||||||
source,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (damage > 0) {
|
if (damage > 0) {
|
||||||
if (source.isPlayer()) {
|
if (source.isPlayer()) {
|
||||||
@ -4557,7 +4553,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
globalScene.unshiftPhase(
|
globalScene.unshiftPhase(
|
||||||
new FaintPhase(
|
new FaintPhase(
|
||||||
this.getBattlerIndex(),
|
this.getBattlerIndex(),
|
||||||
isOneHitKo,
|
false,
|
||||||
destinyTag,
|
destinyTag,
|
||||||
grudgeTag,
|
grudgeTag,
|
||||||
source,
|
source,
|
||||||
@ -4635,28 +4631,37 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by apply(), given the damage, adds a new DamagePhase and actually updates HP values, etc.
|
* Called by apply(), given the damage, adds a new DamagePhase and actually updates HP values, etc.
|
||||||
|
* Checks for 'Indirect' HitResults to account for Endure/Reviver Seed applying correctly
|
||||||
* @param damage integer - passed to damage()
|
* @param damage integer - passed to damage()
|
||||||
* @param result an enum if it's super effective, not very, etc.
|
* @param result an enum if it's super effective, not very, etc.
|
||||||
* @param critical boolean if move is a critical hit
|
* @param isCritical boolean if move is a critical hit
|
||||||
* @param ignoreSegments boolean, passed to damage() and not used currently
|
* @param ignoreSegments boolean, passed to damage() and not used currently
|
||||||
* @param preventEndure boolean, ignore endure properties of pokemon, passed to damage()
|
* @param preventEndure boolean, ignore endure properties of pokemon, passed to damage()
|
||||||
* @param ignoreFaintPhase boolean to ignore adding a FaintPhase, passsed to damage()
|
* @param ignoreFaintPhase boolean to ignore adding a FaintPhase, passsed to damage()
|
||||||
* @returns integer of damage done
|
* @returns integer of damage done
|
||||||
*/
|
*/
|
||||||
damageAndUpdate(
|
damageAndUpdate(damage: number,
|
||||||
damage: number,
|
{
|
||||||
result?: DamageResult,
|
result = HitResult.EFFECTIVE,
|
||||||
critical = false,
|
isCritical = false,
|
||||||
ignoreSegments = false,
|
ignoreSegments = false,
|
||||||
preventEndure = false,
|
|
||||||
ignoreFaintPhase = false,
|
ignoreFaintPhase = false,
|
||||||
|
source = undefined,
|
||||||
|
}:
|
||||||
|
{
|
||||||
|
result?: DamageResult,
|
||||||
|
isCritical?: boolean,
|
||||||
|
ignoreSegments?: boolean,
|
||||||
|
ignoreFaintPhase?: boolean,
|
||||||
source?: Pokemon,
|
source?: Pokemon,
|
||||||
|
} = {}
|
||||||
): number {
|
): number {
|
||||||
|
const isIndirectDamage = [ HitResult.INDIRECT, HitResult.INDIRECT_KO ].includes(result);
|
||||||
const damagePhase = new DamageAnimPhase(
|
const damagePhase = new DamageAnimPhase(
|
||||||
this.getBattlerIndex(),
|
this.getBattlerIndex(),
|
||||||
damage,
|
damage,
|
||||||
result as DamageResult,
|
result as DamageResult,
|
||||||
critical,
|
isCritical
|
||||||
);
|
);
|
||||||
globalScene.unshiftPhase(damagePhase);
|
globalScene.unshiftPhase(damagePhase);
|
||||||
if (this.switchOutStatus && source) {
|
if (this.switchOutStatus && source) {
|
||||||
@ -4665,7 +4670,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
damage = this.damage(
|
damage = this.damage(
|
||||||
damage,
|
damage,
|
||||||
ignoreSegments,
|
ignoreSegments,
|
||||||
preventEndure,
|
isIndirectDamage,
|
||||||
ignoreFaintPhase,
|
ignoreFaintPhase,
|
||||||
);
|
);
|
||||||
// Damage amount may have changed, but needed to be queued before calling damage function
|
// Damage amount may have changed, but needed to be queued before calling damage function
|
||||||
@ -5575,7 +5580,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
}
|
}
|
||||||
this.resetBattleSummonData();
|
this.resetBattleSummonData();
|
||||||
if (this.summonDataPrimer) {
|
if (this.summonDataPrimer) {
|
||||||
for (const k of Object.keys(this.summonData)) {
|
for (const k of Object.keys(this.summonDataPrimer)) {
|
||||||
if (this.summonDataPrimer[k]) {
|
if (this.summonDataPrimer[k]) {
|
||||||
this.summonData[k] = this.summonDataPrimer[k];
|
this.summonData[k] = this.summonDataPrimer[k];
|
||||||
}
|
}
|
||||||
@ -7711,8 +7716,10 @@ export enum HitResult {
|
|||||||
HEAL,
|
HEAL,
|
||||||
FAIL,
|
FAIL,
|
||||||
MISS,
|
MISS,
|
||||||
OTHER,
|
INDIRECT,
|
||||||
IMMUNE,
|
IMMUNE,
|
||||||
|
CONFUSION,
|
||||||
|
INDIRECT_KO,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type DamageResult =
|
export type DamageResult =
|
||||||
@ -7720,7 +7727,9 @@ export type DamageResult =
|
|||||||
| HitResult.SUPER_EFFECTIVE
|
| HitResult.SUPER_EFFECTIVE
|
||||||
| HitResult.NOT_VERY_EFFECTIVE
|
| HitResult.NOT_VERY_EFFECTIVE
|
||||||
| HitResult.ONE_HIT_KO
|
| HitResult.ONE_HIT_KO
|
||||||
| HitResult.OTHER;
|
| HitResult.CONFUSION
|
||||||
|
| HitResult.INDIRECT_KO
|
||||||
|
| HitResult.INDIRECT;
|
||||||
|
|
||||||
/** Interface containing the results of a damage calculation for a given move */
|
/** Interface containing the results of a damage calculation for a given move */
|
||||||
export interface DamageCalculationResult {
|
export interface DamageCalculationResult {
|
||||||
|
@ -250,7 +250,7 @@ export class LoadingScene extends SceneBase {
|
|||||||
this.loadAtlas("statuses", "");
|
this.loadAtlas("statuses", "");
|
||||||
this.loadAtlas("types", "");
|
this.loadAtlas("types", "");
|
||||||
}
|
}
|
||||||
const availableLangs = ["en", "de", "it", "fr", "ja", "ko", "es-ES", "pt-BR", "zh-CN"];
|
const availableLangs = ["en", "de", "it", "fr", "ja", "ko", "es-ES", "pt-BR", "zh-CN", "zh-TW", "ca-ES"];
|
||||||
if (lang && availableLangs.includes(lang)) {
|
if (lang && availableLangs.includes(lang)) {
|
||||||
this.loadImage(`pkmnday2025event-${lang}`, "events");
|
this.loadImage(`pkmnday2025event-${lang}`, "events");
|
||||||
} else {
|
} else {
|
||||||
|
@ -5,8 +5,7 @@ import { allMoves } from "#app/data/moves/move";
|
|||||||
import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball";
|
import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball";
|
||||||
import { type FormChangeItem, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms";
|
import { type FormChangeItem, SpeciesFormChangeItemTrigger } from "#app/data/pokemon-forms";
|
||||||
import { getStatusEffectHealText } from "#app/data/status-effect";
|
import { getStatusEffectHealText } from "#app/data/status-effect";
|
||||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
import Pokemon, { type PlayerPokemon } from "#app/field/pokemon";
|
||||||
import Pokemon from "#app/field/pokemon";
|
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { EvolutionPhase } from "#app/phases/evolution-phase";
|
import { EvolutionPhase } from "#app/phases/evolution-phase";
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { applyAbAttrs, RunSuccessAbAttr } from "#app/data/ability";
|
import { applyAbAttrs, applyPreLeaveFieldAbAttrs, PreLeaveFieldAbAttr, RunSuccessAbAttr } from "#app/data/ability";
|
||||||
import { Stat } from "#app/enums/stat";
|
import { Stat } from "#app/enums/stat";
|
||||||
import { StatusEffect } from "#app/enums/status-effect";
|
import { StatusEffect } from "#app/enums/status-effect";
|
||||||
import type { PlayerPokemon, EnemyPokemon } from "#app/field/pokemon";
|
import type { PlayerPokemon, EnemyPokemon } from "#app/field/pokemon";
|
||||||
@ -29,6 +29,8 @@ export class AttemptRunPhase extends PokemonPhase {
|
|||||||
applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, false, escapeChance);
|
applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, false, escapeChance);
|
||||||
|
|
||||||
if (playerPokemon.randSeedInt(100) < escapeChance.value && !this.forceFailEscape) {
|
if (playerPokemon.randSeedInt(100) < escapeChance.value && !this.forceFailEscape) {
|
||||||
|
enemyField.forEach(enemyPokemon => applyPreLeaveFieldAbAttrs(PreLeaveFieldAbAttr, enemyPokemon));
|
||||||
|
|
||||||
globalScene.playSound("se/flee");
|
globalScene.playSound("se/flee");
|
||||||
globalScene.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500);
|
globalScene.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500);
|
||||||
|
|
||||||
|
@ -21,7 +21,7 @@ export class DamageAnimPhase extends PokemonPhase {
|
|||||||
start() {
|
start() {
|
||||||
super.start();
|
super.start();
|
||||||
|
|
||||||
if (this.damageResult === HitResult.ONE_HIT_KO) {
|
if (this.damageResult === HitResult.ONE_HIT_KO || this.damageResult === HitResult.INDIRECT_KO) {
|
||||||
if (globalScene.moveAnimations) {
|
if (globalScene.moveAnimations) {
|
||||||
globalScene.toggleInvert(true);
|
globalScene.toggleInvert(true);
|
||||||
}
|
}
|
||||||
@ -42,9 +42,11 @@ export class DamageAnimPhase extends PokemonPhase {
|
|||||||
applyDamage() {
|
applyDamage() {
|
||||||
switch (this.damageResult) {
|
switch (this.damageResult) {
|
||||||
case HitResult.EFFECTIVE:
|
case HitResult.EFFECTIVE:
|
||||||
|
case HitResult.CONFUSION:
|
||||||
globalScene.playSound("se/hit");
|
globalScene.playSound("se/hit");
|
||||||
break;
|
break;
|
||||||
case HitResult.SUPER_EFFECTIVE:
|
case HitResult.SUPER_EFFECTIVE:
|
||||||
|
case HitResult.INDIRECT_KO:
|
||||||
case HitResult.ONE_HIT_KO:
|
case HitResult.ONE_HIT_KO:
|
||||||
globalScene.playSound("se/hit_strong");
|
globalScene.playSound("se/hit_strong");
|
||||||
break;
|
break;
|
||||||
@ -57,7 +59,7 @@ export class DamageAnimPhase extends PokemonPhase {
|
|||||||
globalScene.damageNumberHandler.add(this.getPokemon(), this.amount, this.damageResult, this.critical);
|
globalScene.damageNumberHandler.add(this.getPokemon(), this.amount, this.damageResult, this.critical);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.damageResult !== HitResult.OTHER && this.amount > 0) {
|
if (this.damageResult !== HitResult.INDIRECT && this.amount > 0) {
|
||||||
const flashTimer = globalScene.time.addEvent({
|
const flashTimer = globalScene.time.addEvent({
|
||||||
delay: 100,
|
delay: 100,
|
||||||
repeat: 5,
|
repeat: 5,
|
||||||
|
@ -258,7 +258,7 @@ export class FaintPhase extends PokemonPhase {
|
|||||||
} else {
|
} else {
|
||||||
// Final boss' HP threshold has been bypassed; cancel faint and force check for 2nd phase
|
// Final boss' HP threshold has been bypassed; cancel faint and force check for 2nd phase
|
||||||
enemy.hp++;
|
enemy.hp++;
|
||||||
globalScene.unshiftPhase(new DamageAnimPhase(enemy.getBattlerIndex(), 0, HitResult.OTHER));
|
globalScene.unshiftPhase(new DamageAnimPhase(enemy.getBattlerIndex(), 0, HitResult.INDIRECT));
|
||||||
this.end();
|
this.end();
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -3,7 +3,6 @@ import type { BattlerIndex } from "#app/battle";
|
|||||||
import { CommonAnim } from "#app/data/battle-anims";
|
import { CommonAnim } from "#app/data/battle-anims";
|
||||||
import { getStatusEffectHealText } from "#app/data/status-effect";
|
import { getStatusEffectHealText } from "#app/data/status-effect";
|
||||||
import { StatusEffect } from "#app/enums/status-effect";
|
import { StatusEffect } from "#app/enums/status-effect";
|
||||||
import type { DamageResult } from "#app/field/pokemon";
|
|
||||||
import { HitResult } from "#app/field/pokemon";
|
import { HitResult } from "#app/field/pokemon";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages";
|
import { getPokemonNameWithAffix } from "#app/messages";
|
||||||
import { HealingBoosterModifier } from "#app/modifier/modifier";
|
import { HealingBoosterModifier } from "#app/modifier/modifier";
|
||||||
@ -79,7 +78,7 @@ export class PokemonHealPhase extends CommonAnimPhase {
|
|||||||
}
|
}
|
||||||
const healAmount = new Utils.NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value));
|
const healAmount = new Utils.NumberHolder(Math.floor(this.hpHealed * hpRestoreMultiplier.value));
|
||||||
if (healAmount.value < 0) {
|
if (healAmount.value < 0) {
|
||||||
pokemon.damageAndUpdate(healAmount.value * -1, HitResult.HEAL as DamageResult);
|
pokemon.damageAndUpdate(healAmount.value * -1, { result: HitResult.INDIRECT });
|
||||||
healAmount.value = 0;
|
healAmount.value = 0;
|
||||||
}
|
}
|
||||||
// Prevent healing to full if specified (in case of healing tokens so Sturdy doesn't cause a softlock)
|
// Prevent healing to full if specified (in case of healing tokens so Sturdy doesn't cause a softlock)
|
||||||
|
@ -195,6 +195,10 @@ export class SummonPhase extends PartyMemberPokemonPhase {
|
|||||||
pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 });
|
pokemon.cry(pokemon.getHpRatio() > 0.25 ? undefined : { rate: 0.85 });
|
||||||
pokemon.getSprite().clearTint();
|
pokemon.getSprite().clearTint();
|
||||||
pokemon.resetSummonData();
|
pokemon.resetSummonData();
|
||||||
|
// necessary to stay transformed during wild waves
|
||||||
|
if (pokemon.summonData?.speciesForm) {
|
||||||
|
pokemon.loadAssets(false);
|
||||||
|
}
|
||||||
globalScene.time.delayedCall(1000, () => this.end());
|
globalScene.time.delayedCall(1000, () => this.end());
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -66,7 +66,7 @@ export class WeatherEffectPhase extends CommonAnimPhase {
|
|||||||
const damage = Utils.toDmgValue(pokemon.getMaxHp() / 16);
|
const damage = Utils.toDmgValue(pokemon.getMaxHp() / 16);
|
||||||
|
|
||||||
globalScene.queueMessage(getWeatherDamageMessage(this.weather?.weatherType!, pokemon)!); // TODO: are those bangs correct?
|
globalScene.queueMessage(getWeatherDamageMessage(this.weather?.weatherType!, pokemon)!); // TODO: are those bangs correct?
|
||||||
pokemon.damageAndUpdate(damage, HitResult.EFFECTIVE, false, false, true);
|
pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT, ignoreSegments: true });
|
||||||
};
|
};
|
||||||
|
|
||||||
this.executeForAll((pokemon: Pokemon) => {
|
this.executeForAll((pokemon: Pokemon) => {
|
||||||
|
@ -3,7 +3,7 @@ import { globalScene } from "#app/global-scene";
|
|||||||
import type { Gender } from "../data/gender";
|
import type { Gender } from "../data/gender";
|
||||||
import type { Nature } from "#enums/nature";
|
import type { Nature } from "#enums/nature";
|
||||||
import type { PokeballType } from "#enums/pokeball";
|
import type { PokeballType } from "#enums/pokeball";
|
||||||
import { getPokemonSpecies } from "../data/pokemon-species";
|
import { getPokemonSpecies, getPokemonSpeciesForm } from "../data/pokemon-species";
|
||||||
import { Status } from "../data/status-effect";
|
import { Status } from "../data/status-effect";
|
||||||
import Pokemon, { EnemyPokemon, PokemonMove, PokemonSummonData } from "../field/pokemon";
|
import Pokemon, { EnemyPokemon, PokemonMove, PokemonSummonData } from "../field/pokemon";
|
||||||
import { TrainerSlot } from "../data/trainer-config";
|
import { TrainerSlot } from "../data/trainer-config";
|
||||||
@ -14,6 +14,7 @@ import { Moves } from "#enums/moves";
|
|||||||
import type { Species } from "#enums/species";
|
import type { Species } from "#enums/species";
|
||||||
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
import { CustomPokemonData } from "#app/data/custom-pokemon-data";
|
||||||
import type { PokemonType } from "#enums/pokemon-type";
|
import type { PokemonType } from "#enums/pokemon-type";
|
||||||
|
import { getSpeciesFormChangeMessage } from "#app/data/pokemon-forms";
|
||||||
|
|
||||||
export default class PokemonData {
|
export default class PokemonData {
|
||||||
public id: number;
|
public id: number;
|
||||||
@ -63,6 +64,7 @@ export default class PokemonData {
|
|||||||
public bossSegments?: number;
|
public bossSegments?: number;
|
||||||
|
|
||||||
public summonData: PokemonSummonData;
|
public summonData: PokemonSummonData;
|
||||||
|
public summonDataSpeciesFormIndex: number;
|
||||||
|
|
||||||
/** Data that can customize a Pokemon in non-standard ways from its Species */
|
/** Data that can customize a Pokemon in non-standard ways from its Species */
|
||||||
public customPokemonData: CustomPokemonData;
|
public customPokemonData: CustomPokemonData;
|
||||||
@ -145,8 +147,9 @@ export default class PokemonData {
|
|||||||
this.moveset = sourcePokemon.moveset;
|
this.moveset = sourcePokemon.moveset;
|
||||||
if (!forHistory) {
|
if (!forHistory) {
|
||||||
this.status = sourcePokemon.status;
|
this.status = sourcePokemon.status;
|
||||||
if (this.player) {
|
if (this.player && sourcePokemon.summonData) {
|
||||||
this.summonData = sourcePokemon.summonData;
|
this.summonData = sourcePokemon.summonData;
|
||||||
|
this.summonDataSpeciesFormIndex = this.getSummonDataSpeciesFormIndex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -170,6 +173,8 @@ export default class PokemonData {
|
|||||||
this.summonData.ability = source.summonData.ability;
|
this.summonData.ability = source.summonData.ability;
|
||||||
this.summonData.moveset = source.summonData.moveset?.map(m => PokemonMove.loadMove(m));
|
this.summonData.moveset = source.summonData.moveset?.map(m => PokemonMove.loadMove(m));
|
||||||
this.summonData.types = source.summonData.types;
|
this.summonData.types = source.summonData.types;
|
||||||
|
this.summonData.speciesForm = source.summonData.speciesForm;
|
||||||
|
this.summonDataSpeciesFormIndex = source.summonDataSpeciesFormIndex;
|
||||||
|
|
||||||
if (source.summonData.tags) {
|
if (source.summonData.tags) {
|
||||||
this.summonData.tags = source.summonData.tags?.map(t => loadBattlerTag(t));
|
this.summonData.tags = source.summonData.tags?.map(t => loadBattlerTag(t));
|
||||||
@ -213,8 +218,28 @@ export default class PokemonData {
|
|||||||
this,
|
this,
|
||||||
);
|
);
|
||||||
if (this.summonData) {
|
if (this.summonData) {
|
||||||
|
// when loading from saved session, recover summonData.speciesFrom and form index species object
|
||||||
|
// used to stay transformed on reload session
|
||||||
|
if (this.summonData.speciesForm) {
|
||||||
|
this.summonData.speciesForm = getPokemonSpeciesForm(
|
||||||
|
this.summonData.speciesForm.speciesId,
|
||||||
|
this.summonDataSpeciesFormIndex,
|
||||||
|
);
|
||||||
|
}
|
||||||
ret.primeSummonData(this.summonData);
|
ret.primeSummonData(this.summonData);
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to save summon data species form index
|
||||||
|
* Necessary in case the pokemon is transformed
|
||||||
|
* to reload the correct form
|
||||||
|
*/
|
||||||
|
getSummonDataSpeciesFormIndex(): number {
|
||||||
|
if (this.summonData.speciesForm) {
|
||||||
|
return this.summonData.speciesForm.formIndex;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -948,10 +948,10 @@ export function setSetting(setting: string, value: number): boolean {
|
|||||||
label: "日本語",
|
label: "日本語",
|
||||||
handler: () => changeLocaleHandler("ja"),
|
handler: () => changeLocaleHandler("ja"),
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// label: "Català",
|
label: "Català",
|
||||||
// handler: () => changeLocaleHandler("ca-ES")
|
handler: () => changeLocaleHandler("ca-ES")
|
||||||
// },
|
},
|
||||||
{
|
{
|
||||||
label: "עברית",
|
label: "עברית",
|
||||||
handler: () => changeLocaleHandler("he")
|
handler: () => changeLocaleHandler("he")
|
||||||
|
@ -574,9 +574,7 @@ export default class PartyUiHandler extends MessageUiHandler {
|
|||||||
form: pokemon.formIndex,
|
form: pokemon.formIndex,
|
||||||
female: pokemon.gender === Gender.FEMALE,
|
female: pokemon.gender === Gender.FEMALE,
|
||||||
};
|
};
|
||||||
ui.setOverlayMode(Mode.POKEDEX_PAGE, pokemon.species, pokemon.formIndex, attributes).then(() =>
|
ui.setOverlayMode(Mode.POKEDEX_PAGE, pokemon.species, attributes).then(() => this.clearOptions());
|
||||||
this.clearOptions(),
|
|
||||||
);
|
|
||||||
return true;
|
return true;
|
||||||
} else if (option === PartyOption.UNPAUSE_EVOLUTION) {
|
} else if (option === PartyOption.UNPAUSE_EVOLUTION) {
|
||||||
this.clearOptions();
|
this.clearOptions();
|
||||||
|
@ -20,7 +20,6 @@ import { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, normalForm } from
|
|||||||
import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters";
|
import { getStarterValueFriendshipCap, speciesStarterCosts } from "#app/data/balance/starters";
|
||||||
import { starterPassiveAbilities } from "#app/data/balance/passives";
|
import { starterPassiveAbilities } from "#app/data/balance/passives";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { GameModes } from "#app/game-mode";
|
|
||||||
import type { DexEntry, StarterAttributes } from "#app/system/game-data";
|
import type { DexEntry, StarterAttributes } from "#app/system/game-data";
|
||||||
import { AbilityAttr, DexAttr } from "#app/system/game-data";
|
import { AbilityAttr, DexAttr } from "#app/system/game-data";
|
||||||
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
|
||||||
@ -33,7 +32,6 @@ import { Egg } from "#app/data/egg";
|
|||||||
import Overrides from "#app/overrides";
|
import Overrides from "#app/overrides";
|
||||||
import { SettingKeyboard } from "#app/system/settings/settings-keyboard";
|
import { SettingKeyboard } from "#app/system/settings/settings-keyboard";
|
||||||
import { Passive as PassiveAttr } from "#enums/passive";
|
import { Passive as PassiveAttr } from "#enums/passive";
|
||||||
import * as Challenge from "#app/data/challenge";
|
|
||||||
import MoveInfoOverlay from "#app/ui/move-info-overlay";
|
import MoveInfoOverlay from "#app/ui/move-info-overlay";
|
||||||
import PokedexInfoOverlay from "#app/ui/pokedex-info-overlay";
|
import PokedexInfoOverlay from "#app/ui/pokedex-info-overlay";
|
||||||
import { getEggTierForSpecies } from "#app/data/egg";
|
import { getEggTierForSpecies } from "#app/data/egg";
|
||||||
@ -51,7 +49,6 @@ import {
|
|||||||
BooleanHolder,
|
BooleanHolder,
|
||||||
getLocalizedSpriteKey,
|
getLocalizedSpriteKey,
|
||||||
isNullOrUndefined,
|
isNullOrUndefined,
|
||||||
NumberHolder,
|
|
||||||
padInt,
|
padInt,
|
||||||
rgbHexToRgba,
|
rgbHexToRgba,
|
||||||
toReadableString,
|
toReadableString,
|
||||||
@ -242,6 +239,9 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
private starterAttributes: StarterAttributes;
|
private starterAttributes: StarterAttributes;
|
||||||
private savedStarterAttributes: StarterAttributes;
|
private savedStarterAttributes: StarterAttributes;
|
||||||
|
|
||||||
|
private previousSpecies: PokemonSpecies[];
|
||||||
|
private previousStarterAttributes: StarterAttributes[];
|
||||||
|
|
||||||
protected blockInput = false;
|
protected blockInput = false;
|
||||||
protected blockInputOverlay = false;
|
protected blockInputOverlay = false;
|
||||||
|
|
||||||
@ -656,6 +656,9 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
|
|
||||||
// Filter bar sits above everything, except the message box
|
// Filter bar sits above everything, except the message box
|
||||||
this.starterSelectContainer.bringToTop(this.starterSelectMessageBoxContainer);
|
this.starterSelectContainer.bringToTop(this.starterSelectMessageBoxContainer);
|
||||||
|
|
||||||
|
this.previousSpecies = [];
|
||||||
|
this.previousStarterAttributes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
show(args: any[]): boolean {
|
show(args: any[]): boolean {
|
||||||
@ -668,14 +671,14 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
this.species = args[0];
|
this.species = args[0];
|
||||||
this.formIndex = args[1] ?? 0;
|
this.savedStarterAttributes = args[1] ?? {
|
||||||
this.savedStarterAttributes = args[2] ?? {
|
|
||||||
shiny: false,
|
shiny: false,
|
||||||
female: true,
|
female: true,
|
||||||
variant: 0,
|
variant: 0,
|
||||||
form: 0,
|
form: 0,
|
||||||
};
|
};
|
||||||
this.filteredIndices = args[3] ?? null;
|
this.formIndex = this.savedStarterAttributes.form ?? 0;
|
||||||
|
this.filteredIndices = args[2] ?? null;
|
||||||
this.starterSetup();
|
this.starterSetup();
|
||||||
|
|
||||||
this.moveInfoOverlay.clear(); // clear this when removing a menu; the cancel button doesn't seem to trigger this automatically on controllers
|
this.moveInfoOverlay.clear(); // clear this when removing a menu; the cancel button doesn't seem to trigger this automatically on controllers
|
||||||
@ -1091,8 +1094,19 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
if (this.statsMode) {
|
if (this.statsMode) {
|
||||||
this.toggleStatsMode(false);
|
this.toggleStatsMode(false);
|
||||||
success = true;
|
success = true;
|
||||||
|
} else if (this.previousSpecies.length > 0) {
|
||||||
|
this.blockInput = true;
|
||||||
|
ui.setModeWithoutClear(Mode.OPTION_SELECT).then(() => {
|
||||||
|
const species = this.previousSpecies.pop();
|
||||||
|
const starterAttributes = this.previousStarterAttributes.pop();
|
||||||
|
this.moveInfoOverlay.clear();
|
||||||
|
this.clearText();
|
||||||
|
ui.setModeForceTransition(Mode.POKEDEX_PAGE, species, starterAttributes);
|
||||||
|
success = true;
|
||||||
|
});
|
||||||
|
this.blockInput = false;
|
||||||
} else {
|
} else {
|
||||||
this.getUi().revertMode();
|
ui.revertMode();
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -1507,6 +1521,8 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
? (preSpecies ?? this.species).getFormNameToDisplay(preFormIndex, true)
|
? (preSpecies ?? this.species).getFormNameToDisplay(preFormIndex, true)
|
||||||
: (preSpecies ?? this.species).getExpandedSpeciesName(),
|
: (preSpecies ?? this.species).getExpandedSpeciesName(),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
|
this.previousSpecies.push(this.species);
|
||||||
|
this.previousStarterAttributes.push({ ...this.savedStarterAttributes });
|
||||||
const newSpecies = allSpecies.find(
|
const newSpecies = allSpecies.find(
|
||||||
species => species.speciesId === pokemonPrevolutions[pre.speciesId],
|
species => species.speciesId === pokemonPrevolutions[pre.speciesId],
|
||||||
);
|
);
|
||||||
@ -1522,7 +1538,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
this.savedStarterAttributes.form = newFormIndex;
|
this.savedStarterAttributes.form = newFormIndex;
|
||||||
this.moveInfoOverlay.clear();
|
this.moveInfoOverlay.clear();
|
||||||
this.clearText();
|
this.clearText();
|
||||||
ui.setMode(Mode.POKEDEX_PAGE, newSpecies, newFormIndex, this.savedStarterAttributes);
|
ui.setMode(Mode.POKEDEX_PAGE, newSpecies, this.savedStarterAttributes);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
onHover: () => this.showText(conditionText),
|
onHover: () => this.showText(conditionText),
|
||||||
@ -1558,11 +1574,13 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
: (evoSpecies ?? this.species).getExpandedSpeciesName(),
|
: (evoSpecies ?? this.species).getExpandedSpeciesName(),
|
||||||
style: isCaughtEvo && isFormCaughtEvo ? TextStyle.WINDOW : TextStyle.SHADOW_TEXT,
|
style: isCaughtEvo && isFormCaughtEvo ? TextStyle.WINDOW : TextStyle.SHADOW_TEXT,
|
||||||
handler: () => {
|
handler: () => {
|
||||||
|
this.previousSpecies.push(this.species);
|
||||||
|
this.previousStarterAttributes.push({ ...this.savedStarterAttributes });
|
||||||
this.starterAttributes.form = newFormIndex;
|
this.starterAttributes.form = newFormIndex;
|
||||||
this.savedStarterAttributes.form = newFormIndex;
|
this.savedStarterAttributes.form = newFormIndex;
|
||||||
this.moveInfoOverlay.clear();
|
this.moveInfoOverlay.clear();
|
||||||
this.clearText();
|
this.clearText();
|
||||||
ui.setMode(Mode.POKEDEX_PAGE, evoSpecies, newFormIndex, this.savedStarterAttributes);
|
ui.setMode(Mode.POKEDEX_PAGE, evoSpecies, this.savedStarterAttributes);
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
onHover: () => this.showText(conditionText),
|
onHover: () => this.showText(conditionText),
|
||||||
@ -1598,6 +1616,8 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
label: label,
|
label: label,
|
||||||
style: isFormCaught ? TextStyle.WINDOW : TextStyle.SHADOW_TEXT,
|
style: isFormCaught ? TextStyle.WINDOW : TextStyle.SHADOW_TEXT,
|
||||||
handler: () => {
|
handler: () => {
|
||||||
|
this.previousSpecies.push(this.species);
|
||||||
|
this.previousStarterAttributes.push({ ...this.savedStarterAttributes });
|
||||||
const newSpecies = this.species;
|
const newSpecies = this.species;
|
||||||
const newFormIndex = this.species.forms.find(f => f.formKey === bf.formKey)?.formIndex;
|
const newFormIndex = this.species.forms.find(f => f.formKey === bf.formKey)?.formIndex;
|
||||||
this.starterAttributes.form = newFormIndex;
|
this.starterAttributes.form = newFormIndex;
|
||||||
@ -1607,7 +1627,6 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
ui.setMode(
|
ui.setMode(
|
||||||
Mode.POKEDEX_PAGE,
|
Mode.POKEDEX_PAGE,
|
||||||
newSpecies,
|
newSpecies,
|
||||||
newFormIndex,
|
|
||||||
this.savedStarterAttributes,
|
this.savedStarterAttributes,
|
||||||
this.filteredIndices,
|
this.filteredIndices,
|
||||||
);
|
);
|
||||||
@ -1958,6 +1977,11 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
case Button.LEFT:
|
case Button.LEFT:
|
||||||
this.blockInput = true;
|
this.blockInput = true;
|
||||||
ui.setModeWithoutClear(Mode.OPTION_SELECT).then(() => {
|
ui.setModeWithoutClear(Mode.OPTION_SELECT).then(() => {
|
||||||
|
// Always go back to first selection after scrolling around
|
||||||
|
if (this.previousSpecies.length === 0) {
|
||||||
|
this.previousSpecies.push(this.species);
|
||||||
|
this.previousStarterAttributes.push({ ...this.savedStarterAttributes });
|
||||||
|
}
|
||||||
let newSpecies: PokemonSpecies;
|
let newSpecies: PokemonSpecies;
|
||||||
if (this.filteredIndices) {
|
if (this.filteredIndices) {
|
||||||
const index = this.filteredIndices.findIndex(id => id === this.species.speciesId);
|
const index = this.filteredIndices.findIndex(id => id === this.species.speciesId);
|
||||||
@ -1979,7 +2003,6 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
ui.setModeForceTransition(
|
ui.setModeForceTransition(
|
||||||
Mode.POKEDEX_PAGE,
|
Mode.POKEDEX_PAGE,
|
||||||
newSpecies,
|
newSpecies,
|
||||||
newFormIndex,
|
|
||||||
this.savedStarterAttributes,
|
this.savedStarterAttributes,
|
||||||
this.filteredIndices,
|
this.filteredIndices,
|
||||||
);
|
);
|
||||||
@ -1988,6 +2011,11 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
break;
|
break;
|
||||||
case Button.RIGHT:
|
case Button.RIGHT:
|
||||||
ui.setModeWithoutClear(Mode.OPTION_SELECT).then(() => {
|
ui.setModeWithoutClear(Mode.OPTION_SELECT).then(() => {
|
||||||
|
// Always go back to first selection after scrolling around
|
||||||
|
if (this.previousSpecies.length === 0) {
|
||||||
|
this.previousSpecies.push(this.species);
|
||||||
|
this.previousStarterAttributes.push({ ...this.savedStarterAttributes });
|
||||||
|
}
|
||||||
let newSpecies: PokemonSpecies;
|
let newSpecies: PokemonSpecies;
|
||||||
if (this.filteredIndices) {
|
if (this.filteredIndices) {
|
||||||
const index = this.filteredIndices.findIndex(id => id === this.species.speciesId);
|
const index = this.filteredIndices.findIndex(id => id === this.species.speciesId);
|
||||||
@ -2009,7 +2037,6 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
ui.setModeForceTransition(
|
ui.setModeForceTransition(
|
||||||
Mode.POKEDEX_PAGE,
|
Mode.POKEDEX_PAGE,
|
||||||
newSpecies,
|
newSpecies,
|
||||||
newFormIndex,
|
|
||||||
this.savedStarterAttributes,
|
this.savedStarterAttributes,
|
||||||
this.filteredIndices,
|
this.filteredIndices,
|
||||||
);
|
);
|
||||||
@ -2128,22 +2155,6 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getValueLimit(): number {
|
|
||||||
const valueLimit = new NumberHolder(0);
|
|
||||||
switch (globalScene.gameMode.modeId) {
|
|
||||||
case GameModes.ENDLESS:
|
|
||||||
case GameModes.SPLICED_ENDLESS:
|
|
||||||
valueLimit.value = 15;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
valueLimit.value = 10;
|
|
||||||
}
|
|
||||||
|
|
||||||
Challenge.applyChallenges(globalScene.gameMode, Challenge.ChallengeType.STARTER_POINTS, valueLimit);
|
|
||||||
|
|
||||||
return valueLimit.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
setCursor(cursor: number): boolean {
|
setCursor(cursor: number): boolean {
|
||||||
const ret = super.setCursor(cursor);
|
const ret = super.setCursor(cursor);
|
||||||
|
|
||||||
|
@ -1125,7 +1125,7 @@ export default class PokedexUiHandler extends MessageUiHandler {
|
|||||||
} else if (this.showingTray) {
|
} else if (this.showingTray) {
|
||||||
if (button === Button.ACTION) {
|
if (button === Button.ACTION) {
|
||||||
const formIndex = this.trayForms[this.trayCursor].formIndex;
|
const formIndex = this.trayForms[this.trayCursor].formIndex;
|
||||||
ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, formIndex, { form: formIndex }, this.filteredIndices);
|
ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, { form: formIndex }, this.filteredIndices);
|
||||||
success = true;
|
success = true;
|
||||||
} else {
|
} else {
|
||||||
const numberOfForms = this.trayContainers.length;
|
const numberOfForms = this.trayContainers.length;
|
||||||
@ -1174,7 +1174,7 @@ export default class PokedexUiHandler extends MessageUiHandler {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (button === Button.ACTION) {
|
if (button === Button.ACTION) {
|
||||||
ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, 0, null, this.filteredIndices);
|
ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, null, this.filteredIndices);
|
||||||
success = true;
|
success = true;
|
||||||
} else {
|
} else {
|
||||||
switch (button) {
|
switch (button) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { CandyUpgradeNotificationChangedEvent } from "#app/events/battle-scene";
|
import type { CandyUpgradeNotificationChangedEvent } from "#app/events/battle-scene";
|
||||||
import { BattleSceneEventType } from "#app/events/battle-scene";
|
import { BattleSceneEventType } from "#app/events/battle-scene";
|
||||||
import { pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
|
import { pokemonEvolutions, pokemonPrevolutions } from "#app/data/balance/pokemon-evolutions";
|
||||||
import type { Variant } from "#app/data/variant";
|
import type { Variant } from "#app/data/variant";
|
||||||
import { getVariantTint, getVariantIcon } from "#app/data/variant";
|
import { getVariantTint, getVariantIcon } from "#app/data/variant";
|
||||||
import { argbFromRgba } from "@material/material-color-utilities";
|
import { argbFromRgba } from "@material/material-color-utilities";
|
||||||
@ -19,7 +19,7 @@ import { pokemonFormChanges } from "#app/data/pokemon-forms";
|
|||||||
import type { LevelMoves } from "#app/data/balance/pokemon-level-moves";
|
import type { LevelMoves } from "#app/data/balance/pokemon-level-moves";
|
||||||
import { pokemonFormLevelMoves, pokemonSpeciesLevelMoves } from "#app/data/balance/pokemon-level-moves";
|
import { pokemonFormLevelMoves, pokemonSpeciesLevelMoves } from "#app/data/balance/pokemon-level-moves";
|
||||||
import type PokemonSpecies from "#app/data/pokemon-species";
|
import type PokemonSpecies from "#app/data/pokemon-species";
|
||||||
import { allSpecies, getPokemonSpeciesForm, getPokerusStarters } from "#app/data/pokemon-species";
|
import { allSpecies, getPokemonSpecies, getPokemonSpeciesForm, getPokerusStarters } from "#app/data/pokemon-species";
|
||||||
import { getStarterValueFriendshipCap, speciesStarterCosts, POKERUS_STARTER_COUNT } from "#app/data/balance/starters";
|
import { getStarterValueFriendshipCap, speciesStarterCosts, POKERUS_STARTER_COUNT } from "#app/data/balance/starters";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { GameModes } from "#app/game-mode";
|
import { GameModes } from "#app/game-mode";
|
||||||
@ -80,6 +80,7 @@ import { PLAYER_PARTY_MAX_SIZE } from "#app/constants";
|
|||||||
import { achvs } from "#app/system/achv";
|
import { achvs } from "#app/system/achv";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import type { GameObjects } from "phaser";
|
import type { GameObjects } from "phaser";
|
||||||
|
import { checkStarterValidForChallenge } from "#app/data/challenge";
|
||||||
|
|
||||||
export type StarterSelectCallback = (starters: Starter[]) => void;
|
export type StarterSelectCallback = (starters: Starter[]) => void;
|
||||||
|
|
||||||
@ -149,7 +150,7 @@ const languageSettings: { [key: string]: LanguageSetting } = {
|
|||||||
instructionTextSize: "38px",
|
instructionTextSize: "38px",
|
||||||
},
|
},
|
||||||
"ca-ES": {
|
"ca-ES": {
|
||||||
starterInfoTextSize: "56px",
|
starterInfoTextSize: "52px",
|
||||||
instructionTextSize: "38px",
|
instructionTextSize: "38px",
|
||||||
},
|
},
|
||||||
"he":{
|
"he":{
|
||||||
@ -1764,21 +1765,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
const species = starter.species;
|
const species = starter.species;
|
||||||
const [isDupe] = this.isInParty(species);
|
const [isDupe] = this.isInParty(species);
|
||||||
const starterCost = globalScene.gameData.getSpeciesStarterValue(species.speciesId);
|
const starterCost = globalScene.gameData.getSpeciesStarterValue(species.speciesId);
|
||||||
const isValidForChallenge = new BooleanHolder(true);
|
const isValidForChallenge = checkStarterValidForChallenge(
|
||||||
Challenge.applyChallenges(
|
|
||||||
globalScene.gameMode,
|
|
||||||
Challenge.ChallengeType.STARTER_CHOICE,
|
|
||||||
species,
|
species,
|
||||||
isValidForChallenge,
|
|
||||||
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
|
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
|
||||||
this.isPartyValid(),
|
this.isPartyValid(),
|
||||||
);
|
);
|
||||||
const isCaught = globalScene.gameData.dexData[species.speciesId].caughtAttr;
|
const isCaught = globalScene.gameData.dexData[species.speciesId].caughtAttr;
|
||||||
return (
|
return (
|
||||||
!isDupe &&
|
!isDupe && isValidForChallenge && currentPartyValue + starterCost <= this.getValueLimit() && isCaught
|
||||||
isValidForChallenge.value &&
|
|
||||||
currentPartyValue + starterCost <= this.getValueLimit() &&
|
|
||||||
isCaught
|
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
if (validStarters.length === 0) {
|
if (validStarters.length === 0) {
|
||||||
@ -1865,16 +1859,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
const ui = this.getUi();
|
const ui = this.getUi();
|
||||||
let options: any[] = []; // TODO: add proper type
|
let options: any[] = []; // TODO: add proper type
|
||||||
|
|
||||||
const [isDupe, removeIndex]: [boolean, number] = this.isInParty(this.lastSpecies); // checks to see if the pokemon is a duplicate; if it is, returns the index that will be removed
|
const [isDupe, removeIndex]: [boolean, number] = this.isInParty(this.lastSpecies);
|
||||||
|
|
||||||
const isPartyValid = this.isPartyValid();
|
const isPartyValid = this.isPartyValid();
|
||||||
const isValidForChallenge = new BooleanHolder(true);
|
const isValidForChallenge = checkStarterValidForChallenge(
|
||||||
|
|
||||||
Challenge.applyChallenges(
|
|
||||||
globalScene.gameMode,
|
|
||||||
Challenge.ChallengeType.STARTER_CHOICE,
|
|
||||||
this.lastSpecies,
|
this.lastSpecies,
|
||||||
isValidForChallenge,
|
|
||||||
globalScene.gameData.getSpeciesDexAttrProps(
|
globalScene.gameData.getSpeciesDexAttrProps(
|
||||||
this.lastSpecies,
|
this.lastSpecies,
|
||||||
this.getCurrentDexProps(this.lastSpecies.speciesId),
|
this.getCurrentDexProps(this.lastSpecies.speciesId),
|
||||||
@ -1892,11 +1881,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
const newCost = globalScene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId);
|
const newCost = globalScene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId);
|
||||||
if (
|
if (
|
||||||
!isDupe &&
|
!isDupe &&
|
||||||
isValidForChallenge.value &&
|
isValidForChallenge &&
|
||||||
currentPartyValue + newCost <= this.getValueLimit() &&
|
currentPartyValue + newCost <= this.getValueLimit() &&
|
||||||
this.starterSpecies.length < PLAYER_PARTY_MAX_SIZE
|
this.starterSpecies.length < PLAYER_PARTY_MAX_SIZE
|
||||||
) {
|
) {
|
||||||
// this checks to make sure the pokemon doesn't exist in your party, it's valid for the challenge and that it won't go over the cost limit; if it meets all these criteria it will add it to your party
|
|
||||||
options = [
|
options = [
|
||||||
{
|
{
|
||||||
label: i18next.t("starterSelectUiHandler:addToParty"),
|
label: i18next.t("starterSelectUiHandler:addToParty"),
|
||||||
@ -1906,7 +1894,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
globalScene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId),
|
globalScene.gameData.getSpeciesStarterValue(this.lastSpecies.speciesId),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
if (!isDupe && isValidForChallenge.value && isOverValueLimit) {
|
if (!isDupe && isValidForChallenge && isOverValueLimit) {
|
||||||
const cursorObj = this.starterCursorObjs[this.starterSpecies.length];
|
const cursorObj = this.starterCursorObjs[this.starterSpecies.length];
|
||||||
cursorObj.setVisible(true);
|
cursorObj.setVisible(true);
|
||||||
cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y);
|
cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y);
|
||||||
@ -2340,7 +2328,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
form: starterAttributes.form,
|
form: starterAttributes.form,
|
||||||
female: starterAttributes.female,
|
female: starterAttributes.female,
|
||||||
};
|
};
|
||||||
ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, starterAttributes.form, attributes);
|
ui.setOverlayMode(Mode.POKEDEX_PAGE, this.lastSpecies, attributes);
|
||||||
});
|
});
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@ -2997,32 +2985,27 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
/* Here we are making a fake form index dex props for challenges
|
/* Here we are making a fake form index dex props for challenges
|
||||||
* Since some pokemon rely on forms to be valid (i.e. blaze tauros for fire challenges), we make a fake form and dex props to use in the challenge
|
* Since some pokemon rely on forms to be valid (i.e. blaze tauros for fire challenges), we make a fake form and dex props to use in the challenge
|
||||||
*/
|
*/
|
||||||
|
if (!species.forms[i].isStarterSelectable) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
const tempFormProps = BigInt(Math.pow(2, i)) * DexAttr.DEFAULT_FORM;
|
const tempFormProps = BigInt(Math.pow(2, i)) * DexAttr.DEFAULT_FORM;
|
||||||
const isValidForChallenge = new BooleanHolder(true);
|
const isValidForChallenge = checkStarterValidForChallenge(
|
||||||
Challenge.applyChallenges(
|
|
||||||
globalScene.gameMode,
|
|
||||||
Challenge.ChallengeType.STARTER_CHOICE,
|
|
||||||
container.species,
|
container.species,
|
||||||
isValidForChallenge,
|
|
||||||
globalScene.gameData.getSpeciesDexAttrProps(species, tempFormProps),
|
globalScene.gameData.getSpeciesDexAttrProps(species, tempFormProps),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
allFormsValid = allFormsValid || isValidForChallenge.value;
|
allFormsValid = allFormsValid || isValidForChallenge;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const isValidForChallenge = new BooleanHolder(true);
|
const isValidForChallenge = checkStarterValidForChallenge(
|
||||||
Challenge.applyChallenges(
|
|
||||||
globalScene.gameMode,
|
|
||||||
Challenge.ChallengeType.STARTER_CHOICE,
|
|
||||||
container.species,
|
container.species,
|
||||||
isValidForChallenge,
|
|
||||||
globalScene.gameData.getSpeciesDexAttrProps(
|
globalScene.gameData.getSpeciesDexAttrProps(
|
||||||
species,
|
species,
|
||||||
globalScene.gameData.getSpeciesDefaultDexAttr(container.species, false, true),
|
globalScene.gameData.getSpeciesDefaultDexAttr(container.species, false, true),
|
||||||
),
|
),
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
allFormsValid = isValidForChallenge.value;
|
allFormsValid = isValidForChallenge;
|
||||||
}
|
}
|
||||||
if (allFormsValid) {
|
if (allFormsValid) {
|
||||||
this.validStarterContainers.push(container);
|
this.validStarterContainers.push(container);
|
||||||
@ -3855,15 +3838,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonSprite.setVisible(!this.statsMode);
|
this.pokemonSprite.setVisible(!this.statsMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
const isValidForChallenge = new BooleanHolder(true);
|
|
||||||
Challenge.applyChallenges(
|
|
||||||
globalScene.gameMode,
|
|
||||||
Challenge.ChallengeType.STARTER_CHOICE,
|
|
||||||
species,
|
|
||||||
isValidForChallenge,
|
|
||||||
globalScene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor),
|
|
||||||
!!this.starterSpecies.length,
|
|
||||||
);
|
|
||||||
const currentFilteredContainer = this.filteredStarterContainers.find(
|
const currentFilteredContainer = this.filteredStarterContainers.find(
|
||||||
p => p.species.speciesId === species.speciesId,
|
p => p.species.speciesId === species.speciesId,
|
||||||
);
|
);
|
||||||
@ -4237,20 +4211,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
globalScene.time.delayedCall(fixedInt(500), () => this.tryUpdateValue());
|
globalScene.time.delayedCall(fixedInt(500), () => this.tryUpdateValue());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
let isPartyValid: boolean = this.isPartyValid(); // this checks to see if the party is valid
|
let isPartyValid: boolean = this.isPartyValid();
|
||||||
if (addingToParty) {
|
if (addingToParty) {
|
||||||
// this does a check to see if the pokemon being added is valid; if so, it will update the isPartyValid boolean
|
|
||||||
const isNewPokemonValid = new BooleanHolder(true);
|
|
||||||
const species = this.filteredStarterContainers[this.cursor].species;
|
const species = this.filteredStarterContainers[this.cursor].species;
|
||||||
Challenge.applyChallenges(
|
const isNewPokemonValid = checkStarterValidForChallenge(
|
||||||
globalScene.gameMode,
|
|
||||||
Challenge.ChallengeType.STARTER_CHOICE,
|
|
||||||
species,
|
species,
|
||||||
isNewPokemonValid,
|
|
||||||
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
|
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
isPartyValid = isPartyValid || isNewPokemonValid.value;
|
isPartyValid = isPartyValid || isNewPokemonValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -4274,12 +4243,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
* If speciesStarterDexEntry?.caughtAttr is true, this species registered in stater.
|
* If speciesStarterDexEntry?.caughtAttr is true, this species registered in stater.
|
||||||
* we change to can AddParty value to true since the user has enough cost to choose this pokemon and this pokemon registered too.
|
* we change to can AddParty value to true since the user has enough cost to choose this pokemon and this pokemon registered too.
|
||||||
*/
|
*/
|
||||||
const isValidForChallenge = new BooleanHolder(true);
|
const isValidForChallenge = checkStarterValidForChallenge(
|
||||||
Challenge.applyChallenges(
|
|
||||||
globalScene.gameMode,
|
|
||||||
Challenge.ChallengeType.STARTER_CHOICE,
|
|
||||||
this.allSpecies[s],
|
this.allSpecies[s],
|
||||||
isValidForChallenge,
|
|
||||||
globalScene.gameData.getSpeciesDexAttrProps(
|
globalScene.gameData.getSpeciesDexAttrProps(
|
||||||
this.allSpecies[s],
|
this.allSpecies[s],
|
||||||
this.getCurrentDexProps(this.allSpecies[s].speciesId),
|
this.getCurrentDexProps(this.allSpecies[s].speciesId),
|
||||||
@ -4287,7 +4252,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
isPartyValid,
|
isPartyValid,
|
||||||
);
|
);
|
||||||
|
|
||||||
const canBeChosen = remainValue >= speciesStarterValue && isValidForChallenge.value;
|
const canBeChosen = remainValue >= speciesStarterValue && isValidForChallenge;
|
||||||
|
|
||||||
const isPokemonInParty = this.isInParty(this.allSpecies[s])[0]; // this will get the valud of isDupe from isInParty. This will let us see if the pokemon in question is in our party already so we don't grey out the sprites if they're invalid
|
const isPokemonInParty = this.isInParty(this.allSpecies[s])[0]; // this will get the valud of isDupe from isInParty. This will let us see if the pokemon in question is in our party already so we don't grey out the sprites if they're invalid
|
||||||
|
|
||||||
@ -4421,17 +4386,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
isPartyValid(): boolean {
|
isPartyValid(): boolean {
|
||||||
let canStart = false;
|
let canStart = false;
|
||||||
for (let s = 0; s < this.starterSpecies.length; s++) {
|
for (let s = 0; s < this.starterSpecies.length; s++) {
|
||||||
const isValidForChallenge = new BooleanHolder(true);
|
|
||||||
const species = this.starterSpecies[s];
|
const species = this.starterSpecies[s];
|
||||||
Challenge.applyChallenges(
|
const isValidForChallenge = checkStarterValidForChallenge(
|
||||||
globalScene.gameMode,
|
|
||||||
Challenge.ChallengeType.STARTER_CHOICE,
|
|
||||||
species,
|
species,
|
||||||
isValidForChallenge,
|
|
||||||
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
|
globalScene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)),
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
canStart = canStart || isValidForChallenge.value;
|
canStart = canStart || isValidForChallenge;
|
||||||
}
|
}
|
||||||
return canStart;
|
return canStart;
|
||||||
}
|
}
|
||||||
|
@ -465,6 +465,7 @@ export function hasAllLocalizedSprites(lang?: string): boolean {
|
|||||||
case "pt-BR":
|
case "pt-BR":
|
||||||
case "ko":
|
case "ko":
|
||||||
case "ja":
|
case "ja":
|
||||||
|
case "ca-ES":
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
import { PokeballType } from "#app/enums/pokeball";
|
import { PokeballType } from "#app/enums/pokeball";
|
||||||
import { WeatherType } from "#app/enums/weather-type";
|
import { WeatherType } from "#app/enums/weather-type";
|
||||||
|
import type { CommandPhase } from "#app/phases/command-phase";
|
||||||
|
import { Command } from "#app/ui/command-ui-handler";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
@ -131,4 +133,20 @@ describe("Abilities - Desolate Land", () => {
|
|||||||
|
|
||||||
expect(game.scene.arena.weather?.weatherType).not.toBe(WeatherType.HARSH_SUN);
|
expect(game.scene.arena.weather?.weatherType).not.toBe(WeatherType.HARSH_SUN);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should lift after fleeing from a wild pokemon", async () => {
|
||||||
|
game.override
|
||||||
|
.enemyAbility(Abilities.DESOLATE_LAND)
|
||||||
|
.ability(Abilities.BALL_FETCH);
|
||||||
|
await game.classicMode.startBattle([ Species.MAGIKARP ]);
|
||||||
|
expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.HARSH_SUN);
|
||||||
|
|
||||||
|
vi.spyOn(game.scene.getPlayerPokemon()!, "randSeedInt").mockReturnValue(0);
|
||||||
|
|
||||||
|
const commandPhase = game.scene.getCurrentPhase() as CommandPhase;
|
||||||
|
commandPhase.handleCommand(Command.RUN, 0);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.arena.weather?.weatherType).not.toBe(WeatherType.HARSH_SUN);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -127,4 +127,63 @@ describe("Abilities - Imposter", () => {
|
|||||||
|
|
||||||
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should persist transformed attributes across reloads", async () => {
|
||||||
|
game.override.moveset([Moves.ABSORB]);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.DITTO]);
|
||||||
|
|
||||||
|
const player = game.scene.getPlayerPokemon()!;
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.doKillOpponents();
|
||||||
|
await game.toNextWave();
|
||||||
|
|
||||||
|
expect(game.scene.getCurrentPhase()?.constructor.name).toBe("CommandPhase");
|
||||||
|
expect(game.scene.currentBattle.waveIndex).toBe(2);
|
||||||
|
|
||||||
|
await game.reload.reloadSession();
|
||||||
|
|
||||||
|
const playerReloaded = game.scene.getPlayerPokemon()!;
|
||||||
|
const playerMoveset = player.getMoveset();
|
||||||
|
|
||||||
|
expect(playerReloaded.getSpeciesForm().speciesId).toBe(enemy.getSpeciesForm().speciesId);
|
||||||
|
expect(playerReloaded.getAbility()).toBe(enemy.getAbility());
|
||||||
|
expect(playerReloaded.getGender()).toBe(enemy.getGender());
|
||||||
|
|
||||||
|
expect(playerReloaded.getStat(Stat.HP, false)).not.toBe(enemy.getStat(Stat.HP));
|
||||||
|
for (const s of EFFECTIVE_STATS) {
|
||||||
|
expect(playerReloaded.getStat(s, false)).toBe(enemy.getStat(s, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(playerMoveset.length).toEqual(1);
|
||||||
|
expect(playerMoveset[0]?.moveId).toEqual(Moves.SPLASH);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should stay transformed with the correct form after reload", async () => {
|
||||||
|
game.override.moveset([Moves.ABSORB]);
|
||||||
|
game.override.enemySpecies(Species.UNOWN);
|
||||||
|
await game.classicMode.startBattle([Species.DITTO]);
|
||||||
|
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
// change form
|
||||||
|
enemy.species.forms[5];
|
||||||
|
enemy.species.formIndex = 5;
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
await game.doKillOpponents();
|
||||||
|
await game.toNextWave();
|
||||||
|
|
||||||
|
expect(game.scene.getCurrentPhase()?.constructor.name).toBe("CommandPhase");
|
||||||
|
expect(game.scene.currentBattle.waveIndex).toBe(2);
|
||||||
|
|
||||||
|
await game.reload.reloadSession();
|
||||||
|
|
||||||
|
const playerReloaded = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
|
expect(playerReloaded.getSpeciesForm().speciesId).toBe(enemy.getSpeciesForm().speciesId);
|
||||||
|
expect(playerReloaded.getSpeciesForm().formIndex).toBe(enemy.getSpeciesForm().formIndex);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,6 @@
|
|||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import type { CommandPhase } from "#app/phases/command-phase";
|
||||||
|
import { Command } from "#app/ui/command-ui-handler";
|
||||||
import { PostSummonWeatherChangeAbAttr } from "#app/data/ability";
|
import { PostSummonWeatherChangeAbAttr } from "#app/data/ability";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { ArenaTagType } from "#enums/arena-tag-type";
|
import { ArenaTagType } from "#enums/arena-tag-type";
|
||||||
@ -157,6 +159,22 @@ describe("Abilities - Neutralizing Gas", () => {
|
|||||||
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined();
|
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should deactivate after fleeing from a wild pokemon", async () => {
|
||||||
|
game.override
|
||||||
|
.enemyAbility(Abilities.NEUTRALIZING_GAS)
|
||||||
|
.ability(Abilities.BALL_FETCH);
|
||||||
|
await game.classicMode.startBattle([ Species.MAGIKARP ]);
|
||||||
|
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeDefined();
|
||||||
|
|
||||||
|
vi.spyOn(game.scene.getPlayerPokemon()!, "randSeedInt").mockReturnValue(0);
|
||||||
|
|
||||||
|
const commandPhase = game.scene.getCurrentPhase() as CommandPhase;
|
||||||
|
commandPhase.handleCommand(Command.RUN, 0);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(game.scene.arena.getTag(ArenaTagType.NEUTRALIZING_GAS)).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
it("should not activate abilities of pokemon no longer on the field", async () => {
|
it("should not activate abilities of pokemon no longer on the field", async () => {
|
||||||
game.override
|
game.override
|
||||||
.battleType("single")
|
.battleType("single")
|
||||||
|
159
test/items/reviver_seed.test.ts
Normal file
159
test/items/reviver_seed.test.ts
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { allMoves } from "#app/data/moves/move";
|
||||||
|
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
||||||
|
import type { PokemonInstantReviveModifier } from "#app/modifier/modifier";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/testUtils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
|
describe("Items - Reviver Seed", () => {
|
||||||
|
let phaserGame: Phaser.Game;
|
||||||
|
let game: GameManager;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
phaserGame = new Phaser.Game({
|
||||||
|
type: Phaser.HEADLESS,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
game.phaseInterceptor.restoreOg();
|
||||||
|
});
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
game = new GameManager(phaserGame);
|
||||||
|
game.override
|
||||||
|
.moveset([ Moves.SPLASH, Moves.TACKLE, Moves.ENDURE ])
|
||||||
|
.ability(Abilities.BALL_FETCH)
|
||||||
|
.battleType("single")
|
||||||
|
.disableCrits()
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
|
.startingHeldItems([{ name: "REVIVER_SEED" }])
|
||||||
|
.enemyHeldItems([{ name: "REVIVER_SEED" }])
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
vi.spyOn(allMoves[Moves.SHEER_COLD], "accuracy", "get").mockReturnValue(100);
|
||||||
|
vi.spyOn(allMoves[Moves.LEECH_SEED], "accuracy", "get").mockReturnValue(100);
|
||||||
|
vi.spyOn(allMoves[Moves.WHIRLPOOL], "accuracy", "get").mockReturnValue(100);
|
||||||
|
vi.spyOn(allMoves[Moves.WILL_O_WISP], "accuracy", "get").mockReturnValue(100);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
{ moveType: "Special Move", move: Moves.WATER_GUN },
|
||||||
|
{ moveType: "Physical Move", move: Moves.TACKLE },
|
||||||
|
{ moveType: "Fixed Damage Move", move: Moves.SEISMIC_TOSS },
|
||||||
|
{ moveType: "Final Gambit", move: Moves.FINAL_GAMBIT },
|
||||||
|
{ moveType: "Counter", move: Moves.COUNTER },
|
||||||
|
{ moveType: "OHKO", move: Moves.SHEER_COLD }
|
||||||
|
])("should activate the holder's reviver seed from a $moveType", async ({ move }) => {
|
||||||
|
game.override
|
||||||
|
.enemyLevel(100)
|
||||||
|
.startingLevel(1)
|
||||||
|
.enemyMoveset(move);
|
||||||
|
await game.classicMode.startBattle([ Species.MAGIKARP, Species.FEEBAS ]);
|
||||||
|
const player = game.scene.getPlayerPokemon()!;
|
||||||
|
player.damageAndUpdate(player.hp - 1);
|
||||||
|
|
||||||
|
const reviverSeed = player.getHeldItems()[0] as PokemonInstantReviveModifier;
|
||||||
|
vi.spyOn(reviverSeed, "apply");
|
||||||
|
|
||||||
|
game.move.select(Moves.TACKLE);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(player.isFainted()).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should activate the holder's reviver seed from confusion self-hit", async () => {
|
||||||
|
game.override
|
||||||
|
.enemyLevel(1)
|
||||||
|
.startingLevel(100)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
await game.classicMode.startBattle([ Species.MAGIKARP, Species.FEEBAS ]);
|
||||||
|
const player = game.scene.getPlayerPokemon()!;
|
||||||
|
player.damageAndUpdate(player.hp - 1);
|
||||||
|
player.addTag(BattlerTagType.CONFUSED, 3);
|
||||||
|
|
||||||
|
const reviverSeed = player.getHeldItems()[0] as PokemonInstantReviveModifier;
|
||||||
|
vi.spyOn(reviverSeed, "apply");
|
||||||
|
|
||||||
|
vi.spyOn(player, "randSeedInt").mockReturnValue(0); // Force confusion self-hit
|
||||||
|
game.move.select(Moves.TACKLE);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
expect(player.isFainted()).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Damaging opponents tests
|
||||||
|
it.each([
|
||||||
|
{ moveType: "Damaging Move Chip Damage", move: Moves.SALT_CURE },
|
||||||
|
{ moveType: "Chip Damage", move: Moves.LEECH_SEED },
|
||||||
|
{ moveType: "Trapping Chip Damage", move: Moves.WHIRLPOOL },
|
||||||
|
{ moveType: "Status Effect Damage", move: Moves.WILL_O_WISP },
|
||||||
|
{ moveType: "Weather", move: Moves.SANDSTORM },
|
||||||
|
])("should not activate the holder's reviver seed from $moveType", async ({ move }) => {
|
||||||
|
game.override
|
||||||
|
.enemyLevel(1)
|
||||||
|
.startingLevel(100)
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.moveset(move)
|
||||||
|
.enemyMoveset(Moves.ENDURE);
|
||||||
|
await game.classicMode.startBattle([ Species.MAGIKARP, Species.FEEBAS ]);
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
enemy.damageAndUpdate(enemy.hp - 1);
|
||||||
|
|
||||||
|
game.move.select(move);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(enemy.isFainted()).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Self-damage tests
|
||||||
|
it.each([
|
||||||
|
{ moveType: "Recoil", move: Moves.DOUBLE_EDGE },
|
||||||
|
{ moveType: "Self-KO", move: Moves.EXPLOSION },
|
||||||
|
{ moveType: "Self-Deduction", move: Moves.CURSE },
|
||||||
|
{ moveType: "Liquid Ooze", move: Moves.GIGA_DRAIN },
|
||||||
|
])("should not activate the holder's reviver seed from $moveType", async ({ move }) => {
|
||||||
|
game.override
|
||||||
|
.enemyLevel(100)
|
||||||
|
.startingLevel(1)
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.moveset(move)
|
||||||
|
.enemyAbility(Abilities.LIQUID_OOZE)
|
||||||
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
await game.classicMode.startBattle([ Species.GASTLY, Species.FEEBAS ]);
|
||||||
|
const player = game.scene.getPlayerPokemon()!;
|
||||||
|
player.damageAndUpdate(player.hp - 1);
|
||||||
|
|
||||||
|
const playerSeed = player.getHeldItems()[0] as PokemonInstantReviveModifier;
|
||||||
|
vi.spyOn(playerSeed, "apply");
|
||||||
|
|
||||||
|
game.move.select(move);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(player.isFainted()).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not activate the holder's reviver seed from Destiny Bond fainting", async () => {
|
||||||
|
game.override
|
||||||
|
.enemyLevel(100)
|
||||||
|
.startingLevel(1)
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.moveset(Moves.DESTINY_BOND)
|
||||||
|
.startingHeldItems([]) // reset held items to nothing so user doesn't revive and not trigger Destiny Bond
|
||||||
|
.enemyMoveset(Moves.TACKLE);
|
||||||
|
await game.classicMode.startBattle([ Species.MAGIKARP, Species.FEEBAS ]);
|
||||||
|
const player = game.scene.getPlayerPokemon()!;
|
||||||
|
player.damageAndUpdate(player.hp - 1);
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.move.select(Moves.DESTINY_BOND);
|
||||||
|
await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(enemy.isFainted()).toBeTruthy();
|
||||||
|
});
|
||||||
|
});
|
@ -22,7 +22,7 @@ describe("Moves - Endure", () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
game = new GameManager(phaserGame);
|
game = new GameManager(phaserGame);
|
||||||
game.override
|
game.override
|
||||||
.moveset([Moves.THUNDER, Moves.BULLET_SEED, Moves.TOXIC])
|
.moveset([ Moves.THUNDER, Moves.BULLET_SEED, Moves.TOXIC, Moves.SHEER_COLD ])
|
||||||
.ability(Abilities.SKILL_LINK)
|
.ability(Abilities.SKILL_LINK)
|
||||||
.startingLevel(100)
|
.startingLevel(100)
|
||||||
.battleType("single")
|
.battleType("single")
|
||||||
@ -50,16 +50,37 @@ describe("Moves - Endure", () => {
|
|||||||
expect(game.scene.getEnemyPokemon()!.hp).toBe(1);
|
expect(game.scene.getEnemyPokemon()!.hp).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shouldn't prevent fainting from indirect damage", async () => {
|
it("should let the pokemon survive against OHKO moves", async () => {
|
||||||
game.override.enemyLevel(100);
|
await game.classicMode.startBattle([ Species.MAGIKARP ]);
|
||||||
await game.classicMode.startBattle([Species.ARCEUS]);
|
|
||||||
|
|
||||||
const enemy = game.scene.getEnemyPokemon()!;
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
enemy.hp = 2;
|
|
||||||
|
|
||||||
game.move.select(Moves.TOXIC);
|
game.move.select(Moves.SHEER_COLD);
|
||||||
await game.phaseInterceptor.to("VictoryPhase");
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
expect(enemy.isFainted()).toBe(true);
|
expect(enemy.isFainted()).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
|
// comprehensive indirect damage test copied from Reviver Seed test
|
||||||
|
it.each([
|
||||||
|
{ moveType: "Damaging Move Chip Damage", move: Moves.SALT_CURE },
|
||||||
|
{ moveType: "Chip Damage", move: Moves.LEECH_SEED },
|
||||||
|
{ moveType: "Trapping Chip Damage", move: Moves.WHIRLPOOL },
|
||||||
|
{ moveType: "Status Effect Damage", move: Moves.TOXIC },
|
||||||
|
{ moveType: "Weather", move: Moves.SANDSTORM },
|
||||||
|
])("should not prevent fainting from $moveType", async ({ move }) => {
|
||||||
|
game.override
|
||||||
|
.enemyLevel(1)
|
||||||
|
.startingLevel(100)
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.moveset(move)
|
||||||
|
.enemyMoveset(Moves.ENDURE);
|
||||||
|
await game.classicMode.startBattle([ Species.MAGIKARP, Species.FEEBAS ]);
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
enemy.damageAndUpdate(enemy.hp - 1);
|
||||||
|
|
||||||
|
game.move.select(move);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(enemy.isFainted()).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -114,4 +114,25 @@ describe("Moves - Revival Blessing", () => {
|
|||||||
expect(feebas.hp).toBe(toDmgValue(0.5 * feebas.getMaxHp()));
|
expect(feebas.hp).toBe(toDmgValue(0.5 * feebas.getMaxHp()));
|
||||||
expect(game.scene.getPlayerField()[0]).toBe(feebas);
|
expect(game.scene.getPlayerField()[0]).toBe(feebas);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should not summon multiple pokemon to the same slot when reviving the enemy ally in doubles", async () => {
|
||||||
|
game.override
|
||||||
|
.battleType("double")
|
||||||
|
.enemyMoveset([ Moves.REVIVAL_BLESSING ])
|
||||||
|
.moveset([ Moves.SPLASH ])
|
||||||
|
.startingWave(25); // 2nd rival battle - must have 3+ pokemon
|
||||||
|
await game.classicMode.startBattle([ Species.ARCEUS, Species.GIRATINA ]);
|
||||||
|
|
||||||
|
const enemyFainting = game.scene.getEnemyField()[0];
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH, 0);
|
||||||
|
game.move.select(Moves.SPLASH, 1);
|
||||||
|
await game.killPokemon(enemyFainting);
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
await game.toNextTurn();
|
||||||
|
// If there are incorrectly two switch phases into this slot, the fainted pokemon will end up in slot 3
|
||||||
|
// Make sure it's still in slot 1
|
||||||
|
expect(game.scene.getEnemyParty()[0]).toBe(enemyFainting);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -6,6 +6,7 @@ import { TurnEndPhase } from "#app/phases/turn-end-phase";
|
|||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Stat, BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat";
|
import { Stat, BATTLE_STATS, EFFECTIVE_STATS } from "#enums/stat";
|
||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
|
||||||
// TODO: Add more tests once Transform is fully implemented
|
// TODO: Add more tests once Transform is fully implemented
|
||||||
describe("Moves - Transform", () => {
|
describe("Moves - Transform", () => {
|
||||||
@ -58,7 +59,7 @@ describe("Moves - Transform", () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const playerMoveset = player.getMoveset();
|
const playerMoveset = player.getMoveset();
|
||||||
const enemyMoveset = player.getMoveset();
|
const enemyMoveset = enemy.getMoveset();
|
||||||
|
|
||||||
expect(playerMoveset.length).toBe(enemyMoveset.length);
|
expect(playerMoveset.length).toBe(enemyMoveset.length);
|
||||||
for (let i = 0; i < playerMoveset.length && i < enemyMoveset.length; i++) {
|
for (let i = 0; i < playerMoveset.length && i < enemyMoveset.length; i++) {
|
||||||
@ -127,4 +128,71 @@ describe("Moves - Transform", () => {
|
|||||||
|
|
||||||
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
expect(game.scene.getEnemyPokemon()?.getStatStage(Stat.ATK)).toBe(-1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should persist transformed attributes across reloads", async () => {
|
||||||
|
game.override.enemyMoveset([]).moveset([]);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.DITTO]);
|
||||||
|
|
||||||
|
const player = game.scene.getPlayerPokemon()!;
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.move.changeMoveset(player, Moves.TRANSFORM);
|
||||||
|
game.move.changeMoveset(enemy, Moves.MEMENTO);
|
||||||
|
|
||||||
|
game.move.select(Moves.TRANSFORM);
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
|
await game.toNextWave();
|
||||||
|
|
||||||
|
expect(game.scene.getCurrentPhase()?.constructor.name).toBe("CommandPhase");
|
||||||
|
expect(game.scene.currentBattle.waveIndex).toBe(2);
|
||||||
|
|
||||||
|
await game.reload.reloadSession();
|
||||||
|
|
||||||
|
const playerReloaded = game.scene.getPlayerPokemon()!;
|
||||||
|
const playerMoveset = player.getMoveset();
|
||||||
|
|
||||||
|
expect(playerReloaded.getSpeciesForm().speciesId).toBe(enemy.getSpeciesForm().speciesId);
|
||||||
|
expect(playerReloaded.getAbility()).toBe(enemy.getAbility());
|
||||||
|
expect(playerReloaded.getGender()).toBe(enemy.getGender());
|
||||||
|
|
||||||
|
expect(playerReloaded.getStat(Stat.HP, false)).not.toBe(enemy.getStat(Stat.HP));
|
||||||
|
for (const s of EFFECTIVE_STATS) {
|
||||||
|
expect(playerReloaded.getStat(s, false)).toBe(enemy.getStat(s, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(playerMoveset.length).toEqual(1);
|
||||||
|
expect(playerMoveset[0]?.moveId).toEqual(Moves.MEMENTO);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should stay transformed with the correct form after reload", async () => {
|
||||||
|
game.override.enemyMoveset([]).moveset([]);
|
||||||
|
game.override.enemySpecies(Species.DARMANITAN);
|
||||||
|
|
||||||
|
await game.classicMode.startBattle([Species.DITTO]);
|
||||||
|
|
||||||
|
const player = game.scene.getPlayerPokemon()!;
|
||||||
|
const enemy = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
// change form
|
||||||
|
enemy.species.forms[1];
|
||||||
|
enemy.species.formIndex = 1;
|
||||||
|
|
||||||
|
game.move.changeMoveset(player, Moves.TRANSFORM);
|
||||||
|
game.move.changeMoveset(enemy, Moves.MEMENTO);
|
||||||
|
|
||||||
|
game.move.select(Moves.TRANSFORM);
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
|
await game.toNextWave();
|
||||||
|
|
||||||
|
expect(game.scene.getCurrentPhase()?.constructor.name).toBe("CommandPhase");
|
||||||
|
expect(game.scene.currentBattle.waveIndex).toBe(2);
|
||||||
|
|
||||||
|
await game.reload.reloadSession();
|
||||||
|
|
||||||
|
const playerReloaded = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
|
expect(playerReloaded.getSpeciesForm().speciesId).toBe(enemy.getSpeciesForm().speciesId);
|
||||||
|
expect(playerReloaded.getSpeciesForm().formIndex).toBe(enemy.getSpeciesForm().formIndex);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user