Compare commits

...

12 Commits

Author SHA1 Message Date
Matthew Olker
751a3d1e49 add names to battle info ui objects and solve key already exists warning for starter select 2024-05-24 17:23:49 -04:00
Jon Studders
d01cd98d06
Fixed champion ribbon boss segments. (#1334) 2024-05-24 16:07:57 -05:00
Douglas Marchione de Souza
0d6145263f
Acrobatics does not treat vitamins as held items (#718)
* Changed the move Acrobatics so it doesn't include
non-held items on it's damage calculations

* Changed exception so it includes within_party
items, and updated the move description

* Small typo e_e'

* Change Description of Move

---------

Co-authored-by: Benjamin Odom <bennybroseph@gmail.com>
2024-05-24 15:49:23 -05:00
LaukkaE
0309fde7e8
Fix Aftermath not working (#1209) 2024-05-24 15:35:45 -05:00
Jakub Hanko
a48ba9864d
Implement Destiny Bond move (#1104)
* Use getBattleStat instead of getStat in BattleStatRatioPowerAttr

* Change unnecessary let into const

* Refactor BattleStatRatioPowerAttr into two distinct classes

* Add TSDoc for the new classes

* Implementation of Destiny Bond

* Add TSDocs

* Make the move fail in boss battles

* Fix boss immunity and ally fainting

* Update docs

* Add doc of return value of tag lapse

* Fix ESLint
2024-05-24 15:23:23 -05:00
Greenlamp2
136fcbfda8
init dialog call in the loading-scene (#1331) 2024-05-24 15:08:18 -05:00
Jon Studders
3670574342
Added a champion ribbon on enemy pokemon if they have a classic win. (#881)
* Added a champion ribbon on enemy pokemon if they have a classic win.

* Refactored to check for other non-root starterDex entities.

* Check for caughtIcon, if false then move ribbon to the left.

* Fixed Merge.

* Bit of refactoring, added check for classic mode.

* Removed random newline and removed unused import.

* Removed overlapping ribbon.
2024-05-24 15:57:02 -04:00
Madmadness65
41751ab8df Update encounter levels for some Pokémon
When the wild evolution delays were updated, the biomes file wasn't updated to match, so that has been fixed.
Additionally, the previous refactor removed the commented-out outputPools function. It is where it is because it allows for easily filling out the biomes file for an update.
2024-05-24 14:48:24 -05:00
Greenlamp2
c1a7df913a
refactor executed code while importing and initializing all of these in loading-scene (#1125) 2024-05-24 13:46:30 -04:00
神龟
a9af2bd6ff
Update pokemon.ts (#1297) 2024-05-24 11:15:11 -05:00
神龟
34e9236874
Make zh_CN translation easier to understand (#1292)
* Update modifier-type.ts

* Update menu.ts

* Update tutorial.ts
2024-05-24 11:13:51 -05:00
GhostFlys
6168b77761
Update Chinese battle.ts and egg-list-ui-handler.ts (#1314)
* Update battle.ts

update some lines of translation
make some translation more official

* Update egg-list-ui-handler.ts

make text position more accurate
2024-05-24 10:25:57 -05:00
27 changed files with 433 additions and 192 deletions

View File

@ -2,7 +2,7 @@ import Phaser from "phaser";
import UI from "./ui/ui"; import UI from "./ui/ui";
import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from "./phases"; import { NextEncounterPhase, NewBiomeEncounterPhase, SelectBiomePhase, MessagePhase, TurnInitPhase, ReturnPhase, LevelCapPhase, ShowTrainerPhase, LoginPhase, MovePhase, TitlePhase, SwitchPhase } from "./phases";
import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon"; import Pokemon, { PlayerPokemon, EnemyPokemon } from "./field/pokemon";
import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies, initSpecies } from "./data/pokemon-species"; import PokemonSpecies, { PokemonSpeciesFilter, allSpecies, getPokemonSpecies } from "./data/pokemon-species";
import * as Utils from "./utils"; import * as Utils from "./utils";
import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier, overrideModifiers, overrideHeldItems } from "./modifier/modifier"; import { Modifier, ModifierBar, ConsumablePokemonModifier, ConsumableModifier, PokemonHpRestoreModifier, HealingBoosterModifier, PersistentModifier, PokemonHeldItemModifier, ModifierPredicate, DoubleBattleChanceBoosterModifier, FusePokemonModifier, PokemonFormChangeItemModifier, TerastallizeModifier, overrideModifiers, overrideHeldItems } from "./modifier/modifier";
import { PokeballType } from "./data/pokeball"; import { PokeballType } from "./data/pokeball";
@ -15,10 +15,9 @@ import { GameData, PlayerGender } from "./system/game-data";
import { TextStyle, addTextObject } from "./ui/text"; import { TextStyle, addTextObject } from "./ui/text";
import { Moves } from "./data/enums/moves"; import { Moves } from "./data/enums/moves";
import { allMoves } from "./data/move"; import { allMoves } from "./data/move";
import { initMoves } from "./data/move";
import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getPartyLuckValue } from "./modifier/modifier-type"; import { ModifierPoolType, getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getPartyLuckValue } from "./modifier/modifier-type";
import AbilityBar from "./ui/ability-bar"; import AbilityBar from "./ui/ability-bar";
import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, IncrementMovePriorityAbAttr, applyAbAttrs, initAbilities } from "./data/ability"; import { BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, IncrementMovePriorityAbAttr, applyAbAttrs } from "./data/ability";
import { allAbilities } from "./data/ability"; import { allAbilities } from "./data/ability";
import Battle, { BattleType, FixedBattleConfig, fixedBattles } from "./battle"; import Battle, { BattleType, FixedBattleConfig, fixedBattles } from "./battle";
import { GameMode, GameModes, gameModes } from "./game-mode"; import { GameMode, GameModes, gameModes } from "./game-mode";
@ -187,11 +186,6 @@ export default class BattleScene extends SceneBase {
constructor() { constructor() {
super("battle"); super("battle");
initSpecies();
initMoves();
initAbilities();
this.phaseQueue = []; this.phaseQueue = [];
this.phaseQueuePrepend = []; this.phaseQueuePrepend = [];
this.phaseQueuePrependSpliceIndex = -1; this.phaseQueuePrependSpliceIndex = -1;

View File

@ -2641,7 +2641,7 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr {
if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) { if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) {
const cancelled = new Utils.BooleanHolder(false); const cancelled = new Utils.BooleanHolder(false);
pokemon.scene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled)); pokemon.scene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled));
if (cancelled) { if (cancelled.value) {
return false; return false;
} }
attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER); attacker.damageAndUpdate(Math.ceil(attacker.getMaxHp() * (1 / this.damageRatio)), HitResult.OTHER);

View File

@ -254,6 +254,51 @@ export class ConfusedTag extends BattlerTag {
} }
} }
/**
* Tag applied to the {@linkcode Move.DESTINY_BOND} user.
* @extends BattlerTag
* @see {@linkcode apply}
*/
export class DestinyBondTag extends BattlerTag {
constructor(sourceMove: Moves, sourceId: integer) {
super(BattlerTagType.DESTINY_BOND, BattlerTagLapseType.PRE_MOVE, 1, sourceMove, sourceId);
}
/**
* Lapses either before the user's move and does nothing
* or after receiving fatal damage. When the damage is fatal,
* the attacking Pokemon is taken down as well, unless it's a boss.
*
* @param {Pokemon} pokemon Pokemon that is attacking the Destiny Bond user.
* @param {BattlerTagLapseType} lapseType CUSTOM or PRE_MOVE
* @returns false if the tag source fainted or one turn has passed since the application
*/
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType !== BattlerTagLapseType.CUSTOM) {
return super.lapse(pokemon, lapseType);
}
const source = pokemon.scene.getPokemonById(this.sourceId);
if (!source.isFainted()) {
return true;
}
if (source.getAlly() === pokemon) {
return false;
}
const targetMessage = getPokemonMessage(pokemon, "");
if (pokemon.isBossImmune()) {
pokemon.scene.queueMessage(`${targetMessage} is unaffected\nby the effects of Destiny Bond.`);
return false;
}
pokemon.scene.queueMessage(`${getPokemonMessage(source, ` took\n${targetMessage} down with it!`)}`);
pokemon.damageAndUpdate(pokemon.hp, HitResult.ONE_HIT_KO, false, false, true);
return false;
}
}
export class InfatuatedTag extends BattlerTag { export class InfatuatedTag extends BattlerTag {
constructor(sourceMove: integer, sourceId: integer) { constructor(sourceMove: integer, sourceId: integer) {
super(BattlerTagType.INFATUATED, BattlerTagLapseType.MOVE, 1, sourceMove, sourceId); super(BattlerTagType.INFATUATED, BattlerTagLapseType.MOVE, 1, sourceMove, sourceId);
@ -1416,6 +1461,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: integer, sourc
return new MagnetRisenTag(tagType, sourceMove); return new MagnetRisenTag(tagType, sourceMove);
case BattlerTagType.MINIMIZED: case BattlerTagType.MINIMIZED:
return new MinimizeTag(); return new MinimizeTag();
case BattlerTagType.DESTINY_BOND:
return new DestinyBondTag(sourceMove, sourceId);
case BattlerTagType.NONE: case BattlerTagType.NONE:
default: default:
return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId); return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, turnCount, sourceMove, sourceId);

View File

@ -5,7 +5,7 @@ import beautify from "json-beautify";
import { TrainerType } from "./enums/trainer-type"; import { TrainerType } from "./enums/trainer-type";
import { TimeOfDay } from "./enums/time-of-day"; import { TimeOfDay } from "./enums/time-of-day";
import { Biome } from "./enums/biome"; import { Biome } from "./enums/biome";
import { SpeciesFormEvolution } from "./pokemon-evolutions"; import {pokemonEvolutions, SpeciesFormEvolution} from "./pokemon-evolutions";
export function getBiomeName(biome: Biome | -1) { export function getBiomeName(biome: Biome | -1) {
if (biome === -1) { if (biome === -1) {
@ -200,7 +200,7 @@ export const biomePokemonPools: BiomePokemonPools = {
[TimeOfDay.NIGHT]: [ { 1: [ Species.SHINX ], 15: [ Species.LUXIO ], 30: [ Species.LUXRAY ] } ], [TimeOfDay.NIGHT]: [ { 1: [ Species.SHINX ], 15: [ Species.LUXIO ], 30: [ Species.LUXRAY ] } ],
[TimeOfDay.ALL]: [ { 1: [ Species.ABRA ], 16: [ Species.KADABRA ] }, { 1: [ Species.BUNEARY ], 20: [ Species.LOPUNNY ] }, { 1: [ Species.ROOKIDEE ], 18: [ Species.CORVISQUIRE ], 38: [ Species.CORVIKNIGHT ] } ] [TimeOfDay.ALL]: [ { 1: [ Species.ABRA ], 16: [ Species.KADABRA ] }, { 1: [ Species.BUNEARY ], 20: [ Species.LOPUNNY ] }, { 1: [ Species.ROOKIDEE ], 18: [ Species.CORVISQUIRE ], 38: [ Species.CORVIKNIGHT ] } ]
}, },
[BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.FARFETCHD, Species.LICKITUNG, Species.CHANSEY, Species.EEVEE, Species.SNORLAX, { 1: [ Species.DUNSPARCE ], 72: [ Species.DUDUNSPARCE ] } ] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.FARFETCHD, Species.LICKITUNG, Species.CHANSEY, Species.EEVEE, Species.SNORLAX, { 1: [ Species.DUNSPARCE ], 62: [ Species.DUDUNSPARCE ] } ] },
[BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.DITTO, Species.LATIAS, Species.LATIOS ] }, [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.DITTO, Species.LATIAS, Species.LATIOS ] },
[BiomePoolTier.BOSS]: { [BiomePoolTier.BOSS]: {
[TimeOfDay.DAWN]: [ Species.DODRIO, Species.FURRET, Species.GUMSHOOS, Species.GREEDENT ], [TimeOfDay.DAWN]: [ Species.DODRIO, Species.FURRET, Species.GUMSHOOS, Species.GREEDENT ],
@ -268,7 +268,7 @@ export const biomePokemonPools: BiomePokemonPools = {
[TimeOfDay.DAY]: [], [TimeOfDay.DAY]: [],
[TimeOfDay.DUSK]: [], [TimeOfDay.DUSK]: [],
[TimeOfDay.NIGHT]: [], [TimeOfDay.NIGHT]: [],
[TimeOfDay.ALL]: [ Species.PINSIR, { 1: [ Species.CHIKORITA ], 16: [ Species.BAYLEEF ], 32: [ Species.MEGANIUM ] }, { 1: [ Species.GIRAFARIG ], 72: [ Species.FARIGIRAF ] }, Species.ZANGOOSE, Species.KECLEON, Species.TROPIUS ] [TimeOfDay.ALL]: [ Species.PINSIR, { 1: [ Species.CHIKORITA ], 16: [ Species.BAYLEEF ], 32: [ Species.MEGANIUM ] }, { 1: [ Species.GIRAFARIG ], 62: [ Species.FARIGIRAF ] }, Species.ZANGOOSE, Species.KECLEON, Species.TROPIUS ]
}, },
[BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.SCYTHER, Species.SHEDINJA, Species.ROTOM ] }, [BiomePoolTier.SUPER_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [ Species.SCYTHER, Species.SHEDINJA, Species.ROTOM ] },
[BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] }, [BiomePoolTier.ULTRA_RARE]: { [TimeOfDay.DAWN]: [], [TimeOfDay.DAY]: [], [TimeOfDay.DUSK]: [], [TimeOfDay.NIGHT]: [], [TimeOfDay.ALL]: [] },
@ -474,8 +474,8 @@ export const biomePokemonPools: BiomePokemonPools = {
[TimeOfDay.ALL]: [ { 1: [ Species.TOTODILE ], 18: [ Species.CROCONAW ], 30: [ Species.FERALIGATR ] }, { 1: [ Species.MUDKIP ], 16: [ Species.MARSHTOMP ], 36: [ Species.SWAMPERT ] } ] [TimeOfDay.ALL]: [ { 1: [ Species.TOTODILE ], 18: [ Species.CROCONAW ], 30: [ Species.FERALIGATR ] }, { 1: [ Species.MUDKIP ], 16: [ Species.MARSHTOMP ], 36: [ Species.SWAMPERT ] } ]
}, },
[BiomePoolTier.SUPER_RARE]: { [BiomePoolTier.SUPER_RARE]: {
[TimeOfDay.DAWN]: [ { 1: [ Species.GALAR_SLOWPOKE ], 40: [ Species.GALAR_SLOWBRO ] }, { 1: [ Species.HISUI_SLIGGOO ], 90: [ Species.HISUI_GOODRA ] } ], [TimeOfDay.DAWN]: [ { 1: [ Species.GALAR_SLOWPOKE ], 40: [ Species.GALAR_SLOWBRO ] }, { 1: [ Species.HISUI_SLIGGOO ], 80: [ Species.HISUI_GOODRA ] } ],
[TimeOfDay.DAY]: [ { 1: [ Species.GALAR_SLOWPOKE ], 40: [ Species.GALAR_SLOWBRO ] }, { 1: [ Species.HISUI_SLIGGOO ], 90: [ Species.HISUI_GOODRA ] } ], [TimeOfDay.DAY]: [ { 1: [ Species.GALAR_SLOWPOKE ], 40: [ Species.GALAR_SLOWBRO ] }, { 1: [ Species.HISUI_SLIGGOO ], 80: [ Species.HISUI_GOODRA ] } ],
[TimeOfDay.DUSK]: [], [TimeOfDay.DUSK]: [],
[TimeOfDay.NIGHT]: [], [TimeOfDay.NIGHT]: [],
[TimeOfDay.ALL]: [ Species.POLITOED, Species.GALAR_STUNFISK ] [TimeOfDay.ALL]: [ Species.POLITOED, Species.GALAR_STUNFISK ]
@ -2012,7 +2012,7 @@ export const biomeTrainerPools: BiomeTrainerPools = {
} }
}; };
{ export function initBiomes() {
const pokemonBiomes = [ const pokemonBiomes = [
[ Species.BULBASAUR, Type.GRASS, Type.POISON, [ [ Species.BULBASAUR, Type.GRASS, Type.POISON, [
[ Biome.GRASS, BiomePoolTier.RARE ] [ Biome.GRASS, BiomePoolTier.RARE ]
@ -7677,130 +7677,127 @@ export const biomeTrainerPools: BiomeTrainerPools = {
traverseBiome(Biome.TOWN, 0); traverseBiome(Biome.TOWN, 0);
biomeDepths[Biome.END] = [ Object.values(biomeDepths).map(d => d[0]).reduce((max: integer, value: integer) => Math.max(max, value), 0) + 1, 1 ]; biomeDepths[Biome.END] = [ Object.values(biomeDepths).map(d => d[0]).reduce((max: integer, value: integer) => Math.max(max, value), 0) + 1, 1 ];
import("./pokemon-evolutions").then(pe => { for (const biome of Utils.getEnumValues(Biome)) {
const pokemonEvolutions = pe.pokemonEvolutions; biomePokemonPools[biome] = {};
for (const biome of Utils.getEnumValues(Biome)) { biomeTrainerPools[biome] = {};
biomePokemonPools[biome] = {};
biomeTrainerPools[biome] = {};
for (const tier of Utils.getEnumValues(BiomePoolTier)) { for (const tier of Utils.getEnumValues(BiomePoolTier)) {
biomePokemonPools[biome][tier] = {}; biomePokemonPools[biome][tier] = {};
biomeTrainerPools[biome][tier] = []; biomeTrainerPools[biome][tier] = [];
for (const tod of Utils.getEnumValues(TimeOfDay)) { for (const tod of Utils.getEnumValues(TimeOfDay)) {
biomePokemonPools[biome][tier][tod] = []; biomePokemonPools[biome][tier][tod] = [];
}
} }
} }
}
for (const pb of pokemonBiomes) { for (const pb of pokemonBiomes) {
const speciesId = pb[0] as Species; const speciesId = pb[0] as Species;
const biomeEntries = pb[3] as (Biome | BiomePoolTier)[][]; const biomeEntries = pb[3] as (Biome | BiomePoolTier)[][];
const speciesEvolutions: SpeciesFormEvolution[] = pokemonEvolutions.hasOwnProperty(speciesId) const speciesEvolutions: SpeciesFormEvolution[] = pokemonEvolutions.hasOwnProperty(speciesId)
? pokemonEvolutions[speciesId] ? pokemonEvolutions[speciesId]
: []; : [];
if (!biomeEntries.filter(b => b[0] !== Biome.END).length && !speciesEvolutions.filter(es => !!((pokemonBiomes.find(p => p[0] === es.speciesId))[3] as any[]).filter(b => b[0] !== Biome.END).length).length) { if (!biomeEntries.filter(b => b[0] !== Biome.END).length && !speciesEvolutions.filter(es => !!((pokemonBiomes.find(p => p[0] === es.speciesId))[3] as any[]).filter(b => b[0] !== Biome.END).length).length) {
uncatchableSpecies.push(speciesId); uncatchableSpecies.push(speciesId);
}
for (const b of biomeEntries) {
const biome = b[0];
const tier = b[1];
const timesOfDay = b.length > 2
? Array.isArray(b[2])
? b[2]
: [ b[2] ]
: [ TimeOfDay.ALL ];
for (const tod of timesOfDay) {
if (!biomePokemonPools.hasOwnProperty(biome) || !biomePokemonPools[biome].hasOwnProperty(tier) || !biomePokemonPools[biome][tier].hasOwnProperty(tod)) {
continue;
}
const biomeTierPool = biomePokemonPools[biome][tier][tod];
let treeIndex = -1;
let arrayIndex = 0;
for (let t = 0; t < biomeTierPool.length; t++) {
const existingSpeciesIds = biomeTierPool[t] as unknown as Species[];
for (let es = 0; es < existingSpeciesIds.length; es++) {
const existingSpeciesId = existingSpeciesIds[es];
if (pokemonEvolutions.hasOwnProperty(existingSpeciesId) && (pokemonEvolutions[existingSpeciesId] as SpeciesFormEvolution[]).find(ese => ese.speciesId === speciesId)) {
treeIndex = t;
arrayIndex = es + 1;
break;
} else if (speciesEvolutions && speciesEvolutions.find(se => se.speciesId === existingSpeciesId)) {
treeIndex = t;
arrayIndex = es;
break;
}
}
if (treeIndex > -1) {
break;
}
}
if (treeIndex > -1) {
(biomeTierPool[treeIndex] as unknown as Species[]).splice(arrayIndex, 0, speciesId);
} else {
(biomeTierPool as unknown as Species[][]).push([ speciesId ]);
}
}
}
} }
for (const b of Object.keys(biomePokemonPools)) { for (const b of biomeEntries) {
for (const t of Object.keys(biomePokemonPools[b])) { const biome = b[0];
const tier = parseInt(t) as BiomePoolTier; const tier = b[1];
for (const tod of Object.keys(biomePokemonPools[b][t])) { const timesOfDay = b.length > 2
const biomeTierTimePool = biomePokemonPools[b][t][tod]; ? Array.isArray(b[2])
for (let e = 0; e < biomeTierTimePool.length; e++) { ? b[2]
const entry = biomeTierTimePool[e]; : [ b[2] ]
if (entry.length === 1) { : [ TimeOfDay.ALL ];
biomeTierTimePool[e] = entry[0];
} else {
const newEntry = {
1: [ entry[0] ]
};
for (let s = 1; s < entry.length; s++) {
const speciesId = entry[s];
const prevolution = entry.map(s => pokemonEvolutions[s]).flat().find(e => e && e.speciesId === speciesId);
const level = prevolution.level - (prevolution.level === 1 ? 1 : 0) + (prevolution.wildDelay * 10) - (tier >= BiomePoolTier.BOSS ? 10 : 0);
if (!newEntry.hasOwnProperty(level)) {
newEntry[level] = [ speciesId ];
} else {
newEntry[level].push(speciesId);
}
}
biomeTierTimePool[e] = newEntry;
}
}
}
}
}
for (const tb of trainerBiomes) { for (const tod of timesOfDay) {
const trainerType = tb[0] as TrainerType; if (!biomePokemonPools.hasOwnProperty(biome) || !biomePokemonPools[biome].hasOwnProperty(tier) || !biomePokemonPools[biome][tier].hasOwnProperty(tod)) {
const biomeEntries = tb[1] as BiomePoolTier[][];
for (const b of biomeEntries) {
const biome = b[0];
const tier = b[1];
if (!biomeTrainerPools.hasOwnProperty(biome) || !biomeTrainerPools[biome].hasOwnProperty(tier)) {
continue; continue;
} }
const biomeTierPool = biomeTrainerPools[biome][tier]; const biomeTierPool = biomePokemonPools[biome][tier][tod];
biomeTierPool.push(trainerType);
let treeIndex = -1;
let arrayIndex = 0;
for (let t = 0; t < biomeTierPool.length; t++) {
const existingSpeciesIds = biomeTierPool[t] as unknown as Species[];
for (let es = 0; es < existingSpeciesIds.length; es++) {
const existingSpeciesId = existingSpeciesIds[es];
if (pokemonEvolutions.hasOwnProperty(existingSpeciesId) && (pokemonEvolutions[existingSpeciesId] as SpeciesFormEvolution[]).find(ese => ese.speciesId === speciesId)) {
treeIndex = t;
arrayIndex = es + 1;
break;
} else if (speciesEvolutions && speciesEvolutions.find(se => se.speciesId === existingSpeciesId)) {
treeIndex = t;
arrayIndex = es;
break;
}
}
if (treeIndex > -1) {
break;
}
}
if (treeIndex > -1) {
(biomeTierPool[treeIndex] as unknown as Species[]).splice(arrayIndex, 0, speciesId);
} else {
(biomeTierPool as unknown as Species[][]).push([ speciesId ]);
}
} }
} }
}
for (const b of Object.keys(biomePokemonPools)) {
for (const t of Object.keys(biomePokemonPools[b])) {
const tier = parseInt(t) as BiomePoolTier;
for (const tod of Object.keys(biomePokemonPools[b][t])) {
const biomeTierTimePool = biomePokemonPools[b][t][tod];
for (let e = 0; e < biomeTierTimePool.length; e++) {
const entry = biomeTierTimePool[e];
if (entry.length === 1) {
biomeTierTimePool[e] = entry[0];
} else {
const newEntry = {
1: [ entry[0] ]
};
for (let s = 1; s < entry.length; s++) {
const speciesId = entry[s];
const prevolution = entry.map(s => pokemonEvolutions[s]).flat().find(e => e && e.speciesId === speciesId);
const level = prevolution.level - (prevolution.level === 1 ? 1 : 0) + (prevolution.wildDelay * 10) - (tier >= BiomePoolTier.BOSS ? 10 : 0);
if (!newEntry.hasOwnProperty(level)) {
newEntry[level] = [ speciesId ];
} else {
newEntry[level].push(speciesId);
}
}
biomeTierTimePool[e] = newEntry;
}
}
}
}
}
for (const tb of trainerBiomes) {
const trainerType = tb[0] as TrainerType;
const biomeEntries = tb[1] as BiomePoolTier[][];
for (const b of biomeEntries) {
const biome = b[0];
const tier = b[1];
if (!biomeTrainerPools.hasOwnProperty(biome) || !biomeTrainerPools[biome].hasOwnProperty(tier)) {
continue;
}
const biomeTierPool = biomeTrainerPools[biome][tier];
biomeTierPool.push(trainerType);
}
//outputPools(); //outputPools();
}); }
// used in a commented code // used in a commented code
// eslint-disable-next-line @typescript-eslint/no-unused-vars // eslint-disable-next-line @typescript-eslint/no-unused-vars

View File

@ -608,9 +608,11 @@ function parseEggMoves(content: string): void {
console.log(output); console.log(output);
} }
const eggMovesStr = ""; export function initEggMoves() {
if (eggMovesStr) { const eggMovesStr = "";
setTimeout(() => { if (eggMovesStr) {
parseEggMoves(eggMovesStr); setTimeout(() => {
}, 1000); parseEggMoves(eggMovesStr);
}, 1000);
}
} }

View File

@ -56,5 +56,6 @@ export enum BattlerTagType {
CHARGED = "CHARGED", CHARGED = "CHARGED",
GROUNDED = "GROUNDED", GROUNDED = "GROUNDED",
MAGNET_RISEN = "MAGNET_RISEN", MAGNET_RISEN = "MAGNET_RISEN",
MINIMIZED = "MINIMIZED" MINIMIZED = "MINIMIZED",
DESTINY_BOND = "DESTINY_BOND"
} }

View File

@ -4704,6 +4704,31 @@ export class MoneyAttr extends MoveEffectAttr {
} }
} }
/**
* Applies {@linkcode BattlerTagType.DESTINY_BOND} to the user.
*
* @extends MoveEffectAttr
*/
export class DestinyBondAttr extends MoveEffectAttr {
constructor() {
super(true, MoveEffectTrigger.PRE_APPLY);
}
/**
* Applies {@linkcode BattlerTagType.DESTINY_BOND} to the user.
* @param user {@linkcode Pokemon} that is having the tag applied to.
* @param target {@linkcode Pokemon} N/A
* @param move {@linkcode Move} {@linkcode Move.DESTINY_BOND}
* @param {any[]} args N/A
* @returns true
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
user.scene.queueMessage(`${getPokemonMessage(user, " is trying\nto take its foe down with it!")}`);
user.addTag(BattlerTagType.DESTINY_BOND, undefined, move.id, user.id);
return true;
}
}
export class LastResortAttr extends MoveAttr { export class LastResortAttr extends MoveAttr {
getCondition(): MoveConditionFunc { getCondition(): MoveConditionFunc {
return (user: Pokemon, target: Pokemon, move: Move) => { return (user: Pokemon, target: Pokemon, move: Move) => {
@ -5405,8 +5430,7 @@ export function initMoves() {
.unimplemented(), .unimplemented(),
new SelfStatusMove(Moves.DESTINY_BOND, Type.GHOST, -1, 5, -1, 0, 2) new SelfStatusMove(Moves.DESTINY_BOND, Type.GHOST, -1, 5, -1, 0, 2)
.ignoresProtect() .ignoresProtect()
.condition(failOnBossCondition) .attr(DestinyBondAttr),
.unimplemented(),
new StatusMove(Moves.PERISH_SONG, Type.NORMAL, -1, 5, -1, 0, 2) new StatusMove(Moves.PERISH_SONG, Type.NORMAL, -1, 5, -1, 0, 2)
.attr(FaintCountdownAttr) .attr(FaintCountdownAttr)
.ignoresProtect() .ignoresProtect()
@ -6292,7 +6316,7 @@ export function initMoves() {
new StatusMove(Moves.QUASH, Type.DARK, 100, 15, -1, 0, 5) new StatusMove(Moves.QUASH, Type.DARK, 100, 15, -1, 0, 5)
.unimplemented(), .unimplemented(),
new AttackMove(Moves.ACROBATICS, Type.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, -1, 0, 5) new AttackMove(Moves.ACROBATICS, Type.FLYING, MoveCategory.PHYSICAL, 55, 100, 15, -1, 0, 5)
.attr(MovePowerMultiplierAttr, (user, target, move) => Math.max(1, 2 - 0.2 * user.getHeldItems().reduce((v, m) => v + m.stackCount, 0))), .attr(MovePowerMultiplierAttr, (user, target, move) => Math.max(1, 2 - 0.2 * user.getHeldItems().filter(i => i.getTransferrable(true)).reduce((v, m) => v + m.stackCount, 0))),
new StatusMove(Moves.REFLECT_TYPE, Type.NORMAL, -1, 15, -1, 0, 5) new StatusMove(Moves.REFLECT_TYPE, Type.NORMAL, -1, 15, -1, 0, 5)
.attr(CopyTypeAttr), .attr(CopyTypeAttr),
new AttackMove(Moves.RETALIATE, Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 5, -1, 0, 5) new AttackMove(Moves.RETALIATE, Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 5, -1, 0, 5)

View File

@ -1619,7 +1619,7 @@ interface PokemonPrevolutions {
export const pokemonPrevolutions: PokemonPrevolutions = {}; export const pokemonPrevolutions: PokemonPrevolutions = {};
{ export function initPokemonPrevolutions(): void {
const megaFormKeys = [ SpeciesFormKey.MEGA, "", SpeciesFormKey.MEGA_X, "", SpeciesFormKey.MEGA_Y ].map(sfk => sfk as string); const megaFormKeys = [ SpeciesFormKey.MEGA, "", SpeciesFormKey.MEGA_X, "", SpeciesFormKey.MEGA_Y ].map(sfk => sfk as string);
const prevolutionKeys = Object.keys(pokemonEvolutions); const prevolutionKeys = Object.keys(pokemonEvolutions);
prevolutionKeys.forEach(pk => { prevolutionKeys.forEach(pk => {

View File

@ -729,7 +729,7 @@ export const pokemonFormChanges: PokemonFormChanges = {
] ]
}; };
{ export function initPokemonForms() {
const formChangeKeys = Object.keys(pokemonFormChanges); const formChangeKeys = Object.keys(pokemonFormChanges);
formChangeKeys.forEach(pk => { formChangeKeys.forEach(pk => {
const formChanges = pokemonFormChanges[pk]; const formChanges = pokemonFormChanges[pk];

View File

@ -404,12 +404,14 @@ export abstract class PokemonSpeciesForm {
console.warn = () => {}; console.warn = () => {};
const frameNames = scene.anims.generateFrameNames(spriteKey, { zeroPad: 4, suffix: ".png", start: 1, end: 400 }); const frameNames = scene.anims.generateFrameNames(spriteKey, { zeroPad: 4, suffix: ".png", start: 1, end: 400 });
console.warn = originalWarn; console.warn = originalWarn;
scene.anims.create({ if (!(scene.anims.exists(spriteKey))) {
key: this.getSpriteKey(female, formIndex, shiny, variant), scene.anims.create({
frames: frameNames, key: this.getSpriteKey(female, formIndex, shiny, variant),
frameRate: 12, frames: frameNames,
repeat: -1 frameRate: 12,
}); repeat: -1
});
}
let spritePath = this.getSpriteAtlasPath(female, formIndex, shiny, variant).replace("variant/", "").replace(/_[1-3]$/, ""); let spritePath = this.getSpriteAtlasPath(female, formIndex, shiny, variant).replace("variant/", "").replace(/_[1-3]$/, "");
const useExpSprite = scene.experimentalSprites && scene.hasExpSprite(spriteKey); const useExpSprite = scene.experimentalSprites && scene.hasExpSprite(spriteKey);
if (useExpSprite) { if (useExpSprite) {

View File

@ -10,7 +10,6 @@ import PokemonSpecies, {PokemonSpeciesFilter, getPokemonSpecies} from "./pokemon
import {Species} from "./enums/species"; import {Species} from "./enums/species";
import {tmSpecies} from "./tms"; import {tmSpecies} from "./tms";
import {Type} from "./type"; import {Type} from "./type";
import {initTrainerTypeDialogue} from "./dialogue";
import {PersistentModifier} from "../modifier/modifier"; import {PersistentModifier} from "../modifier/modifier";
import {TrainerVariant} from "../field/trainer"; import {TrainerVariant} from "../field/trainer";
import {PartyMemberStrength} from "./enums/party-member-strength"; import {PartyMemberStrength} from "./enums/party-member-strength";
@ -1050,7 +1049,3 @@ export const trainerConfigs: TrainerConfigs = {
return [ modifierTypes.TERA_SHARD().generateType(null, [ starter.species.type1 ]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier ]; return [ modifierTypes.TERA_SHARD().generateType(null, [ starter.species.type1 ]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier ];
}), }),
}; };
(function () {
initTrainerTypeDialogue();
})();

View File

@ -1790,6 +1790,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
console.log("damage", damage.value, move.name, power.value, sourceAtk, targetDef); console.log("damage", damage.value, move.name, power.value, sourceAtk, targetDef);
// In case of fatal damage, this tag would have gotten cleared before we could lapse it.
const destinyTag = this.getTag(BattlerTagType.DESTINY_BOND);
const oneHitKo = result === HitResult.ONE_HIT_KO; const oneHitKo = result === HitResult.ONE_HIT_KO;
if (damage.value) { if (damage.value) {
if (this.getHpRatio() === 1) { if (this.getHpRatio() === 1) {
@ -1850,6 +1853,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (damage) { if (damage) {
this.scene.clearPhaseQueueSplice(); this.scene.clearPhaseQueueSplice();
const attacker = this.scene.getPokemonById(source.id);
destinyTag?.lapse(attacker, BattlerTagLapseType.CUSTOM);
} }
} }
break; break;

View File

@ -9,6 +9,15 @@ import { WindowVariant, getWindowVariantSuffix } from "./ui/ui-theme";
import { isMobile } from "./touch-controls"; import { isMobile } from "./touch-controls";
import * as Utils from "./utils"; import * as Utils from "./utils";
import { initI18n } from "./plugins/i18n"; import { initI18n } from "./plugins/i18n";
import {initStatsKeys} from "#app/ui/game-stats-ui-handler";
import {initPokemonPrevolutions} from "#app/data/pokemon-evolutions";
import {initBiomes} from "#app/data/biomes";
import {initEggMoves} from "#app/data/egg-moves";
import {initPokemonForms} from "#app/data/pokemon-forms";
import {initSpecies} from "#app/data/pokemon-species";
import {initMoves} from "#app/data/move";
import {initAbilities} from "#app/data/ability";
import {initTrainerTypeDialogue} from "#app/data/dialogue";
export class LoadingScene extends SceneBase { export class LoadingScene extends SceneBase {
constructor() { constructor() {
@ -284,6 +293,16 @@ export class LoadingScene extends SceneBase {
this.load.plugin("rextexteditplugin", "https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/dist/rextexteditplugin.min.js", true); this.load.plugin("rextexteditplugin", "https://raw.githubusercontent.com/rexrainbow/phaser3-rex-notes/master/dist/rextexteditplugin.min.js", true);
this.loadLoadingScreen(); this.loadLoadingScreen();
initStatsKeys();
initPokemonPrevolutions();
initBiomes();
initEggMoves();
initPokemonForms();
initTrainerTypeDialogue();
initSpecies();
initMoves();
initAbilities();
} }
loadLoadingScreen() { loadLoadingScreen() {

View File

@ -2047,7 +2047,7 @@ export const move: MoveTranslationEntries = {
}, },
"acrobatics": { "acrobatics": {
name: "Acrobatics", name: "Acrobatics",
effect: "The user nimbly strikes the target. If the user is not holding an item, this attack inflicts massive damage." effect: "The user nimbly strikes the target. The fewer held items, the higher the damage it inflicts."
}, },
"reflectType": { "reflectType": {
name: "Reflect Type", name: "Reflect Type",

View File

@ -4,20 +4,20 @@ export const battle: SimpleTranslationEntries = {
"bossAppeared": "{{bossName}} 出现了。", "bossAppeared": "{{bossName}} 出现了。",
"trainerAppeared": "{{trainerName}}\n想要和你对战", "trainerAppeared": "{{trainerName}}\n想要和你对战",
"trainerAppearedDouble": "{{trainerName}}\n想要和你对战", "trainerAppearedDouble": "{{trainerName}}\n想要和你对战",
"trainerSendOut": "{{trainerName}} sent out\n{{pokemonName}}!", "trainerSendOut": "{{trainerName}} 派出了\n{{pokemonName}}!",
"singleWildAppeared": "一只野生 {{pokemonName}} 出现了!", "singleWildAppeared": "一只野生 {{pokemonName}} 出现了!",
"multiWildAppeared": "野生的 {{pokemonName1}}\n和 {{pokemonName2}} 出现了!", "multiWildAppeared": "野生的 {{pokemonName1}}\n和 {{pokemonName2}} 出现了!",
"playerComeBack": "回来吧, {{pokemonName}}", "playerComeBack": "回来吧, {{pokemonName}}",
"trainerComeBack": "{{trainerName}} 收回了 {{pokemonName}}", "trainerComeBack": "{{trainerName}} 收回了 {{pokemonName}}",
"playerGo": "去吧! {{pokemonName}}", "playerGo": "去吧! {{pokemonName}}",
"trainerGo": "{{trainerName}} 派出了 {{pokemonName}}", "trainerGo": "{{trainerName}} 派出了\n{{pokemonName}}",
"switchQuestion": "要更换\n{{pokemonName}}吗?", "switchQuestion": "要更换\n{{pokemonName}}吗?",
"trainerDefeated": "你击败了\n{{trainerName}}", "trainerDefeated": "你击败了\n{{trainerName}}",
"moneyWon": "You got\n₽{{moneyAmount}} for winning!", "moneyWon": "你赢得了\n₽{{moneyAmount}}",
"pokemonCaught": "{{pokemonName}} 被抓住了!", "pokemonCaught": "{{pokemonName}} 被抓住了!",
"partyFull": "Your party is full.\nRelease a Pokémon to make room for {{pokemonName}}?", "partyFull": "你的队伍已满员.是否放生其他宝可梦\n为 {{pokemonName}} 腾出空间?",
"pokemon": "宝可梦", "pokemon": "宝可梦",
"sendOutPokemon": "上吧! {{pokemonName}}", "sendOutPokemon": "上吧!\n{{pokemonName}}",
"hitResultCriticalHit": "击中了要害!", "hitResultCriticalHit": "击中了要害!",
"hitResultSuperEffective": "效果拔群!", "hitResultSuperEffective": "效果拔群!",
"hitResultNotVeryEffective": "收效甚微…", "hitResultNotVeryEffective": "收效甚微…",
@ -26,7 +26,7 @@ export const battle: SimpleTranslationEntries = {
"attackFailed": "但是失败了!", "attackFailed": "但是失败了!",
"attackHitsCount": "击中 {{count}} 次!", "attackHitsCount": "击中 {{count}} 次!",
"expGain": "{{pokemonName}} 获得了 {{exp}} 经验值!", "expGain": "{{pokemonName}} 获得了 {{exp}} 经验值!",
"levelUp": "{{pokemonName}} 升级到 Lv. {{level}}", "levelUp": "{{pokemonName}} 升级到 Lv.{{level}}",
"learnMove": "{{pokemonName}} 学会了 {{moveName}}", "learnMove": "{{pokemonName}} 学会了 {{moveName}}",
"learnMovePrompt": "{{pokemonName}} 想要学习 {{moveName}}。", "learnMovePrompt": "{{pokemonName}} 想要学习 {{moveName}}。",
"learnMoveLimitReached": "但是,{{pokemonName}} 已经学会了\n四个技能", "learnMoveLimitReached": "但是,{{pokemonName}} 已经学会了\n四个技能",
@ -35,7 +35,7 @@ export const battle: SimpleTranslationEntries = {
"learnMoveNotLearned": "{{pokemonName}} 没有学会 {{moveName}}。", "learnMoveNotLearned": "{{pokemonName}} 没有学会 {{moveName}}。",
"learnMoveForgetQuestion": "要忘记哪个技能?", "learnMoveForgetQuestion": "要忘记哪个技能?",
"learnMoveForgetSuccess": "{{pokemonName}} 忘记了\n如何使用 {{moveName}}。", "learnMoveForgetSuccess": "{{pokemonName}} 忘记了\n如何使用 {{moveName}}。",
"countdownPoof": "@d{32}1, @d{15}2, @d{15}和@d{15}… @d{15}… @d{15}… @d{15}@s{pb_bounce_1}噗", "countdownPoof": "@d{32}1, @d{15}2 @d{15}… @d{15}… @d{15}@s{pb_bounce_1}空",
"learnMoveAnd": "然后...", "learnMoveAnd": "然后...",
"levelCapUp": "等级上限提升到 {{levelCap}}", "levelCapUp": "等级上限提升到 {{levelCap}}",
"moveNotImplemented": "{{moveName}} 尚未实装,无法选择。", "moveNotImplemented": "{{moveName}} 尚未实装,无法选择。",

View File

@ -18,13 +18,13 @@ export const menu: SimpleTranslationEntries = {
"login": "登录", "login": "登录",
"register": "注册", "register": "注册",
"emptyUsername": "用户名不能为空", "emptyUsername": "用户名不能为空",
"invalidLoginUsername": "提供的用户名无效", "invalidLoginUsername": "输入的用户名无效",
"invalidRegisterUsername": "用户名只能包含字母、数字或下划线", "invalidRegisterUsername": "用户名只能包含字母、数字或下划线",
"invalidLoginPassword": "提供的密码无效", "invalidLoginPassword": "输入的密码无效",
"invalidRegisterPassword": "密码必须至少包含 6 个字符", "invalidRegisterPassword": "密码必须至少包含 6 个字符",
"usernameAlreadyUsed": "提供的用户名已被使用", "usernameAlreadyUsed": "输入的用户名已被使用",
"accountNonExistent": "提供的用户不存在", "accountNonExistent": "输入的用户不存在",
"unmatchingPassword": "提供的密码不匹配", "unmatchingPassword": "输入的密码不匹配",
"passwordNotMatchingConfirmPassword": "密码必须与确认密码一致", "passwordNotMatchingConfirmPassword": "密码必须与确认密码一致",
"confirmPassword": "确认密码", "confirmPassword": "确认密码",
"registrationAgeWarning": "注册即表示您确认您已年满 13 岁。", "registrationAgeWarning": "注册即表示您确认您已年满 13 岁。",

View File

@ -17,7 +17,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
} }
}, },
"PokemonHpRestoreModifierType": { "PokemonHpRestoreModifierType": {
description: "为一只宝可梦回复 {{restorePoints}} HP 或 {{restorePercent}}% HP大值", description: "为一只宝可梦回复 {{restorePoints}} HP 或 {{restorePercent}}% HP大值",
extra: { extra: {
"fully": "为一只宝可梦回复全部HP", "fully": "为一只宝可梦回复全部HP",
"fullyWithStatus": "为一只宝可梦回复全部HP并消除所有负面\n状态", "fullyWithStatus": "为一只宝可梦回复全部HP并消除所有负面\n状态",
@ -196,7 +196,7 @@ export const modifierType: ModifierTypeTranslationEntries = {
"MULTI_LENS": { name: "多重镜" }, "MULTI_LENS": { name: "多重镜" },
"HEALING_CHARM": { name: "治愈护符", description: "HP回复量增加10% (含复活)" }, "HEALING_CHARM": { name: "治愈护符", description: "HP回复量增加10% (含复活)" },
"CANDY_JAR": { name: "糖果罐", description: "神奇糖果提供的升级提升1级" }, "CANDY_JAR": { name: "糖果罐", description: "神奇糖果提供的升级额外增加1级" },
"BERRY_POUCH": { name: "树果袋", description: "使用树果时有33%的几率不会消耗树果" }, "BERRY_POUCH": { name: "树果袋", description: "使用树果时有33%的几率不会消耗树果" },

View File

@ -4,7 +4,7 @@ export const tutorial: SimpleTranslationEntries = {
"intro": `欢迎来到PokéRogue这是一款以战斗为核心的融合了roguelite元素的宝可梦同人游戏。 "intro": `欢迎来到PokéRogue这是一款以战斗为核心的融合了roguelite元素的宝可梦同人游戏。
$本游戏未进行商业化\nPokémon或Pokémon使用的版 $本游戏未进行商业化\nPokémon或Pokémon使用的版
$权资产的所有权 $权资产的所有权
$游戏仍在开发中\n告错误使 Discord $游戏仍在开发中\n告错误 Discord
$如果游戏运行缓慢\n打开了`, $如果游戏运行缓慢\n打开了`,
"accessMenu": "在等待输入时,按 M 或 Escape 键可访\n问菜单。菜单包含设置和各种功能。", "accessMenu": "在等待输入时,按 M 或 Escape 键可访\n问菜单。菜单包含设置和各种功能。",

View File

@ -31,7 +31,7 @@ export const pokemon: SimpleTranslationEntries = {
"sandslash": "穿山王", "sandslash": "穿山王",
"nidoran_f": "尼多蘭", "nidoran_f": "尼多蘭",
"nidorina": "尼多娜", "nidorina": "尼多娜",
"nidoqueen": "尼多", "nidoqueen": "尼多",
"nidoran_m": "尼多朗", "nidoran_m": "尼多朗",
"nidorino": "尼多力諾", "nidorino": "尼多力諾",
"nidoking": "尼多王", "nidoking": "尼多王",
@ -57,7 +57,7 @@ export const pokemon: SimpleTranslationEntries = {
"psyduck": "可達鴨", "psyduck": "可達鴨",
"golduck": "哥達鴨", "golduck": "哥達鴨",
"mankey": "猴怪", "mankey": "猴怪",
"primeape": "火猴", "primeape": "火猴",
"growlithe": "卡蒂狗", "growlithe": "卡蒂狗",
"arcanine": "風速狗", "arcanine": "風速狗",
"poliwag": "蚊香蝌蚪", "poliwag": "蚊香蝌蚪",
@ -76,7 +76,7 @@ export const pokemon: SimpleTranslationEntries = {
"tentacruel": "毒刺水母", "tentacruel": "毒刺水母",
"geodude": "小拳石", "geodude": "小拳石",
"graveler": "隆隆石", "graveler": "隆隆石",
"golem": "隆隆", "golem": "隆隆",
"ponyta": "小火馬", "ponyta": "小火馬",
"rapidash": "烈焰馬", "rapidash": "烈焰馬",
"slowpoke": "呆呆獸", "slowpoke": "呆呆獸",
@ -95,7 +95,7 @@ export const pokemon: SimpleTranslationEntries = {
"gastly": "鬼斯", "gastly": "鬼斯",
"haunter": "鬼斯通", "haunter": "鬼斯通",
"gengar": "耿鬼", "gengar": "耿鬼",
"onix": "大蛇", "onix": "大蛇",
"drowzee": "催眠貘", "drowzee": "催眠貘",
"hypno": "引夢貘人", "hypno": "引夢貘人",
"krabby": "大鉗蟹", "krabby": "大鉗蟹",
@ -156,7 +156,7 @@ export const pokemon: SimpleTranslationEntries = {
"bayleef": "月桂葉", "bayleef": "月桂葉",
"meganium": "大竺葵", "meganium": "大竺葵",
"cyndaquil": "火球鼠", "cyndaquil": "火球鼠",
"quilava": "火鼠", "quilava": "火鼠",
"typhlosion": "火暴獸", "typhlosion": "火暴獸",
"totodile": "小鋸鱷", "totodile": "小鋸鱷",
"croconaw": "藍鱷", "croconaw": "藍鱷",
@ -185,7 +185,7 @@ export const pokemon: SimpleTranslationEntries = {
"bellossom": "美麗花", "bellossom": "美麗花",
"marill": "瑪力露", "marill": "瑪力露",
"azumarill": "瑪力露麗", "azumarill": "瑪力露麗",
"sudowoodo": "樹怪", "sudowoodo": "樹怪",
"politoed": "蚊香蛙皇", "politoed": "蚊香蛙皇",
"hoppip": "毽子草", "hoppip": "毽子草",
"skiploom": "毽子花", "skiploom": "毽子花",
@ -233,7 +233,7 @@ export const pokemon: SimpleTranslationEntries = {
"kingdra": "刺龍王", "kingdra": "刺龍王",
"phanpy": "小小象", "phanpy": "小小象",
"donphan": "頓甲", "donphan": "頓甲",
"porygon2": "多邊獸2型", "porygon2": "多邊獸",
"stantler": "驚角鹿", "stantler": "驚角鹿",
"smeargle": "圖圖犬", "smeargle": "圖圖犬",
"tyrogue": "無畏小子", "tyrogue": "無畏小子",
@ -338,7 +338,7 @@ export const pokemon: SimpleTranslationEntries = {
"zangoose": "貓鼬斬", "zangoose": "貓鼬斬",
"seviper": "飯匙蛇", "seviper": "飯匙蛇",
"lunatone": "月石", "lunatone": "月石",
"solrock": "太陽", "solrock": "太陽",
"barboach": "泥泥鰍", "barboach": "泥泥鰍",
"whiscash": "鯰魚王", "whiscash": "鯰魚王",
"corphish": "龍蝦小兵", "corphish": "龍蝦小兵",
@ -438,11 +438,11 @@ export const pokemon: SimpleTranslationEntries = {
"skuntank": "坦克臭鼬", "skuntank": "坦克臭鼬",
"bronzor": "銅鏡怪", "bronzor": "銅鏡怪",
"bronzong": "青銅鐘", "bronzong": "青銅鐘",
"bonsly": "盆怪", "bonsly": "盆怪",
"mime_jr": "魔尼尼", "mime_jr": "魔尼尼",
"happiny": "小福蛋", "happiny": "小福蛋",
"chatot": "聒噪鳥", "chatot": "聒噪鳥",
"spiritomb": "花怪", "spiritomb": "花怪",
"gible": "圓陸鯊", "gible": "圓陸鯊",
"gabite": "尖牙陸鯊", "gabite": "尖牙陸鯊",
"garchomp": "烈咬陸鯊", "garchomp": "烈咬陸鯊",
@ -474,12 +474,12 @@ export const pokemon: SimpleTranslationEntries = {
"glaceon": "冰伊布", "glaceon": "冰伊布",
"gliscor": "天蠍王", "gliscor": "天蠍王",
"mamoswine": "象牙豬", "mamoswine": "象牙豬",
"porygon_z": "多邊獸乙型", "porygon_z": "多邊獸",
"gallade": "艾路雷朵", "gallade": "艾路雷朵",
"probopass": "大朝北鼻", "probopass": "大朝北鼻",
"dusknoir": "黑夜魔靈", "dusknoir": "黑夜魔靈",
"froslass": "雪妖女", "froslass": "雪妖女",
"rotom": "洛姆", "rotom": "洛姆",
"uxie": "由克希", "uxie": "由克希",
"mesprit": "艾姆利多", "mesprit": "艾姆利多",
"azelf": "亞克諾姆", "azelf": "亞克諾姆",
@ -525,8 +525,8 @@ export const pokemon: SimpleTranslationEntries = {
"blitzle": "斑斑馬", "blitzle": "斑斑馬",
"zebstrika": "雷電斑馬", "zebstrika": "雷電斑馬",
"roggenrola": "石丸子", "roggenrola": "石丸子",
"boldore": "地幔", "boldore": "地幔",
"gigalith": "龐怪", "gigalith": "龐怪",
"woobat": "滾滾蝙蝠", "woobat": "滾滾蝙蝠",
"swoobat": "心蝙蝠", "swoobat": "心蝙蝠",
"drilbur": "螺釘地鼠", "drilbur": "螺釘地鼠",
@ -544,7 +544,7 @@ export const pokemon: SimpleTranslationEntries = {
"swadloon": "寶包繭", "swadloon": "寶包繭",
"leavanny": "保姆蟲", "leavanny": "保姆蟲",
"venipede": "百足蜈蚣", "venipede": "百足蜈蚣",
"whirlipede": "車輪", "whirlipede": "車輪",
"scolipede": "蜈蚣王", "scolipede": "蜈蚣王",
"cottonee": "木棉球", "cottonee": "木棉球",
"whimsicott": "風妖精", "whimsicott": "風妖精",
@ -558,12 +558,12 @@ export const pokemon: SimpleTranslationEntries = {
"darmanitan": "達摩狒狒", "darmanitan": "達摩狒狒",
"maractus": "沙鈴仙人掌", "maractus": "沙鈴仙人掌",
"dwebble": "石居蟹", "dwebble": "石居蟹",
"crustle": "殿居蟹", "crustle": "殿居蟹",
"scraggy": "滑滑小子", "scraggy": "滑滑小子",
"scrafty": "頭巾混混", "scrafty": "頭巾混混",
"sigilyph": "象徵鳥", "sigilyph": "象徵鳥",
"yamask": "哭哭面具", "yamask": "哭哭面具",
"cofagrigus": "迭失棺", "cofagrigus": "死神棺",
"tirtouga": "原蓋海龜", "tirtouga": "原蓋海龜",
"carracosta": "肋骨海龜", "carracosta": "肋骨海龜",
"archen": "始祖小鳥", "archen": "始祖小鳥",
@ -650,7 +650,7 @@ export const pokemon: SimpleTranslationEntries = {
"keldeo": "凱路迪歐", "keldeo": "凱路迪歐",
"meloetta": "美洛耶塔", "meloetta": "美洛耶塔",
"genesect": "蓋諾賽克特", "genesect": "蓋諾賽克特",
"chespin": "哈力", "chespin": "哈力",
"quilladin": "胖胖哈力", "quilladin": "胖胖哈力",
"chesnaught": "布里卡隆", "chesnaught": "布里卡隆",
"fennekin": "火狐狸", "fennekin": "火狐狸",
@ -744,8 +744,8 @@ export const pokemon: SimpleTranslationEntries = {
"oricorio": "花舞鳥", "oricorio": "花舞鳥",
"cutiefly": "萌虻", "cutiefly": "萌虻",
"ribombee": "蝶結萌虻", "ribombee": "蝶結萌虻",
"rockruff": "狗狗", "rockruff": "狗狗",
"lycanroc": "鬃狼人", "lycanroc": "鬃狼人",
"wishiwashi": "弱丁魚", "wishiwashi": "弱丁魚",
"mareanie": "好壞星", "mareanie": "好壞星",
"toxapex": "超壞星", "toxapex": "超壞星",
@ -758,7 +758,7 @@ export const pokemon: SimpleTranslationEntries = {
"morelull": "睡睡菇", "morelull": "睡睡菇",
"shiinotic": "燈罩夜菇", "shiinotic": "燈罩夜菇",
"salandit": "夜盜火蜥", "salandit": "夜盜火蜥",
"salazzle": "焰蜥", "salazzle": "焰蜥",
"stufful": "童偶熊", "stufful": "童偶熊",
"bewear": "穿着熊", "bewear": "穿着熊",
"bounsweet": "甜竹竹", "bounsweet": "甜竹竹",
@ -778,7 +778,7 @@ export const pokemon: SimpleTranslationEntries = {
"komala": "樹枕尾熊", "komala": "樹枕尾熊",
"turtonator": "爆焰龜獸", "turtonator": "爆焰龜獸",
"togedemaru": "託戈德瑪爾", "togedemaru": "託戈德瑪爾",
"mimikyu": "謎擬", "mimikyu": "謎擬",
"bruxish": "磨牙彩皮魚", "bruxish": "磨牙彩皮魚",
"drampa": "老翁龍", "drampa": "老翁龍",
"dhelmise": "破破舵輪", "dhelmise": "破破舵輪",
@ -827,8 +827,8 @@ export const pokemon: SimpleTranslationEntries = {
"blipbug": "索偵蟲", "blipbug": "索偵蟲",
"dottler": "天罩蟲", "dottler": "天罩蟲",
"orbeetle": "以歐路普", "orbeetle": "以歐路普",
"nickit": "狡小狐", "nickit": "偷兒狐",
"thievul": "猾大狐", "thievul": "大盜",
"gossifleur": "幼棉棉", "gossifleur": "幼棉棉",
"eldegoss": "白蓬蓬", "eldegoss": "白蓬蓬",
"wooloo": "毛辮羊", "wooloo": "毛辮羊",
@ -848,7 +848,7 @@ export const pokemon: SimpleTranslationEntries = {
"cramorant": "古月鳥", "cramorant": "古月鳥",
"arrokuda": "刺梭魚", "arrokuda": "刺梭魚",
"barraskewda": "戽斗尖梭", "barraskewda": "戽斗尖梭",
"toxel": "嬰", "toxel": "電嬰",
"toxtricity": "顫弦蠑螈", "toxtricity": "顫弦蠑螈",
"sizzlipede": "燒火蚣", "sizzlipede": "燒火蚣",
"centiskorch": "焚焰蚣", "centiskorch": "焚焰蚣",
@ -867,7 +867,7 @@ export const pokemon: SimpleTranslationEntries = {
"cursola": "魔靈珊瑚", "cursola": "魔靈珊瑚",
"sirfetchd": "蔥遊兵", "sirfetchd": "蔥遊兵",
"mr_rime": "踏冰人偶", "mr_rime": "踏冰人偶",
"runerigus": "迭失板", "runerigus": "死神板",
"milcery": "小仙奶", "milcery": "小仙奶",
"alcremie": "霜奶仙", "alcremie": "霜奶仙",
"falinks": "列陣兵", "falinks": "列陣兵",
@ -915,7 +915,7 @@ export const pokemon: SimpleTranslationEntries = {
"quaxly": "潤水鴨", "quaxly": "潤水鴨",
"quaxwell": "湧躍鴨", "quaxwell": "湧躍鴨",
"quaquaval": "狂歡浪舞鴨", "quaquaval": "狂歡浪舞鴨",
"lechonk": "愛豚", "lechonk": "愛豚",
"oinkologne": "飄香豚", "oinkologne": "飄香豚",
"tarountula": "團珠蛛", "tarountula": "團珠蛛",
"spidops": "操陷蛛", "spidops": "操陷蛛",
@ -1039,7 +1039,7 @@ export const pokemon: SimpleTranslationEntries = {
"alola_persian": "貓老大", "alola_persian": "貓老大",
"alola_geodude": "小拳石", "alola_geodude": "小拳石",
"alola_graveler": "隆隆石", "alola_graveler": "隆隆石",
"alola_golem": "隆隆", "alola_golem": "隆隆",
"alola_grimer": "臭泥", "alola_grimer": "臭泥",
"alola_muk": "臭臭泥", "alola_muk": "臭臭泥",
"alola_exeggutor": "椰蛋樹", "alola_exeggutor": "椰蛋樹",

View File

@ -0,0 +1,9 @@
import {describe, expect, it} from "vitest";
import {MoneyAchv} from "#app/system/achv";
describe("check some Achievement related stuff", () => {
it ("should check Achievement creation", () => {
const ach = new MoneyAchv("Achievement", 1000, null, 100);
expect(ach.name).toBe("Achievement");
});
});

View File

@ -0,0 +1,35 @@
import { describe, expect, it} from "vitest";
import {initStatsKeys} from "#app/ui/game-stats-ui-handler";
async function importModule() {
try {
initStatsKeys();
const { PokemonMove } = await import("#app/field/pokemon");
const { Species } = await import("#app/data/enums/species");
return {
PokemonMove,
Species,
};
// Dynamically import the module
} catch (error) {
// Log the error stack trace
console.error("Error during import:", error.stack);
// Rethrow the error to ensure the test fails
throw error;
}
}
describe("tests to debug the import, with trace", () => {
it("import PokemonMove module", async () => {
const module = await importModule();
// Example assertion
expect(module.PokemonMove).toBeDefined();
});
it("import Species module", async () => {
const module = await importModule();
// Example assertion
expect(module.Species).toBeDefined();
});
});

57
src/test/pokemon.test.ts Normal file
View File

@ -0,0 +1,57 @@
import {describe, expect, it} from "vitest";
import {getPokemonSpecies} from "#app/data/pokemon-species";
import {PokemonMove} from "#app/field/pokemon";
import {Species} from "#app/data/enums/species";
import {Moves} from "#app/data/enums/moves";
import PokemonData from "#app/system/pokemon-data";
describe("some tests related to PokemonData and Species", () => {
it("should create a species", () => {
const species = getPokemonSpecies(Species.MEW);
expect(species).not.toBeNull();
});
it("should create a pokemon", () => {
const pokemon = new PokemonData({
species: Species.MEW,
level: 1,
});
expect(pokemon).not.toBeNull();
expect(pokemon.level).toEqual(1);
expect(pokemon.species).toEqual(Species.MEW);
});
it("should generate a moveset", () => {
const pokemon = new PokemonData({
species: Species.MEW,
level: 1,
});
expect(pokemon.moveset[0].moveId).toBe(Moves.TACKLE);
expect(pokemon.moveset[1].moveId).toBe(Moves.GROWL);
});
it("should create an ennemypokemon", () => {
const ennemyPokemon = new PokemonData({
species: Species.MEWTWO,
level: 100,
});
expect(ennemyPokemon).not.toBeNull();
expect(ennemyPokemon.level).toEqual(100);
expect(ennemyPokemon.species).toEqual(Species.MEWTWO);
});
it("should create an ennemypokemon with specified moveset", () => {
const ennemyPokemon = new PokemonData({
species: Species.MEWTWO,
level: 100,
moveset: [
new PokemonMove(Moves.ACID),
new PokemonMove(Moves.ACROBATICS),
new PokemonMove(Moves.FOCUS_ENERGY),
]
});
expect(ennemyPokemon.moveset[0].moveId).toBe(Moves.ACID);
expect(ennemyPokemon.moveset[1].moveId).toBe(Moves.ACROBATICS);
expect(ennemyPokemon.moveset[2].moveId).toBe(Moves.FOCUS_ENERGY);
});
});

View File

@ -1,2 +1,19 @@
import "vitest-canvas-mock"; import "vitest-canvas-mock";
import "#app/test/phaser.setup"; import "#app/test/phaser.setup";
import {initStatsKeys} from "#app/ui/game-stats-ui-handler";
import {initPokemonPrevolutions} from "#app/data/pokemon-evolutions";
import {initBiomes} from "#app/data/biomes";
import {initEggMoves} from "#app/data/egg-moves";
import {initPokemonForms} from "#app/data/pokemon-forms";
import {initSpecies} from "#app/data/pokemon-species";
import {initMoves} from "#app/data/move";
import {initAbilities} from "#app/data/ability";
initStatsKeys();
initPokemonPrevolutions();
initBiomes();
initEggMoves();
initPokemonForms();
initSpecies();
initMoves();
initAbilities();

View File

@ -35,6 +35,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
private nameText: Phaser.GameObjects.Text; private nameText: Phaser.GameObjects.Text;
private genderText: Phaser.GameObjects.Text; private genderText: Phaser.GameObjects.Text;
private ownedIcon: Phaser.GameObjects.Sprite; private ownedIcon: Phaser.GameObjects.Sprite;
private championRibbon: Phaser.GameObjects.Sprite;
private teraIcon: Phaser.GameObjects.Sprite; private teraIcon: Phaser.GameObjects.Sprite;
private shinyIcon: Phaser.GameObjects.Sprite; private shinyIcon: Phaser.GameObjects.Sprite;
private fusionShinyIcon: Phaser.GameObjects.Sprite; private fusionShinyIcon: Phaser.GameObjects.Sprite;
@ -78,27 +79,39 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.setVisible(false); this.setVisible(false);
this.box = this.scene.add.sprite(0, 0, this.getTextureName()); this.box = this.scene.add.sprite(0, 0, this.getTextureName());
this.box.setName("box");
this.box.setOrigin(1, 0.5); this.box.setOrigin(1, 0.5);
this.add(this.box); this.add(this.box);
this.nameText = addTextObject(this.scene, player ? -115 : -124, player ? -15.2 : -11.2, "", TextStyle.BATTLE_INFO); this.nameText = addTextObject(this.scene, player ? -115 : -124, player ? -15.2 : -11.2, "", TextStyle.BATTLE_INFO);
this.nameText.setName("text_name");
this.nameText.setOrigin(0, 0); this.nameText.setOrigin(0, 0);
this.add(this.nameText); this.add(this.nameText);
this.genderText = addTextObject(this.scene, 0, 0, "", TextStyle.BATTLE_INFO); this.genderText = addTextObject(this.scene, 0, 0, "", TextStyle.BATTLE_INFO);
this.genderText.setName("text_gender");
this.genderText.setOrigin(0, 0); this.genderText.setOrigin(0, 0);
this.genderText.setPositionRelative(this.nameText, 0, 2); this.genderText.setPositionRelative(this.nameText, 0, 2);
this.add(this.genderText); this.add(this.genderText);
if (!this.player) { if (!this.player) {
this.ownedIcon = this.scene.add.sprite(0, 0, "icon_owned"); this.ownedIcon = this.scene.add.sprite(0, 0, "icon_owned");
this.ownedIcon.setName("icon_owned");
this.ownedIcon.setVisible(false); this.ownedIcon.setVisible(false);
this.ownedIcon.setOrigin(0, 0); this.ownedIcon.setOrigin(0, 0);
this.ownedIcon.setPositionRelative(this.nameText, 0, 11.75); this.ownedIcon.setPositionRelative(this.nameText, 0, 11.75);
this.add(this.ownedIcon); this.add(this.ownedIcon);
this.championRibbon = this.scene.add.sprite(0, 0, "champion_ribbon");
this.championRibbon.setName("icon_champion_ribbon");
this.championRibbon.setVisible(false);
this.championRibbon.setOrigin(0, 0);
this.championRibbon.setPositionRelative(this.nameText, 11.75, 11.75);
this.add(this.championRibbon);
} }
this.teraIcon = this.scene.add.sprite(0, 0, "icon_tera"); this.teraIcon = this.scene.add.sprite(0, 0, "icon_tera");
this.teraIcon.setName("icon_tera");
this.teraIcon.setVisible(false); this.teraIcon.setVisible(false);
this.teraIcon.setOrigin(0, 0); this.teraIcon.setOrigin(0, 0);
this.teraIcon.setScale(0.5); this.teraIcon.setScale(0.5);
@ -107,6 +120,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.add(this.teraIcon); this.add(this.teraIcon);
this.shinyIcon = this.scene.add.sprite(0, 0, "shiny_star"); this.shinyIcon = this.scene.add.sprite(0, 0, "shiny_star");
this.shinyIcon.setName("icon_shiny");
this.shinyIcon.setVisible(false); this.shinyIcon.setVisible(false);
this.shinyIcon.setOrigin(0, 0); this.shinyIcon.setOrigin(0, 0);
this.shinyIcon.setScale(0.5); this.shinyIcon.setScale(0.5);
@ -115,6 +129,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.add(this.shinyIcon); this.add(this.shinyIcon);
this.fusionShinyIcon = this.scene.add.sprite(0, 0, "shiny_star_2"); this.fusionShinyIcon = this.scene.add.sprite(0, 0, "shiny_star_2");
this.fusionShinyIcon.setName("icon_fusion_shiny");
this.fusionShinyIcon.setVisible(false); this.fusionShinyIcon.setVisible(false);
this.fusionShinyIcon.setOrigin(0, 0); this.fusionShinyIcon.setOrigin(0, 0);
this.fusionShinyIcon.setScale(0.5); this.fusionShinyIcon.setScale(0.5);
@ -122,6 +137,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.add(this.fusionShinyIcon); this.add(this.fusionShinyIcon);
this.splicedIcon = this.scene.add.sprite(0, 0, "icon_spliced"); this.splicedIcon = this.scene.add.sprite(0, 0, "icon_spliced");
this.splicedIcon.setName("icon_spliced");
this.splicedIcon.setVisible(false); this.splicedIcon.setVisible(false);
this.splicedIcon.setOrigin(0, 0); this.splicedIcon.setOrigin(0, 0);
this.splicedIcon.setScale(0.5); this.splicedIcon.setScale(0.5);
@ -130,31 +146,37 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
this.add(this.splicedIcon); this.add(this.splicedIcon);
this.statusIndicator = this.scene.add.sprite(0, 0, "statuses"); this.statusIndicator = this.scene.add.sprite(0, 0, "statuses");
this.statusIndicator.setName("icon_status");
this.statusIndicator.setVisible(false); this.statusIndicator.setVisible(false);
this.statusIndicator.setOrigin(0, 0); this.statusIndicator.setOrigin(0, 0);
this.statusIndicator.setPositionRelative(this.nameText, 0, 11.5); this.statusIndicator.setPositionRelative(this.nameText, 0, 11.5);
this.add(this.statusIndicator); this.add(this.statusIndicator);
this.levelContainer = this.scene.add.container(player ? -41 : -50, player ? -10 : -5); this.levelContainer = this.scene.add.container(player ? -41 : -50, player ? -10 : -5);
this.levelContainer.setName("container_level");
this.add(this.levelContainer); this.add(this.levelContainer);
const levelOverlay = this.scene.add.image(0, 0, "overlay_lv"); const levelOverlay = this.scene.add.image(0, 0, "overlay_lv");
this.levelContainer.add(levelOverlay); this.levelContainer.add(levelOverlay);
this.hpBar = this.scene.add.image(player ? -61 : -71, player ? -1 : 4.5, "overlay_hp"); this.hpBar = this.scene.add.image(player ? -61 : -71, player ? -1 : 4.5, "overlay_hp");
this.hpBar.setName("hp_bar");
this.hpBar.setOrigin(0); this.hpBar.setOrigin(0);
this.add(this.hpBar); this.add(this.hpBar);
this.hpBarSegmentDividers = []; this.hpBarSegmentDividers = [];
this.levelNumbersContainer = this.scene.add.container(9.5, (this.scene as BattleScene).uiTheme ? 0 : -0.5); this.levelNumbersContainer = this.scene.add.container(9.5, (this.scene as BattleScene).uiTheme ? 0 : -0.5);
this.levelNumbersContainer.setName("container_level");
this.levelContainer.add(this.levelNumbersContainer); this.levelContainer.add(this.levelNumbersContainer);
if (this.player) { if (this.player) {
this.hpNumbersContainer = this.scene.add.container(-15, 10); this.hpNumbersContainer = this.scene.add.container(-15, 10);
this.hpNumbersContainer.setName("container_hp");
this.add(this.hpNumbersContainer); this.add(this.hpNumbersContainer);
const expBar = this.scene.add.image(-98, 18, "overlay_exp"); const expBar = this.scene.add.image(-98, 18, "overlay_exp");
expBar.setName("overlay_exp");
expBar.setOrigin(0); expBar.setOrigin(0);
this.add(expBar); this.add(expBar);
@ -173,10 +195,12 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
} }
this.statsContainer = this.scene.add.container(0, 0); this.statsContainer = this.scene.add.container(0, 0);
this.statsContainer.setName("container_stats");
this.statsContainer.setAlpha(0); this.statsContainer.setAlpha(0);
this.add(this.statsContainer); this.add(this.statsContainer);
this.statsBox = this.scene.add.sprite(0, 0, `${this.getTextureName()}_stats`); this.statsBox = this.scene.add.sprite(0, 0, `${this.getTextureName()}_stats`);
this.statsBox.setName("box_stats");
this.statsBox.setOrigin(1, 0.5); this.statsBox.setOrigin(1, 0.5);
this.statsContainer.add(this.statsBox); this.statsContainer.add(this.statsBox);
@ -190,25 +214,30 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
const statX = i > 1 ? this.statNumbers[i - 2].x + this.statNumbers[i - 2].width + 4 : -this.statsBox.width + 8; const statX = i > 1 ? this.statNumbers[i - 2].x + this.statNumbers[i - 2].width + 4 : -this.statsBox.width + 8;
const statY = -this.statsBox.height / 2 + 4 + (i < battleStatOrder.length - 1 ? (i % 2 ? 10 : 0) : 5); const statY = -this.statsBox.height / 2 + 4 + (i < battleStatOrder.length - 1 ? (i % 2 ? 10 : 0) : 5);
const statLabel = this.scene.add.sprite(statX, statY, "pbinfo_stat", BattleStat[s]); const statLabel = this.scene.add.sprite(statX, statY, "pbinfo_stat", BattleStat[s]);
statLabel.setName("icon_stat_label_" + i.toString());
statLabel.setOrigin(0, 0); statLabel.setOrigin(0, 0);
statLabels.push(statLabel); statLabels.push(statLabel);
this.statValuesContainer.add(statLabel); this.statValuesContainer.add(statLabel);
const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, "pbinfo_stat_numbers", "3"); const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, "pbinfo_stat_numbers", "3");
statNumber.setName("icon_stat_number_" + i.toString());
statNumber.setOrigin(0, 0); statNumber.setOrigin(0, 0);
this.statNumbers.push(statNumber); this.statNumbers.push(statNumber);
this.statValuesContainer.add(statNumber); this.statValuesContainer.add(statNumber);
}); });
this.type1Icon = this.scene.add.sprite(player ? -139 : -15, player ? -17 : -15.5, `pbinfo_${player ? "player" : "enemy"}_type1`); this.type1Icon = this.scene.add.sprite(player ? -139 : -15, player ? -17 : -15.5, `pbinfo_${player ? "player" : "enemy"}_type1`);
this.type1Icon.setName("icon_type_1");
this.type1Icon.setOrigin(0, 0); this.type1Icon.setOrigin(0, 0);
this.add(this.type1Icon); this.add(this.type1Icon);
this.type2Icon = this.scene.add.sprite(player ? -139 : -15, player ? -1 : -2.5, `pbinfo_${player ? "player" : "enemy"}_type2`); this.type2Icon = this.scene.add.sprite(player ? -139 : -15, player ? -1 : -2.5, `pbinfo_${player ? "player" : "enemy"}_type2`);
this.type2Icon.setName("icon_type_2");
this.type2Icon.setOrigin(0, 0); this.type2Icon.setOrigin(0, 0);
this.add(this.type2Icon); this.add(this.type2Icon);
this.type3Icon = this.scene.add.sprite(player ? -154 : 0, player ? -17 : -15.5, `pbinfo_${player ? "player" : "enemy"}_type`); this.type3Icon = this.scene.add.sprite(player ? -154 : 0, player ? -17 : -15.5, `pbinfo_${player ? "player" : "enemy"}_type`);
this.type3Icon.setName("icon_type_3");
this.type3Icon.setOrigin(0, 0); this.type3Icon.setOrigin(0, 0);
this.add(this.type3Icon); this.add(this.type3Icon);
} }
@ -266,6 +295,11 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
const dexEntry = pokemon.scene.gameData.dexData[pokemon.species.speciesId]; const dexEntry = pokemon.scene.gameData.dexData[pokemon.species.speciesId];
this.ownedIcon.setVisible(!!dexEntry.caughtAttr); this.ownedIcon.setVisible(!!dexEntry.caughtAttr);
const opponentPokemonDexAttr = pokemon.getDexAttr(); const opponentPokemonDexAttr = pokemon.getDexAttr();
if (pokemon.scene.gameMode.isClassic) {
if (pokemon.scene.gameData.starterData[pokemon.species.getRootSpeciesId()].classicWinCount > 0 && pokemon.scene.gameData.starterData[pokemon.species.getRootSpeciesId(true)].classicWinCount > 0) {
this.championRibbon.setVisible(true);
}
}
// Check if Player owns all genders and forms of the Pokemon // Check if Player owns all genders and forms of the Pokemon
const missingDexAttrs = ((dexEntry.caughtAttr & opponentPokemonDexAttr) < opponentPokemonDexAttr); const missingDexAttrs = ((dexEntry.caughtAttr & opponentPokemonDexAttr) < opponentPokemonDexAttr);
@ -378,7 +412,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
if (boss !== this.boss) { if (boss !== this.boss) {
this.boss = boss; this.boss = boss;
[ this.nameText, this.genderText, this.teraIcon, this.splicedIcon, this.shinyIcon, this.ownedIcon, this.statusIndicator, this.levelContainer, this.statValuesContainer ].map(e => e.x += 48 * (boss ? -1 : 1)); [ this.nameText, this.genderText, this.teraIcon, this.splicedIcon, this.shinyIcon, this.ownedIcon, this.championRibbon, this.statusIndicator, this.levelContainer, this.statValuesContainer ].map(e => e.x += 48 * (boss ? -1 : 1));
this.hpBar.x += 38 * (boss ? -1 : 1); this.hpBar.x += 38 * (boss ? -1 : 1);
this.hpBar.y += 2 * (this.boss ? -1 : 1); this.hpBar.y += 2 * (this.boss ? -1 : 1);
this.hpBar.setTexture(`overlay_hp${boss ? "_boss" : ""}`); this.hpBar.setTexture(`overlay_hp${boss ? "_boss" : ""}`);
@ -402,6 +436,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container {
const dividerX = (Math.round((maxHp / this.bossSegments) * s) / maxHp) * this.hpBar.width; const dividerX = (Math.round((maxHp / this.bossSegments) * s) / maxHp) * this.hpBar.width;
const divider = this.scene.add.rectangle(0, 0, 1, this.hpBar.height - (uiTheme ? 0 : 1), pokemon.bossSegmentIndex >= s ? 0xFFFFFF : 0x404040); const divider = this.scene.add.rectangle(0, 0, 1, this.hpBar.height - (uiTheme ? 0 : 1), pokemon.bossSegmentIndex >= s ? 0xFFFFFF : 0x404040);
divider.setOrigin(0.5, 0); divider.setOrigin(0.5, 0);
divider.setName("hpBar_divider_" + s.toString());
this.add(divider); this.add(divider);
this.moveBelow(divider as Phaser.GameObjects.GameObject, this.statsContainer); this.moveBelow(divider as Phaser.GameObjects.GameObject, this.statsContainer);

View File

@ -49,7 +49,7 @@ export default class EggListUiHandler extends MessageUiHandler {
this.iconAnimHandler = new PokemonIconAnimHandler(); this.iconAnimHandler = new PokemonIconAnimHandler();
this.iconAnimHandler.setup(this.scene); this.iconAnimHandler.setup(this.scene);
this.eggNameText = addTextObject(this.scene, 8, 66, "", TextStyle.SUMMARY); this.eggNameText = addTextObject(this.scene, 8, 68, "", TextStyle.SUMMARY);
this.eggNameText.setOrigin(0, 0); this.eggNameText.setOrigin(0, 0);
this.eggListContainer.add(this.eggNameText); this.eggListContainer.add(this.eggNameText);

View File

@ -230,7 +230,7 @@ export default class GameStatsUiHandler extends UiHandler {
} }
} }
(function () { export function initStatsKeys() {
const statKeys = Object.keys(displayStats); const statKeys = Object.keys(displayStats);
for (const key of statKeys) { for (const key of statKeys) {
@ -256,4 +256,4 @@ export default class GameStatsUiHandler extends UiHandler {
(displayStats[key] as DisplayStat).label = Utils.toReadableString(`${splittableKey[0].toUpperCase()}${splittableKey.slice(1)}`); (displayStats[key] as DisplayStat).label = Utils.toReadableString(`${splittableKey[0].toUpperCase()}${splittableKey.slice(1)}`);
} }
} }
})(); }

View File

@ -14,6 +14,7 @@ export default defineConfig(({ mode }) => {
} }
}, },
threads: false, threads: false,
trace: true,
environmentOptions: { environmentOptions: {
jsdom: { jsdom: {
resources: 'usable', resources: 'usable',