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();
this.scene.getEnemyPokemon().resetTurnData();
if (playerPokemon.summonData.moveQueue.length)
this.handleCommand(Command.FIGHT, playerPokemon.moveset.findIndex(m => m.moveId === playerPokemon.summonData.moveQueue[0].move));
else
while (playerPokemon.summonData.moveQueue.length && playerPokemon.summonData.moveQueue[0]
&& !playerPokemon.moveset[playerPokemon.moveset.findIndex(m => m.moveId === playerPokemon.summonData.moveQueue[0].move)]
.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);
}
@ -492,7 +500,12 @@ export class CommandPhase extends BattlePhase {
const playerPhase = new PlayerMovePhase(this.scene, playerPokemon, playerMove);
this.scene.pushPhase(playerPhase);
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;
case Command.BALL:
if (cursor < 4) {
@ -557,16 +570,32 @@ export class TurnEndPhase extends BattlePhase {
const playerPokemon = this.scene.getPlayerPokemon();
const enemyPokemon = this.scene.getEnemyPokemon();
const handlePokemon = (pokemon: Pokemon) => {
if (!pokemon)
return;
if (playerPokemon) {
playerPokemon.lapseTags(BattleTagLapseType.TURN_END);
playerPokemon.battleSummonData.turnCount++;
}
pokemon.lapseTags(BattleTagLapseType.TURN_END);
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) {
enemyPokemon.lapseTags(BattleTagLapseType.TURN_END);
enemyPokemon.battleSummonData.turnCount++;
}
pokemon.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())
this.scene.arena.trySetWeather(WeatherType.NONE, false);
@ -655,7 +684,7 @@ export abstract class MovePhase extends BattlePhase {
abstract getEffectPhase(): MoveEffectPhase;
canMove(): boolean {
return !!this.pokemon.hp;
return !!this.pokemon.hp && this.move.isUsable();
}
cancel(): void {
@ -665,6 +694,8 @@ export abstract class MovePhase extends BattlePhase {
start() {
super.start();
console.log(Moves[this.move.moveId]);
const target = this.pokemon.isPlayer() ? this.scene.getEnemyPokemon() : this.scene.getPlayerPokemon();
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()))
failed.value = true;
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!'));
} else
this.scene.unshiftPhase(this.getEffectPhase());
@ -694,6 +725,8 @@ export abstract class MovePhase extends BattlePhase {
};
if (!this.canMove()) {
if (this.move.isDisabled())
this.scene.unshiftPhase(new MessagePhase(this.scene, `${this.move.getName()} is disabled!`));
this.end();
return;
}
@ -805,7 +838,7 @@ abstract class MoveEffectPhase extends PokemonPhase {
if (!this.hitCheck()) {
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());
this.end();
return;
@ -816,7 +849,7 @@ abstract class MoveEffectPhase extends PokemonPhase {
new MoveAnim(this.move.getMove().id as Moves, user, target).play(this.scene, () => {
const result = !isProtected ? target.apply(user, this.move) : MoveResult.NO_EFFECT;
++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());
// 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)

View File

@ -10,13 +10,14 @@ import { PokeballType } from './pokeball';
import { Species } from './species';
import { initAutoPlay } from './auto-play';
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 { initGameSpeed } from './game-speed';
import { Arena } from './arena';
import { GameData } from './game-data';
import StarterSelectUiHandler from './ui/starter-select-ui-handler';
import { TextStyle, addTextObject } from './text';
import { Moves } from './move';
const enableAuto = true;
export const startingLevel = 5;
@ -363,7 +364,11 @@ export default class BattleScene extends Phaser.Scene {
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)
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 {
constructor() {
super(true);
@ -1302,16 +1356,12 @@ export class RandomMovesetMoveAttr extends OverrideMoveEffectAttr {
}
export class RandomMoveAttr extends OverrideMoveEffectAttr {
constructor() {
super();
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
return new Promise(resolve => {
const moveIds = Utils.getEnumValues(Moves).filter(m => m !== move.id);
const moveId = moveIds[Utils.randInt(moveIds.length)];
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(() => {
loadMoveAnimAssets(user.scene, [ moveId ], 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.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 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.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)),

View File

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