Add session scores
parent
dd03be2646
commit
0701598be6
|
@ -17,7 +17,7 @@ import { TextStyle, addTextObject } from './ui/text';
|
||||||
import { Moves } from "./data/enums/moves";
|
import { Moves } from "./data/enums/moves";
|
||||||
import { } from "./data/move";
|
import { } from "./data/move";
|
||||||
import { initMoves } from './data/move';
|
import { initMoves } from './data/move';
|
||||||
import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave } from './modifier/modifier-type';
|
import { ModifierPoolType, PokemonBaseStatBoosterModifierType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave } from './modifier/modifier-type';
|
||||||
import AbilityBar from './ui/ability-bar';
|
import AbilityBar from './ui/ability-bar';
|
||||||
import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, applyAbAttrs, initAbilities } from './data/ability';
|
import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, applyAbAttrs, initAbilities } from './data/ability';
|
||||||
import Battle, { BattleType, FixedBattleConfig, fixedBattles } from './battle';
|
import Battle, { BattleType, FixedBattleConfig, fixedBattles } from './battle';
|
||||||
|
@ -131,6 +131,7 @@ export default class BattleScene extends Phaser.Scene {
|
||||||
public arenaNextEnemy: ArenaBase;
|
public arenaNextEnemy: ArenaBase;
|
||||||
public arena: Arena;
|
public arena: Arena;
|
||||||
public gameMode: GameMode;
|
public gameMode: GameMode;
|
||||||
|
public score: integer;
|
||||||
public trainer: Phaser.GameObjects.Sprite;
|
public trainer: Phaser.GameObjects.Sprite;
|
||||||
public lastEnemyTrainer: Trainer;
|
public lastEnemyTrainer: Trainer;
|
||||||
public currentBattle: Battle;
|
public currentBattle: Battle;
|
||||||
|
@ -761,6 +762,7 @@ export default class BattleScene extends Phaser.Scene {
|
||||||
|
|
||||||
this.gameMode = gameModes[GameModes.CLASSIC];
|
this.gameMode = gameModes[GameModes.CLASSIC];
|
||||||
|
|
||||||
|
this.score = 0;
|
||||||
this.money = 0;
|
this.money = 0;
|
||||||
|
|
||||||
this.pokeballCounts = Object.fromEntries(Utils.getEnumValues(PokeballType).filter(p => p <= PokeballType.MASTER_BALL).map(t => [ t, 0 ]));
|
this.pokeballCounts = Object.fromEntries(Utils.getEnumValues(PokeballType).filter(p => p <= PokeballType.MASTER_BALL).map(t => [ t, 0 ]));
|
||||||
|
@ -1138,6 +1140,14 @@ export default class BattleScene extends Phaser.Scene {
|
||||||
this.ui?.achvBar.setY((this.game.canvas.height / 6 + this.moneyText.y + 15));
|
this.ui?.achvBar.setY((this.game.canvas.height / 6 + this.moneyText.y + 15));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addFaintedEnemyScore(enemy: EnemyPokemon): void {
|
||||||
|
let scoreIncrease = enemy.getSpeciesForm().getBaseExp() * (enemy.level / this.getMaxExpLevel()) * ((enemy.ivs.reduce((iv: integer, total: integer) => total += iv, 0) / 93) * 0.2 + 0.8);
|
||||||
|
this.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemy.id, false).map(m => scoreIncrease *= (m as PokemonHeldItemModifier).getScoreMultiplier());
|
||||||
|
if (enemy.isBoss())
|
||||||
|
scoreIncrease *= Math.sqrt(enemy.bossSegments);
|
||||||
|
this.currentBattle.battleScore += Math.ceil(scoreIncrease);
|
||||||
|
}
|
||||||
|
|
||||||
getMaxExpLevel(ignoreLevelCap?: boolean): integer {
|
getMaxExpLevel(ignoreLevelCap?: boolean): integer {
|
||||||
if (ignoreLevelCap)
|
if (ignoreLevelCap)
|
||||||
return Number.MAX_SAFE_INTEGER;
|
return Number.MAX_SAFE_INTEGER;
|
||||||
|
|
|
@ -51,6 +51,7 @@ export default class Battle {
|
||||||
public turn: integer;
|
public turn: integer;
|
||||||
public turnCommands: TurnCommands;
|
public turnCommands: TurnCommands;
|
||||||
public playerParticipantIds: Set<integer>;
|
public playerParticipantIds: Set<integer>;
|
||||||
|
public battleScore: integer;
|
||||||
public postBattleLoot: PokemonHeldItemModifier[];
|
public postBattleLoot: PokemonHeldItemModifier[];
|
||||||
public escapeAttempts: integer;
|
public escapeAttempts: integer;
|
||||||
public lastMove: Moves;
|
public lastMove: Moves;
|
||||||
|
@ -71,6 +72,7 @@ export default class Battle {
|
||||||
this.double = double;
|
this.double = double;
|
||||||
this.turn = 0;
|
this.turn = 0;
|
||||||
this.playerParticipantIds = new Set<integer>();
|
this.playerParticipantIds = new Set<integer>();
|
||||||
|
this.battleScore = 0;
|
||||||
this.postBattleLoot = [];
|
this.postBattleLoot = [];
|
||||||
this.escapeAttempts = 0;
|
this.escapeAttempts = 0;
|
||||||
this.started = false;
|
this.started = false;
|
||||||
|
@ -143,6 +145,17 @@ export default class Battle {
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addBattleScore(scene: BattleScene): void {
|
||||||
|
let partyMemberTurnMultiplier = scene.getEnemyParty().length / 2 + 0.5;
|
||||||
|
if (this.double)
|
||||||
|
partyMemberTurnMultiplier /= 1.5;
|
||||||
|
const turnMultiplier = Phaser.Tweens.Builders.GetEaseFunction('Sine.easeIn')(1 - Math.min(this.turn - 2, 10 * partyMemberTurnMultiplier) / (10 * partyMemberTurnMultiplier));
|
||||||
|
const finalBattleScore = Math.ceil(this.battleScore * turnMultiplier);
|
||||||
|
scene.score += finalBattleScore;
|
||||||
|
console.log(`Battle Score: ${finalBattleScore} (${this.turn - 1} Turns x${Math.floor(turnMultiplier * 100) / 100})`);
|
||||||
|
console.log(`Total Score: ${scene.score}`);
|
||||||
|
}
|
||||||
|
|
||||||
getBgmOverride(scene: BattleScene): string {
|
getBgmOverride(scene: BattleScene): string {
|
||||||
const battlers = this.enemyParty.slice(0, this.getBattlerCount());
|
const battlers = this.enemyParty.slice(0, this.getBattlerCount());
|
||||||
if (this.battleType === BattleType.TRAINER) {
|
if (this.battleType === BattleType.TRAINER) {
|
||||||
|
|
|
@ -165,6 +165,21 @@ export abstract class PokemonSpeciesForm {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBaseExp(): integer {
|
||||||
|
let ret = this.baseExp;
|
||||||
|
switch (this.getFormSpriteKey()) {
|
||||||
|
case SpeciesFormKey.MEGA:
|
||||||
|
case SpeciesFormKey.MEGA_X:
|
||||||
|
case SpeciesFormKey.MEGA_Y:
|
||||||
|
case SpeciesFormKey.PRIMAL:
|
||||||
|
case SpeciesFormKey.GIGANTAMAX:
|
||||||
|
case SpeciesFormKey.ETERNAMAX:
|
||||||
|
ret *= 1.5;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
getSpriteAtlasPath(female: boolean, formIndex?: integer, shiny?: boolean): string {
|
getSpriteAtlasPath(female: boolean, formIndex?: integer, shiny?: boolean): string {
|
||||||
return this.getSpriteId(female, formIndex, shiny).replace(/\_{2}/g, '/');
|
return this.getSpriteId(female, formIndex, shiny).replace(/\_{2}/g, '/');
|
||||||
}
|
}
|
||||||
|
|
|
@ -1662,7 +1662,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
|
|
||||||
getExpValue(): integer {
|
getExpValue(): integer {
|
||||||
// Logic to factor in victor level has been removed for balancing purposes, so the player doesn't have to focus on EXP maxxing
|
// Logic to factor in victor level has been removed for balancing purposes, so the player doesn't have to focus on EXP maxxing
|
||||||
return ((this.getSpeciesForm().baseExp * this.level) / 5 + 1);
|
return ((this.getSpeciesForm().getBaseExp() * this.level) / 5 + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
setFrameRate(frameRate: integer) {
|
setFrameRate(frameRate: integer) {
|
||||||
|
|
|
@ -495,6 +495,10 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier {
|
||||||
return scene.getPokemonById(this.pokemonId);
|
return scene.getPokemonById(this.pokemonId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getScoreMultiplier(): number {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
getMaxStackCount(scene: BattleScene, forThreshold?: boolean): integer {
|
getMaxStackCount(scene: BattleScene, forThreshold?: boolean): integer {
|
||||||
const pokemon = this.getPokemon(scene);
|
const pokemon = this.getPokemon(scene);
|
||||||
if (!pokemon)
|
if (!pokemon)
|
||||||
|
@ -586,6 +590,14 @@ export class TerastallizeModifier extends LapsingPokemonHeldItemModifier {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTransferrable(withinParty: boolean): boolean {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getScoreMultiplier(): number {
|
||||||
|
return 1.25;
|
||||||
|
}
|
||||||
|
|
||||||
getMaxHeldItemCount(pokemon: Pokemon): integer {
|
getMaxHeldItemCount(pokemon: Pokemon): integer {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -627,6 +639,10 @@ export class PokemonBaseStatModifier extends PokemonHeldItemModifier {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getScoreMultiplier(): number {
|
||||||
|
return 1.1;
|
||||||
|
}
|
||||||
|
|
||||||
getMaxHeldItemCount(pokemon: Pokemon): integer {
|
getMaxHeldItemCount(pokemon: Pokemon): integer {
|
||||||
return pokemon.ivs[this.stat];
|
return pokemon.ivs[this.stat];
|
||||||
}
|
}
|
||||||
|
@ -668,6 +684,10 @@ export class AttackTypeBoosterModifier extends PokemonHeldItemModifier {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getScoreMultiplier(): number {
|
||||||
|
return 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
getMaxHeldItemCount(pokemon: Pokemon): integer {
|
getMaxHeldItemCount(pokemon: Pokemon): integer {
|
||||||
return 10;
|
return 10;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1860,6 +1860,8 @@ export class BattleEndPhase extends BattlePhase {
|
||||||
start() {
|
start() {
|
||||||
super.start();
|
super.start();
|
||||||
|
|
||||||
|
this.scene.currentBattle.addBattleScore(this.scene);
|
||||||
|
|
||||||
this.scene.gameData.gameStats.battles++;
|
this.scene.gameData.gameStats.battles++;
|
||||||
if (this.scene.currentBattle.trainer)
|
if (this.scene.currentBattle.trainer)
|
||||||
this.scene.gameData.gameStats.trainersDefeated++;
|
this.scene.gameData.gameStats.trainersDefeated++;
|
||||||
|
@ -2814,8 +2816,10 @@ export class FaintPhase extends PokemonPhase {
|
||||||
pokemon.trySetStatus(StatusEffect.FAINT);
|
pokemon.trySetStatus(StatusEffect.FAINT);
|
||||||
if (pokemon.isPlayer())
|
if (pokemon.isPlayer())
|
||||||
this.scene.currentBattle.removeFaintedParticipant(pokemon as PlayerPokemon);
|
this.scene.currentBattle.removeFaintedParticipant(pokemon as PlayerPokemon);
|
||||||
else
|
else {
|
||||||
|
this.scene.addFaintedEnemyScore(pokemon as EnemyPokemon);
|
||||||
this.scene.currentBattle.addPostBattleLoot(pokemon as EnemyPokemon);
|
this.scene.currentBattle.addPostBattleLoot(pokemon as EnemyPokemon);
|
||||||
|
}
|
||||||
this.scene.field.remove(pokemon);
|
this.scene.field.remove(pokemon);
|
||||||
this.end();
|
this.end();
|
||||||
}
|
}
|
||||||
|
@ -3098,7 +3102,7 @@ export class GameOverPhase extends BattlePhase {
|
||||||
start() {
|
start() {
|
||||||
super.start();
|
super.start();
|
||||||
|
|
||||||
(this.victory ? this.scene.gameData.tryClearSession : this.scene.gameData.deleteSession)(this.scene.sessionSlotId).then((success: boolean | [boolean, boolean]) => {
|
(this.victory ? this.scene.gameData.tryClearSession(this.scene, this.scene.sessionSlotId) : this.scene.gameData.deleteSession(this.scene.sessionSlotId)).then((success: boolean | [boolean, boolean]) => {
|
||||||
this.scene.time.delayedCall(1000, () => {
|
this.scene.time.delayedCall(1000, () => {
|
||||||
let firstClear = false;
|
let firstClear = false;
|
||||||
if (this.victory && success[1]) {
|
if (this.victory && success[1]) {
|
||||||
|
@ -3687,6 +3691,7 @@ export class AttemptCapturePhase extends PokemonPhase {
|
||||||
this.end();
|
this.end();
|
||||||
};
|
};
|
||||||
const removePokemon = () => {
|
const removePokemon = () => {
|
||||||
|
this.scene.addFaintedEnemyScore(pokemon);
|
||||||
this.scene.getPlayerField().filter(p => p.isActive(true)).forEach(playerPokemon => playerPokemon.removeTagsBySourceId(pokemon.id));
|
this.scene.getPlayerField().filter(p => p.isActive(true)).forEach(playerPokemon => playerPokemon.removeTagsBySourceId(pokemon.id));
|
||||||
pokemon.hp = 0;
|
pokemon.hp = 0;
|
||||||
pokemon.trySetStatus(StatusEffect.FAINT);
|
pokemon.trySetStatus(StatusEffect.FAINT);
|
||||||
|
|
|
@ -23,7 +23,6 @@ import { loggedInUser, updateUserInfo } from "../account";
|
||||||
import { Nature } from "../data/nature";
|
import { Nature } from "../data/nature";
|
||||||
import { GameStats } from "./game-stats";
|
import { GameStats } from "./game-stats";
|
||||||
import { Tutorial } from "../tutorial";
|
import { Tutorial } from "../tutorial";
|
||||||
import { BattleSpec } from "../enums/battle-spec";
|
|
||||||
import { Moves } from "../data/enums/moves";
|
import { Moves } from "../data/enums/moves";
|
||||||
import { speciesEggMoves } from "../data/egg-moves";
|
import { speciesEggMoves } from "../data/egg-moves";
|
||||||
import { allMoves } from "../data/move";
|
import { allMoves } from "../data/move";
|
||||||
|
@ -87,6 +86,7 @@ export interface SessionSaveData {
|
||||||
arena: ArenaData;
|
arena: ArenaData;
|
||||||
pokeballCounts: PokeballCounts;
|
pokeballCounts: PokeballCounts;
|
||||||
money: integer;
|
money: integer;
|
||||||
|
score: integer;
|
||||||
waveIndex: integer;
|
waveIndex: integer;
|
||||||
battleType: BattleType;
|
battleType: BattleType;
|
||||||
trainer: TrainerData;
|
trainer: TrainerData;
|
||||||
|
@ -452,13 +452,8 @@ export class GameData {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
saveSession(scene: BattleScene, skipVerification?: boolean): Promise<boolean> {
|
private getSessionSaveData(scene: BattleScene): SessionSaveData {
|
||||||
return new Promise<boolean>(resolve => {
|
return {
|
||||||
Utils.executeIf(!skipVerification, updateUserInfo).then(success => {
|
|
||||||
if (success !== null && !success)
|
|
||||||
return resolve(false);
|
|
||||||
|
|
||||||
const sessionData = {
|
|
||||||
seed: scene.seed,
|
seed: scene.seed,
|
||||||
playTime: scene.sessionPlayTime,
|
playTime: scene.sessionPlayTime,
|
||||||
gameMode: scene.gameMode.modeId,
|
gameMode: scene.gameMode.modeId,
|
||||||
|
@ -469,12 +464,22 @@ export class GameData {
|
||||||
arena: new ArenaData(scene.arena),
|
arena: new ArenaData(scene.arena),
|
||||||
pokeballCounts: scene.pokeballCounts,
|
pokeballCounts: scene.pokeballCounts,
|
||||||
money: scene.money,
|
money: scene.money,
|
||||||
|
score: scene.score,
|
||||||
waveIndex: scene.currentBattle.waveIndex,
|
waveIndex: scene.currentBattle.waveIndex,
|
||||||
battleType: scene.currentBattle.battleType,
|
battleType: scene.currentBattle.battleType,
|
||||||
trainer: scene.currentBattle.battleType == BattleType.TRAINER ? new TrainerData(scene.currentBattle.trainer) : null,
|
trainer: scene.currentBattle.battleType == BattleType.TRAINER ? new TrainerData(scene.currentBattle.trainer) : null,
|
||||||
gameVersion: scene.game.config.gameVersion,
|
gameVersion: scene.game.config.gameVersion,
|
||||||
timestamp: new Date().getTime()
|
timestamp: new Date().getTime()
|
||||||
} as SessionSaveData;
|
} as SessionSaveData;
|
||||||
|
}
|
||||||
|
|
||||||
|
saveSession(scene: BattleScene, skipVerification?: boolean): Promise<boolean> {
|
||||||
|
return new Promise<boolean>(resolve => {
|
||||||
|
Utils.executeIf(!skipVerification, updateUserInfo).then(success => {
|
||||||
|
if (success !== null && !success)
|
||||||
|
return resolve(false);
|
||||||
|
|
||||||
|
const sessionData = this.getSessionSaveData(scene);
|
||||||
|
|
||||||
if (!bypassLogin) {
|
if (!bypassLogin) {
|
||||||
Utils.apiPost(`savedata/update?datatype=${GameDataType.SESSION}&slot=${scene.sessionSlotId}`, JSON.stringify(sessionData))
|
Utils.apiPost(`savedata/update?datatype=${GameDataType.SESSION}&slot=${scene.sessionSlotId}`, JSON.stringify(sessionData))
|
||||||
|
@ -566,6 +571,8 @@ export class GameData {
|
||||||
if (scene.money > this.gameStats.highestMoney)
|
if (scene.money > this.gameStats.highestMoney)
|
||||||
this.gameStats.highestMoney = scene.money;
|
this.gameStats.highestMoney = scene.money;
|
||||||
|
|
||||||
|
scene.score = sessionData.score;
|
||||||
|
|
||||||
const battleType = sessionData.battleType || 0;
|
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);
|
const battle = scene.newBattle(sessionData.waveIndex, battleType, sessionData.trainer, battleType === BattleType.TRAINER ? trainerConfigs[sessionData.trainer.trainerType].isDouble : sessionData.enemyParty.length > 1);
|
||||||
battle.enemyLevels = sessionData.enemyParty.map(p => p.level);
|
battle.enemyLevels = sessionData.enemyParty.map(p => p.level);
|
||||||
|
@ -636,7 +643,7 @@ export class GameData {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
tryClearSession(slotId: integer): Promise<[success: boolean, newClear: boolean]> {
|
tryClearSession(scene: BattleScene, slotId: integer): Promise<[success: boolean, newClear: boolean]> {
|
||||||
return new Promise<[boolean, boolean]>(resolve => {
|
return new Promise<[boolean, boolean]>(resolve => {
|
||||||
if (bypassLogin) {
|
if (bypassLogin) {
|
||||||
localStorage.removeItem('sessionData');
|
localStorage.removeItem('sessionData');
|
||||||
|
@ -646,7 +653,8 @@ export class GameData {
|
||||||
updateUserInfo().then(success => {
|
updateUserInfo().then(success => {
|
||||||
if (success !== null && !success)
|
if (success !== null && !success)
|
||||||
return resolve([false, false]);
|
return resolve([false, false]);
|
||||||
Utils.apiFetch(`savedata/clear?slot=${slotId}`).then(response => {
|
const sessionData = this.getSessionSaveData(scene);
|
||||||
|
Utils.apiPost(`savedata/clear?slot=${slotId}`, JSON.stringify(sessionData)).then(response => {
|
||||||
if (response.ok) {
|
if (response.ok) {
|
||||||
loggedInUser.lastSessionSlot = -1;
|
loggedInUser.lastSessionSlot = -1;
|
||||||
return response.json();
|
return response.json();
|
||||||
|
|
Loading…
Reference in New Issue