mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-13 20:02:19 +02:00
Compare commits
18 Commits
e37b278b4f
...
d34e0dd2c6
Author | SHA1 | Date | |
---|---|---|---|
|
d34e0dd2c6 | ||
|
47d39388ac | ||
|
4d15269eec | ||
|
899a2bf96e | ||
|
0385a90f08 | ||
|
a163a420bd | ||
|
d7146bb1c1 | ||
|
fccd546415 | ||
|
5afe32a1e2 | ||
|
1420c26f22 | ||
|
4695d0617d | ||
|
91013cf8c4 | ||
|
8824082ceb | ||
|
f4acf8bfc3 | ||
|
dc8672b2bd | ||
|
7e003d68a9 | ||
|
9893c21a7e | ||
|
e7cef039c3 |
@ -26,7 +26,7 @@ We're using ESLint as our common linter and formatter. It will run automatically
|
||||
|
||||
|
||||
## 🪧 To Do
|
||||
Check out our [Trello Board](https://trello.com/b/z10B703R/pokerogue-board) to see what we're working on
|
||||
Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to see how can you help us!
|
||||
|
||||
# 📝 Credits
|
||||
> If this project contains assets you have produced and you do not see your name here, **please** reach out.
|
||||
|
2
package-lock.json
generated
2
package-lock.json
generated
@ -38,7 +38,7 @@
|
||||
"vitest-canvas-mock": "^0.3.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
"node": ">=20.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ampproject/remapping": {
|
||||
|
@ -146,14 +146,14 @@
|
||||
"spriteSourceSize": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"w": 3,
|
||||
"h": 3
|
||||
"w": 66,
|
||||
"h": 55
|
||||
},
|
||||
"frame": {
|
||||
"x": 132,
|
||||
"y": 0,
|
||||
"w": 3,
|
||||
"h": 3
|
||||
"x": 0,
|
||||
"y": 112,
|
||||
"w": 66,
|
||||
"h": 55
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -2,6 +2,12 @@ import Move from "./data/move";
|
||||
|
||||
/** Alias for all {@linkcode BattleScene} events */
|
||||
export enum BattleSceneEventType {
|
||||
/**
|
||||
* Triggers when the corresponding setting is changed
|
||||
* @see {@linkcode CandyUpgradeNotificationChangedEvent}
|
||||
*/
|
||||
CANDY_UPGRADE_NOTIFICATION_CHANGED = "onCandyUpgradeDisplayChanged",
|
||||
|
||||
/**
|
||||
* Triggers when a move is successfully used
|
||||
* @see {@linkcode MoveUsedEvent}
|
||||
@ -24,6 +30,20 @@ export enum BattleSceneEventType {
|
||||
NEW_ARENA = "onNewArena",
|
||||
}
|
||||
|
||||
/**
|
||||
* Container class for {@linkcode BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED} events
|
||||
* @extends Event
|
||||
*/
|
||||
export class CandyUpgradeNotificationChangedEvent extends Event {
|
||||
/** The new value the setting was changed to */
|
||||
public newValue: number;
|
||||
constructor(newValue: number) {
|
||||
super(BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED);
|
||||
|
||||
this.newValue = newValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Container class for {@linkcode BattleSceneEventType.MOVE_USED} events
|
||||
* @extends Event
|
||||
|
@ -93,6 +93,19 @@ export default class BattleScene extends SceneBase {
|
||||
public showLevelUpStats: boolean = true;
|
||||
public enableTutorials: boolean = import.meta.env.VITE_BYPASS_TUTORIAL === "1";
|
||||
public enableRetries: boolean = false;
|
||||
/**
|
||||
* Determines the condition for a notification should be shown for Candy Upgrades
|
||||
* - 0 = 'Off'
|
||||
* - 1 = 'Passives Only'
|
||||
* - 2 = 'On'
|
||||
*/
|
||||
public candyUpgradeNotification: integer = 0;
|
||||
/**
|
||||
* Determines what type of notification is used for Candy Upgrades
|
||||
* - 0 = 'Icon'
|
||||
* - 1 = 'Animation'
|
||||
*/
|
||||
public candyUpgradeDisplay: integer = 0;
|
||||
public moneyFormat: MoneyFormat = MoneyFormat.NORMAL;
|
||||
public uiTheme: UiTheme = UiTheme.DEFAULT;
|
||||
public windowType: integer = 0;
|
||||
|
@ -1573,18 +1573,41 @@ export class PostSummonClearAllyStatsAbAttr extends PostSummonAbAttr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Download raises either the Attack stat or Special Attack stat by one stage depending on the foe's currently lowest defensive stat:
|
||||
* it will raise Attack if the foe's current Defense is lower than its current Special Defense stat;
|
||||
* otherwise, it will raise Special Attack.
|
||||
* @extends PostSummonAbAttr
|
||||
* @see {applyPostSummon}
|
||||
*/
|
||||
export class DownloadAbAttr extends PostSummonAbAttr {
|
||||
private enemyDef: integer;
|
||||
private enemySpDef: integer;
|
||||
private enemyCountTally: integer;
|
||||
private stats: BattleStat[];
|
||||
|
||||
// TODO: Implement the Substitute feature(s) once move is implemented.
|
||||
/**
|
||||
* Checks to see if it is the opening turn (starting a new game), if so, Download won't work. This is because Download takes into account
|
||||
* vitamins and items, so it needs to use the BattleStat and the stat alone.
|
||||
* @param {Pokemon} pokemon Pokemon that is using the move, as well as seeing the opposing pokemon.
|
||||
* @param {boolean} passive N/A
|
||||
* @param {any[]} args N/A
|
||||
* @returns Returns true if ability is used successful, false if not.
|
||||
*/
|
||||
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
|
||||
this.enemyDef = 0;
|
||||
this.enemySpDef = 0;
|
||||
this.enemyCountTally = 0;
|
||||
|
||||
for (const opponent of pokemon.getOpponents()) {
|
||||
this.enemyDef += opponent.stats[BattleStat.DEF];
|
||||
this.enemySpDef += opponent.stats[BattleStat.SPDEF];
|
||||
if (pokemon.getOpponents()[0].summonData !== undefined) {
|
||||
for (const opponent of pokemon.getOpponents()) {
|
||||
this.enemyCountTally++;
|
||||
this.enemyDef += opponent.getBattleStat(Stat.DEF);
|
||||
this.enemySpDef += opponent.getBattleStat(Stat.SPDEF);
|
||||
}
|
||||
this.enemyDef = Math.round(this.enemyDef / this.enemyCountTally);
|
||||
this.enemySpDef = Math.round(this.enemySpDef / this.enemyCountTally);
|
||||
}
|
||||
|
||||
if (this.enemyDef < this.enemySpDef) {
|
||||
@ -2662,6 +2685,38 @@ export class PreventBerryUseAbAttr extends AbAttr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A Pokemon with this ability heals by a percentage of their maximum hp after eating a berry
|
||||
* @param healPercent - Percent of Max HP to heal
|
||||
* @see {@linkcode apply()} for implementation
|
||||
*/
|
||||
export class HealFromBerryUseAbAttr extends AbAttr {
|
||||
/** Percent of Max HP to heal */
|
||||
private healPercent: number;
|
||||
|
||||
constructor(healPercent: number) {
|
||||
super();
|
||||
|
||||
// Clamp healPercent so its between [0,1].
|
||||
this.healPercent = Math.max(Math.min(healPercent, 1), 0);
|
||||
}
|
||||
|
||||
apply(pokemon: Pokemon, passive: boolean, ...args: [Utils.BooleanHolder, any[]]): boolean {
|
||||
const { name: abilityName } = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
|
||||
pokemon.scene.unshiftPhase(
|
||||
new PokemonHealPhase(
|
||||
pokemon.scene,
|
||||
pokemon.getBattlerIndex(),
|
||||
Math.max(Math.floor(pokemon.getMaxHp() * this.healPercent), 1),
|
||||
getPokemonMessage(pokemon, `'s ${abilityName}\nrestored its HP!`),
|
||||
true
|
||||
)
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class RunSuccessAbAttr extends AbAttr {
|
||||
apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean {
|
||||
(args[0] as Utils.IntegerHolder).value = 256;
|
||||
@ -3308,9 +3363,11 @@ export function initAbilities() {
|
||||
.bypassFaint(),
|
||||
new Ability(Abilities.VOLT_ABSORB, 3)
|
||||
.attr(TypeImmunityHealAbAttr, Type.ELECTRIC)
|
||||
.partial() // Healing not blocked by Heal Block
|
||||
.ignorable(),
|
||||
new Ability(Abilities.WATER_ABSORB, 3)
|
||||
.attr(TypeImmunityHealAbAttr, Type.WATER)
|
||||
.partial() // Healing not blocked by Heal Block
|
||||
.ignorable(),
|
||||
new Ability(Abilities.OBLIVIOUS, 3)
|
||||
.attr(BattlerTagImmunityAbAttr, BattlerTagType.INFATUATED)
|
||||
@ -3409,7 +3466,8 @@ export function initAbilities() {
|
||||
.attr(MoveImmunityAbAttr, (pokemon, attacker, move) => pokemon !== attacker && move.getMove().hasFlag(MoveFlags.SOUND_BASED))
|
||||
.ignorable(),
|
||||
new Ability(Abilities.RAIN_DISH, 3)
|
||||
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.RAIN, WeatherType.HEAVY_RAIN),
|
||||
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.RAIN, WeatherType.HEAVY_RAIN)
|
||||
.partial(), // Healing not blocked by Heal Block
|
||||
new Ability(Abilities.SAND_STREAM, 3)
|
||||
.attr(PostSummonWeatherChangeAbAttr, WeatherType.SANDSTORM)
|
||||
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SANDSTORM),
|
||||
@ -3530,6 +3588,7 @@ export function initAbilities() {
|
||||
.attr(PostWeatherLapseHealAbAttr, 2, WeatherType.RAIN, WeatherType.HEAVY_RAIN)
|
||||
.attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 1.25)
|
||||
.attr(TypeImmunityHealAbAttr, Type.WATER)
|
||||
.partial() // Healing not blocked by Heal Block
|
||||
.ignorable(),
|
||||
new Ability(Abilities.DOWNLOAD, 4)
|
||||
.attr(DownloadAbAttr),
|
||||
@ -3607,7 +3666,8 @@ export function initAbilities() {
|
||||
.ignorable(),
|
||||
new Ability(Abilities.ICE_BODY, 4)
|
||||
.attr(BlockWeatherDamageAttr, WeatherType.HAIL)
|
||||
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.HAIL, WeatherType.SNOW),
|
||||
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.HAIL, WeatherType.SNOW)
|
||||
.partial(), // Healing not blocked by Heal Block
|
||||
new Ability(Abilities.SOLID_ROCK, 4)
|
||||
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75)
|
||||
.ignorable(),
|
||||
@ -3768,7 +3828,8 @@ export function initAbilities() {
|
||||
.ignorable()
|
||||
.unimplemented(),
|
||||
new Ability(Abilities.CHEEK_POUCH, 6)
|
||||
.unimplemented(),
|
||||
.attr(HealFromBerryUseAbAttr, 1/3)
|
||||
.partial(), // Healing not blocked by Heal Block
|
||||
new Ability(Abilities.PROTEAN, 6)
|
||||
.unimplemented(),
|
||||
new Ability(Abilities.FUR_COAT, 6)
|
||||
@ -4201,6 +4262,7 @@ export function initAbilities() {
|
||||
.ignorable(),
|
||||
new Ability(Abilities.EARTH_EATER, 9)
|
||||
.attr(TypeImmunityHealAbAttr, Type.GROUND)
|
||||
.partial() // Healing not blocked by Heal Block
|
||||
.ignorable(),
|
||||
new Ability(Abilities.MYCELIUM_MIGHT, 9)
|
||||
.attr(MoveAbilityBypassAbAttr, (pokemon, move: Move) => move.category === MoveCategory.STATUS)
|
||||
@ -4214,7 +4276,8 @@ export function initAbilities() {
|
||||
.attr(PostSummonStatChangeAbAttr, BattleStat.EVA, -1)
|
||||
.condition(getOncePerBattleCondition(Abilities.SUPERSWEET_SYRUP)),
|
||||
new Ability(Abilities.HOSPITALITY, 9)
|
||||
.attr(PostSummonAllyHealAbAttr, 4, true),
|
||||
.attr(PostSummonAllyHealAbAttr, 4, true)
|
||||
.partial(), // Healing not blocked by Heal Block
|
||||
new Ability(Abilities.TOXIC_CHAIN, 9)
|
||||
.attr(PostAttackApplyStatusEffectAbAttr, false, 30, StatusEffect.TOXIC),
|
||||
new Ability(Abilities.EMBODY_ASPECT_TEAL, 9)
|
||||
|
@ -9,14 +9,14 @@ export interface TrainerTypeMessages {
|
||||
}
|
||||
|
||||
export interface TrainerTypeDialogue {
|
||||
[key: integer]: TrainerTypeMessages | [TrainerTypeMessages, TrainerTypeMessages]
|
||||
[key: integer]: TrainerTypeMessages | Array<TrainerTypeMessages>
|
||||
}
|
||||
|
||||
export function getTrainerTypeDialogue(): TrainerTypeDialogue {
|
||||
return trainerTypeDialogue;
|
||||
}
|
||||
|
||||
export const trainerTypeDialogue = {
|
||||
export const trainerTypeDialogue: TrainerTypeDialogue = {
|
||||
[TrainerType.YOUNGSTER]: [
|
||||
{
|
||||
encounter: [
|
||||
|
109
src/data/move.ts
109
src/data/move.ts
@ -12,7 +12,7 @@ import * as Utils from "../utils";
|
||||
import { WeatherType } from "./weather";
|
||||
import { ArenaTagSide, ArenaTrapTag } from "./arena-tag";
|
||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr } from "./ability";
|
||||
import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr, HealFromBerryUseAbAttr } from "./ability";
|
||||
import { Abilities } from "./enums/abilities";
|
||||
import { allAbilities } from "./ability";
|
||||
import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier } from "../modifier/modifier";
|
||||
@ -86,6 +86,10 @@ export enum MoveFlags {
|
||||
WIND_MOVE = 1 << 14,
|
||||
TRIAGE_MOVE = 1 << 15,
|
||||
IGNORE_ABILITIES = 1 << 16,
|
||||
/**
|
||||
* Enables all hits of a multi-hit move to be accuracy checked individually
|
||||
*/
|
||||
CHECK_ALL_HITS = 1 << 17,
|
||||
}
|
||||
|
||||
type MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => boolean;
|
||||
@ -346,6 +350,11 @@ export default class Move implements Localizable {
|
||||
return this;
|
||||
}
|
||||
|
||||
checkAllHits(checkAllHits?: boolean): this {
|
||||
this.setFlag(MoveFlags.CHECK_ALL_HITS, checkAllHits);
|
||||
return this;
|
||||
}
|
||||
|
||||
checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon): boolean {
|
||||
switch (flag) {
|
||||
case MoveFlags.MAKES_CONTACT:
|
||||
@ -955,8 +964,7 @@ export enum MultiHitType {
|
||||
_2,
|
||||
_2_TO_5,
|
||||
_3,
|
||||
_3_INCR,
|
||||
_1_TO_10,
|
||||
_10,
|
||||
BEAT_UP,
|
||||
}
|
||||
|
||||
@ -1287,37 +1295,8 @@ export class MultiHitAttr extends MoveAttr {
|
||||
case MultiHitType._3:
|
||||
hitTimes = 3;
|
||||
break;
|
||||
case MultiHitType._3_INCR:
|
||||
hitTimes = 3;
|
||||
// TODO: Add power increase for every hit
|
||||
break;
|
||||
case MultiHitType._1_TO_10:
|
||||
{
|
||||
const rand = user.randSeedInt(90);
|
||||
const hitValue = new Utils.IntegerHolder(rand);
|
||||
applyAbAttrs(MaxMultiHitAbAttr, user, null, hitValue);
|
||||
if (hitValue.value >= 81) {
|
||||
hitTimes = 1;
|
||||
} else if (hitValue.value >= 73) {
|
||||
hitTimes = 2;
|
||||
} else if (hitValue.value >= 66) {
|
||||
hitTimes = 3;
|
||||
} else if (hitValue.value >= 60) {
|
||||
hitTimes = 4;
|
||||
} else if (hitValue.value >= 54) {
|
||||
hitTimes = 5;
|
||||
} else if (hitValue.value >= 49) {
|
||||
hitTimes = 6;
|
||||
} else if (hitValue.value >= 44) {
|
||||
hitTimes = 7;
|
||||
} else if (hitValue.value >= 40) {
|
||||
hitTimes = 8;
|
||||
} else if (hitValue.value >= 36) {
|
||||
hitTimes = 9;
|
||||
} else {
|
||||
hitTimes = 10;
|
||||
}
|
||||
}
|
||||
case MultiHitType._10:
|
||||
hitTimes = 10;
|
||||
break;
|
||||
case MultiHitType.BEAT_UP:
|
||||
const party = user.isPlayer() ? user.scene.getParty() : user.scene.getEnemyParty();
|
||||
@ -1577,8 +1556,11 @@ export class EatBerryAttr extends MoveEffectAttr {
|
||||
}
|
||||
target.scene.updateModifiers(target.isPlayer());
|
||||
}
|
||||
|
||||
this.chosenBerry = undefined;
|
||||
|
||||
applyAbAttrs(HealFromBerryUseAbAttr, target, new Utils.BooleanHolder(false));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2748,6 +2730,43 @@ export class WaterShurikenPowerAttr extends VariablePowerAttr {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Attribute used for multi-hit moves that increase power in increments of the
|
||||
* move's base power for each hit, namely Triple Kick and Triple Axel.
|
||||
* @extends VariablePowerAttr
|
||||
* @see {@linkcode apply}
|
||||
*/
|
||||
export class MultiHitPowerIncrementAttr extends VariablePowerAttr {
|
||||
/** The max number of base power increments allowed for this move */
|
||||
private maxHits: integer;
|
||||
|
||||
constructor(maxHits: integer) {
|
||||
super();
|
||||
|
||||
this.maxHits = maxHits;
|
||||
}
|
||||
|
||||
/**
|
||||
* Increases power of move in increments of the base power for the amount of times
|
||||
* the move hit. In the case that the move is extended, it will circle back to the
|
||||
* original base power of the move after incrementing past the maximum amount of
|
||||
* hits.
|
||||
* @param user {@linkcode Pokemon} that used the move
|
||||
* @param target {@linkcode Pokemon} that the move was used on
|
||||
* @param move {@linkcode Move} with this attribute
|
||||
* @param args [0] {@linkcode Utils.NumberHolder} for final calculated power of move
|
||||
* @returns true if attribute application succeeds
|
||||
*/
|
||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||
const hitsTotal = user.turnData.hitCount - Math.max(user.turnData.hitsLeft, 0);
|
||||
const power = args[0] as Utils.NumberHolder;
|
||||
|
||||
power.value = move.power * (1 + hitsTotal % this.maxHits);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export class VariableAtkAttr extends MoveAttr {
|
||||
constructor() {
|
||||
super();
|
||||
@ -5408,12 +5427,9 @@ export function initMoves() {
|
||||
.attr(SketchAttr)
|
||||
.ignoresVirtual(),
|
||||
new AttackMove(Moves.TRIPLE_KICK, Type.FIGHTING, MoveCategory.PHYSICAL, 10, 90, 10, -1, 0, 2)
|
||||
.attr(MultiHitAttr, MultiHitType._3_INCR)
|
||||
.attr(MissEffectAttr, (user: Pokemon, move: Move) => {
|
||||
user.turnData.hitsLeft = 1;
|
||||
return true;
|
||||
})
|
||||
.partial(),
|
||||
.attr(MultiHitAttr, MultiHitType._3)
|
||||
.attr(MultiHitPowerIncrementAttr, 3)
|
||||
.checkAllHits(),
|
||||
new AttackMove(Moves.THIEF, Type.DARK, MoveCategory.PHYSICAL, 60, 100, 25, -1, 0, 2)
|
||||
.attr(StealHeldItemChanceAttr, 0.3),
|
||||
new StatusMove(Moves.SPIDER_WEB, Type.BUG, -1, 10, -1, 0, 2)
|
||||
@ -7265,12 +7281,9 @@ export function initMoves() {
|
||||
new AttackMove(Moves.FLIP_TURN, Type.WATER, MoveCategory.PHYSICAL, 60, 100, 20, -1, 0, 8)
|
||||
.attr(ForceSwitchOutAttr, true, false),
|
||||
new AttackMove(Moves.TRIPLE_AXEL, Type.ICE, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 8)
|
||||
.attr(MultiHitAttr, MultiHitType._3_INCR)
|
||||
.attr(MissEffectAttr, (user: Pokemon, move: Move) => {
|
||||
user.turnData.hitsLeft = 1;
|
||||
return true;
|
||||
})
|
||||
.partial(),
|
||||
.attr(MultiHitAttr, MultiHitType._3)
|
||||
.attr(MultiHitPowerIncrementAttr, 3)
|
||||
.checkAllHits(),
|
||||
new AttackMove(Moves.DUAL_WINGBEAT, Type.FLYING, MoveCategory.PHYSICAL, 40, 90, 10, -1, 0, 8)
|
||||
.attr(MultiHitAttr, MultiHitType._2),
|
||||
new AttackMove(Moves.SCORCHING_SANDS, Type.GROUND, MoveCategory.SPECIAL, 70, 100, 10, 30, 0, 8)
|
||||
@ -7513,9 +7526,9 @@ export function initMoves() {
|
||||
new AttackMove(Moves.SPIN_OUT, Type.STEEL, MoveCategory.PHYSICAL, 100, 100, 5, 100, 0, 9)
|
||||
.attr(StatChangeAttr, BattleStat.SPD, -2, true),
|
||||
new AttackMove(Moves.POPULATION_BOMB, Type.NORMAL, MoveCategory.PHYSICAL, 20, 90, 10, -1, 0, 9)
|
||||
.attr(MultiHitAttr, MultiHitType._1_TO_10)
|
||||
.attr(MultiHitAttr, MultiHitType._10)
|
||||
.slicingMove()
|
||||
.partial(),
|
||||
.checkAllHits(),
|
||||
new AttackMove(Moves.ICE_SPINNER, Type.ICE, MoveCategory.PHYSICAL, 80, 100, 15, -1, 0, 9)
|
||||
.attr(ClearTerrainAttr),
|
||||
new AttackMove(Moves.GLAIVE_RUSH, Type.DRAGON, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 9)
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { Gender } from "./gender";
|
||||
import { FlinchChanceModifier } from "../modifier/modifier";
|
||||
import { Moves } from "./enums/moves";
|
||||
import { PokeballType } from "./pokeball";
|
||||
import Pokemon from "../field/pokemon";
|
||||
@ -216,7 +215,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
||||
],
|
||||
[Species.SLOWPOKE]: [
|
||||
new SpeciesEvolution(Species.SLOWBRO, 37, null, null),
|
||||
new SpeciesEvolution(Species.SLOWKING, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => !!p.scene.findModifier(m => (m instanceof FlinchChanceModifier) && (m as FlinchChanceModifier).pokemonId === p.id, true)), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.SLOWKING, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => true /* King's Rock */), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.MAGNEMITE]: [
|
||||
new SpeciesEvolution(Species.MAGNETON, 30, null, null)
|
||||
@ -1244,7 +1243,7 @@ export const pokemonEvolutions: PokemonEvolutions = {
|
||||
],
|
||||
[Species.POLIWHIRL]: [
|
||||
new SpeciesEvolution(Species.POLIWRATH, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG),
|
||||
new SpeciesEvolution(Species.POLITOED, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => !!p.scene.findModifier(m => (m instanceof FlinchChanceModifier) && (m as FlinchChanceModifier).pokemonId === p.id, true)), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
new SpeciesEvolution(Species.POLITOED, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition(p => true /* King's Rock */), SpeciesWildEvolutionDelay.VERY_LONG)
|
||||
],
|
||||
[Species.WEEPINBELL]: [
|
||||
new SpeciesEvolution(Species.VICTREEBEL, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG)
|
||||
|
@ -1,4 +1,4 @@
|
||||
import Phaser, {Time} from "phaser";
|
||||
import Phaser from "phaser";
|
||||
import * as Utils from "./utils";
|
||||
import {initTouchControls} from "./touch-controls";
|
||||
import pad_generic from "./configs/pad_generic";
|
||||
@ -6,6 +6,7 @@ import pad_unlicensedSNES from "./configs/pad_unlicensedSNES";
|
||||
import pad_xbox360 from "./configs/pad_xbox360";
|
||||
import pad_dualshock from "./configs/pad_dualshock";
|
||||
import {Button} from "./enums/buttons";
|
||||
import BattleScene from "./battle-scene";
|
||||
|
||||
export interface GamepadMapping {
|
||||
[key: string]: number;
|
||||
@ -47,16 +48,17 @@ const repeatInputDelayMillis = 250;
|
||||
*/
|
||||
export class InputsController {
|
||||
private buttonKeys: Phaser.Input.Keyboard.Key[][];
|
||||
private gamepads: Array<string> = new Array();
|
||||
private scene: Phaser.Scene;
|
||||
private gamepads: Phaser.Input.Gamepad.Gamepad[] = new Array();
|
||||
private scene: BattleScene;
|
||||
|
||||
private buttonLock: Button;
|
||||
private buttonLock2: Button;
|
||||
private interactions: Map<Button, Map<string, boolean>> = new Map();
|
||||
private time: Time;
|
||||
private player: Map<String, GamepadMapping> = new Map();
|
||||
private time: Phaser.Time.Clock;
|
||||
private player: GamepadMapping;
|
||||
|
||||
private gamepadSupport: boolean = true;
|
||||
public events: Phaser.Events.EventEmitter;
|
||||
|
||||
/**
|
||||
* Initializes a new instance of the game control system, setting up initial state and configurations.
|
||||
@ -69,7 +71,7 @@ export class InputsController {
|
||||
* Specific buttons like MENU and STATS are set not to repeat their actions.
|
||||
* It concludes by calling the `init` method to complete the setup.
|
||||
*/
|
||||
constructor(scene: Phaser.Scene) {
|
||||
constructor(scene: BattleScene) {
|
||||
this.scene = scene;
|
||||
this.time = this.scene.time;
|
||||
this.buttonKeys = [];
|
||||
@ -108,7 +110,6 @@ export class InputsController {
|
||||
}, this);
|
||||
|
||||
// Check to see if the gamepad has already been setup by the browser
|
||||
this.scene.input.gamepad.refreshPads();
|
||||
if (this.scene.input.gamepad.total) {
|
||||
this.refreshGamepads();
|
||||
for (const thisGamepad of this.gamepads) {
|
||||
@ -201,7 +202,7 @@ export class InputsController {
|
||||
setupGamepad(thisGamepad: Phaser.Input.Gamepad.Gamepad): void {
|
||||
const gamepadID = thisGamepad.id.toLowerCase();
|
||||
const mappedPad = this.mapGamepad(gamepadID);
|
||||
this.player["mapping"] = mappedPad.gamepadMapping;
|
||||
this.player = mappedPad.gamepadMapping;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -236,26 +237,26 @@ export class InputsController {
|
||||
*/
|
||||
getActionGamepadMapping(): ActionGamepadMapping {
|
||||
const gamepadMapping = {};
|
||||
if (!this.player?.mapping) {
|
||||
if (!this?.player) {
|
||||
return gamepadMapping;
|
||||
}
|
||||
gamepadMapping[this.player.mapping.LC_N] = Button.UP;
|
||||
gamepadMapping[this.player.mapping.LC_S] = Button.DOWN;
|
||||
gamepadMapping[this.player.mapping.LC_W] = Button.LEFT;
|
||||
gamepadMapping[this.player.mapping.LC_E] = Button.RIGHT;
|
||||
gamepadMapping[this.player.mapping.TOUCH] = Button.SUBMIT;
|
||||
gamepadMapping[this.player.mapping.RC_S] = this.scene.abSwapped ? Button.CANCEL : Button.ACTION;
|
||||
gamepadMapping[this.player.mapping.RC_E] = this.scene.abSwapped ? Button.ACTION : Button.CANCEL;
|
||||
gamepadMapping[this.player.mapping.SELECT] = Button.STATS;
|
||||
gamepadMapping[this.player.mapping.START] = Button.MENU;
|
||||
gamepadMapping[this.player.mapping.RB] = Button.CYCLE_SHINY;
|
||||
gamepadMapping[this.player.mapping.LB] = Button.CYCLE_FORM;
|
||||
gamepadMapping[this.player.mapping.LT] = Button.CYCLE_GENDER;
|
||||
gamepadMapping[this.player.mapping.RT] = Button.CYCLE_ABILITY;
|
||||
gamepadMapping[this.player.mapping.RC_W] = Button.CYCLE_NATURE;
|
||||
gamepadMapping[this.player.mapping.RC_N] = Button.CYCLE_VARIANT;
|
||||
gamepadMapping[this.player.mapping.LS] = Button.SPEED_UP;
|
||||
gamepadMapping[this.player.mapping.RS] = Button.SLOW_DOWN;
|
||||
gamepadMapping[this.player.LC_N] = Button.UP;
|
||||
gamepadMapping[this.player.LC_S] = Button.DOWN;
|
||||
gamepadMapping[this.player.LC_W] = Button.LEFT;
|
||||
gamepadMapping[this.player.LC_E] = Button.RIGHT;
|
||||
gamepadMapping[this.player.TOUCH] = Button.SUBMIT;
|
||||
gamepadMapping[this.player.RC_S] = this.scene.abSwapped ? Button.CANCEL : Button.ACTION;
|
||||
gamepadMapping[this.player.RC_E] = this.scene.abSwapped ? Button.ACTION : Button.CANCEL;
|
||||
gamepadMapping[this.player.SELECT] = Button.STATS;
|
||||
gamepadMapping[this.player.START] = Button.MENU;
|
||||
gamepadMapping[this.player.RB] = Button.CYCLE_SHINY;
|
||||
gamepadMapping[this.player.LB] = Button.CYCLE_FORM;
|
||||
gamepadMapping[this.player.LT] = Button.CYCLE_GENDER;
|
||||
gamepadMapping[this.player.RT] = Button.CYCLE_ABILITY;
|
||||
gamepadMapping[this.player.RC_W] = Button.CYCLE_NATURE;
|
||||
gamepadMapping[this.player.RC_N] = Button.CYCLE_VARIANT;
|
||||
gamepadMapping[this.player.LS] = Button.SPEED_UP;
|
||||
gamepadMapping[this.player.RS] = Button.SLOW_DOWN;
|
||||
|
||||
return gamepadMapping;
|
||||
}
|
||||
|
@ -1635,13 +1635,13 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
"encounter": {
|
||||
1: `Ich habe mich entschieden, erneut meinen Hut in den Ring zu werfen.
|
||||
$Komm jetzt... Zeig mir die Früchte deines Trainings.`,
|
||||
"victory": {
|
||||
1: "Ich freue mich auf Neuigkeiten über all deine Erfolge!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "Was ist los? Das ist doch nicht alles, oder?"
|
||||
}
|
||||
},
|
||||
"victory": {
|
||||
1: "Ich freue mich auf Neuigkeiten über all deine Erfolge!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "Was ist los? Das ist doch nicht alles, oder?"
|
||||
}
|
||||
},
|
||||
"nemona": {
|
||||
"encounter": {
|
||||
@ -2337,7 +2337,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
};
|
||||
|
||||
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
|
||||
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
|
||||
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
|
||||
|
||||
// Dialogue of the endboss of the game when the player character is male (Or unset)
|
||||
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {
|
||||
|
@ -11,6 +11,7 @@ export const menu: SimpleTranslationEntries = {
|
||||
"dailyRun": "Täglicher Run (Beta)",
|
||||
"loadGame": "Spiel laden",
|
||||
"newGame": "Neues Spiel",
|
||||
"settings": "Einstellungen",
|
||||
"selectGameMode": "Wähle einen Spielmodus",
|
||||
"logInOrCreateAccount": "Melde dich an oder erstelle einen Account zum starten. Keine Email nötig!",
|
||||
"username": "Benutzername",
|
||||
|
@ -14,7 +14,8 @@ export const tutorial: SimpleTranslationEntries = {
|
||||
$Dort kannst du u. A. die Spielgeschwin-\ndigkeit und das Fensterdesign ändern.
|
||||
$Das Menü verbirgt noch andere Funktionen - probier' sie gerne aus!`,
|
||||
|
||||
"starterSelect": `Hier kannst du deine Starter-Pokémon auswählen.\nSie begleiten dich am Anfang deines Abenteuers.
|
||||
"starterSelect": `In diesem Bildschirm kannst du mit Z oder Leertaste deine\nStarter auswählen.
|
||||
$Sie begleiten dich am Anfang deines Abenteuers.
|
||||
$Jeder Starter hat einen Preis. Dein Team kann bis zu sechs\nMitglieder haben, solange der Gesamtpreis max. 10 beträgt.
|
||||
$Du kannst Geschlecht, Fähigkeit und Form beliebig auswählen,\nsobald du sie mindestens einmal gefangen hast.
|
||||
$Die DVs ergeben sich aus den Höchstwerten aller Pokémon,\ndie du bereits gefangen hast.
|
||||
|
@ -1595,13 +1595,13 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
"encounter": {
|
||||
1: `I decided to throw my hat in the ring once more.
|
||||
$Come now… Show me the fruits of your training.`,
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"nemona": {
|
||||
"encounter": {
|
||||
@ -2278,7 +2278,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
|
||||
|
||||
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
|
||||
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
|
||||
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
|
||||
|
||||
// Dialogue of the endboss of the game when the player character is male (Or unset)
|
||||
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {
|
||||
|
@ -11,6 +11,7 @@ export const menu: SimpleTranslationEntries = {
|
||||
"dailyRun": "Daily Run (Beta)",
|
||||
"loadGame": "Load Game",
|
||||
"newGame": "New Game",
|
||||
"settings": "Settings",
|
||||
"selectGameMode": "Select a game mode.",
|
||||
"logInOrCreateAccount": "Log in or create an account to start. No email required!",
|
||||
"username": "Username",
|
||||
|
@ -12,7 +12,7 @@ export const tutorial: SimpleTranslationEntries = {
|
||||
$From the settings you can change game speed, window style, and other options.
|
||||
$There are also various other features here, so be sure to check them all!`,
|
||||
|
||||
"starterSelect": `From this screen, you can select your starters.\nThese are your initial party members.
|
||||
"starterSelect": `From this screen, you can select your starters by pressing\nZ or the Space bar. These are your initial party members.
|
||||
$Each starter has a value. Your party can have up to\n6 members as long as the total does not exceed 10.
|
||||
$You can also select gender, ability, and form depending on\nthe variants you've caught or hatched.
|
||||
$The IVs for a species are also the best of every one you've\ncaught or hatched, so try to get lots of the same species!`,
|
||||
|
@ -3,8 +3,8 @@ import { SimpleTranslationEntries } from "#app/plugins/i18n";
|
||||
export const battle: SimpleTranslationEntries = {
|
||||
"bossAppeared": "¡{{bossName}} te corta el paso!",
|
||||
"trainerAppeared": "¡{{trainerName}}\nte desafía!",
|
||||
"trainerAppearedDouble": "{{trainerName}}\nwould like to battle!",
|
||||
"trainerSendOut": "{{trainerName}} sent out\n{{pokemonName}}!",
|
||||
"trainerAppearedDouble": "¡{{trainerName}}\nwould te desafían!",
|
||||
"trainerSendOut": "¡{{trainerName}} saca a\n{{pokemonName}}!",
|
||||
"singleWildAppeared": "¡Un {{pokemonName}} salvaje te corta el paso!",
|
||||
"multiWildAppeared": "¡Un {{pokemonName1}} y un {{pokemonName2}} salvajes\nte cortan el paso!",
|
||||
"playerComeBack": "¡{{pokemonName}}, ven aquí!",
|
||||
@ -13,9 +13,9 @@ export const battle: SimpleTranslationEntries = {
|
||||
"trainerGo": "¡{{trainerName}} saca a {{pokemonName}}!",
|
||||
"switchQuestion": "¿Quieres cambiar a\n{{pokemonName}}?",
|
||||
"trainerDefeated": "¡Has derrotado a\n{{trainerName}}!",
|
||||
"moneyWon": "You got\n₽{{moneyAmount}} for winning!",
|
||||
"moneyWon": "¡Has ganado\n₽{{moneyAmount}} por vencer!",
|
||||
"pokemonCaught": "¡{{pokemonName}} atrapado!",
|
||||
"partyFull": "Your party is full.\nRelease a Pokémon to make room for {{pokemonName}}?",
|
||||
"partyFull": "Tu equipo esta completo.\n¿Quieres liberar un Pokémon para meter a {{pokemonName}}?",
|
||||
"pokemon": "Pokémon",
|
||||
"sendOutPokemon": "¡Adelante, {{pokemonName}}!",
|
||||
"hitResultCriticalHit": "!Un golpe crítico!",
|
||||
@ -39,7 +39,7 @@ export const battle: SimpleTranslationEntries = {
|
||||
"learnMoveAnd": "Y…",
|
||||
"levelCapUp": "¡Se ha incrementado el\nnivel máximo a {{levelCap}}!",
|
||||
"moveNotImplemented": "{{moveName}} aún no está implementado y no se puede seleccionar.",
|
||||
"moveNoPP": "There's no PP left for\nthis move!",
|
||||
"moveNoPP": "¡No hay suficientes PP\npara este movimiento!",
|
||||
"moveDisabled": "!No puede usar {{moveName}} porque ha sido anulado!",
|
||||
"noPokeballForce": "Una fuerza misteriosa\nte impide usar Poké Balls.",
|
||||
"noPokeballTrainer": "¡No puedes atrapar a los\nPokémon de los demás!",
|
||||
|
@ -1,40 +1,40 @@
|
||||
import { SimpleTranslationEntries } from "#app/plugins/i18n";
|
||||
|
||||
export const biome: SimpleTranslationEntries = {
|
||||
"unknownLocation": "Somewhere you can\'t remember",
|
||||
"TOWN": "Town",
|
||||
"PLAINS": "Plains",
|
||||
"GRASS": "Grassy Field",
|
||||
"TALL_GRASS": "Tall Grass",
|
||||
"METROPOLIS": "Metropolis",
|
||||
"FOREST": "Forest",
|
||||
"SEA": "Sea",
|
||||
"SWAMP": "Swamp",
|
||||
"BEACH": "Beach",
|
||||
"LAKE": "Lake",
|
||||
"SEABED": "Seabed",
|
||||
"MOUNTAIN": "Mountain",
|
||||
"unknownLocation": "En algún lugar que no puedes recordar",
|
||||
"TOWN": "Ciudad",
|
||||
"PLAINS": "Valle",
|
||||
"GRASS": "Campo",
|
||||
"TALL_GRASS": "Pradera de Hierba Alta",
|
||||
"METROPOLIS": "Metrópolis",
|
||||
"FOREST": "Bosque",
|
||||
"SEA": "Mar",
|
||||
"SWAMP": "Pantano",
|
||||
"BEACH": "Playa",
|
||||
"LAKE": "Lago",
|
||||
"SEABED": "Fondo del mar",
|
||||
"MOUNTAIN": "Montaña",
|
||||
"BADLANDS": "Badlands",
|
||||
"CAVE": "Cave",
|
||||
"DESERT": "Desert",
|
||||
"ICE_CAVE": "Ice Cave",
|
||||
"MEADOW": "Meadow",
|
||||
"POWER_PLANT": "Power Plant",
|
||||
"VOLCANO": "Volcano",
|
||||
"GRAVEYARD": "Graveyard",
|
||||
"CAVE": "Cueva",
|
||||
"DESERT": "Desierto",
|
||||
"ICE_CAVE": "Cueva Helada",
|
||||
"MEADOW": "Prado",
|
||||
"POWER_PLANT": "Central Eléctrica",
|
||||
"VOLCANO": "Volcán",
|
||||
"GRAVEYARD": "Cementerio",
|
||||
"DOJO": "Dojo",
|
||||
"FACTORY": "Factory",
|
||||
"RUINS": "Ancient Ruins",
|
||||
"WASTELAND": "Wasteland",
|
||||
"ABYSS": "Abyss",
|
||||
"SPACE": "Space",
|
||||
"CONSTRUCTION_SITE": "Construction Site",
|
||||
"JUNGLE": "Jungle",
|
||||
"FAIRY_CAVE": "Fairy Cave",
|
||||
"TEMPLE": "Temple",
|
||||
"SLUM": "Slum",
|
||||
"SNOWY_FOREST": "Snowy Forest",
|
||||
"ISLAND": "Island",
|
||||
"LABORATORY": "Laboratory",
|
||||
"FACTORY": "Fábrica",
|
||||
"RUINS": "Ruinas Antiguas",
|
||||
"WASTELAND": "Páramo",
|
||||
"ABYSS": "Abismo",
|
||||
"SPACE": "Espacio",
|
||||
"CONSTRUCTION_SITE": "Obra",
|
||||
"JUNGLE": "Jungla",
|
||||
"FAIRY_CAVE": "Cueva de Hadas",
|
||||
"TEMPLE": "Templo",
|
||||
"SLUM": "Suburbio",
|
||||
"SNOWY_FOREST": "Bosque nevado",
|
||||
"ISLAND": "Isla",
|
||||
"LABORATORY": "Laboratorio",
|
||||
"END": "???",
|
||||
} as const;
|
||||
|
@ -1595,13 +1595,13 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
"encounter": {
|
||||
1: `I decided to throw my hat in the ring once more.
|
||||
$Come now… Show me the fruits of your training.`,
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"nemona": {
|
||||
"encounter": {
|
||||
@ -2278,7 +2278,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
|
||||
|
||||
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
|
||||
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
|
||||
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
|
||||
|
||||
// Dialogue of the endboss of the game when the player character is male (Or unset)
|
||||
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {
|
||||
|
@ -11,6 +11,7 @@ export const menu: SimpleTranslationEntries = {
|
||||
"dailyRun": "Reto diario (Beta)",
|
||||
"loadGame": "Cargar partida",
|
||||
"newGame": "Nueva partida",
|
||||
"settings": "Settings",
|
||||
"selectGameMode": "Elige un modo de juego.",
|
||||
"logInOrCreateAccount": "Inicia sesión o crea una cuenta para empezar. ¡No se requiere correo electrónico!",
|
||||
"username": "Usuario",
|
||||
|
@ -2,17 +2,17 @@ import {SimpleTranslationEntries} from "#app/plugins/i18n";
|
||||
|
||||
// Titles of special trainers like gym leaders, elite four, and the champion
|
||||
export const titles: SimpleTranslationEntries = {
|
||||
"elite_four": "Elite Four",
|
||||
"elite_four_female": "Elite Four",
|
||||
"gym_leader": "Gym Leader",
|
||||
"gym_leader_female": "Gym Leader",
|
||||
"gym_leader_double": "Gym Leader Duo",
|
||||
"champion": "Champion",
|
||||
"champion_female": "Champion",
|
||||
"champion_double": "Champion Duo",
|
||||
"elite_four": "Alto Mando",
|
||||
"elite_four_female": "Alto Mando",
|
||||
"gym_leader": "Líder de gimnasio",
|
||||
"gym_leader_female": "Líder de gimnasio",
|
||||
"gym_leader_double": "Líderes de Gimnasio",
|
||||
"champion": "Campeón",
|
||||
"champion_female": "Campeona",
|
||||
"champion_double": "Campeones",
|
||||
"rival": "Rival",
|
||||
"professor": "Professor",
|
||||
"frontier_brain": "Frontier Brain",
|
||||
"professor": "Profesor",
|
||||
"frontier_brain": "As del Frente Batalla",
|
||||
// Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc.
|
||||
} as const;
|
||||
|
||||
|
@ -1595,13 +1595,13 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
"encounter": {
|
||||
1: `I decided to throw my hat in the ring once more.
|
||||
$Come now… Show me the fruits of your training.`,
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"nemona": {
|
||||
"encounter": {
|
||||
@ -3873,13 +3873,13 @@ export const PGFdialogue: DialogueTranslationEntries = {
|
||||
"encounter": {
|
||||
1: `I decided to throw my hat in the ring once more.
|
||||
$Come now… Show me the fruits of your training.`,
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"nemona": {
|
||||
"encounter": {
|
||||
|
@ -6,6 +6,7 @@ export const menu: SimpleTranslationEntries = {
|
||||
"dailyRun": "Défi du jour (Bêta)",
|
||||
"loadGame": "Charger la partie",
|
||||
"newGame": "Nouvelle partie",
|
||||
"settings": "Paramètres",
|
||||
"selectGameMode": "Sélectionnez un mode de jeu.",
|
||||
"logInOrCreateAccount": "Connectez-vous ou créez un compte pour commencer. Aucun e-mail requis !",
|
||||
"username": "Nom d’utilisateur",
|
||||
|
@ -16,7 +16,7 @@ export const tutorial: SimpleTranslationEntries = {
|
||||
$Il y a également toute une variété d’autres fonctionnalités,
|
||||
$jetez-y un œil !`,
|
||||
|
||||
"starterSelect": `Choisissez vos starters depuis cet écran.\nIls formeront votre équipe de départ.
|
||||
"starterSelect": `Choisissez vos starters depuis cet écran avec Z ou Espace.\nIls formeront votre équipe de départ.
|
||||
$Chacun possède une valeur. Votre équipe peut avoir jusqu’à\n6 membres, tant que vous ne dépassez pas un cout de 10.
|
||||
$Vous pouvez aussi choisir le sexe, le talent et la forme en\nfonction des variants déjà capturés ou éclos.
|
||||
$Les IVs d’un starter sont les meilleurs de tous ceux de son\nespèce déjà obtenus. Essayez donc d’en obtenir plusieurs !`,
|
||||
|
@ -1595,13 +1595,13 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
"encounter": {
|
||||
1: `I decided to throw my hat in the ring once more.
|
||||
$Come now… Show me the fruits of your training.`,
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"nemona": {
|
||||
"encounter": {
|
||||
@ -2278,7 +2278,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
|
||||
|
||||
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
|
||||
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
|
||||
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
|
||||
|
||||
// Dialogue of the endboss of the game when the player character is male (Or unset)
|
||||
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {
|
||||
|
@ -10,6 +10,7 @@ export const menu: SimpleTranslationEntries = {
|
||||
"continue": "Continua",
|
||||
"newGame": "Nuova Partita",
|
||||
"loadGame": "Carica Partita",
|
||||
"settings": "Settings",
|
||||
"dailyRun": "Corsa Giornaliera (Beta)",
|
||||
"selectGameMode": "Seleziona una modalità di gioco.",
|
||||
"logInOrCreateAccount": "Accedi o crea un nuovo account per iniziare. Non è richiesta un'email!",
|
||||
|
@ -1595,13 +1595,13 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
"encounter": {
|
||||
1: `I decided to throw my hat in the ring once more.
|
||||
$Come now… Show me the fruits of your training.`,
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"nemona": {
|
||||
"encounter": {
|
||||
@ -2278,7 +2278,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
|
||||
|
||||
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
|
||||
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
|
||||
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
|
||||
|
||||
// Dialogue of the endboss of the game when the player character is male (Or unset)
|
||||
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {
|
||||
|
@ -11,6 +11,7 @@ export const menu: SimpleTranslationEntries = {
|
||||
"dailyRun": "Desafio Diário (Beta)",
|
||||
"loadGame": "Carregar Jogo",
|
||||
"newGame": "Novo Jogo",
|
||||
"settings": "Configurações",
|
||||
"selectGameMode": "Escolha um modo de jogo.",
|
||||
"logInOrCreateAccount": "Inicie uma sessão ou crie uma conta para começar. Não é necessário email!",
|
||||
"username": "Nome de Usuário",
|
||||
|
@ -18,7 +18,8 @@ export const tutorial: SimpleTranslationEntries = {
|
||||
$Existem também vários outros recursos disponíveis aqui.
|
||||
$Não deixe de conferir todos eles!`,
|
||||
|
||||
"starterSelect": `Aqui você pode escolher seus iniciais.\nEsses serão os primeiro Pokémon da sua equipe.
|
||||
"starterSelect": `Aqui você pode escolher seus iniciais apertando a tecla Z ou\na Barra de Espaço.
|
||||
$Esses serão os primeiro Pokémon da sua equipe.
|
||||
$Cada inicial tem seu custo. Sua equipe pode ter até 6\nmembros, desde que a soma dos custos não ultrapasse 10.
|
||||
$Você pode escolher o gênero, a habilidade\ne até a forma do seu inicial.
|
||||
$Essas opções dependem das variantes dessa\nespécie que você já capturou ou chocou.
|
||||
|
@ -1595,13 +1595,13 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
"encounter": {
|
||||
1: `I decided to throw my hat in the ring once more.
|
||||
$Come now… Show me the fruits of your training.`,
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"nemona": {
|
||||
"encounter": {
|
||||
@ -2278,7 +2278,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
|
||||
|
||||
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
|
||||
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
|
||||
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
|
||||
|
||||
// Dialogue of the endboss of the game when the player character is male (Or unset)
|
||||
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {
|
||||
|
@ -11,6 +11,7 @@ export const menu: SimpleTranslationEntries = {
|
||||
"dailyRun": "每日挑战 (Beta)",
|
||||
"loadGame": "加载游戏",
|
||||
"newGame": "新游戏",
|
||||
"settings": "设置",
|
||||
"selectGameMode": "选择一个游戏模式",
|
||||
"logInOrCreateAccount": "登录或创建账户以开始游戏。无需邮箱!",
|
||||
"username": "用户名",
|
||||
|
@ -13,7 +13,7 @@ export const tutorial: SimpleTranslationEntries = {
|
||||
$在设置中,您可以更改游戏速度、窗口样式\n和其他选项。
|
||||
$这里还有各种其他功能,请务必全部查看!`,
|
||||
|
||||
"starterSelect": `在此页面中,您可以选择您的初始宝可梦。\n这些是您最初的队伍成员。
|
||||
"starterSelect": `在此页面中,您可以通过按Z或空格键选择\n您的初始宝可梦。这些是您最初的队伍成员。
|
||||
$每个初始宝可梦都有一个费用值。您的队伍\n最多可以拥有6名成员,只要总费用不超过10。
|
||||
$您还可以根据您捕获或孵化的变种选择性别\n、特性和形态。
|
||||
$一个物种个体值是您捕获或孵化的所有宝可\n梦中最好的,所以尽量获得更多同种宝可梦!`,
|
||||
|
@ -1595,13 +1595,13 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
"encounter": {
|
||||
1: `I decided to throw my hat in the ring once more.
|
||||
$Come now… Show me the fruits of your training.`,
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"victory": {
|
||||
1: "I eagerly await news of all your achievements!"
|
||||
},
|
||||
"defeat": {
|
||||
1: "What's the matter? This isn't all, is it?"
|
||||
}
|
||||
},
|
||||
"nemona": {
|
||||
"encounter": {
|
||||
@ -2278,7 +2278,7 @@ export const PGMdialogue: DialogueTranslationEntries = {
|
||||
|
||||
|
||||
// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue.
|
||||
export const PGFdialogue: SimpleTranslationEntries = PGMdialogue;
|
||||
export const PGFdialogue: DialogueTranslationEntries = PGMdialogue;
|
||||
|
||||
// Dialogue of the endboss of the game when the player character is male (Or unset)
|
||||
export const PGMbattleSpecDialogue: SimpleTranslationEntries = {
|
||||
|
@ -11,6 +11,7 @@ export const menu: SimpleTranslationEntries = {
|
||||
"dailyRun": "每日挑戰 (Beta)",
|
||||
"loadGame": "加載遊戲",
|
||||
"newGame": "新遊戲",
|
||||
"settings": "Settings",
|
||||
"selectGameMode": "選擇遊戲模式",
|
||||
"logInOrCreateAccount": "登入或註冊即可開始遊戲,無需郵箱!",
|
||||
"username": "用戶名",
|
||||
|
78
src/main.ts
78
src/main.ts
@ -5,7 +5,6 @@ import { version } from "../package.json";
|
||||
import UIPlugin from "phaser3-rex-plugins/templates/ui/ui-plugin";
|
||||
import BBCodeTextPlugin from "phaser3-rex-plugins/plugins/bbcodetext-plugin";
|
||||
import InputTextPlugin from "phaser3-rex-plugins/plugins/inputtext-plugin.js";
|
||||
import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
|
||||
import TransitionImagePackPlugin from "phaser3-rex-plugins/templates/transitionimagepack/transitionimagepack-plugin.js";
|
||||
import { LoadingScene } from "./loading-scene";
|
||||
|
||||
@ -72,23 +71,82 @@ const config: Phaser.Types.Core.GameConfig = {
|
||||
version: version
|
||||
};
|
||||
|
||||
/**
|
||||
* Sets this object's position relative to another object with a given offset
|
||||
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
|
||||
* @param x The relative x position
|
||||
* @param y The relative y position
|
||||
*/
|
||||
const setPositionRelative = function (guideObject: any, x: number, y: number) {
|
||||
if (guideObject && guideObject instanceof Phaser.GameObjects.GameObject) {
|
||||
const offsetX = guideObject.width * (-0.5 + (0.5 - guideObject.originX));
|
||||
const offsetY = guideObject.height * (-0.5 + (0.5 - guideObject.originY));
|
||||
this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y);
|
||||
return;
|
||||
}
|
||||
|
||||
this.setPosition(x, y);
|
||||
const offsetX = guideObject.width * (-0.5 + (0.5 - guideObject.originX));
|
||||
const offsetY = guideObject.height * (-0.5 + (0.5 - guideObject.originY));
|
||||
this.setPosition(guideObject.x + offsetX + x, guideObject.y + offsetY + y);
|
||||
};
|
||||
|
||||
declare module "phaser" {
|
||||
namespace GameObjects {
|
||||
interface Container {
|
||||
/**
|
||||
* Sets this object's position relative to another object with a given offset
|
||||
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
|
||||
* @param x The relative x position
|
||||
* @param y The relative y position
|
||||
*/
|
||||
setPositionRelative(guideObject: any, x: number, y: number): void;
|
||||
}
|
||||
interface Sprite {
|
||||
/**
|
||||
* Sets this object's position relative to another object with a given offset
|
||||
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
|
||||
* @param x The relative x position
|
||||
* @param y The relative y position
|
||||
*/
|
||||
setPositionRelative(guideObject: any, x: number, y: number): void;
|
||||
}
|
||||
interface Image {
|
||||
/**
|
||||
* Sets this object's position relative to another object with a given offset
|
||||
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
|
||||
* @param x The relative x position
|
||||
* @param y The relative y position
|
||||
*/
|
||||
setPositionRelative(guideObject: any, x: number, y: number): void;
|
||||
}
|
||||
interface NineSlice {
|
||||
/**
|
||||
* Sets this object's position relative to another object with a given offset
|
||||
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
|
||||
* @param x The relative x position
|
||||
* @param y The relative y position
|
||||
*/
|
||||
setPositionRelative(guideObject: any, x: number, y: number): void;
|
||||
}
|
||||
interface Text {
|
||||
/**
|
||||
* Sets this object's position relative to another object with a given offset
|
||||
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
|
||||
* @param x The relative x position
|
||||
* @param y The relative y position
|
||||
*/
|
||||
setPositionRelative(guideObject: any, x: number, y: number): void;
|
||||
}
|
||||
interface Rectangle {
|
||||
/**
|
||||
* Sets this object's position relative to another object with a given offset
|
||||
* @param guideObject {@linkcode Phaser.GameObjects.GameObject} to base the position off of
|
||||
* @param x The relative x position
|
||||
* @param y The relative y position
|
||||
*/
|
||||
setPositionRelative(guideObject: any, x: number, y: number): void;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Phaser.GameObjects.Container.prototype.setPositionRelative = setPositionRelative;
|
||||
Phaser.GameObjects.Sprite.prototype.setPositionRelative = setPositionRelative;
|
||||
Phaser.GameObjects.Image.prototype.setPositionRelative = setPositionRelative;
|
||||
Phaser.GameObjects.NineSlice.prototype.setPositionRelative = setPositionRelative;
|
||||
Phaser.GameObjects.Text.prototype.setPositionRelative = setPositionRelative;
|
||||
BBCodeText.prototype.setPositionRelative = setPositionRelative;
|
||||
Phaser.GameObjects.Rectangle.prototype.setPositionRelative = setPositionRelative;
|
||||
|
||||
document.fonts.load("16px emerald").then(() => document.fonts.load("10px pkmnems"));
|
||||
|
@ -30,7 +30,7 @@ import { Weather, WeatherType, getRandomWeatherType, getTerrainBlockMessage, get
|
||||
import { TempBattleStat } from "./data/temp-battle-stat";
|
||||
import { ArenaTagSide, ArenaTrapTag, MistTag, TrickRoomTag } from "./data/arena-tag";
|
||||
import { ArenaTagType } from "./data/enums/arena-tag-type";
|
||||
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, IgnoreOpponentEvasionAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr } from "./data/ability";
|
||||
import { CheckTrappedAbAttr, IgnoreOpponentStatChangesAbAttr, IgnoreOpponentEvasionAbAttr, PostAttackAbAttr, PostBattleAbAttr, PostDefendAbAttr, PostSummonAbAttr, PostTurnAbAttr, PostWeatherLapseAbAttr, PreSwitchOutAbAttr, PreWeatherDamageAbAttr, ProtectStatAbAttr, RedirectMoveAbAttr, BlockRedirectAbAttr, RunSuccessAbAttr, StatChangeMultiplierAbAttr, SuppressWeatherEffectAbAttr, SyncEncounterNatureAbAttr, applyAbAttrs, applyCheckTrappedAbAttrs, applyPostAttackAbAttrs, applyPostBattleAbAttrs, applyPostDefendAbAttrs, applyPostSummonAbAttrs, applyPostTurnAbAttrs, applyPostWeatherLapseAbAttrs, applyPreStatChangeAbAttrs, applyPreSwitchOutAbAttrs, applyPreWeatherEffectAbAttrs, BattleStatMultiplierAbAttr, applyBattleStatMultiplierAbAttrs, IncrementMovePriorityAbAttr, applyPostVictoryAbAttrs, PostVictoryAbAttr, BlockNonDirectDamageAbAttr as BlockNonDirectDamageAbAttr, applyPostKnockOutAbAttrs, PostKnockOutAbAttr, PostBiomeChangeAbAttr, applyPostFaintAbAttrs, PostFaintAbAttr, IncreasePpAbAttr, PostStatChangeAbAttr, applyPostStatChangeAbAttrs, AlwaysHitAbAttr, PreventBerryUseAbAttr, StatChangeCopyAbAttr, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr, MaxMultiHitAbAttr, HealFromBerryUseAbAttr } from "./data/ability";
|
||||
import { Unlockables, getUnlockableName } from "./system/unlockables";
|
||||
import { getBiomeKey } from "./field/arena";
|
||||
import { BattleType, BattlerIndex, TurnCommand } from "./battle";
|
||||
@ -262,6 +262,14 @@ export class TitlePhase extends Phase {
|
||||
return true;
|
||||
},
|
||||
keepOpen: true
|
||||
},
|
||||
{
|
||||
label: i18next.t("menu:settings"),
|
||||
handler: () => {
|
||||
this.scene.ui.setOverlayMode(Mode.SETTINGS);
|
||||
return true;
|
||||
},
|
||||
keepOpen: true
|
||||
});
|
||||
const config: OptionSelectConfig = {
|
||||
options: options,
|
||||
@ -1015,7 +1023,6 @@ export class EncounterPhase extends BattlePhase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handleTutorial(this.scene, Tutorial.Access_Menu).then(() => super.end());
|
||||
}
|
||||
|
||||
@ -2221,7 +2228,9 @@ export class BerryPhase extends FieldPhase {
|
||||
if (cancelled.value) {
|
||||
pokemon.scene.queueMessage(getPokemonMessage(pokemon, " is too\nnervous to eat berries!"));
|
||||
} else {
|
||||
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM));
|
||||
this.scene.unshiftPhase(
|
||||
new CommonAnimPhase(this.scene, pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM)
|
||||
);
|
||||
|
||||
for (const berryModifier of this.scene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon) as BerryModifier[]) {
|
||||
if (berryModifier.consumed) {
|
||||
@ -2234,6 +2243,8 @@ export class BerryPhase extends FieldPhase {
|
||||
}
|
||||
|
||||
this.scene.updateModifiers(pokemon.isPlayer());
|
||||
|
||||
applyAbAttrs(HealFromBerryUseAbAttr, pokemon, new Utils.BooleanHolder(false));
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -2822,9 +2833,13 @@ export class MoveEffectPhase extends PokemonPhase {
|
||||
|
||||
const user = this.getUserPokemon();
|
||||
|
||||
// Hit check only calculated on first hit for multi-hit moves
|
||||
// Hit check only calculated on first hit for multi-hit moves unless flag is set to check all hits.
|
||||
// However, if an ability with the MaxMultiHitAbAttr, namely Skill Link, is present, act as a normal
|
||||
// multi-hit move and proceed with all hits
|
||||
if (user.turnData.hitsLeft < user.turnData.hitCount) {
|
||||
return true;
|
||||
if (!this.move.getMove().hasFlag(MoveFlags.CHECK_ALL_HITS) || user.hasAbilityWithAttr(MaxMultiHitAbAttr)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (user.hasAbilityWithAttr(AlwaysHitAbAttr) || target.hasAbilityWithAttr(AlwaysHitAbAttr)) {
|
||||
|
@ -65,19 +65,14 @@ export interface DialogueTranslationEntry {
|
||||
}
|
||||
|
||||
export interface DialogueTranslationCategory {
|
||||
encounter: DialogueTranslationEntry;
|
||||
victory: DialogueTranslationEntry;
|
||||
defeat?: DialogueTranslationEntry;
|
||||
}
|
||||
|
||||
export interface DialogueTranslationTrainerClass {
|
||||
[key: string]: DialogueTranslationCategory;
|
||||
[category: string]: DialogueTranslationEntry;
|
||||
}
|
||||
|
||||
export interface DialogueTranslationEntries {
|
||||
[key: string]: DialogueTranslationTrainerClass;
|
||||
[trainertype: string]: DialogueTranslationCategory;
|
||||
}
|
||||
|
||||
|
||||
export interface Localizable {
|
||||
localize(): void;
|
||||
}
|
||||
|
@ -19,27 +19,33 @@ export function initGameSpeed() {
|
||||
|
||||
const originalAddEvent = this.time.addEvent;
|
||||
this.time.addEvent = function (config: Phaser.Time.TimerEvent | Phaser.Types.Time.TimerEventConfig) {
|
||||
if (config.delay) {
|
||||
if (!(config instanceof Phaser.Time.TimerEvent) && config.delay) {
|
||||
config.delay = transformValue(config.delay);
|
||||
}
|
||||
return originalAddEvent.apply(this, [ config ]);
|
||||
};
|
||||
const originalTweensAdd = this.tweens.add;
|
||||
this.tweens.add = function (config: Phaser.Types.Tweens.TweenBuilderConfig | Phaser.Types.Tweens.TweenChainBuilderConfig | Phaser.Tweens.Tween | Phaser.Tweens.TweenChain) {
|
||||
if (config.duration) {
|
||||
config.duration = transformValue(config.duration);
|
||||
}
|
||||
if (config.delay) {
|
||||
config.delay = transformValue(config.delay);
|
||||
}
|
||||
if (config.repeatDelay) {
|
||||
config.repeatDelay = transformValue(config.repeatDelay);
|
||||
}
|
||||
if (config.loopDelay) {
|
||||
config.loopDelay = transformValue(config.loopDelay);
|
||||
config.loopDelay = transformValue(config.loopDelay as number);
|
||||
}
|
||||
if (config.hold) {
|
||||
config.hold = transformValue(config.hold);
|
||||
|
||||
if (!(config instanceof Phaser.Tweens.TweenChain) ) {
|
||||
if (config.duration) {
|
||||
config.duration = transformValue(config.duration);
|
||||
}
|
||||
|
||||
if (!(config instanceof Phaser.Tweens.Tween)) {
|
||||
if (config.delay) {
|
||||
config.delay = transformValue(config.delay as number);
|
||||
}
|
||||
if (config.repeatDelay) {
|
||||
config.repeatDelay = transformValue(config.repeatDelay);
|
||||
}
|
||||
if (config.hold) {
|
||||
config.hold = transformValue(config.hold);
|
||||
}
|
||||
}
|
||||
}
|
||||
return originalTweensAdd.apply(this, [ config ]);
|
||||
};
|
||||
@ -51,13 +57,13 @@ export function initGameSpeed() {
|
||||
t.duration = transformValue(t.duration);
|
||||
}
|
||||
if (t.delay) {
|
||||
t.delay = transformValue(t.delay);
|
||||
t.delay = transformValue(t.delay as number);
|
||||
}
|
||||
if (t.repeatDelay) {
|
||||
t.repeatDelay = transformValue(t.repeatDelay);
|
||||
}
|
||||
if (t.loopDelay) {
|
||||
t.loopDelay = transformValue(t.loopDelay);
|
||||
t.loopDelay = transformValue(t.loopDelay as number);
|
||||
}
|
||||
if (t.hold) {
|
||||
t.hold = transformValue(t.hold);
|
||||
@ -78,7 +84,7 @@ export function initGameSpeed() {
|
||||
config.repeatDelay = transformValue(config.repeatDelay);
|
||||
}
|
||||
if (config.loopDelay) {
|
||||
config.loopDelay = transformValue(config.loopDelay);
|
||||
config.loopDelay = transformValue(config.loopDelay as number);
|
||||
}
|
||||
if (config.hold) {
|
||||
config.hold = transformValue(config.hold);
|
||||
|
@ -5,6 +5,7 @@ import BattleScene from "../battle-scene";
|
||||
import { hasTouchscreen } from "../touch-controls";
|
||||
import { updateWindowType } from "../ui/ui-theme";
|
||||
import { PlayerGender } from "./game-data";
|
||||
import { CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js";
|
||||
import { MoneyFormat } from "../enums/money-format";
|
||||
|
||||
export enum Setting {
|
||||
@ -18,6 +19,8 @@ export enum Setting {
|
||||
Window_Type = "WINDOW_TYPE",
|
||||
Tutorials = "TUTORIALS",
|
||||
Enable_Retries = "ENABLE_RETRIES",
|
||||
Candy_Upgrade_Notification = "CANDY_UPGRADE_NOTIFICATION",
|
||||
Candy_Upgrade_Display = "CANDY_UPGRADE_DISPLAY",
|
||||
Money_Format = "MONEY_FORMAT",
|
||||
Sprite_Set = "SPRITE_SET",
|
||||
Move_Animations = "MOVE_ANIMATIONS",
|
||||
@ -52,6 +55,8 @@ export const settingOptions: SettingOptions = {
|
||||
[Setting.Window_Type]: new Array(5).fill(null).map((_, i) => (i + 1).toString()),
|
||||
[Setting.Tutorials]: ["Off", "On"],
|
||||
[Setting.Enable_Retries]: ["Off", "On"],
|
||||
[Setting.Candy_Upgrade_Notification]: ["Off", "Passives Only", "On"],
|
||||
[Setting.Candy_Upgrade_Display]: ["Icon", "Animation"],
|
||||
[Setting.Money_Format]: ["Normal", "Abbreviated"],
|
||||
[Setting.Sprite_Set]: ["Consistent", "Mixed Animated"],
|
||||
[Setting.Move_Animations]: ["Off", "On"],
|
||||
@ -78,6 +83,8 @@ export const settingDefaults: SettingDefaults = {
|
||||
[Setting.Window_Type]: 0,
|
||||
[Setting.Tutorials]: 1,
|
||||
[Setting.Enable_Retries]: 0,
|
||||
[Setting.Candy_Upgrade_Notification]: 0,
|
||||
[Setting.Candy_Upgrade_Display]: 0,
|
||||
[Setting.Money_Format]: 0,
|
||||
[Setting.Sprite_Set]: 0,
|
||||
[Setting.Move_Animations]: 1,
|
||||
@ -93,7 +100,7 @@ export const settingDefaults: SettingDefaults = {
|
||||
[Setting.Vibration]: 0
|
||||
};
|
||||
|
||||
export const reloadSettings: Setting[] = [Setting.UI_Theme, Setting.Language, Setting.Sprite_Set];
|
||||
export const reloadSettings: Setting[] = [Setting.UI_Theme, Setting.Language, Setting.Sprite_Set, Setting.Candy_Upgrade_Display];
|
||||
|
||||
export function setSetting(scene: BattleScene, setting: Setting, value: integer): boolean {
|
||||
switch (setting) {
|
||||
@ -127,6 +134,16 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer)
|
||||
case Setting.Enable_Retries:
|
||||
scene.enableRetries = settingOptions[setting][value] === "On";
|
||||
break;
|
||||
case Setting.Candy_Upgrade_Notification:
|
||||
if (scene.candyUpgradeNotification === value) {
|
||||
break;
|
||||
}
|
||||
|
||||
scene.candyUpgradeNotification = value;
|
||||
scene.eventTarget.dispatchEvent(new CandyUpgradeNotificationChangedEvent(value));
|
||||
break;
|
||||
case Setting.Candy_Upgrade_Display:
|
||||
scene.candyUpgradeDisplay = value;
|
||||
case Setting.Money_Format:
|
||||
switch (settingOptions[setting][value]) {
|
||||
case "Normal":
|
||||
|
@ -3,6 +3,8 @@ export const keysDown = new Map();
|
||||
let lastTouchedId;
|
||||
|
||||
export function initTouchControls(buttonMap) {
|
||||
const dpadDiv = document.querySelector("#dpad");
|
||||
preventElementZoom(dpadDiv);
|
||||
for (const button of document.querySelectorAll("[data-key]")) {
|
||||
// @ts-ignore
|
||||
bindKey(button, button.dataset.key, buttonMap);
|
||||
@ -115,3 +117,26 @@ function bindKey(node, key, buttonMap) {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link https://stackoverflow.com/a/39778831/4622620|Source}
|
||||
*
|
||||
* Prevent zoom on specified element
|
||||
* @param {HTMLElement} element
|
||||
*/
|
||||
function preventElementZoom(element) {
|
||||
element.addEventListener("touchstart", (event) => {
|
||||
const currentTouchTimeStamp = event.timeStamp;
|
||||
const previousTouchTimeStamp = event.currentTarget.dataset.lastTouchTimeStamp || currentTouchTimeStamp;
|
||||
const timeStampDifference = currentTouchTimeStamp - previousTouchTimeStamp;
|
||||
const fingers = event.touches.length;
|
||||
event.currentTarget.dataset.lastTouchTimeStamp = currentTouchTimeStamp;
|
||||
|
||||
if (!timeStampDifference || timeStampDifference > 500 || fingers > 1) {
|
||||
return;
|
||||
} // not double-tap
|
||||
|
||||
event.preventDefault();
|
||||
event.target.click();
|
||||
});
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { BattleSceneEventType, CandyUpgradeNotificationChangedEvent } from "#app/battle-scene-events.js";
|
||||
import { pokemonPrevolutions } from "#app/data/pokemon-evolutions";
|
||||
import { Variant, getVariantTint } from "#app/data/variant";
|
||||
import { argbFromRgba } from "@material/material-color-utilities";
|
||||
@ -103,6 +104,29 @@ function getValueReductionCandyCounts(baseValue: integer): [integer, integer] {
|
||||
return starterCandyCosts[baseValue - 1].costReduction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the icon position for a Pokemon of a given UI index
|
||||
* @param index UI index to calculate the icon position of
|
||||
* @returns An interface with an x and y property
|
||||
*/
|
||||
function calcIconPosition(index: number): {x: number, y: number} {
|
||||
const x = (index % 9) * 18;
|
||||
const y = Math.floor(index / 9) * 18;
|
||||
|
||||
return {x: x, y: y};
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the {@linkcode Phaser.GameObjects.Sprite} position for a Pokemon of a given UI index
|
||||
* @param index UI index to calculate the icon position of
|
||||
* @returns An interface with an x and y property
|
||||
*/
|
||||
function calcSpritePosition(index: number): {x: number, y: number} {
|
||||
const position = calcIconPosition(index);
|
||||
|
||||
return {x: position.x - 2, y: position.y + 2};
|
||||
}
|
||||
|
||||
const gens = [
|
||||
i18next.t("starterSelectUiHandler:gen1"),
|
||||
i18next.t("starterSelectUiHandler:gen2"),
|
||||
@ -202,6 +226,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
private shinyIcons: Phaser.GameObjects.Image[][];
|
||||
private hiddenAbilityIcons: Phaser.GameObjects.Image[];
|
||||
private classicWinIcons: Phaser.GameObjects.Image[];
|
||||
private candyUpgradeIcon: Phaser.GameObjects.Image[];
|
||||
private candyUpgradeOverlayIcon: Phaser.GameObjects.Image[];
|
||||
|
||||
private iconAnimHandler: PokemonIconAnimHandler;
|
||||
|
||||
@ -392,9 +418,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.genSpecies[g].push(species);
|
||||
const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true);
|
||||
const defaultProps = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr);
|
||||
const x = (s % 9) * 18;
|
||||
const y = Math.floor(s / 9) * 18;
|
||||
const icon = this.scene.add.sprite(x - 2, y + 2, species.getIconAtlasKey(defaultProps.formIndex, defaultProps.shiny, defaultProps.variant));
|
||||
const position = calcIconPosition(s);
|
||||
const icon = this.scene.add.sprite(position.x - 2, position.y + 2, species.getIconAtlasKey(defaultProps.formIndex, defaultProps.shiny, defaultProps.variant));
|
||||
icon.setScale(0.5);
|
||||
icon.setOrigin(0, 0);
|
||||
icon.setFrame(species.getIconId(defaultProps.female, defaultProps.formIndex, defaultProps.shiny, defaultProps.variant));
|
||||
@ -417,9 +442,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
});
|
||||
|
||||
this.starterValueLabels = new Array(81).fill(null).map((_, i) => {
|
||||
const x = (i % 9) * 18;
|
||||
const y = Math.floor(i / 9) * 18;
|
||||
const ret = addTextObject(this.scene, x + 152, y + 11, "0", TextStyle.WINDOW, { fontSize: "32px" });
|
||||
const position = calcIconPosition(i);
|
||||
const ret = addTextObject(this.scene, position.x + 152, position.y + 11, "0", TextStyle.WINDOW, { fontSize: "32px" });
|
||||
ret.setShadowOffset(2, 2);
|
||||
ret.setOrigin(0, 0);
|
||||
ret.setVisible(false);
|
||||
@ -428,9 +452,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
});
|
||||
|
||||
const getShinyStar = (i: integer, v: integer): Phaser.GameObjects.Image => {
|
||||
const x = (i % 9) * 18 - v * 3;
|
||||
const y = Math.floor(i / 9) * 18;
|
||||
const ret = this.scene.add.image(x + 163, y + 11, "shiny_star_small");
|
||||
const position = calcIconPosition(i);
|
||||
const ret = this.scene.add.image((position.x - v * 3) + 163, position.y + 11, "shiny_star_small");
|
||||
ret.setOrigin(0, 0);
|
||||
ret.setScale(0.5);
|
||||
ret.setVisible(false);
|
||||
@ -443,9 +466,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
});
|
||||
|
||||
this.hiddenAbilityIcons = 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 + 163, y + 16, "ha_capsule");
|
||||
const position = calcIconPosition(i);
|
||||
const ret = this.scene.add.image(position.x + 163, position.y + 16, "ha_capsule");
|
||||
ret.setOrigin(0, 0);
|
||||
ret.setScale(0.5);
|
||||
ret.setVisible(false);
|
||||
@ -454,9 +476,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
});
|
||||
|
||||
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 + 153, y + 21, "champion_ribbon");
|
||||
const position = calcIconPosition(i);
|
||||
const ret = this.scene.add.image(position.x + 153, position.y + 21, "champion_ribbon");
|
||||
ret.setOrigin(0, 0);
|
||||
ret.setScale(0.5);
|
||||
ret.setVisible(false);
|
||||
@ -464,6 +485,26 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
return ret;
|
||||
});
|
||||
|
||||
this.candyUpgradeIcon = new Array(81).fill(null).map((_, i) => {
|
||||
const position = calcIconPosition(i);
|
||||
const ret = this.scene.add.image(position.x + 163, position.y + 21, "candy");
|
||||
ret.setOrigin(0, 0);
|
||||
ret.setScale(0.25);
|
||||
ret.setVisible(false);
|
||||
this.starterSelectContainer.add(ret);
|
||||
return ret;
|
||||
});
|
||||
|
||||
this.candyUpgradeOverlayIcon = new Array(81).fill(null).map((_, i) => {
|
||||
const position = calcIconPosition(i);
|
||||
const ret = this.scene.add.image(position.x + 163, position.y + 21, "candy_overlay");
|
||||
ret.setOrigin(0, 0);
|
||||
ret.setScale(0.25);
|
||||
ret.setVisible(false);
|
||||
this.starterSelectContainer.add(ret);
|
||||
return ret;
|
||||
});
|
||||
|
||||
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.starterSelectContainer.add(this.pokemonSprite);
|
||||
@ -653,25 +694,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
|
||||
this.starterSelectContainer.add(this.statsContainer);
|
||||
|
||||
this.scene.eventTarget.addEventListener(BattleSceneEventType.CANDY_UPGRADE_NOTIFICATION_CHANGED, (e) => this.onCandyUpgradeDisplayChanged(e));
|
||||
|
||||
this.updateInstructions();
|
||||
}
|
||||
|
||||
show(args: any[]): boolean {
|
||||
if (args.length >= 2 && args[0] instanceof Function && typeof args[1] === "number") {
|
||||
super.show(args);
|
||||
|
||||
for (let g = 0; g < this.genSpecies.length; g++) {
|
||||
this.genSpecies[g].forEach((species, s) => {
|
||||
const dexEntry = this.scene.gameData.dexData[species.speciesId];
|
||||
const icon = this.starterSelectGenIconContainers[g].getAt(s) as Phaser.GameObjects.Sprite;
|
||||
if (dexEntry.caughtAttr) {
|
||||
icon.clearTint();
|
||||
} else if (dexEntry.seenAttr) {
|
||||
icon.setTint(0x808080);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
this.starterSelectCallback = args[0] as StarterSelectCallback;
|
||||
|
||||
this.starterSelectContainer.setVisible(true);
|
||||
@ -684,6 +714,21 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.setCursor(0);
|
||||
this.tryUpdateValue(0);
|
||||
|
||||
for (let g = 0; g < this.genSpecies.length; g++) {
|
||||
this.genSpecies[g].forEach((species, s) => {
|
||||
const icon = this.starterSelectGenIconContainers[g].getAt(s) as Phaser.GameObjects.Sprite;
|
||||
const dexEntry = this.scene.gameData.dexData[species.speciesId];
|
||||
|
||||
if (dexEntry.caughtAttr) {
|
||||
icon.clearTint();
|
||||
} else if (dexEntry.seenAttr) {
|
||||
icon.setTint(0x808080);
|
||||
}
|
||||
|
||||
this.setUpgradeAnimation(icon, species);
|
||||
});
|
||||
}
|
||||
|
||||
handleTutorial(this.scene, Tutorial.Starter_Select);
|
||||
|
||||
return true;
|
||||
@ -706,6 +751,161 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.starterSelectMessageBoxContainer.setVisible(!!text?.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if 'Icon' based upgrade notifications should be shown
|
||||
* @returns true if upgrade notifications are enabled and set to display an 'Icon'
|
||||
*/
|
||||
isUpgradeIconEnabled(): boolean {
|
||||
return this.scene.candyUpgradeNotification !== 0 && this.scene.candyUpgradeDisplay === 0;
|
||||
}
|
||||
/**
|
||||
* Determines if 'Animation' based upgrade notifications should be shown
|
||||
* @returns true if upgrade notifications are enabled and set to display an 'Animation'
|
||||
*/
|
||||
isUpgradeAnimationEnabled(): boolean {
|
||||
return this.scene.candyUpgradeNotification !== 0 && this.scene.candyUpgradeDisplay === 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a passive upgrade is available for the given species ID
|
||||
* @param speciesId The ID of the species to check the passive of
|
||||
* @returns true if the user has enough candies and a passive has not been unlocked already
|
||||
*/
|
||||
isPassiveAvailable(speciesId: number): boolean {
|
||||
// Get this species ID's starter data
|
||||
const starterData = this.scene.gameData.starterData[speciesId];
|
||||
|
||||
return starterData.candyCount >= getPassiveCandyCount(speciesStarters[speciesId])
|
||||
&& !(starterData.passiveAttr & PassiveAttr.UNLOCKED);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a value reduction upgrade is available for the given species ID
|
||||
* @param speciesId The ID of the species to check the value reduction of
|
||||
* @returns true if the user has enough candies and all value reductions have not been unlocked already
|
||||
*/
|
||||
isValueReductionAvailable(speciesId: number): boolean {
|
||||
// Get this species ID's starter data
|
||||
const starterData = this.scene.gameData.starterData[speciesId];
|
||||
|
||||
return starterData.candyCount >= getValueReductionCandyCounts(speciesStarters[speciesId])[starterData.valueReduction]
|
||||
&& starterData.valueReduction < 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a bounce animation if enabled and the Pokemon has an upgrade
|
||||
* @param icon {@linkcode Phaser.GameObjects.GameObject} to animate
|
||||
* @param species {@linkcode PokemonSpecies} of the icon used to check for upgrades
|
||||
* @param startPaused Should this animation be paused after it is added?
|
||||
*/
|
||||
setUpgradeAnimation(icon: Phaser.GameObjects.Sprite, species: PokemonSpecies, startPaused: boolean = false): void {
|
||||
this.scene.tweens.killTweensOf(icon);
|
||||
// Skip animations if they are disabled
|
||||
if (this.scene.candyUpgradeDisplay === 0 || species.speciesId !== species.getRootSpeciesId(false)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const position = calcSpritePosition(this.genSpecies[species.generation - 1].indexOf(species));
|
||||
icon.y = position.y;
|
||||
|
||||
const tweenChain: Phaser.Types.Tweens.TweenChainBuilderConfig = {
|
||||
targets: icon,
|
||||
loop: -1,
|
||||
// Make the initial bounce a little randomly delayed
|
||||
delay: Utils.randIntRange(0, 50) * 5,
|
||||
loopDelay: 1000,
|
||||
tweens: [
|
||||
{
|
||||
targets: icon,
|
||||
y: position.y - 5,
|
||||
duration: Utils.fixedInt(125),
|
||||
ease: "Cubic.easeOut",
|
||||
yoyo: true
|
||||
},
|
||||
{
|
||||
targets: icon,
|
||||
y: position.y - 3,
|
||||
duration: Utils.fixedInt(150),
|
||||
ease: "Cubic.easeOut",
|
||||
yoyo: true
|
||||
}
|
||||
],};
|
||||
|
||||
const passiveAvailable = this.isPassiveAvailable(species.speciesId);
|
||||
// 'Only Passives' mode
|
||||
if (this.scene.candyUpgradeNotification === 1) {
|
||||
if (passiveAvailable) {
|
||||
this.scene.tweens.chain(tweenChain).paused = startPaused;
|
||||
}
|
||||
// 'On' mode
|
||||
} else if (this.scene.candyUpgradeNotification === 2) {
|
||||
if (passiveAvailable || this.isValueReductionAvailable(species.speciesId)) {
|
||||
this.scene.tweens.chain(tweenChain).paused = startPaused;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visibility of a Candy Upgrade Icon given an index
|
||||
* @param index The UI index of the icon within this generation container
|
||||
*/
|
||||
setUpgradeIcon(index: number): void {
|
||||
const species = this.genSpecies[this.getGenCursorWithScroll()][index];
|
||||
const slotVisible = !!species?.speciesId;
|
||||
|
||||
if (!species // No Pokemon exists at that UI index
|
||||
|| this.scene.candyUpgradeNotification === 0 // Notification setting is 'Off'
|
||||
|| species.speciesId !== species.getRootSpeciesId(false)) { // Pokemon is not the base evolution and can't use candy
|
||||
// Set all icons as hidden and exit early
|
||||
this.candyUpgradeIcon[index].setVisible(false);
|
||||
this.candyUpgradeOverlayIcon[index].setVisible(false);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const passiveAvailable = this.isPassiveAvailable(species.speciesId);
|
||||
// 'Only Passive Unlocks' mode
|
||||
if (this.scene.candyUpgradeNotification === 1) {
|
||||
this.candyUpgradeIcon[index].setVisible(slotVisible && passiveAvailable);
|
||||
this.candyUpgradeOverlayIcon[index].setVisible(slotVisible && this.candyUpgradeIcon[index].visible);
|
||||
|
||||
// 'On' mode
|
||||
} else if (this.scene.candyUpgradeNotification === 2) {
|
||||
this.candyUpgradeIcon[index].setVisible(
|
||||
slotVisible && ( passiveAvailable || this.isValueReductionAvailable(species.speciesId)));
|
||||
this.candyUpgradeOverlayIcon[index].setVisible(slotVisible && this.candyUpgradeIcon[index].visible);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes an {@linkcode CandyUpgradeNotificationChangedEvent} sent when the corresponding setting changes
|
||||
* @param event {@linkcode Event} sent by the callback
|
||||
*/
|
||||
onCandyUpgradeDisplayChanged(event: Event): void {
|
||||
const candyUpgradeDisplayEvent = event as CandyUpgradeNotificationChangedEvent;
|
||||
if (!candyUpgradeDisplayEvent) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through all visible candy icons when set to 'Icon' mode
|
||||
if (this.scene.candyUpgradeDisplay === 0) {
|
||||
this.genSpecies[this.getGenCursorWithScroll()].forEach((_species, s) => {
|
||||
this.setUpgradeIcon(s);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop through all animations when set to 'Animation' mode
|
||||
for (let g = 0; g < this.genSpecies.length; g++) {
|
||||
this.genSpecies[g].forEach((species, s) => {
|
||||
const icon = this.starterSelectGenIconContainers[g].getAt(s) as Phaser.GameObjects.Sprite;
|
||||
|
||||
this.setUpgradeAnimation(icon, species);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
processInput(button: Button): boolean {
|
||||
if (this.blockInput) {
|
||||
return false;
|
||||
@ -948,6 +1148,16 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
});
|
||||
ui.setMode(Mode.STARTER_SELECT);
|
||||
this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, undefined);
|
||||
|
||||
// Update the candy upgrade display
|
||||
if (this.isUpgradeIconEnabled() ) {
|
||||
this.setUpgradeIcon(this.cursor);
|
||||
}
|
||||
if (this.isUpgradeAnimationEnabled()) {
|
||||
const genSpecies = this.genSpecies[this.lastSpecies.generation - 1];
|
||||
this.setUpgradeAnimation(this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(genSpecies.indexOf(this.lastSpecies)), this.lastSpecies, true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -975,6 +1185,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
this.tryUpdateValue(0);
|
||||
ui.setMode(Mode.STARTER_SELECT);
|
||||
this.scene.playSound("buy");
|
||||
|
||||
// If the notification setting is set to 'On', update the candy upgrade display
|
||||
if (this.scene.candyUpgradeNotification === 2) {
|
||||
if (this.isUpgradeIconEnabled() ) {
|
||||
this.setUpgradeIcon(this.cursor);
|
||||
}
|
||||
if (this.isUpgradeAnimationEnabled()) {
|
||||
const genSpecies = this.genSpecies[this.lastSpecies.generation - 1];
|
||||
this.setUpgradeAnimation(this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(genSpecies.indexOf(this.lastSpecies)), this.lastSpecies, true);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@ -1293,6 +1515,24 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
}
|
||||
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);
|
||||
|
||||
// 'Candy Icon' mode
|
||||
if (this.scene.candyUpgradeDisplay === 0) {
|
||||
|
||||
if (!starterColors[speciesId]) {
|
||||
// Default to white if no colors are found
|
||||
starterColors[speciesId] = [ "ffffff", "ffffff" ];
|
||||
}
|
||||
|
||||
// Set the candy colors
|
||||
this.candyUpgradeIcon[s].setTint(argbFromRgba(Utils.rgbHexToRgba(starterColors[speciesId][0])));
|
||||
this.candyUpgradeOverlayIcon[s].setTint(argbFromRgba(Utils.rgbHexToRgba(starterColors[speciesId][1])));
|
||||
|
||||
this.setUpgradeIcon(s);
|
||||
} else if (this.scene.candyUpgradeDisplay === 1) {
|
||||
this.candyUpgradeIcon[s].setVisible(false);
|
||||
this.candyUpgradeOverlayIcon[s].setVisible(false);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
changed = super.setCursor(cursor);
|
||||
@ -1370,6 +1610,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
lastSpeciesIcon.setTexture(this.lastSpecies.getIconAtlasKey(props.formIndex, props.shiny, props.variant), this.lastSpecies.getIconId(props.female, props.formIndex, props.shiny, props.variant));
|
||||
this.checkIconId(lastSpeciesIcon, this.lastSpecies, props.female, props.formIndex, props.shiny, props.variant);
|
||||
this.iconAnimHandler.addOrUpdate(lastSpeciesIcon, PokemonIconAnimMode.NONE);
|
||||
|
||||
// Resume the animation for the previously selected species
|
||||
const speciesIndex = this.genSpecies[this.lastSpecies.generation - 1].indexOf(this.lastSpecies);
|
||||
const icon = this.starterSelectGenIconContainers[this.lastSpecies.generation - 1].getAt(speciesIndex) as Phaser.GameObjects.Sprite;
|
||||
this.scene.tweens.getTweensOf(icon).forEach(tween => tween.resume());
|
||||
}
|
||||
|
||||
this.lastSpecies = species;
|
||||
@ -1434,7 +1679,22 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
|
||||
|
||||
this.pokemonCandyDarknessOverlay.setCrop(0,0,16, candyCropY);
|
||||
}
|
||||
this.iconAnimHandler.addOrUpdate(this.starterSelectGenIconContainers[species.generation - 1].getAt(this.genSpecies[species.generation - 1].indexOf(species)) as Phaser.GameObjects.Sprite, PokemonIconAnimMode.PASSIVE);
|
||||
|
||||
|
||||
// Pause the animation when the species is selected
|
||||
const speciesIndex = this.genSpecies[species.generation - 1].indexOf(species);
|
||||
const icon = this.starterSelectGenIconContainers[species.generation - 1].getAt(speciesIndex) as Phaser.GameObjects.Sprite;
|
||||
|
||||
if (this.isUpgradeAnimationEnabled()) {
|
||||
this.scene.tweens.getTweensOf(icon).forEach(tween => tween.pause());
|
||||
// Reset the position of the icon
|
||||
const position = calcSpritePosition(speciesIndex);
|
||||
icon.x = position.x;
|
||||
icon.y = position.y;
|
||||
}
|
||||
|
||||
// Initiates the small up and down idle animation
|
||||
this.iconAnimHandler.addOrUpdate(icon, PokemonIconAnimMode.PASSIVE);
|
||||
|
||||
let starterIndex = -1;
|
||||
|
||||
|
@ -38,7 +38,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler {
|
||||
|
||||
this.titleContainer.add(this.dailyRunScoreboard);
|
||||
|
||||
this.playerCountLabel = addTextObject(this.scene, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - 90, `? ${i18next.t("menu:playersOnline")}`, TextStyle.MESSAGE, { fontSize: "54px" });
|
||||
this.playerCountLabel = addTextObject(this.scene, (this.scene.game.canvas.width / 6) - 2, (this.scene.game.canvas.height / 6) - 109, `? ${i18next.t("menu:playersOnline")}`, TextStyle.MESSAGE, { fontSize: "54px" });
|
||||
this.playerCountLabel.setOrigin(1, 0);
|
||||
this.titleContainer.add(this.playerCountLabel);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user