Progress for July 8

- Use score to display catch rates
- Display catch rates in Pokeball menu
- Show possible damage in type effectiveness window
- Show a flyout with basic details about the opponent(s) during the start of a wild battle
- Fix logger
This commit is contained in:
RedstonewolfX 2024-07-08 10:54:36 -04:00
parent 671c038540
commit 864d4ffa2c
5 changed files with 285 additions and 22 deletions

View File

@ -224,7 +224,7 @@ export default class BattleScene extends SceneBase {
private fieldOverlay: Phaser.GameObjects.Rectangle; private fieldOverlay: Phaser.GameObjects.Rectangle;
private shopOverlay: Phaser.GameObjects.Rectangle; private shopOverlay: Phaser.GameObjects.Rectangle;
public modifiers: PersistentModifier[]; public modifiers: PersistentModifier[];
private enemyModifiers: PersistentModifier[]; public enemyModifiers: PersistentModifier[];
public uiContainer: Phaser.GameObjects.Container; public uiContainer: Phaser.GameObjects.Container;
public ui: UI; public ui: UI;
@ -1497,6 +1497,10 @@ export default class BattleScene extends SceneBase {
this.scoreText.setText(`Score: ${this.score.toString()}`); this.scoreText.setText(`Score: ${this.score.toString()}`);
this.scoreText.setVisible(this.gameMode.isDaily); this.scoreText.setVisible(this.gameMode.isDaily);
} }
setScoreText(text: string): void {
this.scoreText.setText(text);
this.scoreText.setVisible(true);
}
updateAndShowText(duration: integer): void { updateAndShowText(duration: integer): void {
const labels = [ this.luckLabelText, this.luckText ]; const labels = [ this.luckLabelText, this.luckText ];

View File

@ -53,6 +53,30 @@ export function getPokeballName(type: PokeballType): string {
} }
return ret; return ret;
} }
export function getPokeballShortName(type: PokeballType): string {
let ret: string;
switch (type) {
case PokeballType.POKEBALL:
ret = "Poké";
break;
case PokeballType.GREAT_BALL:
ret = "Great";
break;
case PokeballType.ULTRA_BALL:
ret = "Ultra";
break;
case PokeballType.ROGUE_BALL:
ret = "Rogue";
break;
case PokeballType.MASTER_BALL:
ret = "Master";
break;
case PokeballType.LUXURY_BALL:
ret = "Luxury";
break;
}
return ret;
}
export function getPokeballCatchMultiplier(type: PokeballType): number { export function getPokeballCatchMultiplier(type: PokeballType): number {
switch (type) { switch (type) {

View File

@ -99,7 +99,7 @@ export function logTeam(scene: BattleScene, floor: integer = undefined) {
if (team[0].hasTrainer()) { if (team[0].hasTrainer()) {
var sprite = scene.currentBattle.trainer.config.getSpriteKey() var sprite = scene.currentBattle.trainer.config.getSpriteKey()
var trainerCat = Utils.getEnumKeys(TrainerType)[Utils.getEnumValues(TrainerType).indexOf(scene.currentBattle.trainer.config.trainerType)] var trainerCat = Utils.getEnumKeys(TrainerType)[Utils.getEnumValues(TrainerType).indexOf(scene.currentBattle.trainer.config.trainerType)]
setRow("e", floor + "," + team.length + "," + sprite + ",trainer," + trainerCat + ",,,,,,,,,,,,", floor, 0) setRow("e", floor + ",0," + sprite + ",trainer," + trainerCat + ",,,,,,,,,,,,", floor, 0)
} else { } else {
for (var i = 0; i < team.length; i++) { for (var i = 0; i < team.length; i++) {
logPokemon(scene, floor, i, team[i]) logPokemon(scene, floor, i, team[i])
@ -140,8 +140,23 @@ export function logPokemon(scene: BattleScene, floor: integer = undefined, slot:
setRow("e", newLine, floor, slot) setRow("e", newLine, floor, slot)
//console.log(localStorage.getItem(logs[logKeys.indexOf("e")][1]).split("\n")) //console.log(localStorage.getItem(logs[logKeys.indexOf("e")][1]).split("\n"))
} }
export function dataSorter(a: string, b: string) {
var da = a.split(",")
var db = b.split(",")
if (da[0] == "---- " + logs[logKeys.indexOf("e")][3] + " ----") {
return -1;
}
if (db[0] == "---- " + logs[logKeys.indexOf("e")][3] + " ----") {
return 1;
}
if (da[0] == db[0]) {
return ((da[1] as any) * 1) - ((db[1] as any) * 1)
}
return ((da[0] as any) * 1) - ((db[0] as any) * 1)
}
export function setRow(keyword: string, newLine: string, floor: integer, slot: integer) { export function setRow(keyword: string, newLine: string, floor: integer, slot: integer) {
var data = localStorage.getItem(logs[logKeys.indexOf(keyword)][1]).split("\n") var data = localStorage.getItem(logs[logKeys.indexOf(keyword)][1]).split("\n")
data.sort(dataSorter)
var idx = 1 var idx = 1
if (slot == -1) { if (slot == -1) {
while (idx < data.length && (data[idx].split(",")[0] as any) * 1 < floor) { while (idx < data.length && (data[idx].split(",")[0] as any) * 1 < floor) {
@ -153,22 +168,38 @@ export function setRow(keyword: string, newLine: string, floor: integer, slot: i
while (idx < data.length && (data[idx].split(",")[0] as any) * 1 <= floor && (data[idx].split(",")[1] as any) * 1 <= slot) { while (idx < data.length && (data[idx].split(",")[0] as any) * 1 <= floor && (data[idx].split(",")[1] as any) * 1 <= slot) {
idx++ idx++
} }
idx--
console.log((data[idx].split(",")[0] as any) * 1, floor, (data[idx].split(",")[1] as any) * 1, slot)
if (idx < data.length && (data[idx].split(",")[0] as any) * 1 == floor && (data[idx].split(",")[1] as any) * 1 == slot) {
data[idx] = newLine
console.log("Overwrote data at " + idx)
for (var i = 0; i < Math.max(0, idx - 2) && i < 2; i++) {
console.log(i + " " + data[i])
}
if (Math.min(0, idx - 2) > 3) {
console.log("...")
}
for (var i = Math.max(0, idx - 2); i <= idx + 2 && i < data.length; i++) {
console.log(i + (i == idx ? " >> " : " ") + data[i])
}
localStorage.setItem(logs[logKeys.indexOf(keyword)][1], data.join("\n"));
return;
}
idx++
}
console.log("Inserted data at " + idx)
for (var i = 0; i < Math.max(0, idx - 2) && i < 2; i++) {
console.log(i + " " + data[i])
}
if (Math.min(0, idx - 2) > 3) {
console.log("...")
}
for (var i = Math.max(0, idx - 2); i < idx; i++) {
console.log(i + " " + data[i])
}
console.log(i + " >> " + newLine)
for (var i = idx; i <= idx + 2 && i < data.length; i++) {
console.log(i + " " + data[i])
} }
localStorage.setItem(logs[logKeys.indexOf(keyword)][1], data.slice(0, idx).join("\n") + "\n" + newLine + (data.slice(idx).length == 0 ? "" : "\n") + data.slice(idx).join("\n")); localStorage.setItem(logs[logKeys.indexOf(keyword)][1], data.slice(0, idx).join("\n") + "\n" + newLine + (data.slice(idx).length == 0 ? "" : "\n") + data.slice(idx).join("\n"));
} }
export function setRowByID(key: integer, newLine: string, floor: integer, slot: integer) {
var data = localStorage.getItem(logs[key][1]).split("\n")
var idx = 1
if (slot == -1) {
while (idx < data.length && (data[idx].split(",")[0] as any) * 1 < floor) {
idx++
}
idx--
slot = ((data[idx].split(",")[1] as any) * 1) + 1
} else {
while (idx < data.length && (data[idx].split(",")[0] as any) * 1 <= floor && (data[idx].split(",")[1] as any) * 1 <= slot) {
idx++
}
}
localStorage.setItem(logs[key][1], data.slice(0, idx).join("\n") + "\n" + newLine + (data.slice(idx).length == 0 ? "" : "\n") + data.slice(idx).join("\n"));
}

View File

@ -72,6 +72,7 @@ import ChallengeData from "./system/challenge-data";
import { Challenges } from "./enums/challenges" import { Challenges } from "./enums/challenges"
import PokemonData from "./system/pokemon-data" import PokemonData from "./system/pokemon-data"
import * as LoggerTools from "./logger" import * as LoggerTools from "./logger"
import { getNatureName } from "./data/nature";
const { t } = i18next; const { t } = i18next;
@ -2058,14 +2059,51 @@ export class CheckSwitchPhase extends BattlePhase {
return; return;
} }
for (var i = 0; i < this.scene.getEnemyField().length; i++) {
var pk = this.scene.getEnemyField()[i]
var maxIVs = []
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")
}
}
this.scene.ui.showText(i18next.t("battle:switchQuestion", { pokemonName: this.useName ? pokemon.name : i18next.t("battle:pokemon") }), null, () => { this.scene.ui.showText(i18next.t("battle:switchQuestion", { pokemonName: this.useName ? pokemon.name : i18next.t("battle:pokemon") }), null, () => {
this.scene.ui.setMode(Mode.CONFIRM, () => { this.scene.ui.setMode(Mode.CONFIRM, () => {
this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.setMode(Mode.MESSAGE);
this.scene.tryRemovePhase(p => p instanceof PostSummonPhase && p.player && p.fieldIndex === this.fieldIndex); this.scene.tryRemovePhase(p => p instanceof PostSummonPhase && p.player && p.fieldIndex === this.fieldIndex);
this.scene.unshiftPhase(new SwitchPhase(this.scene, this.fieldIndex, false, true)); 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.end(); this.end();
}, () => { }, () => {
this.scene.ui.setMode(Mode.MESSAGE); 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.end(); this.end();
}); });
}); });
@ -2104,6 +2142,60 @@ export class TurnInitPhase extends FieldPhase {
super(scene); super(scene);
} }
catchCalc(pokemon: EnemyPokemon) {
const _3m = 3 * pokemon.getMaxHp();
const _2h = 2 * pokemon.hp;
const catchRate = pokemon.species.catchRate;
const statusMultiplier = pokemon.status ? getStatusEffectCatchRateMultiplier(pokemon.status.effect) : 1;
const rate1 = Math.round(65536 / Math.sqrt(Math.sqrt(255 / (Math.round((((_3m - _2h) * catchRate * 1) / _3m) * statusMultiplier)))));
const rate2 = Math.round(65536 / Math.sqrt(Math.sqrt(255 / (Math.round((((_3m - _2h) * catchRate * 1.5) / _3m) * statusMultiplier)))));
const rate3 = Math.round(65536 / Math.sqrt(Math.sqrt(255 / (Math.round((((_3m - _2h) * catchRate * 2) / _3m) * statusMultiplier)))));
const rate4 = Math.round(65536 / Math.sqrt(Math.sqrt(255 / (Math.round((((_3m - _2h) * catchRate * 3) / _3m) * statusMultiplier)))));
var rates = [rate1, rate2, rate3, rate4]
var rates2 = rates.map(r => ((r/65536) ** 3))
console.log(rates2)
return rates2
}
/**
* Finds the best Poké Ball to catch a Pokemon with, and the % chance of capturing it.
* @param pokemon The Pokémon to get the catch rate for.
* @param override Show the best Poké Ball to use, even if you don't have any.
* @returns The name and % rate of the best Poké Ball.
*/
findBest(pokemon: EnemyPokemon, override?: boolean) {
var rates = this.catchCalc(pokemon)
if (this.scene.pokeballCounts[0] == 0 && !override) rates[0] = 0
if (this.scene.pokeballCounts[1] == 0 && !override) rates[1] = 0
if (this.scene.pokeballCounts[2] == 0 && !override) rates[2] = 0
if (this.scene.pokeballCounts[3] == 0 && !override) rates[3] = 0
var rates2 = rates.slice()
rates2.sort(function(a, b) {return b - a})
switch (rates2[0]) {
case rates[0]:
// Poke Balls are best
return "Poké Ball " + Math.round(rates2[0] * 100) + "%";
case rates[1]:
// Great Balls are best
return "Great Ball " + Math.round(rates2[0] * 100) + "%";
case rates[2]:
// Ultra Balls are best
return "Ultra Ball " + Math.round(rates2[0] * 100) + "%";
case rates[3]:
// Rogue Balls are best
return "Rogue Ball " + Math.round(rates2[0] * 100) + "%";
default:
// Master Balls are the only thing that will work
if (this.scene.pokeballCounts[4] != 0 || override) {
return "Master Ball";
} else {
return "No balls"
}
}
}
start() { start() {
super.start(); super.start();
@ -2152,6 +2244,15 @@ export class TurnInitPhase extends FieldPhase {
this.scene.pushPhase(new TurnStartPhase(this.scene)); this.scene.pushPhase(new TurnStartPhase(this.scene));
var txt = ["Turn: " + this.scene.currentBattle.turn]
if (!this.scene.getEnemyField()[0].hasTrainer()) {
this.scene.getEnemyField().forEach((pk, i) => {
txt = txt.concat(this.findBest(pk))
})
}
this.scene.setScoreText(txt.join("/"))
this.end(); this.end();
} }
} }
@ -5048,6 +5149,16 @@ export class AttemptCapturePhase extends PokemonPhase {
this.pokeballType = pokeballType; this.pokeballType = pokeballType;
} }
roll(y?: integer) {
var roll = (this.getPokemon() as EnemyPokemon).randSeedInt(65536)
if (y != undefined) {
console.log(roll, y, roll < y)
} else {
console.log(roll)
}
return roll;
}
start() { start() {
super.start(); super.start();
@ -5129,7 +5240,7 @@ export class AttemptCapturePhase extends PokemonPhase {
shakeCounter.stop(); shakeCounter.stop();
this.failCatch(shakeCount); this.failCatch(shakeCount);
} else if (shakeCount++ < 3) { } else if (shakeCount++ < 3) {
if (pokeballMultiplier === -1 || pokemon.randSeedInt(65536) < y) { if (pokeballMultiplier === -1 || this.roll(y) < y) {
this.scene.playSound("pb_move"); this.scene.playSound("pb_move");
} else { } else {
shakeCounter.stop(); shakeCounter.stop();

View File

@ -6,10 +6,15 @@ import { Mode } from "./ui";
import UiHandler from "./ui-handler"; import UiHandler from "./ui-handler";
import * as Utils from "../utils"; import * as Utils from "../utils";
import { CommandPhase } from "../phases"; import { CommandPhase } from "../phases";
import { MoveCategory } from "#app/data/move.js"; import * as MoveData from "#app/data/move.js";
import i18next from "i18next"; import i18next from "i18next";
import {Button} from "#enums/buttons"; import {Button} from "#enums/buttons";
import Pokemon, { PokemonMove } from "#app/field/pokemon.js"; import Pokemon, { EnemyPokemon, PlayerPokemon, PokemonMove } from "#app/field/pokemon.js";
import Battle from "#app/battle.js";
import { Stat } from "#app/data/pokemon-stat.js";
import { Abilities } from "#app/enums/abilities.js";
import { WeatherType } from "#app/data/weather.js";
import { Moves } from "#app/enums/moves.js";
export default class FightUiHandler extends UiHandler { export default class FightUiHandler extends UiHandler {
private movesContainer: Phaser.GameObjects.Container; private movesContainer: Phaser.GameObjects.Container;
@ -153,6 +158,93 @@ export default class FightUiHandler extends UiHandler {
return !this.fieldIndex ? this.cursor : this.cursor2; return !this.fieldIndex ? this.cursor : this.cursor2;
} }
calcDamage(scene: BattleScene, user: PlayerPokemon, target: Pokemon, move: PokemonMove) {
var power = move.getMove().power
var myAtk = 0
var theirDef = 0
var myAtkC = 0
var theirDefC = 0
switch (move.getMove().category) {
case MoveData.MoveCategory.PHYSICAL:
myAtk = user.getBattleStat(Stat.ATK, target, move.getMove())
myAtkC = user.getBattleStat(Stat.ATK, target, move.getMove(), true)
theirDef = target.getBattleStat(Stat.DEF, user, move.getMove())
theirDefC = target.getBattleStat(Stat.DEF, user, move.getMove(), true)
break;
case MoveData.MoveCategory.SPECIAL:
myAtk = user.getBattleStat(Stat.SPATK, target, move.getMove())
myAtkC = user.getBattleStat(Stat.SPATK, target, move.getMove(), true)
theirDef = target.getBattleStat(Stat.SPDEF, user, move.getMove())
theirDefC = target.getBattleStat(Stat.SPDEF, user, move.getMove(), true)
break;
case MoveData.MoveCategory.STATUS:
return "---"
}
var stabBonus = 1
var types = user.getTypes()
// Apply STAB bonus
for (var i = 0; i < types.length; i++) {
if (types[i] == move.getMove().type) {
stabBonus = 1.5
}
}
// Apply Tera Type bonus
if (stabBonus == 1.5) {
// STAB
if (move.getMove().type == user.getTeraType()) {
stabBonus = 2
}
} else if (move.getMove().type == user.getTeraType()) {
stabBonus = 1.5
}
// Apply adaptability
if (stabBonus == 2) {
// Tera-STAB
if (move.getMove().type == user.getTeraType()) {
stabBonus = 2.25
}
} else if (stabBonus == 1.5) {
// STAB or Tera
if (move.getMove().type == user.getTeraType()) {
stabBonus = 2
}
} else if (move.getMove().type == user.getTeraType()) {
// Adaptability
stabBonus = 1.5
}
var weatherBonus = 1
if (this.scene.arena.weather.weatherType == WeatherType.RAIN || this.scene.arena.weather.weatherType == WeatherType.HEAVY_RAIN) {
if (move.getMove().type == Type.WATER) {
weatherBonus = 1.5
}
if (move.getMove().type == Type.FIRE) {
weatherBonus = this.scene.arena.weather.weatherType == WeatherType.HEAVY_RAIN ? 0 : 0.5
}
}
if (this.scene.arena.weather.weatherType == WeatherType.SUNNY || this.scene.arena.weather.weatherType == WeatherType.HARSH_SUN) {
if (move.getMove().type == Type.FIRE) {
weatherBonus = 1.5
}
if (move.getMove().type == Type.WATER) {
weatherBonus = this.scene.arena.weather.weatherType == WeatherType.HARSH_SUN ? 0 : (move.moveId == Moves.HYDRO_STEAM ? 1.5 : 0.5)
}
}
var typeBonus = target.getAttackMoveEffectiveness(user, move)
var modifiers = stabBonus * weatherBonus
var dmgLow = (((2*user.level/5 + 2) * power * myAtk / theirDef)/50 + 2) * 0.85 * modifiers
var dmgHigh = (((2*user.level/5 + 2) * power * myAtkC / theirDefC)/50 + 2) * 1.5 * modifiers
if (user.hasAbility(Abilities.PARENTAL_BOND)) {
// Second hit deals 0.25x damage
dmgLow *= 1.25
dmgHigh *= 1.25
}
return (Math.round(dmgLow) == Math.round(dmgHigh) ? Math.round(dmgLow).toString() : Math.round(dmgLow) + "-" + Math.round(dmgHigh)) + ((Math.round(dmgLow) > target.hp) ? " KO" : "")
dmgLow = Math.round((dmgLow)/target.getBattleStat(Stat.HP)*100)
dmgHigh = Math.round((dmgHigh)/target.getBattleStat(Stat.HP)*100)
return (dmgLow == dmgHigh ? dmgLow + "%" : dmgLow + "%-" + dmgHigh + "%") + ((Math.round(dmgLow) > target.hp) ? " KO" : "")
return "???"
}
setCursor(cursor: integer): boolean { setCursor(cursor: integer): boolean {
const ui = this.getUi(); const ui = this.getUi();
@ -178,7 +270,7 @@ export default class FightUiHandler extends UiHandler {
if (hasMove) { if (hasMove) {
const pokemonMove = moveset[cursor]; const pokemonMove = moveset[cursor];
this.typeIcon.setTexture(`types${Utils.verifyLang(i18next.resolvedLanguage) ? `_${i18next.resolvedLanguage}` : ""}`, Type[pokemonMove.getMove().type].toLowerCase()).setScale(0.8); this.typeIcon.setTexture(`types${Utils.verifyLang(i18next.resolvedLanguage) ? `_${i18next.resolvedLanguage}` : ""}`, Type[pokemonMove.getMove().type].toLowerCase()).setScale(0.8);
this.moveCategoryIcon.setTexture("categories", MoveCategory[pokemonMove.getMove().category].toLowerCase()).setScale(1.0); this.moveCategoryIcon.setTexture("categories", MoveData.MoveCategory[pokemonMove.getMove().category].toLowerCase()).setScale(1.0);
const power = pokemonMove.getMove().power; const power = pokemonMove.getMove().power;
const accuracy = pokemonMove.getMove().accuracy; const accuracy = pokemonMove.getMove().accuracy;
@ -207,6 +299,7 @@ export default class FightUiHandler extends UiHandler {
pokemon.getOpponents().forEach((opponent) => { pokemon.getOpponents().forEach((opponent) => {
opponent.updateEffectiveness(this.getEffectivenessText(pokemon, opponent, pokemonMove)); opponent.updateEffectiveness(this.getEffectivenessText(pokemon, opponent, pokemonMove));
opponent.updateEffectiveness(this.calcDamage(this.scene, pokemon, opponent, pokemonMove));
}); });
} }