mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-01 05:52:17 +02:00
* Add abilityAttr.is methods * [WIP] move modifier stuff around * Untangle circular deps from modifiers * Move unlockables to own file * Untangle all circular deps outside of MEs * Move constants in MEs to their own files * Re-add missing import to battle.ts * Add necessary overload for getTag * Add missing type import in weather.ts * Init modifier types and pools in loading-scene * Remove stray commented code * Apply kev's suggestions from code review Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
431 lines
13 KiB
TypeScript
431 lines
13 KiB
TypeScript
import { BiomeId } from "#enums/biome-id";
|
|
import { WeatherType } from "#enums/weather-type";
|
|
import { getPokemonNameWithAffix } from "../messages";
|
|
import type Pokemon from "../field/pokemon";
|
|
import { PokemonType } from "#enums/pokemon-type";
|
|
import type Move from "./moves/move";
|
|
import { randSeedInt } from "#app/utils/common";
|
|
import { TerrainType, getTerrainName } from "./terrain";
|
|
import i18next from "i18next";
|
|
import { globalScene } from "#app/global-scene";
|
|
import type { Arena } from "#app/field/arena";
|
|
import { timedEventManager } from "#app/global-event-manager";
|
|
import type { SuppressWeatherEffectAbAttr } from "./abilities/ability";
|
|
|
|
export class Weather {
|
|
public weatherType: WeatherType;
|
|
public turnsLeft: number;
|
|
|
|
constructor(weatherType: WeatherType, turnsLeft?: number) {
|
|
this.weatherType = weatherType;
|
|
this.turnsLeft = !this.isImmutable() ? turnsLeft || 0 : 0;
|
|
}
|
|
|
|
lapse(): boolean {
|
|
if (this.isImmutable()) {
|
|
return true;
|
|
}
|
|
if (this.turnsLeft) {
|
|
return !!--this.turnsLeft;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
isImmutable(): boolean {
|
|
switch (this.weatherType) {
|
|
case WeatherType.HEAVY_RAIN:
|
|
case WeatherType.HARSH_SUN:
|
|
case WeatherType.STRONG_WINDS:
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
isDamaging(): boolean {
|
|
switch (this.weatherType) {
|
|
case WeatherType.SANDSTORM:
|
|
case WeatherType.HAIL:
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
isTypeDamageImmune(type: PokemonType): boolean {
|
|
switch (this.weatherType) {
|
|
case WeatherType.SANDSTORM:
|
|
return type === PokemonType.GROUND || type === PokemonType.ROCK || type === PokemonType.STEEL;
|
|
case WeatherType.HAIL:
|
|
return type === PokemonType.ICE;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
getAttackTypeMultiplier(attackType: PokemonType): number {
|
|
switch (this.weatherType) {
|
|
case WeatherType.SUNNY:
|
|
case WeatherType.HARSH_SUN:
|
|
if (attackType === PokemonType.FIRE) {
|
|
return 1.5;
|
|
}
|
|
if (attackType === PokemonType.WATER) {
|
|
return 0.5;
|
|
}
|
|
break;
|
|
case WeatherType.RAIN:
|
|
case WeatherType.HEAVY_RAIN:
|
|
if (attackType === PokemonType.FIRE) {
|
|
return 0.5;
|
|
}
|
|
if (attackType === PokemonType.WATER) {
|
|
return 1.5;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
isMoveWeatherCancelled(user: Pokemon, move: Move): boolean {
|
|
const moveType = user.getMoveType(move);
|
|
|
|
switch (this.weatherType) {
|
|
case WeatherType.HARSH_SUN:
|
|
return move.is("AttackMove") && moveType === PokemonType.WATER;
|
|
case WeatherType.HEAVY_RAIN:
|
|
return move.is("AttackMove") && moveType === PokemonType.FIRE;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
isEffectSuppressed(): boolean {
|
|
const field = globalScene.getField(true);
|
|
|
|
for (const pokemon of field) {
|
|
let suppressWeatherEffectAbAttr: SuppressWeatherEffectAbAttr | null = pokemon
|
|
.getAbility()
|
|
.getAttrs("SuppressWeatherEffectAbAttr")[0];
|
|
if (!suppressWeatherEffectAbAttr) {
|
|
suppressWeatherEffectAbAttr = pokemon.hasPassive()
|
|
? pokemon.getPassiveAbility().getAttrs("SuppressWeatherEffectAbAttr")[0]
|
|
: null;
|
|
}
|
|
if (suppressWeatherEffectAbAttr && (!this.isImmutable() || suppressWeatherEffectAbAttr.affectsImmutable)) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
}
|
|
|
|
export function getWeatherStartMessage(weatherType: WeatherType): string | null {
|
|
switch (weatherType) {
|
|
case WeatherType.SUNNY:
|
|
return i18next.t("weather:sunnyStartMessage");
|
|
case WeatherType.RAIN:
|
|
return i18next.t("weather:rainStartMessage");
|
|
case WeatherType.SANDSTORM:
|
|
return i18next.t("weather:sandstormStartMessage");
|
|
case WeatherType.HAIL:
|
|
return i18next.t("weather:hailStartMessage");
|
|
case WeatherType.SNOW:
|
|
return i18next.t("weather:snowStartMessage");
|
|
case WeatherType.FOG:
|
|
return i18next.t("weather:fogStartMessage");
|
|
case WeatherType.HEAVY_RAIN:
|
|
return i18next.t("weather:heavyRainStartMessage");
|
|
case WeatherType.HARSH_SUN:
|
|
return i18next.t("weather:harshSunStartMessage");
|
|
case WeatherType.STRONG_WINDS:
|
|
return i18next.t("weather:strongWindsStartMessage");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export function getWeatherLapseMessage(weatherType: WeatherType): string | null {
|
|
switch (weatherType) {
|
|
case WeatherType.SUNNY:
|
|
return i18next.t("weather:sunnyLapseMessage");
|
|
case WeatherType.RAIN:
|
|
return i18next.t("weather:rainLapseMessage");
|
|
case WeatherType.SANDSTORM:
|
|
return i18next.t("weather:sandstormLapseMessage");
|
|
case WeatherType.HAIL:
|
|
return i18next.t("weather:hailLapseMessage");
|
|
case WeatherType.SNOW:
|
|
return i18next.t("weather:snowLapseMessage");
|
|
case WeatherType.FOG:
|
|
return i18next.t("weather:fogLapseMessage");
|
|
case WeatherType.HEAVY_RAIN:
|
|
return i18next.t("weather:heavyRainLapseMessage");
|
|
case WeatherType.HARSH_SUN:
|
|
return i18next.t("weather:harshSunLapseMessage");
|
|
case WeatherType.STRONG_WINDS:
|
|
return i18next.t("weather:strongWindsLapseMessage");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokemon): string | null {
|
|
switch (weatherType) {
|
|
case WeatherType.SANDSTORM:
|
|
return i18next.t("weather:sandstormDamageMessage", {
|
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
|
});
|
|
case WeatherType.HAIL:
|
|
return i18next.t("weather:hailDamageMessage", {
|
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
|
});
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export function getWeatherClearMessage(weatherType: WeatherType): string | null {
|
|
switch (weatherType) {
|
|
case WeatherType.SUNNY:
|
|
return i18next.t("weather:sunnyClearMessage");
|
|
case WeatherType.RAIN:
|
|
return i18next.t("weather:rainClearMessage");
|
|
case WeatherType.SANDSTORM:
|
|
return i18next.t("weather:sandstormClearMessage");
|
|
case WeatherType.HAIL:
|
|
return i18next.t("weather:hailClearMessage");
|
|
case WeatherType.SNOW:
|
|
return i18next.t("weather:snowClearMessage");
|
|
case WeatherType.FOG:
|
|
return i18next.t("weather:fogClearMessage");
|
|
case WeatherType.HEAVY_RAIN:
|
|
return i18next.t("weather:heavyRainClearMessage");
|
|
case WeatherType.HARSH_SUN:
|
|
return i18next.t("weather:harshSunClearMessage");
|
|
case WeatherType.STRONG_WINDS:
|
|
return i18next.t("weather:strongWindsClearMessage");
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
export function getLegendaryWeatherContinuesMessage(weatherType: WeatherType): string | null {
|
|
switch (weatherType) {
|
|
case WeatherType.HARSH_SUN:
|
|
return i18next.t("weather:harshSunContinueMessage");
|
|
case WeatherType.HEAVY_RAIN:
|
|
return i18next.t("weather:heavyRainContinueMessage");
|
|
case WeatherType.STRONG_WINDS:
|
|
return i18next.t("weather:strongWindsContinueMessage");
|
|
}
|
|
return null;
|
|
}
|
|
|
|
export function getWeatherBlockMessage(weatherType: WeatherType): string {
|
|
switch (weatherType) {
|
|
case WeatherType.HARSH_SUN:
|
|
return i18next.t("weather:harshSunEffectMessage");
|
|
case WeatherType.HEAVY_RAIN:
|
|
return i18next.t("weather:heavyRainEffectMessage");
|
|
}
|
|
return i18next.t("weather:defaultEffectMessage");
|
|
}
|
|
|
|
export function getTerrainStartMessage(terrainType: TerrainType): string | null {
|
|
switch (terrainType) {
|
|
case TerrainType.MISTY:
|
|
return i18next.t("terrain:mistyStartMessage");
|
|
case TerrainType.ELECTRIC:
|
|
return i18next.t("terrain:electricStartMessage");
|
|
case TerrainType.GRASSY:
|
|
return i18next.t("terrain:grassyStartMessage");
|
|
case TerrainType.PSYCHIC:
|
|
return i18next.t("terrain:psychicStartMessage");
|
|
default:
|
|
console.warn("getTerrainStartMessage not defined. Using default null");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function getTerrainClearMessage(terrainType: TerrainType): string | null {
|
|
switch (terrainType) {
|
|
case TerrainType.MISTY:
|
|
return i18next.t("terrain:mistyClearMessage");
|
|
case TerrainType.ELECTRIC:
|
|
return i18next.t("terrain:electricClearMessage");
|
|
case TerrainType.GRASSY:
|
|
return i18next.t("terrain:grassyClearMessage");
|
|
case TerrainType.PSYCHIC:
|
|
return i18next.t("terrain:psychicClearMessage");
|
|
default:
|
|
console.warn("getTerrainClearMessage not defined. Using default null");
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function getTerrainBlockMessage(pokemon: Pokemon, terrainType: TerrainType): string {
|
|
if (terrainType === TerrainType.MISTY) {
|
|
return i18next.t("terrain:mistyBlockMessage", {
|
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
|
});
|
|
}
|
|
return i18next.t("terrain:defaultBlockMessage", {
|
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
|
terrainName: getTerrainName(terrainType),
|
|
});
|
|
}
|
|
|
|
export interface WeatherPoolEntry {
|
|
weatherType: WeatherType;
|
|
weight: number;
|
|
}
|
|
|
|
export function getRandomWeatherType(arena: Arena): WeatherType {
|
|
let weatherPool: WeatherPoolEntry[] = [];
|
|
const hasSun = arena.getTimeOfDay() < 2;
|
|
switch (arena.biomeType) {
|
|
case BiomeId.GRASS:
|
|
weatherPool = [{ weatherType: WeatherType.NONE, weight: 7 }];
|
|
if (hasSun) {
|
|
weatherPool.push({ weatherType: WeatherType.SUNNY, weight: 3 });
|
|
}
|
|
break;
|
|
case BiomeId.TALL_GRASS:
|
|
weatherPool = [
|
|
{ weatherType: WeatherType.NONE, weight: 8 },
|
|
{ weatherType: WeatherType.RAIN, weight: 5 },
|
|
];
|
|
if (hasSun) {
|
|
weatherPool.push({ weatherType: WeatherType.SUNNY, weight: 8 });
|
|
}
|
|
break;
|
|
case BiomeId.FOREST:
|
|
weatherPool = [
|
|
{ weatherType: WeatherType.NONE, weight: 8 },
|
|
{ weatherType: WeatherType.RAIN, weight: 5 },
|
|
];
|
|
break;
|
|
case BiomeId.SEA:
|
|
weatherPool = [
|
|
{ weatherType: WeatherType.NONE, weight: 3 },
|
|
{ weatherType: WeatherType.RAIN, weight: 12 },
|
|
];
|
|
break;
|
|
case BiomeId.SWAMP:
|
|
weatherPool = [
|
|
{ weatherType: WeatherType.NONE, weight: 3 },
|
|
{ weatherType: WeatherType.RAIN, weight: 4 },
|
|
{ weatherType: WeatherType.FOG, weight: 1 },
|
|
];
|
|
break;
|
|
case BiomeId.BEACH:
|
|
weatherPool = [
|
|
{ weatherType: WeatherType.NONE, weight: 8 },
|
|
{ weatherType: WeatherType.RAIN, weight: 3 },
|
|
];
|
|
if (hasSun) {
|
|
weatherPool.push({ weatherType: WeatherType.SUNNY, weight: 5 });
|
|
}
|
|
break;
|
|
case BiomeId.LAKE:
|
|
weatherPool = [
|
|
{ weatherType: WeatherType.NONE, weight: 10 },
|
|
{ weatherType: WeatherType.RAIN, weight: 5 },
|
|
{ weatherType: WeatherType.FOG, weight: 1 },
|
|
];
|
|
break;
|
|
case BiomeId.SEABED:
|
|
weatherPool = [{ weatherType: WeatherType.RAIN, weight: 1 }];
|
|
break;
|
|
case BiomeId.BADLANDS:
|
|
weatherPool = [
|
|
{ weatherType: WeatherType.NONE, weight: 8 },
|
|
{ weatherType: WeatherType.SANDSTORM, weight: 2 },
|
|
];
|
|
if (hasSun) {
|
|
weatherPool.push({ weatherType: WeatherType.SUNNY, weight: 5 });
|
|
}
|
|
break;
|
|
case BiomeId.DESERT:
|
|
weatherPool = [{ weatherType: WeatherType.SANDSTORM, weight: 2 }];
|
|
if (hasSun) {
|
|
weatherPool.push({ weatherType: WeatherType.SUNNY, weight: 2 });
|
|
}
|
|
break;
|
|
case BiomeId.ICE_CAVE:
|
|
weatherPool = [
|
|
{ weatherType: WeatherType.NONE, weight: 3 },
|
|
{ weatherType: WeatherType.SNOW, weight: 4 },
|
|
{ weatherType: WeatherType.HAIL, weight: 1 },
|
|
];
|
|
break;
|
|
case BiomeId.MEADOW:
|
|
weatherPool = [{ weatherType: WeatherType.NONE, weight: 2 }];
|
|
if (hasSun) {
|
|
weatherPool.push({ weatherType: WeatherType.SUNNY, weight: 2 });
|
|
}
|
|
break;
|
|
case BiomeId.VOLCANO:
|
|
weatherPool = [
|
|
{
|
|
weatherType: hasSun ? WeatherType.SUNNY : WeatherType.NONE,
|
|
weight: 1,
|
|
},
|
|
];
|
|
break;
|
|
case BiomeId.GRAVEYARD:
|
|
weatherPool = [
|
|
{ weatherType: WeatherType.NONE, weight: 3 },
|
|
{ weatherType: WeatherType.FOG, weight: 1 },
|
|
];
|
|
break;
|
|
case BiomeId.JUNGLE:
|
|
weatherPool = [
|
|
{ weatherType: WeatherType.NONE, weight: 8 },
|
|
{ weatherType: WeatherType.RAIN, weight: 2 },
|
|
];
|
|
break;
|
|
case BiomeId.SNOWY_FOREST:
|
|
weatherPool = [
|
|
{ weatherType: WeatherType.SNOW, weight: 7 },
|
|
{ weatherType: WeatherType.HAIL, weight: 1 },
|
|
];
|
|
break;
|
|
case BiomeId.ISLAND:
|
|
weatherPool = [
|
|
{ weatherType: WeatherType.NONE, weight: 5 },
|
|
{ weatherType: WeatherType.RAIN, weight: 1 },
|
|
];
|
|
if (hasSun) {
|
|
weatherPool.push({ weatherType: WeatherType.SUNNY, weight: 2 });
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (arena.biomeType === BiomeId.TOWN && timedEventManager.isEventActive()) {
|
|
timedEventManager.getWeather()?.map(w => weatherPool.push(w));
|
|
}
|
|
|
|
if (weatherPool.length > 1) {
|
|
let totalWeight = 0;
|
|
for (const w of weatherPool) {
|
|
totalWeight += w.weight;
|
|
}
|
|
|
|
const rand = randSeedInt(totalWeight);
|
|
let w = 0;
|
|
for (const weather of weatherPool) {
|
|
w += weather.weight;
|
|
if (rand < w) {
|
|
return weather.weatherType;
|
|
}
|
|
}
|
|
}
|
|
|
|
return weatherPool.length ? weatherPool[0].weatherType : WeatherType.NONE;
|
|
}
|