Various changes

pull/1/head
Flashfyre 2023-03-30 23:02:35 -04:00
parent 1969d36669
commit d90c91af06
32 changed files with 4825 additions and 1116 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 404 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 274 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 290 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 251 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 262 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 226 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 454 B

After

Width:  |  Height:  |  Size: 270 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 303 B

View File

@ -1,211 +0,0 @@
import BattleScene from "./battle-scene";
import { default as PokemonSpecies, allSpecies, getPokemonSpecies } from "./pokemon-species";
import { Stat } from "./pokemon-stat";
import { Species } from "./species";
import { Type } from './type';
import * as Utils from './utils';
export enum ArenaType {
PLAINS = 1,
GRASS,
FOREST,
WATER,
SWAMP,
SEA,
MOUNTAIN,
LAND,
CAVE,
DESERT,
ICE_CAVE,
MEADOW,
POWER_PLANT,
VOLCANO,
GRAVEYARD,
DOJO,
RUINS,
ABYSS,
SPACE
};
enum PoolTier {
COMMON,
UNCOMMON,
RARE,
ULTRA_RARE,
LEGENDARY
};
export class Arena {
private scene: BattleScene;
public arenaType: integer;
private bgm: string;
private pokemonPool: PokemonSpecies[][];
constructor(scene: BattleScene, arenaType: integer, bgm: string) {
this.scene = scene;
this.arenaType = arenaType;
this.bgm = bgm;
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 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 {
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]);
ret = getPokemonSpecies(newSpeciesId);
}
return ret;
}
playBgm() {
this.scene.loadBgm(this.bgm);
this.scene.load.once(Phaser.Loader.Events.COMPLETE, () => this.scene.playBgm(this.bgm));
}
}
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.LEDYBA,
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.ODDISH, Species.PARAS, Species.VENONAT, Species.MEOWTH, Species.BELLSPROUT, Species.PICHU, Species.IGGLYBUFF,
Species.LOTAD, Species.SEEDOT, Species.SHROOMISH, Species.NINCADA, Species.AZURILL, Species.WHISMUR, Species.SKITTY, Species.BUDEW, Species.COMBEE, Species.CHERUBI,
Species.VENIPEDE
],
[PoolTier.RARE]: [ Species.ABRA, Species.CLEFFA, Species.WOOPER, Species.RALTS, Species.SURSKIT, Species.SLAKOTH, Species.DUCKLETT ],
[PoolTier.ULTRA_RARE]: [ Species.EEVEE, Species.TOGEPI, Species.SMEARGLE, Species.TYROGUE, Species.WYNAUT ],
[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))
return false;
for (let s in p.baseStats) {
let threshold: integer;
const stat = parseInt(s);
switch (stat) {
case Stat.HP:
threshold = 70;
break;
default:
threshold = 60;
break;
}
if (p.baseStats[s] > threshold) {
if (p.baseTotal <= 300 && p.baseExp <= 75 && (p.isOfType(Type.NORMAL) || p.isOfType(Type.BUG) || p.isOfType(Type.GRASS)))
return true;
return false;
}
}
return p.baseTotal <= 320 && p.baseExp <= 75;
},
[ArenaType.GRASS]: (p, t) => {
switch (t) {
case PoolTier.ULTRA_RARE:
return [ Species.ENTEI, Species.SUICUNE, Species.RAIKOU, Species.LATIOS, Species.LATIAS ].map(s => getPokemonSpecies(s));
case PoolTier.LEGENDARY:
return [ Species.MEW ].map(s => getPokemonSpecies(s));
}
return p.isOfType(Type.NORMAL) || p.isOfType(Type.FAIRY) || p.isOfType(Type.GRASS) || p.isOfType(Type.BUG) || p.isOfType(Type.ELECTRIC);
},
[ArenaType.FOREST]: (p, t) => {
switch (t) {
case PoolTier.LEGENDARY:
return getPokemonSpecies(Species.CELEBI);
}
return p.isOfType(Type.GRASS) || p.isOfType(Type.BUG) || p.isOfType(Type.POISON);
},
[ArenaType.WATER]: (p, t) => {
switch (t) {
case PoolTier.ULTRA_RARE:
return [ Species.UXIE, Species.MESPRIT, Species.AZELF ].map(s => getPokemonSpecies(s));
}
return p.isOfType(Type.WATER)
},
[ArenaType.SWAMP]: (p, t) => {
return p.isOfType(Type.GRASS) || p.isOfType(Type.WATER) || p.isOfType(Type.POISON);
},
[ArenaType.SEA]: (p, t) => {
switch (t) {
case PoolTier.ULTRA_RARE:
return [ Species.KYOGRE ].map(s => getPokemonSpecies(s));
case PoolTier.LEGENDARY:
return [ Species.LUGIA ].map(s => getPokemonSpecies(s));
}
return p.isOfType(Type.WATER);
},
[ArenaType.MOUNTAIN]: (p, t) => {
switch (t) {
case PoolTier.ULTRA_RARE:
return [ Species.ARTICUNO, Species.ZAPDOS, Species.MOLTRES ].map(s => getPokemonSpecies(s));
break;
case PoolTier.LEGENDARY:
return [ Species.HO_OH, Species.RAYQUAZA ].map(s => getPokemonSpecies(s));
}
return p.isOfType(Type.FLYING) || p.isOfType(Type.GROUND) || p.isOfType(Type.ROCK) || p.isOfType(Type.ELECTRIC) || p.isOfType(Type.STEEL);
},
[ArenaType.LAND]: (p, t) => {
switch (t) {
case PoolTier.ULTRA_RARE:
return [ Species.GROUDON ].map(s => getPokemonSpecies(s));
}
return p.isOfType(Type.GROUND);
},
[ArenaType.CAVE]: (p, t) => {
switch (t) {
case PoolTier.ULTRA_RARE:
return [ Species.REGIROCK, Species.REGICE, Species.REGISTEEL ].map(s => getPokemonSpecies(s));
case PoolTier.LEGENDARY:
return [ Species.MEWTWO, Species.REGIGIGAS ].map(s => getPokemonSpecies(s));
}
return p.isOfType(Type.ROCK);
},
[ArenaType.DESERT]: (p, t) => {
return p.isOfType(Type.GROUND) || p.isOfType(Type.ROCK);
},
[ArenaType.ICE_CAVE]: (p, t) => {
return p.isOfType(Type.ICE);
},
[ArenaType.MEADOW]: (p, t) => {
return p.isOfType(Type.FAIRY);
},
[ArenaType.POWER_PLANT]: (p, t) => {
return p.isOfType(Type.ELECTRIC);
},
[ArenaType.VOLCANO]: (p, t) => {
return p.isOfType(Type.FIRE);
},
[ArenaType.GRAVEYARD]: (p, t) => {
return p.isOfType(Type.GHOST);
},
[ArenaType.DOJO]: (p, t) => {
return p.isOfType(Type.FIGHTING);
},
[ArenaType.RUINS]: (p, t) => {
return p.isOfType(Type.PSYCHIC);
},
[ArenaType.ABYSS]: (p, t) => {
return p.isOfType(Type.DARK);
}
};

