Add enemy buffs to balance endless mode

pull/2/head
Flashfyre 2023-10-29 16:05:17 -04:00
parent cb62d79280
commit 5567b39f20
7 changed files with 214 additions and 67 deletions

View File

@ -5,7 +5,7 @@ import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMov
import { Mode } from './ui/ui';
import { Command } from "./ui/command-ui-handler";
import { Stat } from "./data/pokemon-stat";
import { BerryModifier, ContactHeldItemTransferChanceModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, MultipleParticipantExpBonusModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier } from "./modifier/modifier";
import { BerryModifier, ContactHeldItemTransferChanceModifier, EnemyAttackStatusEffectChanceModifier, EnemyInstantReviveChanceModifier, ExpBalanceModifier, ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, FlinchChanceModifier, HealingBoosterModifier, HitHealModifier, LapsingPersistentModifier, MapModifier, Modifier, MultipleParticipantExpBonusModifier, PersistentModifier, PokemonExpBoosterModifier, PokemonHeldItemModifier, PokemonInstantReviveModifier, SwitchEffectTransferModifier, TempBattleStatBoosterModifier, TurnHealModifier, TurnHeldItemTransferModifier } from "./modifier/modifier";
import PartyUiHandler, { PartyOption, PartyUiMode } from "./ui/party-ui-handler";
import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor, PokeballType } from "./data/pokeball";
import { CommonAnim, CommonBattleAnim, MoveAnim, initMoveAnim, loadMoveAnimAssets } from "./data/battle-anims";
@ -16,7 +16,7 @@ import { EvolutionPhase } from "./evolution-phase";
import { BattlePhase } from "./battle-phase";
import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "./data/battle-stat";
import { Biome, biomeLinks } from "./data/biome";
import { ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, TmModifierType, getModifierType, getPlayerModifierTypeOptionsForWave, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type";
import { ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, TmModifierType, getEnemyBuffModifierTypeOptionsForWave, getModifierType, getPlayerModifierTypeOptionsForWave, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type";
import SoundFade from "phaser3-rex-plugins/plugins/soundfade";
import { BattlerTagLapseType, BattlerTagType, HideSpriteTag as HiddenTag, TrappedTag } from "./data/battler-tag";
import { getPokemonMessage } from "./messages";
@ -1561,8 +1561,11 @@ class MoveEffectPhase extends PokemonPhase {
if (!isProtected && !chargeEffect) {
applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.HIT,
user, target, this.move.getMove());
if (!target.isFainted())
if (!target.isFainted()) {
applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move, hitResult);
if (!user.isPlayer())
user.scene.applyModifiers(EnemyAttackStatusEffectChanceModifier, false, target);
}
if (this.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT))
this.scene.applyModifiers(ContactHeldItemTransferChanceModifier, this.player, user, target.getFieldIndex());
}
@ -1987,8 +1990,15 @@ export class FaintPhase extends PokemonPhase {
if (!--instantReviveModifier.stackCount)
this.scene.removeModifier(instantReviveModifier);
this.scene.updateModifiers(this.player);
this.end();
return;
return this.end();
}
if (!pokemon.isPlayer()) {
const enemyInstantReviveModifiers = this.scene.findModifiers(m => m instanceof EnemyInstantReviveChanceModifier);
for (let modifier of enemyInstantReviveModifiers) {
if (modifier.shouldApply([ pokemon ]) && modifier.apply([ pokemon ]))
return this.end();
}
}
this.scene.queueMessage(getPokemonMessage(pokemon, ' fainted!'), null, true);
@ -2113,9 +2123,11 @@ export class VictoryPhase extends PokemonPhase {
if (this.scene.currentBattle.battleType === BattleType.TRAINER)
this.scene.pushPhase(new TrainerVictoryPhase(this.scene));
if (this.scene.gameMode === GameMode.ENDLESS || this.scene.currentBattle.waveIndex < this.scene.finalWave) {
if (this.scene.currentBattle.waveIndex > 30 || this.scene.currentBattle.waveIndex % 10)
if (this.scene.currentBattle.waveIndex > 30 || this.scene.currentBattle.waveIndex % 10) {
this.scene.pushPhase(new SelectModifierPhase(this.scene));
else
if (this.scene.gameMode === GameMode.ENDLESS && !(this.scene.currentBattle.waveIndex % 50))
this.scene.pushPhase(new SelectEnemyBuffModifierPhase(this.scene));
} else
this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.GOLDEN_EXP_CHARM))
this.scene.pushPhase(new NewBattlePhase(this.scene));
} else
@ -2794,13 +2806,13 @@ export class SelectModifierPhase extends BattlePhase {
start() {
super.start();
this.scene.resetSeed();
this.updateSeed();
const party = this.scene.getParty();
regenerateModifierPoolThresholds(party, ModifierPoolType.PLAYER);
regenerateModifierPoolThresholds(party, this.getPoolType());
const modifierCount = new Utils.IntegerHolder(3);
this.scene.applyModifiers(ExtraModifierModifier, true, modifierCount);
const typeOptions: Array<ModifierTypeOption> = getPlayerModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, modifierCount.value, party);
const typeOptions: ModifierTypeOption[] = this.getModifierTypeOptions(modifierCount.value);
const modifierSelectCallback = (cursor: integer) => {
if (cursor < 0) {
@ -2810,7 +2822,7 @@ export class SelectModifierPhase extends BattlePhase {
} else if (cursor >= typeOptions.length) {
this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER, -1, (fromSlotIndex: integer, itemIndex: integer, toSlotIndex: integer) => {
if (toSlotIndex !== undefined && fromSlotIndex < 6 && toSlotIndex < 6 && fromSlotIndex !== toSlotIndex && itemIndex > -1) {
this.scene.ui.setMode(Mode.MODIFIER_SELECT).then(() => {
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => {
const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier
&& (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[];
const itemModifier = itemModifiers[itemIndex];
@ -2820,11 +2832,11 @@ export class SelectModifierPhase extends BattlePhase {
this.scene.ui.setMode(Mode.MESSAGE);
super.end();
} else
this.scene.ui.setMode(Mode.MODIFIER_SELECT, typeOptions, modifierSelectCallback);
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback);
});
});
} else
this.scene.ui.setMode(Mode.MODIFIER_SELECT, typeOptions, modifierSelectCallback);
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback);
}, PartyUiHandler.FilterItemMaxStacks);
return;
}
@ -2841,7 +2853,7 @@ export class SelectModifierPhase extends BattlePhase {
: undefined;
this.scene.ui.setModeWithoutClear(Mode.PARTY, partyUiMode, -1, (slotIndex: integer, option: PartyOption) => {
if (slotIndex < 6) {
this.scene.ui.setMode(Mode.MODIFIER_SELECT).then(() => {
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => {
const modifierType = typeOptions[cursor].type;
const modifier = !isMoveModifier
? modifierType.newModifier(party[slotIndex])
@ -2851,15 +2863,63 @@ export class SelectModifierPhase extends BattlePhase {
this.scene.addModifier(modifier, true).then(() => super.end());
});
} else
this.scene.ui.setMode(Mode.MODIFIER_SELECT, typeOptions, modifierSelectCallback);
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, );
}, pokemonModifierType.selectFilter, modifierType instanceof PokemonMoveModifierType ? (modifierType as PokemonMoveModifierType).moveSelectFilter : undefined, tmMoveId);
} else {
this.scene.addModifier(typeOptions[cursor].type.newModifier(), true).then(() => super.end());
this.addModifier(typeOptions[cursor].type.newModifier()).then(() => super.end());
this.scene.ui.clearText();
this.scene.ui.setMode(Mode.MESSAGE);
}
};
this.scene.ui.setMode(Mode.MODIFIER_SELECT, typeOptions, modifierSelectCallback);
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback);
}
updateSeed(): void {
this.scene.resetSeed();
}
isPlayer(): boolean {
return true;
}
getPoolType(): ModifierPoolType {
return ModifierPoolType.PLAYER;
}
getModifierTypeOptions(modifierCount: integer): ModifierTypeOption[] {
return getPlayerModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, modifierCount, this.scene.getParty());
}
addModifier(modifier: Modifier): Promise<void> {
return this.scene.addModifier(modifier, true);
}
}
export class SelectEnemyBuffModifierPhase extends SelectModifierPhase {
constructor(scene: BattleScene) {
super(scene);
}
start() {
this.scene.time.delayedCall(500, () => super.start());
}
updateSeed(): void { }
isPlayer(): boolean {
return false;
}
getPoolType(): ModifierPoolType {
return ModifierPoolType.ENEMY_BUFF;
}
getModifierTypeOptions(modifierCount: integer): ModifierTypeOption[] {
return getEnemyBuffModifierTypeOptionsForWave(modifierCount);
}
addModifier(modifier: Modifier): Promise<void> {
return this.scene.addEnemyModifier(modifier as PersistentModifier);
}
}

