2024-03-01 01:08:50 +00:00
|
|
|
import BattleScene from "../battle-scene";
|
|
|
|
import { BiomePoolTier, BiomeTierPokemonPools, PokemonPools, BiomeTierTrainerPools, biomePokemonPools, biomeTrainerPools } from "../data/biomes";
|
|
|
|
import { Biome } from "../data/enums/biome";
|
|
|
|
import * as Utils from "../utils";
|
|
|
|
import PokemonSpecies, { getPokemonSpecies } from "../data/pokemon-species";
|
|
|
|
import { Species } from "../data/enums/species";
|
2024-03-10 02:57:33 +00:00
|
|
|
import { Weather, WeatherType, getTerrainClearMessage, getTerrainStartMessage, getWeatherClearMessage, getWeatherStartMessage } from "../data/weather";
|
2024-03-01 01:08:50 +00:00
|
|
|
import { CommonAnimPhase } from "../phases";
|
|
|
|
import { CommonAnim } from "../data/battle-anims";
|
|
|
|
import { Type } from "../data/type";
|
|
|
|
import Move from "../data/move";
|
|
|
|
import { ArenaTag, ArenaTagSide, getArenaTag } from "../data/arena-tag";
|
|
|
|
import { ArenaTagType } from "../data/enums/arena-tag-type";
|
|
|
|
import { TrainerType } from "../data/enums/trainer-type";
|
|
|
|
import { BattlerIndex } from "../battle";
|
|
|
|
import { Moves } from "../data/enums/moves";
|
|
|
|
import { TimeOfDay } from "../data/enums/time-of-day";
|
2024-03-14 04:40:57 +00:00
|
|
|
import { Terrain, TerrainType } from "../data/terrain";
|
2023-04-17 01:41:52 +01:00
|
|
|
|
2023-11-25 09:21:27 +00:00
|
|
|
const WEATHER_OVERRIDE = WeatherType.NONE;
|
2023-11-25 03:25:09 +00:00
|
|
|
|
2023-04-17 01:41:52 +01:00
|
|
|
export class Arena {
|
2023-04-22 00:30:04 +01:00
|
|
|
public scene: BattleScene;
|
2023-04-17 01:41:52 +01:00
|
|
|
public biomeType: Biome;
|
|
|
|
public weather: Weather;
|
2024-03-10 02:57:33 +00:00
|
|
|
public terrain: Terrain;
|
2023-04-22 00:30:04 +01:00
|
|
|
public tags: ArenaTag[];
|
2023-10-10 01:20:02 +01:00
|
|
|
public bgm: string;
|
2024-03-14 04:40:57 +00:00
|
|
|
public ignoreAbilities: boolean;
|
|
|
|
|
2023-12-30 05:00:27 +00:00
|
|
|
private lastTimeOfDay: TimeOfDay;
|
|
|
|
|
|
|
|
private pokemonPool: PokemonPools;
|
2023-10-18 23:01:15 +01:00
|
|
|
private trainerPool: BiomeTierTrainerPools;
|
2023-04-17 01:41:52 +01:00
|
|
|
|
|
|
|
constructor(scene: BattleScene, biome: Biome, bgm: string) {
|
|
|
|
this.scene = scene;
|
|
|
|
this.biomeType = biome;
|
2023-04-22 00:30:04 +01:00
|
|
|
this.tags = [];
|
2023-04-17 01:41:52 +01:00
|
|
|
this.bgm = bgm;
|
2023-10-18 23:01:15 +01:00
|
|
|
this.trainerPool = biomeTrainerPools[biome];
|
2023-12-30 05:00:27 +00:00
|
|
|
this.updatePoolsForTimeOfDay();
|
|
|
|
}
|
|
|
|
|
|
|
|
updatePoolsForTimeOfDay(): void {
|
|
|
|
const timeOfDay = this.getTimeOfDay();
|
|
|
|
if (timeOfDay !== this.lastTimeOfDay) {
|
|
|
|
this.pokemonPool = {};
|
|
|
|
for (let tier of Object.keys(biomePokemonPools[this.biomeType]))
|
|
|
|
this.pokemonPool[tier] = Object.assign([], biomePokemonPools[this.biomeType][tier][TimeOfDay.ALL]).concat(biomePokemonPools[this.biomeType][tier][timeOfDay]);
|
|
|
|
this.lastTimeOfDay = timeOfDay;
|
|
|
|
}
|
2023-04-17 01:41:52 +01:00
|
|
|
}
|
|
|
|
|
2023-04-20 06:04:36 +01:00
|
|
|
randomSpecies(waveIndex: integer, level: integer, attempt?: integer): PokemonSpecies {
|
2024-01-08 04:17:24 +00:00
|
|
|
const isBoss = !!this.scene.getEncounterBossSegments(waveIndex, level) && !!this.pokemonPool[BiomePoolTier.BOSS].length
|
2024-03-14 20:26:57 +00:00
|
|
|
&& (this.biomeType !== Biome.END || this.scene.gameMode.isClassic || this.scene.gameMode.isWaveFinal(waveIndex));
|
2023-10-18 23:01:15 +01:00
|
|
|
const tierValue = Utils.randSeedInt(!isBoss ? 512 : 64);
|
2023-04-17 01:41:52 +01:00
|
|
|
let tier = !isBoss
|
|
|
|
? tierValue >= 156 ? BiomePoolTier.COMMON : tierValue >= 32 ? BiomePoolTier.UNCOMMON : tierValue >= 6 ? BiomePoolTier.RARE : tierValue >= 1 ? BiomePoolTier.SUPER_RARE : BiomePoolTier.ULTRA_RARE
|
|
|
|
: tierValue >= 20 ? BiomePoolTier.BOSS : tierValue >= 6 ? BiomePoolTier.BOSS_RARE : tierValue >= 1 ? BiomePoolTier.BOSS_SUPER_RARE : BiomePoolTier.BOSS_ULTRA_RARE;
|
2023-04-19 19:07:38 +01:00
|
|
|
console.log(BiomePoolTier[tier]);
|
2023-04-17 01:41:52 +01:00
|
|
|
while (!this.pokemonPool[tier].length) {
|
|
|
|
console.log(`Downgraded rarity tier from ${BiomePoolTier[tier]} to ${BiomePoolTier[tier - 1]}`);
|
|
|
|
tier--;
|
|
|
|
}
|
|
|
|
const tierPool = this.pokemonPool[tier];
|
|
|
|
let ret: PokemonSpecies;
|
2023-04-20 06:04:36 +01:00
|
|
|
let regen = false;
|
2023-04-17 01:41:52 +01:00
|
|
|
if (!tierPool.length)
|
2023-04-19 19:07:38 +01:00
|
|
|
ret = this.scene.randomSpecies(waveIndex, level);
|
2023-04-17 01:41:52 +01:00
|
|
|
else {
|
2023-10-18 23:01:15 +01:00
|
|
|
const entry = tierPool[Utils.randSeedInt(tierPool.length)];
|
2023-04-17 01:41:52 +01:00
|
|
|
let species: Species;
|
|
|
|
if (typeof entry === 'number')
|
|
|
|
species = entry as Species;
|
|
|
|
else {
|
|
|
|
const levelThresholds = Object.keys(entry);
|
|
|
|
for (let l = levelThresholds.length - 1; l >= 0; l--) {
|
|
|
|
const levelThreshold = parseInt(levelThresholds[l]);
|
|
|
|
if (level >= levelThreshold) {
|
|
|
|
const speciesIds = entry[levelThreshold];
|
|
|
|
if (speciesIds.length > 1)
|
2023-10-18 23:01:15 +01:00
|
|
|
species = speciesIds[Utils.randSeedInt(speciesIds.length)];
|
2023-04-17 01:41:52 +01:00
|
|
|
else
|
|
|
|
species = speciesIds[0];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = getPokemonSpecies(species);
|
2023-04-20 06:04:36 +01:00
|
|
|
|
2023-05-02 21:58:18 +01:00
|
|
|
if (ret.pseudoLegendary || ret.legendary || ret.mythical) {
|
2023-04-20 06:04:36 +01:00
|
|
|
switch (true) {
|
|
|
|
case (ret.baseTotal >= 720):
|
|
|
|
regen = level < 90;
|
|
|
|
break;
|
|
|
|
case (ret.baseTotal >= 670):
|
|
|
|
regen = level < 70;
|
|
|
|
break;
|
|
|
|
case (ret.baseTotal >= 580):
|
|
|
|
regen = level < 50;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
regen = level < 30;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (regen && (attempt || 0) < 10) {
|
|
|
|
console.log('Incompatible level: regenerating...');
|
|
|
|
return this.randomSpecies(waveIndex, level, (attempt || 0) + 1);
|
2023-04-17 01:41:52 +01:00
|
|
|
}
|
2023-04-20 06:04:36 +01:00
|
|
|
|
2024-01-01 20:27:47 +00:00
|
|
|
const newSpeciesId = ret.getSpeciesForLevel(level, true, false, isBoss);
|
2023-04-17 01:41:52 +01:00
|
|
|
if (newSpeciesId !== ret.speciesId) {
|
|
|
|
console.log('Replaced', Species[ret.speciesId], 'with', Species[newSpeciesId]);
|
|
|
|
ret = getPokemonSpecies(newSpeciesId);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2023-10-18 23:01:15 +01:00
|
|
|
randomTrainerType(waveIndex: integer): TrainerType {
|
2024-01-05 00:37:07 +00:00
|
|
|
const isBoss = (waveIndex % 30) === 20 && !!this.trainerPool[BiomePoolTier.BOSS].length
|
2024-03-14 20:26:57 +00:00
|
|
|
&& (this.biomeType !== Biome.END || this.scene.gameMode.isClassic || this.scene.gameMode.isWaveFinal(waveIndex));
|
2023-10-18 23:01:15 +01:00
|
|
|
const tierValue = Utils.randSeedInt(!isBoss ? 512 : 64);
|
|
|
|
let tier = !isBoss
|
|
|
|
? tierValue >= 156 ? BiomePoolTier.COMMON : tierValue >= 32 ? BiomePoolTier.UNCOMMON : tierValue >= 6 ? BiomePoolTier.RARE : tierValue >= 1 ? BiomePoolTier.SUPER_RARE : BiomePoolTier.ULTRA_RARE
|
|
|
|
: tierValue >= 20 ? BiomePoolTier.BOSS : tierValue >= 6 ? BiomePoolTier.BOSS_RARE : tierValue >= 1 ? BiomePoolTier.BOSS_SUPER_RARE : BiomePoolTier.BOSS_ULTRA_RARE;
|
|
|
|
console.log(BiomePoolTier[tier]);
|
|
|
|
while (tier && !this.trainerPool[tier].length) {
|
|
|
|
console.log(`Downgraded trainer rarity tier from ${BiomePoolTier[tier]} to ${BiomePoolTier[tier - 1]}`);
|
|
|
|
tier--;
|
|
|
|
}
|
|
|
|
const tierPool = this.trainerPool[tier] || [];
|
|
|
|
return !tierPool.length ? TrainerType.BREEDER : tierPool[Utils.randSeedInt(tierPool.length)];
|
|
|
|
}
|
|
|
|
|
2023-10-30 18:57:23 +00:00
|
|
|
getSpeciesFormIndex(species: PokemonSpecies): integer {
|
2023-10-28 05:18:44 +01:00
|
|
|
switch (species.speciesId) {
|
|
|
|
case Species.BURMY:
|
|
|
|
case Species.WORMADAM:
|
|
|
|
switch (this.biomeType) {
|
|
|
|
case Biome.BEACH:
|
|
|
|
return 1;
|
2023-12-14 05:41:35 +00:00
|
|
|
case Biome.SLUM:
|
2023-10-28 05:18:44 +01:00
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
break;
|
2023-12-08 21:29:03 +00:00
|
|
|
case Species.SCATTERBUG:
|
|
|
|
case Species.SPEWPA:
|
|
|
|
case Species.VIVILLON:
|
|
|
|
return 0;
|
2023-12-12 20:32:50 +00:00
|
|
|
case Species.LYCANROC:
|
2023-12-30 02:04:40 +00:00
|
|
|
const timeOfDay = this.getTimeOfDay();
|
|
|
|
switch (timeOfDay) {
|
|
|
|
case TimeOfDay.DAY:
|
|
|
|
case TimeOfDay.DAWN:
|
|
|
|
return 0;
|
|
|
|
case TimeOfDay.DUSK:
|
2023-12-12 20:32:50 +00:00
|
|
|
return 2;
|
2023-12-30 02:04:40 +00:00
|
|
|
case TimeOfDay.NIGHT:
|
|
|
|
return 1;
|
2023-12-12 20:32:50 +00:00
|
|
|
}
|
2023-12-14 05:41:35 +00:00
|
|
|
case Species.CALYREX:
|
|
|
|
switch (this.biomeType) {
|
|
|
|
case Biome.SNOWY_FOREST:
|
|
|
|
return 1;
|
|
|
|
case Biome.GRAVEYARD:
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
break;
|
2023-10-28 05:18:44 +01:00
|
|
|
}
|
2023-10-30 18:57:23 +00:00
|
|
|
|
2023-04-18 03:44:41 +01:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2023-04-22 00:30:04 +01:00
|
|
|
getTypeForBiome() {
|
|
|
|
switch (this.biomeType) {
|
2023-04-22 01:29:22 +01:00
|
|
|
case Biome.TOWN:
|
2023-04-22 00:30:04 +01:00
|
|
|
case Biome.PLAINS:
|
2023-12-14 05:41:35 +00:00
|
|
|
case Biome.METROPOLIS:
|
2023-04-22 00:30:04 +01:00
|
|
|
return Type.NORMAL;
|
|
|
|
case Biome.GRASS:
|
|
|
|
case Biome.TALL_GRASS:
|
|
|
|
return Type.GRASS;
|
2023-05-01 06:00:46 +01:00
|
|
|
case Biome.FOREST:
|
|
|
|
return Type.BUG;
|
2023-12-14 05:41:35 +00:00
|
|
|
case Biome.SLUM:
|
2023-04-22 00:30:04 +01:00
|
|
|
case Biome.SWAMP:
|
|
|
|
return Type.POISON;
|
|
|
|
case Biome.SEA:
|
|
|
|
case Biome.BEACH:
|
|
|
|
case Biome.LAKE:
|
|
|
|
case Biome.SEABED:
|
|
|
|
return Type.WATER;
|
|
|
|
case Biome.MOUNTAIN:
|
|
|
|
return Type.FLYING;
|
2023-05-11 15:31:39 +01:00
|
|
|
case Biome.BADLANDS:
|
2023-04-22 00:30:04 +01:00
|
|
|
return Type.GROUND;
|
|
|
|
case Biome.CAVE:
|
|
|
|
case Biome.DESERT:
|
|
|
|
return Type.ROCK;
|
|
|
|
case Biome.ICE_CAVE:
|
2023-12-14 05:41:35 +00:00
|
|
|
case Biome.SNOWY_FOREST:
|
2023-04-22 00:30:04 +01:00
|
|
|
return Type.ICE;
|
|
|
|
case Biome.MEADOW:
|
2023-12-12 04:24:33 +00:00
|
|
|
case Biome.FAIRY_CAVE:
|
2023-12-12 20:32:50 +00:00
|
|
|
case Biome.ISLAND:
|
2023-04-22 00:30:04 +01:00
|
|
|
return Type.FAIRY;
|
|
|
|
case Biome.POWER_PLANT:
|
|
|
|
return Type.ELECTRIC;
|
|
|
|
case Biome.VOLCANO:
|
|
|
|
return Type.FIRE;
|
|
|
|
case Biome.GRAVEYARD:
|
2023-12-12 05:14:30 +00:00
|
|
|
case Biome.TEMPLE:
|
2023-04-22 00:30:04 +01:00
|
|
|
return Type.GHOST;
|
|
|
|
case Biome.DOJO:
|
|
|
|
return Type.FIGHTING;
|
2023-05-01 06:00:46 +01:00
|
|
|
case Biome.FACTORY:
|
|
|
|
return Type.STEEL;
|
2023-04-22 00:30:04 +01:00
|
|
|
case Biome.RUINS:
|
2023-04-26 22:40:08 +01:00
|
|
|
case Biome.SPACE:
|
2023-04-22 00:30:04 +01:00
|
|
|
return Type.PSYCHIC;
|
|
|
|
case Biome.WASTELAND:
|
2023-05-01 06:00:46 +01:00
|
|
|
case Biome.END:
|
2023-04-22 00:30:04 +01:00
|
|
|
return Type.DRAGON;
|
|
|
|
case Biome.ABYSS:
|
|
|
|
return Type.DARK;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-10 02:57:33 +00:00
|
|
|
getBgTerrainColorRatioForBiome(): number {
|
|
|
|
switch (this.biomeType) {
|
|
|
|
case Biome.SPACE:
|
|
|
|
return 1;
|
|
|
|
case Biome.END:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 83 / 132;
|
|
|
|
}
|
|
|
|
|
2023-11-25 03:25:09 +00:00
|
|
|
trySetWeatherOverride(weather: WeatherType): boolean {
|
|
|
|
this.weather = new Weather(weather, 0);
|
|
|
|
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.SUNNY + (weather - 1)));
|
|
|
|
this.scene.queueMessage(getWeatherStartMessage(weather));
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
2023-04-17 05:46:50 +01:00
|
|
|
trySetWeather(weather: WeatherType, viaMove: boolean): boolean {
|
2023-11-25 03:25:09 +00:00
|
|
|
// override hook for debugging
|
|
|
|
if (WEATHER_OVERRIDE) {
|
|
|
|
return this.trySetWeatherOverride(WEATHER_OVERRIDE);
|
|
|
|
}
|
|
|
|
|
2023-04-19 04:54:07 +01:00
|
|
|
if (this.weather?.weatherType === (weather || undefined))
|
2023-04-17 01:41:52 +01:00
|
|
|
return false;
|
|
|
|
|
2023-04-17 05:46:50 +01:00
|
|
|
const oldWeatherType = this.weather?.weatherType || WeatherType.NONE;
|
|
|
|
|
2023-11-25 03:25:09 +00:00
|
|
|
this.weather = weather ? new Weather(weather, viaMove ? 5 : 0) : null;
|
|
|
|
|
2023-04-17 05:46:50 +01:00
|
|
|
if (this.weather) {
|
2023-05-18 16:11:06 +01:00
|
|
|
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.SUNNY + (weather - 1)));
|
2023-04-22 00:30:04 +01:00
|
|
|
this.scene.queueMessage(getWeatherStartMessage(weather));
|
2023-04-17 05:46:50 +01:00
|
|
|
} else
|
2023-04-22 00:30:04 +01:00
|
|
|
this.scene.queueMessage(getWeatherClearMessage(oldWeatherType));
|
2023-04-17 05:46:50 +01:00
|
|
|
|
2023-04-17 01:41:52 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2024-03-10 02:57:33 +00:00
|
|
|
trySetTerrain(terrain: TerrainType, viaMove: boolean, ignoreAnim: boolean = false): boolean {
|
|
|
|
if (this.terrain?.terrainType === (terrain || undefined))
|
|
|
|
return false;
|
|
|
|
|
|
|
|
const oldTerrainType = this.terrain?.terrainType || TerrainType.NONE;
|
|
|
|
|
|
|
|
this.terrain = terrain ? new Terrain(terrain, viaMove ? 5 : 0) : null;
|
|
|
|
|
|
|
|
if (this.terrain) {
|
|
|
|
if (!ignoreAnim)
|
|
|
|
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.MISTY_TERRAIN + (terrain - 1)));
|
|
|
|
this.scene.queueMessage(getTerrainStartMessage(terrain));
|
|
|
|
} else
|
|
|
|
this.scene.queueMessage(getTerrainClearMessage(oldTerrainType));
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-04-22 00:30:04 +01:00
|
|
|
isMoveWeatherCancelled(move: Move) {
|
2023-04-27 19:30:03 +01:00
|
|
|
return this.weather && !this.weather.isEffectSuppressed(this.scene) && this.weather.isMoveWeatherCancelled(move);
|
2023-04-22 00:30:04 +01:00
|
|
|
}
|
|
|
|
|
2024-03-10 02:57:33 +00:00
|
|
|
getAttackTypeMultiplier(attackType: Type, grounded: boolean): number {
|
|
|
|
let weatherMultiplier = 1;
|
|
|
|
if (this.weather && !this.weather.isEffectSuppressed(this.scene))
|
|
|
|
weatherMultiplier = this.weather.getAttackTypeMultiplier(attackType);
|
|
|
|
|
|
|
|
let terrainMultiplier = 1;
|
|
|
|
if (this.terrain && !grounded)
|
|
|
|
terrainMultiplier = this.terrain.getAttackTypeMultiplier(attackType);
|
2023-04-27 19:30:03 +01:00
|
|
|
|
2024-03-10 02:57:33 +00:00
|
|
|
return weatherMultiplier * terrainMultiplier;
|
2023-04-17 05:46:50 +01:00
|
|
|
}
|
|
|
|
|
2023-10-18 23:01:15 +01:00
|
|
|
getTrainerChance(): integer {
|
|
|
|
switch (this.biomeType) {
|
2023-12-14 05:41:35 +00:00
|
|
|
case Biome.METROPOLIS:
|
|
|
|
return 2;
|
|
|
|
case Biome.SLUM:
|
2023-10-18 23:01:15 +01:00
|
|
|
case Biome.BEACH:
|
|
|
|
case Biome.DOJO:
|
|
|
|
case Biome.CONSTRUCTION_SITE:
|
|
|
|
return 4;
|
|
|
|
case Biome.PLAINS:
|
|
|
|
case Biome.GRASS:
|
|
|
|
case Biome.LAKE:
|
|
|
|
case Biome.CAVE:
|
|
|
|
return 6;
|
|
|
|
case Biome.TALL_GRASS:
|
|
|
|
case Biome.FOREST:
|
|
|
|
case Biome.SEA:
|
|
|
|
case Biome.SWAMP:
|
|
|
|
case Biome.MOUNTAIN:
|
|
|
|
case Biome.BADLANDS:
|
|
|
|
case Biome.DESERT:
|
|
|
|
case Biome.MEADOW:
|
|
|
|
case Biome.POWER_PLANT:
|
|
|
|
case Biome.GRAVEYARD:
|
|
|
|
case Biome.FACTORY:
|
2023-12-14 05:41:35 +00:00
|
|
|
case Biome.SNOWY_FOREST:
|
2023-10-18 23:01:15 +01:00
|
|
|
return 8;
|
|
|
|
case Biome.ICE_CAVE:
|
|
|
|
case Biome.VOLCANO:
|
|
|
|
case Biome.RUINS:
|
|
|
|
case Biome.WASTELAND:
|
|
|
|
case Biome.JUNGLE:
|
2023-12-12 04:24:33 +00:00
|
|
|
case Biome.FAIRY_CAVE:
|
2023-10-18 23:01:15 +01:00
|
|
|
return 12;
|
|
|
|
case Biome.SEABED:
|
|
|
|
case Biome.ABYSS:
|
|
|
|
case Biome.SPACE:
|
2023-12-12 05:14:30 +00:00
|
|
|
case Biome.TEMPLE:
|
2023-10-18 23:01:15 +01:00
|
|
|
return 16;
|
|
|
|
default:
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-30 02:04:40 +00:00
|
|
|
getTimeOfDay(): TimeOfDay {
|
2023-04-17 01:41:52 +01:00
|
|
|
switch (this.biomeType) {
|
2023-12-30 02:04:40 +00:00
|
|
|
case Biome.ABYSS:
|
|
|
|
return TimeOfDay.NIGHT;
|
|
|
|
}
|
|
|
|
|
2024-03-16 01:59:34 +00:00
|
|
|
const waveCycle = ((this.scene.currentBattle?.waveIndex || 0) + this.scene.waveCycleOffset) % 40;
|
2023-12-30 02:04:40 +00:00
|
|
|
|
|
|
|
if (waveCycle < 15)
|
|
|
|
return TimeOfDay.DAY;
|
|
|
|
|
|
|
|
if (waveCycle < 20)
|
2023-12-30 05:00:27 +00:00
|
|
|
return TimeOfDay.DUSK;
|
2023-12-30 02:04:40 +00:00
|
|
|
|
|
|
|
if (waveCycle < 35)
|
|
|
|
return TimeOfDay.NIGHT;
|
|
|
|
|
2023-12-30 05:00:27 +00:00
|
|
|
return TimeOfDay.DAWN;
|
2023-12-30 02:04:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isOutside(): boolean {
|
|
|
|
switch (this.biomeType) {
|
|
|
|
case Biome.SEABED:
|
|
|
|
case Biome.CAVE:
|
|
|
|
case Biome.ICE_CAVE:
|
|
|
|
case Biome.POWER_PLANT:
|
2023-04-17 01:41:52 +01:00
|
|
|
case Biome.DOJO:
|
2023-12-30 02:04:40 +00:00
|
|
|
case Biome.FACTORY:
|
|
|
|
case Biome.ABYSS:
|
|
|
|
case Biome.FAIRY_CAVE:
|
|
|
|
case Biome.TEMPLE:
|
|
|
|
case Biome.LABORATORY:
|
|
|
|
return false;
|
|
|
|
default:
|
2023-04-17 01:41:52 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-12-30 02:04:40 +00:00
|
|
|
getDayTint(): [integer, integer, integer] {
|
|
|
|
switch (this.biomeType) {
|
|
|
|
case Biome.ABYSS:
|
|
|
|
return [ 64, 64, 64 ];
|
|
|
|
default:
|
|
|
|
return [ 128, 128, 128 ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getDuskTint(): [integer, integer, integer] {
|
|
|
|
if (!this.isOutside())
|
|
|
|
return [ 0, 0, 0 ];
|
|
|
|
|
|
|
|
switch (this.biomeType) {
|
|
|
|
default:
|
|
|
|
return [ 98, 48, 73 ].map(c => Math.round((c + 128) / 2)) as [integer, integer, integer];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getNightTint(): [integer, integer, integer] {
|
|
|
|
switch (this.biomeType) {
|
|
|
|
case Biome.ABYSS:
|
|
|
|
case Biome.SPACE:
|
|
|
|
case Biome.END:
|
|
|
|
return this.getDayTint();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.isOutside())
|
|
|
|
return [ 64, 64, 64 ];
|
|
|
|
|
|
|
|
switch (this.biomeType) {
|
|
|
|
default:
|
|
|
|
return [ 48, 48, 98 ];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-14 04:40:57 +00:00
|
|
|
setIgnoreAbilities(ignoreAbilities: boolean = true): void {
|
|
|
|
this.ignoreAbilities = ignoreAbilities;
|
|
|
|
}
|
|
|
|
|
2024-01-16 04:29:22 +00:00
|
|
|
applyTagsForSide(tagType: ArenaTagType | { new(...args: any[]): ArenaTag }, side: ArenaTagSide, ...args: any[]): void {
|
|
|
|
let tags = typeof tagType === 'string'
|
2023-04-22 00:30:04 +01:00
|
|
|
? this.tags.filter(t => t.tagType === tagType)
|
|
|
|
: this.tags.filter(t => t instanceof tagType);
|
2024-01-16 04:29:22 +00:00
|
|
|
if (side !== ArenaTagSide.BOTH)
|
|
|
|
tags = tags.filter(t => t.side === side);
|
|
|
|
tags.forEach(t => t.apply(this, args));
|
|
|
|
}
|
|
|
|
|
|
|
|
applyTags(tagType: ArenaTagType | { new(...args: any[]): ArenaTag }, ...args: any[]): void {
|
2024-02-09 19:48:20 +00:00
|
|
|
this.applyTagsForSide(tagType, ArenaTagSide.BOTH, ...args);
|
2023-04-22 00:30:04 +01:00
|
|
|
}
|
|
|
|
|
2024-01-16 04:29:22 +00:00
|
|
|
addTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer, side: ArenaTagSide = ArenaTagSide.BOTH, targetIndex?: BattlerIndex): boolean {
|
2023-04-22 00:30:04 +01:00
|
|
|
const existingTag = this.getTag(tagType);
|
|
|
|
if (existingTag) {
|
|
|
|
existingTag.onOverlap(this);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-01-16 04:29:22 +00:00
|
|
|
const newTag = getArenaTag(tagType, turnCount || 0, sourceMove, sourceId, targetIndex, side);
|
2023-04-22 00:30:04 +01:00
|
|
|
this.tags.push(newTag);
|
|
|
|
newTag.onAdd(this);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
getTag(tagType: ArenaTagType | { new(...args: any[]): ArenaTag }): ArenaTag {
|
2024-01-16 04:29:22 +00:00
|
|
|
return this.getTagOnSide(tagType, ArenaTagSide.BOTH);
|
|
|
|
}
|
|
|
|
|
|
|
|
getTagOnSide(tagType: ArenaTagType | { new(...args: any[]): ArenaTag }, side: ArenaTagSide): ArenaTag {
|
|
|
|
return typeof(tagType) === 'string'
|
2024-02-22 19:59:59 +00:00
|
|
|
? this.tags.find(t => t.tagType === tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side))
|
|
|
|
: this.tags.find(t => t instanceof tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side));
|
2023-04-22 00:30:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
lapseTags(): void {
|
|
|
|
const tags = this.tags;
|
|
|
|
tags.filter(t => !(t.lapse(this))).forEach(t => {
|
|
|
|
t.onRemove(this);
|
|
|
|
tags.splice(tags.indexOf(t), 1);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2023-12-14 14:35:15 +00:00
|
|
|
removeAllTags(): void {
|
2024-03-05 04:22:22 +00:00
|
|
|
while (this.tags.length) {
|
|
|
|
this.tags[0].onRemove(this);
|
|
|
|
this.tags.splice(0, 1);
|
2023-12-14 14:35:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-04-17 01:41:52 +01:00
|
|
|
preloadBgm(): void {
|
|
|
|
this.scene.loadBgm(this.bgm);
|
|
|
|
}
|
|
|
|
|
2023-04-26 04:56:38 +01:00
|
|
|
getBgmLoopPoint(): number {
|
|
|
|
switch (this.biomeType) {
|
|
|
|
case Biome.TOWN:
|
|
|
|
return 7.288;
|
|
|
|
case Biome.PLAINS:
|
|
|
|
return 7.693;
|
|
|
|
case Biome.GRASS:
|
|
|
|
return 1.995;
|
|
|
|
case Biome.TALL_GRASS:
|
|
|
|
return 9.608;
|
2023-12-14 05:41:35 +00:00
|
|
|
case Biome.METROPOLIS:
|
|
|
|
return 4.867;
|
2023-04-26 04:56:38 +01:00
|
|
|
case Biome.FOREST:
|
|
|
|
return 4.294;
|
|
|
|
case Biome.SEA:
|
|
|
|
return 1.672;
|
|
|
|
case Biome.SWAMP:
|
|
|
|
return 4.461;
|
|
|
|
case Biome.BEACH:
|
|
|
|
return 3.462;
|
|
|
|
case Biome.LAKE:
|
|
|
|
return 5.350;
|
|
|
|
case Biome.SEABED:
|
|
|
|
return 2.629;
|
|
|
|
case Biome.MOUNTAIN:
|
|
|
|
return 4.018;
|
2023-05-11 15:31:39 +01:00
|
|
|
case Biome.BADLANDS:
|
2023-04-26 04:56:38 +01:00
|
|
|
return 17.790;
|
|
|
|
case Biome.CAVE:
|
|
|
|
return 14.240;
|
|
|
|
case Biome.DESERT:
|
|
|
|
return 1.143;
|
|
|
|
case Biome.ICE_CAVE:
|
|
|
|
return 15.010;
|
|
|
|
case Biome.MEADOW:
|
|
|
|
return 3.891;
|
|
|
|
case Biome.POWER_PLANT:
|
|
|
|
return 2.810;
|
|
|
|
case Biome.VOLCANO:
|
|
|
|
return 5.116;
|
|
|
|
case Biome.GRAVEYARD:
|
|
|
|
return 3.232;
|
|
|
|
case Biome.DOJO:
|
|
|
|
return 6.205;
|
2023-05-01 06:00:46 +01:00
|
|
|
case Biome.FACTORY:
|
|
|
|
return 4.985;
|
2023-04-26 04:56:38 +01:00
|
|
|
case Biome.RUINS:
|
|
|
|
return 2.270;
|
|
|
|
case Biome.WASTELAND:
|
|
|
|
return 6.336;
|
|
|
|
case Biome.ABYSS:
|
|
|
|
return 5.130;
|
|
|
|
case Biome.SPACE:
|
|
|
|
return 21.347;
|
2023-10-10 04:43:19 +01:00
|
|
|
case Biome.CONSTRUCTION_SITE:
|
|
|
|
return 1.222;
|
|
|
|
case Biome.JUNGLE:
|
|
|
|
return 2.477;
|
2023-12-12 04:24:33 +00:00
|
|
|
case Biome.FAIRY_CAVE:
|
|
|
|
return 4.542;
|
2023-12-12 05:14:30 +00:00
|
|
|
case Biome.TEMPLE:
|
|
|
|
return 2.547;
|
2023-12-12 20:32:50 +00:00
|
|
|
case Biome.ISLAND:
|
|
|
|
return 2.751;
|
|
|
|
case Biome.LABORATORY:
|
|
|
|
return 0.797;
|
2023-12-14 05:41:35 +00:00
|
|
|
case Biome.SLUM:
|
|
|
|
return 1.221;
|
|
|
|
case Biome.SNOWY_FOREST:
|
|
|
|
return 3.047;
|
2023-04-26 04:56:38 +01:00
|
|
|
}
|
|
|
|
}
|
2023-05-09 17:43:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export function getBiomeKey(biome: Biome): string {
|
|
|
|
switch (biome) {
|
|
|
|
case Biome.POWER_PLANT:
|
|
|
|
return 'ruins';
|
2023-12-14 05:41:35 +00:00
|
|
|
case Biome.METROPOLIS:
|
|
|
|
return 'slum';
|
2023-10-10 04:43:19 +01:00
|
|
|
case Biome.JUNGLE:
|
|
|
|
return 'tall_grass';
|
2023-12-12 20:32:50 +00:00
|
|
|
case Biome.ISLAND:
|
|
|
|
return 'beach';
|
2023-05-09 17:43:28 +01:00
|
|
|
}
|
|
|
|
return Biome[biome].toLowerCase();
|
|
|
|
}
|
|
|
|
|
|
|
|
export function getBiomeHasProps(biomeType: Biome): boolean {
|
|
|
|
switch (biomeType) {
|
2023-05-11 17:16:10 +01:00
|
|
|
case Biome.BEACH:
|
2023-05-09 17:43:28 +01:00
|
|
|
case Biome.LAKE:
|
2023-05-11 17:16:10 +01:00
|
|
|
case Biome.SEABED:
|
2023-05-30 14:46:42 +01:00
|
|
|
case Biome.MOUNTAIN:
|
2023-05-11 15:31:39 +01:00
|
|
|
case Biome.BADLANDS:
|
2023-05-11 17:16:10 +01:00
|
|
|
case Biome.CAVE:
|
2023-05-09 17:43:28 +01:00
|
|
|
case Biome.DESERT:
|
2023-05-15 13:45:26 +01:00
|
|
|
case Biome.ICE_CAVE:
|
2023-05-31 15:21:38 +01:00
|
|
|
case Biome.MEADOW:
|
|
|
|
case Biome.VOLCANO:
|
|
|
|
case Biome.GRAVEYARD:
|
2023-06-01 18:54:52 +01:00
|
|
|
case Biome.FACTORY:
|
2023-06-06 16:09:34 +01:00
|
|
|
case Biome.RUINS:
|
2023-05-30 15:21:09 +01:00
|
|
|
case Biome.WASTELAND:
|
2023-06-06 04:25:17 +01:00
|
|
|
case Biome.ABYSS:
|
2024-01-08 04:54:49 +00:00
|
|
|
case Biome.CONSTRUCTION_SITE:
|
2023-12-14 18:50:25 +00:00
|
|
|
case Biome.FAIRY_CAVE:
|
|
|
|
case Biome.TEMPLE:
|
|
|
|
case Biome.LABORATORY:
|
2023-12-16 04:07:32 +00:00
|
|
|
case Biome.END:
|
2023-05-09 17:43:28 +01:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
export class ArenaBase extends Phaser.GameObjects.Container {
|
|
|
|
public player: boolean;
|
|
|
|
public biome: Biome;
|
|
|
|
public propValue: integer;
|
|
|
|
public base: Phaser.GameObjects.Sprite;
|
|
|
|
public props: Phaser.GameObjects.Sprite[];
|
|
|
|
|
|
|
|
constructor(scene: BattleScene, player: boolean) {
|
|
|
|
super(scene, 0, 0);
|
|
|
|
|
|
|
|
this.player = player;
|
|
|
|
|
2024-03-10 02:57:33 +00:00
|
|
|
this.base = scene.addFieldSprite(0, 0, 'plains_a', null, 1);
|
2023-05-09 17:43:28 +01:00
|
|
|
this.base.setOrigin(0, 0);
|
|
|
|
|
|
|
|
this.props = !player ?
|
|
|
|
new Array(3).fill(null).map(() => {
|
2024-03-10 02:57:33 +00:00
|
|
|
const ret = scene.addFieldSprite(0, 0, 'plains_b', null, 1);
|
2023-05-09 17:43:28 +01:00
|
|
|
ret.setOrigin(0, 0);
|
|
|
|
ret.setVisible(false);
|
|
|
|
return ret;
|
|
|
|
}) : [];
|
|
|
|
}
|
|
|
|
|
|
|
|
setBiome(biome: Biome, propValue?: integer): void {
|
|
|
|
if (this.biome === biome)
|
|
|
|
return;
|
|
|
|
|
|
|
|
const hasProps = getBiomeHasProps(biome);
|
|
|
|
const biomeKey = getBiomeKey(biome);
|
2023-12-16 04:07:32 +00:00
|
|
|
const baseKey = `${biomeKey}_${this.player ? 'a' : 'b'}`;
|
|
|
|
|
|
|
|
this.base.setTexture(baseKey);
|
|
|
|
|
|
|
|
if (this.base.texture.frameTotal > 1) {
|
|
|
|
const baseFrameNames = this.scene.anims.generateFrameNames(baseKey, { zeroPad: 4, suffix: ".png", start: 1, end: this.base.texture.frameTotal - 1 });
|
|
|
|
this.scene.anims.create({
|
|
|
|
key: baseKey,
|
|
|
|
frames: baseFrameNames,
|
|
|
|
frameRate: 12,
|
|
|
|
repeat: -1
|
|
|
|
});
|
|
|
|
this.base.play(baseKey);
|
2023-12-31 15:33:34 +00:00
|
|
|
} else
|
|
|
|
this.base.stop();
|
2023-05-09 17:43:28 +01:00
|
|
|
|
|
|
|
this.add(this.base);
|
|
|
|
|
|
|
|
if (!this.player) {
|
2023-10-18 23:01:15 +01:00
|
|
|
(this.scene as BattleScene).executeWithSeedOffset(() => {
|
|
|
|
this.propValue = propValue === undefined
|
|
|
|
? hasProps ? Utils.randSeedInt(8) : 0
|
|
|
|
: propValue;
|
|
|
|
this.props.forEach((prop, p) => {
|
2023-12-16 04:07:32 +00:00
|
|
|
const propKey = `${biomeKey}_b${hasProps ? `_${p + 1}` : ''}`;
|
|
|
|
prop.setTexture(propKey);
|
|
|
|
|
|
|
|
if (hasProps && prop.texture.frameTotal > 1) {
|
|
|
|
const propFrameNames = this.scene.anims.generateFrameNames(propKey, { zeroPad: 4, suffix: ".png", start: 1, end: prop.texture.frameTotal - 1 });
|
|
|
|
this.scene.anims.create({
|
|
|
|
key: propKey,
|
|
|
|
frames: propFrameNames,
|
|
|
|
frameRate: 12,
|
|
|
|
repeat: -1
|
|
|
|
});
|
|
|
|
prop.play(propKey);
|
2023-12-31 15:33:34 +00:00
|
|
|
} else
|
|
|
|
prop.stop();
|
2023-12-16 04:07:32 +00:00
|
|
|
|
2023-10-18 23:01:15 +01:00
|
|
|
prop.setVisible(hasProps && !!(this.propValue & (1 << p)));
|
|
|
|
this.add(prop);
|
|
|
|
});
|
|
|
|
}, (this.scene as BattleScene).currentBattle?.waveIndex || 0);
|
2023-05-09 17:43:28 +01:00
|
|
|
}
|
|
|
|
}
|
2023-04-17 01:41:52 +01:00
|
|
|
}
|