Update all phases

Migrated all the edits I made in `phases.ts` over to the files in the new `phases` folder
This commit is contained in:
RedstonewolfX 2024-08-25 17:11:19 -04:00
parent 3424d669b9
commit 64cc901fe1
26 changed files with 1334 additions and 269 deletions

View File

@ -411,6 +411,7 @@ export default class BattleScene extends SceneBase {
this.fieldUI = fieldUI;
/*
const transition = this.make.rexTransitionImagePack({
x: 0,
y: 0,
@ -430,6 +431,7 @@ export default class BattleScene extends SceneBase {
});
this.add.existing(transition);
*/
const uiContainer = this.add.container(0, 0);
uiContainer.setName("ui");

View File

@ -1905,7 +1905,7 @@ export function resetWaveActions(scene: BattleScene, floor: integer = scene.curr
// #region Utils from Phases.ts
const tierNames = [
export const tierNames = [
"Poké",
"Great",
"Ultra",

View File

@ -51,6 +51,37 @@ export class BattleEndPhase extends BattlePhase {
}
}
// Format this wave's logs
var drpd: LoggerTools.DRPD = LoggerTools.getDRPD(this.scene)
var wv: LoggerTools.Wave = LoggerTools.getWave(drpd, this.scene.currentBattle.waveIndex, this.scene)
var lastcount = 0;
var lastval;
var tempActions: string[] = wv.actions.slice();
var prevWaveActions: string[] = []
wv.actions = []
// Loop through each action
for (var i = 0; i < tempActions.length; i++) {
if (tempActions[i].substring(0, 10) == "[MOVEBACK]") {
prevWaveActions.push(tempActions[i].substring(10))
} else if (tempActions[i] != lastval) {
if (lastcount > 0) {
wv.actions.push(lastval + (lastcount == 1 ? "" : " x" + lastcount))
}
lastval = tempActions[i]
lastcount = 1
} else {
lastcount++
}
}
if (lastcount > 0) {
wv.actions.push(lastval + (lastcount == 1 ? "" : " x" + lastcount))
}
console.log(tempActions, wv.actions)
var wv2: LoggerTools.Wave = LoggerTools.getWave(drpd, this.scene.currentBattle.waveIndex - 1, this.scene)
wv2.actions = wv2.actions.concat(prevWaveActions)
console.log(drpd)
LoggerTools.save(this.scene, drpd)
this.scene.updateModifiers().then(() => this.end());
}
}

View File

@ -8,6 +8,7 @@ import { BattlePhase } from "./battle-phase";
import { PostSummonPhase } from "./post-summon-phase";
import { SummonMissingPhase } from "./summon-missing-phase";
import { SwitchPhase } from "./switch-phase";
import { getNatureName } from "#app/data/nature.js";
import * as LoggerTools from "../logger";
export class CheckSwitchPhase extends BattlePhase {
@ -47,14 +48,118 @@ export class CheckSwitchPhase extends BattlePhase {
return;
}
for (var i = 0; i < this.scene.getEnemyField().length; i++) {
var pk = this.scene.getEnemyField()[i]
var maxIVs: string[] = []
var ivnames = ["HP", "Atk", "Def", "Sp.Atk", "Sp.Def", "Speed"]
pk.ivs.forEach((iv, j) => {if (iv == 31) maxIVs.push(ivnames[j])})
var ivDesc = maxIVs.join(",")
if (ivDesc == "") {
ivDesc = "No Max IVs"
} else {
ivDesc = "31: " + ivDesc
}
pk.getBattleInfo().flyoutMenu.toggleFlyout(true)
pk.getBattleInfo().flyoutMenu.flyoutText[0].text = getNatureName(pk.nature)
pk.getBattleInfo().flyoutMenu.flyoutText[1].text = ivDesc
pk.getBattleInfo().flyoutMenu.flyoutText[2].text = pk.getAbility().name
pk.getBattleInfo().flyoutMenu.flyoutText[3].text = pk.getPassiveAbility().name
if (pk.hasAbility(pk.species.abilityHidden, true, true)) {
pk.getBattleInfo().flyoutMenu.flyoutText[2].setColor("#e8e8a8")
}
}
if (false) {
this.scene.pokemonInfoContainer.show(this.scene.getEnemyField()[0], false, 1, true);
if (this.scene.getEnemyField()[1] != undefined) {
this.scene.tweens.add({
targets: this.scene.pokemonInfoContainer,
alpha: 1,
duration: 5000,
onComplete: () => {
this.scene.pokemonInfoContainer.hide(1.3)
this.scene.tweens.add({
targets: this.scene.pokemonInfoContainer,
alpha: 1,
duration: 1000,
onComplete: () => {
this.scene.pokemonInfoContainer.show(this.scene.getEnemyField()[1], false, 1, true);
}
})
}
})
}
}
for (var i = 0; i < this.scene.getEnemyField().length; i++) {
var pk = this.scene.getEnemyField()[i]
var maxIVs: string[] = []
var ivnames = ["HP", "Atk", "Def", "Sp.Atk", "Sp.Def", "Speed"]
pk.ivs.forEach((iv, j) => {if (iv == 31) maxIVs.push(ivnames[j])})
var ivDesc = maxIVs.join(",")
if (ivDesc == "") {
ivDesc = "No Max IVs"
} else {
ivDesc = "31: " + ivDesc
}
pk.getBattleInfo().flyoutMenu.toggleFlyout(true)
pk.getBattleInfo().flyoutMenu.flyoutText[0].text = getNatureName(pk.nature)
pk.getBattleInfo().flyoutMenu.flyoutText[1].text = ivDesc
pk.getBattleInfo().flyoutMenu.flyoutText[2].text = pk.getAbility().name
pk.getBattleInfo().flyoutMenu.flyoutText[3].text = pk.getPassiveAbility().name
if (pk.hasAbility(pk.species.abilityHidden, true, true)) {
pk.getBattleInfo().flyoutMenu.flyoutText[2].setColor("#e8e8a8")
}
}
if (false) {
this.scene.pokemonInfoContainer.show(this.scene.getEnemyField()[0], false, 1, true);
if (this.scene.getEnemyField()[1] != undefined) {
this.scene.tweens.add({
targets: this.scene.pokemonInfoContainer,
alpha: 1,
duration: 5000,
onComplete: () => {
this.scene.pokemonInfoContainer.hide(1.3)
this.scene.tweens.add({
targets: this.scene.pokemonInfoContainer,
alpha: 1,
duration: 1000,
onComplete: () => {
this.scene.pokemonInfoContainer.show(this.scene.getEnemyField()[1], false, 1, true);
}
})
}
})
}
}
this.scene.ui.showText(i18next.t("battle:switchQuestion", { pokemonName: this.useName ? getPokemonNameWithAffix(pokemon) : i18next.t("battle:pokemon") }), null, () => {
this.scene.ui.setMode(Mode.CONFIRM, () => {
this.scene.ui.setMode(Mode.MESSAGE);
LoggerTools.isPreSwitch.value = true
this.scene.tryRemovePhase(p => p instanceof PostSummonPhase && p.player && p.fieldIndex === this.fieldIndex);
this.scene.unshiftPhase(new SwitchPhase(this.scene, this.fieldIndex, false, true));
for (var i = 0; i < this.scene.getEnemyField().length; i++) {
this.scene.getEnemyField()[i].getBattleInfo().flyoutMenu.toggleFlyout(false)
this.scene.getEnemyField()[i].getBattleInfo().flyoutMenu.flyoutText[0].text = "???"
this.scene.getEnemyField()[i].getBattleInfo().flyoutMenu.flyoutText[1].text = "???"
this.scene.getEnemyField()[i].getBattleInfo().flyoutMenu.flyoutText[2].text = "???"
this.scene.getEnemyField()[i].getBattleInfo().flyoutMenu.flyoutText[3].text = "???"
this.scene.getEnemyField()[i].getBattleInfo().flyoutMenu.flyoutText[2].setColor("#f8f8f8")
this.scene.getEnemyField()[i].flyout.setText()
}
//this.scene.pokemonInfoContainer.hide()
this.end();
}, () => {
this.scene.ui.setMode(Mode.MESSAGE);
for (var i = 0; i < this.scene.getEnemyField().length; i++) {
this.scene.getEnemyField()[i].getBattleInfo().flyoutMenu.toggleFlyout(false)
this.scene.getEnemyField()[i].getBattleInfo().flyoutMenu.flyoutText[0].text = "???"
this.scene.getEnemyField()[i].getBattleInfo().flyoutMenu.flyoutText[1].text = "???"
this.scene.getEnemyField()[i].getBattleInfo().flyoutMenu.flyoutText[2].text = "???"
this.scene.getEnemyField()[i].getBattleInfo().flyoutMenu.flyoutText[3].text = "???"
this.scene.getEnemyField()[i].getBattleInfo().flyoutMenu.flyoutText[2].setColor("#f8f8f8")
}
//this.scene.pokemonInfoContainer.hide()
this.end();
});
});

View File

@ -54,8 +54,8 @@ export class CommandPhase extends FieldPhase {
const moveQueue = playerPokemon.getMoveQueue();
while (moveQueue.length && moveQueue[0]
&& moveQueue[0].move && (!playerPokemon.getMoveset().find(m => m?.moveId === moveQueue[0].move)
|| !playerPokemon.getMoveset()[playerPokemon.getMoveset().findIndex(m => m?.moveId === moveQueue[0].move)]!.isUsable(playerPokemon, moveQueue[0].ignorePP))) { // TODO: is the bang correct?
&& moveQueue[0].move && (!playerPokemon.getMoveset().find(m => m?.moveId === moveQueue[0].move)
|| !playerPokemon.getMoveset()[playerPokemon.getMoveset().findIndex(m => m?.moveId === moveQueue[0].move)]!.isUsable(playerPokemon, moveQueue[0].ignorePP))) { // TODO: is the bang correct?
moveQueue.shift();
}
@ -85,8 +85,8 @@ export class CommandPhase extends FieldPhase {
case Command.FIGHT:
let useStruggle = false;
if (cursor === -1 ||
playerPokemon.trySelectMove(cursor, args[0] as boolean) ||
(useStruggle = cursor > -1 && !playerPokemon.getMoveset().filter(m => m?.isUsable(playerPokemon)).length)) {
playerPokemon.trySelectMove(cursor, args[0] as boolean) ||
(useStruggle = cursor > -1 && !playerPokemon.getMoveset().filter(m => m?.isUsable(playerPokemon)).length)) {
const moveId = !useStruggle ? cursor > -1 ? playerPokemon.getMoveset()[cursor]!.moveId : Moves.NONE : Moves.STRUGGLE; // TODO: is the bang correct?
const turnCommand: TurnCommand = { command: Command.FIGHT, cursor: cursor, move: { move: moveId, targets: [], ignorePP: args[0] }, args: args };
const moveTargets: MoveTargetSet = args.length < 3 ? getMoveTargets(playerPokemon, moveId) : args[2];
@ -98,9 +98,9 @@ export class CommandPhase extends FieldPhase {
this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex));
}
if (moveTargets.targets.length <= 1 || moveTargets.multiple) {
turnCommand.move!.targets = moveTargets.targets; //TODO: is the bang correct here?
turnCommand.move!.targets = moveTargets.targets; //TODO: is the bang correct here?
} else if (playerPokemon.getTag(BattlerTagType.CHARGING) && playerPokemon.getMoveQueue().length >= 1) {
turnCommand.move!.targets = playerPokemon.getMoveQueue()[0].targets; //TODO: is the bang correct here?
turnCommand.move!.targets = playerPokemon.getMoveQueue()[0].targets; //TODO: is the bang correct here?
} else {
this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex));
}
@ -112,8 +112,8 @@ export class CommandPhase extends FieldPhase {
// Decides between a Disabled, Not Implemented, or No PP translation message
const errorMessage =
playerPokemon.summonData.disabledMove === move.moveId ? "battle:moveDisabled" :
move.getName().endsWith(" (N)") ? "battle:moveNotImplemented" : "battle:moveNoPP";
playerPokemon.summonData.disabledMove === move.moveId ? "battle:moveDisabled" :
move.getName().endsWith(" (N)") ? "battle:moveNotImplemented" : "battle:moveNoPP";
const moveName = move.getName().replace(" (N)", ""); // Trims off the indicator
this.scene.ui.showText(i18next.t(errorMessage, { moveName: moveName }), null, () => {
@ -158,11 +158,11 @@ export class CommandPhase extends FieldPhase {
}, null, true);
} else {
this.scene.currentBattle.turnCommands[this.fieldIndex] = { command: Command.BALL, cursor: cursor };
this.scene.currentBattle.turnCommands[this.fieldIndex]!.targets = targets;
if (this.fieldIndex) {
this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true;
}
success = true;
this.scene.currentBattle.turnCommands[this.fieldIndex]!.targets = targets;
if (this.fieldIndex) {
this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true;
}
success = true;
}
}
}
@ -198,7 +198,7 @@ export class CommandPhase extends FieldPhase {
: { command: Command.RUN };
success = true;
if (!isSwitch && this.fieldIndex) {
this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true;
this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true;
}
} else if (trapTag) {
if (trapTag.sourceMove === Moves.INGRAIN && trapTag.sourceId && this.scene.getPokemonById(trapTag.sourceId)?.isOfType(Type.GHOST)) {

View File

@ -26,6 +26,7 @@ import { ScanIvsPhase } from "./scan-ivs-phase";
import { ShinySparklePhase } from "./shiny-sparkle-phase";
import { SummonPhase } from "./summon-phase";
import { ToggleDoublePositionPhase } from "./toggle-double-position-phase";
import { GameModes } from "#app/game-mode.js";
import * as LoggerTools from "../logger";
export class EncounterPhase extends BattlePhase {
@ -57,11 +58,17 @@ export class EncounterPhase extends BattlePhase {
let totalBst = 0;
while (LoggerTools.rarities.length > 0) {
LoggerTools.rarities.pop()
}
LoggerTools.rarityslot[0] = 0
//console.log(this.scene.gameMode.getDailyOverride())
battle.enemyLevels?.forEach((level, e) => {
if (!this.loaded) {
if (battle.battleType === BattleType.TRAINER) {
battle.enemyParty[e] = battle.trainer?.genPartyMember(e)!; // TODO:: is the bang correct here?
} else {
LoggerTools.rarityslot[0] = e
const enemySpecies = this.scene.randomSpecies(battle.waveIndex, level, true);
battle.enemyParty[e] = this.scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, !!this.scene.getEncounterBossSegments(battle.waveIndex, level, enemySpecies));
if (this.scene.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) {
@ -105,6 +112,7 @@ export class EncounterPhase extends BattlePhase {
console.log(getPokemonNameWithAffix(enemyPokemon), enemyPokemon.species.speciesId, enemyPokemon.stats);
});
console.log(LoggerTools.rarities)
if (this.scene.getParty().filter(p => p.isShiny()).length === 6) {
this.scene.validateAchv(achvs.SHINY_PARTY);
@ -174,10 +182,10 @@ export class EncounterPhase extends BattlePhase {
this.scene.setFieldScale(1);
/*if (startingWave > 10) {
for (let m = 0; m < Math.min(Math.floor(startingWave / 10), 99); m++)
this.scene.addModifier(getPlayerModifierTypeOptionsForWave((m + 1) * 10, 1, this.scene.getParty())[0].type.newModifier(), true);
this.scene.updateModifiers(true);
}*/
for (let m = 0; m < Math.min(Math.floor(startingWave / 10), 99); m++)
this.scene.addModifier(getPlayerModifierTypeOptionsForWave((m + 1) * 10, 1, this.scene.getParty())[0].type.newModifier(), true);
this.scene.updateModifiers(true);
}*/
for (const pokemon of this.scene.getParty()) {
if (pokemon) {
@ -226,6 +234,30 @@ export class EncounterPhase extends BattlePhase {
doEncounterCommon(showEncounterMessage: boolean = true) {
const enemyField = this.scene.getEnemyField();
//LoggerTools.resetWave(this.scene, this.scene.currentBattle.waveIndex)
if (this.scene.lazyReloads) {
LoggerTools.flagResetIfExists(this.scene)
}
LoggerTools.logTeam(this.scene, this.scene.currentBattle.waveIndex)
if (this.scene.getEnemyParty()[0].hasTrainer()) {
LoggerTools.logTrainer(this.scene, this.scene.currentBattle.waveIndex)
}
if (this.scene.currentBattle.waveIndex == 1) {
LoggerTools.logPlayerTeam(this.scene)
if (this.scene.gameMode.modeId == GameModes.DAILY && this.scene.disableDailyShinies) {
this.scene.getParty().forEach(p => {
p.species.luckOverride = 0; // Disable shiny luck for party members
})
}
}
LoggerTools.resetWaveActions(this.scene, undefined, true)
//this.scene.doShinyCheck()
if (LoggerTools.autoCheckpoints.includes(this.scene.currentBattle.waveIndex)) {
//this.scene.gameData.saveGameToAuto(this.scene)
}
if (this.scene.currentBattle.battleType === BattleType.WILD) {
enemyField.forEach(enemyPokemon => {
enemyPokemon.untint(100, "Sine.easeOut");
@ -351,7 +383,15 @@ export class EncounterPhase extends BattlePhase {
}
}
}
handleTutorial(this.scene, Tutorial.Access_Menu).then(() => super.end());
handleTutorial(this.scene, Tutorial.Access_Menu).then(() => {
// Auto-show the flyout
if (this.scene.currentBattle.battleType !== BattleType.TRAINER) {
this.scene.arenaFlyout.display2()
this.scene.arenaFlyout.toggleFlyout(true)
this.scene.arenaFlyout.isAuto = true
}
super.end()
});
}
tryOverrideForBattleSpec(): boolean {

View File

@ -6,6 +6,7 @@ import { Command } from "#app/ui/command-ui-handler.js";
import * as Utils from "#app/utils.js";
import { FieldPhase } from "./field-phase";
import * as LoggerTools from "../logger";
import { EnemyPokemon, PokemonMove } from "#app/field/pokemon.js";
/**
* Phase for determining an enemy AI's action for the next turn.
@ -29,20 +30,21 @@ export class EnemyCommandPhase extends FieldPhase {
super.start();
const enemyPokemon = this.scene.getEnemyField()[this.fieldIndex];
console.log(enemyPokemon.getMoveset().map(m => m?.getName()))
const battle = this.scene.currentBattle;
const trainer = battle.trainer;
/**
* If the enemy has a trainer, decide whether or not the enemy should switch
* to another member in its party.
*
* This block compares the active enemy Pokemon's {@linkcode Pokemon.getMatchupScore | matchup score}
* against the active player Pokemon with the enemy party's other non-fainted Pokemon. If a party
* member's matchup score is 3x the active enemy's score (or 2x for "boss" trainers),
* the enemy will switch to that Pokemon.
*/
* If the enemy has a trainer, decide whether or not the enemy should switch
* to another member in its party.
*
* This block compares the active enemy Pokemon's {@linkcode Pokemon.getMatchupScore | matchup score}
* against the active player Pokemon with the enemy party's other non-fainted Pokemon. If a party
* member's matchup score is 3x the active enemy's score (or 2x for "boss" trainers),
* the enemy will switch to that Pokemon.
*/
if (trainer && !enemyPokemon.getMoveQueue().length) {
const opponents = enemyPokemon.getOpponents();
@ -64,10 +66,17 @@ export class EnemyCommandPhase extends FieldPhase {
const index = trainer.getNextSummonIndex(enemyPokemon.trainerSlot, partyMemberScores);
battle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] =
{ command: Command.POKEMON, cursor: index, args: [false] };
{ command: Command.POKEMON, cursor: index, args: [false] };
console.log(enemyPokemon.name + " selects:", "Switch to " + this.scene.getEnemyParty()[index].name)
battle.enemySwitchCounter++;
LoggerTools.enemyPlan[this.fieldIndex*2] = "Switching out"
LoggerTools.enemyPlan[this.fieldIndex*2 + 1] = "→ " + this.scene.getEnemyParty()[index].name
enemyPokemon.flyout.setText()
this.scene.updateCatchRate()
return this.end();
}
}
@ -76,12 +85,40 @@ export class EnemyCommandPhase extends FieldPhase {
/** Select a move to use (and a target to use it against, if applicable) */
const nextMove = enemyPokemon.getNextMove();
const mv = new PokemonMove(nextMove.move)
this.scene.currentBattle.turnCommands[this.fieldIndex + BattlerIndex.ENEMY] =
{ command: Command.FIGHT, move: nextMove };
{ command: Command.FIGHT, move: nextMove };
const targetLabels = ["Counter", "[PLAYER L]", "[PLAYER R]", "[ENEMY L]", "[ENEMY R]"]
this.scene.getParty().forEach((v, i, a) => {
if (v.isActive() && v.name) {
targetLabels[i + 1] = v.name
}
})
this.scene.getEnemyParty().forEach((v, i, a) => {
if (v.isActive() && v.name) {
targetLabels[i + 3] = v.name
}
})
if (this.fieldIndex == 0) {
targetLabels[3] = "Self"
}
if (this.fieldIndex == 1) {
targetLabels[4] = "Self"
}
if (targetLabels[1] == targetLabels[2]) {
targetLabels[1] += " (L)"
targetLabels[2] += " (R)"
}
console.log(enemyPokemon.name + " selects:", mv.getName() + " → " + nextMove.targets.map((m) => targetLabels[m + 1]))
this.scene.currentBattle.enemySwitchCounter = Math.max(this.scene.currentBattle.enemySwitchCounter - 1, 0);
LoggerTools.enemyPlan[this.fieldIndex*2] = mv.getName()
LoggerTools.enemyPlan[this.fieldIndex*2 + 1] = "→ " + nextMove.targets.map((m) => targetLabels[m + 1])
this.scene.arenaFlyout.updateFieldText()
this.scene.updateCatchRate()
this.end();
}
}

View File

@ -101,6 +101,7 @@ export class FaintPhase extends PokemonPhase {
* If previous conditions weren't met, and the player has at least 1 legal Pokemon off the field,
* push a phase that prompts the player to summon a Pokemon from their party.
*/
LoggerTools.isFaintSwitch.value = true;
this.scene.pushPhase(new SwitchPhase(this.scene, this.fieldIndex, true, false));
}
} else {

View File

@ -9,6 +9,7 @@ import { SummaryUiMode } from "#app/ui/summary-ui-handler.js";
import { Mode } from "#app/ui/ui.js";
import i18next from "i18next";
import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase";
import { PokemonMove } from "#app/field/pokemon.js";
import * as LoggerTools from "../logger";
export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
@ -39,14 +40,81 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
const messageMode = this.scene.ui.getHandler() instanceof EvolutionSceneHandler
? Mode.EVOLUTION_SCENE
: Mode.MESSAGE;
const noHandler = () => {
this.scene.ui.setMode(messageMode).then(() => {
this.scene.ui.showText(i18next.t("battle:learnMoveStopTeaching", { moveName: move.name }), null, () => {
this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => {
this.scene.ui.setMode(messageMode);
var W = LoggerTools.getWave(LoggerTools.getDRPD(this.scene), this.scene.currentBattle.waveIndex, this.scene)
if (W.shop != "") {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, W.shop + "; skip learning it")
} else {
var actions = LoggerTools.getActionCount(this.scene, this.scene.currentBattle.waveIndex)
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, "Skip " + move.name)
}
this.scene.ui.showText(i18next.t("battle:learnMoveNotLearned", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => this.end(), null, true);
}, (false ? movesFullHandler : () => {
this.scene.ui.setMode(messageMode);
this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId));
this.end();
}));
});
});
};
const noHandlerInstant = () => {
this.scene.ui.setMode(messageMode);
var W = LoggerTools.getWave(LoggerTools.getDRPD(this.scene), this.scene.currentBattle.waveIndex, this.scene)
if (W.shop != "") {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, W.shop + "; skip learning it")
} else {
var actions = LoggerTools.getActionCount(this.scene, this.scene.currentBattle.waveIndex)
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, (actions == 0 ? "" : "") + LoggerTools.playerPokeName(this.scene, pokemon) + " | Skip " + move.name)
}
this.scene.ui.showText(i18next.t("battle:learnMoveNotLearned", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => this.end(), null, true);
};
const movesFullHandler = () => {
this.scene.ui.showText(i18next.t("battle:learnMovePrompt", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => {
this.scene.ui.showText(i18next.t("battle:learnMoveLimitReached", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => {
this.scene.ui.showText(i18next.t("battle:learnMoveReplaceQuestion", { moveName: move.name }), null, () => {
this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => {
this.scene.ui.setMode(messageMode);
this.scene.ui.showText(i18next.t("battle:learnMoveForgetQuestion"), null, () => {
this.scene.ui.setModeWithoutClear(Mode.SUMMARY, this.getPokemon(), SummaryUiMode.LEARN_MOVE, move, (moveIndex: integer) => {
if (moveIndex === 4) {
noHandler();
return;
}
this.scene.ui.setMode(messageMode).then(() => {
this.scene.ui.showText(i18next.t("battle:countdownPoof"), null, () => {
this.scene.ui.showText(i18next.t("battle:learnMoveForgetSuccess", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: pokemon.moveset[moveIndex]!.getName() }), null, () => { // TODO: is the bang correct?
this.scene.ui.showText(i18next.t("battle:learnMoveAnd"), null, () => {
var W = LoggerTools.getWave(LoggerTools.getDRPD(this.scene), this.scene.currentBattle.waveIndex, this.scene)
if (W.shop != "") {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, W.shop + " | " + new PokemonMove(this.moveId).getName() + " → " + pokemon.moveset[moveIndex]!.getName())
} else {
var actions = LoggerTools.getActionCount(this.scene, this.scene.currentBattle.waveIndex)
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, (actions == 0 ? "" : "") + LoggerTools.playerPokeName(this.scene, pokemon) + " | " + new PokemonMove(this.moveId).getName() + " → " + pokemon.moveset[moveIndex]!.getName())
}
pokemon.setMove(moveIndex, Moves.NONE);
this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId));
this.end();
}, null, true);
}, null, true);
}, null, true);
});
});
}, null, true);
}, noHandler);
});
}, null, true);
}, null, true);
}
if (emptyMoveIndex > -1) {
pokemon.setMove(emptyMoveIndex, this.moveId);
initMoveAnim(this.scene, this.moveId).then(() => {
loadMoveAnimAssets(this.scene, [this.moveId], true)
.then(() => {
this.scene.ui.setMode(messageMode).then(() => {
// Sound loaded into game as is
this.scene.playSound("level_up_fanfare");
this.scene.ui.showText(i18next.t("battle:learnMove", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => {
this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeMoveLearnedTrigger, true);
@ -55,51 +123,16 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
});
});
});
} else {
} else if (move.isUnimplemented() && false) {
this.scene.ui.setMode(messageMode).then(() => {
this.scene.ui.showText(i18next.t("battle:learnMovePrompt", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => {
this.scene.ui.showText(i18next.t("battle:learnMoveLimitReached", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => {
this.scene.ui.showText(i18next.t("battle:learnMoveReplaceQuestion", { moveName: move.name }), null, () => {
const noHandler = () => {
this.scene.ui.setMode(messageMode).then(() => {
this.scene.ui.showText(i18next.t("battle:learnMoveStopTeaching", { moveName: move.name }), null, () => {
this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => {
this.scene.ui.setMode(messageMode);
this.scene.ui.showText(i18next.t("battle:learnMoveNotLearned", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }), null, () => this.end(), null, true);
}, () => {
this.scene.ui.setMode(messageMode);
this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId));
this.end();
});
});
});
};
this.scene.ui.setModeWithoutClear(Mode.CONFIRM, () => {
this.scene.ui.setMode(messageMode);
this.scene.ui.showText(i18next.t("battle:learnMoveForgetQuestion"), null, () => {
this.scene.ui.setModeWithoutClear(Mode.SUMMARY, this.getPokemon(), SummaryUiMode.LEARN_MOVE, move, (moveIndex: integer) => {
if (moveIndex === 4) {
noHandler();
return;
}
this.scene.ui.setMode(messageMode).then(() => {
this.scene.ui.showText(i18next.t("battle:countdownPoof"), null, () => {
this.scene.ui.showText(i18next.t("battle:learnMoveForgetSuccess", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: pokemon.moveset[moveIndex]!.getName() }), null, () => { // TODO: is the bang correct?
this.scene.ui.showText(i18next.t("battle:learnMoveAnd"), null, () => {
pokemon.setMove(moveIndex, Moves.NONE);
this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId));
this.end();
}, null, true);
}, null, true);
}, null, true);
});
});
}, null, true);
}, noHandler);
});
}, null, true);
}, null, true);
this.scene.ui.showText(`${getPokemonNameWithAffix(pokemon)} wants to learn ${move.name}, but this move does nothing.`, null, () => {
this.scene.ui.showText(`Would you like to teach ${move.name} anyways? (This will be logged as normal)`, null, () => {
this.scene.ui.setModeWithoutClear(Mode.CONFIRM, movesFullHandler, noHandler)
})
})
});
} else {
this.scene.ui.setMode(messageMode).then(movesFullHandler);
}
}
}

