Add move priority, flinching, and fixed damage
This commit is contained in:
parent
656b6951b6
commit
0e9710d45c
|
@ -1,7 +1,7 @@
|
||||||
import BattleScene from "./battle-scene";
|
import BattleScene from "./battle-scene";
|
||||||
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult } from "./pokemon";
|
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult } from "./pokemon";
|
||||||
import * as Utils from './utils';
|
import * as Utils from './utils';
|
||||||
import { allMoves, applyMoveAttrs, ChargeAttr, HitsTagAttr, MissEffectAttr, MoveCategory, MoveEffectAttr, MoveHitEffectAttr, Moves, MultiHitAttr, OverrideMoveEffectAttr } from "./move";
|
import { allMoves, applyMoveAttrs, ChargeAttr, ConditionalFailMoveAttr, HitsTagAttr, MissEffectAttr, MoveCategory, MoveEffectAttr, MoveHitEffectAttr, Moves, MultiHitAttr, OverrideMoveEffectAttr } from "./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 "./pokemon-stat";
|
import { Stat } from "./pokemon-stat";
|
||||||
|
@ -440,12 +440,31 @@ export class CommandPhase extends BattlePhase {
|
||||||
const playerSpeed = playerPokemon.getBattleStat(Stat.SPD);
|
const playerSpeed = playerPokemon.getBattleStat(Stat.SPD);
|
||||||
const enemySpeed = enemyPokemon.getBattleStat(Stat.SPD);
|
const enemySpeed = enemyPokemon.getBattleStat(Stat.SPD);
|
||||||
|
|
||||||
const isDelayed = () => playerSpeed < enemySpeed || (playerSpeed === enemySpeed && Utils.randInt(2) === 1);
|
let isDelayed = (command: Command, playerMove: PokemonMove, enemyMove: PokemonMove) => {
|
||||||
|
switch (command) {
|
||||||
|
case Command.FIGHT:
|
||||||
|
const playerMovePriority = playerMove.getMove().priority;
|
||||||
|
const enemyMovePriority = enemyMove.getMove().priority;
|
||||||
|
if (playerMovePriority !== enemyMovePriority)
|
||||||
|
return playerMovePriority < enemyMovePriority;
|
||||||
|
break;
|
||||||
|
case Command.BALL:
|
||||||
|
case Command.POKEMON:
|
||||||
|
return false;
|
||||||
|
case Command.RUN:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return playerSpeed < enemySpeed || (playerSpeed === enemySpeed && Utils.randInt(2) === 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
let playerMove: PokemonMove;
|
||||||
|
|
||||||
switch (command) {
|
switch (command) {
|
||||||
case Command.FIGHT:
|
case Command.FIGHT:
|
||||||
if (playerPokemon.trySelectMove(cursor)) {
|
if (playerPokemon.trySelectMove(cursor)) {
|
||||||
const playerPhase = new PlayerMovePhase(this.scene, playerPokemon, playerPokemon.moveset[cursor]);
|
playerMove = playerPokemon.moveset[cursor];
|
||||||
|
const playerPhase = new PlayerMovePhase(this.scene, playerPokemon, playerMove);
|
||||||
this.scene.pushPhase(playerPhase);
|
this.scene.pushPhase(playerPhase);
|
||||||
success = true;
|
success = true;
|
||||||
}
|
}
|
||||||
|
@ -469,7 +488,7 @@ export class CommandPhase extends BattlePhase {
|
||||||
if (success) {
|
if (success) {
|
||||||
const enemyMove = enemyPokemon.getNextMove();
|
const enemyMove = enemyPokemon.getNextMove();
|
||||||
const enemyPhase = new EnemyMovePhase(this.scene, enemyPokemon, enemyMove);
|
const enemyPhase = new EnemyMovePhase(this.scene, enemyPokemon, enemyMove);
|
||||||
if (isDelayed())
|
if (isDelayed(command, playerMove, enemyMove))
|
||||||
this.scene.unshiftPhase(enemyPhase);
|
this.scene.unshiftPhase(enemyPhase);
|
||||||
else
|
else
|
||||||
this.scene.pushPhase(enemyPhase);
|
this.scene.pushPhase(enemyPhase);
|
||||||
|
@ -479,7 +498,7 @@ export class CommandPhase extends BattlePhase {
|
||||||
statusEffectPhases.push(new PostTurnStatusEffectPhase(this.scene, true));
|
statusEffectPhases.push(new PostTurnStatusEffectPhase(this.scene, true));
|
||||||
if (enemyPokemon.status && enemyPokemon.status.isPostTurn()) {
|
if (enemyPokemon.status && enemyPokemon.status.isPostTurn()) {
|
||||||
const enemyStatusEffectPhase = new PostTurnStatusEffectPhase(this.scene, false);
|
const enemyStatusEffectPhase = new PostTurnStatusEffectPhase(this.scene, false);
|
||||||
if (isDelayed())
|
if (isDelayed(command, playerMove, enemyMove))
|
||||||
statusEffectPhases.unshift(enemyStatusEffectPhase);
|
statusEffectPhases.unshift(enemyStatusEffectPhase);
|
||||||
else
|
else
|
||||||
statusEffectPhases.push(enemyStatusEffectPhase);
|
statusEffectPhases.push(enemyStatusEffectPhase);
|
||||||
|
@ -506,8 +525,14 @@ export class TurnEndPhase extends BattlePhase {
|
||||||
}
|
}
|
||||||
|
|
||||||
start() {
|
start() {
|
||||||
this.scene.getPlayerPokemon().lapseTags(BattleTagLapseType.TURN_END);
|
const playerPokemon = this.scene.getPlayerPokemon();
|
||||||
this.scene.getEnemyPokemon().lapseTags(BattleTagLapseType.TURN_END);
|
const enemyPokemon = this.scene.getEnemyPokemon();
|
||||||
|
|
||||||
|
playerPokemon.lapseTags(BattleTagLapseType.TURN_END);
|
||||||
|
enemyPokemon.lapseTags(BattleTagLapseType.TURN_END);
|
||||||
|
|
||||||
|
playerPokemon.battleSummonData.turnCount++;
|
||||||
|
enemyPokemon.battleSummonData.turnCount++;
|
||||||
|
|
||||||
this.end();
|
this.end();
|
||||||
}
|
}
|
||||||
|
@ -591,9 +616,17 @@ export abstract class MovePhase extends BattlePhase {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.scene.unshiftPhase(new MessagePhase(this.scene, getPokemonMessage(this.pokemon, ` used\n${this.move.getName()}!`), 500));
|
this.scene.unshiftPhase(new MessagePhase(this.scene, getPokemonMessage(this.pokemon, ` used\n${this.move.getName()}!`), 500));
|
||||||
this.scene.unshiftPhase(this.getEffectPhase());
|
|
||||||
if (this.pokemon.summonData.moveQueue.length && !this.pokemon.summonData.moveQueue.shift().ignorePP)
|
if (this.pokemon.summonData.moveQueue.length && !this.pokemon.summonData.moveQueue.shift().ignorePP)
|
||||||
this.move.ppUsed++;
|
this.move.ppUsed++;
|
||||||
|
|
||||||
|
const failed = new Utils.BooleanHolder(false);
|
||||||
|
applyMoveAttrs(ConditionalFailMoveAttr, this.scene, this.pokemon,
|
||||||
|
this.pokemon.isPlayer() ? this.scene.getEnemyPokemon() : this.scene.getPlayerPokemon(), this.move.getMove(), failed);
|
||||||
|
if (failed.value)
|
||||||
|
this.scene.unshiftPhase(new MessagePhase(this.scene, 'But it failed!'));
|
||||||
|
else
|
||||||
|
this.scene.unshiftPhase(this.getEffectPhase());
|
||||||
|
|
||||||
this.end();
|
this.end();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import * as Utils from "./utils";
|
||||||
|
|
||||||
export enum BattleTagType {
|
export enum BattleTagType {
|
||||||
NONE,
|
NONE,
|
||||||
|
FLINCHED,
|
||||||
CONFUSED,
|
CONFUSED,
|
||||||
FRENZY,
|
FRENZY,
|
||||||
FLYING,
|
FLYING,
|
||||||
|
@ -39,7 +40,22 @@ export class BattleTag {
|
||||||
onOverlap(pokemon: Pokemon): void { }
|
onOverlap(pokemon: Pokemon): void { }
|
||||||
|
|
||||||
lapse(pokemon: Pokemon): boolean {
|
lapse(pokemon: Pokemon): boolean {
|
||||||
return !!--this.turnCount;
|
return --this.turnCount > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class FlinchedTag extends BattleTag {
|
||||||
|
constructor() {
|
||||||
|
super(BattleTagType.FLINCHED, BattleTagLapseType.MOVE, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
lapse(pokemon: Pokemon): boolean {
|
||||||
|
super.lapse(pokemon);
|
||||||
|
|
||||||
|
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
|
||||||
|
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' flinched!')));
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,6 +134,9 @@ export class HideSpriteTag extends BattleTag {
|
||||||
|
|
||||||
export function getBattleTag(tagType: BattleTagType, turnCount: integer): BattleTag {
|
export function getBattleTag(tagType: BattleTagType, turnCount: integer): BattleTag {
|
||||||
switch (tagType) {
|
switch (tagType) {
|
||||||
|
case BattleTagType.FLINCHED:
|
||||||
|
return new FlinchedTag();
|
||||||
|
break;
|
||||||
case BattleTagType.CONFUSED:
|
case BattleTagType.CONFUSED:
|
||||||
return new ConfusedTag(tagType, turnCount);
|
return new ConfusedTag(tagType, turnCount);
|
||||||
case BattleTagType.FLYING:
|
case BattleTagType.FLYING:
|
||||||
|
|
1193
src/move.ts
1193
src/move.ts
File diff suppressed because it is too large
Load Diff
|
@ -1,7 +1,7 @@
|
||||||
import Phaser from 'phaser';
|
import Phaser from 'phaser';
|
||||||
import BattleScene from './battle-scene';
|
import BattleScene from './battle-scene';
|
||||||
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from './battle-info';
|
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from './battle-info';
|
||||||
import { default as Move, allMoves, MoveCategory, Moves, StatChangeAttr, HighCritAttr, HitsTagAttr, applyMoveAttrs } from './move';
|
import { default as Move, allMoves, MoveCategory, Moves, StatChangeAttr, HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr } from './move';
|
||||||
import { pokemonLevelMoves } from './pokemon-level-moves';
|
import { pokemonLevelMoves } from './pokemon-level-moves';
|
||||||
import { default as PokemonSpecies, getPokemonSpecies } from './pokemon-species';
|
import { default as PokemonSpecies, getPokemonSpecies } from './pokemon-species';
|
||||||
import * as Utils from './utils';
|
import * as Utils from './utils';
|
||||||
|
@ -412,7 +412,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(source: Pokemon, battlerMove: PokemonMove): MoveResult {
|
apply(source: Pokemon, battlerMove: PokemonMove): MoveResult {
|
||||||
let result: MoveResult = MoveResult.STATUS;
|
let result: MoveResult;
|
||||||
let success = false;
|
let success = false;
|
||||||
const move = battlerMove.getMove();
|
const move = battlerMove.getMove();
|
||||||
const moveCategory = move.category;
|
const moveCategory = move.category;
|
||||||
|
@ -422,6 +422,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
case MoveCategory.SPECIAL:
|
case MoveCategory.SPECIAL:
|
||||||
const isPhysical = moveCategory === MoveCategory.PHYSICAL;
|
const isPhysical = moveCategory === MoveCategory.PHYSICAL;
|
||||||
const power = new Utils.NumberHolder(move.power);
|
const power = new Utils.NumberHolder(move.power);
|
||||||
|
const typeMultiplier = getTypeDamageMultiplier(move.type, this.species.type1) * (this.species.type2 > -1 ? getTypeDamageMultiplier(move.type, this.species.type2) : 1);
|
||||||
this.scene.applyModifiers(AttackTypeBoosterModifier, source, power);
|
this.scene.applyModifiers(AttackTypeBoosterModifier, source, power);
|
||||||
const critChance = new Utils.IntegerHolder(16);
|
const critChance = new Utils.IntegerHolder(16);
|
||||||
applyMoveAttrs(HighCritAttr, this.scene, source, this, move, critChance);
|
applyMoveAttrs(HighCritAttr, this.scene, source, this, move, critChance);
|
||||||
|
@ -429,7 +430,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
const sourceAtk = source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK);
|
const sourceAtk = source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK);
|
||||||
const targetDef = this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF);
|
const targetDef = this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF);
|
||||||
const stabMultiplier = source.species.type1 === move.type || (source.species.type2 > -1 && source.species.type2 === move.type) ? 1.5 : 1;
|
const stabMultiplier = source.species.type1 === move.type || (source.species.type2 > -1 && source.species.type2 === move.type) ? 1.5 : 1;
|
||||||
const typeMultiplier = getTypeDamageMultiplier(move.type, this.species.type1) * (this.species.type2 > -1 ? getTypeDamageMultiplier(move.type, this.species.type2) : 1);
|
|
||||||
const criticalMultiplier = isCritical ? 2 : 1;
|
const criticalMultiplier = isCritical ? 2 : 1;
|
||||||
damage = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk / targetDef) / 50) + 2) * stabMultiplier * typeMultiplier * ((Utils.randInt(15) + 85) / 100)) * criticalMultiplier;
|
damage = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk / targetDef) / 50) + 2) * stabMultiplier * typeMultiplier * ((Utils.randInt(15) + 85) / 100)) * criticalMultiplier;
|
||||||
if (isPhysical && source.status && source.status.effect === StatusEffect.BURN)
|
if (isPhysical && source.status && source.status.effect === StatusEffect.BURN)
|
||||||
|
@ -438,18 +438,26 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
if (this.getTag(hta.tagType))
|
if (this.getTag(hta.tagType))
|
||||||
damage *= 2;
|
damage *= 2;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const fixedDamage = new Utils.IntegerHolder(0);
|
||||||
|
applyMoveAttrs(FixedDamageAttr, this.scene, source, this, move, fixedDamage);
|
||||||
|
if (damage && fixedDamage.value) {
|
||||||
|
damage = fixedDamage.value;
|
||||||
|
result = MoveResult.EFFECTIVE;
|
||||||
|
}
|
||||||
|
|
||||||
console.log('damage', damage, move.name, move.power, sourceAtk, targetDef);
|
console.log('damage', damage, move.name, move.power, sourceAtk, targetDef);
|
||||||
|
|
||||||
if (typeMultiplier >= 2)
|
if (!result) {
|
||||||
result = MoveResult.SUPER_EFFECTIVE;
|
if (typeMultiplier >= 2)
|
||||||
else if (typeMultiplier >= 1)
|
result = MoveResult.SUPER_EFFECTIVE;
|
||||||
result = MoveResult.EFFECTIVE;
|
else if (typeMultiplier >= 1)
|
||||||
else if (typeMultiplier > 0)
|
result = MoveResult.EFFECTIVE;
|
||||||
result = MoveResult.NOT_VERY_EFFECTIVE;
|
else if (typeMultiplier > 0)
|
||||||
else
|
result = MoveResult.NOT_VERY_EFFECTIVE;
|
||||||
result = MoveResult.NO_EFFECT;
|
else
|
||||||
|
result = MoveResult.NO_EFFECT;
|
||||||
|
}
|
||||||
|
|
||||||
if (damage) {
|
if (damage) {
|
||||||
this.hp = Math.max(this.hp - damage, 0);
|
this.hp = Math.max(this.hp - damage, 0);
|
||||||
|
@ -493,7 +501,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newTag = getBattleTag(tagType, turnCount || 1);
|
const newTag = getBattleTag(tagType, turnCount || 0);
|
||||||
this.summonData.tags.push(newTag);
|
this.summonData.tags.push(newTag);
|
||||||
newTag.onAdd(this);
|
newTag.onAdd(this);
|
||||||
}
|
}
|
||||||
|
@ -529,7 +537,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
|
|
||||||
lapseTags(lapseType: BattleTagLapseType): void {
|
lapseTags(lapseType: BattleTagLapseType): void {
|
||||||
const tags = this.summonData.tags;
|
const tags = this.summonData.tags;
|
||||||
tags.filter(t => lapseType === BattleTagLapseType.FAINT || ((t.lapseType === lapseType) && !(t.lapse(this)))).forEach(t => {
|
tags.filter(t => lapseType === BattleTagLapseType.FAINT || ((t.lapseType === lapseType) && !(t.lapse(this))) || (lapseType === BattleTagLapseType.TURN_END && t.turnCount < 1)).forEach(t => {
|
||||||
t.onRemove(this);
|
t.onRemove(this);
|
||||||
tags.splice(tags.indexOf(t), 1);
|
tags.splice(tags.indexOf(t), 1);
|
||||||
});
|
});
|
||||||
|
@ -910,7 +918,7 @@ export class PokemonSummonData {
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PokemonBattleSummonData {
|
export class PokemonBattleSummonData {
|
||||||
public infatuated: boolean;
|
public turnCount: integer = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PokemonTurnData {
|
export class PokemonTurnData {
|
||||||
|
@ -928,7 +936,7 @@ export enum AiType {
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum MoveResult {
|
export enum MoveResult {
|
||||||
EFFECTIVE,
|
EFFECTIVE = 1,
|
||||||
SUPER_EFFECTIVE,
|
SUPER_EFFECTIVE,
|
||||||
NOT_VERY_EFFECTIVE,
|
NOT_VERY_EFFECTIVE,
|
||||||
NO_EFFECT,
|
NO_EFFECT,
|
||||||
|
|
Loading…
Reference in New Issue