Refactor source files and add berries

This commit is contained in:
Flashfyre committed 2023-04-20 15:46:05 -04:00
1 parent 6135243641
commit 3546f3b5a7
103 files changed
+2598 -1171

No files matched your search

+360
View File
@@ -0,0 +1,360 @@
export class Ability {
public id: Abilities;
public name: string;
public description: string;
public generation: integer;
constructor(id: Abilities, name: string, description: string, generation: integer) {
this.id = id;
this.name = name;
this.description = description;
this.generation = generation;
}
}
export enum Abilities {
NONE,
AIR_LOCK = 1,
ARENA_TRAP,
BATTLE_ARMOR,
BLAZE,
CHLOROPHYLL,
CLEAR_BODY,
CLOUD_NINE,
COLOR_CHANGE,
COMPOUND_EYES,
CUTE_CHARM,
DAMP,
DRIZZLE,
DROUGHT,
EARLY_BIRD,
EFFECT_SPORE,
FLAME_BODY,
FLASH_FIRE,
FORECAST,
GUTS,
HUGE_POWER,
HUSTLE,
HYPER_CUTTER,
ILLUMINATE,
IMMUNITY,
INNER_FOCUS,
INSOMNIA,
INTIMIDATE,
KEEN_EYE,
LEVITATE,
LIGHTNING_ROD,
LIMBER,
LIQUID_OOZE,
MAGMA_ARMOR,
MAGNET_PULL,
MARVEL_SCALE,
MINUS,
NATURAL_CURE,
OBLIVIOUS,
OVERGROW,
OWN_TEMPO,
PICKUP,
PLUS,
POISON_POINT,
PRESSURE,
PURE_POWER,
RAIN_DISH,
ROCK_HEAD,
ROUGH_SKIN,
RUN_AWAY,
SAND_STREAM,
SAND_VEIL,
SERENE_GRACE,
SHADOW_TAG,
SHED_SKIN,
SHELL_ARMOR,
SHIELD_DUST,
SOUNDPROOF,
SPEED_BOOST,
STATIC,
STENCH,
STICKY_HOLD,
STURDY,
SUCTION_CUPS,
SWARM,
SWIFT_SWIM,
SYNCHRONIZE,
THICK_FAT,
TORRENT,
TRACE,
TRUANT,
VITAL_SPIRIT,
VOLT_ABSORB,
WATER_ABSORB,
WATER_VEIL,
WHITE_SMOKE,
WONDER_GUARD,
ADAPTABILITY,
AFTERMATH,
ANGER_POINT,
ANTICIPATION,
BAD_DREAMS,
DOWNLOAD,
DRY_SKIN,
FILTER,
FLOWER_GIFT,
FOREWARN,
FRISK,
GLUTTONY,
HEATPROOF,
HONEY_GATHER,
HYDRATION,
ICE_BODY,
IRON_FIST,
KLUTZ,
LEAF_GUARD,
MAGIC_GUARD,
MOLD_BREAKER,
MOTOR_DRIVE,
MULTITYPE,
NO_GUARD,
NORMALIZE,
POISON_HEAL,
QUICK_FEET,
RECKLESS,
RIVALRY,
SCRAPPY,
SIMPLE,
SKILL_LINK,
SLOW_START,
SNIPER,
SNOW_CLOAK,
SNOW_WARNING,
SOLAR_POWER,
SOLID_ROCK,
STALL,
STEADFAST,
STORM_DRAIN,
SUPER_LUCK,
TANGLED_FEET,
TECHNICIAN,
TINTED_LENS,
UNAWARE,
UNBURDEN,
ANALYTIC,
BIG_PECKS,
CONTRARY,
CURSED_BODY,
DEFEATIST,
DEFIANT,
FLARE_BOOST,
FRIEND_GUARD,
HARVEST,
HEALER,
HEAVY_METAL,
ILLUSION,
IMPOSTER,
INFILTRATOR,
IRON_BARBS,
JUSTIFIED,
LIGHT_METAL,
MAGIC_BOUNCE,
MOODY,
MOXIE,
MULTISCALE,
MUMMY,
OVERCOAT,
PICKPOCKET,
POISON_TOUCH,
PRANKSTER,
RATTLED,
REGENERATOR,
SAND_FORCE,
SAND_RUSH,
SAP_SIPPER,
SHEER_FORCE,
TELEPATHY,
TERAVOLT,
TOXIC_BOOST,
TURBOBLAZE,
UNNERVE,
VICTORY_STAR,
WEAK_ARMOR,
WONDER_SKIN,
ZEN_MODE,
COMPETITIVE,
DARK_AURA,
FAIRY_AURA,
PROTEAN,
SLUSH_RUSH,
NEUTRALIZING_GAS
}
export const abilities = [
new Ability(Abilities.AIR_LOCK, "Air Lock", "Eliminates the effects of weather.", 3),
new Ability(Abilities.ARENA_TRAP, "Arena Trap", "Prevents the foe from fleeing.", 3),
new Ability(Abilities.BATTLE_ARMOR, "Battle Armor", "The POKéMON is protected against critical hits.", 3),
new Ability(Abilities.BLAZE, "Blaze", "Powers up Fire-type moves in a pinch.", 3),
new Ability(Abilities.CHLOROPHYLL, "Chlorophyll", "Boosts the POKéMON's SPEED in sunshine.", 3),
new Ability(Abilities.CLEAR_BODY, "Clear Body", "Prevents other POKéMON from lowering its stats.", 3),
new Ability(Abilities.CLOUD_NINE, "Cloud Nine", "Eliminates the effects of weather.", 3),
new Ability(Abilities.COLOR_CHANGE, "Color Change", "Changes the POKéMON's type to the foe's move.", 3),
new Ability(Abilities.COMPOUND_EYES, "Compound Eyes", "The POKéMON's accuracy is boosted.", 3),
new Ability(Abilities.CUTE_CHARM, "Cute Charm", "Contact with the POKéMON may cause infatuation.", 3),
new Ability(Abilities.DAMP, "Damp", "Prevents the use of self-destructing moves.", 3),
new Ability(Abilities.DRIZZLE, "Drizzle", "The POKéMON makes it rain when it enters a battle.", 3),
new Ability(Abilities.DROUGHT, "Drought", "Turns the sunlight harsh when the POKéMON enters a battle.", 3),
new Ability(Abilities.EARLY_BIRD, "Early Bird", "The POKéMON awakens quickly from sleep.", 3),
new Ability(Abilities.EFFECT_SPORE, "Effect Spore", "Contact may poison or cause paralysis or sleep.", 3),
new Ability(Abilities.FLAME_BODY, "Flame Body", "Contact with the POKéMON may burn the attacker.", 3),
new Ability(Abilities.FLASH_FIRE, "Flash Fire", "It powers up Fire-type moves if it's hit by one.", 3),
new Ability(Abilities.FORECAST, "Forecast", "Castform transforms with the weather.", 3),
new Ability(Abilities.GUTS, "Guts", "Boosts ATTACK if there is a status problem.", 3),
new Ability(Abilities.HUGE_POWER, "Huge Power", "Raises the POKéMON's ATTACK stat.", 3),
new Ability(Abilities.HUSTLE, "Hustle", "Boosts the ATTACK stat, but lowers accuracy.", 3),
new Ability(Abilities.HYPER_CUTTER, "Hyper Cutter", "Prevents other POKéMON from lowering ATTACK stat.", 3),
new Ability(Abilities.ILLUMINATE, "Illuminate", "Raises the likelihood of meeting wild POKéMON.", 3),
new Ability(Abilities.IMMUNITY, "Immunity", "Prevents the POKéMON from getting poisoned.", 3),
new Ability(Abilities.INNER_FOCUS, "Inner Focus", "The POKéMON is protected from flinching.", 3),
new Ability(Abilities.INSOMNIA, "Insomnia", "Prevents the POKéMON from falling asleep.", 3),
new Ability(Abilities.INTIMIDATE, "Intimidate", "Lowers the foe's ATTACK stat.", 3),
new Ability(Abilities.KEEN_EYE, "Keen Eye", "Prevents other POKéMON from lowering accuracy.", 3),
new Ability(Abilities.LEVITATE, "Levitate", "Gives immunity to Ground type moves.", 3),
new Ability(Abilities.LIGHTNING_ROD, "Lightning Rod", "Draws in all Electric-type moves to up SP. ATK.", 3),
new Ability(Abilities.LIMBER, "Limber", "The POKéMON is protected from paralysis.", 3),
new Ability(Abilities.LIQUID_OOZE, "Liquid Ooze", "Damages attackers using any draining move.", 3),
new Ability(Abilities.MAGMA_ARMOR, "Magma Armor", "Prevents the POKéMON from becoming frozen.", 3),
new Ability(Abilities.MAGNET_PULL, "Magnet Pull", "Prevents Steel-type POKéMON from escaping.", 3),
new Ability(Abilities.MARVEL_SCALE, "Marvel Scale", "Ups DEFENSE if there is a status problem.", 3),
new Ability(Abilities.MINUS, "Minus", "Ups SP. ATK if another POKéMON has Plus or Minus.", 3),
new Ability(Abilities.NATURAL_CURE, "Natural Cure", "All status problems heal when it switches out.", 3),
new Ability(Abilities.OBLIVIOUS, "Oblivious", "Prevents it from becoming infatuated.", 3),
new Ability(Abilities.OVERGROW, "Overgrow", "Powers up Grass-type moves in a pinch.", 3),
new Ability(Abilities.OWN_TEMPO, "Own Tempo", "Prevents the POKéMON from becoming confused.", 3),
new Ability(Abilities.PICKUP, "Pickup", "The POKéMON may pick up items.", 3),
new Ability(Abilities.PLUS, "Plus", "Ups SP. ATK if another POKéMON has Plus or Minus.", 3),
new Ability(Abilities.POISON_POINT, "Poison Point", "Contact with the POKéMON may poison the attacker.", 3),
new Ability(Abilities.PRESSURE, "Pressure", "The POKéMON raises the foe's PP usage.", 3),
new Ability(Abilities.PURE_POWER, "Pure Power", "Raises the POKéMON's ATTACK stat.", 3),
new Ability(Abilities.RAIN_DISH, "Rain Dish", "The POKéMON gradually regains HP in rain.", 3),
new Ability(Abilities.ROCK_HEAD, "Rock Head", "Protects the POKéMON from recoil damage.", 3),
new Ability(Abilities.ROUGH_SKIN, "Rough Skin", "Inflicts damage to the attacker on contact.", 3),
new Ability(Abilities.RUN_AWAY, "Run Away", "Enables a sure getaway from wild POKéMON.", 3),
new Ability(Abilities.SAND_STREAM, "Sand Stream", "The POKéMON summons a sandstorm in battle.", 3),
new Ability(Abilities.SAND_VEIL, "Sand Veil", "Boosts the POKéMON's evasion in a sandstorm.", 3),
new Ability(Abilities.SERENE_GRACE, "Serene Grace", "Boosts the likelihood of added effects appearing.", 3),
new Ability(Abilities.SHADOW_TAG, "Shadow Tag", "Prevents the foe from escaping.", 3),
new Ability(Abilities.SHED_SKIN, "Shed Skin", "The POKéMON may heal its own status problems.", 3),
new Ability(Abilities.SHELL_ARMOR, "Shell Armor", "The POKéMON is protected against critical hits.", 3),
new Ability(Abilities.SHIELD_DUST, "Shield Dust", "Blocks the added effects of attacks taken.", 3),
new Ability(Abilities.SOUNDPROOF, "Soundproof", "Gives immunity to sound-based moves.", 3),
new Ability(Abilities.SPEED_BOOST, "Speed Boost", "Its SPEED stat is gradually boosted.", 3),
new Ability(Abilities.STATIC, "Static", "Contact with the POKéMON may cause paralysis.", 3),
new Ability(Abilities.STENCH, "Stench", "The stench may cause the target to flinch.", 3),
new Ability(Abilities.STICKY_HOLD, "Sticky Hold", "Protects the POKéMON from item theft.", 3),
new Ability(Abilities.STURDY, "Sturdy", "It cannot be knocked out with one hit.", 3),
new Ability(Abilities.SUCTION_CUPS, "Suction Cups", "Negates all moves that force switching out.", 3),
new Ability(Abilities.SWARM, "Swarm", "Powers up Bug-type moves in a pinch.", 3),
new Ability(Abilities.SWIFT_SWIM, "Swift Swim", "Boosts the POKéMON's SPEED in rain.", 3),
new Ability(Abilities.SYNCHRONIZE, "Synchronize", "Passes a burn, poison, or paralysis to the foe.", 3),
new Ability(Abilities.THICK_FAT, "Thick Fat", "Ups resistance to Fire- and Ice-type moves.", 3),
new Ability(Abilities.TORRENT, "Torrent", "Powers up Water-type moves in a pinch.", 3),
new Ability(Abilities.TRACE, "Trace", "The POKéMON copies a foe's Ability.", 3),
new Ability(Abilities.TRUANT, "Truant", "POKéMON can't attack on consecutive turns.", 3),
new Ability(Abilities.VITAL_SPIRIT, "Vital Spirit", "Prevents the POKéMON from falling asleep.", 3),
new Ability(Abilities.VOLT_ABSORB, "Volt Absorb", "Restores HP if hit by an Electric-type move.", 3),
new Ability(Abilities.WATER_ABSORB, "Water Absorb", "Restores HP if hit by a Water-type move.", 3),
new Ability(Abilities.WATER_VEIL, "Water Veil", "Prevents the POKéMON from getting a burn.", 3),
new Ability(Abilities.WHITE_SMOKE, "White Smoke", "Prevents other POKéMON from lowering its stats.", 3),
new Ability(Abilities.WONDER_GUARD, "Wonder Guard", "Only supereffective moves will hit.", 3),
new Ability(Abilities.ADAPTABILITY, "Adaptability", "Powers up moves of the same type.", 4),
new Ability(Abilities.AFTERMATH, "Aftermath", "Damages the attacker landing the finishing hit.", 4),
new Ability(Abilities.ANGER_POINT, "Anger Point", "Maxes ATTACK after taking a critical hit.", 4),
new Ability(Abilities.ANTICIPATION, "Anticipation", "Senses a foe's dangerous moves.", 4),
new Ability(Abilities.BAD_DREAMS, "Bad Dreams", "Reduces a sleeping foe's HP.", 4),
new Ability(Abilities.DOWNLOAD, "Download", "Adjusts power according to a foe's defenses.", 4),
new Ability(Abilities.DRY_SKIN, "Dry Skin", "Reduces HP if it is hot. Water restores HP.", 4),
new Ability(Abilities.FILTER, "Filter", "Reduces damage from super-effective attacks.", 4),
new Ability(Abilities.FLOWER_GIFT, "Flower Gift", "Powers up party POKéMON when it is sunny.", 4),
new Ability(Abilities.FOREWARN, "Forewarn", "Determines what moves a foe has.", 4),
new Ability(Abilities.FRISK, "Frisk", "The POKéMON can check a foe's held item.", 4),
new Ability(Abilities.GLUTTONY, "Gluttony", "Encourages the early use of a held Berry.", 4),
new Ability(Abilities.HEATPROOF, "Heatproof", "Weakens the power of Fire-type moves.", 4),
new Ability(Abilities.HONEY_GATHER, "Honey Gather", "The POKéMON may gather Honey from somewhere.", 4),
new Ability(Abilities.HYDRATION, "Hydration", "Heals status problems if it is raining.", 4),
new Ability(Abilities.ICE_BODY, "Ice Body", "The POKéMON gradually regains HP in a hailstorm.", 4),
new Ability(Abilities.IRON_FIST, "Iron Fist", "Boosts the power of punching moves.", 4),
new Ability(Abilities.KLUTZ, "Klutz", "The POKéMON can't use any held items.", 4),
new Ability(Abilities.LEAF_GUARD, "Leaf Guard", "Prevents problems with status in sunny weather.", 4),
new Ability(Abilities.MAGIC_GUARD, "Magic Guard", "Protects the POKéMON from indirect damage.", 4),
new Ability(Abilities.MOLD_BREAKER, "Mold Breaker", "Moves can be used regardless of Abilities.", 4),
new Ability(Abilities.MOTOR_DRIVE, "Motor Drive", "Raises SPEED if hit by an Electric-type move.", 4),
new Ability(Abilities.MULTITYPE, "Multitype", "Changes type to match the held Plate.", 4),
new Ability(Abilities.NO_GUARD, "No Guard", "Ensures attacks by or against the POKéMON land.", 4),
new Ability(Abilities.NORMALIZE, "Normalize", "All the POKéMON's moves become the Normal type.", 4),
new Ability(Abilities.POISON_HEAL, "Poison Heal", "Restores HP if the POKéMON is poisoned.", 4),
new Ability(Abilities.QUICK_FEET, "Quick Feet", "Boosts SPEED if there is a status problem.", 4),
new Ability(Abilities.RECKLESS, "Reckless", "Powers up moves that have recoil damage.", 4),
new Ability(Abilities.RIVALRY, "Rivalry", "Deals more damage to a POKéMON of same gender.", 4),
new Ability(Abilities.SCRAPPY, "Scrappy", "Enables moves to hit Ghost-type POKéMON.", 4),
new Ability(Abilities.SIMPLE, "Simple", "Doubles all stat changes.", 4),
new Ability(Abilities.SKILL_LINK, "Skill Link", "Increases the frequency of multi-strike moves.", 4),
new Ability(Abilities.SLOW_START, "Slow Start", "Temporarily halves ATTACK and SPEED.", 4),
new Ability(Abilities.SNIPER, "Sniper", "Powers up moves if they become critical hits.", 4),
new Ability(Abilities.SNOW_CLOAK, "Snow Cloak", "Raises evasion in a hailstorm.", 4),
new Ability(Abilities.SNOW_WARNING, "Snow Warning", "The POKéMON summons a hailstorm in battle.", 4),
new Ability(Abilities.SOLAR_POWER, "Solar Power", "In sunshine, SP. ATK is boosted but HP decreases.", 4),
new Ability(Abilities.SOLID_ROCK, "Solid Rock", "Reduces damage from super-effective attacks.", 4),
new Ability(Abilities.STALL, "Stall", "The POKéMON moves after all other POKéMON do.", 4),
new Ability(Abilities.STEADFAST, "Steadfast", "Raises SPEED each time the POKéMON flinches.", 4),
new Ability(Abilities.STORM_DRAIN, "Storm Drain", "Draws in all Water-type moves to up SP. ATK.", 4),
new Ability(Abilities.SUPER_LUCK, "Super Luck", "Heightens the critical-hit ratios of moves.", 4),
new Ability(Abilities.TANGLED_FEET, "Tangled Feet", "Raises evasion if the POKéMON is confused.", 4),
new Ability(Abilities.TECHNICIAN, "Technician", "Powers up the POKéMON's weaker moves.", 4),
new Ability(Abilities.TINTED_LENS, "Tinted Lens", "Powers up “not very effective” moves.", 4),
new Ability(Abilities.UNAWARE, "Unaware", "Ignores any stat changes in the POKéMON.", 4),
new Ability(Abilities.UNBURDEN, "Unburden", "Raises SPEED if a held item is used.", 4),
new Ability(Abilities.ANALYTIC, "Analytic", "Boosts move power when the POKéMON moves last.", 5),
new Ability(Abilities.BIG_PECKS, "Big Pecks", "Protects the POKéMON from DEFENSE-lowering attacks.", 5),
new Ability(Abilities.CONTRARY, "Contrary", "Makes stat changes have an opposite effect.", 5),
new Ability(Abilities.CURSED_BODY, "Cursed Body", "May disable a move used on the POKéMON.", 5),
new Ability(Abilities.DEFEATIST, "Defeatist", "Lowers stats when HP drops below half.", 5),
new Ability(Abilities.DEFIANT, "Defiant", "Sharply raises ATTACK when the POKéMON's stats are lowered.", 5),
new Ability(Abilities.FLARE_BOOST, "Flare Boost", "Powers up special attacks when burned.", 5),
new Ability(Abilities.FRIEND_GUARD, "Friend Guard", "Reduces damage done to allies.", 5),
new Ability(Abilities.HARVEST, "Harvest", "May create another Berry after one is used.", 5),
new Ability(Abilities.HEALER, "Healer", "May heal an ally's status conditions.", 5),
new Ability(Abilities.HEAVY_METAL, "Heavy Metal", "Doubles the POKéMON's weight.", 5),
new Ability(Abilities.ILLUSION, "Illusion", "Enters battle disguised as the last POKéMON in the party.", 5),
new Ability(Abilities.IMPOSTER, "Imposter", "It transforms itself into the POKéMON it is facing.", 5),
new Ability(Abilities.INFILTRATOR, "Infiltrator", "Passes through the foe's barrier and strikes.", 5),
new Ability(Abilities.IRON_BARBS, "Iron Barbs", "Inflicts damage to the POKéMON on contact.", 5),
new Ability(Abilities.JUSTIFIED, "Justified", "Raises ATTACK when hit by a Dark-type move.", 5),
new Ability(Abilities.LIGHT_METAL, "Light Metal", "Halves the POKéMON's weight.", 5),
new Ability(Abilities.MAGIC_BOUNCE, "Magic Bounce", "Reflects status- changing moves.", 5),
new Ability(Abilities.MOODY, "Moody", "Raises one stat and lowers another.", 5),
new Ability(Abilities.MOXIE, "Moxie", "Boosts ATTACK after knocking out any POKéMON.", 5),
new Ability(Abilities.MULTISCALE, "Multiscale", "Reduces damage when HP is full.", 5),
new Ability(Abilities.MUMMY, "Mummy", "Contact with this POKéMON spreads this Ability.", 5),
new Ability(Abilities.OVERCOAT, "Overcoat", "Protects the POKéMON from weather damage.", 5),
new Ability(Abilities.PICKPOCKET, "Pickpocket", "Steals an item when hit by another POKéMON.", 5),
new Ability(Abilities.POISON_TOUCH, "Poison Touch", "May poison targets when a POKéMON makes contact.", 5),
new Ability(Abilities.PRANKSTER, "Prankster", "Gives priority to a status move.", 5),
new Ability(Abilities.RATTLED, "Rattled", "Bug, Ghost or Dark type moves scare it and boost its SPEED.", 5),
new Ability(Abilities.REGENERATOR, "Regenerator", "Restores a little HP when withdrawn from battle.", 5),
new Ability(Abilities.SAND_FORCE, "Sand Force", "Boosts certain moves' power in a sandstorm.", 5),
new Ability(Abilities.SAND_RUSH, "Sand Rush", "Boosts the POKéMON's SPEED in a sandstorm.", 5),
new Ability(Abilities.SAP_SIPPER, "Sap Sipper", "Boosts ATTACK when hit by a Grass-type move.", 5),
new Ability(Abilities.SHEER_FORCE, "Sheer Force", "Removes added effects to increase move damage.", 5),
new Ability(Abilities.TELEPATHY, "Telepathy", "Anticipates an ally's ATTACK and dodges it.", 5),
new Ability(Abilities.TERAVOLT, "Teravolt", "Moves can be used regardless of Abilities.", 5),
new Ability(Abilities.TOXIC_BOOST, "Toxic Boost", "Powers up physical attacks when poisoned.", 5),
new Ability(Abilities.TURBOBLAZE, "Turboblaze", "Moves can be used regardless of Abilities.", 5),
new Ability(Abilities.UNNERVE, "Unnerve", "Makes the foe nervous and unable to eat Berries.", 5),
new Ability(Abilities.VICTORY_STAR, "Victory Star", "Boosts the accuracy of its allies and itself.", 5),
new Ability(Abilities.WEAK_ARMOR, "Weak Armor", "Physical attacks lower DEFENSE and raise SPEED.", 5),
new Ability(Abilities.WONDER_SKIN, "Wonder Skin", "Makes status-changing moves more likely to miss.", 5),
new Ability(Abilities.ZEN_MODE, "Zen Mode", "Changes form when HP drops below half.", 5),
new Ability(Abilities.COMPETITIVE, "Competitive", "Sharply raises SP. ATK when the POKéMON's stats are lowered.", 6),
new Ability(Abilities.DARK_AURA, "Dark Aura", "Raises power of Dark type moves for all POKéMON in battle.", 6),
new Ability(Abilities.FAIRY_AURA, "Fairy Aura", "Raises power of Fairy type moves for all POKéMON in battle.", 6),
new Ability(Abilities.PROTEAN, "Protean", "Changes the POKéMON's type to its last used move.", 6),
new Ability(Abilities.SLUSH_RUSH, "Slush Rush", "Boosts the POKéMON's SPEED stat in a hailstorm.", 7),
new Ability(Abilities.NEUTRALIZING_GAS, "Neutralizing Gas", "Neutralizes abilities of all POKéMON in battle.", 8)
];
+974
View File
@@ -0,0 +1,974 @@
//import { battleAnimRawData } from "./battle-anim-raw-data";
import BattleScene from "../battle-scene";
import { ChargeAttr, Moves, allMoves } from "./move";
import Pokemon from "../pokemon";
import * as Utils from "../utils";
//import fs from 'vite-plugin-fs/browser';
export enum AnimFrameTarget {
USER,
TARGET,
GRAPHIC
}
enum AnimFocus {
USER = 1,
TARGET,
USER_TARGET,
SCREEN
}
enum AnimBlendType {
NORMAL,
ADD,
SUBTRACT
}
export enum ChargeAnim {
FLY_CHARGING = 1000,
BOUNCE_CHARGING,
DIG_CHARGING,
DIVE_CHARGING,
SOLAR_BEAM_CHARGING,
SHADOW_FORCE_CHARGING,
SKULL_BASH_CHARGING,
FREEZE_SHOCK_CHARGING,
SKY_DROP_CHARGING,
SKY_ATTACK_CHARGING,
ICE_BURN_CHARGING,
DOOM_DESIRE_CHARGING,
RAZOR_WIND_CHARGING
}
export enum CommonAnim {
USE_ITEM = 2000,
HEALTH_UP,
POISON = 2010,
TOXIC,
PARALYSIS,
SLEEP,
FROZEN,
BURN,
CONFUSION,
ATTRACT,
BIND,
WRAP,
CURSE_NO_GHOST,
LEECH_SEED,
FIRE_SPIN,
PROTECT,
COVET,
WHIRLPOOL,
BIDE,
SAND_TOMB,
QUICK_GUARD,
WIDE_GUARD,
CURSE,
MAGMA_STORM,
CLAMP,
SUNNY = 2100,
RAIN,
SANDSTORM,
HAIL,
WIND,
HEAVY_RAIN,
HARSH_SUN,
STRONG_WINDS,
MISTY_TERRAIN = 2110,
ELECTRIC_TERRAIN,
GRASSY_TERRAIN,
PSYCHIC_TERRAIN
}
export class AnimConfig {
public id: integer;
public graphic: string;
public frames: AnimFrame[][];
public frameTimedEvents: Map<integer, AnimTimedEvent[]>;
public position: integer;
public hue: integer;
constructor(source?: any) {
this.frameTimedEvents = new Map<integer, AnimTimedEvent[]>;
if (source) {
this.id = source.id;
this.graphic = source.graphic;
this.frames = source.frames;
const frameTimedEvents = source.frameTimedEvents;
for (let fte of Object.keys(frameTimedEvents)) {
const timedEvents: AnimTimedEvent[] = [];
for (let te of frameTimedEvents[fte]) {
let timedEvent: AnimTimedEvent;
switch (te.eventType) {
case 'AnimTimedSoundEvent':
timedEvent = new AnimTimedSoundEvent(te.frameIndex, te.resourceName, te);
break;
case 'AnimTimedAddBgEvent':
timedEvent = new AnimTimedAddBgEvent(te.frameIndex, te.resourceName, te);
break;
case 'AnimTimedUpdateBgEvent':
timedEvent = new AnimTimedUpdateBgEvent(te.frameIndex, te.resourceName, te);
break;
}
timedEvents.push(timedEvent);
}
this.frameTimedEvents.set(parseInt(fte), timedEvents);
}
this.position = source.position;
this.hue = source.hue;
} else
this.frames = [];
}
getSoundResourceNames(): string[] {
const sounds = new Set<string>();
for (let ftes of this.frameTimedEvents.values()) {
for (let fte of ftes) {
if (fte instanceof AnimTimedSoundEvent && fte.resourceName)
sounds.add(fte.resourceName);
}
}
return Array.from(sounds.values());
}
getBackgroundResourceNames(): string[] {
const backgrounds = new Set<string>();
for (let ftes of this.frameTimedEvents.values()) {
for (let fte of ftes) {
if (fte instanceof AnimTimedAddBgEvent && fte.resourceName)
backgrounds.add(fte.resourceName);
}
}
return Array.from(backgrounds.values());
}
}
class AnimFrame {
public x: number;
public y: number;
public zoomX: number;
public zoomY: number;
public angle: number;
public mirror: boolean;
public visible: boolean;
public blendType: AnimBlendType;
public target: AnimFrameTarget;
public graphicFrame: integer;
public opacity: integer;
public color: integer[];
public tone: integer[];
public flash: integer[];
public locked: boolean;
public priority: integer;
public focus: AnimFocus;
constructor(x: number, y: number, zoomX: number, zoomY: number, angle: number, mirror: boolean, visible: boolean, blendType: AnimBlendType, pattern: integer,
opacity: integer, colorR: integer, colorG: integer, colorB: integer, colorA: integer, toneR: integer, toneG: integer, toneB: integer, toneA: integer,
flashR: integer, flashG: integer, flashB: integer, flashA: integer, locked: boolean, priority: integer, focus: AnimFocus) {
this.x = x;
this.y = y;
this.zoomX = zoomX;
this.zoomY = zoomY;
this.angle = angle;
this.mirror = mirror;
this.visible = visible;
this.blendType = blendType;
let target = AnimFrameTarget.GRAPHIC;
switch (pattern) {
case -2:
target = AnimFrameTarget.TARGET;
this.x -= 384;
this.y -= 96;
break;
case -1:
target = AnimFrameTarget.USER;
this.x -= 128;
this.y -= 224;
break;
default:
this.x = (this.x - 128) * 0.5;
this.y = (this.y - 224) * 0.5;
}
this.target = target;
this.graphicFrame = pattern >= 0 ? pattern : 0;
this.opacity = opacity;
this.color = [ colorR, colorG, colorB, colorA ];
this.tone = [ toneR, toneG, toneB, toneA ];
this.flash = [ flashR, flashG, flashB, flashA ];
this.locked = locked;
this.priority = priority;
this.focus = focus;
}
}
abstract class AnimTimedEvent {
public frameIndex: integer;
public resourceName: string;
constructor(frameIndex: integer, resourceName: string) {
this.frameIndex = frameIndex;
this.resourceName = resourceName;
}
abstract execute(scene: BattleScene, battleAnim: BattleAnim): integer;
abstract getEventType(): string;
}
class AnimTimedSoundEvent extends AnimTimedEvent {
public volume: number;
public pitch: number;
constructor(frameIndex: integer, resourceName: string, source?: any) {
super(frameIndex, resourceName + (resourceName && resourceName.indexOf('.') === -1 ? resourceName.startsWith('PRSFX-') ? '.wav' : '.ogg' : ''));
if (source) {
this.volume = source.volume;
this.pitch = source.pitch;
} else
this.pitch = 100;
}
execute(scene: BattleScene, battleAnim: BattleAnim): integer {
const soundConfig = { rate: (this.pitch * 0.01), volume: (this.volume * 0.01) };
if (this.resourceName) {
try {
scene.sound.play(this.resourceName, soundConfig);
} catch (err) {
console.error(err);
}
return Math.ceil((scene.sound.get(this.resourceName).totalDuration * 1000) / 33.33);
} else
return Math.ceil(battleAnim.user.cry(soundConfig) / 33.33);
}
getEventType(): string {
return 'AnimTimedSoundEvent';
}
}
abstract class AnimTimedBgEvent extends AnimTimedEvent {
public bgX: number;
public bgY: number;
public opacity: integer;
public colorRed: integer;
public colorGreen: integer;
public colorBlue: integer;
public colorAlpha: integer;
public duration: integer;
public flashScope: integer;
public flashRed: integer;
public flashGreen: integer;
public flashBlue: integer;
public flashAlpha: integer;
public flashDuration: integer;
constructor(frameIndex: integer, resourceName: string, source: any) {
super(frameIndex, resourceName);
if (source) {
this.bgX = source.bgX;
this.bgY = source.bgY;
this.opacity = source.opacity;
this.colorRed = source.colorRed;
this.colorGreen = source.colorGreen;
this.colorBlue = source.colorBlue;
this.colorAlpha = source.colorAlpha;
this.duration = source.duration;
this.flashScope = source.flashScope;
this.flashRed = source.flashRed;
this.flashGreen = source.flashGreen;
this.flashBlue = source.flashBlue;
this.flashAlpha = source.flashAlpha;
this.flashDuration = source.flashDuration;
}
}
}
class AnimTimedUpdateBgEvent extends AnimTimedBgEvent {
constructor(frameIndex: integer, resourceName: string, source?: any) {
super(frameIndex, resourceName, source);
}
execute(scene: BattleScene, moveAnim: MoveAnim): integer {
const tweenProps = {};
if (this.bgX !== undefined)
tweenProps['x'] = (this.bgX * 0.5) - 320;
if (this.bgY !== undefined)
tweenProps['y'] = (this.bgY * 0.5) - 284;
if (this.opacity !== undefined)
tweenProps['alpha'] = this.opacity / 255;
if (Object.keys(tweenProps).length) {
scene.tweens.add(Object.assign({
targets: moveAnim.bgSprite,
duration: this.duration * 3,
useFrames: true
}, tweenProps))
}
return this.duration * 2;
}
getEventType(): string {
return 'AnimTimedUpdateBgEvent';
}
}
class AnimTimedAddBgEvent extends AnimTimedBgEvent {
constructor(frameIndex: integer, resourceName: string, source?: any) {
super(frameIndex, resourceName, source);
}
execute(scene: BattleScene, moveAnim: MoveAnim): integer {
if (moveAnim.bgSprite)
moveAnim.bgSprite.destroy();
moveAnim.bgSprite = scene.add.tileSprite(this.bgX - 320, this.bgY - 284, 896, 576, this.resourceName);
moveAnim.bgSprite.setOrigin(0, 0);
moveAnim.bgSprite.setScale(1.25);
moveAnim.bgSprite.setAlpha(0);
scene.field.add(moveAnim.bgSprite);
scene.field.moveBelow(moveAnim.bgSprite, scene.getEnemyPokemon());
scene.tweens.add({
targets: moveAnim.bgSprite,
alpha: 1,
duration: this.duration * 3,
useFrames: true
});
return this.duration * 2;
}
getEventType(): string {
return 'AnimTimedAddBgEvent';
}
}
export const moveAnims = new Map<Moves, AnimConfig | [AnimConfig, AnimConfig]>();
export const chargeAnims = new Map<ChargeAnim, AnimConfig | [AnimConfig, AnimConfig]>();
export const commonAnims = new Map<CommonAnim, AnimConfig>();
export function initCommonAnims(): Promise<void> {
return new Promise(resolve => {
const commonAnimNames = Utils.getEnumKeys(CommonAnim);
const commonAnimIds = Utils.getEnumValues(CommonAnim);
const commonAnimFetches = [];
for (let ca = 0; ca < commonAnimIds.length; ca++) {
const commonAnimId = commonAnimIds[ca];
commonAnimFetches.push(fetch(`./battle-anims/common-${commonAnimNames[ca].toLowerCase().replace(/\_/g, '-')}.json`)
.then(response => response.json())
.then(cas => commonAnims.set(commonAnimId, new AnimConfig(cas))));
}
Promise.allSettled(commonAnimFetches).then(() => resolve());
});
}
export function initMoveAnim(move: Moves): Promise<void> {
return new Promise(resolve => {
if (moveAnims.has(move)) {
if (moveAnims.get(move) !== null)
resolve();
else {
let loadedCheckTimer = setInterval(() => {
if (moveAnims.get(move) !== null) {
clearInterval(loadedCheckTimer);
resolve();
}
}, 50);
}
} else {
moveAnims.set(move, null);
fetch(`./battle-anims/${Moves[move].toLowerCase().replace(/\_/g, '-')}.json`)
.then(response => response.json())
.then(ba => {
if (Array.isArray(ba)) {
populateMoveAnim(move, ba[0]);
populateMoveAnim(move, ba[1]);
} else
populateMoveAnim(move, ba);
const chargeAttr = allMoves[move - 1].getAttrs(ChargeAttr) as ChargeAttr[];
if (chargeAttr.length)
initMoveChargeAnim(chargeAttr[0].chargeAnim).then(() => resolve());
else
resolve();
});
}
});
}
export function initMoveChargeAnim(chargeAnim: ChargeAnim): Promise<void> {
return new Promise(resolve => {
if (chargeAnims.has(chargeAnim)) {
if (chargeAnims.get(chargeAnim) !== null)
resolve();
else {
let loadedCheckTimer = setInterval(() => {
if (chargeAnims.get(chargeAnim) !== null) {
clearInterval(loadedCheckTimer);
resolve();
}
}, 50);
}
} else {
chargeAnims.set(chargeAnim, null);
fetch(`./battle-anims/${ChargeAnim[chargeAnim].toLowerCase().replace(/\_/g, '-')}.json`)
.then(response => response.json())
.then(ca => {
if (Array.isArray(ca)) {
populateMoveChargeAnim(chargeAnim, ca[0]);
populateMoveChargeAnim(chargeAnim, ca[1]);
} else
populateMoveChargeAnim(chargeAnim, ca);
resolve();
});
}
});
}
function populateMoveAnim(move: Moves, animSource: any): void {
const moveAnim = new AnimConfig(animSource);
if (moveAnims.get(move) === null) {
moveAnims.set(move, moveAnim);
return;
}
moveAnims.set(move, [ moveAnims.get(move) as AnimConfig, moveAnim ]);
}
function populateMoveChargeAnim(chargeAnim: ChargeAnim, animSource: any) {
const moveChargeAnim = new AnimConfig(animSource);
if (chargeAnims.get(chargeAnim) === null) {
chargeAnims.set(chargeAnim, moveChargeAnim);
return;
}
chargeAnims.set(chargeAnim, [ chargeAnims.get(chargeAnim) as AnimConfig, moveChargeAnim ]);
}
export function loadCommonAnimAssets(scene: BattleScene, startLoad?: boolean): Promise<void> {
return new Promise(resolve => {
loadAnimAssets(scene, Array.from(commonAnims.values()), startLoad).then(() => resolve());
});
}
export function loadMoveAnimAssets(scene: BattleScene, moveIds: Moves[], startLoad?: boolean): Promise<void> {
return new Promise(resolve => {
const moveAnimations = moveIds.map(m => moveAnims.get(m) as AnimConfig).flat();
for (let moveId of moveIds) {
const chargeAttr = allMoves[moveId - 1].getAttrs(ChargeAttr) as ChargeAttr[];
if (chargeAttr.length) {
const moveChargeAnims = chargeAnims.get(chargeAttr[0].chargeAnim);
moveAnimations.push(moveChargeAnims instanceof AnimConfig ? moveChargeAnims : moveChargeAnims[0]);
if (Array.isArray(moveChargeAnims))
moveAnimations.push(moveChargeAnims[1]);
}
}
loadAnimAssets(scene, moveAnimations, startLoad).then(() => resolve());
});
}
function loadAnimAssets(scene: BattleScene, anims: AnimConfig[], startLoad?: boolean): Promise<void> {
return new Promise(resolve => {
const backgrounds = new Set<string>();
const sounds = new Set<string>();
for (let a of anims) {
const animSounds = a.getSoundResourceNames();
for (let ms of animSounds)
sounds.add(ms);
const animBackgrounds = a.getBackgroundResourceNames();
for (let abg of animBackgrounds)
backgrounds.add(abg);
if (a.graphic)
scene.loadSpritesheet(a.graphic, 'battle_anims', 96);
}
for (let bg of backgrounds)
scene.loadImage(bg, 'battle_anims');
for (let s of sounds)
scene.loadSe(s, 'battle_anims', s);
if (startLoad) {
scene.load.once(Phaser.Loader.Events.COMPLETE, () => resolve());
if (!scene.load.isLoading())
scene.load.start();
} else
resolve();
});
}
interface GraphicFrameData {
x: number,
y: number,
angle: number
}
export abstract class BattleAnim {
public user: Pokemon;
public target: Pokemon;
public sprites: Phaser.GameObjects.Sprite[];
public bgSprite: Phaser.GameObjects.TileSprite;
constructor(user: Pokemon, target: Pokemon) {
this.user = user;
this.target = target;
this.sprites = [];
}
abstract getAnim(): AnimConfig;
abstract isOppAnim(): boolean;
abstract isReverseCoords(): boolean;
getGraphicScale(): number {
return 1;
}
private getGraphicFrameData(scene: BattleScene, frames: AnimFrame[]): Map<integer, GraphicFrameData> {
const ret = new Map<integer, GraphicFrameData>();
const isOppAnim = this.isOppAnim();
const user = !isOppAnim ? this.user : this.target;
const target = !isOppAnim ? this.target : this.user;
const isReverseCoords = this.isReverseCoords();
const graphicScale = this.getGraphicScale();
const userInitialX = user.x;
const userInitialY = user.y;
const userHalfHeight = user.getSprite().displayHeight / 2;
const targetInitialX = target.x;
const targetInitialY = target.y;
const targetHalfHeight = target.getSprite().displayHeight / 2;
let g = 0;
for (let frame of frames) {
if (frame.target !== AnimFrameTarget.GRAPHIC)
continue;
const xProgress = frame.focus !== AnimFocus.SCREEN ? Math.min(Math.max(frame.x, 0) / 128, 1) : 0;
const initialX = targetInitialX;
const initialY = targetInitialY;
let xOffset = (!isReverseCoords ? (userInitialX - targetInitialX) : (targetInitialX - userInitialX));
let yOffset = (!isReverseCoords ? (userInitialY - targetInitialY) : (targetInitialY - userInitialY));
const ySpriteOffset = ((userHalfHeight * (1 - xProgress)) + (targetHalfHeight * xProgress)) * -1;
if (graphicScale > 1) {
xOffset -= ((scene.game.canvas.width / 6) * (graphicScale - 1)) / 2;
yOffset -= ((scene.game.canvas.height / 6) * (graphicScale - 1)) / 2;
}
const x = initialX + xOffset * (!isReverseCoords ? 1 : -1) + (frame.x * graphicScale) * (!isReverseCoords ? 1 : -1);
const y = ((initialY + yOffset * (!isReverseCoords || frame.focus === AnimFocus.USER || frame.focus === AnimFocus.SCREEN ? 1 : -1)
+ (frame.y * graphicScale) * (!isReverseCoords || (frame.focus !== AnimFocus.USER_TARGET) ? 1 : -1) + ySpriteOffset));
const angle = -frame.angle * (!isReverseCoords ? 1 : -1);
ret.set(g++, { x: x, y: y, angle: angle });
}
return ret;
}
play(scene: BattleScene, callback?: Function) {
const isOppAnim = this.isOppAnim();
const user = !isOppAnim ? this.user : this.target;
const target = !isOppAnim ? this.target : this.user;
const anim = this.getAnim();
const userInitialX = user.x;
const userInitialY = user.y;
const targetInitialX = target.x;
const targetInitialY = target.y;
const isReverseCoords = this.isReverseCoords();
let r = anim.frames.length;
let f = 0;
const sprites: Phaser.GameObjects.Sprite[] = [];
const spritePriorities: integer[] = [];
scene.tweens.addCounter({
useFrames: true,
duration: 3,
repeat: anim.frames.length,
onRepeat: () => {
const spriteFrames = anim.frames[f];
const frameData = this.getGraphicFrameData(scene, anim.frames[f]);
let g = 0;
for (let frame of spriteFrames) {
switch (frame.target) {
case AnimFrameTarget.USER:
user.setPosition(userInitialX + frame.x / (!isReverseCoords ? 2 : -2), userInitialY + frame.y / (!isOppAnim ? 2 : -2));
break;
case AnimFrameTarget.TARGET:
target.setPosition(targetInitialX + frame.x / (!isReverseCoords ? 2 : -2), targetInitialY + frame.y / (!isOppAnim ? 2 : -2));
break;
case AnimFrameTarget.GRAPHIC:
if (g === sprites.length) {
const newSprite = scene.add.sprite(0, 0, anim.graphic, 1);
sprites.push(newSprite);
scene.field.add(newSprite);
spritePriorities.push(1);
}
const graphicIndex = g++;
const moveSprite = sprites[graphicIndex];
if (spritePriorities[graphicIndex] !== frame.priority) {
spritePriorities[graphicIndex] = frame.priority;
const setSpritePriority = (priority: integer) => {
switch (priority) {
case 0:
scene.field.moveBelow(moveSprite, scene.getEnemyPokemon());
break;
case 1:
scene.field.moveTo(moveSprite, scene.field.getAll().length - 1);
break;
case 2:
switch (frame.focus) {
case AnimFocus.USER:
if (this.bgSprite)
scene.field.moveAbove(moveSprite, this.bgSprite);
else
scene.field.moveBelow(moveSprite, this.user);
break;
case AnimFocus.TARGET:
scene.field.moveBelow(moveSprite, this.target);
break;
default:
setSpritePriority(1);
break;
}
break;
case 3:
switch (frame.focus) {
case AnimFocus.USER:
scene.field.moveAbove(moveSprite, this.user);
break;
case AnimFocus.TARGET:
scene.field.moveAbove(moveSprite, this.target);
break;
default:
setSpritePriority(1);
break;
}
break;
default:
setSpritePriority(1);
}
};
setSpritePriority(frame.priority);
}
moveSprite.setFrame(frame.graphicFrame);
//console.log(AnimFocus[frame.focus]);
const graphicScale = this.getGraphicScale();
moveSprite.setPosition(frameData.get(graphicIndex).x, frameData.get(graphicIndex).y);
moveSprite.setAngle(frameData.get(graphicIndex).angle);
const scaleX = graphicScale * (isReverseCoords === frame.mirror ? 1 : -1);
const scaleY = graphicScale;
moveSprite.setScale(scaleX, scaleY);
moveSprite.setAlpha(frame.opacity / 255);
moveSprite.setBlendMode(frame.blendType === AnimBlendType.NORMAL ? Phaser.BlendModes.NORMAL : frame.blendType === AnimBlendType.ADD ? Phaser.BlendModes.ADD : Phaser.BlendModes.DIFFERENCE);
break;
}
if (frame.target !== AnimFrameTarget.GRAPHIC) {
const pokemon = frame.target === AnimFrameTarget.USER ? user : target;
pokemon.setScale(!frame.mirror ? 1 : -1)
pokemon.setAlpha(frame.opacity / 255);
pokemon.setAngle(-frame.angle * (!isReverseCoords ? 1 : -1));
const zoomScaleX = frame.zoomX / 100;
const zoomScaleY = frame.zoomY / 100;
const zoomSprite = pokemon.getZoomSprite();
zoomSprite.setY(zoomSprite.displayHeight * (zoomScaleY - 1) * 0.5);
zoomSprite.setScale(zoomScaleX, zoomScaleY);
}
}
if (anim.frameTimedEvents.has(f)) {
for (let event of anim.frameTimedEvents.get(f))
r = Math.max((anim.frames.length - f) + event.execute(scene, this), r);
}
if (g < sprites.length) {
const removedSprites = sprites.splice(g, sprites.length - g);
spritePriorities.splice(g, sprites.length - g);
for (let rs of removedSprites)
rs.destroy();
}
f++;
r--;
},
onComplete: () => {
const cleanUpAndComplete = () => {
user.setPosition(userInitialX, userInitialY);
user.setScale(1);
user.setAlpha(1);
user.setAngle(0);
target.setPosition(targetInitialX, targetInitialY);
target.setScale(1);
target.setAlpha(1);
target.setAngle(0);
if (this.bgSprite)
this.bgSprite.destroy();
if (callback)
callback();
};
for (let ms of sprites) {
if (ms)
ms.destroy();
}
if (r) {
scene.tweens.addCounter({
duration: r,
useFrames: true,
onComplete: () => cleanUpAndComplete()
});
} else
cleanUpAndComplete();
}
});
}
}
export class CommonBattleAnim extends BattleAnim {
public commonAnim: CommonAnim;
constructor(commonAnim: CommonAnim, user: Pokemon, target?: Pokemon) {
super(user, target || user);
this.commonAnim = commonAnim;
}
getAnim(): AnimConfig {
return commonAnims.get(this.commonAnim);
}
isOppAnim(): boolean {
return false;
}
isReverseCoords(): boolean {
return false;
}
}
export class MoveAnim extends BattleAnim {
public move: Moves;
constructor(move: Moves, user: Pokemon, target: Pokemon) {
super(user, target);
this.move = move;
}
getAnim(): AnimConfig {
return moveAnims.get(this.move) instanceof AnimConfig
? moveAnims.get(this.move) as AnimConfig
: moveAnims.get(this.move)[this.user.isPlayer() ? 0 : 1] as AnimConfig;
}
isOppAnim(): boolean {
const ret = !this.user.isPlayer() && Array.isArray(moveAnims.get(this.move));
switch (this.move) {
case Moves.TELEPORT:
return !ret;
}
return ret;
}
isReverseCoords(): boolean {
return !this.user.isPlayer() === !this.isOppAnim();
}
getGraphicScale(): number {
switch (this.move) {
case Moves.FISSURE:
return 1.25;
}
return 1;
}
}
export class MoveChargeAnim extends MoveAnim {
private chargeAnim: ChargeAnim;
constructor(chargeAnim: ChargeAnim, move: Moves, user: Pokemon, target: Pokemon) {
super(move, user, target);
this.chargeAnim = chargeAnim;
}
getAnim(): AnimConfig {
return chargeAnims.get(this.chargeAnim) instanceof AnimConfig
? chargeAnims.get(this.chargeAnim) as AnimConfig
: chargeAnims.get(this.chargeAnim)[this.user.isPlayer() ? 0 : 1] as AnimConfig;
}
}
export function populateAnims() {
return;
const commonAnimNames = Utils.getEnumKeys(CommonAnim).map(k => k.toLowerCase());
const commonAnimMatchNames = commonAnimNames.map(k => k.replace(/\_/g, ''));
const commonAnimIds = Utils.getEnumValues(CommonAnim) as CommonAnim[];
const chargeAnimNames = Utils.getEnumKeys(ChargeAnim).map(k => k.toLowerCase());
const chargeAnimMatchNames = chargeAnimNames.map(k => k.replace(/\_/g, ' '));
const chargeAnimIds = Utils.getEnumValues(ChargeAnim) as ChargeAnim[];
const commonNamePattern = /name: (?:Common:)?(Opp )?(.*)/;
const moveNameToId = {};
for (let move of Utils.getEnumValues(Moves)) {
const moveName = Moves[move].toUpperCase().replace(/\_/g, '');
moveNameToId[moveName] = move;
}
const animsData = [];//battleAnimRawData.split('!ruby/array:PBAnimation').slice(1);
for (let a = 0; a < animsData.length; a++) {
const fields = animsData[a].split('@').slice(1);
let isOppMove: boolean;
let commonAnimId: CommonAnim;
let chargeAnimId: ChargeAnim;
if (!fields[1].startsWith('name: Move:') && !(isOppMove = fields[1].startsWith('name: OppMove:'))) {
const nameMatch = commonNamePattern.exec(fields[1]);
const name = nameMatch[2].toLowerCase();
if (commonAnimMatchNames.indexOf(name) > -1)
commonAnimId = commonAnimIds[commonAnimMatchNames.indexOf(name)];
else if (chargeAnimMatchNames.indexOf(name) > -1)
chargeAnimId = chargeAnimIds[chargeAnimMatchNames.indexOf(name)];
}
const nameIndex = fields[1].indexOf(':', 5) + 1;
const animName = fields[1].slice(nameIndex, fields[1].indexOf('\n', nameIndex));
if (!moveNameToId.hasOwnProperty(animName) && !commonAnimId && !chargeAnimId)
continue;
let anim = commonAnimId || chargeAnimId ? new AnimConfig() : new AnimConfig();
if (anim instanceof AnimConfig)
(anim as AnimConfig).id = moveNameToId[animName];
if (commonAnimId)
commonAnims.set(commonAnimId, anim);
else if (chargeAnimId)
chargeAnims.set(chargeAnimId, !isOppMove ? anim : [ chargeAnims.get(chargeAnimId) as AnimConfig, anim ]);
else
moveAnims.set(moveNameToId[animName], !isOppMove ? anim as AnimConfig : [ moveAnims.get(moveNameToId[animName]) as AnimConfig, anim as AnimConfig ]);
for (let f = 0; f < fields.length; f++) {
const field = fields[f];
const fieldName = field.slice(0, field.indexOf(':'));
const fieldData = field.slice(fieldName.length + 1, field.lastIndexOf('\n')).trim();
switch (fieldName) {
case 'array':
const framesData = fieldData.split(' - - - ').slice(1);
for (let fd = 0; fd < framesData.length; fd++) {
anim.frames.push([]);
const frameData = framesData[fd];
const focusFramesData = frameData.split(' - - ');
for (let tf = 0; tf < focusFramesData.length; tf++) {
const values = focusFramesData[tf].replace(/ \- /g, '').split('\n');
const targetFrame = new AnimFrame(parseFloat(values[0]), parseFloat(values[1]), parseFloat(values[2]), parseFloat(values[11]), parseFloat(values[3]),
values[4] === '1', values[6] === '1', parseInt(values[5]), parseInt(values[7]), parseInt(values[8]), parseInt(values[12]), parseInt(values[13]),
parseInt(values[14]), parseInt(values[15]), parseInt(values[16]), parseInt(values[17]), parseInt(values[18]), parseInt(values[19]),
parseInt(values[21]), parseInt(values[22]), parseInt(values[23]), parseInt(values[24]), values[20] === '1', parseInt(values[25]), parseInt(values[26]) as AnimFocus);
anim.frames[fd].push(targetFrame);
}
}
break;
case 'graphic':
anim.graphic = fieldData !== "''" ? fieldData.slice(0, fieldData.indexOf('.')) : '';
break;
case 'timing':
const timingEntries = fieldData.split('- !ruby/object:PBAnimTiming ').slice(1);
for (let t = 0; t < timingEntries.length; t++) {
const timingData = timingEntries[t].replace(/\n/g, ' ').replace(/[ ]{2,}/g, ' ').replace(/[a-z]+: ! '', /ig, '').replace(/name: (.*?),/, 'name: "$1",')
.replace(/flashColor: !ruby\/object:Color { alpha: ([\d\.]+), blue: ([\d\.]+), green: ([\d\.]+), red: ([\d\.]+)}/, 'flashRed: $4, flashGreen: $3, flashBlue: $2, flashAlpha: $1');
const frameIndex = parseInt(/frame: (\d+)/.exec(timingData)[1]);
const resourceName = /name: "(.*?)"/.exec(timingData)[1].replace("''", '');
const timingType = parseInt(/timingType: (\d)/.exec(timingData)[1]);
let timedEvent: AnimTimedEvent;
switch (timingType) {
case 0:
timedEvent = new AnimTimedSoundEvent(frameIndex, resourceName);
break;
case 1:
timedEvent = new AnimTimedAddBgEvent(frameIndex, resourceName.slice(0, resourceName.indexOf('.')));
break;
case 2:
timedEvent = new AnimTimedUpdateBgEvent(frameIndex, resourceName.slice(0, resourceName.indexOf('.')));
break;
}
if (!timedEvent)
continue;
const propPattern = /([a-z]+): (.*?)(?:,|\})/ig;
let propMatch: RegExpExecArray;
while ((propMatch = propPattern.exec(timingData))) {
const prop = propMatch[1];
let value: any = propMatch[2];
switch (prop) {
case 'bgX':
case 'bgY':
value = parseFloat(value);
break;
case 'volume':
case 'pitch':
case 'opacity':
case 'colorRed':
case 'colorGreen':
case 'colorBlue':
case 'colorAlpha':
case 'duration':
case 'flashScope':
case 'flashRed':
case 'flashGreen':
case 'flashBlue':
case 'flashAlpha':
case 'flashDuration':
value = parseInt(value);
break;
}
if (timedEvent.hasOwnProperty(prop))
timedEvent[prop] = value;
}
if (!anim.frameTimedEvents.has(frameIndex))
anim.frameTimedEvents.set(frameIndex, []);
anim.frameTimedEvents.get(frameIndex).push(timedEvent);
}
break;
case 'position':
anim.position = parseInt(fieldData);
break;
case 'hue':
anim.hue = parseInt(fieldData);
break;
}
}
}
const animReplacer = (k, v) => {
if (k === 'id' && !v)
return undefined;
if (v instanceof Map)
return Object.fromEntries(v);
if (v instanceof AnimTimedEvent)
v['eventType'] = v.getEventType();
return v;
}
/*for (let ma of moveAnims.keys()) {
const data = moveAnims.get(ma);
(async () => {
await fs.writeFile(`../public/battle-anims/${Moves[ma].toLowerCase().replace(/\_/g, '-')}.json`, JSON.stringify(data, animReplacer, ' '));
})();
}
for (let ca of chargeAnims.keys()) {
const data = chargeAnims.get(ca);
(async () => {
await fs.writeFile(`../public/battle-anims/${chargeAnimNames[chargeAnimIds.indexOf(ca)].replace(/\_/g, '-')}.json`, JSON.stringify(data, animReplacer, ' '));
})();
}
for (let cma of commonAnims.keys()) {
const data = commonAnims.get(cma);
(async () => {
await fs.writeFile(`../public/battle-anims/common-${commonAnimNames[commonAnimIds.indexOf(cma)].replace(/\_/g, '-')}.json`, JSON.stringify(data, animReplacer, ' '));
})();
}*/
}
+63
View File
@@ -0,0 +1,63 @@
export enum BattleStat {
ATK,
DEF,
SPATK,
SPDEF,
SPD,
ACC,
EVA,
RAND
}
export function getBattleStatName(stat: BattleStat) {
switch (stat) {
case BattleStat.ATK:
return 'ATTACK';
case BattleStat.DEF:
return 'DEFENSE';
case BattleStat.SPATK:
return 'SP. ATK';
case BattleStat.SPDEF:
return 'SP. DEF';
case BattleStat.SPD:
return 'SPEED';
case BattleStat.ACC:
return 'accuracy';
case BattleStat.EVA:
return 'evasiveness';
default:
return '???';
}
}
export function getBattleStatLevelChangeDescription(levels: integer, up: boolean) {
if (up) {
switch (levels) {
case 1:
return 'rose';
case 2:
return 'sharply rose';
case 3:
case 4:
case 5:
case 6:
return 'rose drastically';
default:
return 'won\'t go any higher';
}
} else {
switch (levels) {
case 1:
return 'fell';
case 2:
return 'harshly fell';
case 3:
case 4:
case 5:
case 6:
return 'severely fell';
default:
return 'won\'t go any lower';
}
}
}
+322
View File
@@ -0,0 +1,322 @@
import { CommonAnim, CommonBattleAnim } from "./battle-anims";
import { CommonAnimPhase, DamagePhase, MessagePhase, MovePhase, ObtainStatusEffectPhase, PokemonHealPhase } from "../battle-phases";
import { getPokemonMessage } from "../messages";
import Pokemon from "../pokemon";
import { Stat } from "./pokemon-stat";
import { StatusEffect } from "./status-effect";
import * as Utils from "../utils";
export enum BattleTagType {
NONE,
FLINCHED,
CONFUSED,
SEEDED,
NIGHTMARE,
FRENZY,
INGRAIN,
AQUA_RING,
DROWSY,
PROTECTED,
FLYING,
UNDERGROUND,
NO_CRIT,
BYPASS_SLEEP,
IGNORE_FLYING
}
export enum BattleTagLapseType {
FAINT,
MOVE,
AFTER_MOVE,
MOVE_EFFECT,
TURN_END,
CUSTOM
}
export class BattleTag {
public tagType: BattleTagType;
public lapseType: BattleTagLapseType;
public turnCount: integer;
constructor(tagType: BattleTagType, lapseType: BattleTagLapseType, turnCount: integer) {
this.tagType = tagType;
this.lapseType = lapseType;
this.turnCount = turnCount;
}
onAdd(pokemon: Pokemon): void { }
onRemove(pokemon: Pokemon): void { }
onOverlap(pokemon: Pokemon): void { }
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
return --this.turnCount > 0;
}
}
export class FlinchedTag extends BattleTag {
constructor() {
super(BattleTagType.FLINCHED, BattleTagLapseType.MOVE, 0);
}
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
super.lapse(pokemon, lapseType);
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' flinched!')));
return true;
}
}
export class PseudoStatusTag extends BattleTag {
constructor(tagType: BattleTagType, lapseType: BattleTagLapseType, turnCount: integer) {
super(tagType, lapseType, turnCount);
}
}
export class ConfusedTag extends PseudoStatusTag {
constructor(turnCount: integer) {
super(BattleTagType.CONFUSED, BattleTagLapseType.MOVE, turnCount);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.isPlayer(), CommonAnim.CONFUSION));
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' became\nconfused!')));
}
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' snapped\nout of confusion!')));
}
onOverlap(pokemon: Pokemon): void {
super.onOverlap(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' is\nalready confused!')));
}
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
const ret = lapseType !== BattleTagLapseType.CUSTOM && super.lapse(pokemon, lapseType);
if (ret) {
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' is\nconfused!')));
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.isPlayer(), CommonAnim.CONFUSION));
if (Utils.randInt(2)) {
const atk = pokemon.getBattleStat(Stat.ATK);
const def = pokemon.getBattleStat(Stat.DEF);
const damage = Math.ceil(((((2 * pokemon.level / 5 + 2) * 40 * atk / def) / 50) + 2) * ((Utils.randInt(15) + 85) / 100));
pokemon.damage(damage);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, 'It hurt itself in its\nconfusion!'));
pokemon.scene.unshiftPhase(new DamagePhase(pokemon.scene, pokemon.isPlayer()));
(pokemon.scene.getCurrentPhase() as MovePhase).cancel();
}
}
return ret;
}
}
export class SeedTag extends PseudoStatusTag {
constructor() {
super(BattleTagType.SEEDED, BattleTagLapseType.AFTER_MOVE, 1);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' was seeded!')));
}
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
console.trace(lapseType);
const ret = lapseType !== BattleTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, !pokemon.isPlayer(), CommonAnim.LEECH_SEED));
const damage = Math.max(Math.floor(pokemon.getMaxHp() / 8), 1);
pokemon.damage(damage);
pokemon.scene.unshiftPhase(new DamagePhase(pokemon.scene, pokemon.isPlayer()));
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, !pokemon.isPlayer(), damage, getPokemonMessage(pokemon, '\'s health is\nsapped by LEECH SEED!'), false, true));
}
return ret;
}
}
export class NightmareTag extends PseudoStatusTag {
constructor() {
super(BattleTagType.NIGHTMARE, BattleTagLapseType.AFTER_MOVE, 1);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' began\nhaving a NIGHTMARE!')));
}
onOverlap(pokemon: Pokemon): void {
super.onOverlap(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' is\nalready locked in a NIGHTMARE!')));
}
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
const ret = lapseType !== BattleTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' is locked\nin a NIGHTMARE!')));
pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.isPlayer(), CommonAnim.CURSE)); // TODO: Update animation type
const damage = Math.ceil(pokemon.getMaxHp() / 4);
pokemon.damage(damage);
pokemon.scene.unshiftPhase(new DamagePhase(pokemon.scene, pokemon.isPlayer()));
}
return ret;
}
}
export class IngrainTag extends PseudoStatusTag {
constructor() {
super(BattleTagType.INGRAIN, BattleTagLapseType.TURN_END, 1);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' planted its roots!')));
}
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
const ret = lapseType !== BattleTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret)
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.isPlayer(), Math.floor(pokemon.getMaxHp() / 16),
getPokemonMessage(pokemon, ` absorbed\nnutrients with its roots!`), true));
return ret;
}
}
export class AquaRingTag extends PseudoStatusTag {
constructor() {
super(BattleTagType.AQUA_RING, BattleTagLapseType.TURN_END, 1);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' surrounded\nitself with a veil of water!')));
}
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
const ret = lapseType !== BattleTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret)
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.isPlayer(), Math.floor(pokemon.getMaxHp() / 16), `AQUA RING restored\n${pokemon.name}\'s HP!`, true));
return ret;
}
}
export class DrowsyTag extends BattleTag {
constructor() {
super(BattleTagType.DROWSY, BattleTagLapseType.TURN_END, 2);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, ' grew drowsy!')));
}
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
if (!super.lapse(pokemon, lapseType)) {
pokemon.scene.unshiftPhase(new ObtainStatusEffectPhase(pokemon.scene, pokemon.isPlayer(), StatusEffect.SLEEP));
return false;
}
return true;
}
}
export class ProtectedTag extends BattleTag {
constructor() {
super(BattleTagType.PROTECTED, BattleTagLapseType.CUSTOM, 0);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, '\nprotected itself!')));
}
lapse(pokemon: Pokemon, lapseType: BattleTagLapseType): boolean {
console.log(pokemon, BattleTagLapseType[lapseType]);
if (lapseType === BattleTagLapseType.CUSTOM) {
new CommonBattleAnim(CommonAnim.PROTECT, pokemon).play(pokemon.scene);
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene, getPokemonMessage(pokemon, '\nprotected itself!')));
return true;
}
return super.lapse(pokemon, lapseType);
}
}
export class HideSpriteTag extends BattleTag {
constructor(tagType: BattleTagType, turnCount: integer) {
super(tagType, BattleTagLapseType.MOVE_EFFECT, turnCount);
}
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
pokemon.setVisible(false);
}
onRemove(pokemon: Pokemon): void {
// Wait 2 frames before setting visible for battle animations that don't immediately show the sprite invisible
pokemon.scene.tweens.addCounter({
duration: 2,
useFrames: true,
onComplete: () => pokemon.setVisible(true)
});
}
}
export function getBattleTag(tagType: BattleTagType, turnCount: integer): BattleTag {
switch (tagType) {
case BattleTagType.FLINCHED:
return new FlinchedTag();
case BattleTagType.CONFUSED:
return new ConfusedTag(turnCount);
case BattleTagType.SEEDED:
return new SeedTag();
case BattleTagType.NIGHTMARE:
return new NightmareTag();
case BattleTagType.AQUA_RING:
return new AquaRingTag();
case BattleTagType.DROWSY:
return new DrowsyTag();
case BattleTagType.PROTECTED:
return new ProtectedTag();
case BattleTagType.FLYING:
case BattleTagType.UNDERGROUND:
return new HideSpriteTag(tagType, turnCount);
case BattleTagType.NO_CRIT:
return new BattleTag(tagType, BattleTagLapseType.AFTER_MOVE, turnCount);
case BattleTagType.BYPASS_SLEEP:
return new BattleTag(BattleTagType.BYPASS_SLEEP, BattleTagLapseType.TURN_END, turnCount);
case BattleTagType.IGNORE_FLYING:
return new BattleTag(tagType, BattleTagLapseType.TURN_END, turnCount);
default:
return new BattleTag(tagType, BattleTagLapseType.CUSTOM, turnCount);
}
}
+60
View File
@@ -0,0 +1,60 @@
import { MessagePhase, PokemonHealPhase } from "../battle-phases";
import { getPokemonMessage } from "../messages";
import Pokemon from "../pokemon";
import { BattleTagType } from "./battle-tag";
import { getStatusEffectHealText } from "./status-effect";
export enum BerryType {
SITRUS,
LUM
}
export function getBerryName(berryType: BerryType) {
switch (berryType) {
case BerryType.SITRUS:
return 'SITRUS BERRY';
case BerryType.LUM:
return 'LUM BERRY';
}
}
export function getBerryEffectDescription(berryType: BerryType) {
switch (berryType) {
case BerryType.SITRUS:
return 'Restores 25% HP if HP is below 50%';
case BerryType.LUM:
return 'Cures any non-volatile status condition and confusion';
}
}
export type BerryPredicate = (pokemon: Pokemon) => boolean;
export function getBerryPredicate(berryType: BerryType): BerryPredicate {
switch (berryType) {
case BerryType.SITRUS:
return (pokemon: Pokemon) => pokemon.getHpRatio() < 0.5;
case BerryType.LUM:
return (pokemon: Pokemon) => !!pokemon.status || !!pokemon.getTag(BattleTagType.CONFUSED);
}
}
export type BerryEffectFunc = (pokemon: Pokemon) => void;
export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
switch (berryType) {
case BerryType.SITRUS:
return (pokemon: Pokemon) => {
pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, true, Math.floor(pokemon.getMaxHp() / 4), getPokemonMessage(pokemon, `'s ${getBerryName(berryType)}\nrestored its HP!`), true));
};
case BerryType.LUM:
return (pokemon: Pokemon) => {
if (pokemon.status) {
pokemon.scene.unshiftPhase(new MessagePhase(pokemon.scene,
getPokemonMessage(pokemon, getStatusEffectHealText(pokemon.status.effect))));
pokemon.resetStatus();
pokemon.updateInfo();
} else if (pokemon.getTag(BattleTagType.CONFUSED))
pokemon.lapseTag(BattleTagType.CONFUSED);
};
}
}
+3891
View File
File diff suppressed because it is too large. Load diff
+25
View File
@@ -0,0 +1,25 @@
export enum GrowthRate {
ERRATIC = 0,
FAST,
MEDIUM_FAST,
MEDIUM_SLOW,
SLOW,
FLUCTUATING
};
const expLevels = [
[ 0, 15, 52, 122, 237, 406, 637, 942, 1326, 1800, 2369, 3041, 3822, 4719, 5737, 6881, 8155, 9564, 11111, 12800, 14632, 16610, 18737, 21012, 23437, 26012, 28737, 31610, 34632, 37800, 41111, 44564, 48155, 51881, 55737, 59719, 63822, 68041, 72369, 76800, 81326, 85942, 90637, 95406, 100237, 105122, 110052, 115015, 120001, 125000, 131324, 137795, 144410, 151165, 158056, 165079, 172229, 179503, 186894, 194400, 202013, 209728, 217540, 225443, 233431, 241496, 249633, 257834, 267406, 276458, 286328, 296358, 305767, 316074, 326531, 336255, 346965, 357812, 367807, 378880, 390077, 400293, 411686, 423190, 433572, 445239, 457001, 467489, 479378, 491346, 501878, 513934, 526049, 536557, 548720, 560922, 571333, 583539, 591882, 600000 ],
[ 0, 6, 21, 51, 100, 172, 274, 409, 583, 800, 1064, 1382, 1757, 2195, 2700, 3276, 3930, 4665, 5487, 6400, 7408, 8518, 9733, 11059, 12500, 14060, 15746, 17561, 19511, 21600, 23832, 26214, 28749, 31443, 34300, 37324, 40522, 43897, 47455, 51200, 55136, 59270, 63605, 68147, 72900, 77868, 83058, 88473, 94119, 100000, 106120, 112486, 119101, 125971, 133100, 140492, 148154, 156089, 164303, 172800, 181584, 190662, 200037, 209715, 219700, 229996, 240610, 251545, 262807, 274400, 286328, 298598, 311213, 324179, 337500, 351180, 365226, 379641, 394431, 409600, 425152, 441094, 457429, 474163, 491300, 508844, 526802, 545177, 563975, 583200, 602856, 622950, 643485, 664467, 685900, 707788, 730138, 752953, 776239, 800000 ],
[ 0, 8, 27, 64, 125, 216, 343, 512, 729, 1000, 1331, 1728, 2197, 2744, 3375, 4096, 4913, 5832, 6859, 8000, 9261, 10648, 12167, 13824, 15625, 17576, 19683, 21952, 24389, 27000, 29791, 32768, 35937, 39304, 42875, 46656, 50653, 54872, 59319, 64000, 68921, 74088, 79507, 85184, 91125, 97336, 103823, 110592, 117649, 125000, 132651, 140608, 148877, 157464, 166375, 175616, 185193, 195112, 205379, 216000, 226981, 238328, 250047, 262144, 274625, 287496, 300763, 314432, 328509, 343000, 357911, 373248, 389017, 405224, 421875, 438976, 456533, 474552, 493039, 512000, 531441, 551368, 571787, 592704, 614125, 636056, 658503, 681472, 704969, 729000, 753571, 778688, 804357, 830584, 857375, 884736, 912673, 941192, 970299, 1000000 ],
[ 0, 9, 57, 96, 135, 179, 236, 314, 419, 560, 742, 973, 1261, 1612, 2035, 2535, 3120, 3798, 4575, 5460, 6458, 7577, 8825, 10208, 11735, 13411, 15244, 17242, 19411, 21760, 24294, 27021, 29949, 33084, 36435, 40007, 43808, 47846, 52127, 56660, 61450, 66505, 71833, 77440, 83335, 89523, 96012, 102810, 109923, 117360, 125126, 133229, 141677, 150476, 159635, 169159, 179056, 189334, 199999, 211060, 222522, 234393, 246681, 259392, 272535, 286115, 300140, 314618, 329555, 344960, 360838, 377197, 394045, 411388, 429235, 447591, 466464, 485862, 505791, 526260, 547274, 568841, 590969, 613664, 636935, 660787, 685228, 710266, 735907, 762160, 789030, 816525, 844653, 873420, 902835, 932903, 963632, 995030, 1027103, 1059860 ],
[ 0, 10, 33, 80, 156, 270, 428, 640, 911, 1250, 1663, 2160, 2746, 3430, 4218, 5120, 6141, 7290, 8573, 10000, 11576, 13310, 15208, 17280, 19531, 21970, 24603, 27440, 30486, 33750, 37238, 40960, 44921, 49130, 53593, 58320, 63316, 68590, 74148, 80000, 86151, 92610, 99383, 106480, 113906, 121670, 129778, 138240, 147061, 156250, 165813, 175760, 186096, 196830, 207968, 219520, 231491, 243890, 256723, 270000, 283726, 297910, 312558, 327680, 343281, 359370, 375953, 393040, 410636, 428750, 447388, 466560, 486271, 506530, 527343, 548720, 570666, 593190, 616298, 640000, 664301, 689210, 714733, 740880, 767656, 795070, 823128, 851840, 881211, 911250, 941963, 973360, 1005446, 1038230, 1071718, 1105920, 1140841, 1176490, 1212873, 1250000 ],
[ 0, 4, 13, 32, 65, 112, 178, 276, 393, 540, 745, 967, 1230, 1591, 1957, 2457, 3046, 3732, 4526, 5440, 6482, 7666, 9003, 10506, 12187, 14060, 16140, 18439, 20974, 23760, 26811, 30146, 33780, 37731, 42017, 46656, 50653, 55969, 60505, 66560, 71677, 78533, 84277, 91998, 98415, 107069, 114205, 123863, 131766, 142500, 151222, 163105, 172697, 185807, 196322, 210739, 222231, 238036, 250562, 267840, 281456, 300293, 315059, 335544, 351520, 373744, 390991, 415050, 433631, 459620, 479600, 507617, 529063, 559209, 582187, 614566, 639146, 673863, 700115, 737280, 765275, 804997, 834809, 877201, 908905, 954084, 987754, 1035837, 1071552, 1122660, 1160499, 1214753, 1254796, 1312322, 1354652, 1415577, 1460276, 1524731, 1571884, 1640000 ]
];
export function getLevelTotalExp(level: integer, growthRate: integer) {
return expLevels[growthRate][level - 1];
};
export function getLevelRelExp(level: integer, growthRate: integer) {
return getLevelTotalExp(level, growthRate) - getLevelTotalExp(level - 1, growthRate);
};
+25
View File
@@ -0,0 +1,25 @@
export enum Gender {
GENDERLESS = -1,
MALE,
FEMALE
}
export function getGenderSymbol(gender: Gender) {
switch (gender) {
case Gender.MALE:
return '♂';
case Gender.FEMALE:
return '♀';
}
return '';
}
export function getGenderColor(gender: Gender, shadow?: boolean) {
switch (gender) {
case Gender.MALE:
return shadow ? '#006090' : '#40c8f8';
case Gender.FEMALE:
return shadow ? '#984038' : '#f89890';
}
return '#ffffff';
}
+1995
View File
File diff suppressed because it is too large. Load diff
+114
View File
@@ -0,0 +1,114 @@
import BattleScene from "../battle-scene";
import { toPokemonUpperCase } from "../utils";
export enum PokeballType {
POKEBALL,
GREAT_BALL,
ULTRA_BALL,
MASTER_BALL,
LUXURY_BALL
};
export function getPokeballAtlasKey(type: PokeballType): string {
switch (type) {
case PokeballType.POKEBALL:
return 'pb';
case PokeballType.GREAT_BALL:
return 'gb';
case PokeballType.ULTRA_BALL:
return 'ub';
case PokeballType.MASTER_BALL:
return 'mb';
case PokeballType.LUXURY_BALL:
return 'lb';
}
}
export function getPokeballName(type: PokeballType): string {
let ret: string;
switch (type) {
case PokeballType.POKEBALL:
ret = 'Poké ball';
break;
case PokeballType.GREAT_BALL:
ret = 'Great Ball';
break;
case PokeballType.ULTRA_BALL:
ret = 'Ultra Ball';
break;
case PokeballType.MASTER_BALL:
ret = 'Master Ball';
break;
case PokeballType.LUXURY_BALL:
ret = 'Luxury Ball';
break;
}
return toPokemonUpperCase(ret);
}
export function getPokeballCatchMultiplier(type: PokeballType): number {
switch (type) {
case PokeballType.POKEBALL:
return 1;
case PokeballType.GREAT_BALL:
return 1.5;
case PokeballType.ULTRA_BALL:
return 2;
case PokeballType.MASTER_BALL:
return -1;
case PokeballType.LUXURY_BALL:
return 1;
}
}
export function getPokeballTintColor(type: PokeballType): number {
switch (type) {
case PokeballType.POKEBALL:
return 0xd52929;
case PokeballType.GREAT_BALL:
return 0x94b4de;
case PokeballType.ULTRA_BALL:
return 0xe6cd31;
case PokeballType.MASTER_BALL:
return 0xa441bd;
case PokeballType.LUXURY_BALL:
return 0xffde6a;
}
}
export function doPokeballBounceAnim(scene: BattleScene, pokeball: Phaser.GameObjects.Sprite, y1: number, y2: number, baseBounceDuration: integer, callback: Function) {
let bouncePower = 1;
let bounceYOffset = y1;
let bounceY = y2;
let yd = y2 - y1;
const doBounce = () => {
scene.tweens.add({
targets: pokeball,
y: y2,
duration: bouncePower * baseBounceDuration,
ease: 'Cubic.easeIn',
onComplete: () => {
scene.sound.play('pb_bounce_1', { volume: bouncePower });
bouncePower = bouncePower > 0.01 ? bouncePower * 0.5 : 0;
if (bouncePower) {
bounceYOffset = yd * bouncePower;
bounceY = y2 - bounceYOffset;
scene.tweens.add({
targets: pokeball,
y: bounceY,
duration: bouncePower * baseBounceDuration,
ease: 'Cubic.easeOut',
onComplete: () => doBounce()
});
} else if (callback)
callback();
}
});
};
doBounce();
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+35
View File
@@ -0,0 +1,35 @@
import { toPokemonUpperCase } from "../utils";
export enum Stat {
HP = 0,
ATK,
DEF,
SPATK,
SPDEF,
SPD
};
export function getStatName(stat: Stat) {
let ret: string;
switch (stat) {
case Stat.HP:
ret = 'Max. HP';
break;
case Stat.ATK:
ret = 'Attack';
break;
case Stat.DEF:
ret = 'Defense';
break;
case Stat.SPATK:
ret = 'Sp. Atk';
break;
case Stat.SPDEF:
ret = 'Sp. Def';
break;
case Stat.SPD:
ret = 'Speed';
break;
}
return toPokemonUpperCase(ret);
}
+653
View File
@@ -0,0 +1,653 @@
export enum Species {
BULBASAUR = 1,
IVYSAUR,
VENUSAUR,
CHARMANDER,
CHARMELEON,
CHARIZARD,
SQUIRTLE,
WARTORTLE,
BLASTOISE,
CATERPIE,
METAPOD,
BUTTERFREE,
WEEDLE,
KAKUNA,
BEEDRILL,
PIDGEY,
PIDGEOTTO,
PIDGEOT,
RATTATA,
RATICATE,
SPEAROW,
FEAROW,
EKANS,
ARBOK,
PIKACHU,
RAICHU,
SANDSHREW,
SANDSLASH,
NIDORAN_F,
NIDORINA,
NIDOQUEEN,
NIDORAN_M,
NIDORINO,
NIDOKING,
CLEFAIRY,
CLEFABLE,
VULPIX,
NINETALES,
JIGGLYPUFF,
WIGGLYTUFF,
ZUBAT,
GOLBAT,
ODDISH,
GLOOM,
VILEPLUME,
PARAS,
PARASECT,
VENONAT,
VENOMOTH,
DIGLETT,
DUGTRIO,
MEOWTH,
PERSIAN,
PSYDUCK,
GOLDUCK,
MANKEY,
PRIMEAPE,
GROWLITHE,
ARCANINE,
POLIWAG,
POLIWHIRL,
POLIWRATH,
ABRA,
KADABRA,
ALAKAZAM,
MACHOP,
MACHOKE,
MACHAMP,
BELLSPROUT,
WEEPINBELL,
VICTREEBEL,
TENTACOOL,
TENTACRUEL,
GEODUDE,
GRAVELER,
GOLEM,
PONYTA,
RAPIDASH,
SLOWPOKE,
SLOWBRO,
MAGNEMITE,
MAGNETON,
FARFETCHD,
DODUO,
DODRIO,
SEEL,
DEWGONG,
GRIMER,
MUK,
SHELLDER,
CLOYSTER,
GASTLY,
HAUNTER,
GENGAR,
ONIX,
DROWZEE,
HYPNO,
KRABBY,
KINGLER,
VOLTORB,
ELECTRODE,
EXEGGCUTE,
EXEGGUTOR,
CUBONE,
MAROWAK,
HITMONLEE,
HITMONCHAN,
LICKITUNG,
KOFFING,
WEEZING,
RHYHORN,
RHYDON,
CHANSEY,
TANGELA,
KANGASKHAN,
HORSEA,
SEADRA,
GOLDEEN,
SEAKING,
STARYU,
STARMIE,
MR_MIME,
SCYTHER,
JYNX,
ELECTABUZZ,
MAGMAR,
PINSIR,
TAUROS,
MAGIKARP,
GYARADOS,
LAPRAS,
DITTO,
EEVEE,
VAPOREON,
JOLTEON,
FLAREON,
PORYGON,
OMANYTE,
OMASTAR,
KABUTO,
KABUTOPS,
AERODACTYL,
SNORLAX,
ARTICUNO,
ZAPDOS,
MOLTRES,
DRATINI,
DRAGONAIR,
DRAGONITE,
MEWTWO,
MEW,
CHIKORITA,
BAYLEEF,
MEGANIUM,
CYNDAQUIL,
QUILAVA,
TYPHLOSION,
TOTODILE,
CROCONAW,
FERALIGATR,
SENTRET,
FURRET,
HOOTHOOT,
NOCTOWL,
LEDYBA,
LEDIAN,
SPINARAK,
ARIADOS,
CROBAT,
CHINCHOU,
LANTURN,
PICHU,
CLEFFA,
IGGLYBUFF,
TOGEPI,
TOGETIC,
NATU,
XATU,
MAREEP,
FLAAFFY,
AMPHAROS,
BELLOSSOM,
MARILL,
AZUMARILL,
SUDOWOODO,
POLITOED,
HOPPIP,
SKIPLOOM,
JUMPLUFF,
AIPOM,
SUNKERN,
SUNFLORA,
YANMA,
WOOPER,
QUAGSIRE,
ESPEON,
UMBREON,
MURKROW,
SLOWKING,
MISDREAVUS,
UNOWN,
WOBBUFFET,
GIRAFARIG,
PINECO,
FORRETRESS,
DUNSPARCE,
GLIGAR,
STEELIX,
SNUBBULL,
GRANBULL,
QWILFISH,
SCIZOR,
SHUCKLE,
HERACROSS,
SNEASEL,
TEDDIURSA,
URSARING,
SLUGMA,
MAGCARGO,
SWINUB,
PILOSWINE,
CORSOLA,
REMORAID,
OCTILLERY,
DELIBIRD,
MANTINE,
SKARMORY,
HOUNDOUR,
HOUNDOOM,
KINGDRA,
PHANPY,
DONPHAN,
PORYGON2,
STANTLER,
SMEARGLE,
TYROGUE,
HITMONTOP,
SMOOCHUM,
ELEKID,
MAGBY,
MILTANK,
BLISSEY,
RAIKOU,
ENTEI,
SUICUNE,
LARVITAR,
PUPITAR,
TYRANITAR,
LUGIA,
HO_OH,
CELEBI,
TREECKO,
GROVYLE,
SCEPTILE,
TORCHIC,
COMBUSKEN,
BLAZIKEN,
MUDKIP,
MARSHTOMP,
SWAMPERT,
POOCHYENA,
MIGHTYENA,
ZIGZAGOON,
LINOONE,
WURMPLE,
SILCOON,
BEAUTIFLY,
CASCOON,
DUSTOX,
LOTAD,
LOMBRE,
LUDICOLO,
SEEDOT,
NUZLEAF,
SHIFTRY,
TAILLOW,
SWELLOW,
WINGULL,
PELIPPER,
RALTS,
KIRLIA,
GARDEVOIR,
SURSKIT,
MASQUERAIN,
SHROOMISH,
BRELOOM,
SLAKOTH,
VIGOROTH,
SLAKING,
NINCADA,
NINJASK,
SHEDINJA,
WHISMUR,
LOUDRED,
EXPLOUD,
MAKUHITA,
HARIYAMA,
AZURILL,
NOSEPASS,
SKITTY,
DELCATTY,
SABLEYE,
MAWILE,
ARON,
LAIRON,
AGGRON,
MEDITITE,
MEDICHAM,
ELECTRIKE,
MANECTRIC,
PLUSLE,
MINUN,
VOLBEAT,
ILLUMISE,
ROSELIA,
GULPIN,
SWALOT,
CARVANHA,
SHARPEDO,
WAILMER,
WAILORD,
NUMEL,
CAMERUPT,
TORKOAL,
SPOINK,
GRUMPIG,
SPINDA,
TRAPINCH,
VIBRAVA,
FLYGON,
CACNEA,
CACTURNE,
SWABLU,
ALTARIA,
ZANGOOSE,
SEVIPER,
LUNATONE,
SOLROCK,
BARBOACH,
WHISCASH,
CORPHISH,
CRAWDAUNT,
BALTOY,
CLAYDOL,
LILEEP,
CRADILY,
ANORITH,
ARMALDO,
FEEBAS,
MILOTIC,
CASTFORM,
KECLEON,
SHUPPET,
BANETTE,
DUSKULL,
DUSCLOPS,
TROPIUS,
CHIMECHO,
ABSOL,
WYNAUT,
SNORUNT,
GLALIE,
SPHEAL,
SEALEO,
WALREIN,
CLAMPERL,
HUNTAIL,
GOREBYSS,
RELICANTH,
LUVDISC,
BAGON,
SHELGON,
SALAMENCE,
BELDUM,
METANG,
METAGROSS,
REGIROCK,
REGICE,
REGISTEEL,
LATIAS,
LATIOS,
KYOGRE,
GROUDON,
RAYQUAZA,
JIRACHI,
DEOXYS,
TURTWIG,
GROTLE,
TORTERRA,
CHIMCHAR,
MONFERNO,
INFERNAPE,
PIPLUP,
PRINPLUP,
EMPOLEON,
STARLY,
STARAVIA,
STARAPTOR,
BIDOOF,
BIBAREL,
KRICKETOT,
KRICKETUNE,
SHINX,
LUXIO,
LUXRAY,
BUDEW,
ROSERADE,
CRANIDOS,
RAMPARDOS,
SHIELDON,
BASTIODON,
BURMY,
WORMADAM,
MOTHIM,
COMBEE,
VESPIQUEN,
PACHIRISU,
BUIZEL,
FLOATZEL,
CHERUBI,
CHERRIM,
SHELLOS,
GASTRODON,
AMBIPOM,
DRIFLOON,
DRIFBLIM,
BUNEARY,
LOPUNNY,
MISMAGIUS,
HONCHKROW,
GLAMEOW,
PURUGLY,
CHINGLING,
STUNKY,
SKUNTANK,
BRONZOR,
BRONZONG,
BONSLY,
MIME_JR,
HAPPINY,
CHATOT,
SPIRITOMB,
GIBLE,
GABITE,
GARCHOMP,
MUNCHLAX,
RIOLU,
LUCARIO,
HIPPOPOTAS,
HIPPOWDON,
SKORUPI,
DRAPION,
CROAGUNK,
TOXICROAK,
CARNIVINE,
FINNEON,
LUMINEON,
MANTYKE,
SNOVER,
ABOMASNOW,
WEAVILE,
MAGNEZONE,
LICKILICKY,
RHYPERIOR,
TANGROWTH,
ELECTIVIRE,
MAGMORTAR,
TOGEKISS,
YANMEGA,
LEAFEON,
GLACEON,
GLISCOR,
MAMOSWINE,
PORYGON_Z,
GALLADE,
PROBOPASS,
DUSKNOIR,
FROSLASS,
ROTOM,
UXIE,
MESPRIT,
AZELF,
DIALGA,
PALKIA,
HEATRAN,
REGIGIGAS,
GIRATINA,
CRESSELIA,
PHIONE,
MANAPHY,
DARKRAI,
SHAYMIN,
ARCEUS,
VICTINI,
SNIVY,
SERVINE,
SERPERIOR,
TEPIG,
PIGNITE,
EMBOAR,
OSHAWOTT,
DEWOTT,
SAMUROTT,
PATRAT,
WATCHOG,
LILLIPUP,
HERDIER,
STOUTLAND,
PURRLOIN,
LIEPARD,
PANSAGE,
SIMISAGE,
PANSEAR,
SIMISEAR,
PANPOUR,
SIMIPOUR,
MUNNA,
MUSHARNA,
PIDOVE,
TRANQUILL,
UNFEZANT,
BLITZLE,
ZEBSTRIKA,
ROGGENROLA,
BOLDORE,
GIGALITH,
WOOBAT,
SWOOBAT,
DRILBUR,
EXCADRILL,
AUDINO,
TIMBURR,
GURDURR,
CONKELDURR,
TYMPOLE,
PALPITOAD,
SEISMITOAD,
THROH,
SAWK,
SEWADDLE,
SWADLOON,
LEAVANNY,
VENIPEDE,
WHIRLIPEDE,
SCOLIPEDE,
COTTONEE,
WHIMSICOTT,
PETILIL,
LILLIGANT,
BASCULIN,
SANDILE,
KROKOROK,
KROOKODILE,
DARUMAKA,
DARMANITAN,
MARACTUS,
DWEBBLE,
CRUSTLE,
SCRAGGY,
SCRAFTY,
SIGILYPH,
YAMASK,
COFAGRIGUS,
TIRTOUGA,
CARRACOSTA,
ARCHEN,
ARCHEOPS,
TRUBBISH,
GARBODOR,
ZORUA,
ZOROARK,
MINCCINO,
CINCCINO,
GOTHITA,
GOTHORITA,
GOTHITELLE,
SOLOSIS,
DUOSION,
REUNICLUS,
DUCKLETT,
SWANNA,
VANILLITE,
VANILLISH,
VANILLUXE,
DEERLING,
SAWSBUCK,
EMOLGA,
KARRABLAST,
ESCAVALIER,
FOONGUS,
AMOONGUSS,
FRILLISH,
JELLICENT,
ALOMOMOLA,
JOLTIK,
GALVANTULA,
FERROSEED,
FERROTHORN,
KLINK,
KLANG,
KLINKLANG,
TYNAMO,
EELEKTRIK,
EELEKTROSS,
ELGYEM,
BEHEEYEM,
LITWICK,
LAMPENT,
CHANDELURE,
AXEW,
FRAXURE,
HAXORUS,
CUBCHOO,
BEARTIC,
CRYOGONAL,
SHELMET,
ACCELGOR,
STUNFISK,
MIENFOO,
MIENSHAO,
DRUDDIGON,
GOLETT,
GOLURK,
PAWNIARD,
BISHARP,
BOUFFALANT,
RUFFLET,
BRAVIARY,
VULLABY,
MANDIBUZZ,
HEATMOR,
DURANT,
DEINO,
ZWEILOUS,
HYDREIGON,
LARVESTA,
VOLCARONA,
COBALION,
TERRAKION,
VIRIZION,
TORNADUS,
THUNDURUS,
RESHIRAM,
ZEKROM,
LANDORUS,
KYUREM,
KELDEO,
MELOETTA,
GENESECT,
XERNEAS = 716,
YVELTAL
};
+137
View File
@@ -0,0 +1,137 @@
import * as Utils from "../utils";
export enum StatusEffect {
NONE,
POISON,
TOXIC,
PARALYSIS,
SLEEP,
FREEZE,
BURN,
FAINT
}
export class Status {
public effect: StatusEffect;
public turnCount: integer;
public cureTurn: integer;
constructor(effect: StatusEffect) {
this.effect = effect;
this.turnCount = 0;
if (effect === StatusEffect.SLEEP)
this.cureTurn = Utils.randInt(3, 1);
}
incrementTurn(): void {
this.turnCount++;
}
isPostTurn(): boolean {
return this.effect === StatusEffect.POISON || this.effect === StatusEffect.TOXIC || this.effect === StatusEffect.BURN;
}
}
export function getStatusEffectObtainText(statusEffect: StatusEffect): string {
switch (statusEffect) {
case StatusEffect.POISON:
return '\nwas poisoned!';
case StatusEffect.TOXIC:
return '\nwas badly poisoned!';
case StatusEffect.PARALYSIS:
return ' is paralyzed!\nIt may be unable to move!';
case StatusEffect.SLEEP:
return '\nfell asleep!';
case StatusEffect.FREEZE:
return '\nwas frozen solid!';
case StatusEffect.BURN:
return '\nwas burned!';
}
return '';
}
export function getStatusEffectActivationText(statusEffect: StatusEffect): string {
switch (statusEffect) {
case StatusEffect.POISON:
case StatusEffect.TOXIC:
return ' is hurt\nby poison!';
case StatusEffect.PARALYSIS:
return ' is paralyzed!\nIt can\'t move!';
case StatusEffect.SLEEP:
return ' is fast asleep.';
case StatusEffect.FREEZE:
return ' is\nfrozen solid!';
case StatusEffect.BURN:
return ' is hurt\nby its burn!';
}
return '';
}
export function getStatusEffectOverlapText(statusEffect: StatusEffect): string {
switch (statusEffect) {
case StatusEffect.POISON:
case StatusEffect.TOXIC:
return ' is\nalready poisoned!';
case StatusEffect.PARALYSIS:
return ' is\nalready paralyzed!';
case StatusEffect.SLEEP:
return ' is\nalready asleep!';
case StatusEffect.FREEZE:
return ' is\nalready frozen!';
case StatusEffect.BURN:
return ' is\nalready burned!';
}
return '';
}
export function getStatusEffectHealText(statusEffect: StatusEffect) {
switch (statusEffect) {
case StatusEffect.POISON:
case StatusEffect.TOXIC:
return ' was\ncured of its poison!';
case StatusEffect.PARALYSIS:
return ' was\nhealed of paralysis!';
case StatusEffect.SLEEP:
return ' woke up!';
case StatusEffect.FREEZE:
return ' was\ndefrosted!';
case StatusEffect.BURN:
return ' is hurt\nby its burn!';
}
return '';
}
export function getStatusEffectDescriptor(statusEffect: StatusEffect) {
switch (statusEffect) {
case StatusEffect.POISON:
case StatusEffect.TOXIC:
return 'poisoning';
case StatusEffect.PARALYSIS:
return 'paralysis';
case StatusEffect.SLEEP:
return 'sleep';
case StatusEffect.FREEZE:
return 'freezing';
case StatusEffect.BURN:
return 'burn';
}
}
export function getStatusEffectCatchRateMultiplier(statusEffect: StatusEffect) {
switch (statusEffect) {
case StatusEffect.POISON:
case StatusEffect.TOXIC:
case StatusEffect.PARALYSIS:
case StatusEffect.BURN:
return 1.5;
case StatusEffect.SLEEP:
case StatusEffect.FREEZE:
return 2.5;
}
return 1;
}
+36
View File
@@ -0,0 +1,36 @@
import { BattleStat, getBattleStatName } from "./battle-stat";
export enum TempBattleStat {
ATK,
DEF,
SPATK,
SPDEF,
SPD,
ACC,
CRIT
}
export function getTempBattleStatName(tempBattleStat: TempBattleStat) {
if (tempBattleStat === TempBattleStat.CRIT)
return 'critical-hit ratio';
return getBattleStatName(tempBattleStat as integer as BattleStat);
}
export function getTempBattleStatBoosterItemName(tempBattleStat: TempBattleStat) {
switch (tempBattleStat) {
case TempBattleStat.ATK:
return 'X Attack';
case TempBattleStat.DEF:
return 'X Defense';
case TempBattleStat.SPATK:
return 'X Sp. Atk';
case TempBattleStat.SPDEF:
return 'X Sp. Def';
case TempBattleStat.SPD:
return 'X Speed';
case TempBattleStat.ACC:
return 'X Accuracy';
case TempBattleStat.CRIT:
return 'Dire Hit';
}
}
+30930
View File
File diff suppressed because it is too large. Load diff
+492
View File
@@ -0,0 +1,492 @@
export enum Type {
NORMAL = 0,
FIGHTING,
FLYING,
POISON,
GROUND,
ROCK,
BUG,
GHOST,
STEEL,
FIRE,
WATER,
GRASS,
ELECTRIC,
PSYCHIC,
ICE,
DRAGON,
DARK,
FAIRY
};
export function getTypeDamageMultiplier(attackType: integer, defType: integer) {
switch (defType) {
case Type.NORMAL:
switch (attackType) {
case Type.FIGHTING:
return 2;
case Type.NORMAL:
case Type.FLYING:
case Type.POISON:
case Type.GROUND:
case Type.ROCK:
case Type.BUG:
case Type.STEEL:
case Type.FIRE:
case Type.WATER:
case Type.GRASS:
case Type.ELECTRIC:
case Type.PSYCHIC:
case Type.ICE:
case Type.DRAGON:
case Type.DARK:
case Type.FAIRY:
return 1;
case Type.GHOST:
default:
return 0;
}
case Type.FIGHTING:
switch (attackType) {
case Type.FLYING:
case Type.PSYCHIC:
case Type.FAIRY:
return 2;
case Type.NORMAL:
case Type.FIGHTING:
case Type.POISON:
case Type.GROUND:
case Type.GHOST:
case Type.STEEL:
case Type.FIRE:
case Type.WATER:
case Type.GRASS:
case Type.ELECTRIC:
case Type.ICE:
case Type.DRAGON:
case Type.DARK:
return 1;
case Type.ROCK:
case Type.BUG:
return 0.5;
default:
return 0;
}
case Type.FLYING:
switch (attackType) {
case Type.ROCK:
case Type.ELECTRIC:
case Type.ICE:
return 2;
case Type.NORMAL:
case Type.FLYING:
case Type.POISON:
case Type.GHOST:
case Type.STEEL:
case Type.FIRE:
case Type.WATER:
case Type.PSYCHIC:
case Type.DRAGON:
case Type.DARK:
case Type.FAIRY:
return 1;
case Type.FIGHTING:
case Type.BUG:
case Type.GRASS:
return 0.5;
case Type.GROUND:
default:
return 0;
}
case Type.POISON:
switch (attackType) {
case Type.GROUND:
case Type.PSYCHIC:
return 2;
case Type.NORMAL:
case Type.FLYING:
case Type.ROCK:
case Type.GHOST:
case Type.STEEL:
case Type.FIRE:
case Type.WATER:
case Type.ELECTRIC:
case Type.ICE:
case Type.DRAGON:
case Type.DARK:
return 1;
case Type.FIGHTING:
case Type.POISON:
case Type.BUG:
case Type.GRASS:
case Type.FAIRY:
return 0.5;
default:
return 0;
}
case Type.GROUND:
switch (attackType) {
case Type.WATER:
case Type.GRASS:
case Type.ICE:
return 2;
case Type.NORMAL:
case Type.FIGHTING:
case Type.FLYING:
case Type.GROUND:
case Type.BUG:
case Type.GHOST:
case Type.STEEL:
case Type.FIRE:
case Type.PSYCHIC:
case Type.DRAGON:
case Type.DARK:
case Type.FAIRY:
return 1;
case Type.POISON:
case Type.ROCK:
return 0.5;
case Type.ELECTRIC:
default:
return 0;
}
case Type.ROCK:
switch (attackType) {
case Type.FIGHTING:
case Type.GROUND:
case Type.STEEL:
case Type.WATER:
case Type.GRASS:
return 2;
case Type.ROCK:
case Type.BUG:
case Type.GHOST:
case Type.ELECTRIC:
case Type.PSYCHIC:
case Type.ICE:
case Type.DRAGON:
case Type.DARK:
case Type.FAIRY:
return 1;
case Type.NORMAL:
case Type.FLYING:
case Type.POISON:
case Type.FIRE:
return 0.5;
default:
return 0;
}
case Type.BUG:
switch (attackType) {
case Type.FLYING:
case Type.ROCK:
case Type.FIRE:
return 2;
case Type.NORMAL:
case Type.POISON:
case Type.BUG:
case Type.GHOST:
case Type.STEEL:
case Type.WATER:
case Type.ELECTRIC:
case Type.PSYCHIC:
case Type.ICE:
case Type.DRAGON:
case Type.DARK:
case Type.FAIRY:
return 1;
case Type.FIGHTING:
case Type.GROUND:
case Type.GRASS:
return 0.5;
default:
return 0;
}
case Type.GHOST:
switch (attackType) {
case Type.GHOST:
case Type.DARK:
return 2;
case Type.FLYING:
case Type.GROUND:
case Type.ROCK:
case Type.STEEL:
case Type.FIRE:
case Type.WATER:
case Type.GRASS:
case Type.ELECTRIC:
case Type.PSYCHIC:
case Type.ICE:
case Type.DRAGON:
case Type.FAIRY:
return 1;
case Type.POISON:
case Type.BUG:
return 0.5;
case Type.NORMAL:
case Type.FIGHTING:
default:
return 0;
}
case Type.STEEL:
switch (attackType) {
case Type.FIGHTING:
case Type.GROUND:
case Type.FIRE:
return 2;
case Type.GHOST:
case Type.WATER:
case Type.ELECTRIC:
case Type.DARK:
return 1;
case Type.NORMAL:
case Type.FLYING:
case Type.ROCK:
case Type.BUG:
case Type.STEEL:
case Type.GRASS:
case Type.PSYCHIC:
case Type.ICE:
case Type.DRAGON:
case Type.FAIRY:
return 0.5;
case Type.POISON:
default:
return 0;
}
case Type.FIRE:
switch (attackType) {
case Type.GROUND:
case Type.ROCK:
case Type.WATER:
return 2;
case Type.NORMAL:
case Type.FIGHTING:
case Type.FLYING:
case Type.POISON:
case Type.GHOST:
case Type.ELECTRIC:
case Type.PSYCHIC:
case Type.DRAGON:
case Type.DARK:
return 1;
case Type.BUG:
case Type.STEEL:
case Type.FIRE:
case Type.GRASS:
case Type.ICE:
case Type.FAIRY:
return 0.5;
default:
return 0;
}
case Type.WATER:
switch (attackType) {
case Type.GRASS:
case Type.ELECTRIC:
return 2;
case Type.NORMAL:
case Type.FIGHTING:
case Type.FLYING:
case Type.POISON:
case Type.GROUND:
case Type.ROCK:
case Type.BUG:
case Type.GHOST:
case Type.PSYCHIC:
case Type.DRAGON:
case Type.DARK:
case Type.FAIRY:
return 1;
case Type.STEEL:
case Type.FIRE:
case Type.WATER:
case Type.ICE:
return 0.5;
default:
return 0;
}
case Type.GRASS:
switch (attackType) {
case Type.FLYING:
case Type.POISON:
case Type.BUG:
case Type.FIRE:
case Type.ICE:
return 2;
case Type.NORMAL:
case Type.FIGHTING:
case Type.ROCK:
case Type.GHOST:
case Type.STEEL:
case Type.PSYCHIC:
case Type.DRAGON:
case Type.DARK:
case Type.FAIRY:
return 1;
case Type.GROUND:
case Type.WATER:
case Type.GRASS:
case Type.ELECTRIC:
return 0.5;
default:
return 0;
}
case Type.ELECTRIC:
switch (attackType) {
case Type.GROUND:
return 2;
case Type.NORMAL:
case Type.FIGHTING:
case Type.POISON:
case Type.ROCK:
case Type.BUG:
case Type.GHOST:
case Type.FIRE:
case Type.WATER:
case Type.GRASS:
case Type.PSYCHIC:
case Type.ICE:
case Type.DRAGON:
case Type.DARK:
case Type.FAIRY:
return 1;
case Type.FLYING:
case Type.STEEL:
case Type.ELECTRIC:
return 0.5;
default:
return 0;
}
case Type.PSYCHIC:
switch (attackType) {
case Type.BUG:
case Type.GHOST:
case Type.DARK:
return 2;
case Type.NORMAL:
case Type.FLYING:
case Type.POISON:
case Type.GROUND:
case Type.ROCK:
case Type.STEEL:
case Type.FIRE:
case Type.WATER:
case Type.GRASS:
case Type.ELECTRIC:
case Type.ICE:
case Type.DRAGON:
case Type.FAIRY:
return 1;
case Type.FIGHTING:
case Type.PSYCHIC:
return 0.5;
default:
return 0;
}
case Type.ICE:
switch (attackType) {
case Type.FIGHTING:
case Type.ROCK:
case Type.STEEL:
case Type.FIRE:
return 2;
case Type.NORMAL:
case Type.FLYING:
case Type.POISON:
case Type.GROUND:
case Type.BUG:
case Type.GHOST:
case Type.WATER:
case Type.GRASS:
case Type.ELECTRIC:
case Type.PSYCHIC:
case Type.DRAGON:
case Type.DARK:
case Type.FAIRY:
return 1;
case Type.ICE:
return 0.5;
default:
return 0;
}
case Type.DRAGON:
switch (attackType) {
case Type.ICE:
case Type.DRAGON:
case Type.FAIRY:
return 2;
case Type.NORMAL:
case Type.FIGHTING:
case Type.FLYING:
case Type.POISON:
case Type.GROUND:
case Type.ROCK:
case Type.BUG:
case Type.GHOST:
case Type.STEEL:
case Type.PSYCHIC:
case Type.DARK:
return 1;
case Type.FIRE:
case Type.WATER:
case Type.GRASS:
case Type.ELECTRIC:
return 0.5;
default:
return 0;
}
case Type.DARK:
switch (attackType) {
case Type.FIGHTING:
case Type.BUG:
case Type.FAIRY:
return 2;
case Type.NORMAL:
case Type.FLYING:
case Type.POISON:
case Type.GROUND:
case Type.ROCK:
case Type.STEEL:
case Type.FIRE:
case Type.WATER:
case Type.GRASS:
case Type.ELECTRIC:
case Type.ICE:
case Type.DRAGON:
return 1;
case Type.GHOST:
case Type.DARK:
return 0.5;
case Type.PSYCHIC:
default:
return 0;
}
case Type.FAIRY:
switch (attackType) {
case Type.POISON:
case Type.STEEL:
return 2;
case Type.NORMAL:
case Type.FLYING:
case Type.GROUND:
case Type.ROCK:
case Type.GHOST:
case Type.FIRE:
case Type.WATER:
case Type.GRASS:
case Type.ELECTRIC:
case Type.PSYCHIC:
case Type.ICE:
case Type.FAIRY:
return 1;
case Type.FIGHTING:
case Type.BUG:
case Type.DARK:
return 0.5;
case Type.DRAGON:
default:
return 0;
}
}
}
+317
View File
@@ -0,0 +1,317 @@
import { Biome } from "./biome";
import { getPokemonMessage } from "../messages";
import Pokemon from "../pokemon";
import { Type } from "./type";
import Move, { AttackMove } from "./move";
import * as Utils from "../utils";
export enum WeatherType {
NONE,
SUNNY,
RAIN,
SANDSTORM,
HAIL,
FOG,
HEAVY_RAIN,
HARSH_SUN,
STRONG_WINDS
}
export class Weather {
public weatherType: WeatherType;
public turnsLeft: integer;
constructor(weatherType: WeatherType, turnsLeft?: integer) {
this.weatherType = weatherType;
this.turnsLeft = turnsLeft || 0;
}
lapse(): boolean {
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: Type): boolean {
switch (this.weatherType) {
case WeatherType.SANDSTORM:
return type === Type.GROUND || type === Type.ROCK || type === Type.STEEL;
case WeatherType.HAIL:
return type === Type.ICE;
}
return false;
}
getAttackTypeMultiplier(attackType: Type): number {
switch (this.weatherType) {
case WeatherType.SUNNY:
case WeatherType.HARSH_SUN:
if (attackType === Type.FIRE)
return 1.5;
if (attackType === Type.WATER)
return 0.5;
break;
case WeatherType.RAIN:
case WeatherType.HEAVY_RAIN:
if (attackType === Type.FIRE)
return 0.5;
if (attackType === Type.WATER)
return 1.5;
break;
}
return 1;
}
isMoveWeatherCancelled(move: Move): boolean {
switch (this.weatherType) {
case WeatherType.HARSH_SUN:
return move instanceof AttackMove && move.type === Type.WATER;
case WeatherType.HEAVY_RAIN:
return move instanceof AttackMove && move.type === Type.FIRE;
}
return false;
}
}
export function getWeatherStartMessage(weatherType: WeatherType) {
switch (weatherType) {
case WeatherType.SUNNY:
return 'The sunlight got bright!';
case WeatherType.RAIN:
return 'A downpour started!';
case WeatherType.SANDSTORM:
return 'A sandstorm brewed!';
case WeatherType.HAIL:
return 'It started to hail!';
case WeatherType.FOG:
return 'A thick fog emerged!'
case WeatherType.HEAVY_RAIN:
return 'A heavy downpour started!'
case WeatherType.HARSH_SUN:
return 'The sunlight got hot!'
case WeatherType.STRONG_WINDS:
return 'A heavy wind began!';
}
return null;
}
export function getWeatherLapseMessage(weatherType: WeatherType) {
switch (weatherType) {
case WeatherType.SUNNY:
return 'The sunlight is strong.';
case WeatherType.RAIN:
return 'The downpour continues.';
case WeatherType.SANDSTORM:
return 'The sandstorm rages.';
case WeatherType.HAIL:
return 'Hail continues to fall.';
case WeatherType.FOG:
return 'The fog continues.';
case WeatherType.HEAVY_RAIN:
return 'The heavy downpour continues.'
case WeatherType.HARSH_SUN:
return 'The sun is scorching hot.'
case WeatherType.STRONG_WINDS:
return 'The wind blows intensely.';
}
return null;
}
export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokemon) {
switch (weatherType) {
case WeatherType.SANDSTORM:
return getPokemonMessage(pokemon, ' is buffeted\nby the sandstorm!');
case WeatherType.HAIL:
return getPokemonMessage(pokemon, ' is pelted\nby the hail!');
}
return null;
}
export function getWeatherClearMessage(weatherType: WeatherType) {
switch (weatherType) {
case WeatherType.SUNNY:
return 'The sunlight faded.';
case WeatherType.RAIN:
return 'The rain stopped.';
case WeatherType.SANDSTORM:
return 'The sandstorm subsided.';
case WeatherType.HAIL:
return 'The hail stopped.';
case WeatherType.FOG:
return 'The fog disappeared.'
case WeatherType.HEAVY_RAIN:
return 'The heavy rain stopped.'
case WeatherType.HARSH_SUN:
return 'The harsh sunlight faded.'
case WeatherType.STRONG_WINDS:
return 'The heavy wind stopped.';
}
return null;
}
interface WeatherPoolEntry {
weatherType: WeatherType;
weight: integer;
}
export function getRandomWeatherType(biome: Biome): WeatherType {
let weatherPool: WeatherPoolEntry[] = [];
switch (biome) {
case Biome.GRASS:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 7 },
{ weatherType: WeatherType.SUNNY, weight: 3 }
];
break;
case Biome.TALL_GRASS:
weatherPool = [
{ weatherType: WeatherType.SUNNY, weight: 8 },
{ weatherType: WeatherType.RAIN, weight: 5 },
{ weatherType: WeatherType.FOG, weight: 2 }
];
break;
case Biome.FOREST:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 8 },
{ weatherType: WeatherType.RAIN, weight: 5 },
{ weatherType: WeatherType.HEAVY_RAIN, weight: 2 }
];
break;
case Biome.SEA:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 3 },
{ weatherType: WeatherType.RAIN, weight: 7 },
{ weatherType: WeatherType.HEAVY_RAIN, weight: 5 }
];
break;
case Biome.SWAMP:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 2 },
{ weatherType: WeatherType.RAIN, weight: 5 },
{ weatherType: WeatherType.FOG, weight: 8 }
];
break;
case Biome.BEACH:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 5 },
{ weatherType: WeatherType.SUNNY, weight: 8 },
{ weatherType: WeatherType.RAIN, weight: 2 }
];
break;
case Biome.LAKE:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 10 },
{ weatherType: WeatherType.RAIN, weight: 5 },
{ weatherType: WeatherType.FOG, weight: 3 },
{ weatherType: WeatherType.HEAVY_RAIN, weight: 2 }
];
break;
case Biome.SEABED:
weatherPool = [
{ weatherType: WeatherType.HEAVY_RAIN, weight: 1 }
];
break;
case Biome.MOUNTAIN:
weatherPool = [
{ weatherType: WeatherType.STRONG_WINDS, weight: 1 }
];
break;
case Biome.LAND:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 8 },
{ weatherType: WeatherType.SUNNY, weight: 3 },
{ weatherType: WeatherType.SANDSTORM, weight: 2 },
{ weatherType: WeatherType.HARSH_SUN, weight: 5 }
];
break;
case Biome.DESERT:
weatherPool = [
{ weatherType: WeatherType.SANDSTORM, weight: 1 },
{ weatherType: WeatherType.HARSH_SUN, weight: 1 }
];
break;
case Biome.ICE_CAVE:
weatherPool = [
{ weatherType: WeatherType.HAIL, weight: 1 }
];
break;
case Biome.MEADOW:
weatherPool = [
{ weatherType: WeatherType.SUNNY, weight: 1 }
];
case Biome.VOLCANO:
weatherPool = [
{ weatherType: WeatherType.HARSH_SUN, weight: 1 }
];
break;
case Biome.GRAVEYARD:
weatherPool = [
{ weatherType: WeatherType.FOG, weight: 1 }
];
break;
case Biome.RUINS:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 4 },
{ weatherType: WeatherType.FOG, weight: 1 }
];
break;
case Biome.WASTELAND:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 4 },
{ weatherType: WeatherType.FOG, weight: 1 }
];
break;
case Biome.ABYSS:
weatherPool = [
{ weatherType: WeatherType.NONE, weight: 4 },
{ weatherType: WeatherType.FOG, weight: 1 }
];
break;
}
if (weatherPool.length > 1) {
let totalWeight = 0;
weatherPool.forEach(w => totalWeight += w.weight);
const rand = Utils.randInt(totalWeight);
let w = 0;
for (let weather of weatherPool) {
w += weather.weight;
if (rand < w)
return weather.weatherType;
}
}
return weatherPool.length
? weatherPool[0].weatherType
: WeatherType.NONE;
}