View File

@ -24,10 +24,10 @@ export class MoveEffectPhase extends PokemonPhase {
super(scene, battlerIndex);
this.move = move;
/**
* In double battles, if the right Pokemon selects a spread move and the left Pokemon dies
* with no party members available to switch in, then the right Pokemon takes the index
* of the left Pokemon and gets hit unless this is checked.
*/
* In double battles, if the right Pokemon selects a spread move and the left Pokemon dies
* with no party members available to switch in, then the right Pokemon takes the index
* of the left Pokemon and gets hit unless this is checked.
*/
if (targets.includes(battlerIndex) && this.move.getMove().moveTarget === MoveTarget.ALL_NEAR_OTHERS) {
const i = targets.indexOf(battlerIndex);
targets.splice(i, i + 1);
@ -49,9 +49,9 @@ export class MoveEffectPhase extends PokemonPhase {
}
/**
* Does an effect from this move override other effects on this turn?
* e.g. Charging moves (Fly, etc.) on their first turn of use.
*/
* Does an effect from this move override other effects on this turn?
* e.g. Charging moves (Fly, etc.) on their first turn of use.
*/
const overridden = new Utils.BooleanHolder(false);
/** The {@linkcode Move} object from {@linkcode allMoves} invoked by this phase */
const move = this.move.getMove();
@ -66,10 +66,10 @@ export class MoveEffectPhase extends PokemonPhase {
user.lapseTags(BattlerTagLapseType.MOVE_EFFECT);
/**
* If this phase is for the first hit of the invoked move,
* resolve the move's total hit count. This block combines the
* effects of the move itself, Parental Bond, and Multi-Lens to do so.
*/
* If this phase is for the first hit of the invoked move,
* resolve the move's total hit count. This block combines the
* effects of the move itself, Parental Bond, and Multi-Lens to do so.
*/
if (user.turnData.hitsLeft === undefined) {
const hitCount = new Utils.IntegerHolder(1);
// Assume single target for multi hit
@ -86,23 +86,23 @@ export class MoveEffectPhase extends PokemonPhase {
}
/**
* Log to be entered into the user's move history once the move result is resolved.
* Note that `result` (a {@linkcode MoveResult}) logs whether the move was successfully
* used in the sense of "Does it have an effect on the user?".
*/
* Log to be entered into the user's move history once the move result is resolved.
* Note that `result` (a {@linkcode MoveResult}) logs whether the move was successfully
* used in the sense of "Does it have an effect on the user?".
*/
const moveHistoryEntry = { move: this.move.moveId, targets: this.targets, result: MoveResult.PENDING, virtual: this.move.virtual };
/**
* Stores results of hit checks of the invoked move against all targets, organized by battler index.
* @see {@linkcode hitCheck}
*/
* Stores results of hit checks of the invoked move against all targets, organized by battler index.
* @see {@linkcode hitCheck}
*/
const targetHitChecks = Object.fromEntries(targets.map(p => [p.getBattlerIndex(), this.hitCheck(p)]));
const hasActiveTargets = targets.some(t => t.isActive(true));
/**
* If no targets are left for the move to hit (FAIL), or the invoked move is single-target
* (and not random target) and failed the hit check against its target (MISS), log the move
* as FAILed or MISSed (depending on the conditions above) and end this phase.
*/
* If no targets are left for the move to hit (FAIL), or the invoked move is single-target
* (and not random target) and failed the hit check against its target (MISS), log the move
* as FAILed or MISSed (depending on the conditions above) and end this phase.
*/
if (!hasActiveTargets || (!move.hasAttr(VariableTargetAttr) && !move.isMultiTarget() && !targetHitChecks[this.targets[0]])) {
this.stopMultiHit();
if (hasActiveTargets) {
@ -126,9 +126,9 @@ export class MoveEffectPhase extends PokemonPhase {
let hasHit: boolean = false;
for (const target of targets) {
/**
* If the move missed a target, stop all future hits against that target
* and move on to the next target (if there is one).
*/
* If the move missed a target, stop all future hits against that target
* and move on to the next target (if there is one).
*/
if (!targetHitChecks[target.getBattlerIndex()]) {
this.stopMultiHit(target);
this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: getPokemonNameWithAffix(target) }));
@ -153,7 +153,7 @@ export class MoveEffectPhase extends PokemonPhase {
/** Is the target protected by Protect, etc. or a relevant conditional protection effect? */
const isProtected = (bypassIgnoreProtect.value || !this.move.getMove().checkFlag(MoveFlags.IGNORE_PROTECT, user, target))
&& (hasConditionalProtectApplied.value || target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType)));
&& (hasConditionalProtectApplied.value || target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType)));
/** Does this phase represent the invoked move's first strike? */
const firstHit = (user.turnData.hitsLeft === user.turnData.hitCount);
@ -164,23 +164,23 @@ export class MoveEffectPhase extends PokemonPhase {
}
/**
* Since all fail/miss checks have applied, the move is considered successfully applied.
* It's worth noting that if the move has no effect or is protected against, this assignment
* is overwritten and the move is logged as a FAIL.
*/
* Since all fail/miss checks have applied, the move is considered successfully applied.
* It's worth noting that if the move has no effect or is protected against, this assignment
* is overwritten and the move is logged as a FAIL.
*/
moveHistoryEntry.result = MoveResult.SUCCESS;
/**
* Stores the result of applying the invoked move to the target.
* If the target is protected, the result is always `NO_EFFECT`.
* Otherwise, the hit result is based on type effectiveness, immunities,
* and other factors that may negate the attack or status application.
*
* Internally, the call to {@linkcode Pokemon.apply} is where damage is calculated
* (for attack moves) and the target's HP is updated. However, this isn't
* made visible to the user until the resulting {@linkcode DamagePhase}
* is invoked.
*/
* Stores the result of applying the invoked move to the target.
* If the target is protected, the result is always `NO_EFFECT`.
* Otherwise, the hit result is based on type effectiveness, immunities,
* and other factors that may negate the attack or status application.
*
* Internally, the call to {@linkcode Pokemon.apply} is where damage is calculated
* (for attack moves) and the target's HP is updated. However, this isn't
* made visible to the user until the resulting {@linkcode DamagePhase}
* is invoked.
*/
const hitResult = !isProtected ? target.apply(user, move) : HitResult.NO_EFFECT;
/** Does {@linkcode hitResult} indicate that damage was dealt to the target? */
@ -198,9 +198,9 @@ export class MoveEffectPhase extends PokemonPhase {
}
/**
* If the move has no effect on the target (i.e. the target is protected or immune),
* change the logged move result to FAIL.
*/
* If the move has no effect on the target (i.e. the target is protected or immune),
* change the logged move result to FAIL.
*/
if (hitResult === HitResult.NO_EFFECT) {
moveHistoryEntry.result = MoveResult.FAIL;
}
@ -209,19 +209,19 @@ export class MoveEffectPhase extends PokemonPhase {
const lastHit = (user.turnData.hitsLeft === 1 || !this.getTarget()?.isActive());
/**
* If the user can change forms by using the invoked move,
* it only changes forms after the move's last hit
* (see Relic Song's interaction with Parental Bond when used by Meloetta).
*/
* If the user can change forms by using the invoked move,
* it only changes forms after the move's last hit
* (see Relic Song's interaction with Parental Bond when used by Meloetta).
*/
if (lastHit) {
this.scene.triggerPokemonFormChange(user, SpeciesFormChangePostMoveTrigger);
}
/**
* Create a Promise that applys *all* effects from the invoked move's MoveEffectAttrs.
* These are ordered by trigger type (see {@linkcode MoveEffectTrigger}), and each trigger
* type requires different conditions to be met with respect to the move's hit result.
*/
* Create a Promise that applys *all* effects from the invoked move's MoveEffectAttrs.
* These are ordered by trigger type (see {@linkcode MoveEffectTrigger}), and each trigger
* type requires different conditions to be met with respect to the move's hit result.
*/
applyAttrs.push(new Promise(resolve => {
// Apply all effects with PRE_MOVE triggers (if the target isn't immune to the move)
applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.PRE_APPLY && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit) && hitResult !== HitResult.NO_EFFECT,
@ -231,21 +231,21 @@ export class MoveEffectPhase extends PokemonPhase {
/** Are the move's effects tied to the first turn of a charge move? */
const chargeEffect = !!move.getAttrs(ChargeAttr).find(ca => ca.usedChargeEffect(user, this.getTarget() ?? null, move));
/**
* If the invoked move's effects are meant to trigger during the move's "charge turn,"
* ignore all effects after this point.
* Otherwise, apply all self-targeted POST_APPLY effects.
*/
* If the invoked move's effects are meant to trigger during the move's "charge turn,"
* ignore all effects after this point.
* Otherwise, apply all self-targeted POST_APPLY effects.
*/
Utils.executeIf(!chargeEffect, () => applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.POST_APPLY
&& attr.selfTarget && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit), user, target, move)).then(() => {
&& attr.selfTarget && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit), user, target, move)).then(() => {
// All effects past this point require the move to have hit the target
if (hitResult !== HitResult.NO_EFFECT) {
// Apply all non-self-targeted POST_APPLY effects
applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.POST_APPLY
&& !(attr as MoveEffectAttr).selfTarget && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit), user, target, this.move.getMove()).then(() => {
&& !(attr as MoveEffectAttr).selfTarget && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit), user, target, this.move.getMove()).then(() => {
/**
* If the move hit, and the target doesn't have Shield Dust,
* apply the chance to flinch the target gained from King's Rock
*/
* If the move hit, and the target doesn't have Shield Dust,
* apply the chance to flinch the target gained from King's Rock
*/
if (dealsDamage && !target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr)) {
const flinched = new Utils.BooleanHolder(false);
user.scene.applyModifiers(FlinchChanceModifier, user.isPlayer(), user, flinched);
@ -255,7 +255,7 @@ export class MoveEffectPhase extends PokemonPhase {
}
// If the move was not protected against, apply all HIT effects
Utils.executeIf(!isProtected && !chargeEffect, () => applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.HIT
&& (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit) && (!attr.firstTargetOnly || firstTarget), user, target, this.move.getMove()).then(() => {
&& (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit) && (!attr.firstTargetOnly || firstTarget), user, target, this.move.getMove()).then(() => {
// Apply the target's post-defend ability effects (as long as the target is active or can otherwise apply them)
return Utils.executeIf(!target.isFainted() || target.canApplyAbility(), () => applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move.getMove(), hitResult).then(() => {
// If the invoked move is an enemy attack, apply the enemy's status effect-inflicting tags and tokens
@ -270,9 +270,9 @@ export class MoveEffectPhase extends PokemonPhase {
// Apply the user's post-attack ability effects
applyPostAttackAbAttrs(PostAttackAbAttr, user, target, this.move.getMove(), hitResult).then(() => {
/**
* If the invoked move is an attack, apply the user's chance to
* steal an item from the target granted by Grip Claw
*/
* If the invoked move is an attack, apply the user's chance to
* steal an item from the target granted by Grip Claw
*/
if (this.move.getMove() instanceof AttackMove) {
this.scene.applyModifiers(ContactHeldItemTransferChanceModifier, this.player, user, target);
}
@ -316,12 +316,12 @@ export class MoveEffectPhase extends PokemonPhase {
move.type = move.defaultType;
const user = this.getUserPokemon();
/**
* If this phase isn't for the invoked move's last strike,
* unshift another MoveEffectPhase for the next strike.
* Otherwise, queue a message indicating the number of times the move has struck
* (if the move has struck more than once), then apply the heal from Shell Bell
* to the user.
*/
* If this phase isn't for the invoked move's last strike,
* unshift another MoveEffectPhase for the next strike.
* Otherwise, queue a message indicating the number of times the move has struck
* (if the move has struck more than once), then apply the heal from Shell Bell
* to the user.
*/
if (user) {
if (user.turnData.hitsLeft && --user.turnData.hitsLeft >= 1 && this.getTarget()?.isActive()) {
this.scene.unshiftPhase(this.getNewHitPhase());
@ -341,10 +341,10 @@ export class MoveEffectPhase extends PokemonPhase {
}
/**
* Resolves whether this phase's invoked move hits or misses the given target
* @param target {@linkcode Pokemon} the Pokemon targeted by the invoked move
* @returns `true` if the move does not miss the target; `false` otherwise
*/
* Resolves whether this phase's invoked move hits or misses the given target
* @param target {@linkcode Pokemon} the Pokemon targeted by the invoked move
* @returns `true` if the move does not miss the target; `false` otherwise
*/
hitCheck(target: Pokemon): boolean {
// Moves targeting the user and entry hazards can't miss
if ([MoveTarget.USER, MoveTarget.ENEMY_SIDE].includes(this.move.getMove().moveTarget)) {
@ -387,7 +387,7 @@ export class MoveEffectPhase extends PokemonPhase {
}
const accuracyMultiplier = user.getAccuracyMultiplier(target, this.move.getMove());
const rand = user.randSeedInt(100, 1);
const rand = user.randSeedInt(100, 1, "Accuracy roll");
return rand <= moveAccuracy * (accuracyMultiplier!); // TODO: is this bang correct?
}
@ -411,9 +411,9 @@ export class MoveEffectPhase extends PokemonPhase {
}
/**
* Removes the given {@linkcode Pokemon} from this phase's target list
* @param target {@linkcode Pokemon} the Pokemon to be removed
*/
* Removes the given {@linkcode Pokemon} from this phase's target list
* @param target {@linkcode Pokemon} the Pokemon to be removed
*/
removeTarget(target: Pokemon): void {
const targetIndex = this.targets.findIndex(ind => ind === target.getBattlerIndex());
if (targetIndex !== -1) {
@ -422,22 +422,22 @@ export class MoveEffectPhase extends PokemonPhase {
}
/**
* Prevents subsequent strikes of this phase's invoked move from occurring
* @param target {@linkcode Pokemon} if defined, only stop subsequent
* strikes against this Pokemon
*/
* Prevents subsequent strikes of this phase's invoked move from occurring
* @param target {@linkcode Pokemon} if defined, only stop subsequent
* strikes against this Pokemon
*/
stopMultiHit(target?: Pokemon): void {
/** If given a specific target, remove the target from subsequent strikes */
if (target) {
this.removeTarget(target);
}
/**
* If no target specified, or the specified target was the last of this move's
* targets, completely cancel all subsequent strikes.
*/
* If no target specified, or the specified target was the last of this move's
* targets, completely cancel all subsequent strikes.
*/
if (!target || this.targets.length === 0 ) {
this.getUserPokemon()!.turnData.hitCount = 1; // TODO: is the bang correct here?
this.getUserPokemon()!.turnData.hitsLeft = 1; // TODO: is the bang correct here?
this.getUserPokemon()!.turnData.hitCount = 1; // TODO: is the bang correct here?
this.getUserPokemon()!.turnData.hitsLeft = 1; // TODO: is the bang correct here?
}
}

View File

@ -218,10 +218,10 @@ export class MovePhase extends BattlePhase {
}
/**
* Trigger pokemon type change before playing the move animation
* Will still change the user's type when using Roar, Whirlwind, Trick-or-Treat, and Forest's Curse,
* regardless of whether the move successfully executes or not.
*/
* Trigger pokemon type change before playing the move animation
* Will still change the user's type when using Roar, Whirlwind, Trick-or-Treat, and Forest's Curse,
* regardless of whether the move successfully executes or not.
*/
if (success || [Moves.ROAR, Moves.WHIRLWIND, Moves.TRICK_OR_TREAT, Moves.FORESTS_CURSE].includes(this.move.moveId)) {
applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove());
}
@ -254,7 +254,7 @@ export class MovePhase extends BattlePhase {
switch (this.pokemon.status.effect) {
case StatusEffect.PARALYSIS:
if (!this.pokemon.randSeedInt(4)) {
if (!this.pokemon.randSeedInt(4, undefined, "Paralysis chance")) {
activated = true;
this.cancelled = true;
}
@ -266,7 +266,7 @@ export class MovePhase extends BattlePhase {
this.cancelled = activated;
break;
case StatusEffect.FREEZE:
healed = !!this.move.getMove().findAttr(attr => attr instanceof HealStatusEffectAttr && attr.selfTarget && attr.isOfEffect(StatusEffect.FREEZE)) || !this.pokemon.randSeedInt(5);
healed = !!this.move.getMove().findAttr(attr => attr instanceof HealStatusEffectAttr && attr.selfTarget && attr.isOfEffect(StatusEffect.FREEZE)) || !this.pokemon.randSeedInt(5, undefined, "Chance to thaw out from freeze");
activated = !healed;
this.cancelled = activated;
break;

View File

@ -29,7 +29,7 @@ export class ObtainStatusEffectPhase extends PokemonPhase {
if (!pokemon?.status) {
if (pokemon?.trySetStatus(this.statusEffect, false, this.sourcePokemon)) {
if (this.cureTurn) {
pokemon.status!.cureTurn = this.cureTurn; // TODO: is this bang correct?
pokemon.status!.cureTurn = this.cureTurn; // TODO: is this bang correct?
}
pokemon.updateInfo(true);
new CommonBattleAnim(CommonAnim.POISON + (this.statusEffect! - 1), pokemon).play(this.scene, () => {

View File

@ -24,7 +24,7 @@ export class PartyHealPhase extends BattlePhase {
pokemon.hp = pokemon.getMaxHp();
pokemon.resetStatus();
for (const move of pokemon.moveset) {
move!.ppUsed = 0; // TODO: is this bang correct?
move!.ppUsed = 0; // TODO: is this bang correct?
}
pokemon.updateInfo(true);
}

View File

@ -52,6 +52,7 @@ export class ScanIvsPhase extends PokemonPhase {
if (!this.scene.hideIvs) {
this.scene.ui.showText(i18next.t("battle:ivScannerUseQuestion", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => {
this.scene.ui.setMode(Mode.CONFIRM, () => {
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, "IV Scanner → " + LoggerTools.enemyPokeName(this.scene, pokemon))
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.clearText();
new CommonBattleAnim(CommonAnim.LOCK_ON, pokemon, pokemon).play(this.scene, () => {

View File

@ -30,8 +30,8 @@ export class SelectBiomePhase extends BattlePhase {
};
if ((this.scene.gameMode.isClassic && this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex + 9))
|| (this.scene.gameMode.isDaily && this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex))
|| (this.scene.gameMode.hasShortBiomes && !(this.scene.currentBattle.waveIndex % 50))) {
|| (this.scene.gameMode.isDaily && this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex))
|| (this.scene.gameMode.hasShortBiomes && !(this.scene.currentBattle.waveIndex % 50))) {
setNextBiome(Biome.END);
} else if (this.scene.gameMode.hasRandomBiomes) {
setNextBiome(this.generateNextBiome());

View File

@ -1,6 +1,6 @@
import BattleScene from "#app/battle-scene.js";
import { ModifierTier } from "#app/modifier/modifier-tier.js";
import { regenerateModifierPoolThresholds, ModifierTypeOption, ModifierType, getPlayerShopModifierTypeOptionsForWave, PokemonModifierType, FusePokemonModifierType, PokemonMoveModifierType, TmModifierType, RememberMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, ModifierPoolType, getPlayerModifierTypeOptions } from "#app/modifier/modifier-type.js";
import { regenerateModifierPoolThresholds, ModifierTypeOption, ModifierType, getPlayerShopModifierTypeOptionsForWave, PokemonModifierType, FusePokemonModifierType, PokemonMoveModifierType, TmModifierType, RememberMoveModifierType, PokemonPpRestoreModifierType, PokemonPpUpModifierType, ModifierPoolType, getPlayerModifierTypeOptions, getPartyLuckValue, getLuckString, setEvioliteOverride, calculateItemConditions } from "#app/modifier/modifier-type.js";
import { ExtraModifierModifier, Modifier, PokemonHeldItemModifier } from "#app/modifier/modifier.js";
import ModifierSelectUiHandler, { SHOP_OPTIONS_ROW_LIMIT } from "#app/ui/modifier-select-ui-handler.js";
import PartyUiHandler, { PartyUiMode, PartyOption } from "#app/ui/party-ui-handler.js";
@ -13,13 +13,70 @@ import * as LoggerTools from "../logger";
export class SelectModifierPhase extends BattlePhase {
private rerollCount: integer;
private modifierTiers: ModifierTier[];
private modifierTiers: ModifierTier[] = [];
private modifierPredictions: ModifierTypeOption[][] = []
private predictionCost: integer = 0;
private costTiers: integer[] = [];
constructor(scene: BattleScene, rerollCount: integer = 0, modifierTiers?: ModifierTier[]) {
constructor(scene: BattleScene, rerollCount: integer = 0, modifierTiers?: ModifierTier[], predictionCost?: integer, modifierPredictions?: ModifierTypeOption[][]) {
super(scene);
this.rerollCount = rerollCount;
this.modifierTiers = modifierTiers!; // TODO: is this bang correct?
this.modifierPredictions = []
if (modifierPredictions != undefined) {
this.modifierPredictions = modifierPredictions;
}
this.predictionCost = 0
this.costTiers = []
}
generateSelection(rerollOverride: integer, modifierOverride?: integer, eviolite?: boolean) {
//const STATE = Phaser.Math.RND.state() // Store RNG state
//console.log("====================")
//console.log(" Reroll Prediction: " + rerollOverride)
const party = this.scene.getParty();
if (eviolite) {
setEvioliteOverride("on")
} else {
setEvioliteOverride("off")
}
regenerateModifierPoolThresholds(party, this.getPoolType(), rerollOverride);
const modifierCount = new Utils.IntegerHolder(3);
if (this.isPlayer()) {
this.scene.applyModifiers(ExtraModifierModifier, true, modifierCount);
}
if (modifierOverride) {
//modifierCount.value = modifierOverride
}
const typeOptions: ModifierTypeOption[] = this.getModifierTypeOptions(modifierCount.value, true, true);
setEvioliteOverride("")
typeOptions.forEach((option, idx) => {
option.netprice = this.predictionCost
if (option.type.name == "Nugget") {
option.netprice -= this.scene.getWaveMoneyAmount(1)
}
if (option.type.name == "Big Nugget") {
option.netprice -= this.scene.getWaveMoneyAmount(2.5)
}
if (option.type.name == "Relic Gold") {
option.netprice -= this.scene.getWaveMoneyAmount(10)
}
//console.log(option.type.name)
})
//console.log("====================")
if (eviolite) {
this.modifierPredictions[rerollOverride].forEach((m, i) => {
if (m.type.name != typeOptions[i].type.name) {
m.eviolite = typeOptions[i].type
}
})
} else {
this.modifierPredictions[rerollOverride] = typeOptions
}
this.costTiers.push(this.predictionCost)
this.predictionCost += this.getRerollCost(typeOptions, false, rerollOverride)
//Phaser.Math.RND.state(STATE) // Restore RNG state like nothing happened
}
start() {
@ -27,6 +84,21 @@ export class SelectModifierPhase extends BattlePhase {
if (!this.rerollCount) {
this.updateSeed();
console.log(calculateItemConditions(this.scene.getParty(), false, true))
console.log("\n\nPerforming reroll prediction (Eviolite OFF)\n\n\n")
this.predictionCost = 0
this.costTiers = []
for (var idx = 0; idx < 10 && this.predictionCost < this.scene.money; idx++) {
this.generateSelection(idx, undefined, false)
}
this.updateSeed();
console.log("\n\nPerforming reroll prediction (Eviolite ON)\n\n\n")
this.predictionCost = 0
this.costTiers = []
for (var idx = 0; idx < 10 && this.predictionCost < this.scene.money; idx++) {
this.generateSelection(idx, undefined, true)
}
this.updateSeed();
} else {
this.scene.reroll = false;
}
@ -43,10 +115,11 @@ export class SelectModifierPhase extends BattlePhase {
if (rowCursor < 0 || cursor < 0) {
this.scene.ui.showText(i18next.t("battle:skipItemQuestion"), null, () => {
this.scene.ui.setOverlayMode(Mode.CONFIRM, () => {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, "Skip taking items")
this.scene.ui.revertMode();
this.scene.ui.setMode(Mode.MESSAGE);
super.end();
}, () => this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)));
}, () => this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers), this.modifierPredictions));
});
return false;
}
@ -55,30 +128,72 @@ export class SelectModifierPhase extends BattlePhase {
switch (rowCursor) {
case 0:
switch (cursor) {
case 0:
const rerollCost = this.getRerollCost(typeOptions, this.scene.lockModifierTiers);
if (this.scene.money < rerollCost) {
this.scene.ui.playError();
return false;
} else {
this.scene.reroll = true;
this.scene.unshiftPhase(new SelectModifierPhase(this.scene, this.rerollCount + 1, typeOptions.map(o => o.type?.tier).filter(t => t !== undefined) as ModifierTier[]));
this.scene.ui.clearText();
this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end());
if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) {
this.scene.money -= rerollCost;
this.scene.updateMoneyText();
this.scene.animateMoneyChanged(false);
case 0:
const rerollCost1 = this.getRerollCost(typeOptions, this.scene.lockModifierTiers);
if (this.scene.money < rerollCost1) {
this.scene.ui.playError();
return false;
} else {
this.scene.reroll = true;
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, "Reroll" + (this.scene.lockModifierTiers ? " (Locked)" : ""))
this.scene.unshiftPhase(new SelectModifierPhase(this.scene, this.rerollCount + 1, typeOptions.map(o => o.type?.tier).filter(t => t !== undefined) as ModifierTier[], this.predictionCost, this.modifierPredictions));
this.scene.ui.clearText();
this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end());
if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) {
this.scene.money -= rerollCost1;
this.scene.updateMoneyText();
this.scene.animateMoneyChanged(false);
this.scene.playSound("se/buy");
}
}
this.scene.playSound("se/buy");
}
break;
break;
case 0.1:
const rerollCost2 = this.getRerollCost(this.modifierPredictions[this.rerollCount], false);
if (this.scene.money < rerollCost2) {
this.scene.ui.playError();
return false;
} else {
this.scene.reroll = true;
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, "+1 Reroll")
this.scene.unshiftPhase(new SelectModifierPhase(this.scene, this.rerollCount + 1, typeOptions.map(o => o.type!.tier), this.predictionCost, this.modifierPredictions));
this.scene.ui.clearText();
this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end());
if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) {
this.scene.money -= rerollCost2;
this.scene.updateMoneyText();
this.scene.animateMoneyChanged(false);
this.scene.playSound("se/buy");
}
}
break;
case 0.2:
const rerollCost3 = this.getRerollCost(this.modifierPredictions[this.rerollCount + 1], false);
{
this.scene.reroll = true;
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, "-1 Reroll")
this.scene.unshiftPhase(new SelectModifierPhase(this.scene, this.rerollCount - 1, typeOptions.map(o => o.type!.tier), this.predictionCost, this.modifierPredictions));
this.scene.ui.clearText();
this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end());
if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) {
this.scene.money -= rerollCost3;
this.scene.updateMoneyText();
this.scene.animateMoneyChanged(false);
this.scene.playSound("se/buy");
}
}
break;
case 1:
this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER, -1, (fromSlotIndex: integer, itemIndex: integer, itemQuantity: integer, toSlotIndex: integer) => {
this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER, -1, (fromSlotIndex: integer, itemIndex: integer, itemQuantity: integer, toSlotIndex: integer, isAll: boolean, isFirst: boolean) => {
if (toSlotIndex !== undefined && fromSlotIndex < 6 && toSlotIndex < 6 && fromSlotIndex !== toSlotIndex && itemIndex > -1) {
const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier
&& m.isTransferrable && m.pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[];
&& m.isTransferrable && m.pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[];
const itemModifier = itemModifiers[itemIndex];
if (isAll) {
if (isFirst)
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, `Transfer ALL | ${LoggerTools.playerPokeName(this.scene, fromSlotIndex)}${LoggerTools.playerPokeName(this.scene, toSlotIndex)}`)
} else {
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, `Transfer ${itemModifier.type.name + (itemQuantity == itemModifier.getStackCount() ? "" : " x" + itemQuantity)} | ${LoggerTools.playerPokeName(this.scene, fromSlotIndex)}${LoggerTools.playerPokeName(this.scene, toSlotIndex)}`)
}
this.scene.tryTransferHeldItemModifier(itemModifier, party[toSlotIndex], true, itemQuantity);
} else {
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
@ -153,6 +268,7 @@ export class SelectModifierPhase extends BattlePhase {
if (modifierType instanceof FusePokemonModifierType) {
this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.SPLICE, -1, (fromSlotIndex: integer, spliceSlotIndex: integer) => {
if (spliceSlotIndex !== undefined && fromSlotIndex < 6 && spliceSlotIndex < 6 && fromSlotIndex !== spliceSlotIndex) {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, modifierType.name + " → " + this.scene.getParty()[fromSlotIndex].name + " + " + this.scene.getParty()[spliceSlotIndex].name)
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => {
const modifier = modifierType.newModifier(party[fromSlotIndex], party[spliceSlotIndex])!; //TODO: is the bang correct?
applyModifier(modifier, true);
@ -182,6 +298,15 @@ export class SelectModifierPhase extends BattlePhase {
? modifierType.newModifier(party[slotIndex])
: modifierType.newModifier(party[slotIndex], option as integer)
: modifierType.newModifier(party[slotIndex], option - PartyOption.MOVE_1);
if (isPpRestoreModifier) {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, modifierType.name + " → " + this.scene.getParty()[slotIndex].name + " → " + this.scene.getParty()[slotIndex].moveset[option - PartyOption.MOVE_1]!.getName())
} else if (isRememberMoveModifier) {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, modifierType.name + " → " + this.scene.getParty()[slotIndex].name)
} else if (isTmModifier) {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, modifierType.name + " → " + this.scene.getParty()[slotIndex].name)
} else {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, modifierType.name + " → " + this.scene.getParty()[slotIndex].name)
}
applyModifier(modifier!, true); // TODO: is the bang correct?
});
} else {
@ -190,11 +315,91 @@ export class SelectModifierPhase extends BattlePhase {
}, pokemonModifierType.selectFilter, modifierType instanceof PokemonMoveModifierType ? (modifierType as PokemonMoveModifierType).moveSelectFilter : undefined, tmMoveId, isPpRestoreModifier);
}
} else {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, modifierType!.name)
applyModifier(modifierType!.newModifier()!); // TODO: is the bang correct?
}
return !cost!;// TODO: is the bang correct?
};
if (this.rerollCount == 0) {
if (true) {
this.modifierPredictions.forEach((mp, r) => {
// costTiers
console.log("Rerolls: " + r + (this.costTiers[r] != 0 ? " - ₽" + this.costTiers[r] : ""))
mp.forEach((m, i) => {
console.log(" " + m.type!.name + (m.netprice != this.costTiers[r] ? " - ₽" + m.netprice : ""))
if (m.eviolite) {
console.log(" With Eviolite unlocked: " + m.eviolite.name)
}
if (m.alternates) {
//console.log(m.alternates)
let showedLuckFlag = false
for (var j = 0, currentTier = m.type!.tier; j < m.alternates.length; j++) {
if (m.alternates[j] > currentTier) {
currentTier = m.alternates[j]
if (m.advancedAlternates) {
if (!showedLuckFlag) {
showedLuckFlag = true
console.log(" Your luck: " + getPartyLuckValue(party) + " (" + getLuckString(getPartyLuckValue(party)) + ")")
}
console.log(" At " + j + " luck (" + getLuckString(j) + "): " + m.advancedAlternates[j])
} else {
if (!showedLuckFlag) {
showedLuckFlag = true
console.log(" Your luck: " + getPartyLuckValue(party) + " (" + getLuckString(getPartyLuckValue(party)) + ")")
}
console.log(" At " + j + " luck (" + getLuckString(j) + "): " + LoggerTools.tierNames[currentTier] + "-tier item (failed to generate item)")
}
}
}
} else {
//console.log(" No alt-luck data")
}
})
})
} else {
let modifierList: string[] = []
this.modifierPredictions.forEach((mp, r) => {
//console.log("Rerolls: " + r)
mp.forEach((m, i) => {
modifierList.push(m.type!.name + (r > 0 ? " (x" + r + ")" : ""))
//console.log(" " + m.type!.name)
if (m.eviolite) {
modifierList.push(m.type!.name + (r > 0 ? " (x" + r + " with eviolite unlocked)" : " (With eviolite unlocked)"))
//console.log(" With Eviolite unlocked: " + m.eviolite.name)
}
if (m.alternates) {
//console.log(m.alternates)
let showedLuckFlag = false
for (var j = 0, currentTier = m.type!.tier; j < m.alternates.length; j++) {
if (m.alternates[j] > currentTier) {
currentTier = m.alternates[j]
if (m.advancedAlternates) {
if (!showedLuckFlag) {
showedLuckFlag = true
console.log(" Your luck: " + getPartyLuckValue(party) + " (" + getLuckString(getPartyLuckValue(party)) + ")")
}
console.log(" At " + j + " luck (" + getLuckString(j) + "): " + m.advancedAlternates[j])
} else {
if (!showedLuckFlag) {
showedLuckFlag = true
console.log(" Your luck: " + getPartyLuckValue(party) + " (" + getLuckString(getPartyLuckValue(party)) + ")")
}
console.log(" At " + j + " luck (" + getLuckString(j) + "): " + LoggerTools.tierNames[currentTier] + "-tier item (failed to generate item)")
}
}
}
} else {
//console.log(" No alt-luck data")
}
})
})
modifierList.sort()
modifierList.forEach(v => {
console.log(v)
})
}
}
this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers));
}
@ -206,7 +411,7 @@ export class SelectModifierPhase extends BattlePhase {
return true;
}
getRerollCost(typeOptions: ModifierTypeOption[], lockRarities: boolean): number {
getRerollCost(typeOptions: ModifierTypeOption[], lockRarities: boolean, rerollOverride?: integer): integer {
let baseValue = 0;
if (Overrides.WAIVE_ROLL_FEE_OVERRIDE) {
return baseValue;
@ -218,15 +423,15 @@ export class SelectModifierPhase extends BattlePhase {
} else {
baseValue = 250;
}
return Math.min(Math.ceil(this.scene.currentBattle.waveIndex / 10) * baseValue * Math.pow(2, this.rerollCount), Number.MAX_SAFE_INTEGER);
return Math.min(Math.ceil(this.scene.currentBattle.waveIndex / 10) * baseValue * Math.pow(2, (rerollOverride != undefined ? rerollOverride : this.rerollCount)), Number.MAX_SAFE_INTEGER);
}
getPoolType(): ModifierPoolType {
return ModifierPoolType.PLAYER;
}
getModifierTypeOptions(modifierCount: integer): ModifierTypeOption[] {
return getPlayerModifierTypeOptions(modifierCount, this.scene.getParty(), this.scene.lockModifierTiers ? this.modifierTiers : undefined);
getModifierTypeOptions(modifierCount: integer, shutUpBro?: boolean, calcAllLuck?: boolean, advanced?: boolean): ModifierTypeOption[] {
return getPlayerModifierTypeOptions(modifierCount, this.scene.getParty(), this.scene.lockModifierTiers ? this.modifierTiers : undefined, this.scene, shutUpBro, calcAllLuck, advanced);
}
addModifier(modifier: Modifier): Promise<boolean> {

View File

@ -22,10 +22,10 @@ export class SelectTargetPhase extends PokemonPhase {
this.scene.currentBattle.turnCommands[this.fieldIndex] = null;
this.scene.unshiftPhase(new CommandPhase(this.scene, this.fieldIndex));
} else {
turnCommand!.targets = targets; //TODO: is the bang correct here?
turnCommand!.targets = targets; //TODO: is the bang correct here?
}
if (turnCommand?.command === Command.BALL && this.fieldIndex) {
this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true; //TODO: is the bang correct here?
this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true; //TODO: is the bang correct here?
}
this.end();
});

View File

@ -170,7 +170,7 @@ export class StatChangePhase extends PokemonPhase {
getRandomStat(): BattleStat {
const allStats = Utils.getEnumValues(BattleStat);
return this.getPokemon() ? allStats[this.getPokemon()!.randSeedInt(BattleStat.SPD + 1)] : BattleStat.ATK; // TODO: return default ATK on random? idk...
return this.getPokemon() ? allStats[this.getPokemon()!.randSeedInt(BattleStat.SPD + 1, undefined, "Randomly selecting a stat")] : BattleStat.ATK; // TODO: return default ATK on random? idk...
}
aggregateStatChanges(random: boolean = false): void {

View File

@ -30,8 +30,8 @@ export class SummonPhase extends PartyMemberPokemonPhase {
}
/**
* Sends out a Pokemon before the battle begins and shows the appropriate messages
*/
* Sends out a Pokemon before the battle begins and shows the appropriate messages
*/
preSummon(): void {
const partyMember = this.getPokemon();
// If the Pokemon about to be sent out is fainted or illegal under a challenge, switch to the first non-fainted legal Pokemon

View File

@ -15,14 +15,14 @@ export class SwitchPhase extends BattlePhase {
private doReturn: boolean;
/**
* Creates a new SwitchPhase
* @param scene {@linkcode BattleScene} Current battle scene
* @param fieldIndex Field index to switch out
* @param isModal Indicates if the switch should be forced (true) or is
* optional (false).
* @param doReturn Indicates if the party member on the field should be
* recalled to ball or has already left the field. Passed to {@linkcode SwitchSummonPhase}.
*/
* Creates a new SwitchPhase
* @param scene {@linkcode BattleScene} Current battle scene
* @param fieldIndex Field index to switch out
* @param isModal Indicates if the switch should be forced (true) or is
* optional (false).
* @param doReturn Indicates if the party member on the field should be
* recalled to ball or has already left the field. Passed to {@linkcode SwitchSummonPhase}.
*/
constructor(scene: BattleScene, fieldIndex: integer, isModal: boolean, doReturn: boolean) {
super(scene);
@ -36,6 +36,8 @@ export class SwitchPhase extends BattlePhase {
// Skip modal switch if impossible (no remaining party members that aren't in battle)
if (this.isModal && !this.scene.getParty().filter(p => p.isAllowedInBattle() && !p.isActive(true)).length) {
LoggerTools.isPreSwitch.value = false;
LoggerTools.isFaintSwitch.value = false;
return super.end();
}
@ -50,6 +52,8 @@ export class SwitchPhase extends BattlePhase {
// Check if there is any space still in field
if (this.isModal && this.scene.getPlayerField().filter(p => p.isAllowedInBattle() && p.isActive(true)).length >= this.scene.currentBattle.getBattlerCount()) {
LoggerTools.isPreSwitch.value = false;
LoggerTools.isFaintSwitch.value = false;
return super.end();
}
@ -57,9 +61,19 @@ export class SwitchPhase extends BattlePhase {
const fieldIndex = this.scene.currentBattle.getBattlerCount() === 1 || this.scene.getParty().filter(p => p.isAllowedInBattle()).length > 1 ? this.fieldIndex : 0;
this.scene.ui.setMode(Mode.PARTY, this.isModal ? PartyUiMode.FAINT_SWITCH : PartyUiMode.POST_BATTLE_SWITCH, fieldIndex, (slotIndex: integer, option: PartyOption) => {
if (this.isModal) {console.error("Forced Switch Detected")}
if (slotIndex >= this.scene.currentBattle.getBattlerCount() && slotIndex < 6) {
if (LoggerTools.isPreSwitch.value) {
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, "Pre-switch" + (option == PartyOption.PASS_BATON ? "+ Baton" : "") + " " + LoggerTools.playerPokeName(this.scene, fieldIndex) + " to " + LoggerTools.playerPokeName(this.scene, slotIndex))
} else if (LoggerTools.isFaintSwitch.value) {
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, (option == PartyOption.PASS_BATON ? "Baton" : "Send") + " in " + LoggerTools.playerPokeName(this.scene, slotIndex))
} else {
//LoggerTools.Actions[this.scene.getParty()[fieldIndex].getBattlerIndex()] += " to " + LoggerTools.playerPokeName(this.scene, slotIndex)
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, `Switch ${LoggerTools.playerPokeName(this.scene, fieldIndex)} to ${LoggerTools.playerPokeName(this.scene, slotIndex)}`)
}
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, fieldIndex, slotIndex, this.doReturn, option === PartyOption.PASS_BATON));
}
LoggerTools.isPreSwitch.value = false;
this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end());
}, PartyUiHandler.FilterNonFainted);
}

View File

@ -21,14 +21,14 @@ export class SwitchSummonPhase extends SummonPhase {
private lastPokemon: Pokemon;
/**
* Constructor for creating a new SwitchSummonPhase
* @param scene {@linkcode BattleScene} the scene the phase is associated with
* @param fieldIndex integer representing position on the battle field
* @param slotIndex integer for the index of pokemon (in party of 6) to switch into
* @param doReturn boolean whether to render "comeback" dialogue
* @param batonPass boolean if the switch is from baton pass
* @param player boolean if the switch is from the player
*/
* Constructor for creating a new SwitchSummonPhase
* @param scene {@linkcode BattleScene} the scene the phase is associated with
* @param fieldIndex integer representing position on the battle field
* @param slotIndex integer for the index of pokemon (in party of 6) to switch into
* @param doReturn boolean whether to render "comeback" dialogue
* @param batonPass boolean if the switch is from baton pass
* @param player boolean if the switch is from the player
*/
constructor(scene: BattleScene, fieldIndex: integer, slotIndex: integer, doReturn: boolean, batonPass: boolean, player?: boolean) {
super(scene, fieldIndex, player !== undefined ? player : true);
@ -99,7 +99,7 @@ export class SwitchSummonPhase extends SummonPhase {
(this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.transferTagsBySourceId(this.lastPokemon.id, switchedInPokemon.id));
if (!this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedInPokemon.id)) {
const batonPassModifier = this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier
&& (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id) as SwitchEffectTransferModifier;
&& (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id) as SwitchEffectTransferModifier;
if (batonPassModifier && !this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedInPokemon.id)) {
this.scene.tryTransferHeldItemModifier(batonPassModifier, switchedInPokemon, false);
}

View File

@ -22,6 +22,8 @@ import { SelectChallengePhase } from "./select-challenge-phase";
import { SelectStarterPhase } from "./select-starter-phase";
import { SummonPhase } from "./summon-phase";
import * as LoggerTools from "../logger";
import { Biome } from "#app/enums/biome.js";
import { GameDataType } from "#app/enums/game-data-type.js";
export class TitlePhase extends Phase {
@ -35,20 +37,68 @@ export class TitlePhase extends Phase {
this.loaded = false;
}
setBiomeByType(biome: Biome, override?: boolean): void {
if (!this.scene.menuChangesBiome && !override)
return;
this.scene.arenaBg.setTexture(`${getBiomeKey(biome)}_bg`);
}
setBiomeByName(biome: string, override?: boolean): void {
if (!this.scene.menuChangesBiome && !override)
return;
this.scene.arenaBg.setTexture(`${getBiomeKey(Utils.getEnumValues(Biome)[Utils.getEnumKeys(Biome).indexOf(biome)])}_bg`);
}
setBiomeByFile(sessionData: SessionSaveData, override?: boolean): void {
if (!this.scene.menuChangesBiome && !override)
return;
this.scene.arenaBg.setTexture(`${getBiomeKey(sessionData.arena.biome)}_bg`);
}
confirmSlot = (message: string, slotFilter: (i: integer) => boolean, callback: (i: integer) => void) => {
const p = this;
this.scene.ui.revertMode();
this.scene.ui.showText(message, null, () => {
const config: OptionSelectConfig = {
options: new Array(5).fill(null).map((_, i) => i).filter(slotFilter).map(i => {
var data = LoggerTools.parseSlotData(i)
return {
//label: `${i18next.t("menuUiHandler:slot", {slotNumber: i+1})}`,
label: (data ? `${i18next.t("menuUiHandler:slot", {slotNumber: i+1})}${data.description.substring(1)}` : `${i18next.t("menuUiHandler:slot", {slotNumber: i+1})}`),
handler: () => {
callback(i);
this.scene.ui.revertMode();
this.scene.ui.showText("", 0);
return true;
}
};
}).concat([{
label: i18next.t("menuUiHandler:cancel"),
handler: () => {
p.callEnd()
return true
}
}]),
//xOffset: 98
};
this.scene.ui.setOverlayMode(Mode.MENU_OPTION_SELECT, config);
});
};
start(): void {
super.start();
//console.log(LoggerTools.importDocument(JSON.stringify(LoggerTools.newDocument())))
this.scene.ui.clearText();
this.scene.ui.fadeIn(250);
this.scene.playBgm("title", true);
this.scene.biomeChangeMode = false
this.scene.gameData.getSession(loggedInUser?.lastSessionSlot ?? -1).then(sessionData => {
if (sessionData) {
this.lastSessionData = sessionData;
const biomeKey = getBiomeKey(sessionData.arena.biome);
const bgTexture = `${biomeKey}_bg`;
this.scene.arenaBg.setTexture(bgTexture);
this.setBiomeByFile(sessionData, true)
this.setBiomeByType(Biome.END)
}
this.showOptions();
}).catch(err => {
@ -57,20 +107,245 @@ export class TitlePhase extends Phase {
});
}
showOptions(): void {
getLastSave(log?: boolean, dailyOnly?: boolean, noDaily?: boolean): SessionSaveData | undefined {
var saves: Array<Array<any>> = [];
for (var i = 0; i < 5; i++) {
var s = LoggerTools.parseSlotData(i);
if (s != undefined) {
if ((!noDaily && !dailyOnly) || (s.gameMode == GameModes.DAILY && dailyOnly) || (s.gameMode != GameModes.DAILY && noDaily)) {
saves.push([i, s, s.timestamp]);
}
}
}
saves.sort((a, b): integer => {return b[2] - a[2]})
if (log) console.log(saves)
if (saves == undefined) return undefined;
if (saves[0] == undefined) return undefined;
return saves[0][1]
}
getLastSavesOfEach(log?: boolean): SessionSaveData[] | undefined {
var saves: Array<Array<SessionSaveData | number>> = [];
for (var i = 0; i < 5; i++) {
var s = LoggerTools.parseSlotData(i);
if (s != undefined) {
saves.push([i, s, s.timestamp]);
}
}
saves.sort((a, b): integer => {return (b[2] as number) - (a[2] as number)})
if (log) console.log(saves)
if (saves == undefined) return undefined;
if (saves[0] == undefined) return undefined;
var validSaves: Array<Array<SessionSaveData | number>> = []
var hasNormal = false;
var hasDaily = false;
for (var i = 0; i < saves.length; i++) {
if ((saves[i][1] as SessionSaveData).gameMode == GameModes.DAILY && !hasDaily) {
hasDaily = true;
validSaves.push(saves[i])
}
if ((saves[i][1] as SessionSaveData).gameMode != GameModes.DAILY && !hasNormal) {
hasNormal = true;
validSaves.push(saves[i])
}
}
console.log(saves, validSaves)
if (validSaves.length == 0)
return undefined;
return validSaves.map(f => f[1] as SessionSaveData);
}
getSaves(log?: boolean, dailyOnly?: boolean): SessionSaveData[] | undefined {
var saves: Array<Array<any>> = [];
for (var i = 0; i < 5; i++) {
var s = LoggerTools.parseSlotData(i);
if (s != undefined) {
if (!dailyOnly || s.gameMode == GameModes.DAILY) {
saves.push([i, s, s.timestamp]);
}
}
}
saves.sort((a, b): integer => {return b[2] - a[2]})
if (log) console.log(saves)
if (saves == undefined) return undefined;
return saves.map(f => f[1]);
}
getSavesUnsorted(log?: boolean, dailyOnly?: boolean): SessionSaveData[] | undefined {
var saves: Array<Array<any>> = [];
for (var i = 0; i < 5; i++) {
var s = LoggerTools.parseSlotData(i);
if (s != undefined) {
if (!dailyOnly || s.gameMode == GameModes.DAILY) {
saves.push([i, s, s.timestamp]);
}
}
}
if (log) console.log(saves)
if (saves == undefined) return undefined;
return saves.map(f => f[1]);
}
callEnd(): boolean {
this.scene.clearPhaseQueue();
this.scene.pushPhase(new TitlePhase(this.scene));
super.end();
return true;
}
showLoggerOptions(txt: string, options: OptionSelectItem[]): boolean {
this.scene.ui.showText("Export or clear game logs.", null, () => this.scene.ui.setOverlayMode(Mode.OPTION_SELECT, { options: options }));
return true;
}
logMenu(): boolean {
const options: OptionSelectItem[] = [];
if (loggedInUser && loggedInUser.lastSessionSlot > -1) {
LoggerTools.getLogs()
for (var i = 0; i < LoggerTools.logs.length; i++) {
if (localStorage.getItem(LoggerTools.logs[i][1]) != null) {
options.push(LoggerTools.generateOption(i, this.getSaves()) as OptionSelectItem)
} else {
//options.push(LoggerTools.generateAddOption(i, this.scene, this))
}
}
options.push({
label: "Delete all",
handler: () => {
for (var i = 0; i < LoggerTools.logs.length; i++) {
if (localStorage.getItem(LoggerTools.logs[i][1]) != null) {
localStorage.removeItem(LoggerTools.logs[i][1])
}
}
this.scene.clearPhaseQueue();
this.scene.pushPhase(new TitlePhase(this.scene));
super.end();
return true;
}
}, {
label: i18next.t("menu:cancel"),
handler: () => {
this.scene.clearPhaseQueue();
this.scene.pushPhase(new TitlePhase(this.scene));
super.end();
return true;
}
});
this.scene.ui.showText("Export or clear game logs.", null, () => this.scene.ui.setOverlayMode(Mode.OPTION_SELECT, { options: options }));
return true;
}
logRenameMenu(): boolean {
const options: OptionSelectItem[] = [];
LoggerTools.getLogs()
this.setBiomeByType(Biome.FACTORY)
for (var i = 0; i < LoggerTools.logs.length; i++) {
if (localStorage.getItem(LoggerTools.logs[i][1]) != null) {
options.push(LoggerTools.generateEditOption(this.scene, i, this.getSaves(), this) as OptionSelectItem)
} else {
//options.push(LoggerTools.generateAddOption(i, this.scene, this))
}
}
options.push({
label: "Delete all",
handler: () => {
for (var i = 0; i < LoggerTools.logs.length; i++) {
if (localStorage.getItem(LoggerTools.logs[i][1]) != null) {
localStorage.removeItem(LoggerTools.logs[i][1])
}
}
this.scene.clearPhaseQueue();
this.scene.pushPhase(new TitlePhase(this.scene));
super.end();
return true;
}
}, {
label: i18next.t("menu:cancel"),
handler: () => {
this.scene.clearPhaseQueue();
this.scene.pushPhase(new TitlePhase(this.scene));
super.end();
return true;
}
});
this.scene.ui.showText("Export, rename, or delete logs.", null, () => this.scene.ui.setOverlayMode(Mode.OPTION_SELECT, { options: options }));
return true;
}
showOptions(): void {
this.scene.biomeChangeMode = true
const options: OptionSelectItem[] = [];
if (false)
if (loggedInUser && loggedInUser!.lastSessionSlot > -1) {
options.push({
label: i18next.t("continue", {ns: "menu"}),
handler: () => {
this.loadSaveSlot(this.lastSessionData || !loggedInUser ? -1 : loggedInUser.lastSessionSlot);
this.loadSaveSlot(this.lastSessionData ? -1 : loggedInUser!.lastSessionSlot);
return true;
}
});
}
// Replaces 'Continue' with all Daily Run saves, sorted by when they last saved
// If there are no daily runs, it instead shows the most recently saved run
// If this fails too, there are no saves, and the option does not appear
var lastsaves = this.getSaves(false, true); // Gets all Daily Runs sorted by last play time
var lastsave = this.getLastSave(); // Gets the last save you played
var ls1 = this.getLastSave(false, true)
var ls2 = this.getLastSavesOfEach()
this.scene.quickloadDisplayMode = "Both"
switch (true) {
case (this.scene.quickloadDisplayMode == "Daily" && ls1 != undefined):
options.push({
label: (ls1.description ? ls1.description : "[???]"),
handler: () => {
this.loadSaveSlot(ls1!.slot);
return true;
}
})
break;
case this.scene.quickloadDisplayMode == "Dailies" && lastsaves != undefined && ls1 != undefined:
lastsaves.forEach(lastsave1 => {
options.push({
label: (lastsave1.description ? lastsave1.description : "[???]"),
handler: () => {
this.loadSaveSlot(lastsave1.slot);
return true;
}
})
})
break;
case lastsave != undefined && (this.scene.quickloadDisplayMode == "Latest" || ((this.scene.quickloadDisplayMode == "Daily" || this.scene.quickloadDisplayMode == "Dailies") && ls1 == undefined)):
options.push({
label: (lastsave.description ? lastsave.description : "[???]"),
handler: () => {
this.loadSaveSlot(lastsave!.slot);
return true;
}
})
break;
case this.scene.quickloadDisplayMode == "Both" && ls2 != undefined:
ls2.forEach(lastsave2 => {
options.push({
label: (lastsave2.description ? lastsave2.description : "[???]"),
handler: () => {
this.loadSaveSlot(lastsave2.slot);
return true;
}
})
})
break;
default: // If set to "Off" or all above conditions failed
if (loggedInUser && loggedInUser.lastSessionSlot > -1) {
options.push({
label: i18next.t("continue", { ns: "menu"}),
handler: () => {
this.loadSaveSlot(this.lastSessionData ? -1 : loggedInUser!.lastSessionSlot);
return true;
}
});
}
break;
}
options.push({
label: i18next.t("menu:newGame"),
handler: () => {
this.scene.biomeChangeMode = false
this.setBiomeByType(Biome.TOWN)
const setModeAndEnd = (gameMode: GameModes) => {
this.gameMode = gameMode;
this.scene.ui.setMode(Mode.MESSAGE);
@ -110,6 +385,14 @@ export class TitlePhase extends Phase {
}
});
}
options.push({
label: i18next.t("menuUiHandler:importSession"),
handler: () => {
this.confirmSlot(i18next.t("menuUiHandler:importSlotSelect"), () => true, slotId => this.scene.gameData.importData(GameDataType.SESSION, slotId));
return true;
},
keepOpen: true
})
options.push({
label: i18next.t("menu:cancel"),
handler: () => {
@ -121,38 +404,88 @@ export class TitlePhase extends Phase {
});
this.scene.ui.showText(i18next.t("menu:selectGameMode"), null, () => this.scene.ui.setOverlayMode(Mode.OPTION_SELECT, { options: options }));
} else {
this.gameMode = GameModes.CLASSIC;
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.clearText();
this.end();
const options: OptionSelectItem[] = [
{
label: GameMode.getModeName(GameModes.CLASSIC),
handler: () => {
setModeAndEnd(GameModes.CLASSIC);
return true;
}
}
];
options.push({
label: i18next.t("menuUiHandler:importSession"),
handler: () => {
this.confirmSlot(i18next.t("menuUiHandler:importSlotSelect"), () => true, slotId => this.scene.gameData.importData(GameDataType.SESSION, slotId));
return true;
},
keepOpen: true
})
options.push({
label: i18next.t("menu:cancel"),
handler: () => {
this.scene.clearPhaseQueue();
this.scene.pushPhase(new TitlePhase(this.scene));
super.end();
return true;
}
});
this.scene.ui.showText(i18next.t("menu:selectGameMode"), null, () => this.scene.ui.setOverlayMode(Mode.OPTION_SELECT, { options: options }));
}
return true;
}
},
{
label: i18next.t("menu:loadGame"),
}, {
label: "Manage Logs",
handler: () => {
this.scene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD,
(slotId: integer) => {
if (slotId === -1) {
this.scene.biomeChangeMode = false
//return this.logRenameMenu()
this.scene.ui.setOverlayMode(Mode.LOG_HANDLER,
(k: string) => {
if (k === undefined) {
return this.showOptions();
}
this.loadSaveSlot(slotId);
console.log(k)
this.showOptions();
}, () => {
this.showOptions();
});
return true;
}
},
{
label: i18next.t("menu:dailyRun"),
}, {
label: "Manage Logs (Old Menu)",
handler: () => {
this.initDailyRun();
return this.logRenameMenu()
}
})
options.push({
label: i18next.t("menu:loadGame"),
handler: () => {
this.scene.biomeChangeMode = false
this.scene.ui.setOverlayMode(Mode.SAVE_SLOT, SaveSlotUiMode.LOAD,
(slotId: integer, autoSlot: integer) => {
if (slotId === -1) {
return this.showOptions();
}
this.loadSaveSlot(slotId, autoSlot);
});
return true;
},
keepOpen: true
},
{
}
})
if (false) {
options.push({
label: i18next.t("menu:dailyRun"),
handler: () => {
this.scene.biomeChangeMode = false
this.setupDaily();
return true;
},
keepOpen: true
})
}
options.push({
label: i18next.t("menu:settings"),
handler: () => {
this.scene.biomeChangeMode = false
this.scene.ui.setOverlayMode(Mode.SETTINGS);
return true;
},
@ -166,11 +499,11 @@ export class TitlePhase extends Phase {
this.scene.ui.setMode(Mode.TITLE, config);
}
loadSaveSlot(slotId: integer): void {
loadSaveSlot(slotId: integer, autoSlot?: integer): void {
this.scene.sessionSlotId = slotId > -1 || !loggedInUser ? slotId : loggedInUser.lastSessionSlot;
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.ui.resetModeChain();
this.scene.gameData.loadSession(this.scene, slotId, slotId === -1 ? this.lastSessionData : undefined).then((success: boolean) => {
this.scene.gameData.loadSession(this.scene, slotId, slotId === -1 ? this.lastSessionData : undefined, autoSlot).then((success: boolean) => {
if (success) {
this.loaded = true;
this.scene.ui.showText(i18next.t("menu:sessionSuccess"), null, () => this.end());
@ -218,7 +551,6 @@ export class TitlePhase extends Phase {
}
regenerateModifierPoolThresholds(party, ModifierPoolType.DAILY_STARTER);
const modifiers: Modifier[] = Array(3).fill(null).map(() => modifierTypes.EXP_SHARE().withIdFromFunc(modifierTypes.EXP_SHARE).newModifier())
.concat(Array(3).fill(null).map(() => modifierTypes.GOLDEN_EXP_CHARM().withIdFromFunc(modifierTypes.GOLDEN_EXP_CHARM).newModifier()))
.concat(getDailyRunStarterModifiers(party))
@ -257,8 +589,52 @@ export class TitlePhase extends Phase {
}
});
}
setupDaily(): void {
// TODO
var saves = this.getSaves()
var saveNames = new Array(5).fill("")
for (var i = 0; i < saves!.length; i++) {
saveNames[saves![i][0]] = saves![i][1].description
}
const ui = this.scene.ui
const confirmSlot = (message: string, slotFilter: (i: integer) => boolean, callback: (i: integer) => void) => {
ui.revertMode();
ui.showText(message, null, () => {
const config: OptionSelectConfig = {
options: new Array(5).fill(null).map((_, i) => i).filter(slotFilter).map(i => {
return {
label: (i+1) + " " + saveNames[i],
handler: () => {
callback(i);
ui.revertMode();
ui.showText("", 0);
return true;
}
};
}).concat([{
label: i18next.t("menuUiHandler:cancel"),
handler: () => {
ui.revertMode();
ui.showText("", 0);
return true;
}
}]),
xOffset: 98
};
ui.setOverlayMode(Mode.MENU_OPTION_SELECT, config);
});
};
ui.showText("This feature is incomplete.", null, () => {
this.scene.clearPhaseQueue();
this.scene.pushPhase(new TitlePhase(this.scene));
super.end();
return true;
})
return;
confirmSlot("Select a slot to replace.", () => true, slotId => this.scene.gameData.importData(GameDataType.SESSION, slotId));
}
end(): void {
this.scene.biomeChangeMode = false
if (!this.loaded && !this.scene.gameMode.isDaily) {
this.scene.arena.preloadBgm();
this.scene.gameMode = getGameMode(this.gameMode);

View File

@ -23,6 +23,8 @@ export class TurnEndPhase extends FieldPhase {
start() {
super.start();
this.scene.arenaFlyout.updateFieldText()
this.scene.currentBattle.incrementTurn(this.scene);
this.scene.eventTarget.dispatchEvent(new TurnEndEvent(this.scene.currentBattle.turn));

View File

@ -1,7 +1,7 @@
import BattleScene from "#app/battle-scene.js";
import { BattlerIndex } from "#app/battle.js";
import { TurnInitEvent } from "#app/events/battle-scene.js";
import { PlayerPokemon } from "#app/field/pokemon.js";
import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon.js";
import i18next from "i18next";
import { FieldPhase } from "./field-phase";
import { ToggleDoublePositionPhase } from "./toggle-double-position-phase";
@ -19,6 +19,9 @@ export class TurnInitPhase extends FieldPhase {
start() {
super.start();
// If the flyout was shown automatically, and the user hasn't made it go away, auto-hide it
this.scene.arenaFlyout.dismiss()
this.scene.getPlayerField().forEach(p => {
// If this pokemon is in play and evolved into something illegal under the current challenge, force a switch
if (p.isOnField() && !p.isAllowedInBattle()) {
@ -47,20 +50,86 @@ export class TurnInitPhase extends FieldPhase {
//this.scene.pushPhase(new MoveAnimTestPhase(this.scene));
this.scene.eventTarget.dispatchEvent(new TurnInitEvent());
this.scene.getField().forEach((pokemon, i) => {
if (pokemon?.isActive()) {
if (pokemon.isPlayer()) {
this.scene.currentBattle.addParticipant(pokemon as PlayerPokemon);
LoggerTools.enemyPlan[0] = ""
LoggerTools.enemyPlan[1] = ""
LoggerTools.enemyPlan[2] = ""
LoggerTools.enemyPlan[3] = ""
if (false) {
this.scene.getField().forEach((pokemon, i) => {
if (pokemon != undefined && pokemon != null)
console.log("Handle " + pokemon.name)
if (pokemon?.isActive()) {
if (pokemon.isPlayer()) {
this.scene.currentBattle.addParticipant(pokemon as PlayerPokemon);
} else {
console.log("Marked " + pokemon.name + " as used")
pokemon.usedInBattle = true;
pokemon.flyout.setText()
pokemon.getBattleInfo().iconsActive = true
}
pokemon.resetTurnData();
this.scene.pushPhase(pokemon.isPlayer() ? new CommandPhase(this.scene, i) : new EnemyCommandPhase(this.scene, i - BattlerIndex.ENEMY));
}
});
} else {
this.scene.getField().forEach((pokemon, i) => {
if (pokemon?.isActive()) {
if (!pokemon.isPlayer()) {
pokemon.flyout.setText()
pokemon.usedInBattle = true;
pokemon.getBattleInfo().iconsActive = true
pokemon.resetTurnData();
this.scene.pushPhase(pokemon.isPlayer() ? new CommandPhase(this.scene, i) : new EnemyCommandPhase(this.scene, i - BattlerIndex.ENEMY));
}
}
});
this.scene.getField().forEach((pokemon, i) => {
if (pokemon?.isActive()) {
if (pokemon.isPlayer()) {
this.scene.currentBattle.addParticipant(pokemon as PlayerPokemon);
pokemon.resetTurnData();
this.scene.pushPhase(pokemon.isPlayer() ? new CommandPhase(this.scene, i) : new EnemyCommandPhase(this.scene, i - BattlerIndex.ENEMY));
}
}
});
}
pokemon.resetTurnData();
this.scene.pushPhase(pokemon.isPlayer() ? new CommandPhase(this.scene, i) : new EnemyCommandPhase(this.scene, i - BattlerIndex.ENEMY));
var Pt = this.scene.getEnemyParty()
var Pt1: EnemyPokemon[] = []
var Pt2: EnemyPokemon[] = []
for (var i = 0; i < Pt.length; i++) {
if (i % 2 == 0) {
Pt1.push(Pt[i])
} else {
Pt2.push(Pt[i])
}
});
}
Pt.forEach((pokemon, i) => {
if (pokemon != undefined && pokemon.hp > 0 && pokemon.isActive())
if (pokemon.hasTrainer() || true) {
console.log(i)
if (pokemon.getFieldIndex() == 1 && pokemon.isOnField()) {
// Switch this to cycle between
// - hiding the top mon's team bar
// - showing the bottom mon's team bar with its active slots reversed
if (false) {
pokemon.getBattleInfo().displayParty(Pt)
Pt[0].getBattleInfo().switchIconVisibility(false); // Make the top mon's team bar go away
Pt[0].getBattleInfo().iconsActive = false; // Prevent the top mon from re-opening its bar
} else {
pokemon.getBattleInfo().displayParty(Pt2)
}
} else {
pokemon.getBattleInfo().displayParty((this.scene.currentBattle.double ? Pt1 : Pt))
}
}
})
this.scene.pushPhase(new TurnStartPhase(this.scene));
this.scene.updateCatchRate()
this.end();
}
}

View File

@ -3,7 +3,7 @@ import { applyAbAttrs, BypassSpeedChanceAbAttr, PreventBypassSpeedChanceAbAttr,
import { allMoves, applyMoveAttrs, IncrementMovePriorityAttr, MoveHeaderAttr } from "#app/data/move.js";
import { Abilities } from "#app/enums/abilities.js";
import { Stat } from "#app/enums/stat.js";
import { PokemonMove } from "#app/field/pokemon.js";
import Pokemon, { PokemonMove } from "#app/field/pokemon.js";
import { BypassSpeedChanceModifier } from "#app/modifier/modifier.js";
import { Command } from "#app/ui/command-ui-handler.js";
import * as Utils from "#app/utils.js";
@ -18,12 +18,41 @@ import { SwitchSummonPhase } from "./switch-summon-phase";
import { TurnEndPhase } from "./turn-end-phase";
import { WeatherEffectPhase } from "./weather-effect-phase";
import * as LoggerTools from "../logger";
import { BattlerIndex } from "#app/battle.js";
export class TurnStartPhase extends FieldPhase {
constructor(scene: BattleScene) {
super(scene);
}
generateTargString(t: BattlerIndex[]) {
var targets = ['Self']
for (var i = 0; i < this.scene.getField().length; i++) {
if (this.scene.getField()[i] != null)
targets[this.scene.getField()[i].getBattlerIndex() + 1] = this.scene.getField()[i].name
}
for (var i = 0; i < this.scene.getEnemyField().length; i++) {
if (this.scene.getEnemyField()[i] != null)
targets[this.scene.getEnemyField()[i].getBattlerIndex() + 1] = this.scene.getEnemyField()[i].name
}
var targetFull: string[] = []
for (var i = 0; i < t.length; i++) {
targetFull.push(targets[t[i] + 1])
}
if (targetFull.join(", ") == targets.join(", ")) return ""
return " → " + targetFull.join(", ")
}
getBattlers(user: Pokemon): Pokemon[] {
var battlers: Pokemon[] = []
battlers[0] = this.scene.getField()[0]
battlers[1] = this.scene.getField()[1]
battlers[2] = this.scene.getEnemyField()[0]
battlers[3] = this.scene.getEnemyField()[1]
battlers.unshift(user)
return battlers;
}
start() {
super.start();
@ -32,6 +61,54 @@ export class TurnStartPhase extends FieldPhase {
const battlerBypassSpeed = {};
const playerActions: string[] = []
const moveOrder = order.slice(0);
while (LoggerTools.Actions.length > 0) {
LoggerTools.Actions.pop()
}
for (const o of moveOrder) {
const pokemon = field[o];
const turnCommand = this.scene.currentBattle.turnCommands[o];
if (turnCommand?.skip || !pokemon.isPlayer()) {
continue;
}
switch (turnCommand?.command) {
case Command.FIGHT:
const queuedMove = turnCommand.move;
if (!queuedMove) {
continue;
}
LoggerTools.Actions[pokemon.getBattlerIndex()] = `[[ ${new PokemonMove(queuedMove.move).getName()} unknown target ]]`
break;
case Command.BALL:
var ballNames = [
"Poké Ball",
"Great Ball",
"Ultra Ball",
"Rogue Ball",
"Master Ball",
"Luxury Ball"
]
LoggerTools.Actions[pokemon.getBattlerIndex()] = ballNames[turnCommand.cursor!]
playerActions.push(ballNames[turnCommand.cursor!])
//this.scene.unshiftPhase(new AttemptCapturePhase(this.scene, turnCommand.targets[0] % 2, turnCommand.cursor));
break;
case Command.POKEMON:
break;
case Command.RUN:
LoggerTools.Actions[pokemon.getBattlerIndex()] = "Run"
playerActions.push("Run")
break;
}
}
//LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, playerActions.join(" | "))
this.scene.getField(true).filter(p => p.summonData).map(p => {
const bypassSpeed = new Utils.BooleanHolder(false);
const canCheckHeldItems = new Utils.BooleanHolder(true);
@ -43,8 +120,6 @@ export class TurnStartPhase extends FieldPhase {
battlerBypassSpeed[p.getBattlerIndex()] = bypassSpeed;
});
const moveOrder = order.slice(0);
moveOrder.sort((a, b) => {
const aCommand = this.scene.currentBattle.turnCommands[a];
const bCommand = this.scene.currentBattle.turnCommands[b];
@ -112,19 +187,81 @@ export class TurnStartPhase extends FieldPhase {
}
if (pokemon.isPlayer()) {
if (turnCommand.cursor === -1) {
//console.log("turncommand cursor was -1 -- running TOP block")
this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move));//TODO: is the bang correct here?
var targets = turnCommand.targets || turnCommand.move!.targets
var mv = move
if (pokemon.isPlayer()) {
console.log(turnCommand.targets, turnCommand.move!.targets)
LoggerTools.Actions[pokemon.getBattlerIndex()] = mv.getName()
if (this.scene.currentBattle.double) {
var targIDs = ["Self", "Self", "Ally", "L", "R"]
if (pokemon.getBattlerIndex() == 1) targIDs = ["Self", "Ally", "Self", "L", "R"]
LoggerTools.Actions[pokemon.getBattlerIndex()] += " → " + targets.map(v => targIDs[v+1])
} else {
var targIDs = ["Self", "", "", "", ""]
var myField = this.scene.getField()
if (myField[0])
targIDs[1] = myField[0].name
if (myField[1])
targIDs[2] = myField[1].name
var eField = this.scene.getEnemyField()
if (eField[0])
targIDs[3] = eField[0].name
if (eField[1])
targIDs[4] = eField[1].name
//LoggerTools.Actions[pokemon.getBattlerIndex()] += " → " + targets.map(v => targIDs[v+1])
}
console.log(mv.getName(), targets)
}
} else {
//console.log("turncommand = ", turnCommand, " -- running BOTTOM block")
const playerPhase = new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move, false, queuedMove.ignorePP);//TODO: is the bang correct here?
var targets = turnCommand.targets || turnCommand.move!.targets
var mv = move
if (pokemon.isPlayer()) {
console.log(turnCommand.targets, turnCommand.move!.targets)
if (turnCommand.args && turnCommand.args[1] && turnCommand.args[1].isContinuing != undefined) {
console.log(mv.getName(), targets)
} else {
LoggerTools.Actions[pokemon.getBattlerIndex()] = mv.getName()
if (this.scene.currentBattle.double) {
var targIDs = ["Self", "Self", "Ally", "L", "R"]
if (pokemon.getBattlerIndex() == 1) targIDs = ["Self", "Ally", "Self", "L", "R"]
LoggerTools.Actions[pokemon.getBattlerIndex()] += " → " + targets.map(v => targIDs[v+1])
} else {
var targIDs = ["Self", "", "", "", ""]
var myField = this.scene.getField()
if (myField[0])
targIDs[1] = myField[0].name
if (myField[1])
targIDs[2] = myField[1].name
var eField = this.scene.getEnemyField()
if (eField[0])
targIDs[3] = eField[0].name
if (eField[1])
targIDs[4] = eField[1].name
//LoggerTools.Actions[pokemon.getBattlerIndex()] += " → " + targets.map(v => targIDs[v+1])
}
console.log(mv.getName(), targets)
}
}
this.scene.pushPhase(playerPhase);
}
} else {
this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move, false, queuedMove.ignorePP));//TODO: is the bang correct here?
var targets = turnCommand.targets || turnCommand.move!.targets
var mv = new PokemonMove(queuedMove.move)
}
break;
case Command.BALL:
this.scene.unshiftPhase(new AttemptCapturePhase(this.scene, turnCommand.targets![0] % 2, turnCommand.cursor!));//TODO: is the bang correct here?
break;
case Command.POKEMON:
if (pokemon.isPlayer()) {
// " " + LoggerTools.playerPokeName(this.scene, pokemon) +
LoggerTools.Actions[pokemon.getBattlerIndex()] = ((turnCommand.args![0] as boolean) ? "Baton" : "Switch") + " to " + LoggerTools.playerPokeName(this.scene, turnCommand.cursor!)
}
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, pokemon.getFieldIndex(), turnCommand.cursor!, true, turnCommand.args![0] as boolean, pokemon.isPlayer()));//TODO: is the bang correct here?
break;
case Command.RUN:
@ -137,7 +274,7 @@ export class TurnStartPhase extends FieldPhase {
return;
}
});
// if only one pokemon is alive, use that one
// if only one pokemon is alive, use that one
if (playerActivePokemon.length > 1) {
// find which active pokemon has faster speed
const fasterPokemon = playerActivePokemon[0].getStat(Stat.SPD) > playerActivePokemon[1].getStat(Stat.SPD) ? playerActivePokemon[0] : playerActivePokemon[1];
@ -163,11 +300,20 @@ export class TurnStartPhase extends FieldPhase {
this.scene.pushPhase(new BerryPhase(this.scene));
this.scene.pushPhase(new TurnEndPhase(this.scene));
this.scene.arenaFlyout.updateFieldText()
if (LoggerTools.Actions.length > 1 && !this.scene.currentBattle.double) {
LoggerTools.Actions.pop() // If this is a single battle, but we somehow have two actions, delete the second
}
if (LoggerTools.Actions.length > 1 && (LoggerTools.Actions[0] == "" || LoggerTools.Actions[0] == undefined || LoggerTools.Actions[0] == null))
LoggerTools.Actions.shift() // If the left slot isn't doing anything, delete its entry
LoggerTools.logActions(this.scene, this.scene.currentBattle.waveIndex, LoggerTools.Actions.join(" & "))
/**
* this.end() will call shiftPhase(), which dumps everything from PrependQueue (aka everything that is unshifted()) to the front
* of the queue and dequeues to start the next phase
* this is important since stuff like SwitchSummon, AttemptRun, AttemptCapture Phases break the "flow" and should take precedence
*/
* this.end() will call shiftPhase(), which dumps everything from PrependQueue (aka everything that is unshifted()) to the front
* of the queue and dequeues to start the next phase
* this is important since stuff like SwitchSummon, AttemptRun, AttemptCapture Phases break the "flow" and should take precedence
*/
this.end();
}
}

View File

@ -118,11 +118,13 @@ export class VictoryPhase extends PokemonPhase {
if (this.scene.currentBattle.waveIndex % 10) {
this.scene.pushPhase(new SelectModifierPhase(this.scene));
} else if (this.scene.gameMode.isDaily) {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, "")
this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.EXP_CHARM));
if (this.scene.currentBattle.waveIndex > 10 && !this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex)) {
this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.GOLDEN_POKEBALL));
}
} else {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, "")
const superExpWave = !this.scene.gameMode.isEndless ? (this.scene.offsetGym ? 0 : 20) : 10;
if (this.scene.gameMode.isEndless && this.scene.currentBattle.waveIndex === 10) {
this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.EXP_SHARE));
@ -140,6 +142,7 @@ export class VictoryPhase extends PokemonPhase {
}
this.scene.pushPhase(new NewBattlePhase(this.scene));
} else {
LoggerTools.logShop(this.scene, this.scene.currentBattle.waveIndex, "")
this.scene.currentBattle.battleType = BattleType.CLEAR;
this.scene.score += this.scene.gameMode.getClearScoreBonus();
this.scene.updateScoreText();