pokemonbase.js

/**
 * @module
 */
import constants from './constants.js';
import { LevelTrigger, StatStages } from './models.js';
const random_iv = () => Math.floor(Math.random() * 32);
const random_nature = () => constants.NATURES[Math.floor(Math.random() * constants.NATURES.length)];
// Function to calculate stats
function calcStat(pokemon, stat) {
    const ivstat = `iv_${stat}`;
    const base = pokemon.species.base_stats[stat];
    const iv = pokemon[ivstat];
    return Math.floor((((2 * base + iv + 5) * pokemon.level) / 100 + 5) *
        constants.NATURE_MULTIPLIERS[pokemon.nature][stat]);
}
/**
 * Represents a base Pokemon instance.
 *
 * @class PokemonBase
 * @property {number} id - Unique identifier for the Pokemon.
 * @property {string|number} owner_id - ID of the Pokemon's owner.
 * @property {number} idx - Index of the Pokemon within the owner's collection.
 * @property {number} [timestamp] - Timestamp of when the Pokemon was created or obtained.
 * @property {number} species_id - ID of the Pokemon species.
 * @property {number} level - Current level of the Pokemon.
 * @property {number} xp - Current experience points of the Pokemon.
 * @property {string} nature - Nature of the Pokemon, which affects stat growth.
 * @property {boolean} shiny - Whether the Pokemon is shiny.
 * @property {number} iv_hp - Individual Value (IV) for HP.
 * @property {number} iv_atk - Individual Value (IV) for Attack.
 * @property {number} iv_defn - Individual Value (IV) for Defense.
 * @property {number} iv_satk - Individual Value (IV) for Special Attack.
 * @property {number} iv_sdef - Individual Value (IV) for Special Defense.
 * @property {number} iv_spd - Individual Value (IV) for Speed.
 * @property {number} iv_total - Sum of all IVs.
 * @property {string|undefined} nickname - Nickname of the Pokemon, or undefined if none.
 * @property {string|false} favorite - Favorite status of the Pokemon.
 * @property {number|string|undefined} held_item - ID or name of the held item, or undefined if none.
 * @property {PokemonMove[]} moves - List of moves the Pokemon knows.
 * @property {boolean|false} has_color - Whether the Pokemon has a custom color.
 * @property {number|undefined} color - Custom color of the Pokemon, or undefined if none.
 * @property {number|null} _hp - Current HP of the Pokemon.
 * @property {string[]} ailments - List of ailments affecting the Pokemon.
 * @property {StatStages} stages - Stat stage modifications affecting the Pokemon.
 */
class PokemonBase {
    id;
    idx;
    species_id;
    level;
    xp;
    nature;
    shiny;
    iv_hp;
    iv_atk;
    iv_defn;
    iv_satk;
    iv_sdef;
    iv_spd;
    iv_total;
    nickname;
    favorite;
    held_item;
    moves;
    has_color;
    color;
    _hp;
    ailments;
    stages;
    instance;
    constructor(data, instance) {
        this.id = data.id;
        this.idx = 1;
        this.species_id = data.id;
        this.level = 0;
        this.xp = 0;
        this.nature = random_nature();
        this.shiny = Math.floor(Math.random() * 4096) == 1 ? true : false;
        this.iv_hp = random_iv();
        this.iv_atk = random_iv();
        this.iv_defn = random_iv();
        this.iv_satk = random_iv();
        this.iv_sdef = random_iv();
        this.iv_spd = random_iv();
        this.iv_total = this.iv_hp + this.iv_defn + this.iv_satk + this.iv_atk + this.iv_sdef + this.iv_spd;
        // Customization
        this.nickname = null;
        this.favorite = false;
        this.held_item = null;
        this.moves = data.moves || [];
        this.has_color = false;
        this.color = null;
        this._hp = null;
        this.ailments = [];
        this.stages = new StatStages();
        this.instance = [instance];
    }
    format(spec) {
        let name = this.shiny ? '✨ ' : '';
        name += this.species.toString();
        return name;
    }
    toString() {
        return this.format('');
    }
    toJSON() {
        const copy = { ...this };
        delete copy.instance;
        return copy;
    }
    get max_xp() {
        return 500 + 30 * this.level;
    }
    get max_hp() {
        if (this.species_id === 292) {
            return 1;
        }
        return Math.floor(((2 * this.species.base_stats.hp + this.iv_hp + 5) * this.level) / 100 +
            this.level +
            10);
    }
    get hp() {
        return this._hp === null ? this.max_hp : this._hp;
    }
    set hp(value) {
        this._hp = value;
    }
    get species() {
        return this.instance[0].findSpeciesByNumber(this.species_id);
    }
    get atk() {
        return calcStat(this, 'atk');
    }
    get defn() {
        return calcStat(this, 'defn');
    }
    get satk() {
        return calcStat(this, 'satk');
    }
    get sdef() {
        return calcStat(this, 'sdef');
    }
    get spd() {
        return calcStat(this, 'spd');
    }
    get ivPercentage() {
        return ((this.iv_hp +
            this.iv_atk +
            this.iv_defn +
            this.iv_satk +
            this.iv_sdef +
            this.iv_spd) /
            (6 * 31));
    }
    getNextEvolution() {
        if (!this.species.evolution_to || this.held_item === 13001) {
            return null;
        }
        const possible = [];
        for (const evo of this.species.evolution_to.items) {
            if (!(evo.trigger instanceof LevelTrigger)) {
                continue;
            }
            let can = true;
            if (evo.trigger.level && this.level < evo.trigger.level) {
                can = false;
            }
            if (evo.trigger.item && this.held_item !== evo.trigger.item_id) {
                can = false;
            }
            //TODO
            /*if (evo.trigger.move_id) {
                can = false;
            }*/
            if (evo.trigger.relative_stats === 1 && this.atk <= this.defn) {
                can = false;
            }
            if (evo.trigger.relative_stats === -1 && this.defn <= this.atk) {
                can = false;
            }
            if (evo.trigger.relative_stats === 0 && this.atk !== this.defn) {
                can = false;
            }
            if (can) {
                possible.push(evo.target);
            }
        }
        if (possible.length === 0) {
            return null;
        }
        return possible[Math.floor(Math.random() * possible.length)];
    }
    canEvolve() {
        return this.getNextEvolution() !== null;
    }
}
export { PokemonBase, calcStat };