Add color change ability, some moves, and fix mimic

pull/1/head
Flashfyre 2023-05-06 00:42:01 -04:00
parent 45f73cc6ed
commit 15cfd3bad4
9 changed files with 152 additions and 52 deletions

View File

@ -413,12 +413,16 @@ export class SummonPhase extends BattlePhase {
}
end() {
if (this.scene.getPlayerPokemon().shiny)
const pokemon = this.scene.getPlayerPokemon();
if (pokemon.shiny)
this.scene.unshiftPhase(new ShinySparklePhase(this.scene, true));
this.scene.arena.applyTags(ArenaTrapTag, this.scene.getPlayerPokemon());
pokemon.resetTurnData();
applyPostSummonAbAttrs(PostSummonAbAttr, this.scene.getPlayerPokemon());
this.scene.arena.applyTags(ArenaTrapTag, pokemon);
applyPostSummonAbAttrs(PostSummonAbAttr, pokemon);
super.end();
}
@ -594,8 +598,8 @@ export class CommandPhase extends FieldPhase {
const moveQueue = playerPokemon.getMoveQueue();
while (moveQueue.length && moveQueue[0]
&& moveQueue[0].move && (!playerPokemon.moveset.find(m => m.moveId === moveQueue[0].move)
|| !playerPokemon.moveset[playerPokemon.moveset.findIndex(m => m.moveId === moveQueue[0].move)].isUsable(moveQueue[0].ignorePP)))
&& moveQueue[0].move && (!playerPokemon.getMoveset().find(m => m.moveId === moveQueue[0].move)
|| !playerPokemon.getMoveset()[playerPokemon.getMoveset().findIndex(m => m.moveId === moveQueue[0].move)].isUsable(moveQueue[0].ignorePP)))
moveQueue.shift();
if (moveQueue.length) {
@ -603,8 +607,8 @@ export class CommandPhase extends FieldPhase {
if (!queuedMove.move)
this.handleCommand(Command.FIGHT, -1, false);
else {
const moveIndex = playerPokemon.moveset.findIndex(m => m.moveId === queuedMove.move);
if (moveIndex > -1 && playerPokemon.moveset[moveIndex].isUsable(queuedMove.ignorePP))
const moveIndex = playerPokemon.getMoveset().findIndex(m => m.moveId === queuedMove.move);
if (moveIndex > -1 && playerPokemon.getMoveset()[moveIndex].isUsable(queuedMove.ignorePP))
this.handleCommand(Command.FIGHT, moveIndex, queuedMove.ignorePP);
}
} else
@ -647,12 +651,12 @@ export class CommandPhase extends FieldPhase {
}
if (playerPokemon.trySelectMove(cursor, args[0] as boolean)) {
playerMove = playerPokemon.moveset[cursor];
playerMove = playerPokemon.getMoveset()[cursor];
const playerPhase = new PlayerMovePhase(this.scene, playerPokemon, playerMove, false, args[0] as boolean);
this.scene.pushPhase(playerPhase);
success = true;
} else if (cursor < playerPokemon.moveset.length) {
const move = playerPokemon.moveset[cursor];
} else if (cursor < playerPokemon.getMoveset().length) {
const move = playerPokemon.getMoveset()[cursor];
if (move.isDisabled()) {
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.showText(`${move.getName()} is disabled!`, null, () => {
@ -703,7 +707,7 @@ export class CommandPhase extends FieldPhase {
const enemyNextMove = enemyPokemon.getNextMove();
let enemyMove: PokemonMove;
if (enemyNextMove.move) {
enemyMove = enemyPokemon.moveset.find(m => m.moveId === enemyNextMove.move) || new PokemonMove(enemyNextMove.move, 0, 0);
enemyMove = enemyPokemon.getMoveset().find(m => m.moveId === enemyNextMove.move) || new PokemonMove(enemyNextMove.move, 0, 0);
const enemyPhase = new EnemyMovePhase(this.scene, enemyPokemon, enemyMove, false, enemyNextMove.ignorePP);
if (isDelayed(command, playerMove, enemyMove))
this.scene.unshiftPhase(enemyPhase);
@ -753,7 +757,7 @@ export class TurnEndPhase extends FieldPhase {
pokemon.lapseTags(BattlerTagLapseType.TURN_END);
const disabledMoves = pokemon.moveset.filter(m => m.isDisabled());
const disabledMoves = pokemon.getMoveset().filter(m => m.isDisabled());
for (let dm of disabledMoves) {
if (!--dm.disableTurns)
this.scene.pushPhase(new MessagePhase(this.scene, `${dm.getName()} is disabled\nno more!`));
@ -1048,7 +1052,7 @@ abstract class MoveEffectPhase extends PokemonPhase {
if (!isProtected && !this.move.getMove().getAttrs(ChargeAttr).filter(ca => (ca as ChargeAttr).chargeEffect).length) {
applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveHitEffectAttr && (!!target.hp || (attr as MoveHitEffectAttr).selfTarget), user, target, this.move.getMove());
if (target.hp)
applyPostDefendAbAttrs(PostDefendAbAttr, user, target, this.move, result);
applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move, result);
if (this.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT))
this.scene.applyModifiers(ContactHeldItemTransferChanceModifier, this.player, user);
}
@ -1763,23 +1767,23 @@ export class LearnMovePhase extends PartyMemberPokemonPhase {
const pokemon = this.getPokemon();
const move = allMoves[this.moveId];
const existingMoveIndex = pokemon.moveset.findIndex(m => m?.moveId === move.id);
const existingMoveIndex = pokemon.getMoveset().findIndex(m => m?.moveId === move.id);
if (existingMoveIndex > -1) {
this.end();
return;
}
const emptyMoveIndex = pokemon.moveset.length < 4
? pokemon.moveset.length
: pokemon.moveset.findIndex(m => m === null);
const emptyMoveIndex = pokemon.getMoveset().length < 4
? pokemon.getMoveset().length
: pokemon.getMoveset().findIndex(m => m === null);
const messageMode = this.scene.ui.getHandler() instanceof EvolutionSceneHandler
? Mode.EVOLUTION_SCENE
: Mode.MESSAGE;
if (emptyMoveIndex > -1) {
pokemon.moveset[emptyMoveIndex] = new PokemonMove(this.moveId, 0, 0);
pokemon.setMove(emptyMoveIndex, this.moveId);
initMoveAnim(this.moveId).then(() => {
loadMoveAnimAssets(this.scene, [ this.moveId ], true)
.then(() => {
@ -1820,7 +1824,7 @@ export class LearnMovePhase extends PartyMemberPokemonPhase {
this.scene.ui.showText('@d{32}1, @d{15}2, and@d{15}… @d{15}… @d{15}… @d{15}@s{pb_bounce_1}Poof!', null, () => {
this.scene.ui.showText(`${pokemon.name} forgot how to\nuse ${pokemon.moveset[moveIndex].getName()}.`, null, () => {
this.scene.ui.showText('And…', null, () => {
pokemon.moveset[moveIndex] = null;
pokemon.setMove(moveIndex, Moves.NONE);
this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId));
this.end();
}, null, true);

View File

@ -7,7 +7,7 @@ import { getPokemonMessage } from "../messages";
import { Weather, WeatherType } from "./weather";
import { BattlerTag, BattlerTagType, TrappedTag } from "./battler-tag";
import { StatusEffect, getStatusEffectDescriptor } from "./status-effect";
import { MoveFlags, Moves, RecoilAttr } from "./move";
import { MoveFlags, Moves, RecoilAttr, allMoves } from "./move";
export class Ability {
public id: Abilities;
@ -230,6 +230,25 @@ export class PostDefendAbAttr extends AbAttr {
}
}
export class PostDefendTypeChangeAbAttr extends PostDefendAbAttr {
applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, moveResult: MoveResult, args: any[]): boolean {
if (moveResult < MoveResult.NO_EFFECT) {
const type = move.getMove().type;
const type2 = pokemon.species.type2;
if (type !== pokemon.getTypes()[0] && type !== type2) {
pokemon.summonData.types = [ type ].concat(type2 !== null ? [ type2 ] : []);
return true;
}
}
return false;
}
getTriggerMessage(pokemon: Pokemon, ...args: any[]): string {
return getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nmade it the ${Type[pokemon.getTypes()[0]]} type!`);
}
}
export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr {
private chance: integer;
private effects: StatusEffect[];
@ -1104,7 +1123,8 @@ export function initAbilities() {
.attr(ProtectStatAttr),
new Ability(Abilities.CLOUD_NINE, "Cloud Nine", "Eliminates the effects of non-severe weather.", 3)
.attr(SuppressWeatherEffectAbAttr),
new Ability(Abilities.COLOR_CHANGE, "Color Change (N)", "Changes the POKéMON's type to the foe's move.", 3),
new Ability(Abilities.COLOR_CHANGE, "Color Change", "Changes the POKéMON's type to the foe's move.", 3)
.attr(PostDefendTypeChangeAbAttr),
new Ability(Abilities.COMPOUND_EYES, "Compound Eyes", "The POKéMON's accuracy is boosted.", 3)
.attr(BattleStatMultiplierAbAttr, BattleStat.ACC, 1.3),
new Ability(Abilities.CUTE_CHARM, "Cute Charm", "Contact with the POKéMON may cause infatuation.", 3)

View File

@ -3,7 +3,7 @@ import { DamagePhase, EnemyMovePhase, ObtainStatusEffectPhase, PlayerMovePhase,
import { BattleStat } from "./battle-stat";
import { BattlerTagType } from "./battler-tag";
import { getPokemonMessage } from "../messages";
import Pokemon, { EnemyPokemon, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../pokemon";
import Pokemon, { AttackMoveResult, EnemyPokemon, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../pokemon";
import { StatusEffect, getStatusEffectDescriptor } from "./status-effect";
import { Type } from "./type";
import * as Utils from "../utils";
@ -847,6 +847,29 @@ export class TargetHalfHpDamageAttr extends FixedDamageAttr {
}
}
type MoveFilter = (move: Move) => boolean;
export class CounterDamageAttr extends FixedDamageAttr {
private moveFilter: MoveFilter;
constructor(moveFilter: MoveFilter) {
super(0);
this.moveFilter = moveFilter;
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const damage = user.turnData.attacksReceived.filter(ar => this.moveFilter(allMoves[ar.move])).reduce((total: integer, ar: AttackMoveResult) => total + ar.damage, 0);
(args[0] as Utils.IntegerHolder).value = Math.max(damage * 2, 1);
return true;
}
getCondition(): MoveCondition {
return (user: Pokemon, target: Pokemon, move: Move) => !!user.turnData.attacksReceived.filter(ar => this.moveFilter(allMoves[ar.move])).length;
}
}
export class RecoilAttr extends MoveEffectAttr {
private useHp: boolean;
@ -1460,11 +1483,11 @@ export class DisableMoveAttr extends MoveEffectAttr {
if (turnMove.virtual)
continue;
const moveIndex = target.moveset.findIndex(m => m.moveId === turnMove.move);
const moveIndex = target.getMoveset().findIndex(m => m.moveId === turnMove.move);
if (moveIndex === -1)
return false;
const disabledMove = target.moveset[moveIndex];
const disabledMove = target.getMoveset()[moveIndex];
disabledMove.disableTurns = 4;
user.scene.queueMessage(getPokemonMessage(target, `'s ${disabledMove.getName()}\nwas disabled!`));
@ -1484,7 +1507,7 @@ export class DisableMoveAttr extends MoveEffectAttr {
if (turnMove.virtual)
continue;
const move = target.moveset.find(m => m.moveId === turnMove.move);
const move = target.getMoveset().find(m => m.moveId === turnMove.move);
if (!move)
continue;
@ -1733,7 +1756,7 @@ export class RandomMovesetMoveAttr extends OverrideMoveEffectAttr {
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const moveset = (!this.enemyMoveset ? user : target).moveset;
const moveset = (!this.enemyMoveset ? user : target).getMoveset();
const moves = moveset.filter(m => !m.getMove().hasFlag(MoveFlags.IGNORE_VIRTUAL));
if (moves.length) {
const move = moves[Utils.randInt(moves.length)];
@ -1805,6 +1828,32 @@ export class CopyMoveAttr extends OverrideMoveEffectAttr {
}
}
export class MovesetCopyMoveAttr extends OverrideMoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
const targetMoves = target.getMoveHistory().filter(m => !m.virtual);
if (!targetMoves.length)
return false;
const copiedMove = allMoves[targetMoves[0].move];
const thisMoveIndex = user.getMoveset().findIndex(m => m.moveId === move.id);
if (thisMoveIndex === -1)
return false;
user.summonData.moveset = user.getMoveset().slice(0);
user.summonData.moveset[thisMoveIndex] = new PokemonMove(copiedMove.id, 0, 0);
user.scene.queueMessage(getPokemonMessage(user, ` copied\n${copiedMove.name}!`));
return true;
}
getCondition(): MoveCondition {
return targetMoveCopiableCondition;
}
}
export class SketchAttr extends MoveEffectAttr {
constructor() {
super(true);
@ -1820,12 +1869,12 @@ export class SketchAttr extends MoveEffectAttr {
const sketchedMove = allMoves[targetMoves[0].move];
const sketchIndex = user.moveset.findIndex(m => m.moveId === move.id);
const sketchIndex = user.getMoveset().findIndex(m => m.moveId === move.id);
if (sketchIndex === -1)
return false;
user.moveset[sketchIndex] = new PokemonMove(sketchedMove.id, 0, 0);
user.setMove(sketchIndex, sketchedMove.id);
user.scene.queueMessage(getPokemonMessage(user, ` sketched\n${sketchedMove.name}!`));
@ -1843,7 +1892,7 @@ export class SketchAttr extends MoveEffectAttr {
const sketchableMove = targetMoves[0];
if (user.moveset.find(m => m.moveId === sketchableMove.move))
if (user.getMoveset().find(m => m.moveId === sketchableMove.move))
return false;
return true;
@ -2034,7 +2083,8 @@ export function initMoves() {
.attr(RecoilAttr),
new AttackMove(Moves.LOW_KICK, "Low Kick", Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 20, 12, "The heavier the opponent, the stronger the attack.", -1, 0, 1)
.attr(WeightPowerAttr),
new AttackMove(Moves.COUNTER, "Counter (N)", Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 20, -1, "When hit by a Physical Attack, user strikes back with 2x power.", -1, -5, 1)
new AttackMove(Moves.COUNTER, "Counter", Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 20, -1, "When hit by a Physical Attack, user strikes back with 2x power.", -1, -5, 1)
.attr(CounterDamageAttr, (move: Move) => move.category === MoveCategory.PHYSICAL)
.target(MoveTarget.ATTACKER),
new AttackMove(Moves.SEISMIC_TOSS, "Seismic Toss", Type.FIGHTING, MoveCategory.PHYSICAL, -1, 100, 20, -1, "Inflicts damage equal to user's level (maximum 150).", -1, 0, 1)
.attr(LevelPowerAttr),
@ -2114,7 +2164,7 @@ export function initMoves() {
new AttackMove(Moves.NIGHT_SHADE, "Night Shade", Type.GHOST, MoveCategory.SPECIAL, -1, 100, 15, 42, "Inflicts damage equal to user's level (maximum 150).", -1, 0, 1)
.attr(LevelPowerAttr),
new StatusMove(Moves.MIMIC, "Mimic", Type.NORMAL, -1, 10, -1, "Copies the opponent's last move.", -1, 0, 1)
.attr(CopyMoveAttr)
.attr(MovesetCopyMoveAttr)
.ignoresVirtual(),
new StatusMove(Moves.SCREECH, "Screech", Type.NORMAL, 85, 40, -1, "Sharply lowers opponent's Defense.", -1, 0, 1)
.attr(StatChangeAttr, BattleStat.DEF, -2),
@ -2150,7 +2200,8 @@ export function initMoves() {
new SelfStatusMove(Moves.METRONOME, "Metronome", Type.NORMAL, -1, 10, 80, "User performs almost any move in the game at random.", -1, 0, 1)
.attr(RandomMoveAttr)
.ignoresVirtual(),
new SelfStatusMove(Moves.MIRROR_MOVE, "Mirror Move (N)", Type.FLYING, -1, 20, -1, "User performs the opponent's last move.", -1, 0, 1)
new SelfStatusMove(Moves.MIRROR_MOVE, "Mirror Move", Type.FLYING, -1, 20, -1, "User performs the opponent's last move.", -1, 0, 1)
.attr(CopyMoveAttr)
.ignoresVirtual(),
new AttackMove(Moves.SELF_DESTRUCT, "Self-Destruct", Type.NORMAL, MoveCategory.PHYSICAL, 200, 100, 5, -1, "User faints.", -1, 0, 1)
.attr(SacrificialAttr)
@ -2434,7 +2485,8 @@ export function initMoves() {
.target(MoveTarget.BOTH_SIDES),
new AttackMove(Moves.CRUNCH, "Crunch", Type.DARK, MoveCategory.PHYSICAL, 80, 100, 15, 108, "May lower opponent's Defense.", 20, 0, 2)
.attr(StatChangeAttr, BattleStat.DEF, -1),
new AttackMove(Moves.MIRROR_COAT, "Mirror Coat (N)", Type.PSYCHIC, MoveCategory.SPECIAL, -1, 100, 20, -1, "When hit by a Special Attack, user strikes back with 2x power.", -1, -5, 2)
new AttackMove(Moves.MIRROR_COAT, "Mirror Coat", Type.PSYCHIC, MoveCategory.SPECIAL, -1, 100, 20, -1, "When hit by a Special Attack, user strikes back with 2x power.", -1, -5, 2)
.attr(CounterDamageAttr, (move: Move) => move.category === MoveCategory.SPECIAL)
.target(MoveTarget.ATTACKER),
new SelfStatusMove(Moves.PSYCH_UP, "Psych Up (N)", Type.NORMAL, -1, 10, -1, "Copies the opponent's stat changes.", -1, 0, 2),
new AttackMove(Moves.EXTREME_SPEED, "Extreme Speed", Type.NORMAL, MoveCategory.PHYSICAL, 80, 100, 5, -1, "User attacks first.", -1, 2, 2),
@ -2721,7 +2773,7 @@ export function initMoves() {
new StatusMove(Moves.GUARD_SWAP, "Guard Swap (N)", Type.PSYCHIC, -1, 10, -1, "User and opponent swap Defense and Special Defense.", -1, 0, 4),
new AttackMove(Moves.PUNISHMENT, "Punishment (N)", Type.DARK, MoveCategory.PHYSICAL, -1, 100, 5, -1, "Power increases when opponent's stats have been raised.", -1, 0, 4),
new AttackMove(Moves.LAST_RESORT, "Last Resort", Type.NORMAL, MoveCategory.PHYSICAL, 140, 100, 5, -1, "Can only be used after all other moves are used.", -1, 0, 4)
.condition((user: Pokemon, target: Pokemon, move: Move) => !user.moveset.filter(m => m.moveId !== move.id && m.getPpRatio() > 0).length),
.condition((user: Pokemon, target: Pokemon, move: Move) => !user.getMoveset().filter(m => m.moveId !== move.id && m.getPpRatio() > 0).length),
new StatusMove(Moves.WORRY_SEED, "Worry Seed (N)", Type.GRASS, 100, 10, -1, "Changes the opponent's Ability to Insomnia.", -1, 0, 4),
new AttackMove(Moves.SUCKER_PUNCH, "Sucker Punch (N)", Type.DARK, MoveCategory.PHYSICAL, 70, 100, 5, -1, "User attacks first, but only works if opponent is readying an attack.", -1, 0, 4),
new StatusMove(Moves.TOXIC_SPIKES, "Toxic Spikes", Type.POISON, -1, 20, 91, "Poisons opponents when they switch into battle.", -1, 0, 4)

View File

@ -185,7 +185,7 @@ export class PokemonAllMovePpRestoreModifierType extends PokemonModifierType {
constructor(name: string, restorePoints: integer, iconImage?: string) {
super(name, `Restore ${restorePoints > -1 ? restorePoints : 'all'} PP for all of one POKéMON's moves`, (_type, args) => new Modifiers.PokemonAllMovePpRestoreModifier(this, (args[0] as PlayerPokemon).id, this.restorePoints),
(pokemon: PlayerPokemon) => {
if (!pokemon.moveset.filter(m => m.ppUsed).length)
if (!pokemon.getMoveset().filter(m => m.ppUsed).length)
return PartyUiHandler.NoEffectMessage;
return null;
}, iconImage, 'elixir');
@ -361,7 +361,7 @@ export class TmModifierType extends PokemonModifierType {
constructor(moveId: Moves) {
super(`TM${Utils.padInt(Object.keys(tmSpecies).indexOf(moveId.toString()) + 1, 3)} - ${allMoves[moveId].name}`, `Teach ${allMoves[moveId].name} to a POKéMON`, (_type, args) => new Modifiers.TmModifier(this, (args[0] as PlayerPokemon).id),
(pokemon: PlayerPokemon) => {
if (pokemon.compatibleTms.indexOf(moveId) === -1 || pokemon.moveset.filter(m => m?.moveId === moveId).length)
if (pokemon.compatibleTms.indexOf(moveId) === -1 || pokemon.getMoveset().filter(m => m?.moveId === moveId).length)
return PartyUiHandler.NoEffectMessage;
return null;
}, `tm_${Type[allMoves[moveId].type].toLowerCase()}`, 'tm');
@ -424,7 +424,7 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator {
if (pregenArgs)
return new AttackTypeBoosterModifierType(pregenArgs[0] as Type, 20);
const attackMoveTypes = party.map(p => p.moveset.map(m => m.getMove()).filter(m => m instanceof AttackMove).map(m => m.type)).flat();
const attackMoveTypes = party.map(p => p.getMoveset().map(m => m.getMove()).filter(m => m instanceof AttackMove).map(m => m.type)).flat();
const attackMoveTypeWeights = new Map<Type, integer>();
let totalWeight = 0;
for (let t of attackMoveTypes) {
@ -648,11 +648,11 @@ const modifierPool = {
return thresholdPartyMemberCount;
}),
new WeightedModifierType(modifierTypes.ETHER, (party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.moveset.filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length, 3);
const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length, 3);
return thresholdPartyMemberCount * 3;
}),
new WeightedModifierType(modifierTypes.MAX_ETHER, (party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.moveset.filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length, 3);
const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length, 3);
return thresholdPartyMemberCount;
}),
new WeightedModifierType(modifierTypes.TEMP_STAT_BOOSTER, 4),
@ -685,11 +685,11 @@ const modifierPool = {
return thresholdPartyMemberCount;
}),
new WeightedModifierType(modifierTypes.ELIXIR, (party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.moveset.filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length, 3);
const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length, 3);
return thresholdPartyMemberCount * 3;
}),
new WeightedModifierType(modifierTypes.MAX_ELIXIR, (party: Pokemon[]) => {
const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.moveset.filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length, 3);
const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => (m.getMove().pp - m.ppUsed) <= 5).length).length, 3);
return thresholdPartyMemberCount;
}),
new WeightedModifierType(modifierTypes.MAP, (party: Pokemon[]) => {

View File

@ -699,7 +699,7 @@ export class PokemonPpRestoreModifier extends ConsumablePokemonMoveModifier {
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
const move = pokemon.moveset[this.moveIndex];
const move = pokemon.getMoveset()[this.moveIndex];
move.ppUsed = this.restorePoints >= -1 ? Math.max(move.ppUsed - this.restorePoints, 0) : 0;
return true;
@ -717,7 +717,7 @@ export class PokemonAllMovePpRestoreModifier extends ConsumablePokemonModifier {
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
for (let move of pokemon.moveset)
for (let move of pokemon.getMoveset())
move.ppUsed = this.restorePoints >= -1 ? Math.max(move.ppUsed - this.restorePoints, 0) : 0;
return true;

View File

@ -181,7 +181,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
loadAssets(): Promise<void> {
return new Promise(resolve => {
const moveIds = this.moveset.map(m => m.getMove().id);
const moveIds = this.getMoveset().map(m => m.getMove().id);
Promise.allSettled(moveIds.map(m => initMoveAnim(m)))
.then(() => {
loadMoveAnimAssets(this.scene, moveIds);
@ -320,6 +320,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return Math.floor((this.hp / this.getMaxHp()) * 100) / 100;
}
getMoveset(): PokemonMove[] {
if (this.summonData?.moveset)
return this.summonData.moveset;
return this.moveset;
}
getTypes(): Type[] {
const types = [];
@ -395,6 +401,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return ret;
}
setMove(moveIndex: integer, moveId: Moves): void {
const move = moveId ? new PokemonMove(moveId) : null;
this.moveset[moveId] = move;
if (this.summonData.moveset)
this.summonData.moveset[moveIndex] = move;
}
generateAndPopulateMoveset(): void {
this.moveset = [];
@ -434,8 +447,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
trySelectMove(moveIndex: integer, ignorePp?: boolean): boolean {
const move = this.moveset.length > moveIndex
? this.moveset[moveIndex]
const move = this.getMoveset().length > moveIndex
? this.getMoveset()[moveIndex]
: null;
return move?.isUsable(ignorePp);
}
@ -576,6 +589,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.scene.queueMessage('A critical hit!');
this.damage(damage);
source.turnData.damageDealt += damage;
this.turnData.attacksReceived.unshift({ move: move.id, result: result as DamageResult, damage: damage, sourceId: source.id });
}
switch (result) {
@ -1023,7 +1037,7 @@ export class EnemyPokemon extends Pokemon {
getNextMove(): QueuedMove {
const queuedMove = this.getMoveQueue().length
? this.moveset.find(m => m.moveId === this.getMoveQueue()[0].move)
? this.getMoveset().find(m => m.moveId === this.getMoveQueue()[0].move)
: null;
if (queuedMove) {
if (queuedMove.isUsable(this.getMoveQueue()[0].ignorePP))
@ -1034,7 +1048,7 @@ export class EnemyPokemon extends Pokemon {
}
}
const movePool = this.moveset.filter(m => m.isUsable());
const movePool = this.getMoveset().filter(m => m.isUsable());
if (movePool.length) {
if (movePool.length === 1)
return { move: movePool[0].moveId };
@ -1139,10 +1153,18 @@ export interface QueuedMove {
ignorePP?: boolean;
}
export interface AttackMoveResult {
move: Moves;
result: DamageResult;
damage: integer;
sourceId: integer;
}
export class PokemonSummonData {
public battleStats: integer[] = [ 0, 0, 0, 0, 0, 0, 0 ];
public moveQueue: QueuedMove[] = [];
public tags: BattlerTag[] = [];
public moveset: PokemonMove[];
public types: Type[];
}
@ -1156,6 +1178,7 @@ export class PokemonTurnData {
public hitCount: integer;
public hitsLeft: integer;
public damageDealt: integer = 0;
public attacksReceived: AttackMoveResult[] = [];
}
export enum AiType {

View File

@ -63,7 +63,7 @@ export function initAutoPlay() {
const getMaxMoveEffectiveness = (attacker: Pokemon, defender: Pokemon) => {
let maxEffectiveness = 0.5;
for (let m of attacker.moveset) {
for (let m of attacker.getMoveset()) {
const moveType = m.getMove().type;
const effectiveness = defender.getAttackMoveEffectiveness(moveType);
if (effectiveness > maxEffectiveness)
@ -129,7 +129,7 @@ export function initAutoPlay() {
playerPokemon.aiType = AiType.SMART;
thisArg.time.delayedCall(20, () => {
const nextMove = playerPokemon.getNextMove() as PokemonMove;
fightUiHandler.setCursor(playerPokemon.moveset.indexOf(nextMove));
fightUiHandler.setCursor(playerPokemon.getMoveset().indexOf(nextMove));
thisArg.time.delayedCall(20, () => this.processInput(Button.ACTION));
});
}

View File

@ -65,6 +65,7 @@ export default class PokemonData {
this.summonData.battleStats = source.summonData.battleStats;
this.summonData.moveQueue = source.summonData.moveQueue;
this.summonData.tags = []; // TODO
this.summonData.moveset = source.summonData.moveset;
this.summonData.types = source.summonData.types;
}
}

View File

@ -91,7 +91,7 @@ export default class FightUiHandler extends UiHandler {
ui.add(this.cursorObj);
}
const moveset = this.scene.getPlayerPokemon().moveset;
const moveset = this.scene.getPlayerPokemon().getMoveset();
const hasMove = cursor < moveset.length;
@ -114,7 +114,7 @@ export default class FightUiHandler extends UiHandler {
}
displayMoves() {
const moveset = this.scene.getPlayerPokemon().moveset;
const moveset = this.scene.getPlayerPokemon().getMoveset();
for (let m = 0; m < 4; m++) {
const moveText = addTextObject(this.scene, m % 2 === 0 ? 0 : 100, m < 2 ? 0 : 16, '-', TextStyle.WINDOW);
if (m < moveset.length)