Merge branch 'pagefaultgames:main' into main

pull/590/head
YounesM 2024-05-07 12:43:54 +02:00 committed by GitHub
commit 029fc89ce5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 5908 additions and 5606 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 400 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 408 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 407 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 406 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 285 B

View File

@ -59,7 +59,7 @@ import { SceneBase } from './scene-base';
import CandyBar from './ui/candy-bar'; import CandyBar from './ui/candy-bar';
import { Variant, variantData } from './data/variant'; import { Variant, variantData } from './data/variant';
import { Localizable } from './plugins/i18n'; import { Localizable } from './plugins/i18n';
import { STARTING_WAVE_OVERRIDE, OPP_SPECIES_OVERRIDE, SEED_OVERRIDE, STARTING_BIOME_OVERRIDE } from './overrides'; import { STARTING_WAVE_OVERRIDE, OPP_SPECIES_OVERRIDE, SEED_OVERRIDE, STARTING_BIOME_OVERRIDE, DOUBLE_BATTLE_OVERRIDE } from './overrides';
import {InputsController} from "./inputs-controller"; import {InputsController} from "./inputs-controller";
import {UiInputs} from "./ui-inputs"; import {UiInputs} from "./ui-inputs";
@ -842,6 +842,9 @@ export default class BattleScene extends SceneBase {
} else if (!battleConfig) } else if (!battleConfig)
newDouble = !!double; newDouble = !!double;
if (DOUBLE_BATTLE_OVERRIDE)
newDouble = true;
const lastBattle = this.currentBattle; const lastBattle = this.currentBattle;
if (lastBattle?.double && !newDouble) if (lastBattle?.double && !newDouble)

View File

