Accommodate i8n changes

This commit is contained in:
AJ Fontaine 2024-04-16 20:10:51 -04:00
commit c3e0774a7d
27 changed files with 7936 additions and 1332 deletions

4
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "pokemon-rogue-battle",
"version": "1.0.0",
"version": "1.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "pokemon-rogue-battle",
"version": "1.0.0",
"version": "1.0.1",
"dependencies": {
"@material/material-color-utilities": "^0.2.7",
"crypto-js": "^4.2.0",

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -128,6 +128,7 @@ export default class BattleScene extends SceneBase {
public moveAnimations: boolean = true;
public hpBarSpeed: integer = 0;
public fusionPaletteSwaps: boolean = true;
public gamepadSupport: boolean = true;
public enableTouchControls: boolean = false;
public enableVibration: boolean = false;
@ -198,6 +199,26 @@ export default class BattleScene extends SceneBase {
// (i.e. by holding down a button) at a time
private movementButtonLock: Button;
// using a dualshock controller as a map
private gamepadKeyConfig = {
[Button.UP]: 12, // up
[Button.DOWN]: 13, // down
[Button.LEFT]: 14, // left
[Button.RIGHT]: 15, // right
[Button.SUBMIT]: 17, // touchpad
[Button.ACTION]: 0, // X
[Button.CANCEL]: 1, // O
[Button.MENU]: 9, // options
[Button.CYCLE_SHINY]: 5, // RB
[Button.CYCLE_FORM]: 4, // LB
[Button.CYCLE_GENDER]: 6, // LT
[Button.CYCLE_ABILITY]: 7, // RT
[Button.CYCLE_NATURE]: 2, // square
[Button.SPEED_UP]: 10, // L3
[Button.SLOW_DOWN]: 11 // R3
};
public gamepadButtonStates: boolean[] = new Array(17).fill(false);
public rngCounter: integer = 0;
public rngSeedOverride: string = '';
public rngOffset: integer = 0;
@ -1225,7 +1246,6 @@ export default class BattleScene extends SceneBase {
case Mode.SAVE_SLOT:
case Mode.PARTY:
case Mode.SUMMARY:
case Mode.BIOME_SELECT:
case Mode.STARTER_SELECT:
case Mode.CONFIRM:
case Mode.OPTION_SELECT:
@ -1245,14 +1265,19 @@ export default class BattleScene extends SceneBase {
} else if (this.ui?.getHandler() instanceof StarterSelectUiHandler) {
if (this.buttonJustPressed(Button.CYCLE_SHINY)) {
inputSuccess = this.ui.processInput(Button.CYCLE_SHINY);
this.setLastProcessedMovementTime(Button.CYCLE_SHINY);
} else if (this.buttonJustPressed(Button.CYCLE_FORM)) {
inputSuccess = this.ui.processInput(Button.CYCLE_FORM);
this.setLastProcessedMovementTime(Button.CYCLE_FORM);
} else if (this.buttonJustPressed(Button.CYCLE_GENDER)) {
inputSuccess = this.ui.processInput(Button.CYCLE_GENDER);
this.setLastProcessedMovementTime(Button.CYCLE_GENDER);
} else if (this.buttonJustPressed(Button.CYCLE_ABILITY)) {
inputSuccess = this.ui.processInput(Button.CYCLE_ABILITY);
this.setLastProcessedMovementTime(Button.CYCLE_ABILITY);
} else if (this.buttonJustPressed(Button.CYCLE_NATURE)) {
inputSuccess = this.ui.processInput(Button.CYCLE_NATURE);
this.setLastProcessedMovementTime(Button.CYCLE_NATURE);
} else
return;
} else if (this.buttonJustPressed(Button.SPEED_UP)) {
@ -1273,8 +1298,29 @@ export default class BattleScene extends SceneBase {
navigator.vibrate(vibrationLength || 10);
}
/**
* gamepadButtonJustDown returns true if @param button has just been pressed down
* or not. It will only return true once, until the key is released and pressed down
* again.
*/
gamepadButtonJustDown(button: Phaser.Input.Gamepad.Button) : boolean {
if (!button || !this.gamepadSupport)
return false;
let ret = false;
if (button.pressed) {
if (!this.gamepadButtonStates[button.index])
ret = true;
this.gamepadButtonStates[button.index] = true;
} else
this.gamepadButtonStates[button.index] = false;
return ret;
}
buttonJustPressed(button: Button): boolean {
return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustDown(k));
const gamepad = this.input.gamepad?.gamepads[0];
return this.buttonKeys[button].some(k => Phaser.Input.Keyboard.JustDown(k)) || this.gamepadButtonJustDown(gamepad?.buttons[this.gamepadKeyConfig[button]]);
}
/**
@ -1286,7 +1332,7 @@ export default class BattleScene extends SceneBase {
if (this.movementButtonLock !== null && this.movementButtonLock !== button) {
return false;
}
if (this.buttonKeys[button].every(k => k.isUp)) {
if (this.buttonKeys[button].every(k => k.isUp) && this.gamepadButtonStates.every(b => b == false)) {
this.movementButtonLock = null;
return false;
}
@ -1606,8 +1652,9 @@ export default class BattleScene extends SceneBase {
return Math.floor(moneyValue / 10) * 10;
}
addModifier(modifier: Modifier, ignoreUpdate?: boolean, playSound?: boolean, virtual?: boolean, instant?: boolean): Promise<void> {
addModifier(modifier: Modifier, ignoreUpdate?: boolean, playSound?: boolean, virtual?: boolean, instant?: boolean): Promise<boolean> {
return new Promise(resolve => {
let success = false;
const soundName = modifier.type.soundName;
this.validateAchvs(ModifierAchv, modifier);
const modifiersToRemove: PersistentModifier[] = [];
@ -1617,20 +1664,20 @@ export default class BattleScene extends SceneBase {
modifiersToRemove.push(...(this.findModifiers(m => m instanceof TerastallizeModifier && m.pokemonId === modifier.pokemonId)));
if ((modifier as PersistentModifier).add(this.modifiers, !!virtual, this)) {
if (modifier instanceof PokemonFormChangeItemModifier || modifier instanceof TerastallizeModifier)
modifier.apply([ this.getPokemonById(modifier.pokemonId), true ]);
success = modifier.apply([ this.getPokemonById(modifier.pokemonId), true ]);
if (playSound && !this.sound.get(soundName))
this.playSound(soundName);
} else if (!virtual) {
const defaultModifierType = getDefaultModifierTypeForTier(modifier.type.tier);
this.queueMessage(`The stack for this item is full.\n You will receive ${defaultModifierType.name} instead.`, null, true);
return this.addModifier(defaultModifierType.newModifier(), ignoreUpdate, playSound, false, instant).then(() => resolve());
return this.addModifier(defaultModifierType.newModifier(), ignoreUpdate, playSound, false, instant).then(success => resolve(success));
}
for (let rm of modifiersToRemove)
this.removeModifier(rm);
if (!ignoreUpdate && !virtual)
return this.updateModifiers(true, instant).then(() => resolve());
return this.updateModifiers(true, instant).then(() => resolve(success));
} else if (modifier instanceof ConsumableModifier) {
if (playSound && !this.sound.get(soundName))
this.playSound(soundName);
@ -1653,19 +1700,26 @@ export default class BattleScene extends SceneBase {
if (modifier.shouldApply(args)) {
const result = modifier.apply(args);
if (result instanceof Promise)
modifierPromises.push(result);
modifierPromises.push(result.then(s => success ||= s));
else
success ||= result;
}
}
return Promise.allSettled([this.party.map(p => p.updateInfo(instant)), ...modifierPromises]).then(() => resolve());
return Promise.allSettled([this.party.map(p => p.updateInfo(instant)), ...modifierPromises]).then(() => resolve(success));
} else {
const args = [ this ];
if (modifier.shouldApply(args))
modifier.apply(args);
if (modifier.shouldApply(args)) {
const result = modifier.apply(args);
if (result instanceof Promise) {
return result.then(success => resolve(success));
} else
success ||= result;
}
}
}
resolve();
resolve(success);
});
}

View File

@ -212,6 +212,8 @@ export default class Battle {
}
randSeedInt(scene: BattleScene, range: integer, min: integer = 0): integer {
if (range <= 1)
return min;
let ret: integer;
const tempRngCounter = scene.rngCounter;
const tempSeedOverride = scene.rngSeedOverride;

View File

@ -1193,6 +1193,8 @@ export class PostSummonFormChangeAbAttr extends PostSummonAbAttr {
export class TraceAbAttr extends PostSummonAbAttr {
applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean {
const targets = pokemon.getOpponents();
if (!targets.length)
return false;
let target: Pokemon;
if (targets.length > 1)
pokemon.scene.executeWithSeedOffset(() => target = Utils.randSeedItem(targets), pokemon.scene.currentBattle.waveIndex);
@ -2262,7 +2264,7 @@ export function initAbilities() {
.attr(UnswappableAbilityAbAttr)
.ignorable(),
new Ability(Abilities.LEVITATE, "Levitate", "By floating in the air, the Pokémon receives full immunity to all Ground-type moves.", 3)
.attr(TypeImmunityAbAttr, Type.GROUND, (pokemon: Pokemon) => !pokemon.getTag(BattlerTagType.IGNORE_FLYING) && !pokemon.scene.arena.getTag(ArenaTagType.GRAVITY))
.attr(TypeImmunityAbAttr, Type.GROUND, (pokemon: Pokemon) => !pokemon.getTag(BattlerTagType.IGNORE_FLYING) && !pokemon.scene.arena.getTag(ArenaTagType.GRAVITY) && !pokemon.getTag(BattlerTagType.GROUNDED))
.ignorable(),
new Ability(Abilities.EFFECT_SPORE, "Effect Spore", "Contact with the Pokémon may inflict poison, sleep, or paralysis on its attacker.", 3)
.attr(PostDefendContactApplyStatusEffectAbAttr, 10, StatusEffect.POISON, StatusEffect.PARALYSIS, StatusEffect.SLEEP),
@ -2402,10 +2404,10 @@ export function initAbilities() {
.attr(MovePowerBoostAbAttr, (user, target, move) => user.gender !== Gender.GENDERLESS && target.gender !== Gender.GENDERLESS && user.gender !== target.gender, 0.75),
new Ability(Abilities.STEADFAST, "Steadfast", "The Pokémon's determination boosts the Speed stat each time the Pokémon flinches.", 4)
.attr(FlinchStatChangeAbAttr, BattleStat.SPD, 1),
new Ability(Abilities.SNOW_CLOAK, "Snow Cloak", "Boosts evasiveness in a hailstorm.", 4)
new Ability(Abilities.SNOW_CLOAK, "Snow Cloak", "Boosts the Pokémon's evasiveness in snow.", 4)
.attr(BattleStatMultiplierAbAttr, BattleStat.EVA, 1.2)
.attr(BlockWeatherDamageAttr, WeatherType.HAIL)
.condition(getWeatherCondition(WeatherType.HAIL))
.condition(getWeatherCondition(WeatherType.HAIL, WeatherType.SNOW))
.ignorable(),
new Ability(Abilities.GLUTTONY, "Gluttony", "Makes the Pokémon eat a held Berry when its HP drops to half or less, which is sooner than usual.", 4)
.attr(ReduceBerryUseThresholdAbAttr),
@ -2483,14 +2485,15 @@ export function initAbilities() {
.attr(RedirectTypeMoveAbAttr, Type.WATER)
.attr(TypeImmunityStatChangeAbAttr, Type.WATER, BattleStat.SPATK, 1)
.ignorable(),
new Ability(Abilities.ICE_BODY, "Ice Body", "The Pokémon gradually regains HP in a hailstorm.", 4)
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.HAIL),
new Ability(Abilities.ICE_BODY, "Ice Body", "The Pokémon gradually regains HP in snow.", 4)
.attr(BlockWeatherDamageAttr, WeatherType.HAIL)
.attr(PostWeatherLapseHealAbAttr, 1, WeatherType.HAIL, WeatherType.SNOW),
new Ability(Abilities.SOLID_ROCK, "Solid Rock", "Reduces the power of supereffective attacks taken.", 4)
.attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type) >= 2, 0.75)
.ignorable(),
new Ability(Abilities.SNOW_WARNING, "Snow Warning", "The Pokémon summons a hailstorm when it enters a battle.", 4)
.attr(PostSummonWeatherChangeAbAttr, WeatherType.HAIL)
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.HAIL),
new Ability(Abilities.SNOW_WARNING, "Snow Warning", "The Pokémon makes it snow when it enters a battle.", 4)
.attr(PostSummonWeatherChangeAbAttr, WeatherType.SNOW)
.attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.SNOW),
new Ability(Abilities.HONEY_GATHER, "Honey Gather (N)", "The Pokémon may gather Honey after a battle.", 4),
new Ability(Abilities.FRISK, "Frisk (N)", "When it enters a battle, the Pokémon can check an opposing Pokémon's held item.", 4),
new Ability(Abilities.RECKLESS, "Reckless", "Powers up moves that have recoil damage.", 4)
@ -2692,9 +2695,9 @@ export function initAbilities() {
new Ability(Abilities.STEELWORKER, "Steelworker", "Powers up Steel-type moves.", 7)
.attr(MoveTypePowerBoostAbAttr, Type.STEEL),
new Ability(Abilities.BERSERK, "Berserk (N)", "Boosts the Pokémon's Sp. Atk stat when it takes a hit that causes its HP to become half or less.", 7),
new Ability(Abilities.SLUSH_RUSH, "Slush Rush", "Boosts the Pokémon's Speed stat in a hailstorm.", 7)
new Ability(Abilities.SLUSH_RUSH, "Slush Rush", "Boosts the Pokémon's Speed stat in snow.", 7)
.attr(BattleStatMultiplierAbAttr, BattleStat.SPD, 2)
.condition(getWeatherCondition(WeatherType.HAIL)),
.condition(getWeatherCondition(WeatherType.HAIL, WeatherType.SNOW)),
new Ability(Abilities.LONG_REACH, "Long Reach", "The Pokémon uses its moves without making contact with the target.", 7)
.attr(IgnoreContactAbAttr),
new Ability(Abilities.LIQUID_VOICE, "Liquid Voice", "All sound-based moves become Water-type moves.", 7)

View File

@ -89,6 +89,7 @@ export enum CommonAnim {
RAIN,
SANDSTORM,
HAIL,
SNOW,
WIND,
HEAVY_RAIN,
HARSH_SUN,

View File

@ -1077,6 +1077,7 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
return new TerrainHighestStatBoostTag(tagType, Abilities.QUARK_DRIVE, TerrainType.ELECTRIC);
case BattlerTagType.FLYING:
case BattlerTagType.UNDERGROUND:
case BattlerTagType.UNDERWATER:
case BattlerTagType.HIDDEN:
return new HideSpriteTag(tagType, turnCount, sourceMove);
case BattlerTagType.FIRE_BOOST:
@ -1093,6 +1094,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
return new BattlerTag(BattlerTagType.BYPASS_SLEEP, BattlerTagLapseType.TURN_END, turnCount, sourceMove);
case BattlerTagType.IGNORE_FLYING:
return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, turnCount, sourceMove);
case BattlerTagType.GROUNDED:
return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, turnCount - 1, sourceMove);
case BattlerTagType.SALT_CURED:
return new SaltCuredTag(sourceId);
case BattlerTagType.NONE:
@ -1100,3 +1103,4 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);
}
}

View File

@ -44,7 +44,7 @@ export const biomeLinks: BiomeLinks = {
[Biome.SEA]: [ Biome.SEABED, Biome.ICE_CAVE ],
[Biome.SWAMP]: [ Biome.GRAVEYARD, Biome.TALL_GRASS ],
[Biome.BEACH]: [ Biome.SEA, [ Biome.ISLAND, 4 ] ],
[Biome.LAKE]: [ Biome.BEACH, Biome.SWAMP ],
[Biome.LAKE]: [ Biome.BEACH, Biome.SWAMP, Biome.CONSTRUCTION_SITE ],
[Biome.SEABED]: [ Biome.CAVE, [ Biome.VOLCANO, 4 ] ],
[Biome.MOUNTAIN]: [ Biome.VOLCANO, [ Biome.WASTELAND, 3 ] ],
[Biome.BADLANDS]: [ Biome.DESERT, Biome.MOUNTAIN ],
@ -66,9 +66,9 @@ export const biomeLinks: BiomeLinks = {
[Biome.FAIRY_CAVE]: [ Biome.ICE_CAVE, [ Biome.SPACE, 3 ] ],
[Biome.TEMPLE]: [ Biome.SWAMP, [ Biome.RUINS, 3 ] ],
[Biome.METROPOLIS]: Biome.SLUM,
[Biome.SNOWY_FOREST]: Biome.LAKE,
[Biome.SNOWY_FOREST]: [ Biome.FOREST, Biome.LAKE, Biome.MOUNTAIN ],
[Biome.ISLAND]: Biome.SEA,
[Biome.LABORATORY]: Biome.METROPOLIS
[Biome.LABORATORY]: Biome.CONSTRUCTION_SITE
};
export const biomeDepths: BiomeDepths = {};

View File

@ -38,6 +38,7 @@ export enum BattlerTagType {
QUARK_DRIVE = "QUARK_DRIVE",
FLYING = "FLYING",
UNDERGROUND = "UNDERGROUND",
UNDERWATER = "UNDERWATER",
HIDDEN = "HIDDEN",
FIRE_BOOST = "FIRE_BOOST",
CRIT_BOOST = "CRIT_BOOST",
@ -46,5 +47,6 @@ export enum BattlerTagType {
IGNORE_ACCURACY = "IGNORE_ACCURACY",
BYPASS_SLEEP = "BYPASS_SLEEP",
IGNORE_FLYING = "IGNORE_FLYING",
GROUNDED = "GROUNDED",
SALT_CURED = "SALT_CURED"
}

File diff suppressed because it is too large Load Diff

View File

@ -968,8 +968,8 @@ export const pokemonEvolutions: PokemonEvolutions = {
new SpeciesEvolution(Species.COSMOEM, 43, null, null)
],
[Species.COSMOEM]: [
new SpeciesEvolution(Species.SOLGALEO, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.biomeType !== Biome.SPACE && p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), null),
new SpeciesEvolution(Species.LUNALA, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.biomeType !== Biome.SPACE && p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), null)
new SpeciesEvolution(Species.SOLGALEO, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), null),
new SpeciesEvolution(Species.LUNALA, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), null)
],
[Species.MELTAN]: [
new SpeciesEvolution(Species.MELMETAL, 48, null, null)

View File

@ -15,6 +15,7 @@ splashMessages.push(...[
'Now with 33% More Salt!',
'Infinite Fusion at Home!',
'Broken Egg Moves!',
'Magnificent!',
'Mubstitute!',
'That\'s Crazy!',
'Orance Juice!',

View File

@ -14,6 +14,7 @@ export enum WeatherType {
RAIN,
SANDSTORM,
HAIL,
SNOW,
FOG,
HEAVY_RAIN,
HARSH_SUN,
@ -127,6 +128,8 @@ export function getWeatherStartMessage(weatherType: WeatherType): string {
return 'A sandstorm brewed!';
case WeatherType.HAIL:
return 'It started to hail!';
case WeatherType.SNOW:
return 'It started to snow!';
case WeatherType.FOG:
return 'A thick fog emerged!'
case WeatherType.HEAVY_RAIN:
@ -150,6 +153,8 @@ export function getWeatherLapseMessage(weatherType: WeatherType): string {
return 'The sandstorm rages.';
case WeatherType.HAIL:
return 'Hail continues to fall.';
case WeatherType.SNOW:
return 'The snow is falling down.';
case WeatherType.FOG:
return 'The fog continues.';
case WeatherType.HEAVY_RAIN:
@ -184,6 +189,8 @@ export function getWeatherClearMessage(weatherType: WeatherType): string {
return 'The sandstorm subsided.';
case WeatherType.HAIL:
return 'The hail stopped.';
case WeatherType.SNOW:
return 'The snow stopped.';
case WeatherType.FOG:
return 'The fog disappeared.'
case WeatherType.HEAVY_RAIN:
@ -292,11 +299,6 @@ export function getRandomWeatherType(arena: any /* Importing from arena causes a
{ weatherType: WeatherType.RAIN, weight: 1 }
];
break;
case Biome.MOUNTAIN:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 1 }
];
break;
case Biome.BADLANDS:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 8 },
@ -314,6 +316,8 @@ export function getRandomWeatherType(arena: any /* Importing from arena causes a
break;
case Biome.ICE_CAVE:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 3 },
{ weatherType: WeatherType.SNOW, weight: 4 },
{ weatherType: WeatherType.HAIL, weight: 1 }
];
break;
@ -334,20 +338,25 @@ export function getRandomWeatherType(arena: any /* Importing from arena causes a
{ weatherType: WeatherType.FOG, weight: 1 }
];
break;
case Biome.RUINS:
case Biome.JUNGLE:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 4 }
{ weatherType: WeatherType.NONE, weight: 8 },
{ weatherType: WeatherType.RAIN, weight: 2 }
];
break;
case Biome.WASTELAND:
case Biome.SNOWY_FOREST:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 4 }
{ weatherType: WeatherType.SNOW, weight: 7 },
{ weatherType: WeatherType.HAIL, weight: 1 }
];
break;
case Biome.ABYSS:
case Biome.ISLAND:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 4 }
{ weatherType: WeatherType.NONE, weight: 5 },
{ weatherType: WeatherType.RAIN, weight: 1 },
];
if (hasSun)
weatherPool.push({ weatherType: WeatherType.SUNNY, weight: 2 });
break;
}

View File

@ -28,7 +28,7 @@ import { Biome } from "../data/enums/biome";
import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from '../data/ability';
import { Abilities } from "#app/data/enums/abilities";
import PokemonData from '../system/pokemon-data';
import { BattlerIndex } from '../battle';
import Battle, { BattlerIndex } from '../battle';
import { BattleSpec } from "../enums/battle-spec";
import { Mode } from '../ui/ui';
import PartyUiHandler, { PartyOption, PartyUiMode } from '../ui/party-ui-handler';
@ -523,6 +523,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
ret >>= 1;
break;
case Stat.DEF:
if (this.isOfType(Type.ICE) && this.scene.arena.weather?.weatherType === WeatherType.SNOW)
ret *= 1.5;
break;
case Stat.SPATK:
break;
@ -534,7 +536,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (this.getTag(BattlerTagType.SLOW_START))
ret >>= 1;
if (this.status && this.status.effect === StatusEffect.PARALYSIS)
ret >>= 2;
ret >>= 1;
break;
}
@ -692,7 +694,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
}
if (forDefend && (this.getTag(BattlerTagType.IGNORE_FLYING) || this.scene.arena.getTag(ArenaTagType.GRAVITY))) {
if (forDefend && (this.getTag(BattlerTagType.IGNORE_FLYING) || this.scene.arena.getTag(ArenaTagType.GRAVITY) || this.getTag(BattlerTagType.GROUNDED))) {
const flyingIndex = types.indexOf(Type.FLYING);
if (flyingIndex > -1)
types.splice(flyingIndex, 1);
@ -1212,7 +1214,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
if (source.getTag(BattlerTagType.CRIT_BOOST))
critLevel.value += 2;
const critChance = Math.ceil(16 / Math.pow(2, critLevel.value));
const critChance = [24, 8, 2, 1][Math.max(0, Math.min(critLevel.value, 3))];
isCritical = !source.getTag(BattlerTagType.NO_CRIT) && (critChance === 1 || !this.scene.randBattleSeedInt(critChance));
if (isCritical) {
const blockCrit = new Utils.BooleanHolder(false);
@ -1298,6 +1300,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
applyMoveAttrs(ModifiedDamageAttr, source, this, move, damage);
if (power.value === 0) {
damage.value = 0;
}
console.log('damage', damage.value, move.name, power.value, sourceAtk, targetDef);
if (damage.value) {

View File

@ -6,6 +6,7 @@ import { getBiomeHasProps } from "./field/arena";
import CacheBustedLoaderPlugin from "./plugins/cache-busted-loader-plugin";
import { SceneBase } from "./scene-base";
import { WindowVariant, getWindowVariantSuffix } from "./ui/ui-theme";
import { isMobile } from "./touch-controls";
import * as Utils from "./utils";
export class LoadingScene extends SceneBase {
@ -23,7 +24,8 @@ export class LoadingScene extends SceneBase {
this.load['cacheBuster'] = buildIdMatch[1];
}
this.load.video('intro_dark', 'images/intro_dark.mp4', true);
if (!isMobile())
this.load.video('intro_dark', 'images/intro_dark.mp4', true);
this.loadImage('loading_bg', 'arenas');
this.loadImage('logo', '');
@ -252,6 +254,8 @@ export class LoadingScene extends SceneBase {
}
loadLoadingScreen() {
const mobile = isMobile();
const loadingGraphics: any[] = [];
const bg = this.add.image(0, 0, '');
@ -316,7 +320,8 @@ export class LoadingScene extends SceneBase {
loadingGraphics.push(bg, graphics, progressBar, progressBox, logo, percentText, assetText);
loadingGraphics.map(g => g.setVisible(false));
if (!mobile)
loadingGraphics.map(g => g.setVisible(false));
const destroyLoadingAssets = () => {
intro.destroy();
@ -345,9 +350,13 @@ export class LoadingScene extends SceneBase {
break;
case 'loading_bg':
bg.setTexture('loading_bg');
if (mobile)
bg.setVisible(true);
break;
case 'logo':
logo.setTexture('logo');
if (mobile)
logo.setVisible(true);
break;
}
});

3687
src/locales/en/move.ts Normal file

File diff suppressed because it is too large Load Diff

6
src/locales/fr/move.ts Normal file
View File

@ -0,0 +1,6 @@
export const move = {
"ember": {
name: "Flammèche",
effect: "Flammèche inflige des dégâts et a des chances de brûler le Pokémon adverse."
},
} as const;

View File

@ -44,6 +44,7 @@ const config: Phaser.Types.Core.GameConfig = {
touch: {
target: 'app'
},
gamepad: true
},
dom: {
createContainer: true

View File

@ -1001,9 +1001,11 @@ export class PokemonHpRestoreModifier extends ConsumablePokemonModifier {
if (this.fainted || this.healStatus)
pokemon.resetStatus();
pokemon.hp = Math.min(pokemon.hp + Math.max(Math.ceil(Math.max(Math.floor((this.restorePercent * 0.01) * pokemon.getMaxHp()), restorePoints)), 1), pokemon.getMaxHp());
return true;
}
return true;
return false;
}
}

View File

@ -16,7 +16,7 @@ import EvolutionSceneHandler from "./ui/evolution-scene-handler";
import { EvolutionPhase } from "./evolution-phase";
import { Phase } from "./phase";
import { BattleStat, getBattleStatLevelChangeDescription, getBattleStatName } from "./data/battle-stat";
import { biomeLinks } from "./data/biomes";
import { biomeLinks, getBiomeName } from "./data/biomes";
import { Biome } from "./data/enums/biome";
import { ModifierTier } from "./modifier/modifier-tier";
import { FusePokemonModifierType, ModifierPoolType, ModifierType, ModifierTypeFunc, ModifierTypeOption, PokemonModifierType, PokemonMoveModifierType, RememberMoveModifierType, TmModifierType, getDailyRunStarterModifiers, getEnemyBuffModifierForWave, getModifierType, getPlayerModifierTypeOptions, getPlayerShopModifierTypeOptionsForWave, modifierTypes, regenerateModifierPoolThresholds } from "./modifier/modifier-type";
@ -1034,9 +1034,26 @@ export class SelectBiomePhase extends BattlePhase {
.map(b => !Array.isArray(b) ? b : b[0]);
}, this.scene.currentBattle.waveIndex);
if (biomes.length > 1 && this.scene.findModifier(m => m instanceof MapModifier)) {
this.scene.ui.setMode(Mode.BIOME_SELECT, currentBiome, (biomeIndex: integer) => {
this.scene.ui.setMode(Mode.MESSAGE);
setNextBiome(biomes[biomeIndex]);
let biomeChoices: Biome[];
this.scene.executeWithSeedOffset(() => {
biomeChoices = (!Array.isArray(biomeLinks[currentBiome])
? [ biomeLinks[currentBiome] as Biome ]
: biomeLinks[currentBiome] as (Biome | [Biome, integer])[])
.filter((b, i) => !Array.isArray(b) || !Utils.randSeedInt(b[1]))
.map(b => Array.isArray(b) ? b[0] : b);
}, this.scene.currentBattle.waveIndex);
const biomeSelectItems = biomeChoices.map(b => {
return {
label: getBiomeName(b),
handler: () => {
this.scene.ui.setMode(Mode.MESSAGE);
setNextBiome(b);
}
};
});
this.scene.ui.setMode(Mode.OPTION_SELECT, {
options: biomeSelectItems,
delay: 1000
});
} else
setNextBiome(biomes[Utils.randSeedInt(biomes.length)]);
@ -4162,10 +4179,15 @@ export class SelectModifierPhase extends BattlePhase {
const applyModifier = (modifier: Modifier, playSound: boolean = false) => {
const result = this.scene.addModifier(modifier, false, playSound);
if (cost) {
this.scene.money -= cost;
this.scene.updateMoneyText();
this.scene.playSound('buy');
(this.scene.ui.getHandler() as ModifierSelectUiHandler).updateCostText();
result.then(success => {
if (success) {
this.scene.money -= cost;
this.scene.updateMoneyText();
this.scene.playSound('buy');
(this.scene.ui.getHandler() as ModifierSelectUiHandler).updateCostText();
} else
this.scene.ui.playError();
});
} else {
const doEnd = () => {
this.scene.ui.clearText();
@ -4251,7 +4273,7 @@ export class SelectModifierPhase extends BattlePhase {
return getPlayerModifierTypeOptions(modifierCount, this.scene.getParty(), this.scene.lockModifierTiers ? this.modifierTiers : undefined);
}
addModifier(modifier: Modifier): Promise<void> {
addModifier(modifier: Modifier): Promise<boolean> {
return this.scene.addModifier(modifier, false, true);
}
}

View File

@ -2,6 +2,9 @@ import i18next from 'i18next';
import { menu as enMenu } from '../locales/en/menu';
import { menu as itMenu } from '../locales/it/menu';
import { move as enMove } from '../locales/en/move';
import { move as frMove } from '../locales/fr/move';
const DEFAULT_LANGUAGE_OVERRIDE = '';
/**
@ -26,9 +29,13 @@ i18next.init({
resources: {
en: {
menu: enMenu,
move: enMove,
},
it: {
menu: itMenu,
},
fr: {
move: frMove,
}
},
});
@ -38,6 +45,7 @@ declare module 'i18next' {
interface CustomTypeOptions {
resources: {
menu: typeof enMenu;
move: typeof enMove;
};
}
}

View File

@ -184,7 +184,7 @@ const systemShortKeys = {
ivs: '$i',
moveset: '$m',
eggMoves: '$em',
candyCount: '$cc',
candyCount: '$x',
passive: '$p',
valueReduction: '$vr'
};

View File

@ -19,6 +19,7 @@ export enum Setting {
HP_Bar_Speed = "HP_BAR_SPEED",
Fusion_Palette_Swaps = "FUSION_PALETTE_SWAPS",
Player_Gender = "PLAYER_GENDER",
Gamepad_Support = "GAMEPAD_SUPPORT",
Touch_Controls = "TOUCH_CONTROLS",
Vibration = "VIBRATION"
}
@ -47,6 +48,7 @@ export const settingOptions: SettingOptions = {
[Setting.HP_Bar_Speed]: [ 'Normal', 'Fast', 'Faster', 'Instant' ],
[Setting.Fusion_Palette_Swaps]: [ 'Off', 'On' ],
[Setting.Player_Gender]: [ 'Boy', 'Girl' ],
[Setting.Gamepad_Support]: [ 'Auto', 'Disabled' ],
[Setting.Touch_Controls]: [ 'Auto', 'Disabled' ],
[Setting.Vibration]: [ 'Auto', 'Disabled' ]
};
@ -67,6 +69,7 @@ export const settingDefaults: SettingDefaults = {
[Setting.HP_Bar_Speed]: 0,
[Setting.Fusion_Palette_Swaps]: 1,
[Setting.Player_Gender]: 0,
[Setting.Gamepad_Support]: 0,
[Setting.Touch_Controls]: 0,
[Setting.Vibration]: 0
};
@ -130,6 +133,9 @@ export function setSetting(scene: BattleScene, setting: Setting, value: integer)
} else
return false;
break;
case Setting.Gamepad_Support:
scene.gamepadSupport = settingOptions[setting][value] !== 'Disabled';
break;
case Setting.Touch_Controls:
scene.enableTouchControls = settingOptions[setting][value] !== 'Disabled' && hasTouchscreen();
const touchControls = document.getElementById('touchControls');

View File

@ -1,134 +0,0 @@
import BattleScene, { Button } from "../battle-scene";
import { biomeLinks, getBiomeName } from "../data/biomes";
import { Biome } from "../data/enums/biome";
import { addTextObject, TextStyle } from "./text";
import { Mode } from "./ui";
import UiHandler from "./ui-handler";
import * as Utils from "../utils";
import { addWindow } from "./ui-theme";
export default class BiomeSelectUiHandler extends UiHandler {
private biomeSelectContainer: Phaser.GameObjects.Container;
private biomeSelectBg: Phaser.GameObjects.NineSlice;
private biomesText: Phaser.GameObjects.Text;
private biomeChoices: Biome[];
private cursorObj: Phaser.GameObjects.Image;
private blockInput: boolean;
private biomeSelectHandler: Function;
constructor(scene: BattleScene) {
super(scene, Mode.BIOME_SELECT);
}
setup() {
const ui = this.getUi();
this.biomeSelectContainer = this.scene.add.container((this.scene.game.canvas.width / 6) - 97, -49);
this.biomeSelectContainer.setVisible(false);
ui.add(this.biomeSelectContainer);
this.biomeSelectBg = addWindow(this.scene, 0, 0, 96, 32);
this.biomeSelectBg.setOrigin(0, 1);
this.biomeSelectContainer.add(this.biomeSelectBg);
this.biomesText = addTextObject(this.scene, 0, 0, '', TextStyle.WINDOW, { maxLines: 3 });
this.biomesText.setLineSpacing(12);
this.biomeSelectContainer.add(this.biomesText);
}
show(args: any[]): boolean {
if (args.length >= 2 && typeof(args[0]) === 'number' && args[1] instanceof Function) {
super.show(args);
this.scene.executeWithSeedOffset(() => {
this.biomeChoices = (!Array.isArray(biomeLinks[args[0]])
? [ biomeLinks[args[0]] as Biome ]
: biomeLinks[args[0]] as (Biome | [Biome, integer])[])
.filter((b, i) => !Array.isArray(b) || !Utils.randSeedInt(b[1]))
.map(b => Array.isArray(b) ? b[0] : b);
}, this.scene.currentBattle.waveIndex);
if (this.biomeChoices.length <= 1)
return;
this.biomeSelectBg.height = (this.biomeChoices.length + 1) * 16;
this.biomesText.setText(this.biomeChoices.map(b => getBiomeName(b)).join('\n'));
this.biomesText.setPositionRelative(this.biomeSelectBg, 16, 9);
this.biomeSelectHandler = args[1] as Function;
this.biomeSelectContainer.setVisible(true);
this.setCursor(0);
this.blockInput = true;
this.biomesText.setAlpha(0.5);
this.scene.time.delayedCall(Utils.fixedInt(1000), () => {
this.blockInput = false;
this.biomesText.setAlpha(1);
});
}
return true;
}
processInput(button: Button): boolean {
const ui = this.getUi();
let success = false;
if (button === Button.ACTION || button === Button.CANCEL) {
if (this.blockInput)
return false;
success = true;
const originalBiomeSelectHandler = this.biomeSelectHandler;
this.biomeSelectHandler = null;
originalBiomeSelectHandler(this.cursor);
this.clear();
} else {
switch (button) {
case Button.UP:
if (this.cursor)
success = this.setCursor(this.cursor - 1);
break;
case Button.DOWN:
if (this.cursor < this.biomeChoices.length - 1)
success = this.setCursor(this.cursor + 1);
break;
}
}
if (success)
ui.playSelect();
return success;
}
setCursor(cursor: integer): boolean {
const ret = super.setCursor(cursor);
if (!this.cursorObj) {
this.cursorObj = this.scene.add.image(0, 0, 'cursor');
this.biomeSelectContainer.add(this.cursorObj);
}
this.cursorObj.setPositionRelative(this.biomeSelectBg, 12, 17 + 16 * this.cursor);
return ret;
}
clear() {
super.clear();
this.biomeSelectContainer.setVisible(false);
this.biomeSelectHandler = null;
this.eraseCursor();
}
eraseCursor() {
if (this.cursorObj)
this.cursorObj.destroy();
this.cursorObj = null;
}
}

View File

@ -1304,6 +1304,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
this.dexAttrCursor = 0n;
this.natureCursor = -1;
if (species?.forms?.find(f => f.formKey === 'female')) {
if (female !== undefined)
formIndex = female ? 1 : 0;
else if (formIndex !== undefined)
female = formIndex === 1;
}
if (species) {
this.dexAttrCursor |= (shiny !== undefined ? !shiny : !(shiny = oldProps.shiny)) ? DexAttr.NON_SHINY : DexAttr.SHINY;
this.dexAttrCursor |= (female !== undefined ? !female : !(female = oldProps.female)) ? DexAttr.MALE : DexAttr.FEMALE;

View File

@ -11,7 +11,6 @@ import BallUiHandler from './ball-ui-handler';
import SummaryUiHandler from './summary-ui-handler';
import StarterSelectUiHandler from './starter-select-ui-handler';
import EvolutionSceneHandler from './evolution-scene-handler';
import BiomeSelectUiHandler from './biome-select-ui-handler';
import TargetSelectUiHandler from './target-select-ui-handler';
import SettingsUiHandler from './settings-ui-handler';
import { TextStyle, addTextObject } from './text';
@ -47,7 +46,6 @@ export enum Mode {
SAVE_SLOT,
PARTY,
SUMMARY,
BIOME_SELECT,
STARTER_SELECT,
EVOLUTION_SCENE,
EGG_HATCH_SCENE,
@ -127,7 +125,6 @@ export default class UI extends Phaser.GameObjects.Container {
new SaveSlotSelectUiHandler(scene),
new PartyUiHandler(scene),
new SummaryUiHandler(scene),
new BiomeSelectUiHandler(scene),
new StarterSelectUiHandler(scene),
new EvolutionSceneHandler(scene),
new EggHatchSceneHandler(scene),