View File

@ -63,28 +63,18 @@ export default class Battle {
private getLevelForWave(): integer {
let baseLevel = 1 + this.waveIndex / 2 + Math.pow(this.waveIndex / 25, 2);
let bossMultiplier = this.waveIndex <= 250 ? 1.2 : Math.pow(1.2, this.waveIndex / 250);
const bossMultiplier = 1.2;
if (!(this.waveIndex % 10)) {
const ret = Math.floor(baseLevel * bossMultiplier);
if (this.waveIndex === 200 || !(this.waveIndex % 250))
return Math.ceil(ret / 25) * 25;
return ret;
return ret + Math.round(Phaser.Math.RND.realInRange(-1, 1) * Math.floor(this.waveIndex / 10));
}
const deviation = 10 / this.waveIndex;
const randLevel = Math.max(Math.round(baseLevel + Math.abs(Utils.randSeedGauss(deviation))), 1);
if (this.waveIndex <= 250)
return randLevel;
const waveRatio = Math.min(this.waveIndex - 250 / 250, 1);
const easeInFunc = Phaser.Tweens.Builders.GetEaseFunction('Sine.easeIn');
const easeOutFunc = Phaser.Tweens.Builders.GetEaseFunction('Sine.easeOut');
return Math.ceil(easeInFunc(waveRatio) * Math.floor(baseLevel * bossMultiplier) + easeOutFunc(1 - waveRatio) * randLevel);
return Math.max(Math.round(baseLevel + Math.abs(Utils.randSeedGauss(deviation))), 1);
}
getBattlerCount(): integer {

View File

@ -2635,7 +2635,8 @@ export function initMoves() {
.ignoresVirtual()
.target(MoveTarget.OTHER),
new StatusMove(Moves.TRANSFORM, "Transform", Type.NORMAL, -1, 10, -1, "User takes on the form and attacks of the opponent.", -1, 0, 1)
.attr(TransformAttr),
.attr(TransformAttr)
.ignoresProtect(),
new AttackMove(Moves.BUBBLE, "Bubble", Type.WATER, MoveCategory.SPECIAL, 40, 100, 30, -1, "May lower opponent's Speed.", 10, 0, 1)
.attr(StatChangeAttr, BattleStat.SPD, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES),

View File

@ -12,6 +12,7 @@ import { TempBattleStat, getTempBattleStatBoosterItemName, getTempBattleStatName
import { BerryType, getBerryEffectDescription, getBerryName } from '../data/berry';
import { Unlockables } from '../system/unlockables';
import { GameMode } from '../game-mode';
import { StatusEffect, getStatusEffectDescriptor } from '../data/status-effect';
type Modifier = Modifiers.Modifier;
@ -26,7 +27,8 @@ export enum ModifierTier {
export enum ModifierPoolType {
PLAYER,
WILD,
TRAINER
TRAINER,
ENEMY_BUFF
}
type NewModifierFunc = (type: ModifierType, args: any[]) => Modifier;
@ -524,6 +526,18 @@ export class TurnHeldItemTransferModifierType extends PokemonHeldItemModifierTyp
}
}
export class EnemyAttackStatusEffectChanceModifierType extends ModifierType {
constructor(name: string, chancePercent: integer, effect: StatusEffect, iconImage?: string) {
super(name, `Adds a ${chancePercent}% chance on hit to inflict ${getStatusEffectDescriptor(effect)}`, (type, args) => new Modifiers.EnemyAttackStatusEffectChanceModifier(type, effect, chancePercent), iconImage, 'enemy_status_chance')
}
}
export class EnemyInstantReviveChanceModifierType extends ModifierType {
constructor(name: string, chancePercent: integer, fullHeal: boolean, iconImage?: string) {
super(name, `Adds a ${chancePercent}% chance of reviving with ${fullHeal ? '100' : '50'}% HP`, (type, _args) => new Modifiers.EnemyInstantReviveChanceModifier(type, fullHeal, chancePercent), iconImage, 'enemy_revive');
}
}
export type ModifierTypeFunc = () => ModifierType;
type WeightedModifierTypeWeightFunc = (party: Pokemon[]) => integer;
@ -662,7 +676,14 @@ export const modifierTypes = {
(type, _args) => new Modifiers.ExtraModifierModifier(type), 'pb_gold', null, 'pb_bounce_1'),
ENEMY_DAMAGE_BOOSTER: () => new ModifierType('Damage Booster', 'Increases damage by 20%', (type, _args) => new Modifiers.EnemyDamageBoosterModifier(type), 'wl_item_drop'),
ENEMY_DAMAGE_REDUCTION: () => new ModifierType('Damage Reducer', 'Reduces incoming damage by 10%', (type, _args) => new Modifiers.EnemyDamageReducerModifier(type), 'wl_guard_spec')
ENEMY_DAMAGE_REDUCTION: () => new ModifierType('Damage Reducer', 'Reduces incoming damage by 10%', (type, _args) => new Modifiers.EnemyDamageReducerModifier(type), 'wl_guard_spec'),
ENEMY_ATTACK_POISON_CHANCE: () => new EnemyAttackStatusEffectChanceModifierType('Poison Hit', 10, StatusEffect.POISON, 'wl_antidote'),
ENEMY_ATTACK_PARALYZE_CHANCE: () => new EnemyAttackStatusEffectChanceModifierType('Paralyze Hit', 10, StatusEffect.PARALYSIS, 'wl_paralyze_heal'),
ENEMY_ATTACK_SLEEP_CHANCE: () => new EnemyAttackStatusEffectChanceModifierType('Sleep Hit', 10, StatusEffect.SLEEP, 'wl_awakening'),
ENEMY_ATTACK_FREEZE_CHANCE: () => new EnemyAttackStatusEffectChanceModifierType('Freeze Hit', 10, StatusEffect.FREEZE, 'wl_ice_heal'),
ENEMY_ATTACK_BURN_CHANCE: () => new EnemyAttackStatusEffectChanceModifierType('Burn Hit', 10, StatusEffect.BURN, 'wl_burn_heal'),
ENEMY_INSTANT_REVIVE_CHANCE: () => new EnemyInstantReviveChanceModifierType('Reviver', 5, false, 'wl_revive'),
ENEMY_INSTANT_MAX_REVIVE_CHANCE: () => new EnemyInstantReviveChanceModifierType('Reviver', 2, true, 'wl_max_revive'),
};
const modifierPool = {
@ -800,6 +821,23 @@ const trainerModifierPool = {
].map(m => { m.setTier(ModifierTier.MASTER); return m; })
};
const enemyBuffModifierPool = {
[ModifierTier.COMMON]: [
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_BOOSTER, 8),
new WeightedModifierType(modifierTypes.ENEMY_DAMAGE_REDUCTION, 8),
new WeightedModifierType(modifierTypes.ENEMY_ATTACK_POISON_CHANCE, 3),
new WeightedModifierType(modifierTypes.ENEMY_ATTACK_PARALYZE_CHANCE, 3),
new WeightedModifierType(modifierTypes.ENEMY_ATTACK_SLEEP_CHANCE, 3),
new WeightedModifierType(modifierTypes.ENEMY_ATTACK_FREEZE_CHANCE, 3),
new WeightedModifierType(modifierTypes.ENEMY_ATTACK_BURN_CHANCE, 3),
new WeightedModifierType(modifierTypes.ENEMY_INSTANT_REVIVE_CHANCE, 8),
new WeightedModifierType(modifierTypes.ENEMY_INSTANT_MAX_REVIVE_CHANCE, 8)
].map(m => { m.setTier(ModifierTier.COMMON); return m; }),
[ModifierTier.GREAT]: [ ].map(m => { m.setTier(ModifierTier.GREAT); return m; }),
[ModifierTier.ULTRA]: [ ].map(m => { m.setTier(ModifierTier.ULTRA); return m; }),
[ModifierTier.MASTER]: [ ].map(m => { m.setTier(ModifierTier.MASTER); return m; })
};
export function getModifierType(modifierTypeFunc: ModifierTypeFunc): ModifierType {
const modifierType = modifierTypeFunc();
if (!modifierType.id)
@ -813,9 +851,12 @@ let ignoredPoolIndexes = {};
let enemyModifierPoolThresholds = {};
let enemyIgnoredPoolIndexes = {};
let enemyBuffModifierPoolThresholds = {};
let enemyBuffIgnoredPoolIndexes = {};
export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: ModifierPoolType) {
const player = !poolType;
const pool = player ? modifierPool : poolType === ModifierPoolType.WILD ? wildModifierPool : trainerModifierPool;
const pool = player ? modifierPool : poolType === ModifierPoolType.WILD ? wildModifierPool : poolType === ModifierPoolType.TRAINER ? trainerModifierPool : enemyBuffModifierPool;
const ignoredIndexes = {};
const thresholds = Object.fromEntries(new Map(Object.keys(pool).map(t => {
ignoredIndexes[t] = [];
@ -843,9 +884,12 @@ export function regenerateModifierPoolThresholds(party: Pokemon[], poolType: Mod
if (player) {
modifierPoolThresholds = thresholds;
ignoredPoolIndexes = ignoredIndexes;
} else {
} else if (poolType !== ModifierPoolType.ENEMY_BUFF) {
enemyModifierPoolThresholds = thresholds;
enemyIgnoredPoolIndexes = ignoredIndexes;
} else {
enemyBuffModifierPoolThresholds = thresholds;
enemyBuffIgnoredPoolIndexes = ignoredIndexes;
}
}
@ -868,6 +912,19 @@ export function getPlayerModifierTypeOptionsForWave(waveIndex: integer, count: i
return options;
}
export function getEnemyBuffModifierTypeOptionsForWave(count: integer): ModifierTypeOption[] {
const options: ModifierTypeOption[] = [];
const retryCount = Math.min(count * 5, 50);
new Array(count).fill(0).map(() => {
let candidate = getNewModifierTypeOption(null, ModifierPoolType.ENEMY_BUFF, ModifierTier.COMMON);
let r = 0;
while (options.length && ++r < retryCount && options.filter(o => o.type.name === candidate.type.name || o.type.group === candidate.type.group).length)
candidate = getNewModifierTypeOption(null, ModifierPoolType.ENEMY_BUFF, candidate.type.tier);
options.push(candidate);
});
return options;
}
export function getEnemyModifierTypesForWave(waveIndex: integer, count: integer, party: EnemyPokemon[], poolType: ModifierPoolType.WILD | ModifierPoolType.TRAINER, gameMode: GameMode): PokemonHeldItemModifierType[] {
const ret = new Array(count).fill(0).map(() => getNewModifierTypeOption(party, poolType).type as PokemonHeldItemModifierType);
if ((gameMode === GameMode.CLASSIC && waveIndex === 200) || !(waveIndex % 1000))
@ -877,6 +934,7 @@ export function getEnemyModifierTypesForWave(waveIndex: integer, count: integer,
function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, tier?: ModifierTier, upgrade?: boolean): ModifierTypeOption {
const player = !poolType;
const pool = player ? modifierPool : poolType === ModifierPoolType.WILD ? wildModifierPool : poolType === ModifierPoolType.TRAINER ? trainerModifierPool : enemyBuffModifierPool;
if (tier === undefined) {
const tierValue = Utils.randSeedInt(256);
if (player && tierValue) {
@ -886,23 +944,26 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType,
} else
upgrade = false;
tier = (tierValue >= 52 ? ModifierTier.COMMON : tierValue >= 8 ? ModifierTier.GREAT : tierValue >= 1 ? ModifierTier.ULTRA : ModifierTier.MASTER) + (upgrade ? 1 : 0);
while (tier && !modifierPool[tier].length)
tier--;
}
const thresholds = Object.keys((player ? modifierPoolThresholds : enemyModifierPoolThresholds)[tier]);
const totalWeight = parseInt(thresholds[thresholds.length - 1]);
const thresholds = player ? modifierPoolThresholds : pool !== enemyBuffModifierPool ? enemyModifierPoolThresholds : enemyBuffModifierPoolThresholds;
const tierThresholds = Object.keys(thresholds[tier]);
const totalWeight = parseInt(tierThresholds[tierThresholds.length - 1]);
const value = Utils.randSeedInt(totalWeight);
let index: integer;
for (let t of thresholds) {
for (let t of tierThresholds) {
let threshold = parseInt(t);
if (value < threshold) {
index = (player ? modifierPoolThresholds : enemyModifierPoolThresholds)[tier][threshold];
index = thresholds[tier][threshold];
break;
}
}
if (player)
console.log(index, ignoredPoolIndexes[tier].filter(i => i <= index).length, ignoredPoolIndexes[tier])
let modifierType: ModifierType = ((player ? modifierPool : poolType === ModifierPoolType.WILD ? wildModifierPool : trainerModifierPool)[tier][index]).modifierType;
let modifierType: ModifierType = (pool[tier][index]).modifierType;
if (modifierType instanceof ModifierTypeGenerator) {
modifierType = (modifierType as ModifierTypeGenerator).generateType(party);
if (modifierType === null) {

View File

@ -1231,6 +1231,10 @@ export abstract class EnemyPersistentModifer extends PersistentModifier {
constructor(type: ModifierType, stackCount?: integer) {
super(type, stackCount);
}
getMaxStackCount(): number {
return 5;
}
}
export class EnemyDamageBoosterModifier extends EnemyPersistentModifer {
@ -1251,10 +1255,6 @@ export class EnemyDamageBoosterModifier extends EnemyPersistentModifer {
return true;
}
getMaxStackCount(): number {
return 5;
}
}
export class EnemyDamageReducerModifier extends EnemyPersistentModifer {
@ -1275,19 +1275,17 @@ export class EnemyDamageReducerModifier extends EnemyPersistentModifer {
return true;
}
getMaxStackCount(): number {
return 5;
}
}
export class EnemyAttackStatusEffectChanceModifier extends EnemyPersistentModifer {
public effect: StatusEffect;
private chance: number;
constructor(type: ModifierType, effect: StatusEffect, stackCount?: integer) {
constructor(type: ModifierType, effect: StatusEffect, chancePercent: integer, stackCount?: integer) {
super(type, stackCount);
this.effect = effect;
this.chance = chancePercent / 100;
}
match(modifier: Modifier): boolean {
@ -1300,13 +1298,45 @@ export class EnemyAttackStatusEffectChanceModifier extends EnemyPersistentModife
apply(args: any[]): boolean {
const target = (args[0] as Pokemon);
if (Utils.randInt(10) < this.getStackCount())
if (Utils.randIntRange(0, 1) < this.chance * this.getStackCount()) {
target.scene.unshiftPhase(new ObtainStatusEffectPhase(target.scene, target.getBattlerIndex(), this.effect));
return true;
}
getMaxStackCount(): number {
return 5;
return false;
}
}
export class EnemyInstantReviveChanceModifier extends EnemyPersistentModifer {
public fullHeal: boolean;
private chance: number;
constructor(type: ModifierType, healFull: boolean, chancePercent: integer, stackCount?: integer) {
super(type, stackCount);
this.fullHeal = healFull;
this.chance = chancePercent / 100;
}
matchType(modifier: Modifier) {
return modifier instanceof EnemyInstantReviveChanceModifier && modifier.fullHeal === this.fullHeal;
}
clone() {
return new EnemyInstantReviveChanceModifier(this.type, this.fullHeal, this.chance, this.stackCount);
}
apply(args: any[]): boolean {
if (Utils.randIntRange(0, 1) >= this.chance * this.getStackCount())
return false;
const pokemon = args[0] as Pokemon;
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(),
Math.max(Math.floor(pokemon.getMaxHp() / (this.fullHeal ? 1 : 2)), 1), getPokemonMessage(pokemon, ` was revived\nby its ${this.type.name}!`), false, false, true));
pokemon.resetStatus();
return true;
}
}

View File

@ -116,7 +116,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler {
}
}
clear(): void {
clear() {
super.clear();
}

View File

@ -12,6 +12,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
private transferButtonContainer: Phaser.GameObjects.Container;
private lastCursor: integer = 0;
private player: boolean;
public options: ModifierOption[];
@ -47,26 +48,28 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
show(args: any[]) {
if (this.active) {
if (args.length === 2) {
if (args.length === 3) {
this.awaitingActionInput = true;
this.onActionInput = args[1];
this.onActionInput = args[2];
}
return;
}
if (args.length !== 2 || !(args[0] instanceof Array) || !args[0].length || !(args[1] instanceof Function))
if (args.length !== 3 || !(args[1] instanceof Array) || !args[1].length || !(args[2] instanceof Function))
return;
super.show(args);
this.getUi().clearText();
const partyHasHeldItem = !!this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).getTransferrable(true)).length;
this.player = args[0];
const partyHasHeldItem = this.player && !!this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).getTransferrable(true)).length;
this.transferButtonContainer.setVisible(false);
this.transferButtonContainer.setAlpha(0);
const typeOptions = args[0] as ModifierTypeOption[];
const typeOptions = args[1] as ModifierTypeOption[];
for (let m = 0; m < typeOptions.length; m++) {
const sliceWidth = (this.scene.game.canvas.width / 6) / (typeOptions.length + 2);
const option = new ModifierOption(this.scene, sliceWidth * (m + 1) + (sliceWidth * 0.5), -this.scene.game.canvas.height / 12 - 24, typeOptions[m]);
@ -113,7 +116,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
this.setCursor(0);
this.awaitingActionInput = true;
this.onActionInput = args[1];
this.onActionInput = args[2];
});
}
@ -134,6 +137,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
originalOnActionInput(this.cursor);
}
} else if (button === Button.CANCEL) {
if (this.player) {
success = true;
if (this.onActionInput) {
const originalOnActionInput = this.onActionInput;
@ -141,6 +145,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler {
this.onActionInput = null;
originalOnActionInput(-1);
}
}
} else {
switch (button) {
case Button.UP: