Add logic for disable move
parent
da0d607f26
commit
52a28ed95a
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
62
src/move.ts
62
src/move.ts
|
@ -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)),
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in New Issue