diff --git a/jsconfig.json b/jsconfig.json index 0b18b9ccc53..d0406141d06 100644 --- a/jsconfig.json +++ b/jsconfig.json @@ -4,6 +4,7 @@ "module": "ES2020", "moduleResolution": "node", "checkJs": true, - "esModuleInterop": true + "esModuleInterop": true, + "strictNullChecks": false } } \ No newline at end of file diff --git a/src/battle-phases.ts b/src/battle-phases.ts index 88ade6d114d..6a4d7a4068a 100644 --- a/src/battle-phases.ts +++ b/src/battle-phases.ts @@ -26,6 +26,7 @@ import { Weather, WeatherType, getRandomWeatherType, getWeatherDamageMessage, ge import { TempBattleStat } from "./data/temp-battle-stat"; import { ArenaTrapTag, TrickRoomTag } from "./data/arena-tag"; import { PostWeatherLapseAbAttr, PreWeatherDamageAbAttr, ProtectStatAttr, SuppressWeatherEffectAbAttr, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreWeatherEffectAbAttrs } from "./data/ability"; +import { Unlockables, getUnlockableName } from "./system/unlockables"; export class CheckLoadPhase extends BattlePhase { private loaded: boolean; @@ -1602,6 +1603,39 @@ export class GameOverPhase extends BattlePhase { }); }); } + + end(): void { + if (!this.scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE]) + this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.MINI_BLACK_HOLE)); + + super.end(); + } +} + +export class UnlockPhase extends BattlePhase { + private unlockable: Unlockables; + + constructor(scene: BattleScene, unlockable: Unlockables) { + super(scene); + + this.unlockable = unlockable; + } + + start(): void { + this.scene.time.delayedCall(2000, () => { + this.scene.gameData.unlocks[this.unlockable] = true; + this.scene.gameData.saveSystem(); + this.scene.sound.play('level_up_fanfare'); + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.arenaBg.setVisible(false); + this.scene.ui.fadeIn(250).then(() => { + this.scene.ui.showText(`${getUnlockableName(this.unlockable)}\nhas been unlocked.`, null, () => { + this.scene.time.delayedCall(1500, () => this.scene.arenaBg.setVisible(true)); + this.end(); + }, null, true, 1500); + }); + }); + } } export class SwitchPhase extends BattlePhase { diff --git a/src/data/exp.ts b/src/data/exp.ts index f558f19fe8c..ae11a2a0ac7 100644 --- a/src/data/exp.ts +++ b/src/data/exp.ts @@ -17,7 +17,7 @@ const expLevels = [ ]; export function getLevelTotalExp(level: integer, growthRate: integer) { - return expLevels[growthRate][Math.min(level, 100) - 1]; + return expLevels[growthRate][level - 1]; }; export function getLevelRelExp(level: integer, growthRate: integer) { diff --git a/src/evolution-phase.ts b/src/evolution-phase.ts index 658b8689e03..a72223e51e1 100644 --- a/src/evolution-phase.ts +++ b/src/evolution-phase.ts @@ -168,7 +168,7 @@ export class EvolutionPhase extends BattlePhase { this.scene.time.delayedCall(1250, () => { this.scene.sound.play('evolution_fanfare'); this.scene.ui.showText(`Congratulations! Your ${preName}\nevolved into ${pokemon.name}!`, null, () => this.end(), null, true, 3000); - this.scene.time.delayedCall(4250, () => this.scene.playBgm()); + this.scene.time.delayedCall(new Utils.FixedInt(4250) as unknown as integer, () => this.scene.playBgm()); }); }); } diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index bd22bfa3485..d963027bba2 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -10,6 +10,7 @@ import PartyUiHandler, { PokemonMoveSelectFilter, PokemonSelectFilter } from '.. import * as Utils from '../utils'; import { TempBattleStat, getTempBattleStatBoosterItemName, getTempBattleStatName } from '../data/temp-battle-stat'; import { BerryType, getBerryEffectDescription, getBerryName } from '../data/berry'; +import { Unlockables } from '../system/unlockables'; type Modifier = Modifiers.Modifier; @@ -702,7 +703,7 @@ const modifierPool = { [ModifierTier.MASTER]: [ new WeightedModifierType(modifierTypes.MASTER_BALL, 3), new WeightedModifierType(modifierTypes.SHINY_CHARM, 2), - new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, 1) + new WeightedModifierType(modifierTypes.MINI_BLACK_HOLE, (party: Pokemon[]) => party[0].scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE] ? 1 : 0) ].map(m => { m.setTier(ModifierTier.MASTER); return m; }), [ModifierTier.LUXURY]: [ new WeightedModifierType(modifierTypes.GOLDEN_EXP_CHARM, (party: Pokemon[]) => party.filter(p => p.level < 100).length ? 1 : 0), diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index dad05611265..bf6d7a0ff4f 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -1010,10 +1010,12 @@ export class HeldItemTransferModifier extends PokemonHeldItemModifier { apply(args: any[]): boolean { const pokemon = args[0] as Pokemon; const targetPokemon = pokemon.isPlayer() ? pokemon.scene.getEnemyPokemon() : pokemon.scene.getPlayerPokemon(); + if (!targetPokemon) + return false; const transferredModifierTypes: ModifierTypes.ModifierType[] = []; const itemModifiers = pokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier - && (m as PokemonHeldItemModifier).pokemonId === targetPokemon.id, targetPokemon.isPlayer()) as PokemonHeldItemModifier[]; + && (m as PokemonHeldItemModifier).pokemonId === targetPokemon.id && !m.matchType(this), targetPokemon.isPlayer()) as PokemonHeldItemModifier[]; for (let i = 0; i < this.getStackCount(); i++) { if (!itemModifiers.length) diff --git a/src/pokemon.ts b/src/pokemon.ts index 1a28a75c325..48f0c393982 100644 --- a/src/pokemon.ts +++ b/src/pokemon.ts @@ -402,6 +402,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { console.log(this.species.speciesId, 'ERROR') return; } + for (let m = 0; m < allLevelMoves.length; m++) { const levelMove = allLevelMoves[m]; if (this.level < levelMove[0]) @@ -974,6 +975,22 @@ export class EnemyPokemon extends Pokemon { this.aiType = AiType.SMART_RANDOM; } + generateAndPopulateMoveset(): void { + switch (true) { + case (this.species.speciesId === Species.ETERNATUS): + this.moveset = [ + new PokemonMove(Moves.DYNAMAX_CANNON), + new PokemonMove(Moves.CROSS_POISON), + new PokemonMove(Moves.DRAGON_DANCE), + new PokemonMove(Moves.RECOVER) + ]; + break; + default: + super.generateAndPopulateMoveset(); + break; + } + } + getNextMove(): PokemonMove { const queuedMove = this.getMoveQueue().length ? this.moveset.find(m => m.moveId === this.getMoveQueue()[0].move) @@ -1116,7 +1133,7 @@ export enum AiType { RANDOM, SMART_RANDOM, SMART -}; +} export enum MoveResult { EFFECTIVE = 1, @@ -1127,7 +1144,7 @@ export enum MoveResult { FAILED, MISSED, OTHER -}; +} export type DamageResult = MoveResult.EFFECTIVE | MoveResult.SUPER_EFFECTIVE | MoveResult.NOT_VERY_EFFECTIVE | MoveResult.OTHER; diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 3273d9b55b6..68dddbe671f 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -6,17 +6,16 @@ import PokemonSpecies, { allSpecies, getPokemonSpecies } from "../data/pokemon-s import { Species } from "../data/species"; import * as Utils from "../utils"; import PokemonData from "./pokemon-data"; -import { Weather } from "../data/weather"; import PersistentModifierData from "./modifier-data"; -import { Biome } from "../data/biome"; import { PokemonHeldItemModifier } from "../modifier/modifier"; -import { ArenaTag } from "../data/arena-tag"; import ArenaData from "./arena-data"; +import { Unlockables } from "./unlockables"; interface SystemSaveData { trainerId: integer; secretId: integer; dexData: DexData; + unlocks: Unlocks; timestamp: integer; } @@ -31,6 +30,10 @@ interface SessionSaveData { timestamp: integer; } +interface Unlocks { + [key: integer]: boolean; +} + export interface DexData { [key: integer]: DexData | DexEntry } @@ -65,15 +68,20 @@ export class GameData { public dexData: DexData; + public unlocks: Unlocks; + constructor(scene: BattleScene) { this.scene = scene; this.trainerId = Utils.randInt(65536); this.secretId = Utils.randInt(65536); + this.unlocks = { + [Unlockables.MINI_BLACK_HOLE]: false + }; this.initDexData(); this.loadSystem(); } - private saveSystem(): boolean { + public saveSystem(): boolean { if (this.scene.quickStart) return false; @@ -81,6 +89,7 @@ export class GameData { trainerId: this.trainerId, secretId: this.secretId, dexData: this.dexData, + unlocks: this.unlocks, timestamp: new Date().getTime() }; @@ -99,6 +108,13 @@ export class GameData { this.trainerId = data.trainerId; this.secretId = data.secretId; + if (data.unlocks) { + for (let key of Object.keys(data.unlocks)) { + if (this.unlocks.hasOwnProperty(key)) + this.unlocks[key] = data.unlocks[key]; + } + } + if (data.timestamp === undefined) this.convertDexData(data.dexData); diff --git a/src/system/unlockables.ts b/src/system/unlockables.ts new file mode 100644 index 00000000000..aa3e58e9796 --- /dev/null +++ b/src/system/unlockables.ts @@ -0,0 +1,10 @@ +export enum Unlockables { + MINI_BLACK_HOLE +} + +export function getUnlockableName(unlockable: Unlockables) { + switch (unlockable) { + case Unlockables.MINI_BLACK_HOLE: + return 'MINI BLACK HOLE'; + } +} \ No newline at end of file