Merge remote-tracking branch 'upstream/main' into feature/guard-dog
@ -19,7 +19,7 @@ If you have the motivation and experience with Typescript/Javascript (or are wil
|
|||||||
### ❔ FAQ
|
### ❔ FAQ
|
||||||
|
|
||||||
**How do I test a new _______?**
|
**How do I test a new _______?**
|
||||||
- In the `battle-scene.ts` file there are overrides for most values you'll need to change for testing
|
- In the `src/overrides.ts` file there are overrides for most values you'll need to change for testing
|
||||||
|
|
||||||
|
|
||||||
## 🪧 To Do
|
## 🪧 To Do
|
||||||
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 49 KiB |
BIN
public/images/items/burn_drive.png
Normal file
After Width: | Height: | Size: 303 B |
BIN
public/images/items/chill_drive.png
Normal file
After Width: | Height: | Size: 303 B |
BIN
public/images/items/douse_drive.png
Normal file
After Width: | Height: | Size: 303 B |
BIN
public/images/items/shock_drive.png
Normal file
After Width: | Height: | Size: 303 B |
BIN
public/images/ui/candy.png
Normal file
After Width: | Height: | Size: 415 B |
BIN
public/images/ui/candy_overlay.png
Normal file
After Width: | Height: | Size: 211 B |
BIN
public/images/ui/legacy/candy.png
Normal file
After Width: | Height: | Size: 415 B |
BIN
public/images/ui/legacy/candy_overlay.png
Normal file
After Width: | Height: | Size: 211 B |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 3.6 KiB |
@ -3,7 +3,7 @@
|
|||||||
"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": "/",
|
"scope": "/",
|
||||||
"start_url": "https://pokerogue.net",
|
"start_url": "/",
|
||||||
"display": "fullscreen",
|
"display": "fullscreen",
|
||||||
"background_color": "#8c8c8c",
|
"background_color": "#8c8c8c",
|
||||||
"theme_color": "#8c8c8c",
|
"theme_color": "#8c8c8c",
|
||||||
|
@ -9,7 +9,7 @@ import { BattlerTag } from "./battler-tags";
|
|||||||
import { BattlerTagType } from "./enums/battler-tag-type";
|
import { BattlerTagType } from "./enums/battler-tag-type";
|
||||||
import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
||||||
import { Gender } from "./gender";
|
import { Gender } from "./gender";
|
||||||
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves } from "./move";
|
import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, RecoilAttr, StatusMoveTypeImmunityAttr, FlinchAttr, OneHitKOAttr, HitHealAttr, StrengthSapHealAttr, allMoves, StatusMove } from "./move";
|
||||||
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 { Stat } from "./pokemon-stat";
|
import { Stat } from "./pokemon-stat";
|
||||||
@ -828,13 +828,16 @@ export class PostDefendAbilitySwapAbAttr extends PostDefendAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr {
|
export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr {
|
||||||
constructor() {
|
private ability: Abilities;
|
||||||
|
|
||||||
|
constructor(ability: Abilities) {
|
||||||
super();
|
super();
|
||||||
|
this.ability = ability;
|
||||||
}
|
}
|
||||||
|
|
||||||
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
|
applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
|
||||||
if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.getAbility().hasAttr(UnsuppressableAbilityAbAttr) && !attacker.getAbility().hasAttr(PostDefendAbilityGiveAbAttr)) {
|
if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.getAbility().hasAttr(UnsuppressableAbilityAbAttr) && !attacker.getAbility().hasAttr(PostDefendAbilityGiveAbAttr)) {
|
||||||
attacker.summonData.ability = pokemon.getAbility().id;
|
attacker.summonData.ability = this.ability;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -1820,6 +1823,53 @@ function getAnticipationCondition(): AbAttrCondition {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ForewarnAbAttr extends PostSummonAbAttr {
|
||||||
|
constructor() {
|
||||||
|
super(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
|
||||||
|
let maxPowerSeen = 0;
|
||||||
|
let maxMove = "";
|
||||||
|
let movePower = 0;
|
||||||
|
for (let opponent of pokemon.getOpponents()) {
|
||||||
|
for (let move of opponent.moveset) {
|
||||||
|
if (move.getMove() instanceof StatusMove) {
|
||||||
|
movePower = 1;
|
||||||
|
} else if (move.getMove().findAttr(attr => attr instanceof OneHitKOAttr)) {
|
||||||
|
movePower = 150;
|
||||||
|
} else if (move.getMove().id === Moves.COUNTER || move.getMove().id === Moves.MIRROR_COAT || move.getMove().id === Moves.METAL_BURST) {
|
||||||
|
movePower = 120;
|
||||||
|
} else if (move.getMove().power === -1) {
|
||||||
|
movePower = 80;
|
||||||
|
} else {
|
||||||
|
movePower = move.getMove().power;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (movePower > maxPowerSeen) {
|
||||||
|
maxPowerSeen = movePower;
|
||||||
|
maxMove = move.getName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " was forewarned about " + maxMove + "!"));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FriskAbAttr extends PostSummonAbAttr {
|
||||||
|
constructor() {
|
||||||
|
super(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
|
||||||
|
for (let opponent of pokemon.getOpponents()) {
|
||||||
|
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " frisked " + opponent.name + "\'s " + opponent.getAbility().name + "!"));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class PostWeatherChangeAbAttr extends AbAttr {
|
export class PostWeatherChangeAbAttr extends AbAttr {
|
||||||
applyPostWeatherChange(pokemon: Pokemon, passive: boolean, weather: WeatherType, args: any[]): boolean {
|
applyPostWeatherChange(pokemon: Pokemon, passive: boolean, weather: WeatherType, args: any[]): boolean {
|
||||||
return false;
|
return false;
|
||||||
@ -1970,13 +2020,19 @@ export class MoodyAbAttr extends PostTurnAbAttr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
|
applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
|
||||||
// TODO: Edge case of not choosing to buff or debuff a stat that's already maxed
|
|
||||||
let selectableStats = [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD];
|
let selectableStats = [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD];
|
||||||
let increaseStat = selectableStats[Utils.randInt(selectableStats.length)];
|
let increaseStatArray = selectableStats.filter(s => pokemon.summonData.battleStats[s] < 6);
|
||||||
selectableStats = selectableStats.filter(s => s !== increaseStat);
|
let decreaseStatArray = selectableStats.filter(s => pokemon.summonData.battleStats[s] > -6);
|
||||||
let decreaseStat = selectableStats[Utils.randInt(selectableStats.length)];
|
|
||||||
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [increaseStat], 2));
|
if (increaseStatArray.length > 0) {
|
||||||
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [decreaseStat], -1));
|
let increaseStat = increaseStatArray[Utils.randInt(increaseStatArray.length)];
|
||||||
|
decreaseStatArray = decreaseStatArray.filter(s => s !== increaseStat);
|
||||||
|
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [increaseStat], 2));
|
||||||
|
}
|
||||||
|
if (decreaseStatArray.length > 0) {
|
||||||
|
let decreaseStat = selectableStats[Utils.randInt(selectableStats.length)];
|
||||||
|
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [decreaseStat], -1));
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2083,6 +2139,13 @@ export class StatChangeMultiplierAbAttr extends AbAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class StatChangeCopyAbAttr extends AbAttr {
|
||||||
|
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise<boolean> {
|
||||||
|
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, (args[0] as BattleStat[]), (args[1] as integer), true, false, false));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class BypassBurnDamageReductionAbAttr extends AbAttr {
|
export class BypassBurnDamageReductionAbAttr extends AbAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super(false);
|
super(false);
|
||||||
@ -2903,7 +2966,7 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.ANTICIPATION, 4)
|
new Ability(Abilities.ANTICIPATION, 4)
|
||||||
.conditionalAttr(getAnticipationCondition(), PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, ' shuddered!')),
|
.conditionalAttr(getAnticipationCondition(), PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, ' shuddered!')),
|
||||||
new Ability(Abilities.FOREWARN, 4)
|
new Ability(Abilities.FOREWARN, 4)
|
||||||
.unimplemented(),
|
.attr(ForewarnAbAttr),
|
||||||
new Ability(Abilities.UNAWARE, 4)
|
new Ability(Abilities.UNAWARE, 4)
|
||||||
.attr(IgnoreOpponentStatChangesAbAttr)
|
.attr(IgnoreOpponentStatChangesAbAttr)
|
||||||
.ignorable(),
|
.ignorable(),
|
||||||
@ -2933,7 +2996,7 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.HONEY_GATHER, 4)
|
new Ability(Abilities.HONEY_GATHER, 4)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new Ability(Abilities.FRISK, 4)
|
new Ability(Abilities.FRISK, 4)
|
||||||
.unimplemented(),
|
.attr(FriskAbAttr),
|
||||||
new Ability(Abilities.RECKLESS, 4)
|
new Ability(Abilities.RECKLESS, 4)
|
||||||
.attr(MovePowerBoostAbAttr, (user, target, move) => move.getAttrs(RecoilAttr).length && move.id !== Moves.STRUGGLE, 1.2),
|
.attr(MovePowerBoostAbAttr, (user, target, move) => move.getAttrs(RecoilAttr).length && move.id !== Moves.STRUGGLE, 1.2),
|
||||||
new Ability(Abilities.MULTITYPE, 4)
|
new Ability(Abilities.MULTITYPE, 4)
|
||||||
@ -3026,7 +3089,7 @@ export function initAbilities() {
|
|||||||
new Ability(Abilities.INFILTRATOR, 5)
|
new Ability(Abilities.INFILTRATOR, 5)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new Ability(Abilities.MUMMY, 5)
|
new Ability(Abilities.MUMMY, 5)
|
||||||
.attr(PostDefendAbilityGiveAbAttr)
|
.attr(PostDefendAbilityGiveAbAttr, Abilities.MUMMY)
|
||||||
.bypassFaint(),
|
.bypassFaint(),
|
||||||
new Ability(Abilities.MOXIE, 5)
|
new Ability(Abilities.MOXIE, 5)
|
||||||
.attr(PostVictoryStatChangeAbAttr, BattleStat.ATK, 1),
|
.attr(PostVictoryStatChangeAbAttr, BattleStat.ATK, 1),
|
||||||
@ -3359,6 +3422,7 @@ export function initAbilities() {
|
|||||||
.attr(UncopiableAbilityAbAttr)
|
.attr(UncopiableAbilityAbAttr)
|
||||||
.attr(UnswappableAbilityAbAttr)
|
.attr(UnswappableAbilityAbAttr)
|
||||||
.attr(NoTransformAbilityAbAttr)
|
.attr(NoTransformAbilityAbAttr)
|
||||||
|
.attr(PostSummonMessageAbAttr, (pokemon: Pokemon) => getPokemonMessage(pokemon, '\'s Neutralizing Gas filled the area!'))
|
||||||
.partial(),
|
.partial(),
|
||||||
new Ability(Abilities.PASTEL_VEIL, 8)
|
new Ability(Abilities.PASTEL_VEIL, 8)
|
||||||
.attr(StatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
|
.attr(StatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC)
|
||||||
@ -3397,7 +3461,7 @@ export function initAbilities() {
|
|||||||
.attr(UnswappableAbilityAbAttr)
|
.attr(UnswappableAbilityAbAttr)
|
||||||
.attr(UnsuppressableAbilityAbAttr),
|
.attr(UnsuppressableAbilityAbAttr),
|
||||||
new Ability(Abilities.LINGERING_AROMA, 9)
|
new Ability(Abilities.LINGERING_AROMA, 9)
|
||||||
.attr(PostDefendAbilityGiveAbAttr)
|
.attr(PostDefendAbilityGiveAbAttr, Abilities.LINGERING_AROMA)
|
||||||
.bypassFaint(),
|
.bypassFaint(),
|
||||||
new Ability(Abilities.SEED_SOWER, 9)
|
new Ability(Abilities.SEED_SOWER, 9)
|
||||||
.attr(PostDefendTerrainChangeAbAttr, TerrainType.GRASSY),
|
.attr(PostDefendTerrainChangeAbAttr, TerrainType.GRASSY),
|
||||||
@ -3478,7 +3542,7 @@ export function initAbilities() {
|
|||||||
.attr(PostBiomeChangeTerrainChangeAbAttr, TerrainType.ELECTRIC)
|
.attr(PostBiomeChangeTerrainChangeAbAttr, TerrainType.ELECTRIC)
|
||||||
.conditionalAttr(getTerrainCondition(TerrainType.ELECTRIC), BattleStatMultiplierAbAttr, BattleStat.SPATK, 4 / 3),
|
.conditionalAttr(getTerrainCondition(TerrainType.ELECTRIC), BattleStatMultiplierAbAttr, BattleStat.SPATK, 4 / 3),
|
||||||
new Ability(Abilities.OPPORTUNIST, 9)
|
new Ability(Abilities.OPPORTUNIST, 9)
|
||||||
.unimplemented(),
|
.attr(StatChangeCopyAbAttr),
|
||||||
new Ability(Abilities.CUD_CHEW, 9)
|
new Ability(Abilities.CUD_CHEW, 9)
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new Ability(Abilities.SHARPNESS, 9)
|
new Ability(Abilities.SHARPNESS, 9)
|
||||||
|
@ -984,6 +984,19 @@ export class HideSpriteTag extends BattlerTag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TypeImmuneTag extends BattlerTag {
|
||||||
|
public immuneType: Type;
|
||||||
|
constructor(tagType: BattlerTagType, sourceMove: Moves, immuneType: Type, length: number) {
|
||||||
|
super(tagType, BattlerTagLapseType.TURN_END, 1, sourceMove);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MagnetRisenTag extends TypeImmuneTag {
|
||||||
|
constructor(tagType: BattlerTagType, sourceMove: Moves) {
|
||||||
|
super(tagType, sourceMove, Type.GROUND, 5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class TypeBoostTag extends BattlerTag {
|
export class TypeBoostTag extends BattlerTag {
|
||||||
public boostedType: Type;
|
public boostedType: Type;
|
||||||
public boostValue: number;
|
public boostValue: number;
|
||||||
@ -1211,6 +1224,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
|
|||||||
return new CursedTag(sourceId);
|
return new CursedTag(sourceId);
|
||||||
case BattlerTagType.CHARGED:
|
case BattlerTagType.CHARGED:
|
||||||
return new TypeBoostTag(tagType, sourceMove, Type.ELECTRIC, 2, true);
|
return new TypeBoostTag(tagType, sourceMove, Type.ELECTRIC, 2, true);
|
||||||
|
case BattlerTagType.MAGNET_RISEN:
|
||||||
|
return new MagnetRisenTag(tagType, sourceMove);
|
||||||
case BattlerTagType.NONE:
|
case BattlerTagType.NONE:
|
||||||
default:
|
default:
|
||||||
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
|
||||||
|
@ -115,7 +115,7 @@ export const speciesEggMoves = {
|
|||||||
[Species.PHANPY]: [ Moves.SHORE_UP, Moves.HEAD_SMASH, Moves.MOUNTAIN_GALE, Moves.VOLT_TACKLE ],
|
[Species.PHANPY]: [ Moves.SHORE_UP, Moves.HEAD_SMASH, Moves.MOUNTAIN_GALE, Moves.VOLT_TACKLE ],
|
||||||
[Species.STANTLER]: [ Moves.HORN_LEECH, Moves.HIGH_JUMP_KICK, Moves.BULK_UP, Moves.HEAD_CHARGE ],
|
[Species.STANTLER]: [ Moves.HORN_LEECH, Moves.HIGH_JUMP_KICK, Moves.BULK_UP, Moves.HEAD_CHARGE ],
|
||||||
[Species.SMEARGLE]: [ Moves.BATON_PASS, Moves.BURNING_BULWARK, Moves.SALT_CURE, Moves.SPORE ],
|
[Species.SMEARGLE]: [ Moves.BATON_PASS, Moves.BURNING_BULWARK, Moves.SALT_CURE, Moves.SPORE ],
|
||||||
[Species.TYROGUE]: [ Moves.MACH_PUNCH, Moves.WICKED_TORQUE, Moves.METEOR_MASH, Moves.COLLISION_COURSE ],
|
[Species.TYROGUE]: [ Moves.VICTORY_DANCE, Moves.WICKED_TORQUE, Moves.METEOR_MASH, Moves.COLLISION_COURSE ],
|
||||||
[Species.SMOOCHUM]: [ Moves.EXPANDING_FORCE, Moves.AURA_SPHERE, Moves.FREEZY_FROST, Moves.TAKE_HEART ],
|
[Species.SMOOCHUM]: [ Moves.EXPANDING_FORCE, Moves.AURA_SPHERE, Moves.FREEZY_FROST, Moves.TAKE_HEART ],
|
||||||
[Species.ELEKID]: [ Moves.DRAIN_PUNCH, Moves.TIDY_UP, Moves.ICE_HAMMER, Moves.PLASMA_FISTS ],
|
[Species.ELEKID]: [ Moves.DRAIN_PUNCH, Moves.TIDY_UP, Moves.ICE_HAMMER, Moves.PLASMA_FISTS ],
|
||||||
[Species.MAGBY]: [ Moves.STORED_POWER, Moves.EARTH_POWER, Moves.ARMOR_CANNON, Moves.FLEUR_CANNON ],
|
[Species.MAGBY]: [ Moves.STORED_POWER, Moves.EARTH_POWER, Moves.ARMOR_CANNON, Moves.FLEUR_CANNON ],
|
||||||
|
@ -77,8 +77,6 @@ export function getEggHatchWavesMessage(hatchWaves: integer): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getEggGachaTypeDescriptor(scene: BattleScene, egg: Egg): string {
|
export function getEggGachaTypeDescriptor(scene: BattleScene, egg: Egg): string {
|
||||||
if (egg.isManaphyEgg())
|
|
||||||
return '';
|
|
||||||
switch (egg.gachaType) {
|
switch (egg.gachaType) {
|
||||||
case GachaType.LEGENDARY:
|
case GachaType.LEGENDARY:
|
||||||
return `Legendary Rate Up (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(scene, egg.timestamp)).getName()})`;
|
return `Legendary Rate Up (${getPokemonSpecies(getLegendaryGachaSpeciesForTimestamp(scene, egg.timestamp)).getName()})`;
|
||||||
|
@ -54,5 +54,6 @@ export enum BattlerTagType {
|
|||||||
SALT_CURED = "SALT_CURED",
|
SALT_CURED = "SALT_CURED",
|
||||||
CURSED = "CURSED",
|
CURSED = "CURSED",
|
||||||
CHARGED = "CHARGED",
|
CHARGED = "CHARGED",
|
||||||
GROUNDED = "GROUNDED"
|
GROUNDED = "GROUNDED",
|
||||||
|
MAGNET_RISEN = "MAGNET_RISEN"
|
||||||
}
|
}
|
||||||
|
@ -1496,6 +1496,23 @@ export class StatChangeAttr extends MoveEffectAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class AcupressureStatChangeAttr extends MoveEffectAttr {
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise<boolean> {
|
||||||
|
let randStats = [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD, BattleStat.ACC, BattleStat.EVA ];
|
||||||
|
randStats = randStats.filter(s => target.summonData.battleStats[s] < 6);
|
||||||
|
if (randStats.length > 0) {
|
||||||
|
let boostStat = [randStats[Utils.randInt(randStats.length)]];
|
||||||
|
user.scene.unshiftPhase(new StatChangePhase(user.scene, target.getBattlerIndex(), this.selfTarget, boostStat, 2));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class GrowthStatChangeAttr extends StatChangeAttr {
|
export class GrowthStatChangeAttr extends StatChangeAttr {
|
||||||
constructor() {
|
constructor() {
|
||||||
super([ BattleStat.ATK, BattleStat.SPATK ], 1, true);
|
super([ BattleStat.ATK, BattleStat.SPATK ], 1, true);
|
||||||
@ -2199,6 +2216,36 @@ export class VariableMoveTypeAttr extends MoveAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TechnoBlastTypeAttr extends VariableMoveTypeAttr {
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
if ([user.species.speciesId, user.fusionSpecies?.speciesId].includes(Species.GENESECT)) {
|
||||||
|
const form = user.species.speciesId === Species.GENESECT ? user.formIndex : user.fusionSpecies.formIndex;
|
||||||
|
const type = (args[0] as Utils.IntegerHolder);
|
||||||
|
|
||||||
|
switch (form) {
|
||||||
|
case 1: // Shock Drive
|
||||||
|
type.value = Type.ELECTRIC;
|
||||||
|
break;
|
||||||
|
case 2: // Burn Drive
|
||||||
|
type.value = Type.FIRE;
|
||||||
|
break;
|
||||||
|
case 3: // Chill Drive
|
||||||
|
type.value = Type.ICE;
|
||||||
|
break;
|
||||||
|
case 4: // Douse Drive
|
||||||
|
type.value = Type.WATER;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
type.value = Type.NORMAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class AuraWheelTypeAttr extends VariableMoveTypeAttr {
|
export class AuraWheelTypeAttr extends VariableMoveTypeAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if ([user.species.speciesId, user.fusionSpecies?.speciesId].includes(Species.MORPEKO)) {
|
if ([user.species.speciesId, user.fusionSpecies?.speciesId].includes(Species.MORPEKO)) {
|
||||||
@ -3695,6 +3742,22 @@ export class LastResortAttr extends MoveAttr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class VariableTargetAttr extends MoveAttr {
|
||||||
|
private targetChangeFunc: (user: Pokemon, target: Pokemon, move: Move) => number;
|
||||||
|
|
||||||
|
constructor(targetChange: (user: Pokemon, target: Pokemon, move: Move) => number) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.targetChangeFunc = targetChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
const targetVal = args[0] as Utils.NumberHolder;
|
||||||
|
targetVal.value = this.targetChangeFunc(user, target, move);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const failOnGravityCondition: MoveConditionFunc = (user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY);
|
const failOnGravityCondition: MoveConditionFunc = (user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY);
|
||||||
|
|
||||||
const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.isBossImmune();
|
const failOnBossCondition: MoveConditionFunc = (user, target, move) => !target.isBossImmune();
|
||||||
@ -3775,7 +3838,10 @@ export type MoveTargetSet = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getMoveTargets(user: Pokemon, move: Moves): MoveTargetSet {
|
export function getMoveTargets(user: Pokemon, move: Moves): MoveTargetSet {
|
||||||
const moveTarget = move ? allMoves[move].moveTarget : move === undefined ? MoveTarget.NEAR_ENEMY : [];
|
const variableTarget = new Utils.NumberHolder(0);
|
||||||
|
user.getOpponents().forEach(p => applyMoveAttrs(VariableTargetAttr, user, p, allMoves[move], variableTarget));
|
||||||
|
|
||||||
|
const moveTarget = allMoves[move].getAttrs(VariableTargetAttr).length ? variableTarget.value : move ? allMoves[move].moveTarget : move === undefined ? MoveTarget.NEAR_ENEMY : [];
|
||||||
const opponents = user.getOpponents();
|
const opponents = user.getOpponents();
|
||||||
|
|
||||||
let set: Pokemon[] = [];
|
let set: Pokemon[] = [];
|
||||||
@ -4705,8 +4771,7 @@ export function initMoves() {
|
|||||||
.attr(StatusEffectAttr, StatusEffect.SLEEP)
|
.attr(StatusEffectAttr, StatusEffect.SLEEP)
|
||||||
.soundBased(),
|
.soundBased(),
|
||||||
new StatusMove(Moves.TICKLE, Type.NORMAL, 100, 20, -1, 0, 3)
|
new StatusMove(Moves.TICKLE, Type.NORMAL, 100, 20, -1, 0, 3)
|
||||||
.attr(StatChangeAttr, BattleStat.ATK, -1)
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.DEF ], -1),
|
||||||
.attr(StatChangeAttr, BattleStat.DEF, -1),
|
|
||||||
new SelfStatusMove(Moves.COSMIC_POWER, Type.PSYCHIC, -1, 20, -1, 0, 3)
|
new SelfStatusMove(Moves.COSMIC_POWER, Type.PSYCHIC, -1, 20, -1, 0, 3)
|
||||||
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, true),
|
.attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, true),
|
||||||
new AttackMove(Moves.WATER_SPOUT, Type.WATER, MoveCategory.SPECIAL, 150, 100, 5, -1, 0, 3)
|
new AttackMove(Moves.WATER_SPOUT, Type.WATER, MoveCategory.SPECIAL, 150, 100, 5, -1, 0, 3)
|
||||||
@ -4828,7 +4893,7 @@ export function initMoves() {
|
|||||||
.attr(AddArenaTagAttr, ArenaTagType.TAILWIND, 4, true)
|
.attr(AddArenaTagAttr, ArenaTagType.TAILWIND, 4, true)
|
||||||
.target(MoveTarget.USER_SIDE),
|
.target(MoveTarget.USER_SIDE),
|
||||||
new StatusMove(Moves.ACUPRESSURE, Type.NORMAL, -1, 30, -1, 0, 4)
|
new StatusMove(Moves.ACUPRESSURE, Type.NORMAL, -1, 30, -1, 0, 4)
|
||||||
.attr(StatChangeAttr, BattleStat.RAND, 2)
|
.attr(AcupressureStatChangeAttr)
|
||||||
.target(MoveTarget.USER_OR_NEAR_ALLY),
|
.target(MoveTarget.USER_OR_NEAR_ALLY),
|
||||||
new AttackMove(Moves.METAL_BURST, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 4)
|
new AttackMove(Moves.METAL_BURST, Type.STEEL, MoveCategory.PHYSICAL, -1, 100, 10, -1, 0, 4)
|
||||||
.attr(CounterDamageAttr, (move: Move) => (move.category === MoveCategory.PHYSICAL || move.category === MoveCategory.SPECIAL), 1.5)
|
.attr(CounterDamageAttr, (move: Move) => (move.category === MoveCategory.PHYSICAL || move.category === MoveCategory.SPECIAL), 1.5)
|
||||||
@ -4900,6 +4965,10 @@ export function initMoves() {
|
|||||||
new SelfStatusMove(Moves.AQUA_RING, Type.WATER, -1, 20, -1, 0, 4)
|
new SelfStatusMove(Moves.AQUA_RING, Type.WATER, -1, 20, -1, 0, 4)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true),
|
.attr(AddBattlerTagAttr, BattlerTagType.AQUA_RING, true, true),
|
||||||
new SelfStatusMove(Moves.MAGNET_RISE, Type.ELECTRIC, -1, 10, -1, 0, 4)
|
new SelfStatusMove(Moves.MAGNET_RISE, Type.ELECTRIC, -1, 10, -1, 0, 4)
|
||||||
|
.attr(AddBattlerTagAttr, BattlerTagType.MAGNET_RISEN, true, true)
|
||||||
|
.condition((user, target, move) => !user.scene.arena.getTag(ArenaTagType.GRAVITY) &&
|
||||||
|
!user.getTag(BattlerTagType.IGNORE_FLYING) && !user.getTag(BattlerTagType.INGRAIN) &&
|
||||||
|
!user.getTag(BattlerTagType.MAGNET_RISEN))
|
||||||
.unimplemented(),
|
.unimplemented(),
|
||||||
new AttackMove(Moves.FLARE_BLITZ, Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 10, 0, 4)
|
new AttackMove(Moves.FLARE_BLITZ, Type.FIRE, MoveCategory.PHYSICAL, 120, 100, 15, 10, 0, 4)
|
||||||
.attr(RecoilAttr, false, 0.33)
|
.attr(RecoilAttr, false, 0.33)
|
||||||
@ -5299,7 +5368,7 @@ export function initMoves() {
|
|||||||
.ballBombMove()
|
.ballBombMove()
|
||||||
.target(MoveTarget.ALL_NEAR_OTHERS),
|
.target(MoveTarget.ALL_NEAR_OTHERS),
|
||||||
new AttackMove(Moves.TECHNO_BLAST, Type.NORMAL, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 5)
|
new AttackMove(Moves.TECHNO_BLAST, Type.NORMAL, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 5)
|
||||||
.partial(),
|
.attr(TechnoBlastTypeAttr),
|
||||||
new AttackMove(Moves.RELIC_SONG, Type.NORMAL, MoveCategory.SPECIAL, 75, 100, 10, 10, 0, 5)
|
new AttackMove(Moves.RELIC_SONG, Type.NORMAL, MoveCategory.SPECIAL, 75, 100, 10, 10, 0, 5)
|
||||||
.attr(StatusEffectAttr, StatusEffect.SLEEP)
|
.attr(StatusEffectAttr, StatusEffect.SLEEP)
|
||||||
.soundBased()
|
.soundBased()
|
||||||
@ -5742,8 +5811,7 @@ export function initMoves() {
|
|||||||
.ignoresAbilities()
|
.ignoresAbilities()
|
||||||
.partial(),
|
.partial(),
|
||||||
new StatusMove(Moves.TEARFUL_LOOK, Type.NORMAL, -1, 20, 100, 0, 7)
|
new StatusMove(Moves.TEARFUL_LOOK, Type.NORMAL, -1, 20, 100, 0, 7)
|
||||||
.attr(StatChangeAttr, BattleStat.ATK, -1)
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], -1),
|
||||||
.attr(StatChangeAttr, BattleStat.SPATK, -1),
|
|
||||||
new AttackMove(Moves.ZING_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 80, 100, 10, 30, 0, 7)
|
new AttackMove(Moves.ZING_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 80, 100, 10, 30, 0, 7)
|
||||||
.attr(FlinchAttr),
|
.attr(FlinchAttr),
|
||||||
new AttackMove(Moves.NATURES_MADNESS, Type.FAIRY, MoveCategory.SPECIAL, -1, 90, 10, -1, 0, 7)
|
new AttackMove(Moves.NATURES_MADNESS, Type.FAIRY, MoveCategory.SPECIAL, -1, 90, 10, -1, 0, 7)
|
||||||
@ -5922,8 +5990,7 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.BODY_PRESS, Type.FIGHTING, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 8)
|
new AttackMove(Moves.BODY_PRESS, Type.FIGHTING, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 8)
|
||||||
.attr(DefAtkAttr),
|
.attr(DefAtkAttr),
|
||||||
new StatusMove(Moves.DECORATE, Type.FAIRY, -1, 15, 100, 0, 8)
|
new StatusMove(Moves.DECORATE, Type.FAIRY, -1, 15, 100, 0, 8)
|
||||||
.attr(StatChangeAttr, BattleStat.ATK, 2)
|
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 2),
|
||||||
.attr(StatChangeAttr, BattleStat.SPATK, 2),
|
|
||||||
new AttackMove(Moves.DRUM_BEATING, Type.GRASS, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 8)
|
new AttackMove(Moves.DRUM_BEATING, Type.GRASS, MoveCategory.PHYSICAL, 80, 100, 10, 100, 0, 8)
|
||||||
.attr(StatChangeAttr, BattleStat.SPD, -1)
|
.attr(StatChangeAttr, BattleStat.SPD, -1)
|
||||||
.makesContact(false),
|
.makesContact(false),
|
||||||
@ -5973,7 +6040,8 @@ export function initMoves() {
|
|||||||
new AttackMove(Moves.STEEL_BEAM, Type.STEEL, MoveCategory.SPECIAL, 140, 95, 5, -1, 0, 8)
|
new AttackMove(Moves.STEEL_BEAM, Type.STEEL, MoveCategory.SPECIAL, 140, 95, 5, -1, 0, 8)
|
||||||
.attr(HalfSacrificialAttr),
|
.attr(HalfSacrificialAttr),
|
||||||
new AttackMove(Moves.EXPANDING_FORCE, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 8)
|
new AttackMove(Moves.EXPANDING_FORCE, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, -1, 0, 8)
|
||||||
.partial(),
|
.attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.PSYCHIC && user.isGrounded() ? 1.5 : 1)
|
||||||
|
.attr(VariableTargetAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.PSYCHIC && user.isGrounded() ? 6 : 3),
|
||||||
new AttackMove(Moves.STEEL_ROLLER, Type.STEEL, MoveCategory.PHYSICAL, 130, 100, 5, -1, 0, 8)
|
new AttackMove(Moves.STEEL_ROLLER, Type.STEEL, MoveCategory.PHYSICAL, 130, 100, 5, -1, 0, 8)
|
||||||
.attr(ClearTerrainAttr)
|
.attr(ClearTerrainAttr)
|
||||||
.condition((user, target, move) => !!user.scene.arena.terrain),
|
.condition((user, target, move) => !!user.scene.arena.terrain),
|
||||||
|
@ -82,7 +82,11 @@ export enum FormChangeItem {
|
|||||||
SHADOW_REINS_OF_UNITY,
|
SHADOW_REINS_OF_UNITY,
|
||||||
WELLSPRING_MASK,
|
WELLSPRING_MASK,
|
||||||
HEARTHFLAME_MASK,
|
HEARTHFLAME_MASK,
|
||||||
CORNERSTONE_MASK
|
CORNERSTONE_MASK,
|
||||||
|
SHOCK_DRIVE,
|
||||||
|
BURN_DRIVE,
|
||||||
|
CHILL_DRIVE,
|
||||||
|
DOUSE_DRIVE
|
||||||
}
|
}
|
||||||
|
|
||||||
export type SpeciesFormChangeConditionPredicate = (p: Pokemon) => boolean;
|
export type SpeciesFormChangeConditionPredicate = (p: Pokemon) => boolean;
|
||||||
@ -542,6 +546,12 @@ export const pokemonFormChanges: PokemonFormChanges = {
|
|||||||
new SpeciesFormChange(Species.MELOETTA, 'pirouette', 'aria', new SpeciesFormChangePostMoveTrigger(Moves.RELIC_SONG), true),
|
new SpeciesFormChange(Species.MELOETTA, 'pirouette', 'aria', new SpeciesFormChangePostMoveTrigger(Moves.RELIC_SONG), true),
|
||||||
new SpeciesFormChange(Species.MELOETTA, 'pirouette', 'aria', new SpeciesFormChangeActiveTrigger(false), true)
|
new SpeciesFormChange(Species.MELOETTA, 'pirouette', 'aria', new SpeciesFormChangeActiveTrigger(false), true)
|
||||||
],
|
],
|
||||||
|
[Species.GENESECT]: [
|
||||||
|
new SpeciesFormChange(Species.GENESECT, '', 'shock', new SpeciesFormChangeItemTrigger(FormChangeItem.SHOCK_DRIVE)),
|
||||||
|
new SpeciesFormChange(Species.GENESECT, '', 'burn', new SpeciesFormChangeItemTrigger(FormChangeItem.BURN_DRIVE)),
|
||||||
|
new SpeciesFormChange(Species.GENESECT, '', 'chill', new SpeciesFormChangeItemTrigger(FormChangeItem.CHILL_DRIVE)),
|
||||||
|
new SpeciesFormChange(Species.GENESECT, '', 'douse', new SpeciesFormChangeItemTrigger(FormChangeItem.DOUSE_DRIVE))
|
||||||
|
],
|
||||||
[Species.GRENINJA]: [
|
[Species.GRENINJA]: [
|
||||||
new SpeciesFormChange(Species.GRENINJA, 'battle-bond', 'ash', new SpeciesFormChangeManualTrigger(), true),
|
new SpeciesFormChange(Species.GRENINJA, 'battle-bond', 'ash', new SpeciesFormChangeManualTrigger(), true),
|
||||||
new SpeciesFormChange(Species.GRENINJA, 'ash', 'battle-bond', new SpeciesFormChangeManualTrigger(), true)
|
new SpeciesFormChange(Species.GRENINJA, 'ash', 'battle-bond', new SpeciesFormChangeManualTrigger(), true)
|
||||||
|
@ -30,7 +30,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 24, Moves.SWEET_SCENT ],
|
[ 24, Moves.SWEET_SCENT ],
|
||||||
[ 27, Moves.SYNTHESIS ],
|
[ 27, Moves.SYNTHESIS ],
|
||||||
[ 30, Moves.WORRY_SEED ],
|
[ 30, Moves.WORRY_SEED ],
|
||||||
[ 33, Moves.DOUBLE_EDGE ],
|
[ 33, Moves.POWER_WHIP ],
|
||||||
[ 36, Moves.SOLAR_BEAM ],
|
[ 36, Moves.SOLAR_BEAM ],
|
||||||
],
|
],
|
||||||
[Species.IVYSAUR]: [
|
[Species.IVYSAUR]: [
|
||||||
@ -47,16 +47,16 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 30, Moves.SWEET_SCENT ],
|
[ 30, Moves.SWEET_SCENT ],
|
||||||
[ 35, Moves.SYNTHESIS ],
|
[ 35, Moves.SYNTHESIS ],
|
||||||
[ 40, Moves.WORRY_SEED ],
|
[ 40, Moves.WORRY_SEED ],
|
||||||
[ 45, Moves.DOUBLE_EDGE ],
|
[ 45, Moves.POWER_WHIP ],
|
||||||
[ 50, Moves.SOLAR_BEAM ],
|
[ 50, Moves.SOLAR_BEAM ],
|
||||||
],
|
],
|
||||||
[Species.VENUSAUR]: [
|
[Species.VENUSAUR]: [
|
||||||
[ 0, Moves.PETAL_BLIZZARD ],
|
[ 0, Moves.PETAL_BLIZZARD ],
|
||||||
|
[ 1, Moves.GROWTH ],
|
||||||
|
[ 1, Moves.PETAL_DANCE ],
|
||||||
[ 1, Moves.VINE_WHIP ],
|
[ 1, Moves.VINE_WHIP ],
|
||||||
[ 1, Moves.TACKLE ],
|
[ 1, Moves.TACKLE ],
|
||||||
[ 1, Moves.GROWL ],
|
[ 1, Moves.GROWL ],
|
||||||
[ 1, Moves.GROWTH ],
|
|
||||||
[ 1, Moves.PETAL_DANCE ],
|
|
||||||
[ 9, Moves.LEECH_SEED ],
|
[ 9, Moves.LEECH_SEED ],
|
||||||
[ 12, Moves.RAZOR_LEAF ],
|
[ 12, Moves.RAZOR_LEAF ],
|
||||||
[ 15, Moves.POISON_POWDER ],
|
[ 15, Moves.POISON_POWDER ],
|
||||||
@ -66,7 +66,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 30, Moves.SWEET_SCENT ],
|
[ 30, Moves.SWEET_SCENT ],
|
||||||
[ 37, Moves.SYNTHESIS ],
|
[ 37, Moves.SYNTHESIS ],
|
||||||
[ 44, Moves.WORRY_SEED ],
|
[ 44, Moves.WORRY_SEED ],
|
||||||
[ 51, Moves.DOUBLE_EDGE ],
|
[ 51, Moves.POWER_WHIP ],
|
||||||
[ 58, Moves.SOLAR_BEAM ],
|
[ 58, Moves.SOLAR_BEAM ],
|
||||||
],
|
],
|
||||||
[Species.CHARMANDER]: [
|
[Species.CHARMANDER]: [
|
||||||
@ -127,7 +127,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 27, Moves.SHELL_SMASH ],
|
[ 27, Moves.SHELL_SMASH ],
|
||||||
[ 30, Moves.IRON_DEFENSE ],
|
[ 30, Moves.IRON_DEFENSE ],
|
||||||
[ 33, Moves.HYDRO_PUMP ],
|
[ 33, Moves.HYDRO_PUMP ],
|
||||||
[ 36, Moves.SKULL_BASH ],
|
[ 36, Moves.WAVE_CRASH ],
|
||||||
],
|
],
|
||||||
[Species.WARTORTLE]: [
|
[Species.WARTORTLE]: [
|
||||||
[ 1, Moves.TACKLE ],
|
[ 1, Moves.TACKLE ],
|
||||||
@ -143,7 +143,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 35, Moves.SHELL_SMASH ],
|
[ 35, Moves.SHELL_SMASH ],
|
||||||
[ 40, Moves.IRON_DEFENSE ],
|
[ 40, Moves.IRON_DEFENSE ],
|
||||||
[ 45, Moves.HYDRO_PUMP ],
|
[ 45, Moves.HYDRO_PUMP ],
|
||||||
[ 50, Moves.SKULL_BASH ],
|
[ 50, Moves.WAVE_CRASH ],
|
||||||
],
|
],
|
||||||
[Species.BLASTOISE]: [
|
[Species.BLASTOISE]: [
|
||||||
[ 0, Moves.FLASH_CANNON ],
|
[ 0, Moves.FLASH_CANNON ],
|
||||||
@ -160,7 +160,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 35, Moves.SHELL_SMASH ],
|
[ 35, Moves.SHELL_SMASH ],
|
||||||
[ 42, Moves.IRON_DEFENSE ],
|
[ 42, Moves.IRON_DEFENSE ],
|
||||||
[ 49, Moves.HYDRO_PUMP ],
|
[ 49, Moves.HYDRO_PUMP ],
|
||||||
[ 56, Moves.SKULL_BASH ],
|
[ 56, Moves.WAVE_CRASH ],
|
||||||
],
|
],
|
||||||
[Species.CATERPIE]: [
|
[Species.CATERPIE]: [
|
||||||
[ 1, Moves.TACKLE ],
|
[ 1, Moves.TACKLE ],
|
||||||
@ -341,9 +341,9 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 12, Moves.GLARE ],
|
[ 12, Moves.GLARE ],
|
||||||
[ 17, Moves.SCREECH ],
|
[ 17, Moves.SCREECH ],
|
||||||
[ 20, Moves.ACID ],
|
[ 20, Moves.ACID ],
|
||||||
|
[ 25, Moves.SWALLOW ],
|
||||||
[ 25, Moves.STOCKPILE ],
|
[ 25, Moves.STOCKPILE ],
|
||||||
[ 25, Moves.SPIT_UP ],
|
[ 25, Moves.SPIT_UP ],
|
||||||
[ 25, Moves.SWALLOW ],
|
|
||||||
[ 28, Moves.ACID_SPRAY ],
|
[ 28, Moves.ACID_SPRAY ],
|
||||||
[ 33, Moves.SLUDGE_BOMB ],
|
[ 33, Moves.SLUDGE_BOMB ],
|
||||||
[ 36, Moves.GASTRO_ACID ],
|
[ 36, Moves.GASTRO_ACID ],
|
||||||
@ -1780,14 +1780,15 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 4, Moves.DOUBLE_KICK ],
|
[ 4, Moves.DOUBLE_KICK ],
|
||||||
[ 8, Moves.LOW_KICK ],
|
[ 8, Moves.LOW_KICK ],
|
||||||
[ 12, Moves.ENDURE ],
|
[ 12, Moves.ENDURE ],
|
||||||
[ 16, Moves.REVENGE ],
|
[ 16, Moves.SUCKER_PUNCH ],
|
||||||
[ 21, Moves.WIDE_GUARD ],
|
[ 21, Moves.WIDE_GUARD ],
|
||||||
[ 24, Moves.BLAZE_KICK ],
|
[ 24, Moves.BLAZE_KICK ],
|
||||||
[ 28, Moves.MIND_READER ],
|
[ 28, Moves.FEINT ],
|
||||||
[ 32, Moves.MEGA_KICK ],
|
[ 32, Moves.MEGA_KICK ],
|
||||||
[ 36, Moves.CLOSE_COMBAT ],
|
[ 36, Moves.CLOSE_COMBAT ],
|
||||||
[ 40, Moves.REVERSAL ],
|
[ 40, Moves.REVERSAL ],
|
||||||
[ 44, Moves.HIGH_JUMP_KICK ],
|
[ 44, Moves.HIGH_JUMP_KICK ],
|
||||||
|
[ 50, Moves.AXE_KICK ],
|
||||||
],
|
],
|
||||||
[Species.HITMONCHAN]: [
|
[Species.HITMONCHAN]: [
|
||||||
[ 0, Moves.DRAIN_PUNCH ],
|
[ 0, Moves.DRAIN_PUNCH ],
|
||||||
@ -1796,16 +1797,14 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 1, Moves.FAKE_OUT ],
|
[ 1, Moves.FAKE_OUT ],
|
||||||
[ 1, Moves.HELPING_HAND ],
|
[ 1, Moves.HELPING_HAND ],
|
||||||
[ 1, Moves.FEINT ],
|
[ 1, Moves.FEINT ],
|
||||||
[ 1, Moves.VACUUM_WAVE ],
|
|
||||||
[ 1, Moves.BULLET_PUNCH ],
|
|
||||||
[ 4, Moves.MACH_PUNCH ],
|
[ 4, Moves.MACH_PUNCH ],
|
||||||
[ 8, Moves.POWER_UP_PUNCH ],
|
[ 8, Moves.VACUUM_WAVE ],
|
||||||
[ 12, Moves.DETECT ],
|
[ 12, Moves.DETECT ],
|
||||||
[ 16, Moves.REVENGE ],
|
[ 16, Moves.BULLET_PUNCH ],
|
||||||
[ 21, Moves.QUICK_GUARD ],
|
[ 21, Moves.QUICK_GUARD ],
|
||||||
[ 24, Moves.FIRE_PUNCH ],
|
|
||||||
[ 24, Moves.ICE_PUNCH ],
|
|
||||||
[ 24, Moves.THUNDER_PUNCH ],
|
[ 24, Moves.THUNDER_PUNCH ],
|
||||||
|
[ 24, Moves.ICE_PUNCH ],
|
||||||
|
[ 24, Moves.FIRE_PUNCH ],
|
||||||
[ 28, Moves.AGILITY ],
|
[ 28, Moves.AGILITY ],
|
||||||
[ 32, Moves.MEGA_PUNCH ],
|
[ 32, Moves.MEGA_PUNCH ],
|
||||||
[ 36, Moves.CLOSE_COMBAT ],
|
[ 36, Moves.CLOSE_COMBAT ],
|
||||||
@ -2598,7 +2597,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 31, Moves.LIGHT_SCREEN ],
|
[ 31, Moves.LIGHT_SCREEN ],
|
||||||
[ 34, Moves.BODY_SLAM ],
|
[ 34, Moves.BODY_SLAM ],
|
||||||
[ 39, Moves.SAFEGUARD ],
|
[ 39, Moves.SAFEGUARD ],
|
||||||
[ 42, Moves.AROMATHERAPY ],
|
[ 42, Moves.GIGA_DRAIN ],
|
||||||
[ 45, Moves.SOLAR_BEAM ],
|
[ 45, Moves.SOLAR_BEAM ],
|
||||||
],
|
],
|
||||||
[Species.BAYLEEF]: [
|
[Species.BAYLEEF]: [
|
||||||
@ -2614,7 +2613,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 36, Moves.LIGHT_SCREEN ],
|
[ 36, Moves.LIGHT_SCREEN ],
|
||||||
[ 40, Moves.BODY_SLAM ],
|
[ 40, Moves.BODY_SLAM ],
|
||||||
[ 46, Moves.SAFEGUARD ],
|
[ 46, Moves.SAFEGUARD ],
|
||||||
[ 50, Moves.AROMATHERAPY ],
|
[ 50, Moves.GIGA_DRAIN ],
|
||||||
[ 54, Moves.SOLAR_BEAM ],
|
[ 54, Moves.SOLAR_BEAM ],
|
||||||
],
|
],
|
||||||
[Species.MEGANIUM]: [
|
[Species.MEGANIUM]: [
|
||||||
@ -2632,7 +2631,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 40, Moves.LIGHT_SCREEN ],
|
[ 40, Moves.LIGHT_SCREEN ],
|
||||||
[ 46, Moves.BODY_SLAM ],
|
[ 46, Moves.BODY_SLAM ],
|
||||||
[ 54, Moves.SAFEGUARD ],
|
[ 54, Moves.SAFEGUARD ],
|
||||||
[ 60, Moves.AROMATHERAPY ],
|
[ 60, Moves.GIGA_DRAIN ],
|
||||||
[ 65, Moves.SOLAR_BEAM ],
|
[ 65, Moves.SOLAR_BEAM ],
|
||||||
],
|
],
|
||||||
[Species.CYNDAQUIL]: [
|
[Species.CYNDAQUIL]: [
|
||||||
@ -2796,6 +2795,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 1, Moves.ECHOED_VOICE ],
|
[ 1, Moves.ECHOED_VOICE ],
|
||||||
[ 9, Moves.CONFUSION ],
|
[ 9, Moves.CONFUSION ],
|
||||||
[ 12, Moves.REFLECT ],
|
[ 12, Moves.REFLECT ],
|
||||||
|
[ 15, Moves.DEFOG ],
|
||||||
[ 18, Moves.AIR_SLASH ],
|
[ 18, Moves.AIR_SLASH ],
|
||||||
[ 23, Moves.EXTRASENSORY ],
|
[ 23, Moves.EXTRASENSORY ],
|
||||||
[ 28, Moves.TAKE_DOWN ],
|
[ 28, Moves.TAKE_DOWN ],
|
||||||
@ -3574,7 +3574,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 13, Moves.LICK ],
|
[ 13, Moves.LICK ],
|
||||||
[ 19, Moves.HEADBUTT ],
|
[ 19, Moves.HEADBUTT ],
|
||||||
[ 25, Moves.ROAR ],
|
[ 25, Moves.ROAR ],
|
||||||
[ 31, Moves.RAGE ],
|
[ 31, Moves.LAST_RESORT ],
|
||||||
[ 37, Moves.PLAY_ROUGH ],
|
[ 37, Moves.PLAY_ROUGH ],
|
||||||
[ 43, Moves.PAYBACK ],
|
[ 43, Moves.PAYBACK ],
|
||||||
[ 49, Moves.CRUNCH ],
|
[ 49, Moves.CRUNCH ],
|
||||||
@ -3592,7 +3592,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 13, Moves.LICK ],
|
[ 13, Moves.LICK ],
|
||||||
[ 19, Moves.HEADBUTT ],
|
[ 19, Moves.HEADBUTT ],
|
||||||
[ 27, Moves.ROAR ],
|
[ 27, Moves.ROAR ],
|
||||||
[ 35, Moves.RAGE ],
|
[ 35, Moves.LAST_RESORT ],
|
||||||
[ 43, Moves.PLAY_ROUGH ],
|
[ 43, Moves.PLAY_ROUGH ],
|
||||||
[ 51, Moves.PAYBACK ],
|
[ 51, Moves.PAYBACK ],
|
||||||
[ 59, Moves.CRUNCH ],
|
[ 59, Moves.CRUNCH ],
|
||||||
@ -3868,7 +3868,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 20, Moves.WING_ATTACK ],
|
[ 20, Moves.WING_ATTACK ],
|
||||||
[ 24, Moves.SLASH ],
|
[ 24, Moves.SLASH ],
|
||||||
[ 28, Moves.STEEL_WING ],
|
[ 28, Moves.STEEL_WING ],
|
||||||
[ 32, Moves.AUTOTOMIZE ],
|
[ 32, Moves.PAYBACK ],
|
||||||
[ 36, Moves.DRILL_PECK ],
|
[ 36, Moves.DRILL_PECK ],
|
||||||
[ 40, Moves.METAL_SOUND ],
|
[ 40, Moves.METAL_SOUND ],
|
||||||
[ 44, Moves.SPIKES ],
|
[ 44, Moves.SPIKES ],
|
||||||
@ -3923,11 +3923,12 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 20, Moves.DRAGON_BREATH ],
|
[ 20, Moves.DRAGON_BREATH ],
|
||||||
[ 25, Moves.BUBBLE_BEAM ],
|
[ 25, Moves.BUBBLE_BEAM ],
|
||||||
[ 30, Moves.AGILITY ],
|
[ 30, Moves.AGILITY ],
|
||||||
[ 37, Moves.LASER_FOCUS ],
|
[ 37, Moves.WATER_PULSE ],
|
||||||
[ 44, Moves.DRAGON_PULSE ],
|
[ 44, Moves.DRAGON_PULSE ],
|
||||||
[ 51, Moves.HYDRO_PUMP ],
|
[ 51, Moves.HYDRO_PUMP ],
|
||||||
[ 58, Moves.DRAGON_DANCE ],
|
[ 58, Moves.DRAGON_DANCE ],
|
||||||
[ 65, Moves.RAIN_DANCE ],
|
[ 65, Moves.RAIN_DANCE ],
|
||||||
|
[ 72, Moves.WAVE_CRASH ],
|
||||||
],
|
],
|
||||||
[Species.PHANPY]: [
|
[Species.PHANPY]: [
|
||||||
[ 1, Moves.TACKLE ],
|
[ 1, Moves.TACKLE ],
|
||||||
@ -3974,10 +3975,9 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 35, Moves.RECOVER ],
|
[ 35, Moves.RECOVER ],
|
||||||
[ 40, Moves.DISCHARGE ],
|
[ 40, Moves.DISCHARGE ],
|
||||||
[ 45, Moves.TRI_ATTACK ],
|
[ 45, Moves.TRI_ATTACK ],
|
||||||
[ 50, Moves.MAGIC_COAT ],
|
[ 50, Moves.LOCK_ON ],
|
||||||
[ 55, Moves.LOCK_ON ],
|
[ 55, Moves.ZAP_CANNON ],
|
||||||
[ 60, Moves.ZAP_CANNON ],
|
[ 60, Moves.HYPER_BEAM ],
|
||||||
[ 65, Moves.HYPER_BEAM ],
|
|
||||||
],
|
],
|
||||||
[Species.STANTLER]: [
|
[Species.STANTLER]: [
|
||||||
[ 1, Moves.TACKLE ],
|
[ 1, Moves.TACKLE ],
|
||||||
@ -4268,7 +4268,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = {
|
|||||||
[ 72, Moves.FIRE_BLAST ],
|
[ 72, Moves.FIRE_BLAST ],
|
||||||
[ 81, Moves.FUTURE_SIGHT ],
|
[ 81, Moves.FUTURE_SIGHT ],
|
||||||
[ 90, Moves.SKY_ATTACK ],
|
[ 90, Moves.SKY_ATTACK ],
|
||||||
[ 99, Moves.BURN_UP ],
|
[ 99, Moves.OVERHEAT ],
|
||||||
],
|
],
|
||||||
[Species.CELEBI]: [
|
[Species.CELEBI]: [
|
||||||
[ 1, Moves.CONFUSION ],
|
[ 1, Moves.CONFUSION ],
|
||||||
|
@ -135,3 +135,43 @@ export function getStatusEffectCatchRateMultiplier(statusEffect: StatusEffect):
|
|||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a random non-volatile StatusEffect
|
||||||
|
*/
|
||||||
|
export function generateRandomStatusEffect(): StatusEffect {
|
||||||
|
return Utils.randIntRange(1, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a random non-volatile StatusEffect between the two provided
|
||||||
|
* @param statusEffectA The first StatusEffect
|
||||||
|
* @param statusEffectA The second StatusEffect
|
||||||
|
*/
|
||||||
|
export function getRandomStatusEffect(statusEffectA: StatusEffect, statusEffectB: StatusEffect): StatusEffect {
|
||||||
|
if (statusEffectA === StatusEffect.NONE || statusEffectA === StatusEffect.FAINT) {
|
||||||
|
return statusEffectB;
|
||||||
|
}
|
||||||
|
if (statusEffectB === StatusEffect.NONE || statusEffectB === StatusEffect.FAINT) {
|
||||||
|
return statusEffectA;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Utils.randIntRange(0, 2) ? statusEffectA : statusEffectB;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a random non-volatile StatusEffect between the two provided
|
||||||
|
* @param statusA The first Status
|
||||||
|
* @param statusB The second Status
|
||||||
|
*/
|
||||||
|
export function getRandomStatus(statusA: Status, statusB: Status): Status {
|
||||||
|
if (statusA === undefined || statusA.effect === StatusEffect.NONE || statusA.effect === StatusEffect.FAINT) {
|
||||||
|
return statusB;
|
||||||
|
}
|
||||||
|
if (statusB === undefined || statusB.effect === StatusEffect.NONE || statusB.effect === StatusEffect.FAINT) {
|
||||||
|
return statusA;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return Utils.randIntRange(0, 2) ? statusA : statusB;
|
||||||
|
}
|
@ -14,7 +14,7 @@ import { AttackTypeBoosterModifier, DamageMoneyRewardModifier, EnemyDamageBooste
|
|||||||
import { PokeballType } from '../data/pokeball';
|
import { PokeballType } from '../data/pokeball';
|
||||||
import { Gender } from '../data/gender';
|
import { Gender } from '../data/gender';
|
||||||
import { initMoveAnim, loadMoveAnimAssets } from '../data/battle-anims';
|
import { initMoveAnim, loadMoveAnimAssets } from '../data/battle-anims';
|
||||||
import { Status, StatusEffect } from '../data/status-effect';
|
import { Status, StatusEffect, getRandomStatus } from '../data/status-effect';
|
||||||
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from '../data/pokemon-evolutions';
|
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition, FusionSpeciesFormEvolution } from '../data/pokemon-evolutions';
|
||||||
import { reverseCompatibleTms, tmSpecies } from '../data/tms';
|
import { reverseCompatibleTms, tmSpecies } from '../data/tms';
|
||||||
import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase } from '../phases';
|
import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase } from '../phases';
|
||||||
@ -43,8 +43,8 @@ import { Nature, getNatureStatMultiplier } from '../data/nature';
|
|||||||
import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangeStatusEffectTrigger } from '../data/pokemon-forms';
|
import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangeStatusEffectTrigger } from '../data/pokemon-forms';
|
||||||
import { TerrainType } from '../data/terrain';
|
import { TerrainType } from '../data/terrain';
|
||||||
import { TrainerSlot } from '../data/trainer-config';
|
import { TrainerSlot } from '../data/trainer-config';
|
||||||
|
import { ABILITY_OVERRIDE, MOVE_OVERRIDE, MOVE_OVERRIDE_2, OPP_ABILITY_OVERRIDE, OPP_MOVE_OVERRIDE, OPP_MOVE_OVERRIDE_2, OPP_SHINY_OVERRIDE, OPP_VARIANT_OVERRIDE } from '../overrides';
|
||||||
import { BerryType } from '../data/berry';
|
import { BerryType } from '../data/berry';
|
||||||
import { ABILITY_OVERRIDE, MOVE_OVERRIDE, OPP_ABILITY_OVERRIDE, OPP_MOVE_OVERRIDE, OPP_SHINY_OVERRIDE, OPP_VARIANT_OVERRIDE } from '../overrides';
|
|
||||||
import i18next from '../plugins/i18n';
|
import i18next from '../plugins/i18n';
|
||||||
|
|
||||||
export enum FieldPosition {
|
export enum FieldPosition {
|
||||||
@ -725,6 +725,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||||||
this.moveset[0] = new PokemonMove(MOVE_OVERRIDE, Math.min(this.moveset[0].ppUsed, allMoves[MOVE_OVERRIDE].pp));
|
this.moveset[0] = new PokemonMove(MOVE_OVERRIDE, Math.min(this.moveset[0].ppUsed, allMoves[MOVE_OVERRIDE].pp));
|
||||||
else if (OPP_MOVE_OVERRIDE && !this.isPlayer())
|
else if (OPP_MOVE_OVERRIDE && !this.isPlayer())
|
||||||
this.moveset[0] = new PokemonMove(OPP_MOVE_OVERRIDE, Math.min(this.moveset[0].ppUsed, allMoves[OPP_MOVE_OVERRIDE].pp));
|
this.moveset[0] = new PokemonMove(OPP_MOVE_OVERRIDE, Math.min(this.moveset[0].ppUsed, allMoves[OPP_MOVE_OVERRIDE].pp));
|
||||||
|
if (MOVE_OVERRIDE_2 && this.isPlayer())
|
||||||
|
this.moveset[1] = new PokemonMove(MOVE_OVERRIDE_2, Math.min(this.moveset[1].ppUsed, allMoves[MOVE_OVERRIDE_2].pp));
|
||||||
|
else if (OPP_MOVE_OVERRIDE_2 && !this.isPlayer())
|
||||||
|
this.moveset[1] = new PokemonMove(OPP_MOVE_OVERRIDE_2, Math.min(this.moveset[1].ppUsed, allMoves[OPP_MOVE_OVERRIDE_2].pp));
|
||||||
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@ -2474,9 +2479,10 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
if (newEvolution.condition.predicate(this)) {
|
if (newEvolution.condition.predicate(this)) {
|
||||||
const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, undefined, this.shiny, this.variant, this.ivs, this.nature);
|
const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, undefined, this.shiny, this.variant, this.ivs, this.nature);
|
||||||
newPokemon.natureOverride = this.natureOverride;
|
newPokemon.natureOverride = this.natureOverride;
|
||||||
|
newPokemon.passive = this.passive;
|
||||||
|
newPokemon.moveset = this.moveset.slice();
|
||||||
newPokemon.moveset = this.copyMoveset();
|
newPokemon.moveset = this.copyMoveset();
|
||||||
newPokemon.luck = this.luck;
|
newPokemon.luck = this.luck;
|
||||||
|
|
||||||
newPokemon.fusionSpecies = this.fusionSpecies;
|
newPokemon.fusionSpecies = this.fusionSpecies;
|
||||||
newPokemon.fusionFormIndex = this.fusionFormIndex;
|
newPokemon.fusionFormIndex = this.fusionFormIndex;
|
||||||
newPokemon.fusionAbilityIndex = this.fusionAbilityIndex;
|
newPokemon.fusionAbilityIndex = this.fusionAbilityIndex;
|
||||||
@ -2536,6 +2542,10 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
this.generateCompatibleTms();
|
this.generateCompatibleTms();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a Promise to fuse two PlayerPokemon together
|
||||||
|
* @param pokemon The PlayerPokemon to fuse to this one
|
||||||
|
*/
|
||||||
fuse(pokemon: PlayerPokemon): Promise<void> {
|
fuse(pokemon: PlayerPokemon): Promise<void> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
this.fusionSpecies = pokemon.species;
|
this.fusionSpecies = pokemon.species;
|
||||||
@ -2549,8 +2559,25 @@ export class PlayerPokemon extends Pokemon {
|
|||||||
this.scene.validateAchv(achvs.SPLICE);
|
this.scene.validateAchv(achvs.SPLICE);
|
||||||
this.scene.gameData.gameStats.pokemonFused++;
|
this.scene.gameData.gameStats.pokemonFused++;
|
||||||
|
|
||||||
|
// Store the average HP% that each Pokemon has
|
||||||
|
const newHpPercent = ((pokemon.hp / pokemon.stats[Stat.HP]) + (this.hp / this.stats[Stat.HP])) / 2;
|
||||||
|
|
||||||
this.generateName();
|
this.generateName();
|
||||||
this.calculateStats();
|
this.calculateStats();
|
||||||
|
|
||||||
|
// Set this Pokemon's HP to the average % of both fusion components
|
||||||
|
this.hp = Math.round(this.stats[Stat.HP] * newHpPercent);
|
||||||
|
if (!this.isFainted()) {
|
||||||
|
// If this Pokemon hasn't fainted, make sure the HP wasn't set over the new maximum
|
||||||
|
this.hp = Math.min(this.hp, this.stats[Stat.HP]);
|
||||||
|
this.status = getRandomStatus(this.status, pokemon.status); // Get a random valid status between the two
|
||||||
|
}
|
||||||
|
else if (!pokemon.isFainted()) {
|
||||||
|
// If this Pokemon fainted but the other hasn't, make sure the HP wasn't set to zero
|
||||||
|
this.hp = Math.max(this.hp, 1);
|
||||||
|
this.status = pokemon.status; // Inherit the other Pokemon's status
|
||||||
|
}
|
||||||
|
|
||||||
this.generateCompatibleTms();
|
this.generateCompatibleTms();
|
||||||
this.updateInfo(true);
|
this.updateInfo(true);
|
||||||
const fusedPartyMemberIndex = this.scene.getParty().indexOf(pokemon);
|
const fusedPartyMemberIndex = this.scene.getParty().indexOf(pokemon);
|
||||||
@ -2731,8 +2758,8 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
let targetScores: integer[] = [];
|
let targetScores: integer[] = [];
|
||||||
|
|
||||||
for (let mt of moveTargets[move.id]) {
|
for (let mt of moveTargets[move.id]) {
|
||||||
// Prevent a target score from being calculated when there isn't a target
|
// Prevent a target score from being calculated when the target is whoever attacks the user
|
||||||
if (mt === -1)
|
if (mt === BattlerIndex.ATTACKER)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
const target = this.scene.getField()[mt];
|
const target = this.scene.getField()[mt];
|
||||||
@ -2806,10 +2833,10 @@ export class EnemyPokemon extends Pokemon {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!sortedBenefitScores.length) {
|
if (!sortedBenefitScores.length) {
|
||||||
// Set target to -1 when using a counter move
|
// Set target to BattlerIndex.ATTACKER when using a counter move
|
||||||
// This is the same as when the player does so
|
// This is the same as when the player does so
|
||||||
if (!!move.findAttr(attr => attr instanceof CounterDamageAttr))
|
if (!!move.findAttr(attr => attr instanceof CounterDamageAttr))
|
||||||
return [-1];
|
return [BattlerIndex.ATTACKER];
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
@ -31,6 +31,8 @@ export class LoadingScene extends SceneBase {
|
|||||||
this.loadAtlas('bg', 'ui');
|
this.loadAtlas('bg', 'ui');
|
||||||
this.loadImage('command_fight_labels', 'ui');
|
this.loadImage('command_fight_labels', 'ui');
|
||||||
this.loadAtlas('prompt', 'ui');
|
this.loadAtlas('prompt', 'ui');
|
||||||
|
this.loadImage('candy', 'ui');
|
||||||
|
this.loadImage('candy_overlay', 'ui');
|
||||||
this.loadImage('cursor', 'ui');
|
this.loadImage('cursor', 'ui');
|
||||||
this.loadImage('cursor_reverse', 'ui');
|
this.loadImage('cursor_reverse', 'ui');
|
||||||
for (let wv of Utils.getEnumValues(WindowVariant)) {
|
for (let wv of Utils.getEnumValues(WindowVariant)) {
|
||||||
|
@ -9,7 +9,7 @@ export const battle: SimpleTranslationEntries = {
|
|||||||
"trainerComeBack": "{{trainerName}} retire {{pokemonName}} !",
|
"trainerComeBack": "{{trainerName}} retire {{pokemonName}} !",
|
||||||
"playerGo": "{{pokemonName}} ! Go !",
|
"playerGo": "{{pokemonName}} ! Go !",
|
||||||
"trainerGo": "{{pokemonName}} est envoyé par\n{{trainerName}} !",
|
"trainerGo": "{{pokemonName}} est envoyé par\n{{trainerName}} !",
|
||||||
"switchQuestion": "Voulez-vous changer\n{{pokemonName}} ?",
|
"switchQuestion": "Voulez-vous changer\nvotre {{pokemonName}} ?",
|
||||||
"trainerDefeated": `Vous avez battu\n{{trainerName}} !`,
|
"trainerDefeated": `Vous avez battu\n{{trainerName}} !`,
|
||||||
"pokemonCaught": "Vous avez attrapé {{pokemonName}} !",
|
"pokemonCaught": "Vous avez attrapé {{pokemonName}} !",
|
||||||
"pokemon": "Pokémon",
|
"pokemon": "Pokémon",
|
||||||
|
@ -1151,7 +1151,7 @@ const enemyBuffModifierPool: ModifierPool = {
|
|||||||
new WeightedModifierType(modifierTypes.ENEMY_ATTACK_FREEZE_CHANCE, 2),
|
new WeightedModifierType(modifierTypes.ENEMY_ATTACK_FREEZE_CHANCE, 2),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_ATTACK_BURN_CHANCE, 2),
|
new WeightedModifierType(modifierTypes.ENEMY_ATTACK_BURN_CHANCE, 2),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_STATUS_EFFECT_HEAL_CHANCE, 10),
|
new WeightedModifierType(modifierTypes.ENEMY_STATUS_EFFECT_HEAL_CHANCE, 10),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 10000),
|
new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 5),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 1)
|
new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 1)
|
||||||
].map(m => { m.setTier(ModifierTier.COMMON); return m; }),
|
].map(m => { m.setTier(ModifierTier.COMMON); return m; }),
|
||||||
[ModifierTier.GREAT]: [
|
[ModifierTier.GREAT]: [
|
||||||
@ -1162,12 +1162,12 @@ const enemyBuffModifierPool: ModifierPool = {
|
|||||||
new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 1)
|
new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 1)
|
||||||
].map(m => { m.setTier(ModifierTier.GREAT); return m; }),
|
].map(m => { m.setTier(ModifierTier.GREAT); return m; }),
|
||||||
[ModifierTier.ULTRA]: [
|
[ModifierTier.ULTRA]: [
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_BOOSTER, 5),
|
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_BOOSTER, 10),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_REDUCTION, 5),
|
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_REDUCTION, 10),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_HEAL, 5),
|
new WeightedModifierType(modifierTypes.ENEMY_HEAL, 10),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_STATUS_EFFECT_HEAL_CHANCE, 5),
|
new WeightedModifierType(modifierTypes.ENEMY_STATUS_EFFECT_HEAL_CHANCE, 10),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 5),
|
new WeightedModifierType(modifierTypes.ENEMY_ENDURE_CHANCE, 10),
|
||||||
new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 300)
|
new WeightedModifierType(modifierTypes.ENEMY_FUSED_CHANCE, 5)
|
||||||
].map(m => { m.setTier(ModifierTier.ULTRA); return m; }),
|
].map(m => { m.setTier(ModifierTier.ULTRA); return m; }),
|
||||||
[ModifierTier.ROGUE]: [ ].map(m => { m.setTier(ModifierTier.ROGUE); return m; }),
|
[ModifierTier.ROGUE]: [ ].map(m => { m.setTier(ModifierTier.ROGUE); return m; }),
|
||||||
[ModifierTier.MASTER]: [ ].map(m => { m.setTier(ModifierTier.MASTER); return m; })
|
[ModifierTier.MASTER]: [ ].map(m => { m.setTier(ModifierTier.MASTER); return m; })
|
||||||
|
@ -15,9 +15,11 @@ export const WEATHER_OVERRIDE = WeatherType.NONE;
|
|||||||
|
|
||||||
export const ABILITY_OVERRIDE = Abilities.NONE;
|
export const ABILITY_OVERRIDE = Abilities.NONE;
|
||||||
export const MOVE_OVERRIDE = Moves.NONE;
|
export const MOVE_OVERRIDE = Moves.NONE;
|
||||||
|
export const MOVE_OVERRIDE_2 = Moves.NONE;
|
||||||
export const OPP_SPECIES_OVERRIDE = 0;
|
export const OPP_SPECIES_OVERRIDE = 0;
|
||||||
export const OPP_ABILITY_OVERRIDE = Abilities.NONE;
|
export const OPP_ABILITY_OVERRIDE = Abilities.NONE;
|
||||||
export const OPP_MOVE_OVERRIDE = Moves.NONE;
|
export const OPP_MOVE_OVERRIDE = Moves.NONE;
|
||||||
|
export const OPP_MOVE_OVERRIDE_2 = Moves.NONE;
|
||||||
|
|
||||||
export const OPP_SHINY_OVERRIDE = false;
|
export const OPP_SHINY_OVERRIDE = false;
|
||||||
export const OPP_VARIANT_OVERRIDE = 0;
|
export const OPP_VARIANT_OVERRIDE = 0;
|
||||||
|
@ -2,7 +2,7 @@ import BattleScene, { bypassLogin, startingWave } from "./battle-scene";
|
|||||||
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon";
|
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon";
|
||||||
import * as Utils from './utils';
|
import * as Utils from './utils';
|
||||||
import { Moves } from "./data/enums/moves";
|
import { Moves } from "./data/enums/moves";
|
||||||
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, DelayedAttackAttr, RechargeAttr, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, FixedDamageAttr, OneHitKOAccuracyAttr, ForceSwitchOutAttr } from "./data/move";
|
import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, VariableAccuracyAttr, MoveTarget, OneHitKOAttr, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, DelayedAttackAttr, RechargeAttr, PreMoveMessageAttr, HealStatusEffectAttr, IgnoreOpponentStatChangesAttr, NoEffectAttr, FixedDamageAttr, OneHitKOAccuracyAttr, ForceSwitchOutAttr, VariableTargetAttr } from "./data/move";
|
||||||
import { Mode } from './ui/ui';
|
import { Mode } from './ui/ui';
|
||||||
import { Command } from "./ui/command-ui-handler";
|
import { Command } from "./ui/command-ui-handler";
|
||||||
import { Stat } from "./data/pokemon-stat";
|
import { Stat } from "./data/pokemon-stat";
|
||||||
@ -30,7 +30,7 @@ import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, get
|
|||||||
import { TempBattleStat } from "./data/temp-battle-stat";
|
import { TempBattleStat } from "./data/temp-battle-stat";
|
||||||
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
|
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
|
||||||
import { ArenaTagType } from "./data/enums/arena-tag-type";
|
import { ArenaTagType } from "./data/enums/arena-tag-type";
|
||||||
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr } from "./data/ability";
|
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, applyPostBattleInitAbAttrs, PostBattleInitAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr } from "./data/ability";
|
||||||
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
||||||
import { getBiomeKey } from "./field/arena";
|
import { getBiomeKey } from "./field/arena";
|
||||||
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
||||||
@ -57,6 +57,7 @@ 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';
|
import i18next from './plugins/i18n';
|
||||||
|
import { Abilities } from "./data/enums/abilities";
|
||||||
import { STARTER_FORM_OVERRIDE, STARTER_SPECIES_OVERRIDE } from './overrides';
|
import { STARTER_FORM_OVERRIDE, STARTER_SPECIES_OVERRIDE } from './overrides';
|
||||||
|
|
||||||
export class LoginPhase extends Phase {
|
export class LoginPhase extends Phase {
|
||||||
@ -1178,14 +1179,25 @@ export class SummonPhase extends PartyMemberPokemonPhase {
|
|||||||
this.preSummon();
|
this.preSummon();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sends out a Pokemon before the battle begins and shows the appropriate messages
|
||||||
|
*/
|
||||||
preSummon(): void {
|
preSummon(): void {
|
||||||
const partyMember = this.getPokemon();
|
const partyMember = this.getPokemon();
|
||||||
|
// If the Pokemon about to be sent out is fainted, switch to the first non-fainted Pokemon
|
||||||
if (partyMember.isFainted()) {
|
if (partyMember.isFainted()) {
|
||||||
|
console.warn("The Pokemon about to be sent out is fainted. Attempting to resolve...");
|
||||||
const party = this.getParty();
|
const party = this.getParty();
|
||||||
const nonFaintedIndex = party.slice(this.partyMemberIndex).findIndex(p => !p.isFainted()) + this.partyMemberIndex;
|
|
||||||
const nonFaintedPartyMember = party[nonFaintedIndex];
|
const nonFaintedIndex = party.findIndex(x => !x.isFainted()); // Find the first non-fainted Pokemon index
|
||||||
party[nonFaintedIndex] = partyMember;
|
if (nonFaintedIndex === -1) {
|
||||||
party[this.partyMemberIndex] = nonFaintedPartyMember;
|
console.error("Party Details:\n", party);
|
||||||
|
throw new Error("All available Pokemon were fainted!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Swaps the fainted Pokemon and the first non-fainted Pokemon in the party
|
||||||
|
[party[this.partyMemberIndex], party[nonFaintedIndex]] = [party[nonFaintedIndex], party[this.partyMemberIndex]];
|
||||||
|
console.warn("Swapped %s %O with %s %O", partyMember?.name, partyMember, party[0]?.name, party[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.player) {
|
if (this.player) {
|
||||||
@ -1729,7 +1741,7 @@ export class CommandPhase extends FieldPhase {
|
|||||||
}, null, true);
|
}, null, true);
|
||||||
} else if (cursor < 5) {
|
} else if (cursor < 5) {
|
||||||
const targetPokemon = this.scene.getEnemyField().find(p => p.isActive(true));
|
const targetPokemon = this.scene.getEnemyField().find(p => p.isActive(true));
|
||||||
if (targetPokemon.isBoss() && targetPokemon.bossSegmentIndex >= 1 && cursor < PokeballType.MASTER_BALL) {
|
if (targetPokemon.isBoss() && targetPokemon.bossSegmentIndex >= 1 && !targetPokemon.hasAbility(Abilities.WONDER_GUARD, false, true) && cursor < PokeballType.MASTER_BALL) {
|
||||||
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
|
this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex);
|
||||||
this.scene.ui.setMode(Mode.MESSAGE);
|
this.scene.ui.setMode(Mode.MESSAGE);
|
||||||
this.scene.ui.showText(i18next.t('battle:noPokeballStrong'), null, () => {
|
this.scene.ui.showText(i18next.t('battle:noPokeballStrong'), null, () => {
|
||||||
@ -2399,7 +2411,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
|
|
||||||
const targetHitChecks = Object.fromEntries(targets.map(p => [ p.getBattlerIndex(), this.hitCheck(p) ]));
|
const targetHitChecks = Object.fromEntries(targets.map(p => [ p.getBattlerIndex(), this.hitCheck(p) ]));
|
||||||
const activeTargets = targets.map(t => t.isActive(true));
|
const activeTargets = targets.map(t => t.isActive(true));
|
||||||
if (!activeTargets.length || (!this.move.getMove().isMultiTarget() && !targetHitChecks[this.targets[0]])) {
|
if (!activeTargets.length || (!this.move.getMove().getAttrs(VariableTargetAttr).length && !this.move.getMove().isMultiTarget() && !targetHitChecks[this.targets[0]])) {
|
||||||
user.turnData.hitCount = 1;
|
user.turnData.hitCount = 1;
|
||||||
user.turnData.hitsLeft = 1;
|
user.turnData.hitsLeft = 1;
|
||||||
if (activeTargets.length) {
|
if (activeTargets.length) {
|
||||||
@ -2660,8 +2672,9 @@ export class StatChangePhase extends PokemonPhase {
|
|||||||
private levels: integer;
|
private levels: integer;
|
||||||
private showMessage: boolean;
|
private showMessage: boolean;
|
||||||
private ignoreAbilities: boolean;
|
private ignoreAbilities: boolean;
|
||||||
|
private canBeCopied: boolean;
|
||||||
|
|
||||||
constructor(scene: BattleScene, battlerIndex: BattlerIndex, selfTarget: boolean, stats: BattleStat[], levels: integer, showMessage: boolean = true, ignoreAbilities: boolean = false) {
|
constructor(scene: BattleScene, battlerIndex: BattlerIndex, selfTarget: boolean, stats: BattleStat[], levels: integer, showMessage: boolean = true, ignoreAbilities: boolean = false, canBeCopied: boolean = true) {
|
||||||
super(scene, battlerIndex);
|
super(scene, battlerIndex);
|
||||||
|
|
||||||
this.selfTarget = selfTarget;
|
this.selfTarget = selfTarget;
|
||||||
@ -2669,6 +2682,7 @@ export class StatChangePhase extends PokemonPhase {
|
|||||||
this.levels = levels;
|
this.levels = levels;
|
||||||
this.showMessage = showMessage;
|
this.showMessage = showMessage;
|
||||||
this.ignoreAbilities = ignoreAbilities;
|
this.ignoreAbilities = ignoreAbilities;
|
||||||
|
this.canBeCopied = canBeCopied;
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
@ -2716,6 +2730,10 @@ export class StatChangePhase extends PokemonPhase {
|
|||||||
for (let stat of filteredStats)
|
for (let stat of filteredStats)
|
||||||
pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + levels.value, 6), -6);
|
pokemon.summonData.battleStats[stat] = Math.max(Math.min(pokemon.summonData.battleStats[stat] + levels.value, 6), -6);
|
||||||
|
|
||||||
|
if (levels.value > 0 && this.canBeCopied)
|
||||||
|
for (let opponent of pokemon.getOpponents())
|
||||||
|
applyAbAttrs(StatChangeCopyAbAttr, opponent, null, this.stats, levels.value);
|
||||||
|
|
||||||
applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget);
|
applyPostStatChangeAbAttrs(PostStatChangeAbAttr, pokemon, filteredStats, this.levels, this.selfTarget);
|
||||||
|
|
||||||
pokemon.updateInfo();
|
pokemon.updateInfo();
|
||||||
@ -3219,19 +3237,22 @@ export class VictoryPhase extends PokemonPhase {
|
|||||||
const expShareModifier = this.scene.findModifier(m => m instanceof ExpShareModifier) as ExpShareModifier;
|
const expShareModifier = this.scene.findModifier(m => m instanceof ExpShareModifier) as ExpShareModifier;
|
||||||
const expBalanceModifier = this.scene.findModifier(m => m instanceof ExpBalanceModifier) as ExpBalanceModifier;
|
const expBalanceModifier = this.scene.findModifier(m => m instanceof ExpBalanceModifier) as ExpBalanceModifier;
|
||||||
const multipleParticipantExpBonusModifier = this.scene.findModifier(m => m instanceof MultipleParticipantExpBonusModifier) as MultipleParticipantExpBonusModifier;
|
const multipleParticipantExpBonusModifier = this.scene.findModifier(m => m instanceof MultipleParticipantExpBonusModifier) as MultipleParticipantExpBonusModifier;
|
||||||
const expPartyMembers = party.filter(p => p.hp && p.level < this.scene.getMaxExpLevel());
|
const nonFaintedPartyMembers = party.filter(p => p.hp);
|
||||||
|
const expPartyMembers = nonFaintedPartyMembers.filter(p => p.level < this.scene.getMaxExpLevel());
|
||||||
const partyMemberExp = [];
|
const partyMemberExp = [];
|
||||||
|
|
||||||
if (participantIds.size) {
|
if (participantIds.size) {
|
||||||
let expValue = this.getPokemon().getExpValue();
|
let expValue = this.getPokemon().getExpValue();
|
||||||
if (this.scene.currentBattle.battleType === BattleType.TRAINER)
|
if (this.scene.currentBattle.battleType === BattleType.TRAINER)
|
||||||
expValue = Math.floor(expValue * 1.5);
|
expValue = Math.floor(expValue * 1.5);
|
||||||
for (let partyMember of expPartyMembers) {
|
for (let partyMember of nonFaintedPartyMembers) {
|
||||||
const pId = partyMember.id;
|
const pId = partyMember.id;
|
||||||
const participated = participantIds.has(pId);
|
const participated = participantIds.has(pId);
|
||||||
if (participated)
|
if (participated)
|
||||||
partyMember.addFriendship(2);
|
partyMember.addFriendship(2);
|
||||||
else if (!expShareModifier) {
|
if (!expPartyMembers.includes(partyMember))
|
||||||
|
continue;
|
||||||
|
if (!participated && !expShareModifier) {
|
||||||
partyMemberExp.push(0);
|
partyMemberExp.push(0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -4340,7 +4361,7 @@ export class SelectModifierPhase extends BattlePhase {
|
|||||||
const isMoveModifier = modifierType instanceof PokemonMoveModifierType;
|
const isMoveModifier = modifierType instanceof PokemonMoveModifierType;
|
||||||
const isTmModifier = modifierType instanceof TmModifierType;
|
const isTmModifier = modifierType instanceof TmModifierType;
|
||||||
const isRememberMoveModifier = modifierType instanceof RememberMoveModifierType;
|
const isRememberMoveModifier = modifierType instanceof RememberMoveModifierType;
|
||||||
const isPpRestoreModifier = modifierType instanceof PokemonPpRestoreModifierType;
|
const isPpRestoreModifier = (modifierType instanceof PokemonPpRestoreModifierType || modifierType instanceof PokemonPpUpModifierType);
|
||||||
const partyUiMode = isMoveModifier ? PartyUiMode.MOVE_MODIFIER
|
const partyUiMode = isMoveModifier ? PartyUiMode.MOVE_MODIFIER
|
||||||
: isTmModifier ? PartyUiMode.TM_MODIFIER
|
: isTmModifier ? PartyUiMode.TM_MODIFIER
|
||||||
: isRememberMoveModifier ? PartyUiMode.REMEMBER_MOVE_MODIFIER
|
: isRememberMoveModifier ? PartyUiMode.REMEMBER_MOVE_MODIFIER
|
||||||
|
@ -128,6 +128,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
private starterSelectMessageBox: Phaser.GameObjects.NineSlice;
|
private starterSelectMessageBox: Phaser.GameObjects.NineSlice;
|
||||||
private starterSelectMessageBoxContainer: Phaser.GameObjects.Container;
|
private starterSelectMessageBoxContainer: Phaser.GameObjects.Container;
|
||||||
private statsContainer: StatsContainer;
|
private statsContainer: StatsContainer;
|
||||||
|
private pokemonFormText: Phaser.GameObjects.Text;
|
||||||
|
|
||||||
private genMode: boolean;
|
private genMode: boolean;
|
||||||
private statsMode: boolean;
|
private statsMode: boolean;
|
||||||
@ -434,6 +435,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonCandyIcon.setOrigin(0, 0);
|
this.pokemonCandyIcon.setOrigin(0, 0);
|
||||||
this.starterSelectContainer.add(this.pokemonCandyIcon);
|
this.starterSelectContainer.add(this.pokemonCandyIcon);
|
||||||
|
|
||||||
|
this.pokemonFormText = addTextObject(this.scene, 6, 42, 'Form', TextStyle.WINDOW_ALT, { fontSize: '42px' });
|
||||||
|
this.pokemonFormText.setOrigin(0, 0);
|
||||||
|
this.starterSelectContainer.add(this.pokemonFormText);
|
||||||
|
|
||||||
this.pokemonCandyOverlayIcon = this.scene.add.sprite(1, 12, 'items', 'candy_overlay');
|
this.pokemonCandyOverlayIcon = this.scene.add.sprite(1, 12, 'items', 'candy_overlay');
|
||||||
this.pokemonCandyOverlayIcon.setScale(0.5);
|
this.pokemonCandyOverlayIcon.setScale(0.5);
|
||||||
this.pokemonCandyOverlayIcon.setOrigin(0, 0);
|
this.pokemonCandyOverlayIcon.setOrigin(0, 0);
|
||||||
@ -1288,6 +1293,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonCandyOverlayIcon.setVisible(true);
|
this.pokemonCandyOverlayIcon.setVisible(true);
|
||||||
this.pokemonCandyCountText.setText(`x${this.scene.gameData.starterData[species.speciesId].candyCount}`);
|
this.pokemonCandyCountText.setText(`x${this.scene.gameData.starterData[species.speciesId].candyCount}`);
|
||||||
this.pokemonCandyCountText.setVisible(true);
|
this.pokemonCandyCountText.setVisible(true);
|
||||||
|
this.pokemonFormText.setVisible(true);
|
||||||
}
|
}
|
||||||
this.iconAnimHandler.addOrUpdate(this.starterSelectGenIconContainers[species.generation - 1].getAt(this.genSpecies[species.generation - 1].indexOf(species)) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.PASSIVE);
|
this.iconAnimHandler.addOrUpdate(this.starterSelectGenIconContainers[species.generation - 1].getAt(this.genSpecies[species.generation - 1].indexOf(species)) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.PASSIVE);
|
||||||
|
|
||||||
@ -1337,6 +1343,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonCandyIcon.setVisible(false);
|
this.pokemonCandyIcon.setVisible(false);
|
||||||
this.pokemonCandyOverlayIcon.setVisible(false);
|
this.pokemonCandyOverlayIcon.setVisible(false);
|
||||||
this.pokemonCandyCountText.setVisible(false);
|
this.pokemonCandyCountText.setVisible(false);
|
||||||
|
this.pokemonFormText.setVisible(false);
|
||||||
|
|
||||||
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, true, true);
|
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, true, true);
|
||||||
const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species);
|
||||||
@ -1363,6 +1370,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
this.pokemonCandyIcon.setVisible(false);
|
this.pokemonCandyIcon.setVisible(false);
|
||||||
this.pokemonCandyOverlayIcon.setVisible(false);
|
this.pokemonCandyOverlayIcon.setVisible(false);
|
||||||
this.pokemonCandyCountText.setVisible(false);
|
this.pokemonCandyCountText.setVisible(false);
|
||||||
|
this.pokemonFormText.setVisible(false);
|
||||||
|
|
||||||
this.setSpeciesDetails(species, false, 0, false, 0, 0, 0);
|
this.setSpeciesDetails(species, false, 0, false, 0, 0, 0);
|
||||||
this.pokemonSprite.clearTint();
|
this.pokemonSprite.clearTint();
|
||||||
@ -1522,6 +1530,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
|||||||
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);
|
const speciesForm = getPokemonSpeciesForm(species.speciesId, formIndex);
|
||||||
|
|
||||||
|
const formText = species?.forms[formIndex]?.formKey.split('-');
|
||||||
|
for (let i = 0; i < formText?.length; i++)
|
||||||
|
formText[i] = formText[i].charAt(0).toUpperCase() + formText[i].substring(1);
|
||||||
|
|
||||||
|
this.pokemonFormText.setText(formText?.join(' '));
|
||||||
|
|
||||||
this.setTypeIcons(speciesForm.type1, speciesForm.type2);
|
this.setTypeIcons(speciesForm.type1, speciesForm.type2);
|
||||||
} else {
|
} else {
|
||||||
this.pokemonAbilityText.setText('');
|
this.pokemonAbilityText.setText('');
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import BattleScene, { Button } from "../battle-scene";
|
import BattleScene, { Button, starterColors } from "../battle-scene";
|
||||||
import { Mode } from "./ui";
|
import { Mode } from "./ui";
|
||||||
import UiHandler from "./ui-handler";
|
import UiHandler from "./ui-handler";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { PlayerPokemon } from "../field/pokemon";
|
import { PlayerPokemon } from "../field/pokemon";
|
||||||
|
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies, getPokemonSpeciesForm, getStarterValueFriendshipCap, speciesStarters, starterPassiveAbilities } from '../data/pokemon-species';
|
||||||
|
import { argbFromRgba } from "@material/material-color-utilities";
|
||||||
import { Type, getTypeRgb } from "../data/type";
|
import { Type, getTypeRgb } from "../data/type";
|
||||||
import { TextStyle, addBBCodeTextObject, addTextObject, getBBCodeFrag, getTextColor } from "./text";
|
import { TextStyle, addBBCodeTextObject, addTextObject, getBBCodeFrag, getTextColor } from "./text";
|
||||||
import Move, { MoveCategory } from "../data/move";
|
import Move, { MoveCategory } from "../data/move";
|
||||||
@ -44,6 +46,9 @@ export default class SummaryUiHandler extends UiHandler {
|
|||||||
private genderText: Phaser.GameObjects.Text;
|
private genderText: Phaser.GameObjects.Text;
|
||||||
private shinyIcon: Phaser.GameObjects.Image;
|
private shinyIcon: Phaser.GameObjects.Image;
|
||||||
private fusionShinyIcon: Phaser.GameObjects.Image;
|
private fusionShinyIcon: Phaser.GameObjects.Image;
|
||||||
|
private candyShadow: Phaser.GameObjects.Sprite;
|
||||||
|
private candyIcon: Phaser.GameObjects.Sprite;
|
||||||
|
private candyOverlay: Phaser.GameObjects.Sprite;
|
||||||
private statusContainer: Phaser.GameObjects.Container;
|
private statusContainer: Phaser.GameObjects.Container;
|
||||||
private status: Phaser.GameObjects.Image;
|
private status: Phaser.GameObjects.Image;
|
||||||
private summaryPageContainer: Phaser.GameObjects.Container;
|
private summaryPageContainer: Phaser.GameObjects.Container;
|
||||||
@ -136,6 +141,20 @@ export default class SummaryUiHandler extends UiHandler {
|
|||||||
this.pokeball.setOrigin(0, 1);
|
this.pokeball.setOrigin(0, 1);
|
||||||
this.summaryContainer.add(this.pokeball);
|
this.summaryContainer.add(this.pokeball);
|
||||||
|
|
||||||
|
this.candyShadow = this.scene.add.sprite(13, -140, 'candy');
|
||||||
|
this.candyShadow.setTint(0x141414)
|
||||||
|
this.candyShadow.setScale(0.8);
|
||||||
|
this.candyShadow.setInteractive(new Phaser.Geom.Rectangle(0, 0, 16, 16), Phaser.Geom.Rectangle.Contains);
|
||||||
|
this.summaryContainer.add(this.candyShadow);
|
||||||
|
|
||||||
|
this.candyIcon = this.scene.add.sprite(13, -140, 'candy');
|
||||||
|
this.candyIcon.setScale(0.8);
|
||||||
|
this.summaryContainer.add(this.candyIcon);
|
||||||
|
|
||||||
|
this.candyOverlay = this.scene.add.sprite(13, -140, 'candy_overlay');
|
||||||
|
this.candyOverlay.setScale(0.8);
|
||||||
|
this.summaryContainer.add(this.candyOverlay);
|
||||||
|
|
||||||
this.levelText = addTextObject(this.scene, 36, -17, '', TextStyle.SUMMARY_ALT);
|
this.levelText = addTextObject(this.scene, 36, -17, '', TextStyle.SUMMARY_ALT);
|
||||||
this.levelText.setOrigin(0, 1);
|
this.levelText.setOrigin(0, 1);
|
||||||
this.summaryContainer.add(this.levelText);
|
this.summaryContainer.add(this.levelText);
|
||||||
@ -222,6 +241,10 @@ export default class SummaryUiHandler extends UiHandler {
|
|||||||
|
|
||||||
this.shinyOverlay.setVisible(this.pokemon.isShiny());
|
this.shinyOverlay.setVisible(this.pokemon.isShiny());
|
||||||
|
|
||||||
|
const colorScheme = starterColors[this.pokemon.species.getRootSpeciesId()];
|
||||||
|
this.candyIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[0])));
|
||||||
|
this.candyOverlay.setTint(argbFromRgba(Utils.rgbHexToRgba(colorScheme[1])));
|
||||||
|
|
||||||
this.numberText.setText(Utils.padInt(this.pokemon.species.speciesId, 4));
|
this.numberText.setText(Utils.padInt(this.pokemon.species.speciesId, 4));
|
||||||
this.numberText.setColor(this.getTextColor(!this.pokemon.isShiny() ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD));
|
this.numberText.setColor(this.getTextColor(!this.pokemon.isShiny() ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD));
|
||||||
this.numberText.setShadowColor(this.getTextColor(!this.pokemon.isShiny() ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD, true));
|
this.numberText.setShadowColor(this.getTextColor(!this.pokemon.isShiny() ? TextStyle.SUMMARY : TextStyle.SUMMARY_GOLD, true));
|
||||||
@ -251,6 +274,21 @@ export default class SummaryUiHandler extends UiHandler {
|
|||||||
this.splicedIcon.on('pointerout', () => (this.scene as BattleScene).ui.hideTooltip());
|
this.splicedIcon.on('pointerout', () => (this.scene as BattleScene).ui.hideTooltip());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var currentFriendship = this.scene.gameData.starterData[this.pokemon.species.getRootSpeciesId()].friendship;
|
||||||
|
if (!currentFriendship || currentFriendship === undefined)
|
||||||
|
currentFriendship = 0;
|
||||||
|
|
||||||
|
const friendshipCap = getStarterValueFriendshipCap(speciesStarters[this.pokemon.species.getRootSpeciesId()]);
|
||||||
|
const candyCropY = 16 - (16 * (currentFriendship / friendshipCap));
|
||||||
|
|
||||||
|
if (this.candyShadow.visible) {
|
||||||
|
this.candyShadow.on('pointerover', () => (this.scene as BattleScene).ui.showTooltip(null, `${currentFriendship}/${friendshipCap}`, true));
|
||||||
|
this.candyShadow.on('pointerout', () => (this.scene as BattleScene).ui.hideTooltip());
|
||||||
|
}
|
||||||
|
|
||||||
|
this.candyIcon.setCrop(0,candyCropY,16, 16);
|
||||||
|
this.candyOverlay.setCrop(0,candyCropY,16, 16);
|
||||||
|
|
||||||
const doubleShiny = isFusion && this.pokemon.shiny && this.pokemon.fusionShiny;
|
const doubleShiny = isFusion && this.pokemon.shiny && this.pokemon.fusionShiny;
|
||||||
const baseVariant = !doubleShiny ? this.pokemon.getVariant() : this.pokemon.variant;
|
const baseVariant = !doubleShiny ? this.pokemon.getVariant() : this.pokemon.variant;
|
||||||
|
|
||||||
|
10
src/utils.ts
@ -62,6 +62,11 @@ export function padInt(value: integer, length: integer, padWith?: string): strin
|
|||||||
return valueStr;
|
return valueStr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a random integer between min and min + range
|
||||||
|
* @param range The amount of possible numbers
|
||||||
|
* @param min The starting number
|
||||||
|
*/
|
||||||
export function randInt(range: integer, min: integer = 0): integer {
|
export function randInt(range: integer, min: integer = 0): integer {
|
||||||
if (range === 1)
|
if (range === 1)
|
||||||
return min;
|
return min;
|
||||||
@ -74,6 +79,11 @@ export function randSeedInt(range: integer, min: integer = 0): integer {
|
|||||||
return Phaser.Math.RND.integerInRange(min, (range - 1) + min);
|
return Phaser.Math.RND.integerInRange(min, (range - 1) + min);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a random integer between min and max (non-inclusive)
|
||||||
|
* @param min The lowest number
|
||||||
|
* @param max The highest number
|
||||||
|
*/
|
||||||
export function randIntRange(min: integer, max: integer): integer {
|
export function randIntRange(min: integer, max: integer): integer {
|
||||||
return randInt(max - min, min);
|
return randInt(max - min, min);
|
||||||
}
|
}
|
||||||
|