@ -1827,6 +1827,19 @@ function getAnticipationCondition(): AbAttrCondition {
}; };
} }
/**
* Creates an ability condition that causes the ability to fail if that ability
* has already been used by that pokemon that battle. It requires an ability to
* be specified due to current limitations in how conditions on abilities work.
* @param {Abilities} ability The ability to check if it's already been applied
* @returns {AbAttrCondition} The condition
*/
function getOncePerBattleCondition(ability: Abilities): AbAttrCondition {
return (pokemon: Pokemon) => {
return !pokemon.battleData?.abilitiesApplied.includes(ability);
}
}
export class ForewarnAbAttr extends PostSummonAbAttr { export class ForewarnAbAttr extends PostSummonAbAttr {
constructor() { constructor() {
super(true); super(true);
@ -2549,6 +2562,9 @@ function applyAbAttrsInternal<TAttr extends AbAttr>(attrType: { new(...args: any
return applyNextAbAttr(); return applyNextAbAttr();
pokemon.scene.setPhaseQueueSplice(); pokemon.scene.setPhaseQueueSplice();
const onApplySuccess = () => { const onApplySuccess = () => {
if (pokemon.battleData && !pokemon.battleData.abilitiesApplied.includes(ability.id)) {
pokemon.battleData.abilitiesApplied.push(ability.id);
}
if (attr.showAbility && !quiet) { if (attr.showAbility && !quiet) {
if (showAbilityInstant) if (showAbilityInstant)
pokemon.scene.abilityBar.showAbility(pokemon, passive); pokemon.scene.abilityBar.showAbility(pokemon, passive);
@ -3411,9 +3427,11 @@ export function initAbilities() {
new Ability(Abilities.NEUROFORCE, 7) new Ability(Abilities.NEUROFORCE, 7)
.attr(MovePowerBoostAbAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 1.25), .attr(MovePowerBoostAbAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 1.25),
new Ability(Abilities.INTREPID_SWORD, 8) new Ability(Abilities.INTREPID_SWORD, 8)
.attr(PostSummonStatChangeAbAttr, BattleStat.ATK, 1, true), .attr(PostSummonStatChangeAbAttr, BattleStat.ATK, 1, true)
.condition(getOncePerBattleCondition(Abilities.INTREPID_SWORD)),
new Ability(Abilities.DAUNTLESS_SHIELD, 8) new Ability(Abilities.DAUNTLESS_SHIELD, 8)
.attr(PostSummonStatChangeAbAttr, BattleStat.DEF, 1, true), .attr(PostSummonStatChangeAbAttr, BattleStat.DEF, 1, true)
.condition(getOncePerBattleCondition(Abilities.DAUNTLESS_SHIELD)),
new Ability(Abilities.LIBERO, 8) new Ability(Abilities.LIBERO, 8)
.unimplemented(), .unimplemented(),
new Ability(Abilities.BALL_FETCH, 8) new Ability(Abilities.BALL_FETCH, 8)
@ -3622,7 +3640,8 @@ export function initAbilities() {
.attr(IgnoreTypeImmunityAbAttr, Type.GHOST, [Type.NORMAL, Type.FIGHTING]) .attr(IgnoreTypeImmunityAbAttr, Type.GHOST, [Type.NORMAL, Type.FIGHTING])
.ignorable(), // TODO: evasiveness bypass should not be ignored, but accuracy immunity should .ignorable(), // TODO: evasiveness bypass should not be ignored, but accuracy immunity should
new Ability(Abilities.SUPERSWEET_SYRUP, 9) new Ability(Abilities.SUPERSWEET_SYRUP, 9)
.unimplemented(), .attr(PostSummonStatChangeAbAttr, BattleStat.EVA, -1)
.condition(getOncePerBattleCondition(Abilities.SUPERSWEET_SYRUP)),
new Ability(Abilities.HOSPITALITY, 9) new Ability(Abilities.HOSPITALITY, 9)
.attr(PostSummonAllyHealAbAttr, 4, true), .attr(PostSummonAllyHealAbAttr, 4, true),
new Ability(Abilities.TOXIC_CHAIN, 9) new Ability(Abilities.TOXIC_CHAIN, 9)

View File

@ -2961,6 +2961,42 @@ export class AddArenaTrapTagAttr extends AddArenaTagAttr {
} }
} }
export class RemoveArenaTrapAttr extends MoveEffectAttr {
private targetBothSides: boolean;
constructor(targetBothSides: boolean = false) {
super(true, MoveEffectTrigger.PRE_APPLY);
this.targetBothSides = targetBothSides;
}
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!super.apply(user, target, move, args))
return false;
if(this.targetBothSides){
user.scene.arena.removeTagOnSide(ArenaTagType.SPIKES, ArenaTagSide.PLAYER);
user.scene.arena.removeTagOnSide(ArenaTagType.TOXIC_SPIKES, ArenaTagSide.PLAYER);
user.scene.arena.removeTagOnSide(ArenaTagType.STEALTH_ROCK, ArenaTagSide.PLAYER);
user.scene.arena.removeTagOnSide(ArenaTagType.STICKY_WEB, ArenaTagSide.PLAYER);
user.scene.arena.removeTagOnSide(ArenaTagType.SPIKES, ArenaTagSide.ENEMY);
user.scene.arena.removeTagOnSide(ArenaTagType.TOXIC_SPIKES, ArenaTagSide.ENEMY);
user.scene.arena.removeTagOnSide(ArenaTagType.STEALTH_ROCK, ArenaTagSide.ENEMY);
user.scene.arena.removeTagOnSide(ArenaTagType.STICKY_WEB, ArenaTagSide.ENEMY);
}
else {
user.scene.arena.removeTagOnSide(ArenaTagType.SPIKES, target.isPlayer() ? ArenaTagSide.ENEMY : ArenaTagSide.PLAYER);
user.scene.arena.removeTagOnSide(ArenaTagType.TOXIC_SPIKES, target.isPlayer() ? ArenaTagSide.ENEMY : ArenaTagSide.PLAYER);
user.scene.arena.removeTagOnSide(ArenaTagType.STEALTH_ROCK, target.isPlayer() ? ArenaTagSide.ENEMY : ArenaTagSide.PLAYER);
user.scene.arena.removeTagOnSide(ArenaTagType.STICKY_WEB, target.isPlayer() ? ArenaTagSide.ENEMY : ArenaTagSide.PLAYER);
}
return true;
}
}
export class RemoveScreensAttr extends MoveEffectAttr { export class RemoveScreensAttr extends MoveEffectAttr {
private targetBothSides: boolean; private targetBothSides: boolean;
@ -4602,7 +4638,7 @@ export function initMoves() {
BattlerTagType.SEEDED, BattlerTagType.SEEDED,
BattlerTagType.INFESTATION BattlerTagType.INFESTATION
], true) ], true)
.partial(), .attr(RemoveArenaTrapAttr),
new StatusMove(Moves.SWEET_SCENT, Type.NORMAL, 100, 20, -1, 0, 2) new StatusMove(Moves.SWEET_SCENT, Type.NORMAL, 100, 20, -1, 0, 2)
.attr(StatChangeAttr, BattleStat.EVA, -1) .attr(StatChangeAttr, BattleStat.EVA, -1)
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
@ -5144,7 +5180,8 @@ export function initMoves() {
.attr(StatChangeAttr, BattleStat.EVA, -1) .attr(StatChangeAttr, BattleStat.EVA, -1)
.attr(ClearWeatherAttr, WeatherType.FOG) .attr(ClearWeatherAttr, WeatherType.FOG)
.attr(ClearTerrainAttr) .attr(ClearTerrainAttr)
.attr(RemoveScreensAttr, true), .attr(RemoveScreensAttr, false)
.attr(RemoveArenaTrapAttr, true),
new StatusMove(Moves.TRICK_ROOM, Type.PSYCHIC, -1, 5, -1, -7, 4) new StatusMove(Moves.TRICK_ROOM, Type.PSYCHIC, -1, 5, -1, -7, 4)
.attr(AddArenaTagAttr, ArenaTagType.TRICK_ROOM, 5) .attr(AddArenaTagAttr, ArenaTagType.TRICK_ROOM, 5)
.ignoresProtect() .ignoresProtect()
@ -6444,6 +6481,7 @@ export function initMoves() {
BattlerTagType.INFESTATION BattlerTagType.INFESTATION
], true) ], true)
.attr(StatusEffectAttr, StatusEffect.POISON) .attr(StatusEffectAttr, StatusEffect.POISON)
.attr(RemoveArenaTrapAttr)
.target(MoveTarget.ALL_NEAR_ENEMIES), .target(MoveTarget.ALL_NEAR_ENEMIES),
new StatusMove(Moves.DOODLE, Type.NORMAL, 100, 10, -1, 0, 9) new StatusMove(Moves.DOODLE, Type.NORMAL, 100, 10, -1, 0, 9)
.attr(AbilityCopyAttr, true), .attr(AbilityCopyAttr, true),
@ -6487,7 +6525,7 @@ export function initMoves() {
.target(MoveTarget.BOTH_SIDES), .target(MoveTarget.BOTH_SIDES),
new SelfStatusMove(Moves.TIDY_UP, Type.NORMAL, -1, 10, 100, 0, 9) new SelfStatusMove(Moves.TIDY_UP, Type.NORMAL, -1, 10, 100, 0, 9)
.attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPD ], 1, true) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPD ], 1, true)
.partial(), .attr(RemoveArenaTrapAttr),
new StatusMove(Moves.SNOWSCAPE, Type.ICE, -1, 10, -1, 0, 9) new StatusMove(Moves.SNOWSCAPE, Type.ICE, -1, 10, -1, 0, 9)
.attr(WeatherChangeAttr, WeatherType.SNOW) .attr(WeatherChangeAttr, WeatherType.SNOW)
.target(MoveTarget.BOTH_SIDES), .target(MoveTarget.BOTH_SIDES),

File diff suppressed because it is too large Load Diff

View File

@ -43,7 +43,7 @@ import { Nature, getNatureStatMultiplier } from '../data/nature';
import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangeStatusEffectTrigger } from '../data/pokemon-forms'; import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangePostMoveTrigger, SpeciesFormChangeStatusEffectTrigger } from '../data/pokemon-forms';
import { TerrainType } from '../data/terrain'; import { TerrainType } from '../data/terrain';
import { TrainerSlot } from '../data/trainer-config'; import { TrainerSlot } from '../data/trainer-config';
import { ABILITY_OVERRIDE, MOVE_OVERRIDE, MOVE_OVERRIDE_2, OPP_ABILITY_OVERRIDE, OPP_MOVE_OVERRIDE, OPP_MOVE_OVERRIDE_2, OPP_SHINY_OVERRIDE, OPP_VARIANT_OVERRIDE } from '../overrides'; import { ABILITY_OVERRIDE, MOVE_OVERRIDE, MOVE_OVERRIDE_2, OPP_ABILITY_OVERRIDE, OPP_MOVE_OVERRIDE, OPP_MOVE_OVERRIDE_2, OPP_PASSIVE_ABILITY_OVERRIDE, OPP_SHINY_OVERRIDE, OPP_VARIANT_OVERRIDE, PASSIVE_ABILITY_OVERRIDE } from '../overrides';
import { BerryType } from '../data/berry'; import { BerryType } from '../data/berry';
import i18next from '../plugins/i18n'; import i18next from '../plugins/i18n';
@ -811,6 +811,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
getPassiveAbility(): Ability { getPassiveAbility(): Ability {
if (PASSIVE_ABILITY_OVERRIDE && this.isPlayer())
return allAbilities[PASSIVE_ABILITY_OVERRIDE];
if (OPP_PASSIVE_ABILITY_OVERRIDE && !this.isPlayer())
return allAbilities[OPP_PASSIVE_ABILITY_OVERRIDE];
let starterSpeciesId = this.species.speciesId; let starterSpeciesId = this.species.speciesId;
while (pokemonPrevolutions.hasOwnProperty(starterSpeciesId)) while (pokemonPrevolutions.hasOwnProperty(starterSpeciesId))
starterSpeciesId = pokemonPrevolutions[starterSpeciesId]; starterSpeciesId = pokemonPrevolutions[starterSpeciesId];
@ -818,6 +823,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
hasPassive(): boolean { hasPassive(): boolean {
if ((PASSIVE_ABILITY_OVERRIDE !== Abilities.NONE && this.isPlayer()) || (OPP_PASSIVE_ABILITY_OVERRIDE !== Abilities.NONE && !this.isPlayer()))
return true;
return this.passive || this.isBoss(); return this.passive || this.isBoss();
} }
@ -1701,18 +1708,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}); });
} }
cry(soundConfig?: Phaser.Types.Sound.SoundConfig): AnySound { cry(soundConfig?: Phaser.Types.Sound.SoundConfig, sceneOverride?: BattleScene): AnySound {
const cry = this.getSpeciesForm().cry(this.scene, soundConfig); const scene = sceneOverride || this.scene;
const cry = this.getSpeciesForm().cry(scene, soundConfig);
let duration = cry.totalDuration * 1000; let duration = cry.totalDuration * 1000;
if (this.fusionSpecies) { if (this.fusionSpecies) {
let fusionCry = this.getFusionSpeciesForm().cry(this.scene, soundConfig, true); let fusionCry = this.getFusionSpeciesForm().cry(scene, soundConfig, true);
duration = Math.min(duration, fusionCry.totalDuration * 1000); duration = Math.min(duration, fusionCry.totalDuration * 1000);
fusionCry.destroy(); fusionCry.destroy();
this.scene.time.delayedCall(Utils.fixedInt(Math.ceil(duration * 0.4)), () => { scene.time.delayedCall(Utils.fixedInt(Math.ceil(duration * 0.4)), () => {
try { try {
SoundFade.fadeOut(this.scene, cry, Utils.fixedInt(Math.ceil(duration * 0.2))); SoundFade.fadeOut(scene, cry, Utils.fixedInt(Math.ceil(duration * 0.2)));
fusionCry = this.getFusionSpeciesForm().cry(this.scene, Object.assign({ seek: Math.max(fusionCry.totalDuration * 0.4, 0) }, soundConfig)); fusionCry = this.getFusionSpeciesForm().cry(scene, Object.assign({ seek: Math.max(fusionCry.totalDuration * 0.4, 0) }, soundConfig));
SoundFade.fadeIn(this.scene, fusionCry, Utils.fixedInt(Math.ceil(duration * 0.2)), this.scene.masterVolume * this.scene.seVolume, 0); SoundFade.fadeIn(scene, fusionCry, Utils.fixedInt(Math.ceil(duration * 0.2)), scene.masterVolume * scene.seVolume, 0);
} catch (err) { } catch (err) {
console.error(err); console.error(err);
} }
@ -3126,6 +3134,7 @@ export class PokemonBattleData {
public hitCount: integer = 0; public hitCount: integer = 0;
public endured: boolean = false; public endured: boolean = false;
public berriesEaten: BerryType[] = []; public berriesEaten: BerryType[] = [];
public abilitiesApplied: Abilities[] = [];
} }
export class PokemonBattleSummonData { export class PokemonBattleSummonData {

View File

@ -77,6 +77,7 @@ export class LoadingScene extends SceneBase {
this.loadImage('shiny_star_small_1', 'ui', 'shiny_small_1.png'); this.loadImage('shiny_star_small_1', 'ui', 'shiny_small_1.png');
this.loadImage('shiny_star_small_2', 'ui', 'shiny_small_2.png'); this.loadImage('shiny_star_small_2', 'ui', 'shiny_small_2.png');
this.loadImage('ha_capsule', 'ui', 'ha_capsule.png'); this.loadImage('ha_capsule', 'ui', 'ha_capsule.png');
this.loadImage('champion_ribbon', 'ui', 'champion_ribbon.png');
this.loadImage('icon_spliced', 'ui'); this.loadImage('icon_spliced', 'ui');
this.loadImage('icon_tera', 'ui'); this.loadImage('icon_tera', 'ui');
this.loadImage('type_tera', 'ui'); this.loadImage('type_tera', 'ui');

View File

@ -144,9 +144,16 @@ class AddPokeballModifierType extends ModifierType implements Localizable {
} }
localize(): void { localize(): void {
// TODO: Actually use i18n to localize this description.
this.name = `${this.count}x ${getPokeballName(this.pokeballType)}`; this.name = `${this.count}x ${getPokeballName(this.pokeballType)}`;
this.description = `Receive ${getPokeballName(this.pokeballType)} x${this.count}\nCatch Rate: ${getPokeballCatchMultiplier(this.pokeballType) > -1 ? `${getPokeballCatchMultiplier(this.pokeballType)}x` : 'Certain'}`; this.description = `Receive ${getPokeballName(this.pokeballType)} x${this.count} (Inventory: {AMOUNT}) \nCatch Rate: ${getPokeballCatchMultiplier(this.pokeballType) > -1 ? `${getPokeballCatchMultiplier(this.pokeballType)}x` : 'Certain'}`;
} }
getDescription(scene: BattleScene): string {
this.localize();
return this.description.replace('{AMOUNT}', scene.pokeballCounts[this.pokeballType].toString());
}
} }
class AddVoucherModifierType extends ModifierType { class AddVoucherModifierType extends ModifierType {
@ -299,7 +306,7 @@ export class PokemonNatureChangeModifierType extends PokemonModifierType {
protected nature: Nature; protected nature: Nature;
constructor(nature: Nature) { constructor(nature: Nature) {
super(`${getNatureName(nature)} Mint`, `Changes a Pokémon\'s nature to ${getNatureName(nature, true, true, true)}`, ((_type, args) => new Modifiers.PokemonNatureChangeModifier(this, (args[0] as PlayerPokemon).id, this.nature)), super(`${getNatureName(nature)} Mint`, `Changes a Pokémon\'s nature to ${getNatureName(nature, true, true, true)} and permanently unlocks the nature for the starter.`, ((_type, args) => new Modifiers.PokemonNatureChangeModifier(this, (args[0] as PlayerPokemon).id, this.nature)),
((pokemon: PlayerPokemon) => { ((pokemon: PlayerPokemon) => {
if (pokemon.getNature() === this.nature) if (pokemon.getNature() === this.nature)
return PartyUiHandler.NoEffectMessage; return PartyUiHandler.NoEffectMessage;

View File

@ -8,15 +8,14 @@ import { Stat } from "../data/pokemon-stat";
import { addTextObject, TextStyle } from "../ui/text"; import { addTextObject, TextStyle } from "../ui/text";
import { Type } from '../data/type'; import { Type } from '../data/type';
import { EvolutionPhase } from '../evolution-phase'; import { EvolutionPhase } from '../evolution-phase';
import { FusionSpeciesFormEvolution, pokemonEvolutions } from '../data/pokemon-evolutions'; import { FusionSpeciesFormEvolution, pokemonEvolutions, pokemonPrevolutions } from '../data/pokemon-evolutions';
import { getPokemonMessage } from '../messages'; import { getPokemonMessage } from '../messages';
import * as Utils from "../utils"; import * as Utils from "../utils";
import { TempBattleStat } from '../data/temp-battle-stat'; import { TempBattleStat } from '../data/temp-battle-stat';
import { BerryType, getBerryEffectFunc, getBerryPredicate } from '../data/berry'; import { BerryType, getBerryEffectFunc, getBerryPredicate } from '../data/berry';
import { StatusEffect, getStatusEffectHealText } from '../data/status-effect'; import { StatusEffect, getStatusEffectHealText } from '../data/status-effect';
import { MoneyAchv, achvs } from '../system/achv'; import { achvs } from '../system/achv';
import { VoucherType } from '../system/voucher'; import { VoucherType } from '../system/voucher';
import { PreventBerryUseAbAttr, applyAbAttrs } from '../data/ability';
import { FormChangeItem, SpeciesFormChangeItemTrigger } from '../data/pokemon-forms'; import { FormChangeItem, SpeciesFormChangeItemTrigger } from '../data/pokemon-forms';
import { Nature } from '#app/data/nature'; import { Nature } from '#app/data/nature';
import { BattlerTagType } from '#app/data/enums/battler-tag-type'; import { BattlerTagType } from '#app/data/enums/battler-tag-type';
@ -1090,6 +1089,13 @@ export class PokemonNatureChangeModifier extends ConsumablePokemonModifier {
apply(args: any[]): boolean { apply(args: any[]): boolean {
const pokemon = args[0] as Pokemon; const pokemon = args[0] as Pokemon;
pokemon.natureOverride = this.nature; pokemon.natureOverride = this.nature;
let speciesId = pokemon.species.speciesId;
pokemon.scene.gameData.dexData[speciesId].natureAttr |= Math.pow(2, this.nature + 1);
while (pokemonPrevolutions.hasOwnProperty(speciesId)) {
speciesId = pokemonPrevolutions[speciesId];
pokemon.scene.gameData.dexData[speciesId].natureAttr |= Math.pow(2, this.nature + 1);
}
return true; return true;
} }

View File

@ -12,12 +12,15 @@ export const STARTING_WAVE_OVERRIDE = 0;
export const STARTING_BIOME_OVERRIDE = Biome.TOWN; export const STARTING_BIOME_OVERRIDE = Biome.TOWN;
export const STARTING_MONEY_OVERRIDE = 0; export const STARTING_MONEY_OVERRIDE = 0;
export const WEATHER_OVERRIDE = WeatherType.NONE; export const WEATHER_OVERRIDE = WeatherType.NONE;
export const DOUBLE_BATTLE_OVERRIDE = false;
export const ABILITY_OVERRIDE = Abilities.NONE; export const ABILITY_OVERRIDE = Abilities.NONE;
export const PASSIVE_ABILITY_OVERRIDE = Abilities.NONE;
export const MOVE_OVERRIDE = Moves.NONE; export const MOVE_OVERRIDE = Moves.NONE;
export const MOVE_OVERRIDE_2 = Moves.NONE; export const MOVE_OVERRIDE_2 = Moves.NONE;
export const OPP_SPECIES_OVERRIDE = 0; export const OPP_SPECIES_OVERRIDE = 0;
export const OPP_ABILITY_OVERRIDE = Abilities.NONE; export const OPP_ABILITY_OVERRIDE = Abilities.NONE;
export const OPP_PASSIVE_ABILITY_OVERRIDE = Abilities.NONE;
export const OPP_MOVE_OVERRIDE = Moves.NONE; export const OPP_MOVE_OVERRIDE = Moves.NONE;
export const OPP_MOVE_OVERRIDE_2 = Moves.NONE; export const OPP_MOVE_OVERRIDE_2 = Moves.NONE;

View File

@ -1,4 +1,4 @@
import BattleScene, { bypassLogin, startingWave } from "./battle-scene"; import BattleScene, { AnySound, bypassLogin, startingWave } from "./battle-scene";
import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon"; import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon";
import * as Utils from './utils'; import * as Utils from './utils';
import { Moves } from "./data/enums/moves"; import { Moves } from "./data/enums/moves";
@ -55,7 +55,7 @@ import { OptionSelectConfig, OptionSelectItem } from "./ui/abstact-option-select
import { SaveSlotUiMode } from "./ui/save-slot-select-ui-handler"; import { SaveSlotUiMode } from "./ui/save-slot-select-ui-handler";
import { fetchDailyRunSeed, getDailyRunStarters } from "./data/daily-run"; import { fetchDailyRunSeed, getDailyRunStarters } from "./data/daily-run";
import { GameModes, gameModes } from "./game-mode"; import { GameModes, gameModes } from "./game-mode";
import { getPokemonSpecies, speciesStarters } from "./data/pokemon-species"; import PokemonSpecies, { getPokemonSpecies, getPokemonSpeciesForm, speciesStarters } from "./data/pokemon-species";
import i18next from './plugins/i18n'; import i18next from './plugins/i18n';
import { Abilities } from "./data/enums/abilities"; import { Abilities } from "./data/enums/abilities";
import { STARTER_FORM_OVERRIDE, STARTER_SPECIES_OVERRIDE } from './overrides'; import { STARTER_FORM_OVERRIDE, STARTER_SPECIES_OVERRIDE } from './overrides';
@ -3480,8 +3480,40 @@ export class GameOverModifierRewardPhase extends ModifierRewardPhase {
} }
} }
export class RibbonModifierRewardPhase extends ModifierRewardPhase {
private species: PokemonSpecies;
constructor(scene: BattleScene, modifierTypeFunc: ModifierTypeFunc, species: PokemonSpecies) {
super(scene, modifierTypeFunc);
this.species = species;
}
doReward(): Promise<void> {
return new Promise<void>(resolve => {
const newModifier = this.modifierType.newModifier();
this.scene.addModifier(newModifier).then(() => {
this.scene.gameData.saveSystem().then(success => {
if (success) {
this.scene.playSound('level_up_fanfare');
this.scene.ui.setMode(Mode.MESSAGE);
this.scene.arenaBg.setVisible(false);
this.scene.ui.fadeIn(250).then(() => {
this.scene.ui.showText(`${this.species.name} beat ${this.scene.gameMode.getName()} Mode for the first time!\nYou received ${newModifier.type.name}!`, null, () => {
resolve();
}, null, true, 1500);
});
} else
this.scene.reset(true);
});
});
})
}
}
export class GameOverPhase extends BattlePhase { export class GameOverPhase extends BattlePhase {
private victory: boolean; private victory: boolean;
private firstRibbons: PokemonSpecies[] = [];
constructor(scene: BattleScene, victory?: boolean) { constructor(scene: BattleScene, victory?: boolean) {
super(scene); super(scene);
@ -3533,6 +3565,13 @@ export class GameOverPhase extends BattlePhase {
if (this.scene.gameMode.isClassic) { if (this.scene.gameMode.isClassic) {
firstClear = this.scene.validateAchv(achvs.CLASSIC_VICTORY); firstClear = this.scene.validateAchv(achvs.CLASSIC_VICTORY);
this.scene.gameData.gameStats.sessionsWon++; this.scene.gameData.gameStats.sessionsWon++;
for (let pokemon of this.scene.getParty()) {
this.awardRibbon(pokemon);
if (pokemon.species.getRootSpeciesId() != pokemon.species.getRootSpeciesId(true)) {
this.awardRibbon(pokemon, true);
}
}
} else if (this.scene.gameMode.isDaily && success[1]) } else if (this.scene.gameMode.isDaily && success[1])
this.scene.gameData.gameStats.dailyRunSessionsWon++; this.scene.gameData.gameStats.dailyRunSessionsWon++;
} }
@ -3544,8 +3583,11 @@ export class GameOverPhase extends BattlePhase {
this.scene.clearPhaseQueue(); this.scene.clearPhaseQueue();
this.scene.ui.clearText(); this.scene.ui.clearText();
this.handleUnlocks(); this.handleUnlocks();
if (this.victory && !firstClear && success[1]) if (this.victory && !firstClear && success[1]) {
for (let species of this.firstRibbons)
this.scene.unshiftPhase(new RibbonModifierRewardPhase(this.scene, modifierTypes.VOUCHER_PLUS, species));
this.scene.unshiftPhase(new GameOverModifierRewardPhase(this.scene, modifierTypes.VOUCHER_PREMIUM)); this.scene.unshiftPhase(new GameOverModifierRewardPhase(this.scene, modifierTypes.VOUCHER_PREMIUM));
}
this.scene.reset(); this.scene.reset();
this.scene.unshiftPhase(new TitlePhase(this.scene)); this.scene.unshiftPhase(new TitlePhase(this.scene));
this.end(); this.end();
@ -3564,6 +3606,15 @@ export class GameOverPhase extends BattlePhase {
this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.MINI_BLACK_HOLE)); this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.MINI_BLACK_HOLE));
} }
} }
awardRibbon(pokemon: Pokemon, forStarter: boolean = false): void {
const speciesId = getPokemonSpecies(pokemon.species.speciesId)
const speciesRibbonCount = this.scene.gameData.incrementRibbonCount(speciesId, forStarter);
// first time classic win, award voucher
if (speciesRibbonCount === 1) {
this.firstRibbons.push(getPokemonSpecies(pokemon.species.getRootSpeciesId(forStarter)));
}
}
} }
export class UnlockPhase extends Phase { export class UnlockPhase extends Phase {

View File

@ -51,9 +51,9 @@ export class Achv {
} }
getTier(): AchvTier { getTier(): AchvTier {
if (this.score >= 150)
return AchvTier.MASTER;
if (this.score >= 100) if (this.score >= 100)
return AchvTier.MASTER;
if (this.score >= 75)
return AchvTier.ROGUE; return AchvTier.ROGUE;
if (this.score >= 50) if (this.score >= 50)
return AchvTier.ULTRA; return AchvTier.ULTRA;
@ -73,6 +73,16 @@ export class MoneyAchv extends Achv {
} }
} }
export class RibbonAchv extends Achv {
private ribbonAmount: integer;
constructor(name: string, ribbonAmount: integer, iconImage: string, score: integer) {
super(name, `Accumulate a total of ${ribbonAmount.toLocaleString('en-US')} Ribbons`, iconImage, score, (scene: BattleScene, _args: any[]) => scene.gameData.gameStats.ribbonsOwned >= this.ribbonAmount);
this.ribbonAmount = ribbonAmount;
}
}
export class DamageAchv extends Achv { export class DamageAchv extends Achv {
private damageAmount: integer; private damageAmount: integer;
@ -125,6 +135,11 @@ export const achvs = {
LV_100: new LevelAchv('But Wait, There\'s More!', 100, 'rare_candy', 25).setSecret(), LV_100: new LevelAchv('But Wait, There\'s More!', 100, 'rare_candy', 25).setSecret(),
LV_250: new LevelAchv('Elite', 250, 'rarer_candy', 50).setSecret(true), LV_250: new LevelAchv('Elite', 250, 'rarer_candy', 50).setSecret(true),
LV_1000: new LevelAchv('To Go Even Further Beyond', 1000, 'candy_jar', 100).setSecret(true), LV_1000: new LevelAchv('To Go Even Further Beyond', 1000, 'candy_jar', 100).setSecret(true),
_10_RIBBONS: new RibbonAchv('Pokémon League Champion', 10, 'bronze_ribbon', 10),
_25_RIBBONS: new RibbonAchv('Great League Champion', 25, 'great_ribbon', 25).setSecret(true),
_50_RIBBONS: new RibbonAchv('Ultra League Champion', 50, 'ultra_ribbon', 50).setSecret(true),
_75_RIBBONS: new RibbonAchv('Rogue League Champion', 75, 'rogue_ribbon', 75).setSecret(true),
_100_RIBBONS: new RibbonAchv('Master League Champion', 100, 'master_ribbon', 100).setSecret(true),
TRANSFER_MAX_BATTLE_STAT: new Achv('Teamwork', 'Baton pass to another party member with at least one stat maxed out', 'stick', 20), TRANSFER_MAX_BATTLE_STAT: new Achv('Teamwork', 'Baton pass to another party member with at least one stat maxed out', 'stick', 20),
MAX_FRIENDSHIP: new Achv('Friendmaxxing', 'Reach max friendship on a Pokémon', 'soothe_bell', 25), MAX_FRIENDSHIP: new Achv('Friendmaxxing', 'Reach max friendship on a Pokémon', 'soothe_bell', 25),
MEGA_EVOLVE: new Achv('Megamorph', 'Mega evolve a Pokémon', 'mega_bracelet', 50), MEGA_EVOLVE: new Achv('Megamorph', 'Mega evolve a Pokémon', 'mega_bracelet', 50),

View File

@ -173,6 +173,7 @@ export interface StarterDataEntry {
abilityAttr: integer; abilityAttr: integer;
passiveAttr: integer; passiveAttr: integer;
valueReduction: integer; valueReduction: integer;
classicWinCount: integer;
} }
export interface StarterData { export interface StarterData {
@ -194,7 +195,8 @@ const systemShortKeys = {
eggMoves: '$em', eggMoves: '$em',
candyCount: '$x', candyCount: '$x',
passive: '$p', passive: '$p',
valueReduction: '$vr' valueReduction: '$vr',
classicWinCount: '$wc'
}; };
export class GameData { export class GameData {
@ -995,7 +997,8 @@ export class GameData {
friendship: 0, friendship: 0,
abilityAttr: defaultStarterSpecies.includes(speciesId) ? AbilityAttr.ABILITY_1 : 0, abilityAttr: defaultStarterSpecies.includes(speciesId) ? AbilityAttr.ABILITY_1 : 0,
passiveAttr: 0, passiveAttr: 0,
valueReduction: 0 valueReduction: 0,
classicWinCount: 0
}; };
} }
@ -1089,6 +1092,32 @@ export class GameData {
}); });
} }
incrementRibbonCount(species: PokemonSpecies, forStarter: boolean = false): integer {
const speciesIdToIncrement: Species = species.getRootSpeciesId(forStarter);
if (!this.starterData[speciesIdToIncrement].classicWinCount) {
this.starterData[speciesIdToIncrement].classicWinCount = 0;
}
if (!this.starterData[speciesIdToIncrement].classicWinCount)
this.scene.gameData.gameStats.ribbonsOwned++;
const ribbonsInStats: integer = this.scene.gameData.gameStats.ribbonsOwned;
if (ribbonsInStats >= 100)
this.scene.validateAchv(achvs._100_RIBBONS);
if (ribbonsInStats >= 75)
this.scene.validateAchv(achvs._75_RIBBONS);
if (ribbonsInStats >= 50)
this.scene.validateAchv(achvs._50_RIBBONS);
if (ribbonsInStats >= 25)
this.scene.validateAchv(achvs._25_RIBBONS);
if (ribbonsInStats >= 10)
this.scene.validateAchv(achvs._10_RIBBONS);
return ++this.starterData[speciesIdToIncrement].classicWinCount;
}
addStarterCandy(species: PokemonSpecies, count: integer): void { addStarterCandy(species: PokemonSpecies, count: integer): void {
this.scene.candyBar.showStarterSpeciesCandy(species.speciesId, count); this.scene.candyBar.showStarterSpeciesCandy(species.speciesId, count);
this.starterData[species.speciesId].candyCount += count; this.starterData[species.speciesId].candyCount += count;

View File

@ -6,6 +6,7 @@ export class GameStats {
public battles: integer; public battles: integer;
public classicSessionsPlayed: integer; public classicSessionsPlayed: integer;
public sessionsWon: integer; public sessionsWon: integer;
public ribbonsOwned: integer;
public dailyRunSessionsPlayed: integer; public dailyRunSessionsPlayed: integer;
public dailyRunSessionsWon: integer; public dailyRunSessionsWon: integer;
public endlessSessionsPlayed: integer; public endlessSessionsPlayed: integer;
@ -43,6 +44,7 @@ export class GameStats {
this.battles = source?.battles || 0; this.battles = source?.battles || 0;
this.classicSessionsPlayed = source?.classicSessionsPlayed || 0; this.classicSessionsPlayed = source?.classicSessionsPlayed || 0;
this.sessionsWon = source?.sessionsWon || 0; this.sessionsWon = source?.sessionsWon || 0;
this.ribbonsOwned = source?.ribbonsOwned || 0;
this.dailyRunSessionsPlayed = source?.dailyRunSessionsPlayed || 0; this.dailyRunSessionsPlayed = source?.dailyRunSessionsPlayed || 0;
this.dailyRunSessionsWon = source?.dailyRunSessionsWon || 0; this.dailyRunSessionsWon = source?.dailyRunSessionsWon || 0;
this.endlessSessionsPlayed = source?.endlessSessionsPlayed || 0; this.endlessSessionsPlayed = source?.endlessSessionsPlayed || 0;

View File

@ -51,6 +51,7 @@ const displayStats: DisplayStats = {
return `${caughtCount} (${Math.floor((caughtCount / Object.keys(gameData.dexData).length) * 1000) / 10}%)`; return `${caughtCount} (${Math.floor((caughtCount / Object.keys(gameData.dexData).length) * 1000) / 10}%)`;
} }
}, },
ribbonsOwned: 'Ribbons Owned',
classicSessionsPlayed: 'Classic Runs', classicSessionsPlayed: 'Classic Runs',
sessionsWon: 'Classic Wins', sessionsWon: 'Classic Wins',
dailyRunSessionsPlayed: 'Daily Run Attempts', dailyRunSessionsPlayed: 'Daily Run Attempts',

View File

@ -174,6 +174,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
private starterValueLabels: Phaser.GameObjects.Text[]; private starterValueLabels: Phaser.GameObjects.Text[];
private shinyIcons: Phaser.GameObjects.Image[][]; private shinyIcons: Phaser.GameObjects.Image[][];
private hiddenAbilityIcons: Phaser.GameObjects.Image[]; private hiddenAbilityIcons: Phaser.GameObjects.Image[];
private classicWinIcons: Phaser.GameObjects.Image[];
private iconAnimHandler: PokemonIconAnimHandler; private iconAnimHandler: PokemonIconAnimHandler;
@ -410,6 +411,17 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
return ret; return ret;
}); });
this.classicWinIcons = new Array(81).fill(null).map((_, i) => {
const x = (i % 9) * 18;
const y = Math.floor(i / 9) * 18;
const ret = this.scene.add.image(x + 152, y + 16, 'champion_ribbon');
ret.setOrigin(0, 0);
ret.setScale(0.5);
ret.setVisible(false);
this.starterSelectContainer.add(ret);
return ret;
});
this.pokemonSprite = this.scene.add.sprite(53, 63, `pkmn__sub`); this.pokemonSprite = this.scene.add.sprite(53, 63, `pkmn__sub`);
this.pokemonSprite.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true }); this.pokemonSprite.setPipeline(this.scene.spritePipeline, { tone: [ 0.0, 0.0, 0.0, 0.0 ], ignoreTimeTint: true });
this.starterSelectContainer.add(this.pokemonSprite); this.starterSelectContainer.add(this.pokemonSprite);
@ -1192,6 +1204,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.shinyIcons[s][v].setTint(getVariantTint(speciesVariants[v] === DexAttr.DEFAULT_VARIANT ? 0 : speciesVariants[v] === DexAttr.VARIANT_2 ? 1 : 2)); this.shinyIcons[s][v].setTint(getVariantTint(speciesVariants[v] === DexAttr.DEFAULT_VARIANT ? 0 : speciesVariants[v] === DexAttr.VARIANT_2 ? 1 : 2));
} }
this.hiddenAbilityIcons[s].setVisible(slotVisible && !!this.scene.gameData.dexData[speciesId].caughtAttr && !!(this.scene.gameData.starterData[speciesId].abilityAttr & 4)); this.hiddenAbilityIcons[s].setVisible(slotVisible && !!this.scene.gameData.dexData[speciesId].caughtAttr && !!(this.scene.gameData.starterData[speciesId].abilityAttr & 4));
this.classicWinIcons[s].setVisible(slotVisible && this.scene.gameData.starterData[speciesId].classicWinCount > 0);
} }
} else { } else {
changed = super.setCursor(cursor); changed = super.setCursor(cursor);