Factor type immunity abilities into enemy AI
parent
be405f61dd
commit
fdff3a549c
|
@ -100,7 +100,7 @@ export default class Battle {
|
|||
|
||||
randSeedGaussForLevel(value: number): number {
|
||||
let rand = 0;
|
||||
for (var i = value; i > 0; i--)
|
||||
for (let i = value; i > 0; i--)
|
||||
rand += Phaser.Math.RND.realInRange(0, 1);
|
||||
return rand / value;
|
||||
}
|
||||
|
|
|
@ -213,9 +213,13 @@ export class TypeImmunityHealAbAttr extends TypeImmunityAbAttr {
|
|||
const ret = super.applyPreDefend(pokemon, attacker, move, cancelled, args);
|
||||
|
||||
if (ret) {
|
||||
if (pokemon.getHpRatio() < 1)
|
||||
if (pokemon.getHpRatio() < 1) {
|
||||
const simulated = args.length > 1 && args[1];
|
||||
if (!simulated) {
|
||||
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(),
|
||||
Math.max(Math.floor(pokemon.getMaxHp() / 4), 1), getPokemonMessage(pokemon, `'s ${pokemon.getAbility().name}\nrestored its HP a little!`), true));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -239,6 +243,8 @@ class TypeImmunityStatChangeAbAttr extends TypeImmunityAbAttr {
|
|||
|
||||
if (ret) {
|
||||
cancelled.value = true;
|
||||
const simulated = args.length > 1 && args[1];
|
||||
if (!simulated)
|
||||
pokemon.scene.unshiftPhase(new StatChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ this.stat ], this.levels));
|
||||
}
|
||||
|
||||
|
@ -262,6 +268,8 @@ class TypeImmunityAddBattlerTagAbAttr extends TypeImmunityAbAttr {
|
|||
|
||||
if (ret) {
|
||||
cancelled.value = true;
|
||||
const simulated = args.length > 1 && args[1];
|
||||
if (!simulated)
|
||||
pokemon.addTag(this.tagType, this.turnCount, undefined, pokemon.id);
|
||||
}
|
||||
|
||||
|
@ -275,7 +283,7 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr {
|
|||
}
|
||||
|
||||
applyPreDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||
if (pokemon.getAttackMoveEffectiveness(move.getMove().type) < 2) {
|
||||
if (pokemon.getAttackTypeEffectiveness(move.getMove().type) < 2) {
|
||||
cancelled.value = true;
|
||||
(args[0] as Utils.NumberHolder).value = 0;
|
||||
return true;
|
||||
|
@ -1103,7 +1111,7 @@ export class SyncEncounterNatureAbAttr extends AbAttr {
|
|||
}
|
||||
|
||||
function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any[]): TAttr },
|
||||
pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, isAsync?: boolean, showAbilityInstant?: boolean): Promise<void> {
|
||||
pokemon: Pokemon, applyFunc: AbAttrApplyFunc<TAttr>, isAsync: boolean = false, showAbilityInstant: boolean = false, quiet: boolean = false): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
if (!pokemon.canApplyAbility())
|
||||
return resolve();
|
||||
|
@ -1126,12 +1134,13 @@ function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any
|
|||
return applyNextAbAttr();
|
||||
pokemon.scene.setPhaseQueueSplice();
|
||||
const onApplySuccess = () => {
|
||||
if (attr.showAbility) {
|
||||
if (attr.showAbility && !quiet) {
|
||||
if (showAbilityInstant)
|
||||
pokemon.scene.abilityBar.showAbility(pokemon);
|
||||
else
|
||||
queueShowAbility(pokemon);
|
||||
}
|
||||
if (!quiet) {
|
||||
const message = attr.getTriggerMessage(pokemon);
|
||||
if (message) {
|
||||
if (isAsync)
|
||||
|
@ -1139,6 +1148,7 @@ function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any
|
|||
else
|
||||
pokemon.scene.queueMessage(message);
|
||||
}
|
||||
}
|
||||
};
|
||||
const result = applyFunc(attr);
|
||||
if (result instanceof Promise) {
|
||||
|
@ -1163,7 +1173,8 @@ export function applyAbAttrs(attrType: { new(...args: any[]): AbAttr }, pokemon:
|
|||
|
||||
export function applyPreDefendAbAttrs(attrType: { new(...args: any[]): PreDefendAbAttr },
|
||||
pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||
return applyAbAttrsInternal<PreDefendAbAttr>(attrType, pokemon, attr => attr.applyPreDefend(pokemon, attacker, move, cancelled, args));
|
||||
const simulated = args.length > 1 && args[1];
|
||||
return applyAbAttrsInternal<PreDefendAbAttr>(attrType, pokemon, attr => attr.applyPreDefend(pokemon, attacker, move, cancelled, args), false, false, simulated);
|
||||
}
|
||||
|
||||
export function applyPostDefendAbAttrs(attrType: { new(...args: any[]): PostDefendAbAttr },
|
||||
|
@ -1928,7 +1939,7 @@ export function initAbilities() {
|
|||
new Ability(Abilities.SHADOW_SHIELD, "Shadow Shield (N)", "Reduces the amount of damage the Pokémon takes while its HP is full.", 7),
|
||||
new Ability(Abilities.PRISM_ARMOR, "Prism Armor (N)", "Reduces the power of supereffective attacks taken.", 7),
|
||||
new Ability(Abilities.NEUROFORCE, "Neuroforce", "Powers up moves that are super effective.", 7)
|
||||
.attr(MovePowerBoostAbAttr, (user, target, move) => target.getAttackMoveEffectiveness(move.type) >= 2, 1.25),
|
||||
.attr(MovePowerBoostAbAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type) >= 2, 1.25),
|
||||
new Ability(Abilities.INTREPID_SWORD, "Intrepid Sword (N)", "Boosts the Pokémon's Attack stat when the Pokémon enters a battle.", 8),
|
||||
new Ability(Abilities.DAUNTLESS_SHIELD, "Dauntless Shield (N)", "Boosts the Pokémon's Defense stat when the Pokémon enters a battle.", 8),
|
||||
new Ability(Abilities.LIBERO, "Libero (N)", "Changes the Pokémon's type to the type of the move it's about to use.", 8),
|
||||
|
|
|
@ -240,7 +240,7 @@ class StealthRockTag extends ArenaTrapTag {
|
|||
}
|
||||
|
||||
activateTrap(pokemon: Pokemon): boolean {
|
||||
const effectiveness = pokemon.getAttackMoveEffectiveness(Type.ROCK);
|
||||
const effectiveness = pokemon.getAttackTypeEffectiveness(Type.ROCK);
|
||||
|
||||
let damageHpRatio: number;
|
||||
|
||||
|
|
|
@ -282,7 +282,7 @@ export class AttackMove extends Move {
|
|||
|
||||
let attackScore = 0;
|
||||
|
||||
const effectiveness = target.getAttackMoveEffectiveness(this.type);
|
||||
const effectiveness = target.getAttackTypeEffectiveness(this.type);
|
||||
attackScore = Math.pow(effectiveness - 1, 2) * effectiveness < 1 ? -2 : 2;
|
||||
if (attackScore) {
|
||||
if (this.category === MoveCategory.PHYSICAL) {
|
||||
|
@ -770,7 +770,7 @@ export class StatusEffectAttr extends MoveEffectAttr {
|
|||
}
|
||||
|
||||
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
||||
return !(this.selfTarget ? user : target).status && target.getAttackMoveEffectiveness(move.type) ? Math.floor(move.chance * -0.1) : 0;
|
||||
return !(this.selfTarget ? user : target).status && target.getAttackTypeEffectiveness(move.type) ? Math.floor(move.chance * -0.1) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import Phaser from 'phaser';
|
|||
import BattleScene, { AnySound } from './battle-scene';
|
||||
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from './ui/battle-info';
|
||||
import { Moves } from "./data/enums/moves";
|
||||
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusEffectAttr } from "./data/move";
|
||||
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusEffectAttr, AttackMove } from "./data/move";
|
||||
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies } from './data/pokemon-species';
|
||||
import * as Utils from './utils';
|
||||
import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from './data/type';
|
||||
|
@ -707,7 +707,18 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
return this.getTeraType() !== Type.UNKNOWN;
|
||||
}
|
||||
|
||||
getAttackMoveEffectiveness(moveType: Type): TypeDamageMultiplier {
|
||||
getAttackMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier {
|
||||
const typeless = !!move.getMove().getAttrs(TypelessAttr).length;
|
||||
const typeMultiplier = new Utils.NumberHolder(this.getAttackTypeEffectiveness(move.getMove().type));
|
||||
const cancelled = new Utils.BooleanHolder(false);
|
||||
if (!typeless)
|
||||
applyPreDefendAbAttrs(TypeImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true);
|
||||
if (!cancelled.value)
|
||||
applyPreDefendAbAttrs(MoveImmunityAbAttr, this, source, move, cancelled, typeMultiplier, true);
|
||||
return (!cancelled.value ? typeMultiplier.value : 0) as TypeDamageMultiplier;
|
||||
}
|
||||
|
||||
getAttackTypeEffectiveness(moveType: Type): TypeDamageMultiplier {
|
||||
if (moveType === Type.STELLAR)
|
||||
return this.isTerastallized() ? 2 : 1;
|
||||
const types = this.getTypes(true);
|
||||
|
@ -718,12 +729,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
|||
const types = this.getTypes(true);
|
||||
const enemyTypes = pokemon.getTypes(true);
|
||||
const outspeed = (this.isActive(true) ? this.getBattleStat(Stat.SPD, pokemon) : this.getStat(Stat.SPD)) <= pokemon.getBattleStat(Stat.SPD, this);
|
||||
let atkScore = pokemon.getAttackMoveEffectiveness(types[0]) * (outspeed ? 1.25 : 1);
|
||||
let defScore = 1 / Math.max(this.getAttackMoveEffectiveness(enemyTypes[0]), 0.25);
|
||||
let atkScore = pokemon.getAttackTypeEffectiveness(types[0]) * (outspeed ? 1.25 : 1);
|
||||
let defScore = 1 / Math.max(this.getAttackTypeEffectiveness(enemyTypes[0]), 0.25);
|
||||
if (types.length > 1)
|
||||
atkScore *= pokemon.getAttackMoveEffectiveness(types[1]);
|
||||
atkScore *= pokemon.getAttackTypeEffectiveness(types[1]);
|
||||
if (enemyTypes.length > 1)
|
||||
defScore *= (1 / this.getAttackMoveEffectiveness(enemyTypes[1]));
|
||||
defScore *= (1 / this.getAttackTypeEffectiveness(enemyTypes[1]));
|
||||
let hpDiffRatio = this.getHpRatio() + (1 - pokemon.getHpRatio());
|
||||
if (outspeed)
|
||||
hpDiffRatio = Math.min(hpDiffRatio * 1.5, 1);
|
||||
|
@ -2204,7 +2215,7 @@ export class EnemyPokemon extends Pokemon {
|
|||
const target = this.scene.getField()[mt];
|
||||
let targetScore = move.getUserBenefitScore(this, target, move) + move.getTargetBenefitScore(this, target, move) * (mt < BattlerIndex.ENEMY === this.isPlayer() ? 1 : -1);
|
||||
if (mt !== this.getBattlerIndex())
|
||||
targetScore *= target.getAttackMoveEffectiveness(move.type);
|
||||
targetScore *= target.getAttackMoveEffectiveness(this, pokemonMove);
|
||||
targetScores.push(targetScore);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
import { BattlerIndex } from "../battle";
|
||||
import BattleScene, { Button } from "../battle-scene";
|
||||
import { Moves, getMoveTargets } from "../data/move";
|
||||
import { Moves } from "../data/enums/moves";
|
||||
import { Mode } from "./ui";
|
||||
import UiHandler from "./ui-handler";
|
||||
import * as Utils from "../utils";
|
||||
import { getMoveTargets } from "../data/move";
|
||||
|
||||
export type TargetSelectCallback = (cursor: integer) => void;
|
||||
|
||||
|
|
Loading…
Reference in New Issue