Implement terrains and rework status logic
This commit is contained in:
parent
b9395ebd7f
commit
47cf14da9b
|
@ -468,8 +468,8 @@ export default class BattleScene extends Phaser.Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
launchBattle() {
|
launchBattle() {
|
||||||
this.arenaBg = this.addFieldSprite(0, 0, 'plains_bg');
|
this.arenaBg = this.addFieldSprite(0, 0, 'plains_bg', null, 0);
|
||||||
this.arenaBgTransition = this.addFieldSprite(0, 0, `plains_bg`);
|
this.arenaBgTransition = this.addFieldSprite(0, 0, `plains_bg`, null, 1);
|
||||||
|
|
||||||
[ this.arenaBgTransition, this.arenaBg ].forEach(a => {
|
[ this.arenaBgTransition, this.arenaBg ].forEach(a => {
|
||||||
a.setScale(6);
|
a.setScale(6);
|
||||||
|
@ -920,6 +920,7 @@ export default class BattleScene extends Phaser.Scene {
|
||||||
const biomeKey = getBiomeKey(biome);
|
const biomeKey = getBiomeKey(biome);
|
||||||
|
|
||||||
this.arenaBg.setTexture(`${biomeKey}_bg`);
|
this.arenaBg.setTexture(`${biomeKey}_bg`);
|
||||||
|
this.arenaBg.pipelineData['terrainColorRatio'] = this.arena.getBgTerrainColorRatioForBiome();
|
||||||
this.arenaBgTransition.setTexture(`${biomeKey}_bg`);
|
this.arenaBgTransition.setTexture(`${biomeKey}_bg`);
|
||||||
this.arenaPlayer.setBiome(biome);
|
this.arenaPlayer.setBiome(biome);
|
||||||
this.arenaPlayerTransition.setBiome(biome);
|
this.arenaPlayerTransition.setBiome(biome);
|
||||||
|
@ -1077,9 +1078,11 @@ export default class BattleScene extends Phaser.Scene {
|
||||||
Phaser.Math.RND.state(state);
|
Phaser.Math.RND.state(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
addFieldSprite(x: number, y: number, texture: string | Phaser.Textures.Texture, frame?: string | number): Phaser.GameObjects.Sprite {
|
addFieldSprite(x: number, y: number, texture: string | Phaser.Textures.Texture, frame?: string | number, terrainColorRatio: number = 0): Phaser.GameObjects.Sprite {
|
||||||
const ret = this.add.sprite(x, y, texture, frame);
|
const ret = this.add.sprite(x, y, texture, frame);
|
||||||
ret.setPipeline(this.fieldSpritePipeline);
|
ret.setPipeline(this.fieldSpritePipeline);
|
||||||
|
if (terrainColorRatio)
|
||||||
|
ret.pipelineData['terrainColorRatio'] = terrainColorRatio;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
|
||||||
import { Type } from "./type";
|
import { Type } from "./type";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { BattleStat, getBattleStatName } from "./battle-stat";
|
import { BattleStat, getBattleStatName } from "./battle-stat";
|
||||||
import { ObtainStatusEffectPhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases";
|
import { PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases";
|
||||||
import { getPokemonMessage } from "../messages";
|
import { getPokemonMessage } from "../messages";
|
||||||
import { Weather, WeatherType } from "./weather";
|
import { Weather, WeatherType } from "./weather";
|
||||||
import { BattlerTag } from "./battler-tags";
|
import { BattlerTag } from "./battler-tags";
|
||||||
|
@ -368,7 +368,7 @@ export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr {
|
||||||
applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
|
applyPostDefend(pokemon: Pokemon, attacker: Pokemon, move: PokemonMove, hitResult: HitResult, args: any[]): boolean {
|
||||||
if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) {
|
if (move.getMove().checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && pokemon.randSeedInt(100) < this.chance && !pokemon.status) {
|
||||||
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
|
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
|
||||||
pokemon.scene.unshiftPhase(new ObtainStatusEffectPhase(pokemon.scene, attacker.getBattlerIndex(), effect));
|
return pokemon.trySetStatus(effect, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
@ -1261,7 +1261,8 @@ export function applyPreStatChangeAbAttrs(attrType: { new(...args: any[]): PreSt
|
||||||
|
|
||||||
export function applyPreSetStatusAbAttrs(attrType: { new(...args: any[]): PreSetStatusAbAttr },
|
export function applyPreSetStatusAbAttrs(attrType: { new(...args: any[]): PreSetStatusAbAttr },
|
||||||
pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, ...args: any[]): Promise<void> {
|
||||||
return applyAbAttrsInternal<PreSetStatusAbAttr>(attrType, pokemon, attr => attr.applyPreSetStatus(pokemon, effect, cancelled, args));
|
const simulated = args.length > 1 && args[1];
|
||||||
|
return applyAbAttrsInternal<PreSetStatusAbAttr>(attrType, pokemon, attr => attr.applyPreSetStatus(pokemon, effect, cancelled, args), false, false, !simulated);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function applyPreApplyBattlerTagAbAttrs(attrType: { new(...args: any[]): PreApplyBattlerTagAbAttr },
|
export function applyPreApplyBattlerTagAbAttrs(attrType: { new(...args: any[]): PreApplyBattlerTagAbAttr },
|
||||||
|
|
|
@ -4,9 +4,8 @@ import * as Utils from "../utils";
|
||||||
import { allMoves } from "./move";
|
import { allMoves } from "./move";
|
||||||
import { getPokemonMessage } from "../messages";
|
import { getPokemonMessage } from "../messages";
|
||||||
import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
|
import Pokemon, { HitResult, PokemonMove } from "../field/pokemon";
|
||||||
import { DamagePhase, MoveEffectPhase, ObtainStatusEffectPhase } from "../phases";
|
import { MoveEffectPhase } from "../phases";
|
||||||
import { StatusEffect } from "./status-effect";
|
import { StatusEffect } from "./status-effect";
|
||||||
import { BattlerTagType } from "./enums/battler-tag-type";
|
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
import { Moves } from "./enums/moves";
|
import { Moves } from "./enums/moves";
|
||||||
import { ArenaTagType } from "./enums/arena-tag-type";
|
import { ArenaTagType } from "./enums/arena-tag-type";
|
||||||
|
@ -168,7 +167,7 @@ class SpikesTag extends ArenaTrapTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
activateTrap(pokemon: Pokemon): boolean {
|
activateTrap(pokemon: Pokemon): boolean {
|
||||||
if ((!pokemon.isOfType(Type.FLYING) || pokemon.getTag(BattlerTagType.IGNORE_FLYING) || pokemon.scene.arena.getTag(ArenaTagType.GRAVITY))) {
|
if (pokemon.isGrounded()) {
|
||||||
const damageHpRatio = 1 / (10 - 2 * this.layers);
|
const damageHpRatio = 1 / (10 - 2 * this.layers);
|
||||||
const damage = Math.ceil(pokemon.getMaxHp() * damageHpRatio);
|
const damage = Math.ceil(pokemon.getMaxHp() * damageHpRatio);
|
||||||
|
|
||||||
|
@ -194,12 +193,9 @@ class ToxicSpikesTag extends ArenaTrapTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
activateTrap(pokemon: Pokemon): boolean {
|
activateTrap(pokemon: Pokemon): boolean {
|
||||||
if (!pokemon.status && (!pokemon.isOfType(Type.FLYING) || pokemon.getTag(BattlerTagType.IGNORE_FLYING) || pokemon.scene.arena.getTag(ArenaTagType.GRAVITY))) {
|
if (!pokemon.status && pokemon.isGrounded()) {
|
||||||
const toxic = this.layers > 1;
|
const toxic = this.layers > 1;
|
||||||
|
return pokemon.trySetStatus(!toxic ? StatusEffect.POISON : StatusEffect.TOXIC, true, null, `the ${this.getMoveName()}`);
|
||||||
pokemon.scene.unshiftPhase(new ObtainStatusEffectPhase(pokemon.scene, pokemon.getBattlerIndex(),
|
|
||||||
!toxic ? StatusEffect.POISON : StatusEffect.TOXIC, null, `the ${this.getMoveName()}`));
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { CommonAnim, CommonBattleAnim } from "./battle-anims";
|
import { CommonAnim, CommonBattleAnim } from "./battle-anims";
|
||||||
import { CommonAnimPhase, DamagePhase, MovePhase, ObtainStatusEffectPhase, PokemonHealPhase, ShowAbilityPhase } from "../phases";
|
import { CommonAnimPhase, MovePhase, PokemonHealPhase, ShowAbilityPhase } from "../phases";
|
||||||
import { getPokemonMessage } from "../messages";
|
import { getPokemonMessage } from "../messages";
|
||||||
import Pokemon, { MoveResult, HitResult } from "../field/pokemon";
|
import Pokemon, { MoveResult, HitResult } from "../field/pokemon";
|
||||||
import { Stat } from "./pokemon-stat";
|
import { Stat } from "./pokemon-stat";
|
||||||
|
@ -10,6 +10,7 @@ import { ChargeAttr, allMoves } from "./move";
|
||||||
import { Type } from "./type";
|
import { Type } from "./type";
|
||||||
import { Abilities, FlinchEffectAbAttr, applyAbAttrs } from "./ability";
|
import { Abilities, FlinchEffectAbAttr, applyAbAttrs } from "./ability";
|
||||||
import { BattlerTagType } from "./enums/battler-tag-type";
|
import { BattlerTagType } from "./enums/battler-tag-type";
|
||||||
|
import { TerrainType } from "./terrain";
|
||||||
|
|
||||||
export enum BattlerTagLapseType {
|
export enum BattlerTagLapseType {
|
||||||
FAINT,
|
FAINT,
|
||||||
|
@ -148,6 +149,10 @@ export class ConfusedTag extends BattlerTag {
|
||||||
super(BattlerTagType.CONFUSED, BattlerTagLapseType.MOVE, turnCount, sourceMove);
|
super(BattlerTagType.CONFUSED, BattlerTagLapseType.MOVE, turnCount, sourceMove);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canAdd(pokemon: Pokemon): boolean {
|
||||||
|
return pokemon.scene.arena.terrain?.terrainType !== TerrainType.MISTY || !pokemon.isGrounded();
|
||||||
|
}
|
||||||
|
|
||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
|
@ -427,6 +432,10 @@ export class DrowsyTag extends BattlerTag {
|
||||||
super(BattlerTagType.DROWSY, BattlerTagLapseType.TURN_END, 2, Moves.YAWN);
|
super(BattlerTagType.DROWSY, BattlerTagLapseType.TURN_END, 2, Moves.YAWN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
canAdd(pokemon: Pokemon): boolean {
|
||||||
|
return pokemon.scene.arena.terrain?.terrainType !== TerrainType.ELECTRIC || !pokemon.isGrounded();
|
||||||
|
}
|
||||||
|
|
||||||
onAdd(pokemon: Pokemon): void {
|
onAdd(pokemon: Pokemon): void {
|
||||||
super.onAdd(pokemon);
|
super.onAdd(pokemon);
|
||||||
|
|
||||||
|
@ -435,7 +444,7 @@ export class DrowsyTag extends BattlerTag {
|
||||||
|
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
if (!super.lapse(pokemon, lapseType)) {
|
if (!super.lapse(pokemon, lapseType)) {
|
||||||
pokemon.scene.unshiftPhase(new ObtainStatusEffectPhase(pokemon.scene, pokemon.getBattlerIndex(), StatusEffect.SLEEP));
|
pokemon.trySetStatus(StatusEffect.SLEEP, true);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { Moves } from "./enums/moves";
|
import { Moves } from "./enums/moves";
|
||||||
import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims";
|
import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims";
|
||||||
import { BattleEndPhase, DamagePhase, MovePhase, NewBattlePhase, ObtainStatusEffectPhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase } from "../phases";
|
import { BattleEndPhase, MovePhase, NewBattlePhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase } from "../phases";
|
||||||
import { BattleStat, getBattleStatName } from "./battle-stat";
|
import { BattleStat, getBattleStatName } from "./battle-stat";
|
||||||
import { EncoreTag } from "./battler-tags";
|
import { EncoreTag } from "./battler-tags";
|
||||||
import { BattlerTagType } from "./enums/battler-tag-type";
|
import { BattlerTagType } from "./enums/battler-tag-type";
|
||||||
import { getPokemonMessage } from "../messages";
|
import { getPokemonMessage } from "../messages";
|
||||||
import Pokemon, { AttackMoveResult, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon";
|
import Pokemon, { AttackMoveResult, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon";
|
||||||
import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect";
|
import { StatusEffect, getStatusEffectHealText } from "./status-effect";
|
||||||
import { Type } from "./type";
|
import { Type } from "./type";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { WeatherType } from "./weather";
|
import { WeatherType } from "./weather";
|
||||||
|
@ -16,6 +16,7 @@ import { Abilities, ProtectAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAb
|
||||||
import { PokemonHeldItemModifier } from "../modifier/modifier";
|
import { PokemonHeldItemModifier } from "../modifier/modifier";
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
import { Stat } from "./pokemon-stat";
|
import { Stat } from "./pokemon-stat";
|
||||||
|
import { TerrainType } from "./terrain";
|
||||||
|
|
||||||
export enum MoveCategory {
|
export enum MoveCategory {
|
||||||
PHYSICAL,
|
PHYSICAL,
|
||||||
|
@ -767,10 +768,8 @@ export class StatusEffectAttr extends MoveEffectAttr {
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!pokemon.status || (pokemon.status.effect === this.effect && move.chance < 0)) {
|
if (!pokemon.status || (pokemon.status.effect === this.effect && move.chance < 0))
|
||||||
user.scene.unshiftPhase(new ObtainStatusEffectPhase(user.scene, pokemon.getBattlerIndex(), this.effect, this.cureTurn));
|
return pokemon.trySetStatus(this.effect, true);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -902,6 +901,46 @@ export class ClearWeatherAttr extends MoveEffectAttr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class TerrainChangeAttr extends MoveEffectAttr {
|
||||||
|
private terrainType: TerrainType;
|
||||||
|
|
||||||
|
constructor(terrainType: TerrainType) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.terrainType = terrainType;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
return user.scene.arena.trySetTerrain(this.terrainType, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCondition(): MoveConditionFunc {
|
||||||
|
return (user, target, move) => !user.scene.arena.terrain || (user.scene.arena.terrain.terrainType !== this.terrainType);
|
||||||
|
}
|
||||||
|
|
||||||
|
getUserBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
|
||||||
|
// TODO: Expand on this
|
||||||
|
return user.scene.arena.terrain ? 0 : 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ClearTerrainAttr extends MoveEffectAttr {
|
||||||
|
private terrainType: TerrainType;
|
||||||
|
|
||||||
|
constructor(terrainType: TerrainType) {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.terrainType = terrainType;
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
|
if (user.scene.arena.terrain?.terrainType === this.terrainType)
|
||||||
|
return user.scene.arena.trySetTerrain(TerrainType.NONE, true, true);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export class OneHitKOAttr extends MoveAttr {
|
export class OneHitKOAttr extends MoveAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if (target.isBossImmune())
|
if (target.isBossImmune())
|
||||||
|
@ -979,9 +1018,9 @@ export class ChargeAttr extends OverrideMoveEffectAttr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SolarBeamChargeAttr extends ChargeAttr {
|
export class SunlightChargeAttr extends ChargeAttr {
|
||||||
constructor() {
|
constructor(chargeAnim: ChargeAnim, chargeText: string) {
|
||||||
super(ChargeAnim.SOLAR_BEAM_CHARGING, 'took\nin sunlight!');
|
super(chargeAnim, chargeText);
|
||||||
}
|
}
|
||||||
|
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
|
||||||
|
@ -1347,7 +1386,7 @@ export class TurnDamagedDoublePowerAttr extends VariablePowerAttr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SolarBeamPowerAttr extends VariablePowerAttr {
|
export class AntiSunlightPowerDecreaseAttr extends VariablePowerAttr {
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
if (!user.scene.arena.weather?.isEffectSuppressed(user.scene)) {
|
if (!user.scene.arena.weather?.isEffectSuppressed(user.scene)) {
|
||||||
const power = args[0] as Utils.NumberHolder;
|
const power = args[0] as Utils.NumberHolder;
|
||||||
|
@ -2491,8 +2530,8 @@ export function initMoves() {
|
||||||
.slicingMove()
|
.slicingMove()
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
new AttackMove(Moves.SOLAR_BEAM, "Solar Beam", Type.GRASS, MoveCategory.SPECIAL, 120, 100, 10, 168, "In this two-turn attack, the user gathers light, then blasts a bundled beam on the next turn.", -1, 0, 1)
|
new AttackMove(Moves.SOLAR_BEAM, "Solar Beam", Type.GRASS, MoveCategory.SPECIAL, 120, 100, 10, 168, "In this two-turn attack, the user gathers light, then blasts a bundled beam on the next turn.", -1, 0, 1)
|
||||||
.attr(SolarBeamChargeAttr)
|
.attr(SunlightChargeAttr, ChargeAnim.SOLAR_BEAM_CHARGING, 'took\nin sunlight!')
|
||||||
.attr(SolarBeamPowerAttr)
|
.attr(AntiSunlightPowerDecreaseAttr)
|
||||||
.ignoresVirtual(),
|
.ignoresVirtual(),
|
||||||
new StatusMove(Moves.POISON_POWDER, "Poison Powder", Type.POISON, 75, 35, -1, "The user scatters a cloud of poisonous dust that poisons the target.", -1, 0, 1)
|
new StatusMove(Moves.POISON_POWDER, "Poison Powder", Type.POISON, 75, 35, -1, "The user scatters a cloud of poisonous dust that poisons the target.", -1, 0, 1)
|
||||||
.attr(StatusEffectAttr, StatusEffect.POISON)
|
.attr(StatusEffectAttr, StatusEffect.POISON)
|
||||||
|
@ -3677,9 +3716,11 @@ export function initMoves() {
|
||||||
.target(MoveTarget.USER_SIDE),
|
.target(MoveTarget.USER_SIDE),
|
||||||
new StatusMove(Moves.FLOWER_SHIELD, "Flower Shield (N)", Type.FAIRY, -1, 10, -1, "The user raises the Defense stats of all Grass-type Pokémon in battle with a mysterious power.", 100, 0, 6)
|
new StatusMove(Moves.FLOWER_SHIELD, "Flower Shield (N)", Type.FAIRY, -1, 10, -1, "The user raises the Defense stats of all Grass-type Pokémon in battle with a mysterious power.", 100, 0, 6)
|
||||||
.target(MoveTarget.ALL),
|
.target(MoveTarget.ALL),
|
||||||
new StatusMove(Moves.GRASSY_TERRAIN, "Grassy Terrain (N)", Type.GRASS, -1, 10, -1, "The user turns the ground to grass for five turns. This restores the HP of Pokémon on the ground a little every turn and powers up Grass-type moves.", -1, 0, 6)
|
new StatusMove(Moves.GRASSY_TERRAIN, "Grassy Terrain", Type.GRASS, -1, 10, -1, "The user turns the ground to grass for five turns. This restores the HP of Pokémon on the ground a little every turn and powers up Grass-type moves.", -1, 0, 6)
|
||||||
|
.attr(TerrainChangeAttr, TerrainType.GRASSY)
|
||||||
.target(MoveTarget.BOTH_SIDES),
|
.target(MoveTarget.BOTH_SIDES),
|
||||||
new StatusMove(Moves.MISTY_TERRAIN, "Misty Terrain (N)", Type.FAIRY, -1, 10, -1, "This protects Pokémon on the ground from status conditions and halves damage from Dragon-type moves for five turns.", -1, 0, 6)
|
new StatusMove(Moves.MISTY_TERRAIN, "Misty Terrain", Type.FAIRY, -1, 10, -1, "This protects Pokémon on the ground from status conditions and halves damage from Dragon-type moves for five turns.", -1, 0, 6)
|
||||||
|
.attr(TerrainChangeAttr, TerrainType.MISTY)
|
||||||
.target(MoveTarget.BOTH_SIDES),
|
.target(MoveTarget.BOTH_SIDES),
|
||||||
new StatusMove(Moves.ELECTRIFY, "Electrify (N)", Type.ELECTRIC, -1, 20, -1, "If the target is electrified before it uses a move during that turn, the target's move becomes Electric type.", -1, 0, 6),
|
new StatusMove(Moves.ELECTRIFY, "Electrify (N)", Type.ELECTRIC, -1, 20, -1, "If the target is electrified before it uses a move during that turn, the target's move becomes Electric type.", -1, 0, 6),
|
||||||
new AttackMove(Moves.PLAY_ROUGH, "Play Rough", Type.FAIRY, MoveCategory.PHYSICAL, 90, 90, 10, -1, "The user plays rough with the target and attacks it. This may also lower the target's Attack stat.", 10, 0, 6)
|
new AttackMove(Moves.PLAY_ROUGH, "Play Rough", Type.FAIRY, MoveCategory.PHYSICAL, 90, 90, 10, -1, "The user plays rough with the target and attacks it. This may also lower the target's Attack stat.", 10, 0, 6)
|
||||||
|
@ -3733,7 +3774,8 @@ export function initMoves() {
|
||||||
.condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => a === p.getAbility().id))),
|
.condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => a === p.getAbility().id))),
|
||||||
new StatusMove(Moves.HAPPY_HOUR, "Happy Hour (N)", Type.NORMAL, -1, 30, -1, "Using Happy Hour doubles the amount of prize money received after battle.", -1, 0, 6) // No animation
|
new StatusMove(Moves.HAPPY_HOUR, "Happy Hour (N)", Type.NORMAL, -1, 30, -1, "Using Happy Hour doubles the amount of prize money received after battle.", -1, 0, 6) // No animation
|
||||||
.target(MoveTarget.USER_SIDE),
|
.target(MoveTarget.USER_SIDE),
|
||||||
new StatusMove(Moves.ELECTRIC_TERRAIN, "Electric Terrain (N)", Type.ELECTRIC, -1, 10, -1, "The user electrifies the ground for five turns, powering up Electric-type moves. Pokémon on the ground no longer fall asleep.", -1, 0, 6)
|
new StatusMove(Moves.ELECTRIC_TERRAIN, "Electric Terrain", Type.ELECTRIC, -1, 10, -1, "The user electrifies the ground for five turns, powering up Electric-type moves. Pokémon on the ground no longer fall asleep.", -1, 0, 6)
|
||||||
|
.attr(TerrainChangeAttr, TerrainType.ELECTRIC)
|
||||||
.target(MoveTarget.BOTH_SIDES),
|
.target(MoveTarget.BOTH_SIDES),
|
||||||
new AttackMove(Moves.DAZZLING_GLEAM, "Dazzling Gleam", Type.FAIRY, MoveCategory.SPECIAL, 80, 100, 10, -1, "The user damages opposing Pokémon by emitting a powerful flash.", -1, 0, 6)
|
new AttackMove(Moves.DAZZLING_GLEAM, "Dazzling Gleam", Type.FAIRY, MoveCategory.SPECIAL, 80, 100, 10, -1, "The user damages opposing Pokémon by emitting a powerful flash.", -1, 0, 6)
|
||||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||||
|
@ -3831,7 +3873,8 @@ export function initMoves() {
|
||||||
new StatusMove(Moves.STRENGTH_SAP, "Strength Sap (P)", Type.GRASS, 100, 10, -1, "The user restores its HP by the same amount as the target's Attack stat. It also lowers the target's Attack stat.", 100, 0, 7)
|
new StatusMove(Moves.STRENGTH_SAP, "Strength Sap (P)", Type.GRASS, 100, 10, -1, "The user restores its HP by the same amount as the target's Attack stat. It also lowers the target's Attack stat.", 100, 0, 7)
|
||||||
.attr(StatChangeAttr, BattleStat.ATK, -1),
|
.attr(StatChangeAttr, BattleStat.ATK, -1),
|
||||||
new AttackMove(Moves.SOLAR_BLADE, "Solar Blade", Type.GRASS, MoveCategory.PHYSICAL, 125, 100, 10, -1, "In this two-turn attack, the user gathers light and fills a blade with the light's energy, attacking the target on the next turn.", -1, 0, 7)
|
new AttackMove(Moves.SOLAR_BLADE, "Solar Blade", Type.GRASS, MoveCategory.PHYSICAL, 125, 100, 10, -1, "In this two-turn attack, the user gathers light and fills a blade with the light's energy, attacking the target on the next turn.", -1, 0, 7)
|
||||||
.attr(ChargeAttr, ChargeAnim.SOLAR_BLADE_CHARGING, "is glowing!")
|
.attr(SunlightChargeAttr, ChargeAnim.SOLAR_BLADE_CHARGING, "is glowing!")
|
||||||
|
.attr(AntiSunlightPowerDecreaseAttr)
|
||||||
.slicingMove(),
|
.slicingMove(),
|
||||||
new AttackMove(Moves.LEAFAGE, "Leafage", Type.GRASS, MoveCategory.PHYSICAL, 40, 100, 40, -1, "The user attacks by pelting the target with leaves.", -1, 0, 7),
|
new AttackMove(Moves.LEAFAGE, "Leafage", Type.GRASS, MoveCategory.PHYSICAL, 40, 100, 40, -1, "The user attacks by pelting the target with leaves.", -1, 0, 7),
|
||||||
new StatusMove(Moves.SPOTLIGHT, "Spotlight (N)", Type.NORMAL, -1, 15, -1, "The user shines a spotlight on the target so that only the target will be attacked during the turn.", -1, 3, 7),
|
new StatusMove(Moves.SPOTLIGHT, "Spotlight (N)", Type.NORMAL, -1, 15, -1, "The user shines a spotlight on the target so that only the target will be attacked during the turn.", -1, 3, 7),
|
||||||
|
@ -3848,7 +3891,8 @@ export function initMoves() {
|
||||||
.ballBombMove(),
|
.ballBombMove(),
|
||||||
new AttackMove(Moves.ANCHOR_SHOT, "Anchor Shot", Type.STEEL, MoveCategory.PHYSICAL, 80, 100, 20, -1, "The user entangles the target with its anchor chain while attacking. The target becomes unable to flee.", -1, 0, 7)
|
new AttackMove(Moves.ANCHOR_SHOT, "Anchor Shot", Type.STEEL, MoveCategory.PHYSICAL, 80, 100, 20, -1, "The user entangles the target with its anchor chain while attacking. The target becomes unable to flee.", -1, 0, 7)
|
||||||
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1),
|
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1),
|
||||||
new StatusMove(Moves.PSYCHIC_TERRAIN, "Psychic Terrain (N)", Type.PSYCHIC, -1, 10, -1, "This protects Pokémon on the ground from priority moves and powers up Psychic-type moves for five turns.", -1, 0, 7)
|
new StatusMove(Moves.PSYCHIC_TERRAIN, "Psychic Terrain", Type.PSYCHIC, -1, 10, -1, "This protects Pokémon on the ground from priority moves and powers up Psychic-type moves for five turns.", -1, 0, 7)
|
||||||
|
.attr(TerrainChangeAttr, TerrainType.PSYCHIC)
|
||||||
.target(MoveTarget.BOTH_SIDES),
|
.target(MoveTarget.BOTH_SIDES),
|
||||||
new AttackMove(Moves.LUNGE, "Lunge", Type.BUG, MoveCategory.PHYSICAL, 80, 100, 15, -1, "The user makes a lunge at the target, attacking with full force. This also lowers the target's Attack stat.", 100, 0, 7)
|
new AttackMove(Moves.LUNGE, "Lunge", Type.BUG, MoveCategory.PHYSICAL, 80, 100, 15, -1, "The user makes a lunge at the target, attacking with full force. This also lowers the target's Attack stat.", 100, 0, 7)
|
||||||
.attr(StatChangeAttr, BattleStat.ATK, -1),
|
.attr(StatChangeAttr, BattleStat.ATK, -1),
|
||||||
|
|
|
@ -0,0 +1,56 @@
|
||||||
|
import { Type } from "./type";
|
||||||
|
|
||||||
|
export enum TerrainType {
|
||||||
|
NONE,
|
||||||
|
MISTY,
|
||||||
|
ELECTRIC,
|
||||||
|
GRASSY,
|
||||||
|
PSYCHIC
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Terrain {
|
||||||
|
public terrainType: TerrainType;
|
||||||
|
public turnsLeft: integer;
|
||||||
|
|
||||||
|
constructor(terrainType: TerrainType, turnsLeft?: integer) {
|
||||||
|
this.terrainType = terrainType;
|
||||||
|
this.turnsLeft = turnsLeft || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
lapse(): boolean {
|
||||||
|
if (this.turnsLeft)
|
||||||
|
return !!--this.turnsLeft;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAttackTypeMultiplier(attackType: Type): number {
|
||||||
|
switch (this.terrainType) {
|
||||||
|
case TerrainType.GRASSY:
|
||||||
|
if (attackType === Type.GRASS)
|
||||||
|
return 1.3;
|
||||||
|
break;
|
||||||
|
case TerrainType.PSYCHIC:
|
||||||
|
if (attackType === Type.PSYCHIC)
|
||||||
|
return 1.3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTerrainColor(terrainType: TerrainType): [ integer, integer, integer ] {
|
||||||
|
switch (terrainType) {
|
||||||
|
case TerrainType.GRASSY:
|
||||||
|
return [ 120, 200, 80 ];
|
||||||
|
case TerrainType.MISTY:
|
||||||
|
return [ 232, 136, 200 ];
|
||||||
|
case TerrainType.ELECTRIC:
|
||||||
|
return [ 248, 248, 120 ];
|
||||||
|
case TerrainType.PSYCHIC:
|
||||||
|
return [ 160, 64, 160 ];
|
||||||
|
}
|
||||||
|
|
||||||
|
return [ 0, 0, 0 ];
|
||||||
|
}
|
|
@ -6,6 +6,7 @@ import Move, { AttackMove } from "./move";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../battle-scene";
|
||||||
import { SuppressWeatherEffectAbAttr, applyPreWeatherEffectAbAttrs } from "./ability";
|
import { SuppressWeatherEffectAbAttr, applyPreWeatherEffectAbAttrs } from "./ability";
|
||||||
|
import { TerrainType } from "./terrain";
|
||||||
|
|
||||||
export enum WeatherType {
|
export enum WeatherType {
|
||||||
NONE,
|
NONE,
|
||||||
|
@ -112,7 +113,7 @@ export class Weather {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeatherStartMessage(weatherType: WeatherType) {
|
export function getWeatherStartMessage(weatherType: WeatherType): string {
|
||||||
switch (weatherType) {
|
switch (weatherType) {
|
||||||
case WeatherType.SUNNY:
|
case WeatherType.SUNNY:
|
||||||
return 'The sunlight got bright!';
|
return 'The sunlight got bright!';
|
||||||
|
@ -135,7 +136,7 @@ export function getWeatherStartMessage(weatherType: WeatherType) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeatherLapseMessage(weatherType: WeatherType) {
|
export function getWeatherLapseMessage(weatherType: WeatherType): string {
|
||||||
switch (weatherType) {
|
switch (weatherType) {
|
||||||
case WeatherType.SUNNY:
|
case WeatherType.SUNNY:
|
||||||
return 'The sunlight is strong.';
|
return 'The sunlight is strong.';
|
||||||
|
@ -158,7 +159,7 @@ export function getWeatherLapseMessage(weatherType: WeatherType) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokemon) {
|
export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokemon): string {
|
||||||
switch (weatherType) {
|
switch (weatherType) {
|
||||||
case WeatherType.SANDSTORM:
|
case WeatherType.SANDSTORM:
|
||||||
return getPokemonMessage(pokemon, ' is buffeted\nby the sandstorm!');
|
return getPokemonMessage(pokemon, ' is buffeted\nby the sandstorm!');
|
||||||
|
@ -169,7 +170,7 @@ export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokem
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getWeatherClearMessage(weatherType: WeatherType) {
|
export function getWeatherClearMessage(weatherType: WeatherType): string {
|
||||||
switch (weatherType) {
|
switch (weatherType) {
|
||||||
case WeatherType.SUNNY:
|
case WeatherType.SUNNY:
|
||||||
return 'The sunlight faded.';
|
return 'The sunlight faded.';
|
||||||
|
@ -192,6 +193,18 @@ export function getWeatherClearMessage(weatherType: WeatherType) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getTerrainStartMessage(terrainType: TerrainType): string {
|
||||||
|
return terrainType
|
||||||
|
? `The terrain became ${Utils.toReadableString(TerrainType[terrainType])}!`
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTerrainClearMessage(terrainType: TerrainType): string {
|
||||||
|
return terrainType
|
||||||
|
? `The ${Utils.toReadableString(TerrainType[terrainType])} terrain faded.`
|
||||||
|
: null;
|
||||||
|
}
|
||||||
|
|
||||||
interface WeatherPoolEntry {
|
interface WeatherPoolEntry {
|
||||||
weatherType: WeatherType;
|
weatherType: WeatherType;
|
||||||
weight: integer;
|
weight: integer;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { Biome } from "../data/enums/biome";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import PokemonSpecies, { getPokemonSpecies } from "../data/pokemon-species";
|
import PokemonSpecies, { getPokemonSpecies } from "../data/pokemon-species";
|
||||||
import { Species } from "../data/enums/species";
|
import { Species } from "../data/enums/species";
|
||||||
import { Weather, WeatherType, getWeatherClearMessage, getWeatherStartMessage } from "../data/weather";
|
import { Weather, WeatherType, getTerrainClearMessage, getTerrainStartMessage, getWeatherClearMessage, getWeatherStartMessage } from "../data/weather";
|
||||||
import { CommonAnimPhase } from "../phases";
|
import { CommonAnimPhase } from "../phases";
|
||||||
import { CommonAnim } from "../data/battle-anims";
|
import { CommonAnim } from "../data/battle-anims";
|
||||||
import { Type } from "../data/type";
|
import { Type } from "../data/type";
|
||||||
|
@ -16,6 +16,7 @@ import { TrainerType } from "../data/enums/trainer-type";
|
||||||
import { BattlerIndex } from "../battle";
|
import { BattlerIndex } from "../battle";
|
||||||
import { Moves } from "../data/enums/moves";
|
import { Moves } from "../data/enums/moves";
|
||||||
import { TimeOfDay } from "../data/enums/time-of-day";
|
import { TimeOfDay } from "../data/enums/time-of-day";
|
||||||
|
import { Terrain, TerrainType, getTerrainColor } from "../data/terrain";
|
||||||
|
|
||||||
const WEATHER_OVERRIDE = WeatherType.NONE;
|
const WEATHER_OVERRIDE = WeatherType.NONE;
|
||||||
|
|
||||||
|
@ -23,9 +24,9 @@ export class Arena {
|
||||||
public scene: BattleScene;
|
public scene: BattleScene;
|
||||||
public biomeType: Biome;
|
public biomeType: Biome;
|
||||||
public weather: Weather;
|
public weather: Weather;
|
||||||
|
public terrain: Terrain;
|
||||||
public tags: ArenaTag[];
|
public tags: ArenaTag[];
|
||||||
public bgm: string;
|
public bgm: string;
|
||||||
|
|
||||||
private lastTimeOfDay: TimeOfDay;
|
private lastTimeOfDay: TimeOfDay;
|
||||||
|
|
||||||
private pokemonPool: PokemonPools;
|
private pokemonPool: PokemonPools;
|
||||||
|
@ -230,6 +231,17 @@ export class Arena {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getBgTerrainColorRatioForBiome(): number {
|
||||||
|
switch (this.biomeType) {
|
||||||
|
case Biome.SPACE:
|
||||||
|
return 1;
|
||||||
|
case Biome.END:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 83 / 132;
|
||||||
|
}
|
||||||
|
|
||||||
trySetWeatherOverride(weather: WeatherType): boolean {
|
trySetWeatherOverride(weather: WeatherType): boolean {
|
||||||
this.weather = new Weather(weather, 0);
|
this.weather = new Weather(weather, 0);
|
||||||
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.SUNNY + (weather - 1)));
|
this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.SUNNY + (weather - 1)));
|
||||||
|
@ -259,15 +271,52 @@ export class Arena {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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));
|
||||||
|
/*[
|
||||||
|
this.scene.arenaBg,
|
||||||
|
this.scene.arenaBgTransition,
|
||||||
|
this.scene.arenaPlayer.base,
|
||||||
|
this.scene.arenaPlayer.props,
|
||||||
|
this.scene.arenaPlayerTransition.base,
|
||||||
|
this.scene.arenaPlayerTransition.props,
|
||||||
|
this.scene.arenaEnemy.base,
|
||||||
|
this.scene.arenaEnemy.props,
|
||||||
|
this.scene.arenaNextEnemy.base,
|
||||||
|
this.scene.arenaNextEnemy.props
|
||||||
|
]
|
||||||
|
.flat()
|
||||||
|
.map(a => a.pipelineData['terrainColor'] = getTerrainColor());*/
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
isMoveWeatherCancelled(move: Move) {
|
isMoveWeatherCancelled(move: Move) {
|
||||||
return this.weather && !this.weather.isEffectSuppressed(this.scene) && this.weather.isMoveWeatherCancelled(move);
|
return this.weather && !this.weather.isEffectSuppressed(this.scene) && this.weather.isMoveWeatherCancelled(move);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAttackTypeMultiplier(attackType: Type): number {
|
getAttackTypeMultiplier(attackType: Type, grounded: boolean): number {
|
||||||
if (!this.weather || this.weather.isEffectSuppressed(this.scene))
|
let weatherMultiplier = 1;
|
||||||
return 1;
|
if (this.weather && !this.weather.isEffectSuppressed(this.scene))
|
||||||
|
weatherMultiplier = this.weather.getAttackTypeMultiplier(attackType);
|
||||||
|
|
||||||
return this.weather.getAttackTypeMultiplier(attackType);
|
let terrainMultiplier = 1;
|
||||||
|
if (this.terrain && !grounded)
|
||||||
|
terrainMultiplier = this.terrain.getAttackTypeMultiplier(attackType);
|
||||||
|
|
||||||
|
return weatherMultiplier * terrainMultiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
getTrainerChance(): integer {
|
getTrainerChance(): integer {
|
||||||
|
@ -572,12 +621,12 @@ export class ArenaBase extends Phaser.GameObjects.Container {
|
||||||
|
|
||||||
this.player = player;
|
this.player = player;
|
||||||
|
|
||||||
this.base = scene.addFieldSprite(0, 0, 'plains_a');
|
this.base = scene.addFieldSprite(0, 0, 'plains_a', null, 1);
|
||||||
this.base.setOrigin(0, 0);
|
this.base.setOrigin(0, 0);
|
||||||
|
|
||||||
this.props = !player ?
|
this.props = !player ?
|
||||||
new Array(3).fill(null).map(() => {
|
new Array(3).fill(null).map(() => {
|
||||||
const ret = scene.addFieldSprite(0, 0, 'plains_b');
|
const ret = scene.addFieldSprite(0, 0, 'plains_b', null, 1);
|
||||||
ret.setOrigin(0, 0);
|
ret.setOrigin(0, 0);
|
||||||
ret.setVisible(false);
|
ret.setVisible(false);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -2,7 +2,7 @@ import Phaser from 'phaser';
|
||||||
import BattleScene, { AnySound } from '../battle-scene';
|
import BattleScene, { AnySound } from '../battle-scene';
|
||||||
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from '../ui/battle-info';
|
import BattleInfo, { PlayerBattleInfo, EnemyBattleInfo } from '../ui/battle-info';
|
||||||
import { Moves } from "../data/enums/moves";
|
import { Moves } from "../data/enums/moves";
|
||||||
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr } from "../data/move";
|
import Move, { HighCritAttr, HitsTagAttr, applyMoveAttrs, FixedDamageAttr, VariablePowerAttr, allMoves, MoveCategory, TypelessAttr, CritOnlyAttr, getMoveTargets, OneHitKOAttr, MultiHitAttr, StatusMoveTypeImmunityAttr, MoveTarget } from "../data/move";
|
||||||
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies } from '../data/pokemon-species';
|
import { default as PokemonSpecies, PokemonSpeciesForm, SpeciesFormKey, getFusedSpeciesName, getPokemonSpecies } from '../data/pokemon-species';
|
||||||
import * as Utils from '../utils';
|
import * as Utils from '../utils';
|
||||||
import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from '../data/type';
|
import { Type, TypeDamageMultiplier, getTypeDamageMultiplier, getTypeRgb } from '../data/type';
|
||||||
|
@ -15,7 +15,7 @@ import { initMoveAnim, loadMoveAnimAssets } from '../data/battle-anims';
|
||||||
import { Status, StatusEffect } from '../data/status-effect';
|
import { Status, StatusEffect } from '../data/status-effect';
|
||||||
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition } from '../data/pokemon-evolutions';
|
import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEvolutionCondition } from '../data/pokemon-evolutions';
|
||||||
import { reverseCompatibleTms, tmSpecies } from '../data/tms';
|
import { reverseCompatibleTms, tmSpecies } from '../data/tms';
|
||||||
import { DamagePhase, FaintPhase, LearnMovePhase, StatChangePhase, SwitchSummonPhase } from '../phases';
|
import { DamagePhase, FaintPhase, LearnMovePhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase } from '../phases';
|
||||||
import { BattleStat } from '../data/battle-stat';
|
import { BattleStat } from '../data/battle-stat';
|
||||||
import { BattlerTag, BattlerTagLapseType, EncoreTag, TypeBoostTag, getBattlerTag } from '../data/battler-tags';
|
import { BattlerTag, BattlerTagLapseType, EncoreTag, TypeBoostTag, getBattlerTag } from '../data/battler-tags';
|
||||||
import { BattlerTagType } from "../data/enums/battler-tag-type";
|
import { BattlerTagType } from "../data/enums/battler-tag-type";
|
||||||
|
@ -39,6 +39,7 @@ import { DexAttr, StarterMoveset } from '../system/game-data';
|
||||||
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from '@material/material-color-utilities';
|
import { QuantizerCelebi, argbFromRgba, rgbaFromArgb } from '@material/material-color-utilities';
|
||||||
import { Nature, getNatureStatMultiplier } from '../data/nature';
|
import { Nature, getNatureStatMultiplier } from '../data/nature';
|
||||||
import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangeMoveUsedTrigger, SpeciesFormChangeStatusEffectTrigger } from '../data/pokemon-forms';
|
import { SpeciesFormChange, SpeciesFormChangeActiveTrigger, SpeciesFormChangeMoveLearnedTrigger, SpeciesFormChangeMoveUsedTrigger, SpeciesFormChangeStatusEffectTrigger } from '../data/pokemon-forms';
|
||||||
|
import { TerrainType } from '../data/terrain';
|
||||||
|
|
||||||
export enum FieldPosition {
|
export enum FieldPosition {
|
||||||
CENTER,
|
CENTER,
|
||||||
|
@ -664,8 +665,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
return types;
|
return types;
|
||||||
}
|
}
|
||||||
|
|
||||||
isOfType(type: Type) {
|
isOfType(type: Type): boolean {
|
||||||
return this.getTypes(true).indexOf(type) > -1;
|
return !!this.getTypes(true).find(t => t === type);
|
||||||
}
|
}
|
||||||
|
|
||||||
getAbility(ignoreOverride?: boolean): Ability {
|
getAbility(ignoreOverride?: boolean): Ability {
|
||||||
|
@ -708,6 +709,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
return this.getTeraType() !== Type.UNKNOWN;
|
return this.getTeraType() !== Type.UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isGrounded(): boolean {
|
||||||
|
return !this.isOfType(Type.FLYING);
|
||||||
|
}
|
||||||
|
|
||||||
getAttackMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier {
|
getAttackMoveEffectiveness(source: Pokemon, move: PokemonMove): TypeDamageMultiplier {
|
||||||
const typeless = !!move.getMove().getAttrs(TypelessAttr).length;
|
const typeless = !!move.getMove().getAttrs(TypelessAttr).length;
|
||||||
const typeMultiplier = new Utils.NumberHolder(this.getAttackTypeEffectiveness(move.getMove().type));
|
const typeMultiplier = new Utils.NumberHolder(this.getAttackTypeEffectiveness(move.getMove().type));
|
||||||
|
@ -1042,7 +1047,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
else {
|
else {
|
||||||
if (source.findTag(t => t instanceof TypeBoostTag && (t as TypeBoostTag).boostedType === move.type))
|
if (source.findTag(t => t instanceof TypeBoostTag && (t as TypeBoostTag).boostedType === move.type))
|
||||||
power.value *= 1.5;
|
power.value *= 1.5;
|
||||||
const weatherTypeMultiplier = this.scene.arena.getAttackTypeMultiplier(move.type);
|
const arenaAttackTypeMultiplier = this.scene.arena.getAttackTypeMultiplier(move.type, this.isGrounded());
|
||||||
|
if (this.scene.arena.terrain?.terrainType === TerrainType.GRASSY && this.isGrounded() && move.type === Type.GROUND && move.moveTarget === MoveTarget.ALL_NEAR_OTHERS)
|
||||||
|
power.value /= 2;
|
||||||
applyMoveAttrs(VariablePowerAttr, source, this, move, power);
|
applyMoveAttrs(VariablePowerAttr, source, this, move, power);
|
||||||
if (!typeless) {
|
if (!typeless) {
|
||||||
this.scene.arena.applyTags(WeakenMoveTypeTag, move.type, power);
|
this.scene.arena.applyTags(WeakenMoveTypeTag, move.type, power);
|
||||||
|
@ -1065,7 +1072,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
const sourceAtk = source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this);
|
const sourceAtk = source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this);
|
||||||
const targetDef = this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source);
|
const targetDef = this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source);
|
||||||
const criticalMultiplier = isCritical ? 2 : 1;
|
const criticalMultiplier = isCritical ? 2 : 1;
|
||||||
const isTypeImmune = (typeMultiplier.value * weatherTypeMultiplier) === 0;
|
const isTypeImmune = (typeMultiplier.value * arenaAttackTypeMultiplier) === 0;
|
||||||
const sourceTypes = source.getTypes();
|
const sourceTypes = source.getTypes();
|
||||||
const matchesSourceType = sourceTypes[0] === move.type || (sourceTypes.length > 1 && sourceTypes[1] === move.type);
|
const matchesSourceType = sourceTypes[0] === move.type || (sourceTypes.length > 1 && sourceTypes[1] === move.type);
|
||||||
let stabMultiplier = new Utils.NumberHolder(1);
|
let stabMultiplier = new Utils.NumberHolder(1);
|
||||||
|
@ -1080,7 +1087,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
stabMultiplier.value = Math.min(stabMultiplier.value + 0.5, 2.25);
|
stabMultiplier.value = Math.min(stabMultiplier.value + 0.5, 2.25);
|
||||||
|
|
||||||
if (!isTypeImmune) {
|
if (!isTypeImmune) {
|
||||||
damage.value = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk / targetDef) / 50) + 2) * stabMultiplier.value * typeMultiplier.value * weatherTypeMultiplier * ((this.scene.currentBattle.randSeedInt(15) + 85) / 100)) * criticalMultiplier;
|
damage.value = Math.ceil(((((2 * source.level / 5 + 2) * power.value * sourceAtk / targetDef) / 50) + 2) * stabMultiplier.value * typeMultiplier.value * arenaAttackTypeMultiplier * ((this.scene.currentBattle.randSeedInt(15) + 85) / 100)) * criticalMultiplier;
|
||||||
if (isPhysical && source.status && source.status.effect === StatusEffect.BURN)
|
if (isPhysical && source.status && source.status.effect === StatusEffect.BURN)
|
||||||
damage.value = Math.floor(damage.value / 2);
|
damage.value = Math.floor(damage.value / 2);
|
||||||
move.getAttrs(HitsTagAttr).map(hta => hta as HitsTagAttr).filter(hta => hta.doubleDamage).forEach(hta => {
|
move.getAttrs(HitsTagAttr).map(hta => hta as HitsTagAttr).filter(hta => hta.doubleDamage).forEach(hta => {
|
||||||
|
@ -1089,6 +1096,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.scene.arena.terrain?.terrainType === TerrainType.MISTY && this.isGrounded() && move.type === Type.DRAGON)
|
||||||
|
damage.value = Math.floor(damage.value / 2);
|
||||||
|
|
||||||
const fixedDamage = new Utils.IntegerHolder(0);
|
const fixedDamage = new Utils.IntegerHolder(0);
|
||||||
applyMoveAttrs(FixedDamageAttr, source, this, move, fixedDamage);
|
applyMoveAttrs(FixedDamageAttr, source, this, move, fixedDamage);
|
||||||
if (!isTypeImmune && fixedDamage.value) {
|
if (!isTypeImmune && fixedDamage.value) {
|
||||||
|
@ -1528,9 +1538,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
return this.gender !== Gender.GENDERLESS && pokemon.gender === (this.gender === Gender.MALE ? Gender.FEMALE : Gender.MALE);
|
return this.gender !== Gender.GENDERLESS && pokemon.gender === (this.gender === Gender.MALE ? Gender.FEMALE : Gender.MALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
trySetStatus(effect: StatusEffect): boolean {
|
canSetStatus(effect: StatusEffect, quiet: boolean = false): boolean {
|
||||||
if (this.status && effect !== StatusEffect.FAINT)
|
if (effect !== StatusEffect.FAINT && this.status)
|
||||||
return false;
|
return false;
|
||||||
|
if (this.isGrounded() && this.scene.arena.terrain?.terrainType === TerrainType.MISTY)
|
||||||
|
return false;
|
||||||
|
|
||||||
switch (effect) {
|
switch (effect) {
|
||||||
case StatusEffect.POISON:
|
case StatusEffect.POISON:
|
||||||
case StatusEffect.TOXIC:
|
case StatusEffect.TOXIC:
|
||||||
|
@ -1541,6 +1554,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
if (this.isOfType(Type.ELECTRIC))
|
if (this.isOfType(Type.ELECTRIC))
|
||||||
return false;
|
return false;
|
||||||
break;
|
break;
|
||||||
|
case StatusEffect.SLEEP:
|
||||||
|
if (this.isGrounded() && this.scene.arena.terrain?.terrainType === TerrainType.ELECTRIC)
|
||||||
|
return false;
|
||||||
case StatusEffect.FREEZE:
|
case StatusEffect.FREEZE:
|
||||||
if (this.isOfType(Type.ICE))
|
if (this.isOfType(Type.ICE))
|
||||||
return false;
|
return false;
|
||||||
|
@ -1552,21 +1568,33 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||||
}
|
}
|
||||||
|
|
||||||
const cancelled = new Utils.BooleanHolder(false);
|
const cancelled = new Utils.BooleanHolder(false);
|
||||||
applyPreSetStatusAbAttrs(StatusEffectImmunityAbAttr, this, effect, cancelled);
|
applyPreSetStatusAbAttrs(StatusEffectImmunityAbAttr, this, effect, cancelled, quiet);
|
||||||
|
|
||||||
if (cancelled.value)
|
if (cancelled.value)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
let cureTurn: Utils.IntegerHolder;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
trySetStatus(effect: StatusEffect, asPhase: boolean = false, cureTurn: integer = 0, sourceText: string = null): boolean {
|
||||||
|
if (!this.canSetStatus(effect, asPhase))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (asPhase) {
|
||||||
|
this.scene.unshiftPhase(new ObtainStatusEffectPhase(this.scene, this.getBattlerIndex(), effect, cureTurn, sourceText));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let statusCureTurn: Utils.IntegerHolder;
|
||||||
|
|
||||||
if (effect === StatusEffect.SLEEP) {
|
if (effect === StatusEffect.SLEEP) {
|
||||||
cureTurn = new Utils.IntegerHolder(this.randSeedIntRange(2, 4));
|
statusCureTurn = new Utils.IntegerHolder(this.randSeedIntRange(2, 4));
|
||||||
applyAbAttrs(ReduceStatusEffectDurationAbAttr, this, null, effect, cureTurn);
|
applyAbAttrs(ReduceStatusEffectDurationAbAttr, this, null, effect, statusCureTurn);
|
||||||
|
|
||||||
this.setFrameRate(4);
|
this.setFrameRate(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.status = new Status(effect, 0, cureTurn?.value);
|
this.status = new Status(effect, 0, statusCureTurn?.value);
|
||||||
|
|
||||||
if (effect !== StatusEffect.FAINT)
|
if (effect !== StatusEffect.FAINT)
|
||||||
this.scene.triggerPokemonFormChange(this, SpeciesFormChangeStatusEffectTrigger, true);
|
this.scene.triggerPokemonFormChange(this, SpeciesFormChangeStatusEffectTrigger, true);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import * as ModifierTypes from './modifier-type';
|
import * as ModifierTypes from './modifier-type';
|
||||||
import { LearnMovePhase, LevelUpPhase, ObtainStatusEffectPhase, PokemonHealPhase } from "../phases";
|
import { LearnMovePhase, LevelUpPhase, PokemonHealPhase } from "../phases";
|
||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../battle-scene";
|
||||||
import { getLevelTotalExp } from "../data/exp";
|
import { getLevelTotalExp } from "../data/exp";
|
||||||
import { PokeballType } from "../data/pokeball";
|
import { PokeballType } from "../data/pokeball";
|
||||||
|
@ -13,12 +13,11 @@ import { getPokemonMessage } from '../messages';
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
import { TempBattleStat } from '../data/temp-battle-stat';
|
import { TempBattleStat } from '../data/temp-battle-stat';
|
||||||
import { BerryType, getBerryEffectFunc, getBerryPredicate } from '../data/berry';
|
import { BerryType, getBerryEffectFunc, getBerryPredicate } from '../data/berry';
|
||||||
import { StatusEffect, getStatusEffectDescriptor, getStatusEffectHealText } from '../data/status-effect';
|
import { StatusEffect, getStatusEffectHealText } from '../data/status-effect';
|
||||||
import { MoneyAchv, achvs } from '../system/achv';
|
import { MoneyAchv, achvs } from '../system/achv';
|
||||||
import { VoucherType } from '../system/voucher';
|
import { VoucherType } from '../system/voucher';
|
||||||
import { PreventBerryUseAbAttr, applyAbAttrs } from '../data/ability';
|
import { PreventBerryUseAbAttr, applyAbAttrs } from '../data/ability';
|
||||||
import { FormChangeItem, SpeciesFormChangeItemTrigger } from '../data/pokemon-forms';
|
import { FormChangeItem, SpeciesFormChangeItemTrigger } from '../data/pokemon-forms';
|
||||||
import { ModifierTier } from './modifier-tier';
|
|
||||||
|
|
||||||
type ModifierType = ModifierTypes.ModifierType;
|
type ModifierType = ModifierTypes.ModifierType;
|
||||||
export type ModifierPredicate = (modifier: Modifier) => boolean;
|
export type ModifierPredicate = (modifier: Modifier) => boolean;
|
||||||
|
@ -1924,10 +1923,8 @@ export class EnemyAttackStatusEffectChanceModifier extends EnemyPersistentModifi
|
||||||
|
|
||||||
apply(args: any[]): boolean {
|
apply(args: any[]): boolean {
|
||||||
const target = (args[0] as Pokemon);
|
const target = (args[0] as Pokemon);
|
||||||
if (Phaser.Math.RND.realInRange(0, 1) < (this.chance * this.getStackCount())) {
|
if (Phaser.Math.RND.realInRange(0, 1) < (this.chance * this.getStackCount()))
|
||||||
target.scene.unshiftPhase(new ObtainStatusEffectPhase(target.scene, target.getBattlerIndex(), this.effect));
|
return target.trySetStatus(this.effect, true);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1744,6 +1744,11 @@ export class TurnEndPhase extends FieldPhase {
|
||||||
this.scene.applyModifier(EnemyStatusEffectHealChanceModifier, false, pokemon);
|
this.scene.applyModifier(EnemyStatusEffectHealChanceModifier, false, pokemon);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.scene.arena.terrain && pokemon.isGrounded()) {
|
||||||
|
this.scene.unshiftPhase(new PokemonHealPhase(this.scene, pokemon.getBattlerIndex(),
|
||||||
|
Math.max(pokemon.getMaxHp() >> 4, 1), getPokemonMessage(pokemon, ' regained\nhealth from the Grassy Terrain!'), true));
|
||||||
|
}
|
||||||
|
|
||||||
applyPostTurnAbAttrs(PostTurnAbAttr, pokemon);
|
applyPostTurnAbAttrs(PostTurnAbAttr, pokemon);
|
||||||
|
|
||||||
this.scene.applyModifiers(TurnHeldItemTransferModifier, pokemon.isPlayer(), pokemon);
|
this.scene.applyModifiers(TurnHeldItemTransferModifier, pokemon.isPlayer(), pokemon);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import BattleScene from "../battle-scene";
|
import BattleScene from "../battle-scene";
|
||||||
|
import { TerrainType, getTerrainColor } from "../data/terrain";
|
||||||
import * as Utils from "../utils";
|
import * as Utils from "../utils";
|
||||||
|
|
||||||
const spriteFragShader = `
|
const spriteFragShader = `
|
||||||
|
@ -21,6 +22,8 @@ uniform int isOutside;
|
||||||
uniform vec3 dayTint;
|
uniform vec3 dayTint;
|
||||||
uniform vec3 duskTint;
|
uniform vec3 duskTint;
|
||||||
uniform vec3 nightTint;
|
uniform vec3 nightTint;
|
||||||
|
uniform vec3 terrainColor;
|
||||||
|
uniform float terrainColorRatio;
|
||||||
|
|
||||||
float blendOverlay(float base, float blend) {
|
float blendOverlay(float base, float blend) {
|
||||||
return base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend));
|
return base<0.5?(2.0*base*blend):(1.0-2.0*(1.0-base)*(1.0-blend));
|
||||||
|
@ -34,6 +37,89 @@ vec3 blendHardLight(vec3 base, vec3 blend) {
|
||||||
return blendOverlay(blend, base);
|
return blendOverlay(blend, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float hue2rgb(float f1, float f2, float hue) {
|
||||||
|
if (hue < 0.0)
|
||||||
|
hue += 1.0;
|
||||||
|
else if (hue > 1.0)
|
||||||
|
hue -= 1.0;
|
||||||
|
float res;
|
||||||
|
if ((6.0 * hue) < 1.0)
|
||||||
|
res = f1 + (f2 - f1) * 6.0 * hue;
|
||||||
|
else if ((2.0 * hue) < 1.0)
|
||||||
|
res = f2;
|
||||||
|
else if ((3.0 * hue) < 2.0)
|
||||||
|
res = f1 + (f2 - f1) * ((2.0 / 3.0) - hue) * 6.0;
|
||||||
|
else
|
||||||
|
res = f1;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 rgb2hsl(vec3 color) {
|
||||||
|
vec3 hsl;
|
||||||
|
|
||||||
|
float fmin = min(min(color.r, color.g), color.b);
|
||||||
|
float fmax = max(max(color.r, color.g), color.b);
|
||||||
|
float delta = fmax - fmin;
|
||||||
|
|
||||||
|
hsl.z = (fmax + fmin) / 2.0;
|
||||||
|
|
||||||
|
if (delta == 0.0) {
|
||||||
|
hsl.x = 0.0;
|
||||||
|
hsl.y = 0.0;
|
||||||
|
} else {
|
||||||
|
if (hsl.z < 0.5)
|
||||||
|
hsl.y = delta / (fmax + fmin);
|
||||||
|
else
|
||||||
|
hsl.y = delta / (2.0 - fmax - fmin);
|
||||||
|
|
||||||
|
float deltaR = (((fmax - color.r) / 6.0) + (delta / 2.0)) / delta;
|
||||||
|
float deltaG = (((fmax - color.g) / 6.0) + (delta / 2.0)) / delta;
|
||||||
|
float deltaB = (((fmax - color.b) / 6.0) + (delta / 2.0)) / delta;
|
||||||
|
|
||||||
|
if (color.r == fmax )
|
||||||
|
hsl.x = deltaB - deltaG;
|
||||||
|
else if (color.g == fmax)
|
||||||
|
hsl.x = (1.0 / 3.0) + deltaR - deltaB;
|
||||||
|
else if (color.b == fmax)
|
||||||
|
hsl.x = (2.0 / 3.0) + deltaG - deltaR;
|
||||||
|
|
||||||
|
if (hsl.x < 0.0)
|
||||||
|
hsl.x += 1.0;
|
||||||
|
else if (hsl.x > 1.0)
|
||||||
|
hsl.x -= 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return hsl;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hsl2rgb(vec3 hsl) {
|
||||||
|
vec3 rgb;
|
||||||
|
|
||||||
|
if (hsl.y == 0.0)
|
||||||
|
rgb = vec3(hsl.z);
|
||||||
|
else {
|
||||||
|
float f2;
|
||||||
|
|
||||||
|
if (hsl.z < 0.5)
|
||||||
|
f2 = hsl.z * (1.0 + hsl.y);
|
||||||
|
else
|
||||||
|
f2 = (hsl.z + hsl.y) - (hsl.y * hsl.z);
|
||||||
|
|
||||||
|
float f1 = 2.0 * hsl.z - f2;
|
||||||
|
|
||||||
|
rgb.r = hue2rgb(f1, f2, hsl.x + (1.0/3.0));
|
||||||
|
rgb.g = hue2rgb(f1, f2, hsl.x);
|
||||||
|
rgb.b= hue2rgb(f1, f2, hsl.x - (1.0/3.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 blendHue(vec3 base, vec3 blend) {
|
||||||
|
vec3 baseHSL = rgb2hsl(base);
|
||||||
|
return hsl2rgb(vec3(rgb2hsl(blend).r, baseHSL.g, baseHSL.b));
|
||||||
|
}
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 texture;
|
vec4 texture;
|
||||||
|
|
||||||
|
@ -77,6 +163,12 @@ void main() {
|
||||||
color = vec4(blendHardLight(color.rgb, dayNightTint), color.a);
|
color = vec4(blendHardLight(color.rgb, dayNightTint), color.a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (terrainColorRatio > 0.0 && 1.0 - terrainColorRatio < outTexCoord.y) {
|
||||||
|
if (color.a > 0.0 && terrainColor.r > 0.0 && terrainColor.g > 0.0 && terrainColor.b > 0.0) {
|
||||||
|
color.rgb = mix(color.rgb, blendHue(color.rgb, terrainColor), 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gl_FragColor = color;
|
gl_FragColor = color;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -127,6 +219,8 @@ export default class FieldSpritePipeline extends Phaser.Renderer.WebGL.Pipelines
|
||||||
onPreRender(): void {
|
onPreRender(): void {
|
||||||
this.set1f('time', 0);
|
this.set1f('time', 0);
|
||||||
this.set1i('ignoreTimeTint', 0);
|
this.set1i('ignoreTimeTint', 0);
|
||||||
|
this.set1f('terrainColorRatio', 0);
|
||||||
|
this.set3fv('terrainColor', [ 0, 0, 0 ]);
|
||||||
}
|
}
|
||||||
|
|
||||||
onBind(gameObject: Phaser.GameObjects.GameObject): void {
|
onBind(gameObject: Phaser.GameObjects.GameObject): void {
|
||||||
|
@ -137,6 +231,7 @@ export default class FieldSpritePipeline extends Phaser.Renderer.WebGL.Pipelines
|
||||||
|
|
||||||
const data = sprite.pipelineData;
|
const data = sprite.pipelineData;
|
||||||
const ignoreTimeTint = data['ignoreTimeTint'] as boolean;
|
const ignoreTimeTint = data['ignoreTimeTint'] as boolean;
|
||||||
|
const terrainColorRatio = data['terrainColorRatio'] as number || 0;
|
||||||
|
|
||||||
let time = scene.currentBattle?.waveIndex
|
let time = scene.currentBattle?.waveIndex
|
||||||
? ((scene.currentBattle.waveIndex + scene.getWaveCycleOffset()) % 40) / 40 // ((new Date().getSeconds() * 1000 + new Date().getMilliseconds()) % 10000) / 10000
|
? ((scene.currentBattle.waveIndex + scene.getWaveCycleOffset()) % 40) / 40 // ((new Date().getSeconds() * 1000 + new Date().getMilliseconds()) % 10000) / 10000
|
||||||
|
@ -147,6 +242,8 @@ export default class FieldSpritePipeline extends Phaser.Renderer.WebGL.Pipelines
|
||||||
this.set3fv('dayTint', scene.arena.getDayTint().map(c => c / 255));
|
this.set3fv('dayTint', scene.arena.getDayTint().map(c => c / 255));
|
||||||
this.set3fv('duskTint', scene.arena.getDuskTint().map(c => c / 255));
|
this.set3fv('duskTint', scene.arena.getDuskTint().map(c => c / 255));
|
||||||
this.set3fv('nightTint', scene.arena.getNightTint().map(c => c / 255));
|
this.set3fv('nightTint', scene.arena.getNightTint().map(c => c / 255));
|
||||||
|
this.set3fv('terrainColor', getTerrainColor(scene.arena.terrain?.terrainType || TerrainType.NONE).map(c => c / 255));
|
||||||
|
this.set1f('terrainColorRatio', terrainColorRatio);
|
||||||
}
|
}
|
||||||
|
|
||||||
onBatch(gameObject: Phaser.GameObjects.GameObject): void {
|
onBatch(gameObject: Phaser.GameObjects.GameObject): void {
|
||||||
|
|
Loading…
Reference in New Issue