Add WiP trainer logic
This commit is contained in:
1 parent
798f6cc53f
commit
48797cb20f
151 files changed
+114315
-129
No files matched your search
+168
-104
@@ -28,7 +28,7 @@ import { ArenaTagType, ArenaTrapTag, TrickRoomTag } from "./data/arena-tag";
|
||||
import { CheckTrappedAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, SuppressWeatherEffectAbAttr, applyCheckTrappedAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreWeatherEffectAbAttrs } from "./data/ability";
|
||||
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
||||
import { getBiomeKey } from "./arena";
|
||||
import { BattlerIndex, TurnCommand } from "./battle";
|
||||
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
||||
import { GameMode } from "./game-mode";
|
||||
|
||||
export class CheckLoadPhase extends BattlePhase {
|
||||
@@ -74,13 +74,15 @@ export class CheckLoadPhase extends BattlePhase {
|
||||
} else
|
||||
this.scene.arena.playBgm();
|
||||
|
||||
const availablePartyMembers = this.scene.getParty().filter(p => !p.isFainted()).length;
|
||||
|
||||
this.scene.pushPhase(new EncounterPhase(this.scene, this.loaded));
|
||||
this.scene.pushPhase(new SummonPhase(this.scene, 0));
|
||||
if (this.scene.currentBattle.double && this.scene.getParty().filter(p => !p.isFainted()).length > 1)
|
||||
if (this.scene.currentBattle.double && availablePartyMembers > 1)
|
||||
this.scene.pushPhase(new SummonPhase(this.scene, 1));
|
||||
if (this.scene.currentBattle.waveIndex > 1) {
|
||||
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 0, this.scene.currentBattle.double));
|
||||
if (this.scene.currentBattle.double)
|
||||
if (this.scene.currentBattle.double && availablePartyMembers > 1)
|
||||
this.scene.pushPhase(new CheckSwitchPhase(this.scene, 1, this.scene.currentBattle.double));
|
||||
}
|
||||
|
||||
@@ -175,18 +177,44 @@ export abstract class PokemonPhase extends FieldPhase {
|
||||
export abstract class PartyMemberPokemonPhase extends FieldPhase {
|
||||
protected partyMemberIndex: integer;
|
||||
protected fieldIndex: integer;
|
||||
protected player: boolean;
|
||||
|
||||
constructor(scene: BattleScene, partyMemberIndex: integer) {
|
||||
constructor(scene: BattleScene, partyMemberIndex: integer, player: boolean) {
|
||||
super(scene);
|
||||
|
||||
this.partyMemberIndex = partyMemberIndex;
|
||||
this.fieldIndex = partyMemberIndex < this.scene.currentBattle.getBattlerCount()
|
||||
? partyMemberIndex
|
||||
: -1;
|
||||
this.player = player;
|
||||
}
|
||||
|
||||
getPokemon() {
|
||||
return this.scene.getParty()[this.partyMemberIndex];
|
||||
getParty(): Pokemon[] {
|
||||
return this.player ? this.scene.getParty() : this.scene.getEnemyParty();
|
||||
}
|
||||
|
||||
getPokemon(): Pokemon {
|
||||
return this.getParty()[this.partyMemberIndex];
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class PlayerPartyMemberPokemonPhase extends PartyMemberPokemonPhase {
|
||||
constructor(scene: BattleScene, partyMemberIndex: integer) {
|
||||
super(scene, partyMemberIndex, true);
|
||||
}
|
||||
|
||||
getPlayerPokemon(): PlayerPokemon {
|
||||
return super.getPokemon() as PlayerPokemon;
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class EnemyPartyMemberPokemonPhase extends PartyMemberPokemonPhase {
|
||||
constructor(scene: BattleScene, partyMemberIndex: integer) {
|
||||
super(scene, partyMemberIndex, false);
|
||||
}
|
||||
|
||||
getEnemyPokemon(): EnemyPokemon {
|
||||
return super.getPokemon() as EnemyPokemon;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -211,26 +239,38 @@ export class EncounterPhase extends BattlePhase {
|
||||
battle.enemyLevels.forEach((level, e) => {
|
||||
const enemySpecies = this.scene.randomSpecies(battle.waveIndex, level, true);
|
||||
if (!this.loaded)
|
||||
battle.enemyField[e] = new EnemyPokemon(this.scene, enemySpecies, level);
|
||||
const enemyPokemon = this.scene.getEnemyField()[e];
|
||||
enemyPokemon.resetSummonData();
|
||||
|
||||
this.scene.gameData.setPokemonSeen(enemyPokemon);
|
||||
battle.enemyParty[e] = new EnemyPokemon(this.scene, enemySpecies, level);
|
||||
const enemyPokemon = this.scene.getEnemyParty()[e];
|
||||
if (e < (battle.double ? 2 : 1)) {
|
||||
enemyPokemon.setX(-66 + enemyPokemon.getFieldPositionOffset()[0]);
|
||||
enemyPokemon.resetSummonData();
|
||||
this.scene.gameData.setPokemonSeen(enemyPokemon);
|
||||
}
|
||||
|
||||
loadEnemyAssets.push(enemyPokemon.loadAssets());
|
||||
|
||||
console.log(enemyPokemon.species.name, enemyPokemon.species.speciesId, enemyPokemon.stats);
|
||||
});
|
||||
|
||||
if (battle.battleType === BattleType.TRAINER)
|
||||
loadEnemyAssets.push(battle.trainer.loadAssets());
|
||||
|
||||
Promise.all(loadEnemyAssets).then(() => {
|
||||
battle.enemyField.forEach((enemyPokemon, e) => {
|
||||
this.scene.field.add(enemyPokemon);
|
||||
const playerPokemon = this.scene.getPlayerPokemon();
|
||||
if (playerPokemon.visible)
|
||||
this.scene.field.moveBelow(enemyPokemon as Pokemon, playerPokemon);
|
||||
enemyPokemon.tint(0, 0.5);
|
||||
if (battle.enemyField.length > 1)
|
||||
enemyPokemon.setFieldPosition(e ? FieldPosition.RIGHT : FieldPosition.LEFT);
|
||||
battle.enemyParty.forEach((enemyPokemon, e) => {
|
||||
if (e < (battle.double ? 2 : 1)) {
|
||||
if (battle.battleType === BattleType.WILD) {
|
||||
this.scene.field.add(enemyPokemon);
|
||||
const playerPokemon = this.scene.getPlayerPokemon();
|
||||
if (playerPokemon.visible)
|
||||
this.scene.field.moveBelow(enemyPokemon as Pokemon, playerPokemon);
|
||||
enemyPokemon.tint(0, 0.5);
|
||||
} else if (battle.battleType === BattleType.TRAINER) {
|
||||
enemyPokemon.setVisible(false);
|
||||
this.scene.currentBattle.trainer.tint(0, 0.5);
|
||||
}
|
||||
if (battle.double)
|
||||
enemyPokemon.setFieldPosition(e ? FieldPosition.RIGHT : FieldPosition.LEFT);
|
||||
}
|
||||
});
|
||||
|
||||
if (!this.loaded) {
|
||||
@@ -256,23 +296,47 @@ export class EncounterPhase extends BattlePhase {
|
||||
|
||||
const enemyField = this.scene.getEnemyField();
|
||||
this.scene.tweens.add({
|
||||
targets: [ this.scene.arenaEnemy, enemyField, this.scene.arenaPlayer, this.scene.trainer ].flat(),
|
||||
x: (_target, _key, value, fieldIndex: integer) => fieldIndex < 1 + (enemyField.length) ? value + 300 : value - 300,
|
||||
targets: [ this.scene.arenaEnemy, this.scene.currentBattle.trainer, enemyField, this.scene.arenaPlayer, this.scene.trainer ].flat(),
|
||||
x: (_target, _key, value, fieldIndex: integer) => fieldIndex < 2 + (enemyField.length) ? value + 300 : value - 300,
|
||||
duration: 2000,
|
||||
onComplete: () => {
|
||||
enemyField.forEach(enemyPokemon => {
|
||||
enemyPokemon.untint(100, 'Sine.easeOut');
|
||||
enemyPokemon.cry();
|
||||
enemyPokemon.showInfo();
|
||||
});
|
||||
const text = enemyField.length === 1
|
||||
? `A wild ${enemyField[0].name} appeared!`
|
||||
: `A wild ${enemyField[0].name}\nand ${enemyField[1].name} appeared!`;
|
||||
this.scene.ui.showText(text, null, () => this.end(), 1500);
|
||||
}
|
||||
onComplete: () => this.doEncounterCommon()
|
||||
});
|
||||
}
|
||||
|
||||
doEncounterCommon() {
|
||||
const enemyField = this.scene.getEnemyField();
|
||||
|
||||
if (this.scene.currentBattle.battleType === BattleType.WILD) {
|
||||
enemyField.forEach(enemyPokemon => {
|
||||
enemyPokemon.untint(100, 'Sine.easeOut');
|
||||
enemyPokemon.cry();
|
||||
enemyPokemon.showInfo();
|
||||
});
|
||||
let text = enemyField.length === 1
|
||||
? `A wild ${enemyField[0].name} appeared!`
|
||||
: `A wild ${enemyField[0].name}\nand ${enemyField[1].name} appeared!`;
|
||||
this.scene.ui.showText(text, null, () => this.end(), 1500);
|
||||
} else if (this.scene.currentBattle.battleType === BattleType.TRAINER) {
|
||||
this.scene.currentBattle.trainer.untint(100, 'Sine.easeOut');
|
||||
this.scene.currentBattle.trainer.playAnim();
|
||||
const text = `${this.scene.currentBattle.trainer.getName()}\nwould like to battle!`;
|
||||
this.scene.ui.showText(text, null, () => {
|
||||
this.scene.tweens.add({
|
||||
targets: this.scene.currentBattle.trainer,
|
||||
x: '+=16',
|
||||
y: '-=16',
|
||||
alpha: 0,
|
||||
ease: 'Sine.easeInOut',
|
||||
duration: 750
|
||||
});
|
||||
this.scene.unshiftPhase(new SummonPhase(this.scene, 0, false));
|
||||
if (this.scene.currentBattle.double)
|
||||
this.scene.unshiftPhase(new SummonPhase(this.scene, 1, false));
|
||||
this.end();
|
||||
}, 1500);
|
||||
}
|
||||
}
|
||||
|
||||
end() {
|
||||
const enemyField = this.scene.getEnemyField();
|
||||
|
||||
@@ -298,22 +362,15 @@ export class NextEncounterPhase extends EncounterPhase {
|
||||
doEncounter(): void {
|
||||
const enemyField = this.scene.getEnemyField();
|
||||
this.scene.tweens.add({
|
||||
targets: [ this.scene.arenaEnemy, this.scene.arenaNextEnemy, enemyField ].flat(),
|
||||
targets: [ this.scene.arenaEnemy, this.scene.arenaNextEnemy, this.scene.currentBattle.trainer, enemyField ].flat(),
|
||||
x: '+=300',
|
||||
duration: 2000,
|
||||
onComplete: () => {
|
||||
this.scene.arenaEnemy.setX(this.scene.arenaNextEnemy.x);
|
||||
this.scene.arenaEnemy.setAlpha(1);
|
||||
this.scene.arenaNextEnemy.setX(this.scene.arenaNextEnemy.x - 300);
|
||||
enemyField.forEach(enemyPokemon => {
|
||||
enemyPokemon.untint(100, 'Sine.easeOut');
|
||||
enemyPokemon.cry();
|
||||
enemyPokemon.showInfo();
|
||||
});
|
||||
const text = enemyField.length === 1
|
||||
? `A wild ${enemyField[0].name} appeared!`
|
||||
: `A wild ${enemyField[0].name}\nand ${enemyField[1].name} appeared!`;
|
||||
this.scene.ui.showText(text, null, () => this.end(), 1500);
|
||||
|
||||
this.doEncounterCommon();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -332,17 +389,7 @@ export class NewBiomeEncounterPhase extends NextEncounterPhase {
|
||||
targets: [ this.scene.arenaEnemy, enemyField ].flat(),
|
||||
x: '+=300',
|
||||
duration: 2000,
|
||||
onComplete: () => {
|
||||
enemyField.forEach(enemyPokemon => {
|
||||
enemyPokemon.untint(100, 'Sine.easeOut');
|
||||
enemyPokemon.cry();
|
||||
enemyPokemon.showInfo();
|
||||
});
|
||||
const text = enemyField.length === 1
|
||||
? `A wild ${enemyField[0].name} appeared!`
|
||||
: `A wild ${enemyField[0].name}\nand ${enemyField[1].name} appeared!`;
|
||||
this.scene.ui.showText(text, null, () => this.end(), 1500);
|
||||
}
|
||||
onComplete: () => this.doEncounterCommon()
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -461,8 +508,8 @@ export class SwitchBiomePhase extends BattlePhase {
|
||||
}
|
||||
|
||||
export class SummonPhase extends PartyMemberPokemonPhase {
|
||||
constructor(scene: BattleScene, fieldIndex: integer) {
|
||||
super(scene, fieldIndex);
|
||||
constructor(scene: BattleScene, fieldIndex: integer, player?: boolean) {
|
||||
super(scene, fieldIndex, player !== undefined ? player : true);
|
||||
}
|
||||
|
||||
start() {
|
||||
@@ -474,78 +521,89 @@ export class SummonPhase extends PartyMemberPokemonPhase {
|
||||
preSummon(): void {
|
||||
const partyMember = this.getPokemon();
|
||||
if (partyMember.isFainted()) {
|
||||
const party = this.scene.getParty();
|
||||
const party = this.getParty();
|
||||
const nonFaintedIndex = party.slice(this.partyMemberIndex).findIndex(p => !p.isFainted()) + this.partyMemberIndex;
|
||||
const nonFaintedPartyMember = party[nonFaintedIndex];
|
||||
party[nonFaintedIndex] = partyMember;
|
||||
party[this.partyMemberIndex] = nonFaintedPartyMember;
|
||||
}
|
||||
|
||||
this.scene.ui.showText(`Go! ${this.getPokemon().name}!`);
|
||||
this.scene.trainer.play('trainer_m_pb');
|
||||
this.scene.tweens.add({
|
||||
targets: this.scene.trainer,
|
||||
x: -36,
|
||||
duration: 1000
|
||||
});
|
||||
this.scene.time.delayedCall(750, () => this.summon());
|
||||
if (this.player) {
|
||||
this.scene.ui.showText(`Go! ${this.getPokemon().name}!`);
|
||||
if (this.player)
|
||||
this.scene.trainer.play('trainer_m_pb');
|
||||
this.scene.tweens.add({
|
||||
targets: this.scene.trainer,
|
||||
x: -36,
|
||||
duration: 1000
|
||||
});
|
||||
this.scene.time.delayedCall(750, () => this.summon());
|
||||
} else
|
||||
this.scene.ui.showText(`${this.scene.currentBattle.trainer.getName()} sent out\n${this.getPokemon().name}!`, null, () => this.summon());
|
||||
}
|
||||
|
||||
summon(): void {
|
||||
const pokeball = this.scene.add.sprite(36, 80, 'pb', 'pb');
|
||||
const pokeball = this.scene.add.sprite(this.player ? 36 : 248, this.player ? 80 : 44, 'pb', 'pb');
|
||||
pokeball.setVisible(false);
|
||||
pokeball.setOrigin(0.5, 0.625);
|
||||
this.scene.field.add(pokeball);
|
||||
|
||||
const playerPokemon = this.getPokemon();
|
||||
const pokemon = this.getPokemon();
|
||||
|
||||
if (this.fieldIndex === 1)
|
||||
playerPokemon.setFieldPosition(FieldPosition.RIGHT, 0);
|
||||
else
|
||||
playerPokemon.setFieldPosition(!this.scene.currentBattle.double ? FieldPosition.CENTER : FieldPosition.LEFT);
|
||||
pokemon.setFieldPosition(FieldPosition.RIGHT, 0);
|
||||
else {
|
||||
const availablePartyMembers = this.getParty().filter(p => !p.isFainted()).length;
|
||||
pokemon.setFieldPosition(!this.scene.currentBattle.double || availablePartyMembers === 1 ? FieldPosition.CENTER : FieldPosition.LEFT);
|
||||
}
|
||||
|
||||
const fpOffset = playerPokemon.getFieldPositionOffset();
|
||||
const fpOffset = pokemon.getFieldPositionOffset();
|
||||
|
||||
pokeball.setVisible(true);
|
||||
|
||||
this.scene.tweens.add({
|
||||
targets: pokeball,
|
||||
duration: 650,
|
||||
x: 100 + fpOffset[0]
|
||||
x: (this.player ? 100 : 236) + fpOffset[0]
|
||||
});
|
||||
|
||||
this.scene.tweens.add({
|
||||
targets: pokeball,
|
||||
duration: 150,
|
||||
ease: 'Cubic.easeOut',
|
||||
y: 70 + fpOffset[1],
|
||||
y: (this.player ? 70 : 34) + fpOffset[1],
|
||||
onComplete: () => {
|
||||
this.scene.tweens.add({
|
||||
targets: pokeball,
|
||||
duration: 500,
|
||||
ease: 'Cubic.easeIn',
|
||||
angle: 1440,
|
||||
y: 132 + fpOffset[1],
|
||||
y: (this.player ? 132 : 86) + fpOffset[1],
|
||||
onComplete: () => {
|
||||
this.scene.sound.play('pb_rel');
|
||||
pokeball.destroy();
|
||||
this.scene.add.existing(playerPokemon);
|
||||
this.scene.field.add(playerPokemon);
|
||||
playerPokemon.showInfo();
|
||||
playerPokemon.playAnim();
|
||||
playerPokemon.setVisible(true);
|
||||
playerPokemon.setScale(0.5);
|
||||
playerPokemon.tint(getPokeballTintColor(playerPokemon.pokeball));
|
||||
playerPokemon.untint(250, 'Sine.easeIn');
|
||||
this.scene.add.existing(pokemon);
|
||||
this.scene.field.add(pokemon);
|
||||
if (!this.player) {
|
||||
const playerPokemon = this.scene.getPlayerPokemon() as Pokemon;
|
||||
if (playerPokemon.visible)
|
||||
this.scene.field.moveBelow(pokemon, playerPokemon);
|
||||
}
|
||||
pokemon.showInfo();
|
||||
pokemon.playAnim();
|
||||
pokemon.setVisible(true);
|
||||
pokemon.setScale(0.5);
|
||||
pokemon.tint(getPokeballTintColor(pokemon.pokeball));
|
||||
pokemon.untint(250, 'Sine.easeIn');
|
||||
this.scene.tweens.add({
|
||||
targets: playerPokemon,
|
||||
targets: pokemon,
|
||||
duration: 250,
|
||||
ease: 'Sine.easeIn',
|
||||
scale: 1,
|
||||
onComplete: () => {
|
||||
playerPokemon.cry();
|
||||
playerPokemon.getSprite().clearTint();
|
||||
playerPokemon.resetSummonData();
|
||||
pokemon.cry();
|
||||
pokemon.getSprite().clearTint();
|
||||
pokemon.resetSummonData();
|
||||
this.scene.time.delayedCall(1000, () => this.end());
|
||||
}
|
||||
});
|
||||
@@ -582,10 +640,10 @@ export class SwitchSummonPhase extends SummonPhase {
|
||||
private doReturn: boolean;
|
||||
private batonPass: boolean;
|
||||
|
||||
private lastPokemon: PlayerPokemon;
|
||||
private lastPokemon: Pokemon;
|
||||
|
||||
constructor(scene: BattleScene, fieldIndex: integer, slotIndex: integer, doReturn: boolean, batonPass: boolean) {
|
||||
super(scene, fieldIndex);
|
||||
constructor(scene: BattleScene, fieldIndex: integer, slotIndex: integer, doReturn: boolean, batonPass: boolean, player?: boolean) {
|
||||
super(scene, fieldIndex, player !== undefined ? player : true);
|
||||
|
||||
this.slotIndex = slotIndex;
|
||||
this.doReturn = doReturn;
|
||||
@@ -598,30 +656,30 @@ export class SwitchSummonPhase extends SummonPhase {
|
||||
return;
|
||||
}
|
||||
|
||||
const playerPokemon = this.getPokemon();
|
||||
const pokemon = this.getPokemon();
|
||||
|
||||
if (!this.batonPass)
|
||||
this.scene.getEnemyField().forEach(enemyPokemon => enemyPokemon.removeTagsBySourceId(playerPokemon.id));
|
||||
this.scene.getEnemyField().forEach(enemyPokemon => enemyPokemon.removeTagsBySourceId(pokemon.id));
|
||||
|
||||
this.scene.ui.showText(`Come back, ${playerPokemon.name}!`);
|
||||
this.scene.ui.showText(this.player ? `Come back, ${pokemon.name}!` : `${this.scene.currentBattle.trainer.getName()}\nwithdrew ${pokemon.name}!`);
|
||||
this.scene.sound.play('pb_rel');
|
||||
playerPokemon.hideInfo();
|
||||
playerPokemon.tint(getPokeballTintColor(playerPokemon.pokeball), 1, 250, 'Sine.easeIn');
|
||||
pokemon.hideInfo();
|
||||
pokemon.tint(getPokeballTintColor(pokemon.pokeball), 1, 250, 'Sine.easeIn');
|
||||
this.scene.tweens.add({
|
||||
targets: playerPokemon,
|
||||
targets: pokemon,
|
||||
duration: 250,
|
||||
ease: 'Sine.easeIn',
|
||||
scale: 0.5,
|
||||
onComplete: () => {
|
||||
playerPokemon.setVisible(false);
|
||||
this.scene.field.remove(playerPokemon);
|
||||
pokemon.setVisible(false);
|
||||
this.scene.field.remove(pokemon);
|
||||
this.scene.time.delayedCall(750, () => this.switchAndSummon());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
switchAndSummon() {
|
||||
const party = this.scene.getParty();
|
||||
const party = this.getParty();
|
||||
const switchedPokemon = party[this.slotIndex];
|
||||
this.lastPokemon = this.getPokemon();
|
||||
if (this.batonPass && switchedPokemon) {
|
||||
@@ -635,7 +693,7 @@ export class SwitchSummonPhase extends SummonPhase {
|
||||
if (switchedPokemon) {
|
||||
party[this.slotIndex] = this.lastPokemon;
|
||||
party[this.fieldIndex] = switchedPokemon;
|
||||
this.scene.ui.showText(`Go! ${switchedPokemon.name}!`);
|
||||
this.scene.ui.showText(this.player ? `Go! ${switchedPokemon.name}!` : `${this.scene.currentBattle.trainer.getName()} sent out\n${this.getPokemon().name}!`);
|
||||
this.summon();
|
||||
} else
|
||||
this.end();
|
||||
@@ -1800,8 +1858,14 @@ export class FaintPhase extends PokemonPhase {
|
||||
this.scene.unshiftPhase(new SwitchPhase(this.scene, this.fieldIndex, true, false));
|
||||
else if (nonFaintedPartyMemberCount === 1 && this.scene.currentBattle.double)
|
||||
this.scene.unshiftPhase(new ToggleDoublePositionPhase(this.scene, true));
|
||||
} else
|
||||
} else {
|
||||
this.scene.unshiftPhase(new VictoryPhase(this.scene, this.battlerIndex));
|
||||
if (this.scene.currentBattle.battleType === BattleType.TRAINER) {
|
||||
const nonFaintedPartyMemberCount = this.scene.getParty().filter(p => !p.isFainted()).length;
|
||||
if (nonFaintedPartyMemberCount >= this.scene.currentBattle.getBattlerCount())
|
||||
this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, this.fieldIndex, this.scene.currentBattle.trainer.getNextSummonIndex(), false, false, false));
|
||||
}
|
||||
}
|
||||
|
||||
pokemon.lapseTags(BattlerTagLapseType.FAINT);
|
||||
this.scene.getField().filter(p => p !== pokemon && p?.isActive(true)).forEach(p => p.removeTagsBySourceId(pokemon.id));
|
||||
@@ -1897,7 +1961,7 @@ export class VictoryPhase extends PokemonPhase {
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.scene.getEnemyField().filter(p => !p?.isFainted(true)).length) {
|
||||
if (!this.scene.getEnemyParty().filter(p => !p?.isFainted(true)).length) {
|
||||
this.scene.pushPhase(new BattleEndPhase(this.scene));
|
||||
if (this.scene.gameMode === GameMode.ENDLESS || this.scene.currentBattle.waveIndex < this.scene.finalWave) {
|
||||
this.scene.pushPhase(new SelectModifierPhase(this.scene));
|
||||
@@ -1999,7 +2063,7 @@ export class SwitchPhase extends BattlePhase {
|
||||
}
|
||||
}
|
||||
|
||||
export class ExpPhase extends PartyMemberPokemonPhase {
|
||||
export class ExpPhase extends PlayerPartyMemberPokemonPhase {
|
||||
private expValue: number;
|
||||
|
||||
constructor(scene: BattleScene, partyMemberIndex: integer, expValue: number) {
|
||||
@@ -2027,7 +2091,7 @@ export class ExpPhase extends PartyMemberPokemonPhase {
|
||||
}
|
||||
}
|
||||
|
||||
export class ShowPartyExpBarPhase extends PartyMemberPokemonPhase {
|
||||
export class ShowPartyExpBarPhase extends PlayerPartyMemberPokemonPhase {
|
||||
private expValue: number;
|
||||
|
||||
constructor(scene: BattleScene, partyMemberIndex: integer, expValue: number) {
|
||||
@@ -2074,7 +2138,7 @@ export class HidePartyExpBarPhase extends BattlePhase {
|
||||
}
|
||||
}
|
||||
|
||||
export class LevelUpPhase extends PartyMemberPokemonPhase {
|
||||
export class LevelUpPhase extends PlayerPartyMemberPokemonPhase {
|
||||
private lastLevel: integer;
|
||||
private level: integer;
|
||||
|
||||
@@ -2105,7 +2169,7 @@ export class LevelUpPhase extends PartyMemberPokemonPhase {
|
||||
}
|
||||
}
|
||||
|
||||
export class LearnMovePhase extends PartyMemberPokemonPhase {
|
||||
export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
|
||||
private moveId: Moves;
|
||||
|
||||
constructor(scene: BattleScene, partyMemberIndex: integer, moveId: Moves) {
|
||||
|
||||
+43
-9
@@ -1,7 +1,7 @@
|
||||
import Phaser from 'phaser';
|
||||
import { Biome } from './data/biome';
|
||||
import UI from './ui/ui';
|
||||
import { EncounterPhase, SummonPhase, NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, CheckLoadPhase, TurnInitPhase, ReturnPhase, ToggleDoublePositionPhase, CheckSwitchPhase, PostSummonPhase, LevelCapPhase } from './battle-phases';
|
||||
import { EncounterPhase, SummonPhase, NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, CheckLoadPhase, TurnInitPhase, ReturnPhase, ToggleDoublePositionPhase, CheckSwitchPhase, LevelCapPhase } from './battle-phases';
|
||||
import Pokemon, { PlayerPokemon, EnemyPokemon } from './pokemon';
|
||||
import PokemonSpecies, { allSpecies, getPokemonSpecies, initSpecies } from './data/pokemon-species';
|
||||
import * as Utils from './utils';
|
||||
@@ -19,10 +19,13 @@ import { Moves, initMoves } from './data/move';
|
||||
import { getDefaultModifierTypeForTier, getEnemyModifierTypesForWave } from './modifier/modifier-type';
|
||||
import AbilityBar from './ui/ability-bar';
|
||||
import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, applyAbAttrs, initAbilities } from './data/ability';
|
||||
import Battle from './battle';
|
||||
import Battle, { BattleType } from './battle';
|
||||
import { GameMode } from './game-mode';
|
||||
import SpritePipeline from './pipelines/sprite';
|
||||
import PartyExpBar from './ui/party-exp-bar';
|
||||
import { TrainerType, trainerConfigs } from './data/trainer-type';
|
||||
import Trainer from './trainer';
|
||||
import TrainerData from './system/trainer-data';
|
||||
|
||||
const enableAuto = true;
|
||||
const quickStart = false;
|
||||
@@ -232,6 +235,13 @@ export default class BattleScene extends Phaser.Scene {
|
||||
this.loadImage('trainer_m', 'trainer');
|
||||
this.loadAtlas('trainer_m_pb', 'trainer');
|
||||
|
||||
Utils.getEnumValues(TrainerType).map(tt => {
|
||||
const config = trainerConfigs[tt];
|
||||
this.loadAtlas(config.getKey(), 'trainer');
|
||||
if (config.isDouble)
|
||||
this.loadAtlas(config.getKey(true), 'trainer');
|
||||
});
|
||||
|
||||
// Load pokemon-related images
|
||||
this.loadImage(`pkmn__back__sub`, 'pokemon/back', 'sub.png');
|
||||
this.loadImage(`pkmn__sub`, 'pokemon', 'sub.png');
|
||||
@@ -465,12 +475,17 @@ export default class BattleScene extends Phaser.Scene {
|
||||
return party.slice(0, Math.min(party.length, this.currentBattle?.double ? 2 : 1));
|
||||
}
|
||||
|
||||
getEnemyParty(): EnemyPokemon[] {
|
||||
return this.currentBattle?.enemyParty || [];
|
||||
}
|
||||
|
||||
getEnemyPokemon(): EnemyPokemon {
|
||||
return this.getEnemyField().find(p => p.isActive());
|
||||
}
|
||||
|
||||
getEnemyField(): EnemyPokemon[] {
|
||||
return this.currentBattle?.enemyField || [];
|
||||
const party = this.getEnemyParty();
|
||||
return party.slice(0, Math.min(party.length, this.currentBattle?.double ? 2 : 1));
|
||||
}
|
||||
|
||||
getField(): Pokemon[] {
|
||||
@@ -517,15 +532,32 @@ export default class BattleScene extends Phaser.Scene {
|
||||
this.trainer.setPosition(406, 132);
|
||||
}
|
||||
|
||||
newBattle(waveIndex?: integer, double?: boolean): Battle {
|
||||
newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean): Battle {
|
||||
let newWaveIndex = waveIndex || ((this.currentBattle?.waveIndex || (startingWave - 1)) + 1);
|
||||
let newDouble: boolean;
|
||||
let newBattleType: BattleType;
|
||||
let newTrainer: Trainer;
|
||||
|
||||
if (battleType === undefined)
|
||||
newBattleType = BattleType.WILD;
|
||||
else
|
||||
newBattleType = battleType;
|
||||
|
||||
if (newBattleType === BattleType.TRAINER) {
|
||||
newTrainer = trainerData !== undefined ? trainerData.toTrainer(this) : new Trainer(this, TrainerType.SWIMMER, !!Utils.randInt(2));
|
||||
this.field.add(newTrainer);
|
||||
}
|
||||
|
||||
if (double === undefined && newWaveIndex > 1) {
|
||||
const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8);
|
||||
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
|
||||
this.getPlayerField().forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance));
|
||||
newDouble = !Utils.randInt(doubleChance.value);
|
||||
if (newBattleType === BattleType.WILD) {
|
||||
const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8);
|
||||
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
|
||||
this.getPlayerField().forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance));
|
||||
newDouble = !Utils.randInt(doubleChance.value);
|
||||
} else if (newBattleType === BattleType.TRAINER) {
|
||||
console.log(newTrainer, newTrainer.config);
|
||||
newDouble = newTrainer.config.isDouble;
|
||||
}
|
||||
} else
|
||||
newDouble = !!double;
|
||||
|
||||
@@ -533,7 +565,7 @@ export default class BattleScene extends Phaser.Scene {
|
||||
|
||||
const maxExpLevel = this.getMaxExpLevel();
|
||||
|
||||
this.currentBattle = new Battle(newWaveIndex, newDouble);
|
||||
this.currentBattle = new Battle(newWaveIndex, newBattleType, newTrainer, newDouble);
|
||||
this.currentBattle.incrementTurn(this);
|
||||
|
||||
if (!waveIndex) {
|
||||
@@ -559,6 +591,8 @@ export default class BattleScene extends Phaser.Scene {
|
||||
}
|
||||
}
|
||||
|
||||
console.log(lastBattle, newDouble)
|
||||
|
||||
if ((lastBattle?.double || false) !== newDouble) {
|
||||
const availablePartyMemberCount = this.getParty().filter(p => !p.isFainted()).length;
|
||||
if (newDouble) {
|
||||
|
||||
+15
-5
@@ -2,6 +2,12 @@ import BattleScene, { PokeballCounts } from "./battle-scene";
|
||||
import { EnemyPokemon, PlayerPokemon, QueuedMove } from "./pokemon";
|
||||
import { Command } from "./ui/command-ui-handler";
|
||||
import * as Utils from "./utils";
|
||||
import Trainer from "./trainer";
|
||||
|
||||
export enum BattleType {
|
||||
WILD,
|
||||
TRAINER
|
||||
}
|
||||
|
||||
export enum BattlerIndex {
|
||||
PLAYER,
|
||||
@@ -24,8 +30,10 @@ interface TurnCommands {
|
||||
|
||||
export default class Battle {
|
||||
public waveIndex: integer;
|
||||
public battleType: BattleType;
|
||||
public trainer: Trainer;
|
||||
public enemyLevels: integer[];
|
||||
public enemyField: EnemyPokemon[];
|
||||
public enemyParty: EnemyPokemon[];
|
||||
public double: boolean;
|
||||
public turn: integer;
|
||||
public turnCommands: TurnCommands;
|
||||
@@ -33,15 +41,17 @@ export default class Battle {
|
||||
public playerParticipantIds: Set<integer> = new Set<integer>();
|
||||
public escapeAttempts: integer = 0;
|
||||
|
||||
constructor(waveIndex: integer, double: boolean) {
|
||||
constructor(waveIndex: integer, battleType: BattleType, trainer: Trainer, double: boolean) {
|
||||
this.waveIndex = waveIndex;
|
||||
this.enemyLevels = new Array(double ? 2 : 1).fill(null).map(() => this.getLevelForWave());
|
||||
this.enemyField = [];
|
||||
this.battleType = battleType;
|
||||
this.trainer = trainer;
|
||||
this.enemyLevels = new Array(battleType !== BattleType.TRAINER ? double ? 2 : 1 : trainer.config.genPartySize()).fill(null).map(() => this.getLevelForWave());
|
||||
this.enemyParty = [];
|
||||
this.double = double;
|
||||
this.turn = 0;
|
||||
}
|
||||
|
||||
private getLevelForWave(): number {
|
||||
private getLevelForWave(): integer {
|
||||
let baseLevel = 1 + this.waveIndex / 2 + Math.pow(this.waveIndex / 25, 2);
|
||||
|
||||
if (!(this.waveIndex % 10)) {
|
||||
|
||||
@@ -0,0 +1,179 @@
|
||||
import BattleScene from "../battle-scene";
|
||||
import * as Utils from "../utils";
|
||||
|
||||
export enum TrainerType {
|
||||
ACE_TRAINER = 1,
|
||||
ARTIST,
|
||||
BACKERS,
|
||||
BACKPACKER,
|
||||
BAKER,
|
||||
BATTLE_GIRL,
|
||||
BEAUTY,
|
||||
BIKER,
|
||||
BLACKBELT,
|
||||
BREEDER,
|
||||
CLERK,
|
||||
CYCLIST,
|
||||
DANCER,
|
||||
DEPOT_AGENT,
|
||||
DOCTOR,
|
||||
FISHERMAN,
|
||||
GENTLEMAN,
|
||||
GUITARIST,
|
||||
HARLEQUIN,
|
||||
HIKER,
|
||||
HOOLIGANS,
|
||||
HOOPSTER,
|
||||
INFIELDER,
|
||||
JANITOR,
|
||||
LADY,
|
||||
LASS,
|
||||
LINEBACKER,
|
||||
MAID,
|
||||
MUSICIAN,
|
||||
NURSE,
|
||||
NURSERY_AIDE,
|
||||
OFFICER,
|
||||
PARASOL_LADY,
|
||||
PILOT,
|
||||
POKEFAN,
|
||||
PRESCHOOLER,
|
||||
PSYCHIC,
|
||||
RANGER,
|
||||
RICH_BOY,
|
||||
ROUGHNECK,
|
||||
SCIENTIST,
|
||||
SMASHER,
|
||||
SNOW_WORKER,
|
||||
SOCIALITE,
|
||||
STRIKER,
|
||||
STUDENT,
|
||||
SWIMMER,
|
||||
TWINS,
|
||||
VETERAN,
|
||||
WAITER,
|
||||
WORKER,
|
||||
YOUNGSTER,
|
||||
CYNTHIA
|
||||
}
|
||||
|
||||
export class TrainerConfig {
|
||||
public trainerType: TrainerType;
|
||||
public hasGenders: boolean = false;
|
||||
public isDouble: boolean = false;
|
||||
|
||||
constructor(trainerType: TrainerType) {
|
||||
this.trainerType = trainerType;
|
||||
}
|
||||
|
||||
public getKey(female?: boolean): string {
|
||||
let ret = TrainerType[this.trainerType].toString().toLowerCase();
|
||||
if (this.hasGenders)
|
||||
ret += `_${female ? 'f' : 'm'}`;
|
||||
return ret;
|
||||
}
|
||||
|
||||
public setHasGenders(): TrainerConfig {
|
||||
this.hasGenders = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public setDouble(): TrainerConfig {
|
||||
this.isDouble = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public getName(): string {
|
||||
return Utils.toPokemonUpperCase(TrainerType[this.trainerType].toString().replace(/\_/g, ' '));
|
||||
}
|
||||
|
||||
public genPartySize(): integer {
|
||||
// TODO
|
||||
return this.isDouble ? 2 : 1;
|
||||
}
|
||||
|
||||
loadAssets(scene: BattleScene, female: boolean): Promise<void> {
|
||||
return new Promise(resolve => {
|
||||
const trainerKey = this.getKey(female);
|
||||
scene.loadAtlas(trainerKey, 'trainer');
|
||||
scene.load.once(Phaser.Loader.Events.COMPLETE, () => {
|
||||
const originalWarn = console.warn;
|
||||
// Ignore warnings for missing frames, because there will be a lot
|
||||
console.warn = () => {};
|
||||
const frameNames = scene.anims.generateFrameNames(trainerKey, { zeroPad: 4, suffix: ".png", start: 1, end:24 });
|
||||
console.warn = originalWarn;
|
||||
scene.anims.create({
|
||||
key: trainerKey,
|
||||
frames: frameNames,
|
||||
frameRate: 12,
|
||||
repeat: -1
|
||||
});
|
||||
resolve();
|
||||
});
|
||||
if (!scene.load.isLoading())
|
||||
scene.load.start();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let t = 0;
|
||||
|
||||
interface TrainerConfigs {
|
||||
[key: integer]: TrainerConfig
|
||||
}
|
||||
|
||||
export const trainerConfigs: TrainerConfigs = {
|
||||
[TrainerType.ACE_TRAINER]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.ARTIST]: new TrainerConfig(++t),
|
||||
[TrainerType.BACKERS]: new TrainerConfig(++t).setHasGenders().setDouble(),
|
||||
[TrainerType.BACKPACKER]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.BAKER]: new TrainerConfig(++t),
|
||||
[TrainerType.BATTLE_GIRL]: new TrainerConfig(++t),
|
||||
[TrainerType.BEAUTY]: new TrainerConfig(++t),
|
||||
[TrainerType.BIKER]: new TrainerConfig(++t),
|
||||
[TrainerType.BLACKBELT]: new TrainerConfig(++t),
|
||||
[TrainerType.BREEDER]: new TrainerConfig(++t).setHasGenders().setDouble(),
|
||||
[TrainerType.CLERK]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.CYCLIST]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.DANCER]: new TrainerConfig(++t),
|
||||
[TrainerType.DEPOT_AGENT]: new TrainerConfig(++t),
|
||||
[TrainerType.DOCTOR]: new TrainerConfig(++t),
|
||||
[TrainerType.FISHERMAN]: new TrainerConfig(++t),
|
||||
[TrainerType.GENTLEMAN]: new TrainerConfig(++t),
|
||||
[TrainerType.GUITARIST]: new TrainerConfig(++t),
|
||||
[TrainerType.HARLEQUIN]: new TrainerConfig(++t),
|
||||
[TrainerType.HIKER]: new TrainerConfig(++t),
|
||||
[TrainerType.HOOLIGANS]: new TrainerConfig(++t).setDouble(),
|
||||
[TrainerType.HOOPSTER]: new TrainerConfig(++t),
|
||||
[TrainerType.INFIELDER]: new TrainerConfig(++t),
|
||||
[TrainerType.JANITOR]: new TrainerConfig(++t),
|
||||
[TrainerType.LADY]: new TrainerConfig(++t),
|
||||
[TrainerType.LASS]: new TrainerConfig(++t),
|
||||
[TrainerType.LINEBACKER]: new TrainerConfig(++t),
|
||||
[TrainerType.MAID]: new TrainerConfig(++t),
|
||||
[TrainerType.MUSICIAN]: new TrainerConfig(++t),
|
||||
[TrainerType.NURSE]: new TrainerConfig(++t),
|
||||
[TrainerType.NURSERY_AIDE]: new TrainerConfig(++t),
|
||||
[TrainerType.OFFICER]: new TrainerConfig(++t),
|
||||
[TrainerType.PARASOL_LADY]: new TrainerConfig(++t),
|
||||
[TrainerType.PILOT]: new TrainerConfig(++t),
|
||||
[TrainerType.POKEFAN]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.PRESCHOOLER]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.PSYCHIC]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.RANGER]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.RICH_BOY]: new TrainerConfig(++t),
|
||||
[TrainerType.ROUGHNECK]: new TrainerConfig(++t),
|
||||
[TrainerType.SCIENTIST]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.SMASHER]: new TrainerConfig(++t),
|
||||
[TrainerType.SNOW_WORKER]: new TrainerConfig(++t),
|
||||
[TrainerType.SOCIALITE]: new TrainerConfig(++t),
|
||||
[TrainerType.STRIKER]: new TrainerConfig(++t),
|
||||
[TrainerType.STUDENT]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.SWIMMER]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.TWINS]: new TrainerConfig(++t).setDouble(),
|
||||
[TrainerType.VETERAN]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.WAITER]: new TrainerConfig(++t).setHasGenders(),
|
||||
[TrainerType.WORKER]: new TrainerConfig(++t),
|
||||
[TrainerType.YOUNGSTER]: new TrainerConfig(++t),
|
||||
[TrainerType.CYNTHIA]: new TrainerConfig(++t),
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import BattleScene from "../battle-scene";
|
||||
import Pokemon from "../pokemon";
|
||||
import Trainer from "../trainer";
|
||||
|
||||
const spriteFragShader = `
|
||||
#ifdef GL_FRAGMENT_PRECISION_HIGH
|
||||
@@ -150,7 +150,7 @@ export default class SpritePipeline extends Phaser.Renderer.WebGL.Pipelines.Mult
|
||||
const tone = data['tone'] as number[];
|
||||
const hasShadow = data['hasShadow'] as boolean;
|
||||
|
||||
const position = sprite.parentContainer instanceof Pokemon
|
||||
const position = sprite.parentContainer instanceof Pokemon || sprite.parentContainer instanceof Trainer
|
||||
? [ sprite.parentContainer.x, sprite.parentContainer.y ]
|
||||
: [ sprite.x, sprite.y ];
|
||||
position[0] += -(sprite.width - sprite.frame.width) / 2 + sprite.frame.x;
|
||||
@@ -176,7 +176,7 @@ export default class SpritePipeline extends Phaser.Renderer.WebGL.Pipelines.Mult
|
||||
|
||||
const hasShadow = sprite.pipelineData['hasShadow'] as boolean;
|
||||
if (hasShadow) {
|
||||
const baseY = (sprite.parentContainer instanceof Pokemon
|
||||
const baseY = (sprite.parentContainer instanceof Pokemon || sprite.parentContainer instanceof Trainer
|
||||
? sprite.parentContainer.y
|
||||
: sprite.y + sprite.height / 2) * 6;
|
||||
const bottomPadding = Math.ceil(sprite.height * 0.05) * 6;
|
||||
|
||||
+14
-2
@@ -406,7 +406,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
getTypes(): Type[] {
|
||||
const types = [];
|
||||
|
||||
if (this.summonData.types)
|
||||
if (this.summonData?.types)
|
||||
this.summonData.types.forEach(t => types.push(t));
|
||||
else {
|
||||
const speciesForm = this.getSpeciesForm();
|
||||
@@ -447,6 +447,18 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
return getTypeDamageMultiplier(moveType, types[0]) * (types.length > 1 ? getTypeDamageMultiplier(moveType, types[1]) : 1) as TypeDamageMultiplier;
|
||||
}
|
||||
|
||||
getMatchupScore(pokemon: Pokemon): number {
|
||||
const types = this.getTypes();
|
||||
const enemyTypes = pokemon.getTypes();
|
||||
let atkScore = pokemon.getAttackMoveEffectiveness(types[0]);
|
||||
let defScore = 1 / this.getAttackMoveEffectiveness(enemyTypes[0]);
|
||||
if (types.length > 1)
|
||||
atkScore *= pokemon.getAttackMoveEffectiveness(types[1]);
|
||||
if (enemyTypes.length > 1)
|
||||
defScore *= (1 / this.getAttackMoveEffectiveness(enemyTypes[1]));
|
||||
return (atkScore + defScore) * (this.getHpRatio() + (1 - pokemon.getHpRatio()));
|
||||
}
|
||||
|
||||
getEvolution(): SpeciesEvolution {
|
||||
if (!pokemonEvolutions.hasOwnProperty(this.species.speciesId))
|
||||
return null;
|
||||
@@ -1142,7 +1154,7 @@ export class EnemyPokemon extends Pokemon {
|
||||
public aiType: AiType;
|
||||
|
||||
constructor(scene: BattleScene, species: PokemonSpecies, level: integer, dataSource?: PokemonData) {
|
||||
super(scene, -66, 84, species, level, dataSource?.abilityIndex, dataSource ? dataSource.formIndex : scene.arena.getFormIndex(species),
|
||||
super(scene, 236, 84, species, level, dataSource?.abilityIndex, dataSource ? dataSource.formIndex : scene.arena.getFormIndex(species),
|
||||
dataSource?.gender, dataSource?.shiny, dataSource);
|
||||
|
||||
if (!dataSource) {
|
||||
|
||||
+23
-6
@@ -11,6 +11,9 @@ import { PokemonHeldItemModifier } from "../modifier/modifier";
|
||||
import ArenaData from "./arena-data";
|
||||
import { Unlockables } from "./unlockables";
|
||||
import { GameMode } from "../game-mode";
|
||||
import { BattleType } from "../battle";
|
||||
import TrainerData from "./trainer-data";
|
||||
import { trainerConfigs } from "../data/trainer-type";
|
||||
|
||||
interface SystemSaveData {
|
||||
trainerId: integer;
|
||||
@@ -23,12 +26,15 @@ interface SystemSaveData {
|
||||
interface SessionSaveData {
|
||||
gameMode: GameMode;
|
||||
party: PokemonData[];
|
||||
enemyParty: PokemonData[];
|
||||
enemyField: PokemonData[];
|
||||
modifiers: PersistentModifierData[];
|
||||
enemyModifiers: PersistentModifierData[];
|
||||
arena: ArenaData;
|
||||
pokeballCounts: PokeballCounts;
|
||||
waveIndex: integer;
|
||||
battleType: BattleType;
|
||||
trainer: TrainerData;
|
||||
timestamp: integer;
|
||||
}
|
||||
|
||||
@@ -130,12 +136,14 @@ export class GameData {
|
||||
const sessionData = {
|
||||
gameMode: scene.gameMode,
|
||||
party: scene.getParty().map(p => new PokemonData(p)),
|
||||
enemyField: scene.getEnemyField().map(p => new PokemonData(p)),
|
||||
enemyParty: scene.getEnemyParty().map(p => new PokemonData(p)),
|
||||
modifiers: scene.findModifiers(() => true).map(m => new PersistentModifierData(m, true)),
|
||||
enemyModifiers: scene.findModifiers(() => true, false).map(m => new PersistentModifierData(m, false)),
|
||||
arena: new ArenaData(scene.arena),
|
||||
pokeballCounts: scene.pokeballCounts,
|
||||
waveIndex: scene.currentBattle.waveIndex,
|
||||
battleType: scene.currentBattle.battleType,
|
||||
trainer: scene.currentBattle.battleType == BattleType.TRAINER ? new TrainerData(scene.currentBattle.trainer) : null,
|
||||
timestamp: new Date().getTime()
|
||||
} as SessionSaveData;
|
||||
|
||||
@@ -157,13 +165,16 @@ export class GameData {
|
||||
|
||||
try {
|
||||
const sessionData = JSON.parse(atob(localStorage.getItem('sessionData')), (k: string, v: any) => {
|
||||
if (k === 'party' || k === 'enemyField') {
|
||||
if (k === 'party' || k === 'enemyParty' || k === 'enemyField') {
|
||||
const ret: PokemonData[] = [];
|
||||
for (let pd of v)
|
||||
ret.push(new PokemonData(pd));
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (k === 'trainer')
|
||||
return v ? new TrainerData(v) : null;
|
||||
|
||||
if (k === 'modifiers' || k === 'enemyModifiers') {
|
||||
const player = k === 'modifiers';
|
||||
const ret: PersistentModifierData[] = [];
|
||||
@@ -198,12 +209,18 @@ export class GameData {
|
||||
scene.pokeballCounts[key] = sessionData.pokeballCounts[key] || 0;
|
||||
});
|
||||
|
||||
scene.newArena(sessionData.arena.biome, true);
|
||||
const battle = scene.newBattle(sessionData.waveIndex, sessionData.enemyField.length > 1);
|
||||
// TODO: Remove this
|
||||
if (sessionData.enemyField)
|
||||
sessionData.enemyParty = sessionData.enemyField;
|
||||
|
||||
sessionData.enemyField.forEach((enemyData, e) => {
|
||||
scene.newArena(sessionData.arena.biome, true);
|
||||
|
||||
const battleType = sessionData.battleType || 0;
|
||||
const battle = scene.newBattle(sessionData.waveIndex, battleType, sessionData.trainer, battleType === BattleType.TRAINER ? trainerConfigs[sessionData.trainer.trainerType].isDouble : sessionData.enemyParty.length > 1);
|
||||
|
||||
sessionData.enemyParty.forEach((enemyData, e) => {
|
||||
const enemyPokemon = enemyData.toPokemon(scene) as EnemyPokemon;
|
||||
battle.enemyField[e] = enemyPokemon;
|
||||
battle.enemyParty[e] = enemyPokemon;
|
||||
|
||||
loadPokemonAssets.push(enemyPokemon.loadAssets());
|
||||
});
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
import BattleScene from "../battle-scene";
|
||||
import { TrainerType } from "../data/trainer-type";
|
||||
import Trainer from "../trainer";
|
||||
|
||||
export default class TrainerData {
|
||||
public trainerType: TrainerType;
|
||||
public female: boolean;
|
||||
|
||||
constructor(source: Trainer | any) {
|
||||
const sourceTrainer = source instanceof Trainer ? source as Trainer : null;
|
||||
this.trainerType = sourceTrainer ? sourceTrainer.config.trainerType : source.trainerType;
|
||||
this.female = source.female;
|
||||
}
|
||||
|
||||
toTrainer(scene: BattleScene): Trainer {
|
||||
return new Trainer(scene, this.trainerType, this.female);
|
||||
}
|
||||
}
|
||||
+124
@@ -0,0 +1,124 @@
|
||||
import BattleScene from "./battle-scene";
|
||||
import { TrainerConfig, TrainerType, trainerConfigs } from "./data/trainer-type";
|
||||
import * as Utils from "./utils";
|
||||
|
||||
export default class Trainer extends Phaser.GameObjects.Container {
|
||||
public config: TrainerConfig;
|
||||
public female: boolean;
|
||||
|
||||
constructor(scene: BattleScene, trainerType: TrainerType, female?: boolean) {
|
||||
super(scene, -72, 80);
|
||||
this.config = trainerConfigs[trainerType];
|
||||
this.female = female;
|
||||
|
||||
const getSprite = (hasShadow?: boolean) => {
|
||||
const ret = this.scene.add.sprite(0, 0, this.getKey());
|
||||
ret.setOrigin(0.5, 1);
|
||||
ret.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], hasShadow: !!hasShadow });
|
||||
return ret;
|
||||
};
|
||||
|
||||
const sprite = getSprite(true);
|
||||
const tintSprite = getSprite();
|
||||
|
||||
tintSprite.setVisible(false);
|
||||
|
||||
this.add(sprite);
|
||||
this.add(tintSprite);
|
||||
}
|
||||
|
||||
getKey(): string {
|
||||
return this.config.getKey(this.female);
|
||||
}
|
||||
|
||||
getName(): string {
|
||||
return this.config.getName();
|
||||
}
|
||||
|
||||
getNextSummonIndex(): integer {
|
||||
const party = this.scene.getEnemyParty();
|
||||
const nonFaintedPartyMembers = party.slice(this.scene.currentBattle.getBattlerCount()).filter(p => !p.isFainted());
|
||||
const partyMemberScores = nonFaintedPartyMembers.map(p => {
|
||||
const playerField = this.scene.getPlayerField();
|
||||
let score = 0;
|
||||
for (let playerPokemon of playerField)
|
||||
score += p.getMatchupScore(playerPokemon);
|
||||
score /= playerField.length;
|
||||
return [ party.indexOf(p), score ];
|
||||
});
|
||||
|
||||
const sortedPartyMemberScores = partyMemberScores.slice(0);
|
||||
sortedPartyMemberScores.sort((a, b) => {
|
||||
const scoreA = a[1];
|
||||
const scoreB = b[1];
|
||||
return scoreA < scoreB ? 1 : scoreA > scoreB ? -1 : 0;
|
||||
});
|
||||
|
||||
const maxScorePartyMemberIndexes = partyMemberScores.filter(pms => pms[1] === sortedPartyMemberScores[0][1]).map(pms => pms[0]);
|
||||
return maxScorePartyMemberIndexes[Utils.randInt(maxScorePartyMemberIndexes.length)];
|
||||
}
|
||||
|
||||
loadAssets(): Promise<void> {
|
||||
return this.config.loadAssets(this.scene, this.female);
|
||||
}
|
||||
|
||||
playAnim(): void {
|
||||
const trainerAnimConfig = {
|
||||
key: this.scene.currentBattle.trainer.getKey(),
|
||||
repeat: 0
|
||||
};
|
||||
this.getSprite().play(trainerAnimConfig);
|
||||
this.getTintSprite().play(trainerAnimConfig);
|
||||
}
|
||||
|
||||
getSprite(): Phaser.GameObjects.Sprite {
|
||||
return this.getAt(0) as Phaser.GameObjects.Sprite;
|
||||
}
|
||||
|
||||
getTintSprite(): Phaser.GameObjects.Sprite {
|
||||
return this.getAt(1) as Phaser.GameObjects.Sprite;
|
||||
}
|
||||
|
||||
tint(color: number, alpha?: number, duration?: integer, ease?: string): void {
|
||||
const tintSprite = this.getTintSprite();
|
||||
tintSprite.setTintFill(color);
|
||||
tintSprite.setVisible(true);
|
||||
|
||||
if (duration) {
|
||||
tintSprite.setAlpha(0);
|
||||
|
||||
this.scene.tweens.add({
|
||||
targets: tintSprite,
|
||||
alpha: alpha || 1,
|
||||
duration: duration,
|
||||
ease: ease || 'Linear'
|
||||
});
|
||||
} else
|
||||
tintSprite.setAlpha(alpha);
|
||||
}
|
||||
|
||||
untint(duration: integer, ease?: string): void {
|
||||
const tintSprite = this.getTintSprite();
|
||||
|
||||
if (duration) {
|
||||
this.scene.tweens.add({
|
||||
targets: tintSprite,
|
||||
alpha: 0,
|
||||
duration: duration,
|
||||
ease: ease || 'Linear',
|
||||
onComplete: () => {
|
||||
tintSprite.setVisible(false);
|
||||
tintSprite.setAlpha(1);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
tintSprite.setVisible(false);
|
||||
tintSprite.setAlpha(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export default interface Trainer {
|
||||
scene: BattleScene
|
||||
}
|
||||
Reference in new issue
Block a user