View File

@ -6,7 +6,7 @@ import { Mode } from './ui/ui';
import { Command } from "./ui/command-ui-handler"; import { Command } from "./ui/command-ui-handler";
import { interp } from "./temp_interpreter"; import { interp } from "./temp_interpreter";
import { Stat } from "./pokemon-stat"; import { Stat } from "./pokemon-stat";
import { ExpBoosterModifier, ExtraModifierModifier, getModifierTypesForWave, ModifierType, PokemonModifierType, regenerateModifierPoolThresholds } from "./modifier"; import { ExpBoosterModifier, ExpShareModifier, ExtraModifierModifier, getModifierTypesForWave, ModifierType, PokemonModifierType, regenerateModifierPoolThresholds } from "./modifier";
import PartyUiHandler from "./ui/party-ui-handler"; import PartyUiHandler from "./ui/party-ui-handler";
import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor as getPokeballTintColor, PokeballType } from "./pokeball"; import { doPokeballBounceAnim, getPokeballAtlasKey, getPokeballCatchMultiplier, getPokeballTintColor as getPokeballTintColor, PokeballType } from "./pokeball";
import { pokemonLevelMoves } from "./pokemon-level-moves"; import { pokemonLevelMoves } from "./pokemon-level-moves";
@ -68,14 +68,12 @@ export class NextEncounterPhase extends BattlePhase {
start() { start() {
super.start(); super.start();
this.scene.waveIndex++;
console.log(this.scene.getPlayerPokemon(), this.scene.getParty().map(p => p.name), this.scene.getPlayerPokemon().id) console.log(this.scene.getPlayerPokemon(), this.scene.getParty().map(p => p.name), this.scene.getPlayerPokemon().id)
this.scene.getEnemyPokemon().destroy(); this.scene.getEnemyPokemon().destroy();
const newEnemyPokemon = new EnemyPokemon(this.scene, this.scene.randomSpecies(true), this.scene.getLevelForWave()); const newEnemyPokemon = new EnemyPokemon(this.scene, this.scene.randomSpecies(true), this.scene.getLevelForNextWave());
newEnemyPokemon.loadAssets().then(() => { newEnemyPokemon.loadAssets().then(() => {
this.scene.setEnemyPokemon(newEnemyPokemon); this.scene.newBattle(newEnemyPokemon);
this.scene.field.add(newEnemyPokemon); this.scene.field.add(newEnemyPokemon);
this.scene.field.moveBelow(newEnemyPokemon, this.scene.getPlayerPokemon()); this.scene.field.moveBelow(newEnemyPokemon, this.scene.getPlayerPokemon());
newEnemyPokemon.tint(0, 0.5); newEnemyPokemon.tint(0, 0.5);
@ -169,7 +167,10 @@ export class SummonPhase extends BattlePhase {
onComplete: () => { onComplete: () => {
playerPokemon.cry(); playerPokemon.cry();
playerPokemon.getSprite().clearTint(); playerPokemon.getSprite().clearTint();
this.scene.time.delayedCall(1000, () => this.end()); this.scene.time.delayedCall(1000, () => {
this.scene.currentBattle.addParticipant(playerPokemon);
this.end();
});
} }
}); });
} }
@ -245,7 +246,13 @@ export class CheckSwitchPhase extends BattlePhase {
super.start(); super.start();
this.scene.ui.showText('Will you switch\nPOKéMON?', null, () => { this.scene.ui.showText('Will you switch\nPOKéMON?', null, () => {
this.scene.ui.setMode(Mode.SWITCH_CHECK, () => this.end()); this.scene.ui.setMode(Mode.SWITCH_CHECK, () => {
console.log('handler', this.scene.ui.getHandler());
console.log(this.scene.ui.getHandler().getCursor())
if (this.scene.ui.getHandler().getCursor())
this.scene.currentBattle.addParticipant(this.scene.getPlayerPokemon());
this.end();
});
}); });
} }
} }
@ -321,6 +328,20 @@ export abstract class PokemonPhase extends BattlePhase {
} }
} }
export abstract class PartyMemberPokemonPhase extends PokemonPhase {
protected partyMemberIndex: integer;
constructor(scene: BattleScene, partyMemberIndex: integer) {
super(scene, true);
this.partyMemberIndex = partyMemberIndex;
}
getPokemon() {
return this.scene.getParty()[this.partyMemberIndex];
}
}
abstract class MovePhase extends BattlePhase { abstract class MovePhase extends BattlePhase {
protected pokemon: Pokemon; protected pokemon: Pokemon;
protected move: PokemonMove; protected move: PokemonMove;
@ -474,6 +495,8 @@ export class FaintPhase extends PokemonPhase {
onComplete: () => { onComplete: () => {
pokemon.setVisible(false); pokemon.setVisible(false);
pokemon.y -= 150; pokemon.y -= 150;
if (pokemon instanceof PlayerPokemon)
this.scene.currentBattle.removeFaintedParticipant(pokemon as PlayerPokemon);
this.scene.field.remove(pokemon); this.scene.field.remove(pokemon);
this.end(); this.end();
} }
@ -490,8 +513,28 @@ export class VictoryPhase extends PokemonPhase {
start() { start() {
super.start(); super.start();
if (this.scene.getPlayerPokemon().level < 100) const participantIds = this.scene.currentBattle.playerParticipantIds;
this.scene.unshiftPhase(new ExpPhase(this.scene)); const party = this.scene.getParty();
const expShareModifier = this.scene.getModifier(ExpShareModifier) as ExpShareModifier;
const expValue = this.scene.getEnemyPokemon().getExpValue(party[0]);
for (let pm = 0; pm < party.length; pm++) {
const pokemon = party[pm];
if (!pokemon.hp)
continue;
const pId = pokemon.id;
const participated = participantIds.has(pId);
if (!participated && !expShareModifier)
continue;
if (pokemon.level < 100) {
let expMultiplier = 0;
if (participated)
expMultiplier += (1 / participantIds.size);
if (expShareModifier)
expMultiplier += expShareModifier.stackCount * 0.1;
console.log(pokemon.species.name, expMultiplier)
this.scene.unshiftPhase(new ExpPhase(this.scene, pm, expValue * expMultiplier));
}
}
this.scene.unshiftPhase(new SelectModifierPhase(this.scene)); this.scene.unshiftPhase(new SelectModifierPhase(this.scene));
this.scene.unshiftPhase(new NextEncounterPhase(this.scene)); this.scene.unshiftPhase(new NextEncounterPhase(this.scene));
@ -522,17 +565,22 @@ export class SwitchPhase extends BattlePhase {
} }
} }
export class ExpPhase extends PokemonPhase { export class ExpPhase extends PartyMemberPokemonPhase {
constructor(scene: BattleScene) { private expValue: number;
super(scene, true);
constructor(scene: BattleScene, partyMemberIndex: integer, expValue: number) {
super(scene, partyMemberIndex);
this.expValue = expValue;
} }
start() { start() {
super.start(); super.start();
const pokemon = this.getPokemon(); const pokemon = this.getPokemon();
let exp = new Utils.IntegerHolder(this.scene.getEnemyPokemon().getExpValue(pokemon.level)); let exp = new Utils.NumberHolder(this.expValue);
this.scene.applyModifiers(ExpBoosterModifier, exp); this.scene.applyModifiers(ExpBoosterModifier, exp);
exp.value = Math.floor(exp.value);
this.scene.ui.showText(`${pokemon.name} gained\n${exp.value} EXP. Points!`, null, () => { this.scene.ui.showText(`${pokemon.name} gained\n${exp.value} EXP. Points!`, null, () => {
const lastLevel = pokemon.level; const lastLevel = pokemon.level;
let newLevel: integer; let newLevel: integer;
@ -543,6 +591,8 @@ export class ExpPhase extends PokemonPhase {
pokemon.updateInfo(() => this.end()); pokemon.updateInfo(() => this.end());
}, null, true); }, null, true);
} }
} }
export class LevelUpPhase extends PokemonPhase { export class LevelUpPhase extends PokemonPhase {

View File

@ -1,5 +1,5 @@
import Phaser from 'phaser'; import Phaser from 'phaser';
import { ArenaType, Arena } from './arena'; import { Biome, BiomeArena } from './biome';
import UI from './ui/ui'; import UI from './ui/ui';
import { BattlePhase, EncounterPhase, SummonPhase, CommandPhase } from './battle-phase'; import { BattlePhase, EncounterPhase, SummonPhase, CommandPhase } from './battle-phase';
import { PlayerPokemon, EnemyPokemon } from './pokemon'; import { PlayerPokemon, EnemyPokemon } from './pokemon';
@ -9,6 +9,7 @@ import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, P
import { PokeballType } from './pokeball'; import { PokeballType } from './pokeball';
import { Species } from './species'; import { Species } from './species';
import { initAutoPlay } from './auto-play'; import { initAutoPlay } from './auto-play';
import { Battle } from './battle';
export default class BattleScene extends Phaser.Scene { export default class BattleScene extends Phaser.Scene {
private auto: boolean; private auto: boolean;
@ -17,7 +18,7 @@ export default class BattleScene extends Phaser.Scene {
private phaseQueue: Array<BattlePhase>; private phaseQueue: Array<BattlePhase>;
private phaseQueuePrepend: Array<BattlePhase>; private phaseQueuePrepend: Array<BattlePhase>;
private currentPhase: BattlePhase; private currentPhase: BattlePhase;
private arena: Arena; private arena: BiomeArena;
public field: Phaser.GameObjects.Container; public field: Phaser.GameObjects.Container;
public fieldUI: Phaser.GameObjects.Container; public fieldUI: Phaser.GameObjects.Container;
public arenaBg: Phaser.GameObjects.Image; public arenaBg: Phaser.GameObjects.Image;
@ -25,12 +26,11 @@ export default class BattleScene extends Phaser.Scene {
public arenaEnemy: Phaser.GameObjects.Image; public arenaEnemy: Phaser.GameObjects.Image;
public arenaEnemy2: Phaser.GameObjects.Image; public arenaEnemy2: Phaser.GameObjects.Image;
public trainer: Phaser.GameObjects.Sprite; public trainer: Phaser.GameObjects.Sprite;
public waveIndex: integer; public currentBattle: Battle;
public pokeballCounts = Object.fromEntries(Utils.getEnumValues(PokeballType).map(t => [ t, 0 ])); public pokeballCounts = Object.fromEntries(Utils.getEnumValues(PokeballType).map(t => [ t, 0 ]));
private party: PlayerPokemon[]; private party: PlayerPokemon[];
private modifierBar: ModifierBar; private modifierBar: ModifierBar;
private modifiers: Modifier[]; private modifiers: Modifier[];
private enemyPokemon: EnemyPokemon;
public uiContainer: Phaser.GameObjects.Container; public uiContainer: Phaser.GameObjects.Container;
public ui: UI; public ui: UI;
@ -117,8 +117,8 @@ export default class BattleScene extends Phaser.Scene {
this.loadAtlas('party_cancel', 'ui'); this.loadAtlas('party_cancel', 'ui');
// Load arena images // Load arena images
Utils.getEnumValues(ArenaType).map(at => { Utils.getEnumValues(Biome).map(at => {
const atKey = ArenaType[at].toLowerCase(); const atKey = Biome[at].toLowerCase();
this.loadImage(`${atKey}_bg`, 'arenas', `${atKey}_bg.png`); this.loadImage(`${atKey}_bg`, 'arenas', `${atKey}_bg.png`);
this.loadImage(`${atKey}_a`, 'arenas', `${atKey}_a.png`); this.loadImage(`${atKey}_a`, 'arenas', `${atKey}_a.png`);
this.loadImage(`${atKey}_b`, 'arenas', `${atKey}_b.png`); this.loadImage(`${atKey}_b`, 'arenas', `${atKey}_b.png`);
@ -177,15 +177,15 @@ export default class BattleScene extends Phaser.Scene {
this.field = field; this.field = field;
// Init arena // Init arena
const arenas = Utils.getEnumValues(ArenaType).map(at => new Arena(this, at, ArenaType[at].toLowerCase())); const arenas = Utils.getEnumValues(Biome).map(at => new BiomeArena(this, at, Biome[at].toLowerCase()));
const arena = arenas[Utils.randInt(11)]; const arena = arenas[Utils.randInt(11)];
this.arena = arena; this.arena = arena;
this.arenaBg = this.add.image(0, 0, `${ArenaType[arena.arenaType].toLowerCase()}_bg`); this.arenaBg = this.add.image(0, 0, `${Biome[arena.biomeType].toLowerCase()}_bg`);
this.arenaPlayer = this.add.image(340, 20, `${ArenaType[arena.arenaType].toLowerCase()}_a`); this.arenaPlayer = this.add.image(340, 20, `${Biome[arena.biomeType].toLowerCase()}_a`);
this.arenaEnemy = this.add.image(-240, 13, `${ArenaType[arena.arenaType].toLowerCase()}_b`); this.arenaEnemy = this.add.image(-240, 13, `${Biome[arena.biomeType].toLowerCase()}_b`);
this.arenaEnemy2 = this.add.image(-240, 13, `${ArenaType[arena.arenaType].toLowerCase()}_b`); this.arenaEnemy2 = this.add.image(-240, 13, `${Biome[arena.biomeType].toLowerCase()}_b`);
[this.arenaBg, this.arenaPlayer, this.arenaEnemy, this.arenaEnemy2].forEach(a => { [this.arenaBg, this.arenaPlayer, this.arenaEnemy, this.arenaEnemy2].forEach(a => {
a.setOrigin(0, 0); a.setOrigin(0, 0);
@ -209,8 +209,6 @@ export default class BattleScene extends Phaser.Scene {
this.add.existing(this.modifierBar); this.add.existing(this.modifierBar);
uiContainer.add(this.modifierBar); uiContainer.add(this.modifierBar);
this.waveIndex = 1;
this.party = []; this.party = [];
let loadPokemonAssets = []; let loadPokemonAssets = [];
@ -226,11 +224,12 @@ export default class BattleScene extends Phaser.Scene {
const enemySpecies = arena.randomSpecies(1); const enemySpecies = arena.randomSpecies(1);
console.log(enemySpecies.name); console.log(enemySpecies.name);
const enemyPokemon = new EnemyPokemon(this, enemySpecies, this.getLevelForWave()); const enemyPokemon = new EnemyPokemon(this, enemySpecies, this.getLevelForNextWave());
loadPokemonAssets.push(enemyPokemon.loadAssets()); loadPokemonAssets.push(enemyPokemon.loadAssets());
this.add.existing(enemyPokemon); this.add.existing(enemyPokemon);
this.enemyPokemon = enemyPokemon;
this.newBattle(enemyPokemon);
field.add(enemyPokemon); field.add(enemyPokemon);
@ -297,11 +296,12 @@ export default class BattleScene extends Phaser.Scene {
} }
getEnemyPokemon(): EnemyPokemon { getEnemyPokemon(): EnemyPokemon {
return this.enemyPokemon; return this.currentBattle.enemyPokemon;
} }
setEnemyPokemon(enemyPokemon: EnemyPokemon) { newBattle(enemyPokemon: EnemyPokemon): Battle {
this.enemyPokemon = enemyPokemon; this.currentBattle = new Battle((this.currentBattle?.waveIndex || 0) + 1, enemyPokemon);
return this.currentBattle;
} }
randomSpecies(fromArenaPool?: boolean): PokemonSpecies { randomSpecies(fromArenaPool?: boolean): PokemonSpecies {
@ -310,13 +310,14 @@ export default class BattleScene extends Phaser.Scene {
: allSpecies[(Utils.randInt(allSpecies.length)) - 1]; : allSpecies[(Utils.randInt(allSpecies.length)) - 1];
} }
getLevelForWave() { getLevelForNextWave() {
let averageLevel = 1 + this.waveIndex * 0.25; const waveIndex = (this.currentBattle?.waveIndex || 0) + 1;
let averageLevel = 1 + waveIndex * 0.25;
if (this.waveIndex % 10 === 0) if (waveIndex % 10 === 0)
return Math.floor(averageLevel * 1.25); return Math.floor(averageLevel * 1.25);
const deviation = 10 / this.waveIndex; const deviation = 10 / waveIndex;
return Math.max(Math.round(averageLevel + Utils.randGauss(deviation)), 1); return Math.max(Math.round(averageLevel + Utils.randGauss(deviation)), 1);
} }
@ -421,6 +422,10 @@ export default class BattleScene extends Phaser.Scene {
} }
} }
getModifier(modifierType: { new(...args: any[]): Modifier }): Modifier {
return this.modifiers.find(m => m instanceof modifierType);
}
applyModifiers(modifierType: { new(...args: any[]): Modifier }, ...args: any[]): void { applyModifiers(modifierType: { new(...args: any[]): Modifier }, ...args: any[]): void {
const modifiers = this.modifiers.filter(m => m instanceof modifierType && m.shouldApply(args)); const modifiers = this.modifiers.filter(m => m instanceof modifierType && m.shouldApply(args));
for (let modifier of modifiers) { for (let modifier of modifiers) {

21
src/battle.ts Normal file
View File

@ -0,0 +1,21 @@
import { EnemyPokemon, PlayerPokemon } from "./pokemon";
export class Battle {
public waveIndex: integer;
public enemyPokemon: EnemyPokemon;
public playerParticipantIds: Set<integer> = new Set<integer>();
constructor(waveIndex: integer, enemyPokemon: EnemyPokemon) {
this.waveIndex = waveIndex;
this.enemyPokemon = enemyPokemon;
}
addParticipant(playerPokemon: PlayerPokemon) {
console.log('add participant', playerPokemon.name)
this.playerParticipantIds.add(playerPokemon.id);
}
removeFaintedParticipant(playerPokemon: PlayerPokemon) {
this.playerParticipantIds.delete(playerPokemon.id);
}
}

3414
src/biome.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -61,9 +61,14 @@ export abstract class Modifier {
abstract apply(args: any[]): boolean; abstract apply(args: any[]): boolean;
incrementStack(): void { incrementStack(): void {
if (this.stackCount < this.getMaxStackCount())
this.stackCount++; this.stackCount++;
} }
getMaxStackCount(): integer {
return 99;
}
getIcon(scene: BattleScene): Phaser.GameObjects.Container { getIcon(scene: BattleScene): Phaser.GameObjects.Container {
const container = scene.add.container(0, 0); const container = scene.add.container(0, 0);
@ -83,7 +88,7 @@ export abstract class Modifier {
if (this.stackCount <= 1) if (this.stackCount <= 1)
return null; return null;
const text = addTextObject(scene, 16, 12, this.stackCount.toString(), TextStyle.PARTY, { fontSize: '66px' }); const text = addTextObject(scene, 16, 12, this.stackCount.toString(), TextStyle.PARTY, { fontSize: '66px', color: this.stackCount < this.getMaxStackCount() ? '#484848' : '#e64a18' });
text.setStroke('#424242', 16) text.setStroke('#424242', 16)
text.setOrigin(1, 0); text.setOrigin(1, 0);
@ -101,7 +106,7 @@ export abstract class ConsumableModifier extends Modifier {
} }
shouldApply(args: any[]): boolean { shouldApply(args: any[]): boolean {
return args.length === 1 && args[0] instanceof BattleScene; return super.shouldApply(args) && args.length === 1 && args[0] instanceof BattleScene;
} }
} }
@ -134,7 +139,7 @@ export abstract class PokemonModifier extends Modifier {
} }
shouldApply(args: any[]): boolean { shouldApply(args: any[]): boolean {
return args.length && args[0] === this.pokemonId; return super.shouldApply(args) && args.length && args[0] instanceof Pokemon && (this.pokemonId === -1 || (args[0] as Pokemon).id === this.pokemonId);
} }
getIcon(scene: BattleScene): Phaser.GameObjects.Container { getIcon(scene: BattleScene): Phaser.GameObjects.Container {
@ -180,12 +185,11 @@ export class PokemonBaseStatModifier extends PokemonModifier {
} }
shouldApply(args: any[]): boolean { shouldApply(args: any[]): boolean {
console.log(args, this.pokemonId, args)
return super.shouldApply(args) && args.length === 2 && args[1] instanceof Array<integer>; return super.shouldApply(args) && args.length === 2 && args[1] instanceof Array<integer>;
} }
apply(args: any[]): boolean { apply(args: any[]): boolean {
args[1][this.stat] = Math.min(Math.floor(args[1][this.stat] * (1 + this.stackCount * 0.1)), 999999); args[1][this.stat] = Math.min(Math.floor(args[1][this.stat] * (1 + this.stackCount * 0.2)), 999999);
return true; return true;
} }
@ -215,10 +219,6 @@ export abstract class ConsumablePokemonModifier extends PokemonModifier {
add(_modifierBar: ModifierBar, _modifiers: Modifier[]): boolean { add(_modifierBar: ModifierBar, _modifiers: Modifier[]): boolean {
return true; return true;
} }
shouldApply(args: any[]): boolean {
return args.length === 1 && args[0] instanceof Pokemon && (this.pokemonId === -1 || (args[0] as Pokemon).id === this.pokemonId);
}
} }
export class PokemonHpRestoreModifier extends ConsumablePokemonModifier { export class PokemonHpRestoreModifier extends ConsumablePokemonModifier {
@ -266,12 +266,26 @@ export class ExpBoosterModifier extends Modifier {
} }
apply(args: any[]): boolean { apply(args: any[]): boolean {
(args[0] as Utils.IntegerHolder).value = Math.floor((args[0] as Utils.IntegerHolder).value * (1 + (this.stackCount * (this.boostMultiplier)))); (args[0] as Utils.NumberHolder).value = Math.floor((args[0] as Utils.NumberHolder).value * (1 + (this.stackCount * (this.boostMultiplier))));
return true; return true;
} }
} }
export class ExpShareModifier extends Modifier {
constructor(type: ModifierType) {
super(type);
}
apply(_args: any[]): boolean {
return true;
}
getMaxStackCount(): integer {
return 5;
}
}
export class ShinyRateBoosterModifier extends Modifier { export class ShinyRateBoosterModifier extends Modifier {
constructor(type: ModifierType) { constructor(type: ModifierType) {
super(type); super(type);
@ -295,6 +309,10 @@ export class ShinyRateBoosterModifier extends Modifier {
return true; return true;
} }
getMaxStackCount(): integer {
return 5;
}
} }
export class ExtraModifierModifier extends Modifier { export class ExtraModifierModifier extends Modifier {
@ -361,7 +379,7 @@ export class PokemonHpRestoreModifierType extends PokemonModifierType {
constructor(name: string, restorePercent: integer, newModifierFunc?: Function, iconImage?: string) { constructor(name: string, restorePercent: integer, newModifierFunc?: Function, iconImage?: string) {
super(name, `Restore ${restorePercent} HP or ${restorePercent}% HP for one POKéMON, whichever is higher`, super(name, `Restore ${restorePercent} HP or ${restorePercent}% HP for one POKéMON, whichever is higher`,
newModifierFunc || ((_type, args) => new PokemonHpRestoreModifier(this, args[0], this.restorePercent, false)), newModifierFunc || ((_type, args) => new PokemonHpRestoreModifier(this, (args[0] as PlayerPokemon).id, this.restorePercent, false)),
(pokemon: PlayerPokemon) => { (pokemon: PlayerPokemon) => {
if (pokemon.hp >= pokemon.getMaxHp()) if (pokemon.hp >= pokemon.getMaxHp())
return PartyUiHandler.NoEffectMessage; return PartyUiHandler.NoEffectMessage;
@ -374,7 +392,7 @@ export class PokemonHpRestoreModifierType extends PokemonModifierType {
export class PokemonReviveModifierType extends PokemonHpRestoreModifierType { export class PokemonReviveModifierType extends PokemonHpRestoreModifierType {
constructor(name: string, restorePercent: integer, iconImage?: string) { constructor(name: string, restorePercent: integer, iconImage?: string) {
super(name, restorePercent, (_type, args) => new PokemonHpRestoreModifier(this, args[0], this.restorePercent, true), iconImage); super(name, restorePercent, (_type, args) => new PokemonHpRestoreModifier(this, (args[0] as PlayerPokemon).id, this.restorePercent, true), iconImage);
this.description = `Revive one POKéMON and restore ${restorePercent}% HP`; this.description = `Revive one POKéMON and restore ${restorePercent}% HP`;
this.selectFilter = (pokemon: PlayerPokemon) => { this.selectFilter = (pokemon: PlayerPokemon) => {
@ -389,7 +407,7 @@ export class PokemonBaseStatBoosterModifierType extends PokemonModifierType {
private stat: Stat; private stat: Stat;
constructor(name: string, stat: Stat, _iconImage?: string) { constructor(name: string, stat: Stat, _iconImage?: string) {
super(name, `Increases one POKéMON's base ${getStatName(stat)} by 10%` , (_type, args) => new PokemonBaseStatModifier(this, args[0], this.stat)); super(name, `Increases one POKéMON's base ${getStatName(stat)} by 20%` , (_type, args) => new PokemonBaseStatModifier(this, (args[0] as PlayerPokemon).id, this.stat));
this.stat = stat; this.stat = stat;
} }
@ -439,23 +457,27 @@ const modifierPool = {
const thresholdPartyMemberCount = party.filter(p => p.getHpRatio() <= 0.75).length; const thresholdPartyMemberCount = party.filter(p => p.getHpRatio() <= 0.75).length;
return Math.ceil(thresholdPartyMemberCount / 3); return Math.ceil(thresholdPartyMemberCount / 3);
}), }),
].map(m => { m.setTier(ModifierTier.COMMON); return m; }),
[ModifierTier.GREAT]: [
new WeightedModifierType(new AddPokeballModifierType(PokeballType.GREAT_BALL, 5, 'gb'), 3),
new WeightedModifierType(new PokemonReviveModifierType('REVIVE', 50), (party: Array<PlayerPokemon>) => {
const faintedPartyMemberCount = party.filter(p => !p.hp).length;
return faintedPartyMemberCount * 3;
}),
new WeightedModifierType(new PokemonReviveModifierType('MAX REVIVE', 100), (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 thresholdPartyMemberCount;
}),
new PokemonBaseStatBoosterModifierType('HP-UP', Stat.HP), new PokemonBaseStatBoosterModifierType('HP-UP', Stat.HP),
new PokemonBaseStatBoosterModifierType('PROTEIN', Stat.ATK), new PokemonBaseStatBoosterModifierType('PROTEIN', Stat.ATK),
new PokemonBaseStatBoosterModifierType('IRON', Stat.DEF), new PokemonBaseStatBoosterModifierType('IRON', Stat.DEF),
new PokemonBaseStatBoosterModifierType('CALCIUM', Stat.SPATK), new PokemonBaseStatBoosterModifierType('CALCIUM', Stat.SPATK),
new PokemonBaseStatBoosterModifierType('ZINC', Stat.SPDEF), new PokemonBaseStatBoosterModifierType('ZINC', Stat.SPDEF),
new PokemonBaseStatBoosterModifierType('CARBOS', Stat.SPD) new PokemonBaseStatBoosterModifierType('CARBOS', Stat.SPD)
].map(m => { m.setTier(ModifierTier.COMMON); return m; }),
[ModifierTier.GREAT]: [
new AddPokeballModifierType(PokeballType.GREAT_BALL, 5, 'gb'),
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; }), ].map(m => { m.setTier(ModifierTier.GREAT); return m; }),
[ModifierTier.ULTRA]: [ [ModifierTier.ULTRA]: [
new AddPokeballModifierType(PokeballType.ULTRA_BALL, 5, 'ub'), new AddPokeballModifierType(PokeballType.ULTRA_BALL, 5, 'ub'),
@ -463,13 +485,14 @@ const modifierPool = {
const thresholdPartyMemberCount = party.filter(p => p.getHpRatio() <= 0.5).length; const thresholdPartyMemberCount = party.filter(p => p.getHpRatio() <= 0.5).length;
return Math.ceil(thresholdPartyMemberCount / 3); return Math.ceil(thresholdPartyMemberCount / 3);
}), }),
new ExpBoosterModifierType('LUCKY EGG', 25)
].map(m => { m.setTier(ModifierTier.ULTRA); return m; }),
[ModifierTier.MASTER]: [
new AddPokeballModifierType(PokeballType.MASTER_BALL, 1, 'mb'),
new WeightedModifierType(new AllPokemonFullReviveModifierType('SACRED ASH'), (party: Array<PlayerPokemon>) => { new WeightedModifierType(new AllPokemonFullReviveModifierType('SACRED ASH'), (party: Array<PlayerPokemon>) => {
return party.filter(p => !p.hp).length >= Math.ceil(party.length / 2) ? 1 : 0; return party.filter(p => !p.hp).length >= Math.ceil(party.length / 2) ? 1 : 0;
}), }),
new ExpBoosterModifierType('LUCKY EGG', 25),
new ModifierType('EXP. SHARE', 'All POKéMON in your party gain an additional 10% of a battle\'s EXP. Points', (type, _args) => new ExpShareModifier(type), 'exp_share')
].map(m => { m.setTier(ModifierTier.ULTRA); return m; }),
[ModifierTier.MASTER]: [
new AddPokeballModifierType(PokeballType.MASTER_BALL, 1, 'mb'),
new WeightedModifierType(new ModifierType('SHINY CHARM', 'Dramatically increases the chance of a wild POKéMON being shiny', (type, _args) => new ShinyRateBoosterModifier(type)), 2) new WeightedModifierType(new ModifierType('SHINY CHARM', 'Dramatically increases the chance of a wild POKéMON being shiny', (type, _args) => new ShinyRateBoosterModifier(type)), 2)
].map(m => { m.setTier(ModifierTier.MASTER); return m; }), ].map(m => { m.setTier(ModifierTier.MASTER); return m; }),
[ModifierTier.LUXURY]: [ [ModifierTier.LUXURY]: [

View File

@ -345,7 +345,7 @@ export const pokemonEvolutions = {
new SpeciesEvolution(Species.KIRLIA, 20, null, null) new SpeciesEvolution(Species.KIRLIA, 20, null, null)
], ],
[Species.KIRLIA]: [ [Species.KIRLIA]: [
new SpeciesEvolution(Species.GARDEVOIR, 30, null, null), new SpeciesEvolution(Species.GARDEVOIR, 30, null, new SpeciesEvolutionCondition((p: Pokemon) => !p.gender, true)),
new SpeciesEvolution(Species.GALLADE, 1, "Dawn Stone", new SpeciesEvolutionCondition((p: Pokemon) => p.gender, true), SpeciesWildEvolutionRate.SLOW) new SpeciesEvolution(Species.GALLADE, 1, "Dawn Stone", new SpeciesEvolutionCondition((p: Pokemon) => p.gender, true), SpeciesWildEvolutionRate.SLOW)
], ],
[Species.SURSKIT]: [ [Species.SURSKIT]: [

View File

@ -9,7 +9,7 @@ import * as Utils from './utils';
import { getTypeDamageMultiplier } from './type'; import { getTypeDamageMultiplier } from './type';
import { getLevelTotalExp } from './exp'; import { getLevelTotalExp } from './exp';
import { Stat } from './pokemon-stat'; import { Stat } from './pokemon-stat';
import { PokemonBaseStatModifier as PokemonBaseStatBoosterModifier, ShinyRateBoosterModifier } from './modifier'; import { ExpShareModifier, PokemonBaseStatModifier as PokemonBaseStatBoosterModifier, ShinyRateBoosterModifier } from './modifier';
import { PokeballType } from './pokeball'; import { PokeballType } from './pokeball';
export default abstract class Pokemon extends Phaser.GameObjects.Container { export default abstract class Pokemon extends Phaser.GameObjects.Container {
@ -450,11 +450,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}); });
} }
getExpValue(victorLevel: integer): integer { getExpValue(victor: Pokemon): integer {
// Gen 1-4 formula return ((this.species.baseExp * this.level) / 5) * ((Math.round(Math.sqrt(2 * this.level + 10)) * Math.pow(2 * this.level + 10, 2)) / (Math.round(Math.sqrt(this.level + victor.level + 10)) * Math.pow(this.level + victor.level + 10, 2))) + 1;
// 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;
} }
tint(color: number, alpha?: number, duration?: integer, ease?: string) { tint(color: number, alpha?: number, duration?: integer, ease?: string) {

View File

@ -24,6 +24,10 @@ export default abstract class UiHandler {
return this.scene.ui; return this.scene.ui;
} }
getCursor(): integer {
return this.cursor;
}
setCursor(cursor: integer): boolean { setCursor(cursor: integer): boolean {
const changed = this.cursor !== cursor; const changed = this.cursor !== cursor;
if (changed) if (changed)

View File

@ -58,6 +58,13 @@ export function getEnumValues(enumType) {
return Object.values(enumType).filter(v => !isNaN(parseInt(v.toString()))).map(v => parseInt(v.toString())); return Object.values(enumType).filter(v => !isNaN(parseInt(v.toString()))).map(v => parseInt(v.toString()));
} }
export class NumberHolder {
public value: number;
constructor(value: number) {
this.value = value;
}
}
export class IntegerHolder { export class IntegerHolder {
public value: integer; public value: integer;