Changes to plains arena pool

pull/1/head
Flashfyre 2023-03-29 12:23:52 -04:00
parent a739a1666f
commit 27c0b64a3f
8 changed files with 134 additions and 81 deletions

View File

@ -33,28 +33,34 @@ enum PoolTier {
export class Arena {
private scene: BattleScene;
public type: integer;
public arenaType: integer;
private bgm: string;
private pokemonPool: PokemonSpecies[][];
constructor(scene: BattleScene, type: integer, bgm: string) {
constructor(scene: BattleScene, arenaType: integer, bgm: string) {
this.scene = scene;
this.type = type;
this.arenaType = arenaType;
this.bgm = bgm;
const predicate = arenaPoolPredicates[type] || (() => {});
this.pokemonPool = Utils.getEnumValues(PoolTier).map(t => allSpecies.filter(p => predicate(p, t)));
if (arenaPools.hasOwnProperty(arenaType))
this.pokemonPool = arenaPools[arenaType];
else {
const predicate = arenaPoolPredicates[arenaType] || (() => {});
this.pokemonPool = Utils.getEnumValues(PoolTier).map(t => allSpecies.filter(p => predicate(p, t)));
}
}
randomSpecies(waveIndex: integer): PokemonSpecies {
const tier: PoolTier = Utils.randInt(5);
const tierValue = Utils.randInt(512);
const tier = tierValue >= 156 ? PoolTier.COMMON : tierValue >= 32 ? PoolTier.UNCOMMON : tierValue >= 6 ? PoolTier.RARE : tierValue >= 1 ? PoolTier.ULTRA_RARE : PoolTier.LEGENDARY;
const tierPool = this.pokemonPool[tier];
let ret: PokemonSpecies;
if (!tierPool.length)
ret = this.scene.randomSpecies();
else
ret = tierPool[Utils.randInt(tierPool.length)];
else {
const species = tierPool[Utils.randInt(tierPool.length)];
ret = species instanceof PokemonSpecies ? species : getPokemonSpecies(species);
}
const newSpeciesId = ret.getSpeciesForLevel(5);
if (newSpeciesId !== ret.speciesId) {
console.log('Replaced', Species[ret.speciesId], 'with', Species[newSpeciesId]);
@ -69,6 +75,16 @@ export class Arena {
}
}
const arenaPools = {
[ArenaType.PLAINS]: {
[PoolTier.COMMON]: [ Species.CATERPIE, Species.METAPOD, Species.WEEDLE, Species.KAKUNA, Species.PIDGEY, Species.RATTATA, Species.SPEAROW, Species.SENTRET, Species.HOOTHOOT, Species.HOPPIP, Species.SUNKERN, Species.POOCHYENA, Species.ZIGZAGOON, Species.WURMPLE, Species.SILCOON, Species.CASCOON, Species.TAILLOW, Species.STARLY, Species.BIDOOF, Species.KRICKETOT, Species.PATRAT, Species.LILLIPUP, Species.PIDOVE, Species.COTTONEE, Species.PETILIL, Species.MINCCINO, Species.FOONGUS ],
[PoolTier.UNCOMMON]: [ Species.EKANS, Species.NIDORAN_F, Species.NIDORAN_M, Species.PARAS, Species.VENONAT, Species.MEOWTH, Species.BELLSPROUT, Species.LEDYBA, Species.SPINARAK, Species.PINECO, Species.LOTAD, Species.SEEDOT, Species.SHROOMISH, Species.NINCADA, Species.AZURILL, Species.WHISMUR, Species.SKITTY, Species.GULPIN, Species.BUDEW, Species.BURMY, Species.COMBEE, Species.CHERUBI, Species.VENIPEDE ],
[PoolTier.RARE]: [ Species.PICHU, Species.CLEFFA, Species.IGGLYBUFF, Species.WOOPER, Species.RALTS, Species.SURSKIT, Species.SLAKOTH, Species.BARBOACH, Species.DUCKLETT ],
[PoolTier.ULTRA_RARE]: [ Species.EEVEE, Species.TOGEPI, Species.TYROGUE ],
[PoolTier.LEGENDARY]: [ Species.DITTO ]
}
};
const arenaPoolPredicates = {
[ArenaType.PLAINS]: (p, t) => {
if (p.isOfType(Type.GHOST) || p.isOfType(Type.STEEL) || p.isOfType(Type.ICE) || p.isOfType(Type.DRAGON))

View File

@ -66,7 +66,7 @@ export function initAutoPlay(speed: number) {
let bestPartyMemberEffectiveness = 0.5;
for (let p = 0; p < party.length; p++) {
const pokemon = party[p];
if ((pokemon.hp / pokemon.getMaxHp()) <= 0.4)
if (pokemon.getHpRatio() <= 0.4)
continue;
const effectiveness = getMaxMoveEffectiveness(pokemon, enemyPokemon) / getMaxMoveEffectiveness(enemyPokemon, pokemon);
if (effectiveness > bestPartyMemberEffectiveness) {
@ -199,8 +199,8 @@ export function initAutoPlay(speed: number) {
const party = thisArg.getParty();
const modifierTypes = modifierSelectUiHandler.options.map(o => o.modifierType);
const faintedPartyMemberIndex = party.findIndex(p => !p.hp);
const lowHpPartyMemberIndex = party.findIndex(p => (p.hp / p.getMaxHp()) <= 0.5);
const criticalHpPartyMemberIndex = party.findIndex(p => (p.hp / p.getMaxHp()) <= 0.25);
const lowHpPartyMemberIndex = party.findIndex(p => p.getHpRatio() <= 0.5);
const criticalHpPartyMemberIndex = party.findIndex(p => p.getHpRatio() <= 0.25);
let optionIndex = tryGetBestModifier(modifierTypes, (modifierType: ModifierType) => {
if (modifierType instanceof PokemonHpRestoreModifierType) {

View File

@ -82,47 +82,47 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
}
}
initInfo(battler: Pokemon) {
this.nameText.setText(battler.name);
this.lastName = battler.species.name;
initInfo(pokemon: Pokemon) {
this.nameText.setText(pokemon.name);
this.lastName = pokemon.species.name;
this.hpBar.setScale(battler.hp / battler.getMaxHp(), 1);
this.hpBar.setScale(pokemon.getHpRatio(), 1);
if (this.player)
this.setHpNumbers(battler.hp, battler.getMaxHp());
this.lastHp = battler.hp;
this.setHpNumbers(pokemon.hp, pokemon.getMaxHp());
this.lastHp = pokemon.hp;
this.lastHpFrame = this.hpBar.scaleX > 0.5 ? 'high' : this.hpBar.scaleX > 0.25 ? 'medium' : 'low';
this.lastMaxHp = battler.getMaxHp();
this.lastMaxHp = pokemon.getMaxHp();
this.setLevel(battler.level);
this.lastLevel = battler.level;
this.setLevel(pokemon.level);
this.lastLevel = pokemon.level;
if (this.player) {
this.expBar.setScale(battler.levelExp / getLevelTotalExp(battler.level, battler.species.growthRate), 1);
this.lastExp = battler.exp;
this.lastLevelExp = battler.levelExp;
this.expBar.setScale(pokemon.levelExp / getLevelTotalExp(pokemon.level, pokemon.species.growthRate), 1);
this.lastExp = pokemon.exp;
this.lastLevelExp = pokemon.levelExp;
}
}
updateInfo(battler: Pokemon, callback?: Function) {
updateInfo(pokemon: Pokemon, callback?: Function) {
if (!this.scene)
return;
if (this.lastName !== battler.species.name) {
this.nameText.setText(battler.name);
this.lastName = battler.species.name;
if (this.lastName !== pokemon.species.name) {
this.nameText.setText(pokemon.name);
this.lastName = pokemon.species.name;
}
const updatePokemonHp = () => {
const duration = Utils.clampInt(Math.abs((this.lastHp) - battler.hp) * 5, 250, 5000);
const duration = Utils.clampInt(Math.abs((this.lastHp) - pokemon.hp) * 5, 250, 5000);
this.scene.tweens.add({
targets: this.hpBar,
ease: 'Sine.easeOut',
scaleX: battler.hp / battler.getMaxHp(),
scaleX: pokemon.getHpRatio(),
duration: duration,
onUpdate: () => {
if (this.player && this.lastHp !== battler.hp) {
const tweenHp = Math.ceil(this.hpBar.scaleX * battler.getMaxHp());
this.setHpNumbers(tweenHp, battler.getMaxHp())
if (this.player && this.lastHp !== pokemon.hp) {
const tweenHp = Math.ceil(this.hpBar.scaleX * pokemon.getMaxHp());
this.setHpNumbers(tweenHp, pokemon.getMaxHp())
this.lastHp = tweenHp;
}
@ -140,20 +140,20 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
}
});
if (!this.player)
this.lastHp = battler.hp;
this.lastMaxHp = battler.getMaxHp();
this.lastHp = pokemon.hp;
this.lastMaxHp = pokemon.getMaxHp();
};
if (this.player && this.lastExp !== battler.exp) {
if (this.player && this.lastExp !== pokemon.exp) {
const originalCallback = callback;
callback = () => this.updatePokemonExp(battler, originalCallback);
callback = () => this.updatePokemonExp(pokemon, originalCallback);
}
if (this.lastHp !== battler.hp || this.lastMaxHp !== battler.getMaxHp())
if (this.lastHp !== pokemon.hp || this.lastMaxHp !== pokemon.getMaxHp())
updatePokemonHp();
else if (!this.player && this.lastLevel !== battler.level) {
this.setLevel(battler.level);
this.lastLevel = battler.level;
else if (!this.player && this.lastLevel !== pokemon.level) {
this.setLevel(pokemon.level);
this.lastLevel = pokemon.level;
if (callback)
callback();
} else if (callback)

View File

@ -6,7 +6,7 @@ import { Mode } from './ui/ui';
import { Command } from "./ui/command-ui-handler";
import { interp } from "./temp_interpreter";
import { Stat } from "./pokemon-stat";
import { ExpBoosterModifier, getNewModifierType, PokemonBaseStatModifier as PokemonBaseStatModifier, PokemonModifierType } from "./modifier";
import { ExpBoosterModifier, getNewModifierType, PokemonBaseStatModifier, PokemonModifierType, regenerateModifierPoolThresholds } from "./modifier";
import PartyUiHandler from "./ui/party-ui-handler";
import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getTintColor as getPokeballTintColor, PokeballType } from "./pokeball";
import { pokemonLevelMoves } from "./pokemon-level-moves";
@ -332,7 +332,7 @@ abstract class MovePhase extends BattlePhase {
this.move = move;
}
abstract getDamagePhase(): MoveEffectPhase;
abstract getEffectPhase(): MoveEffectPhase;
canMove(): boolean {
return !!this.pokemon.hp;
@ -347,7 +347,7 @@ abstract class MovePhase extends BattlePhase {
console.log(this.pokemon.moveset);
this.scene.ui.showText(`${this.pokemon.name} used\n${this.move.getName()}!`, null, () => this.end(), 500);
if (this.move.getMove().category !== MOVE_CATEGORY.STATUS)
this.scene.unshiftPhase(this.getDamagePhase());
this.scene.unshiftPhase(this.getEffectPhase());
}
}
@ -356,7 +356,7 @@ export class PlayerMovePhase extends MovePhase {
super(scene, pokemon, move);
}
getDamagePhase(): MoveEffectPhase {
getEffectPhase(): MoveEffectPhase {
return new PlayerMoveEffectPhase(this.scene, this.move);
}
}
@ -366,7 +366,7 @@ export class EnemyMovePhase extends MovePhase {
super(scene, pokemon, move);
}
getDamagePhase(): MoveEffectPhase {
getEffectPhase(): MoveEffectPhase {
return new EnemyMoveEffectPhase(this.scene, this.move);
}
}
@ -756,7 +756,8 @@ export class SelectModifierPhase extends BattlePhase {
start() {
super.start();
const types = [ getNewModifierType(), getNewModifierType(), getNewModifierType() ];
regenerateModifierPoolThresholds(this.scene.getParty());
const types = [ getNewModifierType(), getNewModifierType(), getNewModifierType(), getNewModifierType(), getNewModifierType(), getNewModifierType() ];
this.scene.ui.setMode(Mode.MODIFIER_SELECT, types, (cursor: integer) => {
if (cursor < 0) {

View File

@ -12,7 +12,7 @@ import { initAutoPlay } from './auto-play';
export default class BattleScene extends Phaser.Scene {
private auto: boolean;
private autoSpeed: integer = 10;
private autoSpeed: integer = 3;
private phaseQueue: Array<BattlePhase>;
private phaseQueuePrepend: Array<BattlePhase>;
@ -198,10 +198,10 @@ export default class BattleScene extends Phaser.Scene {
this.arena = arena;
this.arenaBg = this.add.image(0, 0, `arena_${Utils.padInt(arena.type, 2)}`);
this.arenaPlayer = this.add.image(340, 20, `arena_${Utils.padInt(arena.type, 2)}a`);
this.arenaEnemy = this.add.image(-240, 13, `arena_${Utils.padInt(arena.type, 2)}b`);
this.arenaEnemy2 = this.add.image(-240, 13, `arena_${Utils.padInt(arena.type, 2)}b`);
this.arenaBg = this.add.image(0, 0, `arena_${Utils.padInt(arena.arenaType, 2)}`);
this.arenaPlayer = this.add.image(340, 20, `arena_${Utils.padInt(arena.arenaType, 2)}a`);
this.arenaEnemy = this.add.image(-240, 13, `arena_${Utils.padInt(arena.arenaType, 2)}b`);
this.arenaEnemy2 = this.add.image(-240, 13, `arena_${Utils.padInt(arena.arenaType, 2)}b`);
[this.arenaBg, this.arenaPlayer, this.arenaEnemy, this.arenaEnemy2].forEach(a => {
a.setOrigin(0, 0);

View File

@ -232,7 +232,7 @@ export class PokemonHpRestoreModifier extends ConsumablePokemonModifier {
apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon;
pokemon.hp = Math.min(pokemon.hp + (this.restorePercent * 0.01) * pokemon.getMaxHp(), pokemon.getMaxHp());
pokemon.hp = Math.min(pokemon.hp + Math.max((this.restorePercent * 0.01) * pokemon.getMaxHp(), this.restorePercent), pokemon.getMaxHp());
return true;
}
@ -338,7 +338,7 @@ export class PokemonHpRestoreModifierType extends PokemonModifierType {
protected restorePercent: integer;
constructor(name: string, restorePercent: integer, iconImage?: string) {
super(name, `Restore ${restorePercent}% HP for one POKéMON`, (_type, args) => new PokemonHpRestoreModifier(this, args[0], this.restorePercent),
super(name, `Restore ${restorePercent} HP or ${restorePercent}% HP for one POKéMON, whichever is higher`, (_type, args) => new PokemonHpRestoreModifier(this, args[0], this.restorePercent),
(pokemon: PlayerPokemon) => {
if (pokemon.hp >= pokemon.getMaxHp())
return PartyUiHandler.NoEffectMessage;
@ -372,21 +372,17 @@ export class PokemonBaseStatBoosterModifierType extends PokemonModifierType {
}
}
class AllPokemonHpRestoreModifierType extends ModifierType {
private restorePercent: integer;
constructor(name: string, restorePercent: integer, iconImage?: string) {
super(name, `Restore ${restorePercent}% HP for all POKéMON`, (_type, _args) => new PokemonHpRestoreModifier(this, -1, this.restorePercent), iconImage);
this.restorePercent = restorePercent;
class AllPokemonFullHpRestoreModifierType extends ModifierType {
constructor(name: string, iconImage?: string) {
super(name, `Restore 100% HP for all POKéMON`, (_type, _args) => new PokemonHpRestoreModifier(this, -1, 100), iconImage);
}
}
class WeightedModifierType {
public modifierType: ModifierType;
public weight: integer;
public weight: integer | Function;
constructor(modifierType: ModifierType, weight: integer) {
constructor(modifierType: ModifierType, weight: integer | Function) {
this.modifierType = modifierType;
this.weight = weight;
}
@ -399,8 +395,15 @@ class WeightedModifierType {
const modifierPool = {
[ModifierTier.COMMON]: [
new WeightedModifierType(new AddPokeballModifierType(PokeballType.POKEBALL, 5, 'pb'), 2),
new WeightedModifierType(new PokemonHpRestoreModifierType('POTION', 20), 3),
new PokemonHpRestoreModifierType('SUPER POTION', 50),
new WeightedModifierType(new PokemonHpRestoreModifierType('POTION', 20), (party: Array<PlayerPokemon>) => {
const thresholdPartyMemberCount = party.filter(p => p.getHpRatio() <= 0.9).length;
console.log(thresholdPartyMemberCount, party.map(p => p.getHpRatio()));
return thresholdPartyMemberCount;
}),
new WeightedModifierType(new PokemonHpRestoreModifierType('SUPER POTION', 50), (party: Array<PlayerPokemon>) => {
const thresholdPartyMemberCount = party.filter(p => p.getHpRatio() <= 0.75).length;
return Math.ceil(thresholdPartyMemberCount / 3);
}),
new PokemonBaseStatBoosterModifierType('HP-UP', Stat.HP),
new PokemonBaseStatBoosterModifierType('PROTEIN', Stat.ATK),
new PokemonBaseStatBoosterModifierType('IRON', Stat.DEF),
@ -410,12 +413,21 @@ const modifierPool = {
].map(m => { m.setTier(ModifierTier.COMMON); return m; }),
[ModifierTier.GREAT]: [
new AddPokeballModifierType(PokeballType.GREAT_BALL, 5, 'gb'),
new PokemonReviveModifierType('REVIVE', 50),
new PokemonHpRestoreModifierType('HYPER POTION', 100)
new WeightedModifierType(new PokemonReviveModifierType('REVIVE', 50), (party: Array<PlayerPokemon>) => {
const faintedPartyMemberCount = party.filter(p => !p.hp).length;
return faintedPartyMemberCount;
}),
new WeightedModifierType(new PokemonHpRestoreModifierType('HYPER POTION', 80), (party: Array<PlayerPokemon>) => {
const thresholdPartyMemberCount = party.filter(p => p.getHpRatio() <= 0.6).length;
return Math.ceil(thresholdPartyMemberCount / 3);
})
].map(m => { m.setTier(ModifierTier.GREAT); return m; }),
[ModifierTier.ULTRA]: [
new AddPokeballModifierType(PokeballType.ULTRA_BALL, 5, 'ub'),
new AllPokemonHpRestoreModifierType('MAX POTION', 100),
new WeightedModifierType(new AllPokemonFullHpRestoreModifierType('MAX POTION'), (party: Array<PlayerPokemon>) => {
const thresholdPartyMemberCount = party.filter(p => p.getHpRatio() <= 0.5).length;
return Math.ceil(thresholdPartyMemberCount / 3);
}),
new ModifierType('LUCKY EGG', 'Increases gain of EXP. Points by 25%', (type, _args) => new ExpBoosterModifier(type))
].map(m => { m.setTier(ModifierTier.ULTRA); return m; }),
[ModifierTier.MASTER]: [
@ -424,18 +436,36 @@ const modifierPool = {
].map(m => { m.setTier(ModifierTier.MASTER); return m; })
};
const modifierPoolThresholds = Object.fromEntries(new Map(Object.keys(modifierPool).map(t => {
const thresholds = new Map();
let i = 0;
modifierPool[t].reduce((total: integer, modifierType: ModifierType | WeightedModifierType) => {
total += modifierType instanceof WeightedModifierType ? (modifierType as WeightedModifierType).weight : 1;
thresholds.set(total, i++);
return total;
}, 0);
return [ t, Object.fromEntries(thresholds) ]
})));
let modifierPoolThresholds = {};
let ignoredPoolIndexes = {};
console.log(modifierPoolThresholds)
export function regenerateModifierPoolThresholds(party: Array<PlayerPokemon>) {
ignoredPoolIndexes = {};
modifierPoolThresholds = Object.fromEntries(new Map(Object.keys(modifierPool).map(t => {
ignoredPoolIndexes[t] = [];
const thresholds = new Map();
let i = 0;
modifierPool[t].reduce((total: integer, modifierType: ModifierType | WeightedModifierType) => {
if (modifierType instanceof WeightedModifierType) {
const weightedModifierType = modifierType as WeightedModifierType;
const weight = weightedModifierType.weight instanceof Function
? (weightedModifierType.weight as Function)(party)
: weightedModifierType.weight as integer;
if (weight)
total += weight;
else {
ignoredPoolIndexes[t].push(i++);
return total;
}
} else
total++;
thresholds.set(total, i++);
return total;
}, 0);
return [ t, Object.fromEntries(thresholds) ]
})));
console.log(modifierPoolThresholds)
}
export function getNewModifierType(): ModifierType {
const tierValue = Utils.randInt(256);
@ -451,6 +481,7 @@ export function getNewModifierType(): ModifierType {
break;
}
}
console.log(index, ignoredPoolIndexes[tier].filter(i => i <= index).length, ignoredPoolIndexes[tier])
let modifierType: ModifierType | WeightedModifierType = modifierPool[tier][index];
if (modifierType instanceof WeightedModifierType)
return (modifierType as WeightedModifierType).modifierType;

View File

@ -222,6 +222,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return this.stats[Stat.HP];
}
getHpRatio() {
return Math.floor((this.hp / this.getMaxHp()) * 100) / 100;
}
generateAndPopulateMoveset() {
this.moveset = [];
const movePool = [];
@ -450,7 +454,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
// Gen 1-4 formula
// return ((this.pokemon.baseExp * this.level) / 7) * (1 / 1)
// TODO: Update for exp share
return Math.floor(((this.species.baseExp * this.level) / 5) * (1 / 1) * ((Math.round(Math.sqrt(2 * this.level + 10)) * Math.pow(2 * this.level + 10, 2)) / (Math.round(Math.sqrt(this.level + victorLevel + 10)) * Math.pow(this.level + victorLevel + 10, 2)))) + 1;
const constantMultiplier = 4;
return Math.floor(((this.species.baseExp * this.level) / 5) * (1 / 1) * constantMultiplier * ((Math.round(Math.sqrt(2 * this.level + 10)) * Math.pow(2 * this.level + 10, 2)) / (Math.round(Math.sqrt(this.level + victorLevel + 10)) * Math.pow(this.level + victorLevel + 10, 2)))) + 1;
}
tint(color: number, alpha?: number, duration?: integer, ease?: string) {

View File

@ -285,7 +285,7 @@ class PartySlot extends Phaser.GameObjects.Container {
slotHpBar.setPositionRelative(slotBg, this.slotIndex ? 72 : 8, this.slotIndex ? 7 : 31);
slotHpBar.setOrigin(0, 0);
const hpRatio = this.pokemon.hp / this.pokemon.getMaxHp();
const hpRatio = this.pokemon.getHpRatio();
const slotHpOverlay = this.scene.add.sprite(0, 0, 'party_slot_hp_overlay', hpRatio > 0.5 ? 'high' : hpRatio > 0.25 ? 'medium' : 'low');
slotHpOverlay.setPositionRelative(slotHpBar, 16, 2);