Add logic for disable move

pull/1/head
Flashfyre 2023-04-19 18:19:55 -04:00
parent da0d607f26
commit 52a28ed95a
4 changed files with 131 additions and 29 deletions

View File

@ -449,9 +449,17 @@ export class CommandPhase extends BattlePhase {
playerPokemon.resetTurnData(); playerPokemon.resetTurnData();
this.scene.getEnemyPokemon().resetTurnData(); this.scene.getEnemyPokemon().resetTurnData();
if (playerPokemon.summonData.moveQueue.length) while (playerPokemon.summonData.moveQueue.length && playerPokemon.summonData.moveQueue[0]
this.handleCommand(Command.FIGHT, playerPokemon.moveset.findIndex(m => m.moveId === playerPokemon.summonData.moveQueue[0].move)); && !playerPokemon.moveset[playerPokemon.moveset.findIndex(m => m.moveId === playerPokemon.summonData.moveQueue[0].move)]
else .isUsable(playerPokemon.summonData.moveQueue[0].ignorePP))
playerPokemon.summonData.moveQueue.shift();
if (playerPokemon.summonData.moveQueue.length) {
const queuedMove = playerPokemon.summonData.moveQueue[0];
const moveIndex = playerPokemon.moveset.findIndex(m => m.moveId === queuedMove.move);
if (playerPokemon.moveset[moveIndex].isUsable(queuedMove.ignorePP))
this.handleCommand(Command.FIGHT, moveIndex);
} else
this.scene.ui.setMode(Mode.COMMAND); this.scene.ui.setMode(Mode.COMMAND);
} }
@ -492,7 +500,12 @@ export class CommandPhase extends BattlePhase {
const playerPhase = new PlayerMovePhase(this.scene, playerPokemon, playerMove); const playerPhase = new PlayerMovePhase(this.scene, playerPokemon, playerMove);
this.scene.pushPhase(playerPhase); this.scene.pushPhase(playerPhase);
success = true; success = true;
} else if (cursor < playerPokemon.moveset.length) {
const move = playerPokemon.moveset[cursor];
if (move.isDisabled())
this.scene.ui.showText(`${move.getName()} is disabled!`);
} }
break; break;
case Command.BALL: case Command.BALL:
if (cursor < 4) { if (cursor < 4) {
@ -557,16 +570,32 @@ export class TurnEndPhase extends BattlePhase {
const playerPokemon = this.scene.getPlayerPokemon(); const playerPokemon = this.scene.getPlayerPokemon();
const enemyPokemon = this.scene.getEnemyPokemon(); const enemyPokemon = this.scene.getEnemyPokemon();
const handlePokemon = (pokemon: Pokemon) => {
if (!pokemon)
return;
if (playerPokemon) { pokemon.lapseTags(BattleTagLapseType.TURN_END);
playerPokemon.lapseTags(BattleTagLapseType.TURN_END);
playerPokemon.battleSummonData.turnCount++; const disabledMoves = pokemon.moveset.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!`));
}
if (enemyPokemon) { pokemon.battleSummonData.turnCount++;
enemyPokemon.lapseTags(BattleTagLapseType.TURN_END); };
enemyPokemon.battleSummonData.turnCount++;
} const playerSpeed = playerPokemon?.getBattleStat(Stat.SPD) || 0;
const enemySpeed = enemyPokemon?.getBattleStat(Stat.SPD) || 0;
const isDelayed = playerSpeed < enemySpeed || (playerSpeed === enemySpeed && Utils.randInt(2) === 1);
if (!isDelayed)
handlePokemon(playerPokemon);
handlePokemon(enemyPokemon);
if (isDelayed)
handlePokemon(playerPokemon);
if (this.scene.arena.weather && !this.scene.arena.weather.lapse()) if (this.scene.arena.weather && !this.scene.arena.weather.lapse())
this.scene.arena.trySetWeather(WeatherType.NONE, false); this.scene.arena.trySetWeather(WeatherType.NONE, false);
@ -655,7 +684,7 @@ export abstract class MovePhase extends BattlePhase {
abstract getEffectPhase(): MoveEffectPhase; abstract getEffectPhase(): MoveEffectPhase;
canMove(): boolean { canMove(): boolean {
return !!this.pokemon.hp; return !!this.pokemon.hp && this.move.isUsable();
} }
cancel(): void { cancel(): void {
@ -665,6 +694,8 @@ export abstract class MovePhase extends BattlePhase {
start() { start() {
super.start(); super.start();
console.log(Moves[this.move.moveId]);
const target = this.pokemon.isPlayer() ? this.scene.getEnemyPokemon() : this.scene.getPlayerPokemon(); const target = this.pokemon.isPlayer() ? this.scene.getEnemyPokemon() : this.scene.getPlayerPokemon();
if (!this.followUp && this.canMove()) if (!this.followUp && this.canMove())
@ -685,7 +716,7 @@ export abstract class MovePhase extends BattlePhase {
if (!failed.value && this.scene.arena.isMoveWeatherCancelled(this.move.getMove())) if (!failed.value && this.scene.arena.isMoveWeatherCancelled(this.move.getMove()))
failed.value = true; failed.value = true;
if (failed.value) { if (failed.value) {
this.pokemon.summonData.moveHistory.push({ move: this.move.moveId, result: MoveResult.FAILED }); this.pokemon.summonData.moveHistory.push({ move: this.move.moveId, result: MoveResult.FAILED, virtual: this.move.virtual });
this.scene.unshiftPhase(new MessagePhase(this.scene, 'But it failed!')); this.scene.unshiftPhase(new MessagePhase(this.scene, 'But it failed!'));
} else } else
this.scene.unshiftPhase(this.getEffectPhase()); this.scene.unshiftPhase(this.getEffectPhase());
@ -694,6 +725,8 @@ export abstract class MovePhase extends BattlePhase {
}; };
if (!this.canMove()) { if (!this.canMove()) {
if (this.move.isDisabled())
this.scene.unshiftPhase(new MessagePhase(this.scene, `${this.move.getName()} is disabled!`));
this.end(); this.end();
return; return;
} }
@ -805,7 +838,7 @@ abstract class MoveEffectPhase extends PokemonPhase {
if (!this.hitCheck()) { if (!this.hitCheck()) {
this.scene.unshiftPhase(new MessagePhase(this.scene, getPokemonMessage(user, '\'s\nattack missed!'))); this.scene.unshiftPhase(new MessagePhase(this.scene, getPokemonMessage(user, '\'s\nattack missed!')));
user.summonData.moveHistory.push({ move: this.move.moveId, result: MoveResult.MISSED }); user.summonData.moveHistory.push({ move: this.move.moveId, result: MoveResult.MISSED, virtual: this.move.virtual });
applyMoveAttrs(MissEffectAttr, user, target, this.move.getMove()); applyMoveAttrs(MissEffectAttr, user, target, this.move.getMove());
this.end(); this.end();
return; return;
@ -816,7 +849,7 @@ abstract class MoveEffectPhase extends PokemonPhase {
new MoveAnim(this.move.getMove().id as Moves, user, target).play(this.scene, () => { new MoveAnim(this.move.getMove().id as Moves, user, target).play(this.scene, () => {
const result = !isProtected ? target.apply(user, this.move) : MoveResult.NO_EFFECT; const result = !isProtected ? target.apply(user, this.move) : MoveResult.NO_EFFECT;
++user.turnData.hitCount; ++user.turnData.hitCount;
user.summonData.moveHistory.push({ move: this.move.moveId, result: result }); user.summonData.moveHistory.push({ move: this.move.moveId, result: result, virtual: this.move.virtual });
applyMoveAttrs(MoveEffectAttr, user, target, this.move.getMove()); applyMoveAttrs(MoveEffectAttr, user, target, this.move.getMove());
// Charge attribute with charge effect takes all effect attributes and applies them to charge stage, so ignore them if this is present // Charge attribute with charge effect takes all effect attributes and applies them to charge stage, so ignore them if this is present
if (!isProtected && target.hp && !this.move.getMove().getAttrs(ChargeAttr).filter(ca => (ca as ChargeAttr).chargeEffect).length) if (!isProtected && target.hp && !this.move.getMove().getAttrs(ChargeAttr).filter(ca => (ca as ChargeAttr).chargeEffect).length)

View File

@ -10,13 +10,14 @@ import { PokeballType } from './pokeball';
import { Species } from './species'; import { Species } from './species';
import { initAutoPlay } from './auto-play'; import { initAutoPlay } from './auto-play';
import { Battle } from './battle'; import { Battle } from './battle';
import { initCommonAnims, loadCommonAnimAssets, populateAnims } from './battle-anims'; import { initCommonAnims, initMoveAnim, loadCommonAnimAssets, loadMoveAnimAssets, populateAnims } from './battle-anims';
import { BattlePhase } from './battle-phase'; import { BattlePhase } from './battle-phase';
import { initGameSpeed } from './game-speed'; import { initGameSpeed } from './game-speed';
import { Arena } from './arena'; import { Arena } from './arena';
import { GameData } from './game-data'; import { GameData } from './game-data';
import StarterSelectUiHandler from './ui/starter-select-ui-handler'; import StarterSelectUiHandler from './ui/starter-select-ui-handler';
import { TextStyle, addTextObject } from './text'; import { TextStyle, addTextObject } from './text';
import { Moves } from './move';
const enableAuto = true; const enableAuto = true;
export const startingLevel = 5; export const startingLevel = 5;
@ -363,7 +364,11 @@ export default class BattleScene extends Phaser.Scene {
ui.setup(); ui.setup();
Promise.all([ Promise.all(loadPokemonAssets), initCommonAnims().then(() => loadCommonAnimAssets(this, true)) ]).then(() => { Promise.all([
Promise.all(loadPokemonAssets),
initCommonAnims().then(() => loadCommonAnimAssets(this, true)),
initMoveAnim(Moves.STRUGGLE).then(() => loadMoveAnimAssets(this, [ Moves.STRUGGLE ], true))
]).then(() => {
if (enableAuto) if (enableAuto)
initAutoPlay.apply(this); initAutoPlay.apply(this);

View File

@ -1184,6 +1184,60 @@ export class MissEffectAttr extends MoveAttr {
} }
} }
export class DisableMoveAttr extends MoveEffectAttr {
constructor() {
super(false);
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.apply(user, target, move, args))
return false;
const moveQueue = target.getLastXMoves();
let turnMove: TurnMove;
while (moveQueue.length) {
turnMove = moveQueue.shift();
if (turnMove.virtual)
continue;
const moveIndex = target.moveset.findIndex(m => m.moveId === turnMove.move);
if (moveIndex === -1)
return false;
const disabledMove = target.moveset[moveIndex];
disabledMove.disableTurns = 4;
console.log(disabledMove);
user.scene.unshiftPhase(new MessagePhase(user.scene, getPokemonMessage(target, `'s ${disabledMove.getName()}\nwas disabled!`)))
return true;
}
return false;
}
}
export class DisableMoveConditionalMoveAttr extends ConditionalMoveAttr {
constructor() {
super((user: Pokemon, target: Pokemon, move: Move) => {
const moveQueue = target.getLastXMoves();
let turnMove: TurnMove;
while (moveQueue.length) {
turnMove = moveQueue.shift();
if (turnMove.virtual)
continue;
const move = target.moveset.find(m => m.moveId === turnMove.move);
if (!move)
continue;
return !move.isDisabled();
}
});
}
}
export class FrenzyAttr extends MoveEffectAttr { export class FrenzyAttr extends MoveEffectAttr {
constructor() { constructor() {
super(true); super(true);
@ -1302,16 +1356,12 @@ export class RandomMovesetMoveAttr extends OverrideMoveEffectAttr {
} }
export class RandomMoveAttr extends OverrideMoveEffectAttr { export class RandomMoveAttr extends OverrideMoveEffectAttr {
constructor() {
super();
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
return new Promise(resolve => { return new Promise(resolve => {
const moveIds = Utils.getEnumValues(Moves).filter(m => m !== move.id); const moveIds = Utils.getEnumValues(Moves).filter(m => m !== move.id);
const moveId = moveIds[Utils.randInt(moveIds.length)]; const moveId = moveIds[Utils.randInt(moveIds.length)];
user.summonData.moveQueue.push({ move: moveId, ignorePP: true }); user.summonData.moveQueue.push({ move: moveId, ignorePP: true });
user.scene.unshiftPhase(user.isPlayer() ? new PlayerMovePhase(user.scene, user as PlayerPokemon, new PokemonMove(moveId), true) : new EnemyMovePhase(user.scene, user as EnemyPokemon, new PokemonMove(moveId), true)); user.scene.unshiftPhase(user.isPlayer() ? new PlayerMovePhase(user.scene, user as PlayerPokemon, new PokemonMove(moveId, 0, 0, true), true) : new EnemyMovePhase(user.scene, user as EnemyPokemon, new PokemonMove(moveId, 0, 0, true), true));
initMoveAnim(moveId).then(() => { initMoveAnim(moveId).then(() => {
loadMoveAnimAssets(user.scene, [ moveId ], true) loadMoveAnimAssets(user.scene, [ moveId ], true)
.then(() => resolve(true)); .then(() => resolve(true));
@ -1374,7 +1424,7 @@ export const allMoves = [
new StatusMove(Moves.SING, "Sing", Type.NORMAL, 55, 15, -1, "Puts opponent to sleep.", -1, 0, 1, new StatusEffectAttr(StatusEffect.SLEEP)), new StatusMove(Moves.SING, "Sing", Type.NORMAL, 55, 15, -1, "Puts opponent to sleep.", -1, 0, 1, new StatusEffectAttr(StatusEffect.SLEEP)),
new StatusMove(Moves.SUPERSONIC, "Supersonic", Type.NORMAL, 55, 20, -1, "Confuses opponent.", -1, 0, 1, new ConfuseAttr()), new StatusMove(Moves.SUPERSONIC, "Supersonic", Type.NORMAL, 55, 20, -1, "Confuses opponent.", -1, 0, 1, new ConfuseAttr()),
new AttackMove(Moves.SONIC_BOOM, "Sonic Boom", Type.NORMAL, MoveCategory.SPECIAL, -1, 90, 20, -1, "Always inflicts 20 HP.", -1, 0, 1, new FixedDamageAttr(20)), new AttackMove(Moves.SONIC_BOOM, "Sonic Boom", Type.NORMAL, MoveCategory.SPECIAL, -1, 90, 20, -1, "Always inflicts 20 HP.", -1, 0, 1, new FixedDamageAttr(20)),
new StatusMove(Moves.DISABLE, "Disable", Type.NORMAL, 100, 20, -1, "Opponent can't use its last attack for a few turns.", -1, 0, 1), new StatusMove(Moves.DISABLE, "Disable", Type.NORMAL, 100, 20, -1, "Opponent can't use its last attack for a few turns.", -1, 0, 1, new DisableMoveConditionalMoveAttr(), new DisableMoveAttr()),
new AttackMove(Moves.ACID, "Acid", Type.POISON, MoveCategory.SPECIAL, 40, 100, 30, -1, "May lower opponent's Special Defense.", 10, 0, 1, new StatChangeAttr(BattleStat.SPDEF, -1)), new AttackMove(Moves.ACID, "Acid", Type.POISON, MoveCategory.SPECIAL, 40, 100, 30, -1, "May lower opponent's Special Defense.", 10, 0, 1, new StatChangeAttr(BattleStat.SPDEF, -1)),
new AttackMove(Moves.EMBER, "Ember", Type.FIRE, MoveCategory.SPECIAL, 40, 100, 25, -1, "May burn opponent.", 10, 0, 1, new StatusEffectAttr(StatusEffect.BURN)), new AttackMove(Moves.EMBER, "Ember", Type.FIRE, MoveCategory.SPECIAL, 40, 100, 25, -1, "May burn opponent.", 10, 0, 1, new StatusEffectAttr(StatusEffect.BURN)),
new AttackMove(Moves.FLAMETHROWER, "Flamethrower", Type.FIRE, MoveCategory.SPECIAL, 90, 100, 15, 125, "May burn opponent.", 10, 0, 1, new StatusEffectAttr(StatusEffect.BURN)), new AttackMove(Moves.FLAMETHROWER, "Flamethrower", Type.FIRE, MoveCategory.SPECIAL, 90, 100, 15, 125, "May burn opponent.", 10, 0, 1, new StatusEffectAttr(StatusEffect.BURN)),

View File

@ -874,8 +874,14 @@ export class EnemyPokemon extends Pokemon {
const queuedMove = this.summonData.moveQueue.length const queuedMove = this.summonData.moveQueue.length
? this.moveset.find(m => m.moveId === this.summonData.moveQueue[0].move) ? this.moveset.find(m => m.moveId === this.summonData.moveQueue[0].move)
: null; : null;
if (queuedMove && (this.summonData.moveQueue[0].ignorePP || queuedMove.isUsable())) if (queuedMove) {
return queuedMove; if (queuedMove.isUsable(this.summonData.moveQueue[0].ignorePP))
return queuedMove;
else {
this.summonData.moveQueue.shift();
return this.getNextMove();
}
}
const movePool = this.moveset.filter(m => m.isUsable()); const movePool = this.moveset.filter(m => m.isUsable());
if (movePool.length) { if (movePool.length) {
@ -949,6 +955,7 @@ export class EnemyPokemon extends Pokemon {
return sortedMovePool[r]; return sortedMovePool[r];
} }
} }
return new PokemonMove(Moves.STRUGGLE, 0, 0); return new PokemonMove(Moves.STRUGGLE, 0, 0);
} }
@ -973,6 +980,7 @@ export class EnemyPokemon extends Pokemon {
export interface TurnMove { export interface TurnMove {
move: Moves; move: Moves;
result: MoveResult; result: MoveResult;
virtual?: boolean;
} }
export interface QueuedMove { export interface QueuedMove {
@ -1022,19 +1030,25 @@ export class PokemonMove {
public moveId: Moves; public moveId: Moves;
public ppUsed: integer; public ppUsed: integer;
public ppUp: integer; public ppUp: integer;
public virtual: boolean;
public disableTurns: integer; public disableTurns: integer;
constructor(moveId: Moves, ppUsed?: integer, ppUp?: integer) { constructor(moveId: Moves, ppUsed?: integer, ppUp?: integer, virtual?: boolean) {
this.moveId = moveId; this.moveId = moveId;
this.ppUsed = ppUsed || 0; this.ppUsed = ppUsed || 0;
this.ppUp = ppUp || 0; this.ppUp = ppUp || 0;
this.virtual = !!virtual;
this.disableTurns = 0; this.disableTurns = 0;
} }
isUsable(): boolean { isUsable(ignorePp?: boolean): boolean {
if (this.disableTurns > 0) if (this.isDisabled())
return false; return false;
return this.ppUsed < this.getMove().pp + this.ppUp; return ignorePp || this.ppUsed < this.getMove().pp + this.ppUp || this.getMove().pp === -1;
}
isDisabled(): boolean {
return !!this.disableTurns;
} }
getMove(): Move { getMove(): Move {