Add wrapper for game mode

This commit is contained in:
Flashfyre 2024-03-14 16:26:57 -04:00
parent 76de0d01f9
commit 623d600e13
12 changed files with 139 additions and 72 deletions

View File

@ -21,7 +21,7 @@ import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesF
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';
import { GameMode } from './game-mode'; import { GameMode, GameModes, gameModes } from './game-mode';
import FieldSpritePipeline from './pipelines/field-sprite'; import FieldSpritePipeline from './pipelines/field-sprite';
import SpritePipeline from './pipelines/sprite'; import SpritePipeline from './pipelines/sprite';
import PartyExpBar from './ui/party-exp-bar'; import PartyExpBar from './ui/party-exp-bar';
@ -747,7 +747,7 @@ export default class BattleScene extends Phaser.Scene {
this.seed = Utils.randomString(16); this.seed = Utils.randomString(16);
console.log('Seed:', this.seed); console.log('Seed:', this.seed);
this.gameMode = GameMode.CLASSIC; this.gameMode = gameModes[GameModes.CLASSIC];
this.money = startingMoney; this.money = startingMoney;
@ -812,7 +812,7 @@ export default class BattleScene extends Phaser.Scene {
this.resetSeed(newWaveIndex); this.resetSeed(newWaveIndex);
if (fixedBattles.hasOwnProperty(newWaveIndex) && this.gameMode === GameMode.CLASSIC && trainerData === undefined) { if (this.gameMode.hasFixedBattles && fixedBattles.hasOwnProperty(newWaveIndex) && trainerData === undefined) {
battleConfig = fixedBattles[newWaveIndex]; battleConfig = fixedBattles[newWaveIndex];
newDouble = battleConfig.double; newDouble = battleConfig.double;
newBattleType = battleConfig.battleType; newBattleType = battleConfig.battleType;
@ -820,15 +820,15 @@ export default class BattleScene extends Phaser.Scene {
if (newTrainer) if (newTrainer)
this.field.add(newTrainer); this.field.add(newTrainer);
} else { } else {
if (this.gameMode !== GameMode.CLASSIC) if (!this.gameMode.hasTrainers)
newBattleType = BattleType.WILD; newBattleType = BattleType.WILD;
else if (battleType === undefined) { else if (battleType === undefined) {
if ((newWaveIndex % 30) === 20 && newWaveIndex !== 200) if ((newWaveIndex % 30) === 20 && !this.gameMode.isWaveFinal(newWaveIndex))
newBattleType = BattleType.TRAINER; newBattleType = BattleType.TRAINER;
else if (newWaveIndex % 10 !== 1 && newWaveIndex % 10) { else if (newWaveIndex % 10 !== 1 && newWaveIndex % 10) {
const trainerChance = this.arena.getTrainerChance(); const trainerChance = this.arena.getTrainerChance();
let allowTrainerBattle = true; let allowTrainerBattle = true;
if (trainerChance && this.gameMode === GameMode.CLASSIC) { if (trainerChance) {
const waveBase = Math.floor(newWaveIndex / 10) * 10; const waveBase = Math.floor(newWaveIndex / 10) * 10;
for (let w = Math.max(newWaveIndex - 3, waveBase + 2); w <= Math.min(newWaveIndex + 3, waveBase + 9); w++) { for (let w = Math.max(newWaveIndex - 3, waveBase + 2); w <= Math.min(newWaveIndex + 3, waveBase + 9); w++) {
if (w === newWaveIndex) if (w === newWaveIndex)
@ -862,7 +862,7 @@ export default class BattleScene extends Phaser.Scene {
const playerField = this.getPlayerField(); const playerField = this.getPlayerField();
if (double === undefined && newWaveIndex > 1) { if (double === undefined && newWaveIndex > 1) {
if (newBattleType === BattleType.WILD && (this.gameMode === GameMode.CLASSIC ? newWaveIndex !== 200 : newWaveIndex % 250)) { if (newBattleType === BattleType.WILD && !this.gameMode.isWaveFinal(newWaveIndex)) {
const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8); const doubleChance = new Utils.IntegerHolder(newWaveIndex % 10 === 0 ? 32 : 8);
this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance); this.applyModifiers(DoubleBattleChanceBoosterModifier, true, doubleChance);
playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance)); playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance));
@ -902,7 +902,7 @@ export default class BattleScene extends Phaser.Scene {
this.triggerPokemonFormChange(pokemon, SpeciesFormChangeTimeOfDayTrigger); this.triggerPokemonFormChange(pokemon, SpeciesFormChangeTimeOfDayTrigger);
} }
} }
if (this.gameMode === GameMode.CLASSIC && !isNewBiome) if (!this.gameMode.hasRandomBiomes && !isNewBiome)
this.pushPhase(new NextEncounterPhase(this)); this.pushPhase(new NextEncounterPhase(this));
else { else {
this.pushPhase(new SelectBiomePhase(this)); this.pushPhase(new SelectBiomePhase(this));
@ -1022,7 +1022,7 @@ export default class BattleScene extends Phaser.Scene {
isBoss = true; isBoss = true;
else { else {
this.executeWithSeedOffset(() => { this.executeWithSeedOffset(() => {
isBoss = waveIndex % 10 === 0 || (this.gameMode !== GameMode.CLASSIC && Utils.randSeedInt(100) < Math.min(Math.max(Math.ceil((waveIndex - 250) / 50), 0) * 2, 30)); isBoss = waveIndex % 10 === 0 || (this.gameMode.hasRandomBosses && Utils.randSeedInt(100) < Math.min(Math.max(Math.ceil((waveIndex - 250) / 50), 0) * 2, 30));
}, waveIndex << 2); }, waveIndex << 2);
} }
if (!isBoss) if (!isBoss)
@ -1683,11 +1683,7 @@ export default class BattleScene extends Phaser.Scene {
const chances = Math.ceil(waveIndex / 10); const chances = Math.ceil(waveIndex / 10);
const isBoss = !(waveIndex % 10) || (this.currentBattle.battleType === BattleType.TRAINER && this.currentBattle.trainer.config.isBoss); const isBoss = !(waveIndex % 10) || (this.currentBattle.battleType === BattleType.TRAINER && this.currentBattle.trainer.config.isBoss);
let modifierChance: integer; const modifierChance = this.gameMode.getEnemyModifierChance(isBoss);
if (this.gameMode === GameMode.CLASSIC)
modifierChance = !isBoss ? 18 : 6;
else
modifierChance = !isBoss ? 12 : 4;
const party = this.getEnemyParty(); const party = this.getEnemyParty();
@ -1708,7 +1704,7 @@ export default class BattleScene extends Phaser.Scene {
} }
if (isBoss) if (isBoss)
count = Math.max(count, Math.floor(chances / 2)); count = Math.max(count, Math.floor(chances / 2));
getEnemyModifierTypesForWave(waveIndex, count, [ enemyPokemon ], this.currentBattle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD, this.gameMode) getEnemyModifierTypesForWave(waveIndex, count, [ enemyPokemon ], this.currentBattle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD)
.map(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false, this)); .map(mt => mt.newModifier(enemyPokemon).add(this.enemyModifiers, false, this));
}); });

View File

@ -6,7 +6,7 @@ import Trainer from "./field/trainer";
import { Species } from "./data/enums/species"; import { Species } from "./data/enums/species";
import { Moves } from "./data/enums/moves"; import { Moves } from "./data/enums/moves";
import { TrainerType } from "./data/enums/trainer-type"; import { TrainerType } from "./data/enums/trainer-type";
import { GameMode } from "./game-mode"; import { GameMode, GameModes } from "./game-mode";
import { BattleSpec } from "./enums/battle-spec"; import { BattleSpec } from "./enums/battle-spec";
import { PlayerGender } from "./system/game-data"; import { PlayerGender } from "./system/game-data";
import { PokemonHeldItemModifier } from "./modifier/modifier"; import { PokemonHeldItemModifier } from "./modifier/modifier";
@ -57,7 +57,7 @@ export default class Battle {
public battleSeed: string; public battleSeed: string;
private battleSeedState: string; private battleSeedState: string;
constructor(gameMode: integer, waveIndex: integer, battleType: BattleType, trainer: Trainer, double: boolean) { constructor(gameMode: GameMode, waveIndex: integer, battleType: BattleType, trainer: Trainer, double: boolean) {
this.gameMode = gameMode; this.gameMode = gameMode;
this.waveIndex = waveIndex; this.waveIndex = waveIndex;
this.battleType = battleType; this.battleType = battleType;
@ -80,7 +80,7 @@ export default class Battle {
private initBattleSpec(): void { private initBattleSpec(): void {
let spec = BattleSpec.DEFAULT; let spec = BattleSpec.DEFAULT;
if (this.gameMode === GameMode.CLASSIC) { if (this.gameMode.isClassic) {
if (this.waveIndex === 200) if (this.waveIndex === 200)
spec = BattleSpec.FINAL_BOSS; spec = BattleSpec.FINAL_BOSS;
} }
@ -88,17 +88,20 @@ export default class Battle {
} }
private getLevelForWave(): integer { private getLevelForWave(): integer {
let baseLevel = 1 + this.waveIndex / 2 + Math.pow(this.waveIndex / 25, 2); let levelWaveIndex = this.waveIndex;
if (this.gameMode.isDaily)
levelWaveIndex += 30 + Math.floor(this.waveIndex / 5);
let baseLevel = 1 + levelWaveIndex / 2 + Math.pow(levelWaveIndex / 25, 2);
const bossMultiplier = 1.2; const bossMultiplier = 1.2;
if (!(this.waveIndex % 10)) { if (!(this.waveIndex % 10)) {
const ret = Math.floor(baseLevel * bossMultiplier); const ret = Math.floor(baseLevel * bossMultiplier);
if (this.battleSpec === BattleSpec.FINAL_BOSS || !(this.waveIndex % 250)) if (this.battleSpec === BattleSpec.FINAL_BOSS || !(this.waveIndex % 250))
return Math.ceil(ret / 25) * 25; return Math.ceil(ret / 25) * 25;
return ret + Math.round(Phaser.Math.RND.realInRange(-1, 1) * Math.floor(this.waveIndex / 10)); return ret + Math.round(Phaser.Math.RND.realInRange(-1, 1) * Math.floor(levelWaveIndex / 10));
} }
const deviation = 10 / this.waveIndex; const deviation = 10 / levelWaveIndex;
return Math.max(Math.round(baseLevel + Math.abs(this.randSeedGaussForLevel(deviation))), 1); return Math.max(Math.round(baseLevel + Math.abs(this.randSeedGaussForLevel(deviation))), 1);
} }
@ -142,7 +145,7 @@ export default class Battle {
if (!this.started && this.trainer.config.encounterBgm && this.trainer.getEncounterMessages()?.length) if (!this.started && this.trainer.config.encounterBgm && this.trainer.getEncounterMessages()?.length)
return `encounter_${this.trainer.getEncounterBgm()}`; return `encounter_${this.trainer.getEncounterBgm()}`;
return this.trainer.getBattleBgm(); return this.trainer.getBattleBgm();
} else if (this.gameMode === GameMode.CLASSIC && this.waveIndex > 195 && this.battleSpec !== BattleSpec.FINAL_BOSS) } else if (this.gameMode.isClassic && this.waveIndex > 195 && this.battleSpec !== BattleSpec.FINAL_BOSS)
return 'end_summit'; return 'end_summit';
for (let pokemon of battlers) { for (let pokemon of battlers) {
if (this.battleSpec === BattleSpec.FINAL_BOSS) { if (this.battleSpec === BattleSpec.FINAL_BOSS) {
@ -159,7 +162,7 @@ export default class Battle {
} }
} }
if (scene.gameMode === GameMode.CLASSIC && this.waveIndex <= 4) if (scene.gameMode.isClassic && this.waveIndex <= 4)
return 'battle_wild'; return 'battle_wild';
return null; return null;

View File

@ -11,7 +11,7 @@ import { Type } from "../data/type";
import Move from "../data/move"; import Move from "../data/move";
import { ArenaTag, ArenaTagSide, getArenaTag } from "../data/arena-tag"; import { ArenaTag, ArenaTagSide, getArenaTag } from "../data/arena-tag";
import { ArenaTagType } from "../data/enums/arena-tag-type"; import { ArenaTagType } from "../data/enums/arena-tag-type";
import { GameMode } from "../game-mode"; import { GameModes } from "../game-mode";
import { TrainerType } from "../data/enums/trainer-type"; import { TrainerType } from "../data/enums/trainer-type";
import { BattlerIndex } from "../battle"; import { BattlerIndex } from "../battle";
import { Moves } from "../data/enums/moves"; import { Moves } from "../data/enums/moves";
@ -55,7 +55,7 @@ export class Arena {
randomSpecies(waveIndex: integer, level: integer, attempt?: integer): PokemonSpecies { randomSpecies(waveIndex: integer, level: integer, attempt?: integer): PokemonSpecies {
const isBoss = !!this.scene.getEncounterBossSegments(waveIndex, level) && !!this.pokemonPool[BiomePoolTier.BOSS].length const isBoss = !!this.scene.getEncounterBossSegments(waveIndex, level) && !!this.pokemonPool[BiomePoolTier.BOSS].length
&& (this.biomeType !== Biome.END || this.scene.gameMode === GameMode.CLASSIC || waveIndex % 250 === 0); && (this.biomeType !== Biome.END || this.scene.gameMode.isClassic || this.scene.gameMode.isWaveFinal(waveIndex));
const tierValue = Utils.randSeedInt(!isBoss ? 512 : 64); const tierValue = Utils.randSeedInt(!isBoss ? 512 : 64);
let tier = !isBoss let tier = !isBoss
? tierValue >= 156 ? BiomePoolTier.COMMON : tierValue >= 32 ? BiomePoolTier.UNCOMMON : tierValue >= 6 ? BiomePoolTier.RARE : tierValue >= 1 ? BiomePoolTier.SUPER_RARE : BiomePoolTier.ULTRA_RARE ? tierValue >= 156 ? BiomePoolTier.COMMON : tierValue >= 32 ? BiomePoolTier.UNCOMMON : tierValue >= 6 ? BiomePoolTier.RARE : tierValue >= 1 ? BiomePoolTier.SUPER_RARE : BiomePoolTier.ULTRA_RARE
@ -125,7 +125,7 @@ export class Arena {
randomTrainerType(waveIndex: integer): TrainerType { randomTrainerType(waveIndex: integer): TrainerType {
const isBoss = (waveIndex % 30) === 20 && !!this.trainerPool[BiomePoolTier.BOSS].length const isBoss = (waveIndex % 30) === 20 && !!this.trainerPool[BiomePoolTier.BOSS].length
&& (this.biomeType !== Biome.END || this.scene.gameMode === GameMode.CLASSIC || waveIndex % 250 === 0); && (this.biomeType !== Biome.END || this.scene.gameMode.isClassic || this.scene.gameMode.isWaveFinal(waveIndex));
const tierValue = Utils.randSeedInt(!isBoss ? 512 : 64); const tierValue = Utils.randSeedInt(!isBoss ? 512 : 64);
let tier = !isBoss let tier = !isBoss
? tierValue >= 156 ? BiomePoolTier.COMMON : tierValue >= 32 ? BiomePoolTier.UNCOMMON : tierValue >= 6 ? BiomePoolTier.RARE : tierValue >= 1 ? BiomePoolTier.SUPER_RARE : BiomePoolTier.ULTRA_RARE ? tierValue >= 156 ? BiomePoolTier.COMMON : tierValue >= 32 ? BiomePoolTier.UNCOMMON : tierValue >= 6 ? BiomePoolTier.RARE : tierValue >= 1 ? BiomePoolTier.SUPER_RARE : BiomePoolTier.ULTRA_RARE

View File

@ -32,7 +32,7 @@ import { BattleSpec } from "../enums/battle-spec";
import { Mode } from '../ui/ui'; import { Mode } from '../ui/ui';
import PartyUiHandler, { PartyOption, PartyUiMode } from '../ui/party-ui-handler'; import PartyUiHandler, { PartyOption, PartyUiMode } from '../ui/party-ui-handler';
import SoundFade from 'phaser3-rex-plugins/plugins/soundfade'; import SoundFade from 'phaser3-rex-plugins/plugins/soundfade';
import { GameMode } from '../game-mode'; import { GameModes } from '../game-mode';
import { LevelMoves } from '../data/pokemon-level-moves'; import { LevelMoves } from '../data/pokemon-level-moves';
import { DamageAchv, achvs } from '../system/achv'; import { DamageAchv, achvs } from '../system/achv';
import { DexAttr, StarterMoveset } from '../system/game-data'; import { DexAttr, StarterMoveset } from '../system/game-data';
@ -180,7 +180,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
this.metBiome = scene.currentBattle ? scene.arena.biomeType : -1; this.metBiome = scene.currentBattle ? scene.arena.biomeType : -1;
this.pokerus = false; this.pokerus = false;
const fused = new Utils.BooleanHolder(scene.gameMode === GameMode.SPLICED_ENDLESS); const fused = new Utils.BooleanHolder(scene.gameMode.isSplicedOnly);
if (!fused.value && !this.isPlayer() && !this.hasTrainer()) if (!fused.value && !this.isPlayer() && !this.hasTrainer())
this.scene.applyModifier(EnemyFusionChanceModifier, false, fused); this.scene.applyModifier(EnemyFusionChanceModifier, false, fused);
@ -536,7 +536,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
const fusionBaseStats = this.getFusionSpeciesForm().baseStats; const fusionBaseStats = this.getFusionSpeciesForm().baseStats;
for (let s = 0; s < this.stats.length; s++) for (let s = 0; s < this.stats.length; s++)
baseStats[s] = Math.ceil((baseStats[s] + fusionBaseStats[s]) / 2); baseStats[s] = Math.ceil((baseStats[s] + fusionBaseStats[s]) / 2);
} else if (this.scene.gameMode === GameMode.SPLICED_ENDLESS) { } else if (this.scene.gameMode.isSplicedOnly) {
for (let s = 0; s < this.stats.length; s++) for (let s = 0; s < this.stats.length; s++)
baseStats[s] = Math.ceil(baseStats[s] / 2); baseStats[s] = Math.ceil(baseStats[s] / 2);
} }

View File

@ -1,11 +1,77 @@
export enum GameMode { export enum GameModes {
DAILY,
CLASSIC, CLASSIC,
ENDLESS, ENDLESS,
SPLICED_ENDLESS SPLICED_ENDLESS
} }
export const gameModeNames = { interface GameModeConfig {
[GameMode.CLASSIC]: 'Classic', isClassic?: boolean;
[GameMode.ENDLESS]: 'Endless', isEndless?: boolean;
[GameMode.SPLICED_ENDLESS]: 'Endless (Spliced)' isDaily?: boolean;
}; hasTrainers?: boolean;
hasFixedBattles?: boolean;
hasRandomBiomes?: boolean;
hasRandomBosses?: boolean;
isSplicedOnly?: boolean;
}
export class GameMode implements GameModeConfig {
public modeId: GameModes;
public isClassic: boolean;
public isEndless: boolean;
public isDaily: boolean;
public hasTrainers: boolean;
public hasFixedBattles: boolean;
public hasRandomBiomes: boolean;
public hasRandomBosses: boolean;
public isSplicedOnly: boolean;
constructor(modeId: GameModes, config: GameModeConfig) {
this.modeId = modeId;
Object.assign(this, config);
}
isWaveFinal(waveIndex: integer): boolean {
switch (this.modeId) {
case GameModes.DAILY:
return waveIndex === 50;
case GameModes.CLASSIC:
return waveIndex === 200;
case GameModes.ENDLESS:
case GameModes.SPLICED_ENDLESS:
return !(waveIndex % 250);
}
}
getEnemyModifierChance(isBoss: boolean): integer {
switch (this.modeId) {
case GameModes.DAILY:
case GameModes.CLASSIC:
return !isBoss ? 18 : 6;
case GameModes.ENDLESS:
case GameModes.SPLICED_ENDLESS:
return !isBoss ? 12 : 4;
}
}
getName(): string {
switch (this.modeId) {
case GameModes.DAILY:
return 'Daily Run';
case GameModes.CLASSIC:
return 'Classic';
case GameModes.ENDLESS:
return 'Endless';
case GameModes.SPLICED_ENDLESS:
return 'Endless (Spliced)';
}
}
}
export const gameModes = Object.freeze({
[GameModes.DAILY]: new GameMode(GameModes.DAILY, { isDaily: true, hasTrainers: true }),
[GameModes.CLASSIC]: new GameMode(GameModes.CLASSIC, { isClassic: true, hasTrainers: true, hasFixedBattles: true }),
[GameModes.ENDLESS]: new GameMode(GameModes.ENDLESS, { isEndless: true, hasRandomBiomes: true, hasRandomBosses: true }),
[GameModes.SPLICED_ENDLESS]: new GameMode(GameModes.SPLICED_ENDLESS, { isEndless: true, hasRandomBiomes: true, hasRandomBosses: true, isSplicedOnly: true })
});

View File

@ -12,7 +12,7 @@ import * as Utils from '../utils';
import { TempBattleStat, getTempBattleStatBoosterItemName, getTempBattleStatName } from '../data/temp-battle-stat'; import { TempBattleStat, getTempBattleStatBoosterItemName, getTempBattleStatName } from '../data/temp-battle-stat';
import { BerryType, getBerryEffectDescription, getBerryName } from '../data/berry'; import { BerryType, getBerryEffectDescription, getBerryName } from '../data/berry';
import { Unlockables } from '../system/unlockables'; import { Unlockables } from '../system/unlockables';
import { GameMode } from '../game-mode'; import { GameModes } from '../game-mode';
import { StatusEffect, getStatusEffectDescriptor } from '../data/status-effect'; import { StatusEffect, getStatusEffectDescriptor } from '../data/status-effect';
import { SpeciesFormKey } from '../data/pokemon-species'; import { SpeciesFormKey } from '../data/pokemon-species';
import BattleScene from '../battle-scene'; import BattleScene from '../battle-scene';
@ -951,7 +951,7 @@ const modifierPool = {
}, 3), }, 3),
new WeightedModifierType(modifierTypes.SUPER_LURE, 4), new WeightedModifierType(modifierTypes.SUPER_LURE, 4),
new WeightedModifierType(modifierTypes.NUGGET, 5), new WeightedModifierType(modifierTypes.NUGGET, 5),
new WeightedModifierType(modifierTypes.MAP, (party: Pokemon[]) => party[0].scene.gameMode === GameMode.CLASSIC ? 1 : 0, 1), new WeightedModifierType(modifierTypes.MAP, (party: Pokemon[]) => party[0].scene.gameMode.isClassic ? 1 : 0, 1),
new WeightedModifierType(modifierTypes.TM_GREAT, 2), new WeightedModifierType(modifierTypes.TM_GREAT, 2),
new WeightedModifierType(modifierTypes.MEMORY_MUSHROOM, (party: Pokemon[]) => { new WeightedModifierType(modifierTypes.MEMORY_MUSHROOM, (party: Pokemon[]) => {
if (!party.find(p => p.getLearnableLevelMoves().length)) if (!party.find(p => p.getLearnableLevelMoves().length))
@ -961,8 +961,8 @@ const modifierPool = {
}, 4), }, 4),
new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 3), new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 3),
new WeightedModifierType(modifierTypes.TERA_SHARD, 1), new WeightedModifierType(modifierTypes.TERA_SHARD, 1),
new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode === GameMode.SPLICED_ENDLESS && party.filter(p => !p.fusionSpecies).length > 1 ? 4 : 0), new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode.isSplicedOnly && party.filter(p => !p.fusionSpecies).length > 1 ? 4 : 0),
new WeightedModifierType(modifierTypes.REVERSE_DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode === GameMode.SPLICED_ENDLESS && party.filter(p => p.fusionSpecies).length ? 6 : 0), new WeightedModifierType(modifierTypes.REVERSE_DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode.isSplicedOnly && party.filter(p => p.fusionSpecies).length ? 6 : 0),
].map(m => { m.setTier(ModifierTier.GREAT); return m; }), ].map(m => { m.setTier(ModifierTier.GREAT); return m; }),
[ModifierTier.ULTRA]: [ [ModifierTier.ULTRA]: [
new WeightedModifierType(modifierTypes.ULTRA_BALL, 24), new WeightedModifierType(modifierTypes.ULTRA_BALL, 24),
@ -988,7 +988,7 @@ const modifierPool = {
new WeightedModifierType(modifierTypes.EXP_SHARE, 12), new WeightedModifierType(modifierTypes.EXP_SHARE, 12),
new WeightedModifierType(modifierTypes.EXP_BALANCE, 1), new WeightedModifierType(modifierTypes.EXP_BALANCE, 1),
new WeightedModifierType(modifierTypes.TERA_ORB, (party: Pokemon[]) => Math.min(Math.max(Math.floor(party[0].scene.currentBattle.waveIndex / 50) * 2, 1), 4), 4), new WeightedModifierType(modifierTypes.TERA_ORB, (party: Pokemon[]) => Math.min(Math.max(Math.floor(party[0].scene.currentBattle.waveIndex / 50) * 2, 1), 4), 4),
new WeightedModifierType(modifierTypes.REVERSE_DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode !== GameMode.SPLICED_ENDLESS && party.filter(p => p.fusionSpecies).length ? 3 : 0, 3), new WeightedModifierType(modifierTypes.REVERSE_DNA_SPLICERS, (party: Pokemon[]) => !party[0].scene.gameMode.isSplicedOnly && party.filter(p => p.fusionSpecies).length ? 3 : 0, 3),
new WeightedModifierType(modifierTypes.VOUCHER, 3), new WeightedModifierType(modifierTypes.VOUCHER, 3),
].map(m => { m.setTier(ModifierTier.ULTRA); return m; }), ].map(m => { m.setTier(ModifierTier.ULTRA); return m; }),
[ModifierTier.ROGUE]: [ [ModifierTier.ROGUE]: [
@ -1013,7 +1013,7 @@ const modifierPool = {
new WeightedModifierType(modifierTypes.SHINY_CHARM, 18), new WeightedModifierType(modifierTypes.SHINY_CHARM, 18),
new WeightedModifierType(modifierTypes.HEALING_CHARM, 18), new WeightedModifierType(modifierTypes.HEALING_CHARM, 18),
new WeightedModifierType(modifierTypes.VOUCHER_PLUS, 8), new WeightedModifierType(modifierTypes.VOUCHER_PLUS, 8),
new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => party[0].scene.gameMode !== GameMode.SPLICED_ENDLESS && party.filter(p => !p.fusionSpecies).length > 1 ? 24 : 0, 24), new WeightedModifierType(modifierTypes.DNA_SPLICERS, (party: Pokemon[]) => !party[0].scene.gameMode.isSplicedOnly && party.filter(p => !p.fusionSpecies).length > 1 ? 24 : 0, 24),
new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => party[0].scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE] ? 1 : 0, 1), new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => party[0].scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE] ? 1 : 0, 1),
].map(m => { m.setTier(ModifierTier.MASTER); return m; }), ].map(m => { m.setTier(ModifierTier.MASTER); return m; }),
[ModifierTier.LUXURY]: [ [ModifierTier.LUXURY]: [
@ -1250,7 +1250,7 @@ export function getEnemyBuffModifierForWave(tier: ModifierTier, enemyModifiers:
return modifier; return modifier;
} }
export function getEnemyModifierTypesForWave(waveIndex: integer, count: integer, party: EnemyPokemon[], poolType: ModifierPoolType.WILD | ModifierPoolType.TRAINER, gameMode: GameMode): PokemonHeldItemModifierType[] { export function getEnemyModifierTypesForWave(waveIndex: integer, count: integer, party: EnemyPokemon[], poolType: ModifierPoolType.WILD | ModifierPoolType.TRAINER): PokemonHeldItemModifierType[] {
const ret = new Array(count).fill(0).map(() => getNewModifierTypeOption(party, poolType).type as PokemonHeldItemModifierType); const ret = new Array(count).fill(0).map(() => getNewModifierTypeOption(party, poolType).type as PokemonHeldItemModifierType);
if (!(waveIndex % 1000)) if (!(waveIndex % 1000))
ret.push(getModifierType(modifierTypes.MINI_BLACK_HOLE) as PokemonHeldItemModifierType); ret.push(getModifierType(modifierTypes.MINI_BLACK_HOLE) as PokemonHeldItemModifierType);

View File

@ -35,7 +35,7 @@ import { Unlockables, getUnlockableName } from "./system/unlockables";
import { getBiomeKey } from "./field/arena"; import { getBiomeKey } from "./field/arena";
import { BattleType, BattlerIndex, TurnCommand } from "./battle"; import { BattleType, BattlerIndex, TurnCommand } from "./battle";
import { BattleSpec } from "./enums/battle-spec"; import { BattleSpec } from "./enums/battle-spec";
import { GameMode } from "./game-mode"; import { GameModes } from "./game-mode";
import { Species } from "./data/enums/species"; import { Species } from "./data/enums/species";
import { HealAchv, LevelAchv, MoneyAchv, achvs } from "./system/achv"; import { HealAchv, LevelAchv, MoneyAchv, achvs } from "./system/achv";
import { trainerConfigs } from "./data/trainer-config"; import { trainerConfigs } from "./data/trainer-config";
@ -294,7 +294,7 @@ export class SelectStarterPhase extends Phase {
starterPokemon.tryPopulateMoveset(starter.moveset); starterPokemon.tryPopulateMoveset(starter.moveset);
if (starter.pokerus) if (starter.pokerus)
starterPokemon.pokerus = true; starterPokemon.pokerus = true;
if (this.scene.gameMode === GameMode.SPLICED_ENDLESS) if (this.scene.gameMode.isSplicedOnly)
starterPokemon.generateFusionSpecies(true); starterPokemon.generateFusionSpecies(true);
starterPokemon.setVisible(false); starterPokemon.setVisible(false);
party.push(starterPokemon); party.push(starterPokemon);
@ -305,7 +305,7 @@ export class SelectStarterPhase extends Phase {
this.scene.ui.setMode(Mode.MESSAGE).then(() => { this.scene.ui.setMode(Mode.MESSAGE).then(() => {
SoundFade.fadeOut(this.scene, this.scene.sound.get('menu'), 500, true); SoundFade.fadeOut(this.scene, this.scene.sound.get('menu'), 500, true);
this.scene.time.delayedCall(500, () => this.scene.playBgm()); this.scene.time.delayedCall(500, () => this.scene.playBgm());
if (this.scene.gameMode === GameMode.CLASSIC) if (this.scene.gameMode.isClassic)
this.scene.gameData.gameStats.classicSessionsPlayed++; this.scene.gameData.gameStats.classicSessionsPlayed++;
else else
this.scene.gameData.gameStats.endlessSessionsPlayed++; this.scene.gameData.gameStats.endlessSessionsPlayed++;
@ -482,7 +482,7 @@ export class EncounterPhase extends BattlePhase {
} }
if (enemyPokemon.species.speciesId === Species.ETERNATUS) { if (enemyPokemon.species.speciesId === Species.ETERNATUS) {
if (this.scene.gameMode === GameMode.CLASSIC && (battle.battleSpec === BattleSpec.FINAL_BOSS || !(battle.waveIndex % 250))) { if (this.scene.gameMode.isClassic && (battle.battleSpec === BattleSpec.FINAL_BOSS || this.scene.gameMode.isWaveFinal(battle.waveIndex))) {
if (battle.battleSpec !== BattleSpec.FINAL_BOSS) { if (battle.battleSpec !== BattleSpec.FINAL_BOSS) {
enemyPokemon.formIndex = 1; enemyPokemon.formIndex = 1;
enemyPokemon.updateScale(); enemyPokemon.updateScale();
@ -797,9 +797,9 @@ export class SelectBiomePhase extends BattlePhase {
this.end(); this.end();
}; };
if (this.scene.gameMode === GameMode.CLASSIC && this.scene.currentBattle.waveIndex === this.scene.finalWave - 9) if (this.scene.gameMode.isClassic && this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex + 9))
setNextBiome(Biome.END); setNextBiome(Biome.END);
else if (this.scene.gameMode !== GameMode.CLASSIC) else if (this.scene.gameMode.hasRandomBiomes)
setNextBiome(this.generateNextBiome()); setNextBiome(this.generateNextBiome());
else if (Array.isArray(biomeLinks[currentBiome])) { else if (Array.isArray(biomeLinks[currentBiome])) {
let biomes: Biome[]; let biomes: Biome[];
@ -1775,7 +1775,7 @@ export class BattleEndPhase extends BattlePhase {
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++;
if (this.scene.gameMode === GameMode.ENDLESS && this.scene.currentBattle.waveIndex + 1 > this.scene.gameData.gameStats.highestEndlessWave) if (this.scene.gameMode.isEndless && this.scene.currentBattle.waveIndex + 1 > this.scene.gameData.gameStats.highestEndlessWave)
this.scene.gameData.gameStats.highestEndlessWave = this.scene.currentBattle.waveIndex + 1; this.scene.gameData.gameStats.highestEndlessWave = this.scene.currentBattle.waveIndex + 1;
for (let pokemon of this.scene.getField()) { for (let pokemon of this.scene.getField()) {
@ -2844,16 +2844,16 @@ export class VictoryPhase extends PokemonPhase {
if (this.scene.currentBattle.battleType === BattleType.TRAINER) if (this.scene.currentBattle.battleType === BattleType.TRAINER)
this.scene.pushPhase(new TrainerVictoryPhase(this.scene)); this.scene.pushPhase(new TrainerVictoryPhase(this.scene));
this.scene.pushPhase(new EggLapsePhase(this.scene)); this.scene.pushPhase(new EggLapsePhase(this.scene));
if (this.scene.gameMode !== GameMode.CLASSIC || this.scene.currentBattle.waveIndex < this.scene.finalWave) { if (this.scene.gameMode.isEndless || !this.scene.gameMode.isWaveFinal(this.scene.currentBattle.waveIndex)) {
if (this.scene.currentBattle.waveIndex % 10) if (this.scene.currentBattle.waveIndex % 10)
this.scene.pushPhase(new SelectModifierPhase(this.scene)); this.scene.pushPhase(new SelectModifierPhase(this.scene));
else { else {
const superExpWave = this.scene.gameMode === GameMode.CLASSIC ? 20 : 10; const superExpWave = !this.scene.gameMode.isEndless ? 20 : 10;
if (this.scene.currentBattle.waveIndex <= 750 && (this.scene.currentBattle.waveIndex <= 500 || (this.scene.currentBattle.waveIndex % 30) === superExpWave)) if (this.scene.currentBattle.waveIndex <= 750 && (this.scene.currentBattle.waveIndex <= 500 || (this.scene.currentBattle.waveIndex % 30) === superExpWave))
this.scene.pushPhase(new ModifierRewardPhase(this.scene, (this.scene.currentBattle.waveIndex % 30) !== superExpWave || this.scene.currentBattle.waveIndex > 250 ? modifierTypes.EXP_CHARM : modifierTypes.SUPER_EXP_CHARM)); this.scene.pushPhase(new ModifierRewardPhase(this.scene, (this.scene.currentBattle.waveIndex % 30) !== superExpWave || this.scene.currentBattle.waveIndex > 250 ? modifierTypes.EXP_CHARM : modifierTypes.SUPER_EXP_CHARM));
if (this.scene.currentBattle.waveIndex <= 150 && !(this.scene.currentBattle.waveIndex % 50)) if (this.scene.currentBattle.waveIndex <= 150 && !(this.scene.currentBattle.waveIndex % 50))
this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.GOLDEN_POKEBALL)); this.scene.pushPhase(new ModifierRewardPhase(this.scene, modifierTypes.GOLDEN_POKEBALL));
if (this.scene.gameMode !== GameMode.CLASSIC && !(this.scene.currentBattle.waveIndex % 50)) { if (this.scene.gameMode.isEndless && !(this.scene.currentBattle.waveIndex % 50)) {
this.scene.pushPhase(new ModifierRewardPhase(this.scene, !(this.scene.currentBattle.waveIndex % 250) ? modifierTypes.VOUCHER_PREMIUM : modifierTypes.VOUCHER_PLUS)); this.scene.pushPhase(new ModifierRewardPhase(this.scene, !(this.scene.currentBattle.waveIndex % 250) ? modifierTypes.VOUCHER_PREMIUM : modifierTypes.VOUCHER_PLUS));
this.scene.pushPhase(new AddEnemyBuffModifierPhase(this.scene)); this.scene.pushPhase(new AddEnemyBuffModifierPhase(this.scene));
} }

View File

@ -8,7 +8,7 @@ import PokemonData from "./pokemon-data";
import PersistentModifierData from "./modifier-data"; import PersistentModifierData from "./modifier-data";
import ArenaData from "./arena-data"; import ArenaData from "./arena-data";
import { Unlockables } from "./unlockables"; import { Unlockables } from "./unlockables";
import { GameMode } from "../game-mode"; import { GameModes, gameModes } from "../game-mode";
import { BattleType } from "../battle"; import { BattleType } from "../battle";
import TrainerData from "./trainer-data"; import TrainerData from "./trainer-data";
import { trainerConfigs } from "../data/trainer-config"; import { trainerConfigs } from "../data/trainer-config";
@ -76,7 +76,7 @@ interface SystemSaveData {
interface SessionSaveData { interface SessionSaveData {
seed: string; seed: string;
playTime: integer; playTime: integer;
gameMode: GameMode; gameMode: GameModes;
party: PokemonData[]; party: PokemonData[];
enemyParty: PokemonData[]; enemyParty: PokemonData[];
modifiers: PersistentModifierData[]; modifiers: PersistentModifierData[];
@ -458,7 +458,7 @@ export class GameData {
const sessionData = { const sessionData = {
seed: scene.seed, seed: scene.seed,
playTime: scene.sessionPlayTime, playTime: scene.sessionPlayTime,
gameMode: scene.gameMode, gameMode: scene.gameMode.modeId,
party: scene.getParty().map(p => new PokemonData(p)), party: scene.getParty().map(p => new PokemonData(p)),
enemyParty: scene.getEnemyParty().map(p => new PokemonData(p)), enemyParty: scene.getEnemyParty().map(p => new PokemonData(p)),
modifiers: scene.findModifiers(() => true).map(m => new PersistentModifierData(m, true)), modifiers: scene.findModifiers(() => true).map(m => new PersistentModifierData(m, true)),
@ -508,7 +508,7 @@ export class GameData {
scene.sessionPlayTime = sessionData.playTime || 0; scene.sessionPlayTime = sessionData.playTime || 0;
scene.gameMode = sessionData.gameMode || GameMode.CLASSIC; scene.gameMode = gameModes[sessionData.gameMode || GameModes.CLASSIC];
const loadPokemonAssets: Promise<void>[] = []; const loadPokemonAssets: Promise<void>[] = [];

View File

@ -1,4 +1,4 @@
import { GameMode } from "../game-mode"; import { GameModes } from "../game-mode";
import PokemonData from "./pokemon-data"; import PokemonData from "./pokemon-data";
import PersistentModifierData from "./modifier-data"; import PersistentModifierData from "./modifier-data";
@ -12,7 +12,7 @@ export interface SessionHistory {
seed: string; seed: string;
playTime: integer; playTime: integer;
result: SessionHistoryResult, result: SessionHistoryResult,
gameMode: GameMode; gameMode: GameModes;
party: PokemonData[]; party: PokemonData[];
modifiers: PersistentModifierData[]; modifiers: PersistentModifierData[];
money: integer; money: integer;

View File

@ -1,4 +1,4 @@
import { GameMode, gameModeNames } from "../game-mode"; import { GameModes, gameModes } from "../game-mode";
export enum Unlockables { export enum Unlockables {
ENDLESS_MODE, ENDLESS_MODE,
@ -9,10 +9,10 @@ export enum Unlockables {
export function getUnlockableName(unlockable: Unlockables) { export function getUnlockableName(unlockable: Unlockables) {
switch (unlockable) { switch (unlockable) {
case Unlockables.ENDLESS_MODE: case Unlockables.ENDLESS_MODE:
return `${gameModeNames[GameMode.ENDLESS]} Mode`; return `${gameModes[GameModes.ENDLESS].getName()} Mode`;
case Unlockables.MINI_BLACK_HOLE: case Unlockables.MINI_BLACK_HOLE:
return 'Mini Black Hole'; return 'Mini Black Hole';
case Unlockables.SPLICED_ENDLESS_MODE: case Unlockables.SPLICED_ENDLESS_MODE:
return `${gameModeNames[GameMode.SPLICED_ENDLESS]} Mode`; return `${gameModes[GameModes.SPLICED_ENDLESS].getName()} Mode`;
} }
} }

View File

@ -282,8 +282,10 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.lastTeraType = teraType; this.lastTeraType = teraType;
} }
if (nameUpdated || teraTypeUpdated) if (nameUpdated || teraTypeUpdated) {
this.splicedIcon.setVisible(!!pokemon.fusionSpecies);
this.splicedIcon.setPositionRelative(this.nameText, this.nameText.displayWidth + this.genderText.displayWidth + 1 + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0), 1.5); this.splicedIcon.setPositionRelative(this.nameText, this.nameText.displayWidth + this.genderText.displayWidth + 1 + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0), 1.5);
}
if (this.lastStatus !== (pokemon.status?.effect || StatusEffect.NONE)) { if (this.lastStatus !== (pokemon.status?.effect || StatusEffect.NONE)) {
this.lastStatus = pokemon.status?.effect || StatusEffect.NONE; this.lastStatus = pokemon.status?.effect || StatusEffect.NONE;

View File

@ -6,7 +6,7 @@ import { Mode } from "./ui";
import MessageUiHandler from "./message-ui-handler"; import MessageUiHandler from "./message-ui-handler";
import { Gender, getGenderColor, getGenderSymbol } from "../data/gender"; import { Gender, getGenderColor, getGenderSymbol } from "../data/gender";
import { allAbilities } from "../data/ability"; import { allAbilities } from "../data/ability";
import { GameMode, gameModeNames } from "../game-mode"; import { GameModes, gameModes } from "../game-mode";
import { Unlockables } from "../system/unlockables"; import { Unlockables } from "../system/unlockables";
import { GrowthRate, getGrowthRateColor } from "../data/exp"; import { GrowthRate, getGrowthRateColor } from "../data/exp";
import { DexAttr, DexEntry, StarterFormMoveData, StarterMoveset } from "../system/game-data"; import { DexAttr, DexEntry, StarterFormMoveData, StarterMoveset } from "../system/game-data";
@ -1204,8 +1204,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
ui.showText('Begin with these Pokémon?', null, () => { ui.showText('Begin with these Pokémon?', null, () => {
ui.setModeWithoutClear(Mode.CONFIRM, () => { ui.setModeWithoutClear(Mode.CONFIRM, () => {
const startRun = (gameMode: GameMode) => { const startRun = (gameMode: GameModes) => {
this.scene.gameMode = gameMode; this.scene.gameMode = gameModes[gameMode];
ui.setMode(Mode.STARTER_SELECT); ui.setMode(Mode.STARTER_SELECT);
const thisObj = this; const thisObj = this;
const originalStarterSelectCallback = this.starterSelectCallback; const originalStarterSelectCallback = this.starterSelectCallback;
@ -1225,18 +1225,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
ui.setMode(Mode.STARTER_SELECT); ui.setMode(Mode.STARTER_SELECT);
const options = [ const options = [
{ {
label: gameModeNames[GameMode.CLASSIC], label: gameModes[GameModes.CLASSIC].getName(),
handler: () => startRun(GameMode.CLASSIC) handler: () => startRun(GameModes.CLASSIC)
}, },
{ {
label: gameModeNames[GameMode.ENDLESS], label: gameModes[GameModes.ENDLESS].getName(),
handler: () => startRun(GameMode.ENDLESS) handler: () => startRun(GameModes.ENDLESS)
} }
]; ];
if (this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) { if (this.scene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]) {
options.push({ options.push({
label: gameModeNames[GameMode.SPLICED_ENDLESS], label: gameModes[GameModes.SPLICED_ENDLESS].getName(),
handler: () => startRun(GameMode.SPLICED_ENDLESS) handler: () => startRun(GameModes.SPLICED_ENDLESS)
}); });
} }
options.push({ options.push({
@ -1245,7 +1245,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
}); });
ui.showText('Select a game mode.', null, () => ui.setModeWithoutClear(Mode.OPTION_SELECT, { options: options, yOffset: 19 })); ui.showText('Select a game mode.', null, () => ui.setModeWithoutClear(Mode.OPTION_SELECT, { options: options, yOffset: 19 }));
} else } else
startRun(GameMode.CLASSIC); startRun(GameModes.CLASSIC);
}, cancel, null, null, 19); }, cancel, null, null, 19);
}); });