mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-04 07:22:19 +02:00
Merge branch 'pagefaultgames:main' into main
This commit is contained in:
commit
c7dac7886f
@ -51,7 +51,7 @@ Check out our [Trello Board](https://trello.com/b/z10B703R/pokerogue-board) to s
|
|||||||
- Squip (Paid Commissions)
|
- Squip (Paid Commissions)
|
||||||
- Contributions by Someonealive-QN
|
- Contributions by Someonealive-QN
|
||||||
|
|
||||||
### UI
|
### 🎨 UI
|
||||||
- GAMEFREAK
|
- GAMEFREAK
|
||||||
- LJ Birdman
|
- LJ Birdman
|
||||||
|
|
||||||
@ -94,5 +94,5 @@ Check out our [Trello Board](https://trello.com/b/z10B703R/pokerogue-board) to s
|
|||||||
- mangalos810
|
- mangalos810
|
||||||
- Involuntary-Twitch
|
- Involuntary-Twitch
|
||||||
|
|
||||||
### Move Animations
|
### 🎨 Move Animations
|
||||||
- Pokémon Reborn
|
- Pokémon Reborn
|
||||||
|
@ -8,7 +8,9 @@
|
|||||||
<meta property="og:title" content="PokéRogue" />
|
<meta property="og:title" content="PokéRogue" />
|
||||||
<meta property="og:type" content="website" />
|
<meta property="og:type" content="website" />
|
||||||
<meta property="og:description" content="A Pokémon fangame heavily inspired by the roguelite genre. Battle endlessly while gathering stacking items, exploring many different biomes, and reaching Pokémon stats you never thought possible." />
|
<meta property="og:description" content="A Pokémon fangame heavily inspired by the roguelite genre. Battle endlessly while gathering stacking items, exploring many different biomes, and reaching Pokémon stats you never thought possible." />
|
||||||
<meta property="og:image" content="https://pokerogue.net/logo.png" />
|
<meta property="og:image" content="https://pokerogue.net/logo512.png" />
|
||||||
|
<link rel="apple-touch-icon" href="/logo512.png" />
|
||||||
|
<link rel="shortcut icon" type="image/png" href="/logo512.png" />
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
@ -23,7 +25,7 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<link rel="stylesheet" type="text/css" href="index.css" />
|
<link rel="stylesheet" type="text/css" href="index.css" />
|
||||||
<link rel="manifest" href="manifest.json" />
|
<link rel="manifest" href="/manifest.webmanifest">
|
||||||
<script>
|
<script>
|
||||||
if ("serviceWorker" in navigator) {
|
if ("serviceWorker" in navigator) {
|
||||||
window.addEventListener("load", function () {
|
window.addEventListener("load", function () {
|
||||||
|
31
package-lock.json
generated
31
package-lock.json
generated
@ -10,6 +10,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material/material-color-utilities": "^0.2.7",
|
"@material/material-color-utilities": "^0.2.7",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
|
"i18next": "^23.11.1",
|
||||||
"json-stable-stringify": "^1.1.0",
|
"json-stable-stringify": "^1.1.0",
|
||||||
"phaser": "^3.70.0",
|
"phaser": "^3.70.0",
|
||||||
"phaser3-rex-plugins": "^1.1.84"
|
"phaser3-rex-plugins": "^1.1.84"
|
||||||
@ -2750,9 +2751,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/i18next": {
|
"node_modules/i18next": {
|
||||||
"version": "22.5.1",
|
"version": "23.11.1",
|
||||||
"resolved": "https://registry.npmjs.org/i18next/-/i18next-22.5.1.tgz",
|
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.11.1.tgz",
|
||||||
"integrity": "sha512-8TGPgM3pAD+VRsMtUMNknRz3kzqwp/gPALrWMsDnmC1mKqJwpWyooQRLMcbTwq8z8YwSmuj+ZYvc+xCuEpkssA==",
|
"integrity": "sha512-mXw4A24BiPZKRsbb9ewgSvjYd6fxFCNwJyfK6nYfSTIAX2GkCWcb598m3DFkDZmqADatvuASrKo6qwORz3VwTQ==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "individual",
|
"type": "individual",
|
||||||
@ -2768,7 +2769,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.20.6"
|
"@babel/runtime": "^7.23.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/i18next-http-backend": {
|
"node_modules/i18next-http-backend": {
|
||||||
@ -3819,6 +3820,28 @@
|
|||||||
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
|
||||||
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
|
"integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q=="
|
||||||
},
|
},
|
||||||
|
"node_modules/phaser3-rex-plugins/node_modules/i18next": {
|
||||||
|
"version": "22.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/i18next/-/i18next-22.5.1.tgz",
|
||||||
|
"integrity": "sha512-8TGPgM3pAD+VRsMtUMNknRz3kzqwp/gPALrWMsDnmC1mKqJwpWyooQRLMcbTwq8z8YwSmuj+ZYvc+xCuEpkssA==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://locize.com"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://locize.com/i18next.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "individual",
|
||||||
|
"url": "https://www.i18next.com/how-to/faq#i18next-is-awesome.-how-can-i-support-the-project"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.20.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/phaser3spectorjs": {
|
"node_modules/phaser3spectorjs": {
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/phaser3spectorjs/-/phaser3spectorjs-0.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/phaser3spectorjs/-/phaser3spectorjs-0.0.8.tgz",
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@material/material-color-utilities": "^0.2.7",
|
"@material/material-color-utilities": "^0.2.7",
|
||||||
"crypto-js": "^4.2.0",
|
"crypto-js": "^4.2.0",
|
||||||
|
"i18next": "^23.11.1",
|
||||||
"json-stable-stringify": "^1.1.0",
|
"json-stable-stringify": "^1.1.0",
|
||||||
"phaser": "^3.70.0",
|
"phaser": "^3.70.0",
|
||||||
"phaser3-rex-plugins": "^1.1.84"
|
"phaser3-rex-plugins": "^1.1.84"
|
||||||
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
BIN
public/logo512.png
Normal file
BIN
public/logo512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.1 KiB |
@ -2,15 +2,13 @@
|
|||||||
"name": "PokéRogue",
|
"name": "PokéRogue",
|
||||||
"short_name": "PokéRogue",
|
"short_name": "PokéRogue",
|
||||||
"description": "A Pokémon fangame heavily inspired by the roguelite genre. Battle endlessly while gathering stacking items, exploring many different biomes, and reaching Pokémon stats you never thought possible.",
|
"description": "A Pokémon fangame heavily inspired by the roguelite genre. Battle endlessly while gathering stacking items, exploring many different biomes, and reaching Pokémon stats you never thought possible.",
|
||||||
|
"scope": "/",
|
||||||
"start_url": "/",
|
"start_url": "/",
|
||||||
"display": "standalone",
|
"display": "standalone",
|
||||||
"background_color": "#8c8c8c",
|
"background_color": "#8c8c8c",
|
||||||
"theme_color": "#8c8c8c",
|
"theme_color": "#8c8c8c",
|
||||||
"icons": [
|
"icons": [
|
||||||
{
|
{ "src": "logo128.png", "sizes": "128x128", "type": "image/png" },
|
||||||
"src": "../logo.png",
|
{ "src": "logo512.png", "sizes": "512x512", "type": "image/png" }
|
||||||
"sizes": "128x128",
|
|
||||||
"type": "image/png"
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
@ -1558,6 +1558,7 @@ export default class BattleScene extends SceneBase {
|
|||||||
const soundName = modifier.type.soundName;
|
const soundName = modifier.type.soundName;
|
||||||
this.validateAchvs(ModifierAchv, modifier);
|
this.validateAchvs(ModifierAchv, modifier);
|
||||||
const modifiersToRemove: PersistentModifier[] = [];
|
const modifiersToRemove: PersistentModifier[] = [];
|
||||||
|
const modifierPromises: Promise<boolean>[] = [];
|
||||||
if (modifier instanceof PersistentModifier) {
|
if (modifier instanceof PersistentModifier) {
|
||||||
if (modifier instanceof TerastallizeModifier)
|
if (modifier instanceof TerastallizeModifier)
|
||||||
modifiersToRemove.push(...(this.findModifiers(m => m instanceof TerastallizeModifier && m.pokemonId === modifier.pokemonId)));
|
modifiersToRemove.push(...(this.findModifiers(m => m instanceof TerastallizeModifier && m.pokemonId === modifier.pokemonId)));
|
||||||
@ -1596,11 +1597,14 @@ export default class BattleScene extends SceneBase {
|
|||||||
} else if (modifier instanceof FusePokemonModifier)
|
} else if (modifier instanceof FusePokemonModifier)
|
||||||
args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon);
|
args.push(this.getPokemonById(modifier.fusePokemonId) as PlayerPokemon);
|
||||||
|
|
||||||
if (modifier.shouldApply(args))
|
if (modifier.shouldApply(args)) {
|
||||||
modifier.apply(args);
|
const result = modifier.apply(args);
|
||||||
|
if (result instanceof Promise)
|
||||||
|
modifierPromises.push(result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.allSettled(this.party.map(p => p.updateInfo(instant))).then(() => resolve());
|
return Promise.allSettled([this.party.map(p => p.updateInfo(instant)), ...modifierPromises]).then(() => resolve());
|
||||||
} else {
|
} else {
|
||||||
const args = [ this ];
|
const args = [ this ];
|
||||||
if (modifier.shouldApply(args))
|
if (modifier.shouldApply(args))
|
||||||
|
@ -941,6 +941,34 @@ export class PostSummonStatChangeAbAttr extends PostSummonAbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class DownloadAbAttr extends PostSummonAbAttr {
|
||||||
|
private enemyDef: integer;
|
||||||
|
private enemySpDef: integer;
|
||||||
|
private stats: BattleStat[];
|
||||||
|
|
||||||
|
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
|
||||||
|
this.enemyDef = 0;
|
||||||
|
this.enemySpDef = 0;
|
||||||
|
|
||||||
|
for (let opponent of pokemon.getOpponents()) {
|
||||||
|
this.enemyDef += opponent.stats[BattleStat.DEF];
|
||||||
|
this.enemySpDef += opponent.stats[BattleStat.SPDEF];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.enemyDef < this.enemySpDef)
|
||||||
|
this.stats = [BattleStat.ATK];
|
||||||
|
else
|
||||||
|
this.stats = [BattleStat.SPATK];
|
||||||
|
|
||||||
|
if (this.enemyDef > 0 && this.enemySpDef > 0) { // only activate if there's actually an enemy to download from
|
||||||
|
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), false, this.stats, 1));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class PostSummonWeatherChangeAbAttr extends PostSummonAbAttr {
|
export class PostSummonWeatherChangeAbAttr extends PostSummonAbAttr {
|
||||||
private weatherType: WeatherType;
|
private weatherType: WeatherType;
|
||||||
|
|
||||||
@ -1151,6 +1179,13 @@ export class BlockCritAbAttr extends AbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class BonusCritAbAttr extends AbAttr {
|
||||||
|
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
|
(args[0] as Utils.BooleanHolder).value = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class BlockNonDirectDamageAbAttr extends AbAttr {
|
export class BlockNonDirectDamageAbAttr extends AbAttr {
|
||||||
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||||
cancelled.value = true;
|
cancelled.value = true;
|
||||||
@ -2091,7 +2126,7 @@ export function initAbilities() {
|
|||||||
.bypassFaint()
|
.bypassFaint()
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.SHED_SKIN, "Shed Skin", "The Pokémon may heal its own status conditions by shedding its skin.", 3)
|
new Ability(Abilities.SHED_SKIN, "Shed Skin", "The Pokémon may heal its own status conditions by shedding its skin.", 3)
|
||||||
.conditionalAttr(pokemon => !Utils.randSeedInt(3), PostTurnResetStatusAbAttr),
|
.conditionalAttr(pokemon => !Utils.randSeedInt(3), PostTurnResetStatusAbAttr),
|
||||||
new Ability(Abilities.GUTS, "Guts", "It's so gutsy that having a status condition boosts the Pokémon's Attack stat.", 3)
|
new Ability(Abilities.GUTS, "Guts", "It's so gutsy that having a status condition boosts the Pokémon's Attack stat.", 3)
|
||||||
.attr(BypassBurnDamageReductionAbAttr)
|
.attr(BypassBurnDamageReductionAbAttr)
|
||||||
.conditionalAttr(pokemon => !!pokemon.status, BattleStatMultiplierAbAttr, BattleStat.ATK, 1.5),
|
.conditionalAttr(pokemon => !!pokemon.status, BattleStatMultiplierAbAttr, BattleStat.ATK, 1.5),
|
||||||
@ -2159,7 +2194,8 @@ export function initAbilities() {
|
|||||||
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 1.25)
|
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 1.25)
|
||||||
.attr(TypeImmunityHealAbAttr, Type.WATER)
|
.attr(TypeImmunityHealAbAttr, Type.WATER)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
new Ability(Abilities.DOWNLOAD, "Download (N)", "Compares an opposing Pokémon's Defense and Sp. Def stats before raising its own Attack or Sp. Atk stat—whichever will be more effective.", 4),
|
new Ability(Abilities.DOWNLOAD, "Download", "Compares an opposing Pokémon's Defense and Sp. Def stats before raising its own Attack or Sp. Atk stat—whichever will be more effective.", 4)
|
||||||
|
.attr(DownloadAbAttr),
|
||||||
new Ability(Abilities.IRON_FIST, "Iron Fist", "Powers up punching moves.", 4)
|
new Ability(Abilities.IRON_FIST, "Iron Fist", "Powers up punching moves.", 4)
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.PUNCHING_MOVE), 1.2),
|
.attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.PUNCHING_MOVE), 1.2),
|
||||||
new Ability(Abilities.POISON_HEAL, "Poison Heal (N)", "Restores HP if the Pokémon is poisoned instead of losing HP.", 4),
|
new Ability(Abilities.POISON_HEAL, "Poison Heal (N)", "Restores HP if the Pokémon is poisoned instead of losing HP.", 4),
|
||||||
@ -2191,7 +2227,8 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.MOLD_BREAKER, "Mold Breaker", "Moves can be used on the target regardless of its Abilities.", 4)
|
new Ability(Abilities.MOLD_BREAKER, "Mold Breaker", "Moves can be used on the target regardless of its Abilities.", 4)
|
||||||
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, ' breaks the mold!'))
|
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, ' breaks the mold!'))
|
||||||
.attr(MoveAbilityBypassAbAttr),
|
.attr(MoveAbilityBypassAbAttr),
|
||||||
new Ability(Abilities.SUPER_LUCK, "Super Luck (N)", "The Pokémon is so lucky that the critical-hit ratios of its moves are boosted.", 4),
|
new Ability(Abilities.SUPER_LUCK, "Super Luck (P)", "The Pokémon is so lucky that the critical-hit ratios of its moves are boosted.", 4)
|
||||||
|
.attr(BonusCritAbAttr),
|
||||||
new Ability(Abilities.AFTERMATH, "Aftermath", "Damages the attacker if it contacts the Pokémon with a finishing hit.", 4)
|
new Ability(Abilities.AFTERMATH, "Aftermath", "Damages the attacker if it contacts the Pokémon with a finishing hit.", 4)
|
||||||
.attr(PostFaintContactDamageAbAttr,4)
|
.attr(PostFaintContactDamageAbAttr,4)
|
||||||
.bypassFaint(),
|
.bypassFaint(),
|
||||||
|
@ -956,6 +956,12 @@ export class CritBoostTag extends BattlerTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class AlwaysCritTag extends BattlerTag {
|
||||||
|
constructor(sourceMove: Moves) {
|
||||||
|
super(BattlerTagType.ALWAYS_CRIT, BattlerTagLapseType.TURN_END, 2, sourceMove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class IgnoreAccuracyTag extends BattlerTag {
|
export class IgnoreAccuracyTag extends BattlerTag {
|
||||||
constructor(sourceMove: Moves) {
|
constructor(sourceMove: Moves) {
|
||||||
super(BattlerTagType.IGNORE_ACCURACY, BattlerTagLapseType.TURN_END, 2, sourceMove);
|
super(BattlerTagType.IGNORE_ACCURACY, BattlerTagLapseType.TURN_END, 2, sourceMove);
|
||||||
@ -1077,6 +1083,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
|
|||||||
return new TypeBoostTag(tagType, sourceMove, Type.FIRE);
|
return new TypeBoostTag(tagType, sourceMove, Type.FIRE);
|
||||||
case BattlerTagType.CRIT_BOOST:
|
case BattlerTagType.CRIT_BOOST:
|
||||||
return new CritBoostTag(tagType, sourceMove);
|
return new CritBoostTag(tagType, sourceMove);
|
||||||
|
case BattlerTagType.ALWAYS_CRIT:
|
||||||
|
return new AlwaysCritTag(sourceMove);
|
||||||
case BattlerTagType.NO_CRIT:
|
case BattlerTagType.NO_CRIT:
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.AFTER_MOVE, turnCount, sourceMove);
|
return new BattlerTag(tagType, BattlerTagLapseType.AFTER_MOVE, turnCount, sourceMove);
|
||||||
case BattlerTagType.IGNORE_ACCURACY:
|
case BattlerTagType.IGNORE_ACCURACY:
|
||||||
|
@ -41,6 +41,7 @@ export enum BattlerTagType {
|
|||||||
HIDDEN = "HIDDEN",
|
HIDDEN = "HIDDEN",
|
||||||
FIRE_BOOST = "FIRE_BOOST",
|
FIRE_BOOST = "FIRE_BOOST",
|
||||||
CRIT_BOOST = "CRIT_BOOST",
|
CRIT_BOOST = "CRIT_BOOST",
|
||||||
|
ALWAYS_CRIT = "ALWAYS_CRIT",
|
||||||
NO_CRIT = "NO_CRIT",
|
NO_CRIT = "NO_CRIT",
|
||||||
IGNORE_ACCURACY = "IGNORE_ACCURACY",
|
IGNORE_ACCURACY = "IGNORE_ACCURACY",
|
||||||
BYPASS_SLEEP = "BYPASS_SLEEP",
|
BYPASS_SLEEP = "BYPASS_SLEEP",
|
||||||
|
179
src/data/move.ts
179
src/data/move.ts
@ -12,7 +12,7 @@ import * as Utils from "../utils";
|
|||||||
import { WeatherType } from "./weather";
|
import { WeatherType } from "./weather";
|
||||||
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
||||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||||
import { ProtectAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr } from "./ability";
|
import { ProtectAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr } from "./ability";
|
||||||
import { Abilities } from "./enums/abilities";
|
import { Abilities } from "./enums/abilities";
|
||||||
import { PokemonHeldItemModifier } from "../modifier/modifier";
|
import { PokemonHeldItemModifier } from "../modifier/modifier";
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
@ -813,6 +813,19 @@ export class HitHealAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class StrengthSapHealAttr extends MoveEffectAttr {
|
||||||
|
constructor() {
|
||||||
|
super(true, MoveEffectTrigger.HIT);
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
user.scene.unshiftPhase(new PokemonHealPhase(user.scene, user.getBattlerIndex(),
|
||||||
|
target.stats[Stat.ATK] * (Math.max(2, 2 + target.summonData.battleStats[BattleStat.ATK]) / Math.max(2, 2 - target.summonData.battleStats[BattleStat.ATK])),
|
||||||
|
getPokemonMessage(user, ` regained\nhealth!`), false, true));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class MultiHitAttr extends MoveAttr {
|
export class MultiHitAttr extends MoveAttr {
|
||||||
private multiHitType: MultiHitType;
|
private multiHitType: MultiHitType;
|
||||||
|
|
||||||
@ -2031,6 +2044,27 @@ export class WeatherBallTypeAttr extends VariableMoveTypeAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class HiddenPowerTypeAttr extends VariableMoveTypeAttr {
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
const type = (args[0] as Utils.IntegerHolder);
|
||||||
|
|
||||||
|
const iv_val = Math.floor(((user.ivs[Stat.HP] & 1)
|
||||||
|
+(user.ivs[Stat.ATK] & 1) * 2
|
||||||
|
+(user.ivs[Stat.DEF] & 1) * 4
|
||||||
|
+(user.ivs[Stat.SPD] & 1) * 8
|
||||||
|
+(user.ivs[Stat.SPATK] & 1) * 16
|
||||||
|
+(user.ivs[Stat.SPDEF] & 1) * 32) * 15/63);
|
||||||
|
|
||||||
|
type.value = [
|
||||||
|
Type.FIGHTING, Type.FLYING, Type.POISON, Type.GROUND,
|
||||||
|
Type.ROCK, Type.BUG, Type.GHOST, Type.STEEL,
|
||||||
|
Type.FIRE, Type.WATER, Type.GRASS, Type.ELECTRIC,
|
||||||
|
Type.PSYCHIC, Type.ICE, Type.DRAGON, Type.DARK][iv_val];
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class VariableMoveTypeMultiplierAttr extends MoveAttr {
|
export class VariableMoveTypeMultiplierAttr extends MoveAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -2266,6 +2300,7 @@ export class AddBattlerTagAttr extends MoveEffectAttr {
|
|||||||
case BattlerTagType.PROTECTED:
|
case BattlerTagType.PROTECTED:
|
||||||
case BattlerTagType.FLYING:
|
case BattlerTagType.FLYING:
|
||||||
case BattlerTagType.CRIT_BOOST:
|
case BattlerTagType.CRIT_BOOST:
|
||||||
|
case BattlerTagType.ALWAYS_CRIT:
|
||||||
return 5;
|
return 5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2387,6 +2422,21 @@ export class IgnoreAccuracyAttr extends AddBattlerTagAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class AlwaysCritsAttr extends AddBattlerTagAttr {
|
||||||
|
constructor() {
|
||||||
|
super(BattlerTagType.ALWAYS_CRIT, true, false, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
if (!super.apply(user, target, move, args))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
user.scene.queueMessage(getPokemonMessage(user, ` took aim\nat ${target.name}!`));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class FaintCountdownAttr extends AddBattlerTagAttr {
|
export class FaintCountdownAttr extends AddBattlerTagAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(BattlerTagType.PERISH_SONG, false, true, 4);
|
super(BattlerTagType.PERISH_SONG, false, true, 4);
|
||||||
@ -2500,61 +2550,72 @@ export class AddArenaTrapTagAttr extends AddArenaTagAttr {
|
|||||||
export class ForceSwitchOutAttr extends MoveEffectAttr {
|
export class ForceSwitchOutAttr extends MoveEffectAttr {
|
||||||
private user: boolean;
|
private user: boolean;
|
||||||
private batonPass: boolean;
|
private batonPass: boolean;
|
||||||
|
|
||||||
constructor(user?: boolean, batonPass?: boolean) {
|
constructor(user?: boolean, batonPass?: boolean) {
|
||||||
super(false, MoveEffectTrigger.HIT, true);
|
super(false, MoveEffectTrigger.HIT, true);
|
||||||
|
|
||||||
this.user = !!user;
|
this.user = !!user;
|
||||||
this.batonPass = !!batonPass;
|
this.batonPass = !!batonPass;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
if (move.category !== MoveCategory.STATUS && !this.getSwitchOutCondition()(user, target, move))
|
// Check if the move category is not STATUS or if the switch out condition is not met
|
||||||
return resolve(false);
|
if (move.category !== MoveCategory.STATUS && !this.getSwitchOutCondition()(user, target, move)) {
|
||||||
const switchOutTarget = this.user ? user : target;
|
//Apply effects before switch out i.e. poison point, flame body, etc
|
||||||
if (switchOutTarget instanceof PlayerPokemon) {
|
applyPostDefendAbAttrs(PostDefendContactApplyStatusEffectAbAttr, target, user, new PokemonMove(move.id), null);
|
||||||
if (switchOutTarget.hp) {
|
return resolve(false);
|
||||||
applyPreSwitchOutAbAttrs(PreSwitchOutAbAttr, switchOutTarget);
|
}
|
||||||
(switchOutTarget as PlayerPokemon).switchOut(this.batonPass, true).then(() => resolve(true));
|
|
||||||
}
|
// Move the switch out logic inside the conditional block
|
||||||
else
|
// This ensures that the switch out only happens when the conditions are met
|
||||||
resolve(false);
|
const switchOutTarget = this.user ? user : target;
|
||||||
return;
|
if (switchOutTarget instanceof PlayerPokemon) {
|
||||||
} else if (user.scene.currentBattle.battleType) {
|
if (switchOutTarget.hp) {
|
||||||
switchOutTarget.resetTurnData();
|
applyPreSwitchOutAbAttrs(PreSwitchOutAbAttr, switchOutTarget);
|
||||||
switchOutTarget.resetSummonData();
|
(switchOutTarget as PlayerPokemon).switchOut(this.batonPass, true).then(() => resolve(true));
|
||||||
switchOutTarget.hideInfo();
|
}
|
||||||
switchOutTarget.setVisible(false);
|
else {
|
||||||
switchOutTarget.scene.field.remove(switchOutTarget);
|
resolve(false);
|
||||||
user.scene.triggerPokemonFormChange(switchOutTarget, SpeciesFormChangeActiveTrigger, true);
|
}
|
||||||
|
return;
|
||||||
if (switchOutTarget.hp)
|
}
|
||||||
user.scene.unshiftPhase(new SwitchSummonPhase(user.scene, switchOutTarget.getFieldIndex(), user.scene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot), false, this.batonPass, false));
|
else if (user.scene.currentBattle.battleType) {
|
||||||
} else {
|
// Switch out logic for the battle type
|
||||||
switchOutTarget.setVisible(false);
|
switchOutTarget.resetTurnData();
|
||||||
|
switchOutTarget.resetSummonData();
|
||||||
if (switchOutTarget.hp) {
|
switchOutTarget.hideInfo();
|
||||||
switchOutTarget.hideInfo().then(() => switchOutTarget.destroy());
|
switchOutTarget.setVisible(false);
|
||||||
switchOutTarget.scene.field.remove(switchOutTarget);
|
switchOutTarget.scene.field.remove(switchOutTarget);
|
||||||
user.scene.queueMessage(getPokemonMessage(switchOutTarget, ' fled!'), null, true, 500);
|
user.scene.triggerPokemonFormChange(switchOutTarget, SpeciesFormChangeActiveTrigger, true);
|
||||||
}
|
|
||||||
|
if (switchOutTarget.hp)
|
||||||
if (!switchOutTarget.getAlly()?.isActive(true)) {
|
user.scene.unshiftPhase(new SwitchSummonPhase(user.scene, switchOutTarget.getFieldIndex(), user.scene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot), false, this.batonPass, false));
|
||||||
user.scene.clearEnemyHeldItemModifiers();
|
}
|
||||||
|
else {
|
||||||
if (switchOutTarget.hp) {
|
// Switch out logic for everything else
|
||||||
user.scene.pushPhase(new BattleEndPhase(user.scene));
|
switchOutTarget.setVisible(false);
|
||||||
user.scene.pushPhase(new NewBattlePhase(user.scene));
|
|
||||||
}
|
if (switchOutTarget.hp) {
|
||||||
}
|
switchOutTarget.hideInfo().then(() => switchOutTarget.destroy());
|
||||||
}
|
switchOutTarget.scene.field.remove(switchOutTarget);
|
||||||
|
user.scene.queueMessage(getPokemonMessage(switchOutTarget, ' fled!'), null, true, 500);
|
||||||
resolve(true);
|
}
|
||||||
});
|
|
||||||
}
|
if (!switchOutTarget.getAlly()?.isActive(true)) {
|
||||||
|
user.scene.clearEnemyHeldItemModifiers();
|
||||||
getCondition(): MoveConditionFunc {
|
|
||||||
|
if (switchOutTarget.hp) {
|
||||||
|
user.scene.pushPhase(new BattleEndPhase(user.scene));
|
||||||
|
user.scene.pushPhase(new NewBattlePhase(user.scene));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getCondition(): MoveConditionFunc {
|
||||||
return (user, target, move) => move.category !== MoveCategory.STATUS || this.getSwitchOutCondition()(user, target, move);
|
return (user, target, move) => move.category !== MoveCategory.STATUS || this.getSwitchOutCondition()(user, target, move);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3450,7 +3511,7 @@ export function initMoves() {
|
|||||||
new SelfStatusMove(Moves.REST, "Rest", Type.PSYCHIC, -1, 5, "The user goes to sleep for two turns. This fully restores the user's HP and heals any status conditions.", -1, 0, 1)
|
new SelfStatusMove(Moves.REST, "Rest", Type.PSYCHIC, -1, 5, "The user goes to sleep for two turns. This fully restores the user's HP and heals any status conditions.", -1, 0, 1)
|
||||||
.attr(StatusEffectAttr, StatusEffect.SLEEP, true, 3, true)
|
.attr(StatusEffectAttr, StatusEffect.SLEEP, true, 3, true)
|
||||||
.attr(HealAttr, 1, true)
|
.attr(HealAttr, 1, true)
|
||||||
.condition((user, target, move) => user.getHpRatio() < 1 && user.canSetStatus(StatusEffect.SLEEP, true))
|
.condition((user, target, move) => user.getHpRatio() < 1 && user.canSetStatus(StatusEffect.SLEEP, true, true))
|
||||||
.triageMove(),
|
.triageMove(),
|
||||||
new AttackMove(Moves.ROCK_SLIDE, "Rock Slide", Type.ROCK, MoveCategory.PHYSICAL, 75, 90, 10, "Large boulders are hurled at opposing Pokémon to inflict damage. This may also make the opposing Pokémon flinch.", 30, 0, 1)
|
new AttackMove(Moves.ROCK_SLIDE, "Rock Slide", Type.ROCK, MoveCategory.PHYSICAL, 75, 90, 10, "Large boulders are hurled at opposing Pokémon to inflict damage. This may also make the opposing Pokémon flinch.", 30, 0, 1)
|
||||||
.attr(FlinchAttr)
|
.attr(FlinchAttr)
|
||||||
@ -3669,7 +3730,8 @@ export function initMoves() {
|
|||||||
new SelfStatusMove(Moves.MOONLIGHT, "Moonlight", Type.FAIRY, -1, 5, "The user restores its own HP. The amount of HP regained varies with the weather.", -1, 0, 2)
|
new SelfStatusMove(Moves.MOONLIGHT, "Moonlight", Type.FAIRY, -1, 5, "The user restores its own HP. The amount of HP regained varies with the weather.", -1, 0, 2)
|
||||||
.attr(PlantHealAttr)
|
.attr(PlantHealAttr)
|
||||||
.triageMove(),
|
.triageMove(),
|
||||||
new AttackMove(Moves.HIDDEN_POWER, "Hidden Power (P)", Type.NORMAL, MoveCategory.SPECIAL, 60, 100, 15, "A unique attack that varies in type depending on the Pokémon using it.", -1, 0, 2),
|
new AttackMove(Moves.HIDDEN_POWER, "Hidden Power", Type.NORMAL, MoveCategory.SPECIAL, 60, 100, 15, "A unique attack that varies in type depending on the Pokémon using it.", -1, 0, 2)
|
||||||
|
.attr(HiddenPowerTypeAttr),
|
||||||
new AttackMove(Moves.CROSS_CHOP, "Cross Chop", Type.FIGHTING, MoveCategory.PHYSICAL, 100, 80, 5, "The user delivers a double chop with its forearms crossed. Critical hits land more easily.", -1, 0, 2)
|
new AttackMove(Moves.CROSS_CHOP, "Cross Chop", Type.FIGHTING, MoveCategory.PHYSICAL, 100, 80, 5, "The user delivers a double chop with its forearms crossed. Critical hits land more easily.", -1, 0, 2)
|
||||||
.attr(HighCritAttr),
|
.attr(HighCritAttr),
|
||||||
new AttackMove(Moves.TWISTER, "Twister", Type.DRAGON, MoveCategory.SPECIAL, 40, 100, 20, "The user whips up a vicious tornado to tear at opposing Pokémon. This may also make them flinch.", 20, 0, 2)
|
new AttackMove(Moves.TWISTER, "Twister", Type.DRAGON, MoveCategory.SPECIAL, 40, 100, 20, "The user whips up a vicious tornado to tear at opposing Pokémon. This may also make them flinch.", 20, 0, 2)
|
||||||
@ -4479,7 +4541,7 @@ export function initMoves() {
|
|||||||
new StatusMove(Moves.TOPSY_TURVY, "Topsy-Turvy", Type.DARK, -1, 20, "All stat changes affecting the target turn topsy-turvy and become the opposite of what they were.", -1, 0, 6)
|
new StatusMove(Moves.TOPSY_TURVY, "Topsy-Turvy", Type.DARK, -1, 20, "All stat changes affecting the target turn topsy-turvy and become the opposite of what they were.", -1, 0, 6)
|
||||||
.attr(InvertStatsAttr),
|
.attr(InvertStatsAttr),
|
||||||
new AttackMove(Moves.DRAINING_KISS, "Draining Kiss", Type.FAIRY, MoveCategory.SPECIAL, 50, 100, 10, "The user steals the target's HP with a kiss. The user's HP is restored by over half of the damage taken by the target.", -1, 0, 6)
|
new AttackMove(Moves.DRAINING_KISS, "Draining Kiss", Type.FAIRY, MoveCategory.SPECIAL, 50, 100, 10, "The user steals the target's HP with a kiss. The user's HP is restored by over half of the damage taken by the target.", -1, 0, 6)
|
||||||
.attr(HitHealAttr)
|
.attr(HitHealAttr, 0.75)
|
||||||
.makesContact()
|
.makesContact()
|
||||||
.triageMove(),
|
.triageMove(),
|
||||||
new StatusMove(Moves.CRAFTY_SHIELD, "Crafty Shield (N)", Type.FAIRY, -1, 10, "The user protects itself and its allies from status moves with a mysterious power. This does not stop moves that do damage.", -1, 3, 6)
|
new StatusMove(Moves.CRAFTY_SHIELD, "Crafty Shield (N)", Type.FAIRY, -1, 10, "The user protects itself and its allies from status moves with a mysterious power. This does not stop moves that do damage.", -1, 3, 6)
|
||||||
@ -4653,8 +4715,10 @@ export function initMoves() {
|
|||||||
.attr(HealAttr, 0.5, true, false)
|
.attr(HealAttr, 0.5, true, false)
|
||||||
.triageMove(),
|
.triageMove(),
|
||||||
new AttackMove(Moves.HIGH_HORSEPOWER, "High Horsepower", Type.GROUND, MoveCategory.PHYSICAL, 95, 95, 10, "The user fiercely attacks the target using its entire body.", -1, 0, 7),
|
new AttackMove(Moves.HIGH_HORSEPOWER, "High Horsepower", Type.GROUND, MoveCategory.PHYSICAL, 95, 95, 10, "The user fiercely attacks the target using its entire body.", -1, 0, 7),
|
||||||
new StatusMove(Moves.STRENGTH_SAP, "Strength Sap (P)", Type.GRASS, 100, 10, "The user restores its HP by the same amount as the target's Attack stat. It also lowers the target's Attack stat.", 100, 0, 7)
|
new StatusMove(Moves.STRENGTH_SAP, "Strength Sap", Type.GRASS, 100, 10, "The user restores its HP by the same amount as the target's Attack stat. It also lowers the target's Attack stat.", 100, 0, 7)
|
||||||
|
.attr(StrengthSapHealAttr)
|
||||||
.attr(StatChangeAttr, BattleStat.ATK, -1)
|
.attr(StatChangeAttr, BattleStat.ATK, -1)
|
||||||
|
.condition((user, target, move) => target.summonData.battleStats[BattleStat.ATK] > -6)
|
||||||
.triageMove(),
|
.triageMove(),
|
||||||
new AttackMove(Moves.SOLAR_BLADE, "Solar Blade", Type.GRASS, MoveCategory.PHYSICAL, 125, 100, 10, "In this two-turn attack, the user gathers light and fills a blade with the light's energy, attacking the target on the next turn.", -1, 0, 7)
|
new AttackMove(Moves.SOLAR_BLADE, "Solar Blade", Type.GRASS, MoveCategory.PHYSICAL, 125, 100, 10, "In this two-turn attack, the user gathers light and fills a blade with the light's energy, attacking the target on the next turn.", -1, 0, 7)
|
||||||
.attr(SunlightChargeAttr, ChargeAnim.SOLAR_BLADE_CHARGING, "is glowing!")
|
.attr(SunlightChargeAttr, ChargeAnim.SOLAR_BLADE_CHARGING, "is glowing!")
|
||||||
@ -4666,7 +4730,8 @@ export function initMoves() {
|
|||||||
new StatusMove(Moves.TOXIC_THREAD, "Toxic Thread", Type.POISON, 100, 20, "The user shoots poisonous threads to poison the target and lower the target's Speed stat.", 100, 0, 7)
|
new StatusMove(Moves.TOXIC_THREAD, "Toxic Thread", Type.POISON, 100, 20, "The user shoots poisonous threads to poison the target and lower the target's Speed stat.", 100, 0, 7)
|
||||||
.attr(StatusEffectAttr, StatusEffect.POISON)
|
.attr(StatusEffectAttr, StatusEffect.POISON)
|
||||||
.attr(StatChangeAttr, BattleStat.SPD, -1),
|
.attr(StatChangeAttr, BattleStat.SPD, -1),
|
||||||
new SelfStatusMove(Moves.LASER_FOCUS, "Laser Focus (N)", Type.NORMAL, -1, 30, "The user concentrates intensely. The attack on the next turn always results in a critical hit.", -1, 0, 7),
|
new SelfStatusMove(Moves.LASER_FOCUS, "Laser Focus", Type.NORMAL, -1, 30, "The user concentrates intensely. The attack on the next turn always results in a critical hit.", -1, 0, 7)
|
||||||
|
.attr(AddBattlerTagAttr, BattlerTagType.ALWAYS_CRIT, true, false),
|
||||||
new StatusMove(Moves.GEAR_UP, "Gear Up", Type.STEEL, -1, 20, "The user engages its gears to raise the Attack and Sp. Atk stats of ally Pokémon with the Plus or Minus Ability.", -1, 0, 7)
|
new StatusMove(Moves.GEAR_UP, "Gear Up", Type.STEEL, -1, 20, "The user engages its gears to raise the Attack and Sp. Atk stats of ally Pokémon with the Plus or Minus Ability.", -1, 0, 7)
|
||||||
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 1, false, (user, target, move) => [ Abilities.PLUS, Abilities.MINUS ].includes(target.getAbility().id) || (target.canApplyPassive() && [ Abilities.PLUS, Abilities.MINUS ].includes(target.getPassiveAbility().id)))
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 1, false, (user, target, move) => [ Abilities.PLUS, Abilities.MINUS ].includes(target.getAbility().id) || (target.canApplyPassive() && [ Abilities.PLUS, Abilities.MINUS ].includes(target.getPassiveAbility().id)))
|
||||||
.target(MoveTarget.USER_AND_ALLIES)
|
.target(MoveTarget.USER_AND_ALLIES)
|
||||||
@ -5156,7 +5221,11 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.AXE_KICK, "Axe Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 120, 90, 10, "The user attacks by kicking up into the air and slamming its heel down upon the target. This may also confuse the target. If it misses, the user takes damage instead.", 30, 0, 9)
|
new AttackMove(Moves.AXE_KICK, "Axe Kick", Type.FIGHTING, MoveCategory.PHYSICAL, 120, 90, 10, "The user attacks by kicking up into the air and slamming its heel down upon the target. This may also confuse the target. If it misses, the user takes damage instead.", 30, 0, 9)
|
||||||
.attr(MissEffectAttr, halveHpMissEffectFunc)
|
.attr(MissEffectAttr, halveHpMissEffectFunc)
|
||||||
.attr(ConfuseAttr),
|
.attr(ConfuseAttr),
|
||||||
new AttackMove(Moves.LAST_RESPECTS, "Last Respects (P)", Type.GHOST, MoveCategory.PHYSICAL, 50, 100, 10, "The user attacks to avenge its allies. The more defeated allies there are in the user's party, the greater the move's power.", -1, 0, 9)
|
new AttackMove(Moves.LAST_RESPECTS, "Last Respects", Type.GHOST, MoveCategory.PHYSICAL, 50, 100, 10, "The user attacks to avenge its allies. The more defeated allies there are in the user's party, the greater the move's power.", -1, 0, 9)
|
||||||
|
.attr(MovePowerMultiplierAttr, (user, target, move) => {
|
||||||
|
return user.scene.getParty().reduce((acc, pokemonInParty) => acc + (pokemonInParty.status?.effect == StatusEffect.FAINT ? 1 : 0),
|
||||||
|
1,)
|
||||||
|
})
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
new AttackMove(Moves.LUMINA_CRASH, "Lumina Crash", Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, "The user attacks by unleashing a peculiar light that even affects the mind. This also harshly lowers the target's Sp. Def stat.", 100, 0, 9)
|
new AttackMove(Moves.LUMINA_CRASH, "Lumina Crash", Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, "The user attacks by unleashing a peculiar light that even affects the mind. This also harshly lowers the target's Sp. Def stat.", 100, 0, 9)
|
||||||
.attr(StatChangeAttr, BattleStat.SPDEF, -2),
|
.attr(StatChangeAttr, BattleStat.SPDEF, -2),
|
||||||
|
@ -1044,7 +1044,7 @@ export function initSpecies() {
|
|||||||
new PokemonSpecies(Species.ENTEI, "Entei", 2, true, false, false, "Volcano Pokémon", Type.FIRE, null, 2.1, 198, Abilities.PRESSURE, Abilities.NONE, Abilities.INNER_FOCUS, 580, 115, 115, 85, 90, 75, 100, 3, 35, 290, GrowthRate.SLOW, null, false),
|
new PokemonSpecies(Species.ENTEI, "Entei", 2, true, false, false, "Volcano Pokémon", Type.FIRE, null, 2.1, 198, Abilities.PRESSURE, Abilities.NONE, Abilities.INNER_FOCUS, 580, 115, 115, 85, 90, 75, 100, 3, 35, 290, GrowthRate.SLOW, null, false),
|
||||||
new PokemonSpecies(Species.SUICUNE, "Suicune", 2, true, false, false, "Aurora Pokémon", Type.WATER, null, 2, 187, Abilities.PRESSURE, Abilities.NONE, Abilities.INNER_FOCUS, 580, 100, 75, 115, 90, 115, 85, 3, 35, 290, GrowthRate.SLOW, null, false),
|
new PokemonSpecies(Species.SUICUNE, "Suicune", 2, true, false, false, "Aurora Pokémon", Type.WATER, null, 2, 187, Abilities.PRESSURE, Abilities.NONE, Abilities.INNER_FOCUS, 580, 100, 75, 115, 90, 115, 85, 3, 35, 290, GrowthRate.SLOW, null, false),
|
||||||
new PokemonSpecies(Species.LARVITAR, "Larvitar", 2, false, false, false, "Rock Skin Pokémon", Type.ROCK, Type.GROUND, 0.6, 72, Abilities.GUTS, Abilities.NONE, Abilities.SAND_VEIL, 300, 50, 64, 50, 45, 50, 41, 45, 35, 60, GrowthRate.SLOW, 50, false),
|
new PokemonSpecies(Species.LARVITAR, "Larvitar", 2, false, false, false, "Rock Skin Pokémon", Type.ROCK, Type.GROUND, 0.6, 72, Abilities.GUTS, Abilities.NONE, Abilities.SAND_VEIL, 300, 50, 64, 50, 45, 50, 41, 45, 35, 60, GrowthRate.SLOW, 50, false),
|
||||||
new PokemonSpecies(Species.PUPITAR, "Pupitar", 2, false, false, false, "Hard Shell Pokémon", Type.ROCK, Type.GROUND, 1.2, 152, Abilities.SHED_SKIN, Abilities.NONE, Abilities.NONE, 410, 70, 84, 70, 65, 70, 51, 45, 35, 144, GrowthRate.SLOW, 50, false),
|
new PokemonSpecies(Species.PUPITAR, "Pupitar", 2, false, false, false, "Hard Shell Pokémon", Type.ROCK, Type.GROUND, 1.2, 152, Abilities.SHED_SKIN, Abilities.NONE, Abilities.SHED_SKIN, 410, 70, 84, 70, 65, 70, 51, 45, 35, 144, GrowthRate.SLOW, 50, false),
|
||||||
new PokemonSpecies(Species.TYRANITAR, "Tyranitar", 2, false, false, false, "Armor Pokémon", Type.ROCK, Type.DARK, 2, 202, Abilities.SAND_STREAM, Abilities.NONE, Abilities.UNNERVE, 600, 100, 134, 110, 95, 100, 61, 45, 35, 300, GrowthRate.SLOW, 50, false, true,
|
new PokemonSpecies(Species.TYRANITAR, "Tyranitar", 2, false, false, false, "Armor Pokémon", Type.ROCK, Type.DARK, 2, 202, Abilities.SAND_STREAM, Abilities.NONE, Abilities.UNNERVE, 600, 100, 134, 110, 95, 100, 61, 45, 35, 300, GrowthRate.SLOW, 50, false, true,
|
||||||
new PokemonForm("Normal", "", Type.ROCK, Type.DARK, 2, 202, Abilities.SAND_STREAM, Abilities.NONE, Abilities.UNNERVE, 600, 100, 134, 110, 95, 100, 61, 45, 35, 300),
|
new PokemonForm("Normal", "", Type.ROCK, Type.DARK, 2, 202, Abilities.SAND_STREAM, Abilities.NONE, Abilities.UNNERVE, 600, 100, 134, 110, 95, 100, 61, 45, 35, 300),
|
||||||
new PokemonForm("Mega", SpeciesFormKey.MEGA, Type.ROCK, Type.DARK, 2.5, 255, Abilities.SAND_STREAM, Abilities.NONE, Abilities.SAND_STREAM, 700, 100, 164, 150, 95, 120, 71, 45, 35, 300),
|
new PokemonForm("Mega", SpeciesFormKey.MEGA, Type.ROCK, Type.DARK, 2.5, 255, Abilities.SAND_STREAM, Abilities.NONE, Abilities.SAND_STREAM, 700, 100, 164, 150, 95, 120, 71, 45, 35, 300),
|
||||||
|
@ -3,6 +3,7 @@ import Move from "./move";
|
|||||||
import { Type } from "./type";
|
import { Type } from "./type";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { IncrementMovePriorityAbAttr, applyAbAttrs } from "./ability";
|
import { IncrementMovePriorityAbAttr, applyAbAttrs } from "./ability";
|
||||||
|
import { ProtectAttr } from "./move";
|
||||||
|
|
||||||
export enum TerrainType {
|
export enum TerrainType {
|
||||||
NONE,
|
NONE,
|
||||||
@ -50,9 +51,11 @@ export class Terrain {
|
|||||||
isMoveTerrainCancelled(user: Pokemon, move: Move): boolean {
|
isMoveTerrainCancelled(user: Pokemon, move: Move): boolean {
|
||||||
switch (this.terrainType) {
|
switch (this.terrainType) {
|
||||||
case TerrainType.PSYCHIC:
|
case TerrainType.PSYCHIC:
|
||||||
const priority = new Utils.IntegerHolder(move.priority);
|
if (!move.getAttrs(ProtectAttr).length){
|
||||||
applyAbAttrs(IncrementMovePriorityAbAttr, user, null, move, priority);
|
const priority = new Utils.IntegerHolder(move.priority);
|
||||||
return priority.value > 0;
|
applyAbAttrs(IncrementMovePriorityAbAttr, user, null, move, priority);
|
||||||
|
return priority.value > 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -25,7 +25,7 @@ import { TempBattleStat } from '../data/temp-battle-stat';
|
|||||||
import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag';
|
import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag';
|
||||||
import { ArenaTagType } from "../data/enums/arena-tag-type";
|
import { ArenaTagType } from "../data/enums/arena-tag-type";
|
||||||
import { Biome } from "../data/enums/biome";
|
import { Biome } from "../data/enums/biome";
|
||||||
import { Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, BypassBurnDamageReductionAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from '../data/ability';
|
import { Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from '../data/ability';
|
||||||
import { Abilities } from "#app/data/enums/abilities";
|
import { Abilities } from "#app/data/enums/abilities";
|
||||||
import PokemonData from '../system/pokemon-data';
|
import PokemonData from '../system/pokemon-data';
|
||||||
import { BattlerIndex } from '../battle';
|
import { BattlerIndex } from '../battle';
|
||||||
@ -601,8 +601,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return this.getMaxHp() - this.hp;
|
return this.getMaxHp() - this.hp;
|
||||||
}
|
}
|
||||||
|
|
||||||
getHpRatio(): number {
|
getHpRatio(precise: boolean = false): number {
|
||||||
return Math.floor((this.hp / this.getMaxHp()) * 100) / 100;
|
return precise
|
||||||
|
? this.hp / this.getMaxHp()
|
||||||
|
: ((this.hp / this.getMaxHp()) * 100) / 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
generateGender(): void {
|
generateGender(): void {
|
||||||
@ -1172,13 +1174,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
power.value *= 1.5;
|
power.value *= 1.5;
|
||||||
let isCritical: boolean;
|
let isCritical: boolean;
|
||||||
const critOnly = new Utils.BooleanHolder(false);
|
const critOnly = new Utils.BooleanHolder(false);
|
||||||
|
const critAlways = source.getTag(BattlerTagType.ALWAYS_CRIT);
|
||||||
applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly);
|
applyMoveAttrs(CritOnlyAttr, source, this, move, critOnly);
|
||||||
if (critOnly.value)
|
if (critOnly.value || critAlways)
|
||||||
isCritical = true;
|
isCritical = true;
|
||||||
else {
|
else {
|
||||||
const critLevel = new Utils.IntegerHolder(0);
|
const critLevel = new Utils.IntegerHolder(0);
|
||||||
applyMoveAttrs(HighCritAttr, source, this, move, critLevel);
|
applyMoveAttrs(HighCritAttr, source, this, move, critLevel);
|
||||||
this.scene.applyModifiers(TempBattleStatBoosterModifier, source.isPlayer(), TempBattleStat.CRIT, critLevel);
|
this.scene.applyModifiers(TempBattleStatBoosterModifier, source.isPlayer(), TempBattleStat.CRIT, critLevel);
|
||||||
|
const bonusCrit = new Utils.BooleanHolder(false);
|
||||||
|
if (applyAbAttrs(BonusCritAbAttr, this, null, bonusCrit)) {
|
||||||
|
if (bonusCrit.value)
|
||||||
|
critLevel.value += 1;
|
||||||
|
}
|
||||||
if (source.getTag(BattlerTagType.CRIT_BOOST))
|
if (source.getTag(BattlerTagType.CRIT_BOOST))
|
||||||
critLevel.value += 2;
|
critLevel.value += 2;
|
||||||
const critChance = Math.ceil(16 / Math.pow(2, critLevel.value));
|
const critChance = Math.ceil(16 / Math.pow(2, critLevel.value));
|
||||||
@ -1688,9 +1696,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
return this.gender !== Gender.GENDERLESS && pokemon.gender === (this.gender === Gender.MALE ? Gender.FEMALE : Gender.MALE);
|
return this.gender !== Gender.GENDERLESS && pokemon.gender === (this.gender === Gender.MALE ? Gender.FEMALE : Gender.MALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
canSetStatus(effect: StatusEffect, quiet: boolean = false): boolean {
|
canSetStatus(effect: StatusEffect, quiet: boolean = false, overrideStatus: boolean = false): boolean {
|
||||||
if (effect !== StatusEffect.FAINT) {
|
if (effect !== StatusEffect.FAINT) {
|
||||||
if (this.status)
|
if (overrideStatus ? this.status?.effect === effect : this.status)
|
||||||
return false;
|
return false;
|
||||||
if (this.isGrounded() && this.scene.arena.terrain?.terrainType === TerrainType.MISTY)
|
if (this.isGrounded() && this.scene.arena.terrain?.terrainType === TerrainType.MISTY)
|
||||||
return false;
|
return false;
|
||||||
@ -2319,25 +2327,25 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
this.generateName();
|
this.generateName();
|
||||||
this.calculateStats();
|
this.calculateStats();
|
||||||
this.generateCompatibleTms();
|
this.generateCompatibleTms();
|
||||||
this.updateInfo(true).then(() => {
|
this.updateInfo(true);
|
||||||
const fusedPartyMemberIndex = this.scene.getParty().indexOf(pokemon);
|
const fusedPartyMemberIndex = this.scene.getParty().indexOf(pokemon);
|
||||||
let partyMemberIndex = this.scene.getParty().indexOf(this);
|
let partyMemberIndex = this.scene.getParty().indexOf(this);
|
||||||
if (partyMemberIndex > fusedPartyMemberIndex)
|
if (partyMemberIndex > fusedPartyMemberIndex)
|
||||||
partyMemberIndex--;
|
partyMemberIndex--;
|
||||||
pokemon.getMoveset(true).map(m => this.scene.unshiftPhase(new LearnMovePhase(this.scene, partyMemberIndex, m.getMove().id)));
|
const fusedPartyMemberHeldModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier
|
||||||
const fusedPartyMemberHeldModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier
|
&& (m as PokemonHeldItemModifier).pokemonId === pokemon.id, true) as PokemonHeldItemModifier[];
|
||||||
&& (m as PokemonHeldItemModifier).pokemonId === pokemon.id, true) as PokemonHeldItemModifier[];
|
const transferModifiers: Promise<boolean>[] = [];
|
||||||
const transferModifiers: Promise<boolean>[] = [];
|
for (let modifier of fusedPartyMemberHeldModifiers)
|
||||||
for (let modifier of fusedPartyMemberHeldModifiers)
|
transferModifiers.push(this.scene.tryTransferHeldItemModifier(modifier, this, true, false, true, true));
|
||||||
transferModifiers.push(this.scene.tryTransferHeldItemModifier(modifier, this, true, false, true, true));
|
Promise.allSettled(transferModifiers).then(() => {
|
||||||
Promise.allSettled(transferModifiers).then(() => {
|
this.scene.updateModifiers(true, true).then(() => {
|
||||||
this.scene.updateModifiers(true, true).then(() => {
|
this.scene.removePartyMemberModifiers(fusedPartyMemberIndex);
|
||||||
this.scene.removePartyMemberModifiers(fusedPartyMemberIndex);
|
this.scene.getParty().splice(fusedPartyMemberIndex, 1)[0];
|
||||||
this.scene.getParty().splice(fusedPartyMemberIndex, 1)[0];
|
const newPartyMemberIndex = this.scene.getParty().indexOf(this);
|
||||||
pokemon.destroy();
|
pokemon.getMoveset(true).map(m => this.scene.unshiftPhase(new LearnMovePhase(this.scene, newPartyMemberIndex, m.getMove().id)));
|
||||||
this.updateFusionPalette();
|
pokemon.destroy();
|
||||||
resolve();
|
this.updateFusionPalette();
|
||||||
});
|
resolve();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -2877,4 +2885,4 @@ export class PokemonMove {
|
|||||||
getName(): string {
|
getName(): string {
|
||||||
return this.getMove().name;
|
return this.getMove().name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
13
src/locales/en/menu.ts
Normal file
13
src/locales/en/menu.ts
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* The menu namespace holds most miscellaneous text that isn't directly part of the game's
|
||||||
|
* contents or directly related to Pokemon. This includes menu navigation, settings,
|
||||||
|
* account interactions, etc.
|
||||||
|
*/
|
||||||
|
export const menu = {
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"continue": "Continue",
|
||||||
|
"dailyRun": "Daily Run (Beta)",
|
||||||
|
"loadGame": "Load Game",
|
||||||
|
"newGame": "New Game",
|
||||||
|
"selectGameMode": "Select a game mode."
|
||||||
|
} as const;
|
8
src/locales/it/menu.ts
Normal file
8
src/locales/it/menu.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export const menu = {
|
||||||
|
"cancel": "Annulla",
|
||||||
|
"continue": "Continua",
|
||||||
|
"newGame": "Nuova Partita",
|
||||||
|
"loadGame": "Carica Partita",
|
||||||
|
"dailyRun": "Corsa Giornaliera (Beta)",
|
||||||
|
"selectGameMode": "Seleziona una modalità di gioco."
|
||||||
|
} as const;
|
@ -109,7 +109,7 @@ export abstract class Modifier {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract apply(args: any[]): boolean;
|
abstract apply(args: any[]): boolean | Promise<boolean>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class PersistentModifier extends Modifier {
|
export abstract class PersistentModifier extends Modifier {
|
||||||
@ -1203,10 +1203,10 @@ export class FusePokemonModifier extends ConsumablePokemonModifier {
|
|||||||
return super.shouldApply(args) && args[1] instanceof PlayerPokemon && this.fusePokemonId === (args[1] as PlayerPokemon).id;
|
return super.shouldApply(args) && args[1] instanceof PlayerPokemon && this.fusePokemonId === (args[1] as PlayerPokemon).id;
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(args: any[]): boolean {
|
apply(args: any[]): Promise<boolean> {
|
||||||
(args[0] as PlayerPokemon).fuse(args[1] as PlayerPokemon);
|
return new Promise<boolean>(resolve => {
|
||||||
|
(args[0] as PlayerPokemon).fuse(args[1] as PlayerPokemon).then(() => resolve(true));
|
||||||
return true;
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,6 +57,7 @@ import { SaveSlotUiMode } from "./ui/save-slot-select-ui-handler";
|
|||||||
import { fetchDailyRunSeed, getDailyRunStarters } from "./data/daily-run";
|
import { fetchDailyRunSeed, getDailyRunStarters } from "./data/daily-run";
|
||||||
import { GameModes, gameModes } from "./game-mode";
|
import { GameModes, gameModes } from "./game-mode";
|
||||||
import { getPokemonSpecies, speciesStarters } from "./data/pokemon-species";
|
import { getPokemonSpecies, speciesStarters } from "./data/pokemon-species";
|
||||||
|
import i18next from './plugins/i18n';
|
||||||
|
|
||||||
export class LoginPhase extends Phase {
|
export class LoginPhase extends Phase {
|
||||||
private showText: boolean;
|
private showText: boolean;
|
||||||
@ -173,12 +174,12 @@ export class TitlePhase extends Phase {
|
|||||||
const options: OptionSelectItem[] = [];
|
const options: OptionSelectItem[] = [];
|
||||||
if (loggedInUser.lastSessionSlot > -1) {
|
if (loggedInUser.lastSessionSlot > -1) {
|
||||||
options.push({
|
options.push({
|
||||||
label: 'Continue',
|
label: i18next.t('menu:continue'),
|
||||||
handler: () => this.loadSaveSlot(this.lastSessionData ? -1 : loggedInUser.lastSessionSlot)
|
handler: () => this.loadSaveSlot(this.lastSessionData ? -1 : loggedInUser.lastSessionSlot)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
options.push({
|
options.push({
|
||||||
label: 'New Game',
|
label: i18next.t('menu:newGame'),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
const setModeAndEnd = (gameMode: GameModes) => {
|
const setModeAndEnd = (gameMode: GameModes) => {
|
||||||
this.gameMode = gameMode;
|
this.gameMode = gameMode;
|
||||||
@ -204,14 +205,14 @@ export class TitlePhase extends Phase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
options.push({
|
options.push({
|
||||||
label: 'Cancel',
|
label: i18next.t('menu:cancel'),
|
||||||
handler: () => {
|
handler: () => {
|
||||||
this.scene.clearPhaseQueue();
|
this.scene.clearPhaseQueue();
|
||||||
this.scene.pushPhase(new TitlePhase(this.scene));
|
this.scene.pushPhase(new TitlePhase(this.scene));
|
||||||
super.end();
|
super.end();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.scene.ui.showText('Select a game mode.', null, () => this.scene.ui.setOverlayMode(Mode.OPTION_SELECT, { options: options }));
|
this.scene.ui.showText(i18next.t("menu:selectGameMode"), null, () => this.scene.ui.setOverlayMode(Mode.OPTION_SELECT, { options: options }));
|
||||||
} else {
|
} else {
|
||||||
this.gameMode = GameModes.CLASSIC;
|
this.gameMode = GameModes.CLASSIC;
|
||||||
this.scene.ui.setMode(Mode.MESSAGE);
|
this.scene.ui.setMode(Mode.MESSAGE);
|
||||||
@ -221,7 +222,7 @@ export class TitlePhase extends Phase {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Load Game',
|
label: i18next.t('menu:loadGame'),
|
||||||
handler: () => this.scene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD,
|
handler: () => this.scene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD,
|
||||||
(slotId: integer) => {
|
(slotId: integer) => {
|
||||||
if (slotId === -1)
|
if (slotId === -1)
|
||||||
@ -231,7 +232,7 @@ export class TitlePhase extends Phase {
|
|||||||
)
|
)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Daily Run (Beta)',
|
label: i18next.t('menu:dailyRun'),
|
||||||
handler: () => this.initDailyRun(),
|
handler: () => this.initDailyRun(),
|
||||||
keepOpen: true
|
keepOpen: true
|
||||||
});
|
});
|
||||||
@ -1294,7 +1295,7 @@ export class SwitchSummonPhase extends SummonPhase {
|
|||||||
if (!this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedPokemon.id)) {
|
if (!this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedPokemon.id)) {
|
||||||
const batonPassModifier = this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier
|
const batonPassModifier = this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier
|
||||||
&& (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id) as SwitchEffectTransferModifier;
|
&& (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id) as SwitchEffectTransferModifier;
|
||||||
if (batonPassModifier)
|
if (batonPassModifier && !this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedPokemon.id))
|
||||||
this.scene.tryTransferHeldItemModifier(batonPassModifier, switchedPokemon, false, false);
|
this.scene.tryTransferHeldItemModifier(batonPassModifier, switchedPokemon, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1568,7 +1569,17 @@ export class CommandPhase extends FieldPhase {
|
|||||||
const moveId = !useStruggle ? cursor > -1 ? playerPokemon.getMoveset()[cursor].moveId : Moves.NONE : Moves.STRUGGLE;
|
const moveId = !useStruggle ? cursor > -1 ? playerPokemon.getMoveset()[cursor].moveId : Moves.NONE : Moves.STRUGGLE;
|
||||||
const turnCommand: TurnCommand = { command: Command.FIGHT, cursor: cursor, move: { move: moveId, targets: [], ignorePP: args[0] }, args: args };
|
const turnCommand: TurnCommand = { command: Command.FIGHT, cursor: cursor, move: { move: moveId, targets: [], ignorePP: args[0] }, args: args };
|
||||||
const moveTargets: MoveTargetSet = args.length < 3 ? getMoveTargets(playerPokemon, moveId) : args[2];
|
const moveTargets: MoveTargetSet = args.length < 3 ? getMoveTargets(playerPokemon, moveId) : args[2];
|
||||||
if (!moveId)
|
if (moveId) {
|
||||||
|
const move = playerPokemon.getMoveset()[cursor];
|
||||||
|
if (move.getName().endsWith(' (N)')) {
|
||||||
|
this.scene.ui.setMode(Mode.MESSAGE);
|
||||||
|
this.scene.ui.showText(`${move.getName().slice(0, -4)} is not yet implemented and cannot be selected.`, null, () => {
|
||||||
|
this.scene.ui.clearText();
|
||||||
|
this.scene.ui.setMode(Mode.FIGHT, this.fieldIndex);
|
||||||
|
}, null, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else
|
||||||
turnCommand.targets = [ this.fieldIndex ];
|
turnCommand.targets = [ this.fieldIndex ];
|
||||||
console.log(moveTargets, playerPokemon.name);
|
console.log(moveTargets, playerPokemon.name);
|
||||||
if (moveTargets.targets.length <= 1 || moveTargets.multiple)
|
if (moveTargets.targets.length <= 1 || moveTargets.multiple)
|
||||||
@ -4092,16 +4103,22 @@ export class SelectModifierPhase extends BattlePhase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const applyModifier = (modifier: Modifier, playSound: boolean = false) => {
|
const applyModifier = (modifier: Modifier, playSound: boolean = false) => {
|
||||||
this.scene.addModifier(modifier, false, playSound);
|
const result = this.scene.addModifier(modifier, false, playSound);
|
||||||
if (cost) {
|
if (cost) {
|
||||||
this.scene.money -= cost;
|
this.scene.money -= cost;
|
||||||
this.scene.updateMoneyText();
|
this.scene.updateMoneyText();
|
||||||
this.scene.playSound('buy');
|
this.scene.playSound('buy');
|
||||||
(this.scene.ui.getHandler() as ModifierSelectUiHandler).updateCostText();
|
(this.scene.ui.getHandler() as ModifierSelectUiHandler).updateCostText();
|
||||||
} else {
|
} else {
|
||||||
this.scene.ui.clearText();
|
const doEnd = () => {
|
||||||
this.scene.ui.setMode(Mode.MESSAGE);
|
this.scene.ui.clearText();
|
||||||
super.end();
|
this.scene.ui.setMode(Mode.MESSAGE);
|
||||||
|
super.end();
|
||||||
|
};
|
||||||
|
if (result instanceof Promise)
|
||||||
|
result.then(() => doEnd());
|
||||||
|
else
|
||||||
|
doEnd();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
42
src/plugins/i18n.ts
Normal file
42
src/plugins/i18n.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
import i18next from 'i18next';
|
||||||
|
import { menu as enMenu } from '../locales/en/menu';
|
||||||
|
import { menu as itMenu } from '../locales/it/menu';
|
||||||
|
|
||||||
|
const DEFAULT_LANGUAGE_OVERRIDE = '';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* i18next is a localization library for maintaining and using translation resources.
|
||||||
|
*
|
||||||
|
* Q: How do I add a new language?
|
||||||
|
* A: To add a new language, create a new folder in the locales directory with the language code.
|
||||||
|
* Each language folder should contain a file for each namespace (ex. menu.ts) with the translations.
|
||||||
|
*
|
||||||
|
* Q: How do I add a new namespace?
|
||||||
|
* A: To add a new namespace, create a new file in each language folder with the translations.
|
||||||
|
* Then update the `resources` field in the init() call and the CustomTypeOptions interface.
|
||||||
|
*/
|
||||||
|
|
||||||
|
i18next.init({
|
||||||
|
lng: DEFAULT_LANGUAGE_OVERRIDE ? DEFAULT_LANGUAGE_OVERRIDE : 'en',
|
||||||
|
fallbackLng: 'en',
|
||||||
|
debug: true,
|
||||||
|
resources: {
|
||||||
|
en: {
|
||||||
|
menu: enMenu,
|
||||||
|
},
|
||||||
|
it: {
|
||||||
|
menu: itMenu,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// Module declared to make referencing keys in the localization files type-safe.
|
||||||
|
declare module 'i18next' {
|
||||||
|
interface CustomTypeOptions {
|
||||||
|
resources: {
|
||||||
|
menu: typeof enMenu;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default i18next;
|
@ -193,7 +193,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
|
|||||||
this.updateBossSegmentDividers(pokemon as EnemyPokemon);
|
this.updateBossSegmentDividers(pokemon as EnemyPokemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hpBar.setScale(pokemon.getHpRatio(), 1);
|
this.hpBar.setScale(pokemon.getHpRatio(true), 1);
|
||||||
this.lastHpFrame = this.hpBar.scaleX > 0.5 ? 'high' : this.hpBar.scaleX > 0.25 ? 'medium' : 'low';
|
this.lastHpFrame = this.hpBar.scaleX > 0.5 ? 'high' : this.hpBar.scaleX > 0.25 ? 'medium' : 'low';
|
||||||
this.hpBar.setFrame(this.lastHpFrame);
|
this.hpBar.setFrame(this.lastHpFrame);
|
||||||
if (this.player)
|
if (this.player)
|
||||||
@ -356,7 +356,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
|
|||||||
this.scene.tweens.add({
|
this.scene.tweens.add({
|
||||||
targets: this.hpBar,
|
targets: this.hpBar,
|
||||||
ease: 'Sine.easeOut',
|
ease: 'Sine.easeOut',
|
||||||
scaleX: pokemon.getHpRatio(),
|
scaleX: pokemon.getHpRatio(true),
|
||||||
duration: duration,
|
duration: duration,
|
||||||
onUpdate: () => {
|
onUpdate: () => {
|
||||||
if (this.player && this.lastHp !== pokemon.hp) {
|
if (this.player && this.lastHp !== pokemon.hp) {
|
||||||
|
@ -1011,13 +1011,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonGrowthRateText.setColor(getGrowthRateColor(species.growthRate));
|
this.pokemonGrowthRateText.setColor(getGrowthRateColor(species.growthRate));
|
||||||
this.pokemonGrowthRateText.setShadowColor(getGrowthRateColor(species.growthRate, true));
|
this.pokemonGrowthRateText.setShadowColor(getGrowthRateColor(species.growthRate, true));
|
||||||
this.pokemonGrowthRateLabelText.setVisible(true);
|
this.pokemonGrowthRateLabelText.setVisible(true);
|
||||||
this.type1Icon.setFrame(Type[species.type1].toLowerCase());
|
|
||||||
this.type1Icon.setVisible(true);
|
|
||||||
if (species.type2) {
|
|
||||||
this.type2Icon.setFrame(Type[species.type2].toLowerCase());
|
|
||||||
this.type2Icon.setVisible(true);
|
|
||||||
} else
|
|
||||||
this.type2Icon.setVisible(false);
|
|
||||||
this.pokemonUncaughtText.setVisible(false);
|
this.pokemonUncaughtText.setVisible(false);
|
||||||
this.pokemonAbilityLabelText.setVisible(true);
|
this.pokemonAbilityLabelText.setVisible(true);
|
||||||
this.pokemonNatureLabelText.setVisible(true);
|
this.pokemonNatureLabelText.setVisible(true);
|
||||||
@ -1037,16 +1030,22 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let props: DexAttrProps;
|
||||||
|
|
||||||
if (starterIndex > -1) {
|
if (starterIndex > -1) {
|
||||||
const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.starterAttr[starterIndex]);
|
props = this.scene.gameData.getSpeciesDexAttrProps(species, this.starterAttr[starterIndex]);
|
||||||
this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.abilityIndex, this.starterNatures[starterIndex]);
|
this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.abilityIndex, this.starterNatures[starterIndex]);
|
||||||
} else {
|
} else {
|
||||||
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species);
|
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species);
|
||||||
const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species);
|
const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species);
|
||||||
const props = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
|
props = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
|
||||||
|
|
||||||
this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.abilityIndex, defaultNature);
|
this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.abilityIndex, defaultNature);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const speciesForm = getPokemonSpeciesForm(species.speciesId, props.formIndex);
|
||||||
|
this.setTypeIcons(speciesForm.type1, speciesForm.type2);
|
||||||
|
|
||||||
this.pokemonSprite.clearTint();
|
this.pokemonSprite.clearTint();
|
||||||
if (this.pokerusCursors.find((cursor: integer, i: integer) => cursor === this.cursor && this.pokerusGens[i] === this.genCursor))
|
if (this.pokerusCursors.find((cursor: integer, i: integer) => cursor === this.cursor && this.pokerusGens[i] === this.genCursor))
|
||||||
handleTutorial(this.scene, Tutorial.Pokerus);
|
handleTutorial(this.scene, Tutorial.Pokerus);
|
||||||
@ -1212,9 +1211,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
// Consolidate move data if it contains an incompatible move
|
// Consolidate move data if it contains an incompatible move
|
||||||
if (this.starterMoveset.length < 4 && this.starterMoveset.length < availableStarterMoves.length)
|
if (this.starterMoveset.length < 4 && this.starterMoveset.length < availableStarterMoves.length)
|
||||||
this.starterMoveset.push(...availableStarterMoves.filter(sm => this.starterMoveset.indexOf(sm) === -1).slice(0, 4 - this.starterMoveset.length));
|
this.starterMoveset.push(...availableStarterMoves.filter(sm => this.starterMoveset.indexOf(sm) === -1).slice(0, 4 - this.starterMoveset.length));
|
||||||
|
|
||||||
|
const speciesForm = getPokemonSpeciesForm(species.speciesId, formIndex);
|
||||||
|
this.setTypeIcons(speciesForm.type1, speciesForm.type2);
|
||||||
} else {
|
} else {
|
||||||
this.pokemonAbilityText.setText('');
|
this.pokemonAbilityText.setText('');
|
||||||
this.pokemonNatureText.setText('');
|
this.pokemonNatureText.setText('');
|
||||||
|
this.setTypeIcons(null, null);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.shinyOverlay.setVisible(false);
|
this.shinyOverlay.setVisible(false);
|
||||||
@ -1223,6 +1226,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonGenderText.setText('');
|
this.pokemonGenderText.setText('');
|
||||||
this.pokemonAbilityText.setText('');
|
this.pokemonAbilityText.setText('');
|
||||||
this.pokemonNatureText.setText('');
|
this.pokemonNatureText.setText('');
|
||||||
|
this.setTypeIcons(null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.starterMoveset)
|
if (!this.starterMoveset)
|
||||||
@ -1252,6 +1256,19 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.updateInstructions();
|
this.updateInstructions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setTypeIcons(type1: Type, type2: Type): void {
|
||||||
|
if (type1 !== null) {
|
||||||
|
this.type1Icon.setVisible(true);
|
||||||
|
this.type1Icon.setFrame(Type[type1].toLowerCase());
|
||||||
|
} else
|
||||||
|
this.type1Icon.setVisible(false);
|
||||||
|
if (type2 !== null) {
|
||||||
|
this.type2Icon.setVisible(true);
|
||||||
|
this.type2Icon.setFrame(Type[type2].toLowerCase());
|
||||||
|
} else
|
||||||
|
this.type2Icon.setVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
popStarter(): void {
|
popStarter(): void {
|
||||||
this.starterGens.pop();
|
this.starterGens.pop();
|
||||||
this.starterCursors.pop();
|
this.starterCursors.pop();
|
||||||
|
Loading…
Reference in New Issue
Block a user