UNPKG

enka-network-api

Version:

Enka-network API wrapper for Genshin Impact.

172 lines (171 loc) 11.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.CharacterData = void 0; const ImageAssets_1 = require("../assets/ImageAssets"); const TextAssets_1 = require("../assets/TextAssets"); const Skill_1 = require("./talents/Skill"); const AssetsNotFoundError_1 = require("../../errors/AssetsNotFoundError"); const Constellation_1 = require("./Constellation"); const ElementalBurst_1 = require("./talents/ElementalBurst"); const Costume_1 = require("./Costume"); const PassiveTalent_1 = require("./talents/PassiveTalent"); const ElementalSkill_1 = require("./talents/ElementalSkill"); const NormalAttack_1 = require("./talents/NormalAttack"); const Material_1 = require("../material/Material"); const CharacterDetails_1 = require("./CharacterDetails"); const CharacterAscension_1 = require("./CharacterAscension"); const config_file_js_1 = require("config_file.js"); const StatProperty_1 = require("../StatProperty"); const ts_utils_1 = require("../../utils/ts_utils"); const ExcelTransformer_1 = require("../../client/ExcelTransformer"); class CharacterData { constructor(data, enka, candSkillDepotId) { var _a, _b, _c; /** This will be null if the character is Traveler */ this.nameCard = null; /** Information in the profile menu in in-game character screen */ this.details = null; this._data = data; this.enka = enka; const json = new config_file_js_1.JsonReader(ExcelTransformer_1.excelJsonOptions, this._data); this.id = json.getAsNumber("id"); this.name = new TextAssets_1.TextAssets(json.getAsNumber("nameTextMapHash"), enka); this.description = new TextAssets_1.TextAssets(json.getAsNumber("descTextMapHash"), enka); this.bodyType = json.getAsString("bodyType"); this.weaponType = json.getAsString("weaponType"); this.gender = this.bodyType === "BODY_MALE" || this.bodyType === "BODY_BOY" ? "MALE" : "FEMALE"; this._nameId = json.getAsString("iconName").slice("UI_AvatarIcon_".length); this.icon = new ImageAssets_1.ImageAssets(json.getAsString("iconName"), enka); this.sideIcon = new ImageAssets_1.ImageAssets(json.getAsString("sideIconName"), enka); this.splashImage = new ImageAssets_1.ImageAssets(`UI_Gacha_AvatarImg_${this._nameId}`, enka); this.gachaSlice = new ImageAssets_1.ImageAssets(`UI_Gacha_AvatarIcon_${this._nameId}`, enka); this.cardIcon = new ImageAssets_1.ImageAssets(`UI_AvatarIcon_${this._nameId}_Card`, enka); const releaseData = enka.cachedAssetsManager.getExcelData("AvatarCodexExcelConfigData", this.id); this._releaseData = releaseData !== null && releaseData !== void 0 ? releaseData : null; this.releasedAt = releaseData ? new Date(`${new config_file_js_1.JsonReader(ExcelTransformer_1.excelJsonOptions, releaseData).getAsString("beginTime")}+8:00`) : null; const archonsIds = Object.keys(enka.cachedAssetsManager.getExcelData("TrialAvatarFetterDataConfigData")); this.isArchon = archonsIds.includes(this.id.toString()); // should always 10000005 and 10000007 const travelerIds = Object.keys(enka.cachedAssetsManager.getExcelData("AvatarHeroEntityExcelConfigData")); this.isTraveler = travelerIds.includes(this.id.toString()); try { this.details = CharacterDetails_1.CharacterDetails.getByCharacterId(this.id, this.isArchon, this.enka); } catch (_d) { // do nothing } const fetterCardData = enka.cachedAssetsManager.getExcelData("FetterCharacterCardExcelConfigData", this.id); if (fetterCardData) { const friendshipRewardId = new config_file_js_1.JsonReader(ExcelTransformer_1.excelJsonOptions, fetterCardData).getAsNumber("rewardId"); const reward = enka.cachedAssetsManager.getExcelData("RewardExcelConfigData", friendshipRewardId); if (!reward) throw new AssetsNotFoundError_1.AssetsNotFoundError("Reward", friendshipRewardId); const nameCardId = new config_file_js_1.JsonReader(ExcelTransformer_1.excelJsonOptions, reward).getAsNumber("rewardItemList", 0, "itemId"); this.nameCard = Material_1.Material.getMaterialById(nameCardId, enka); } this.rarity = json.getAsString("qualityType"); this.stars = this.rarity.startsWith("QUALITY_ORANGE") ? 5 : 4; const costumeData = enka.cachedAssetsManager.getExcelData("AvatarCostumeExcelConfigData", this.id); if (!costumeData) throw new AssetsNotFoundError_1.AssetsNotFoundError("Costumes by character id", this.id); this.costumes = Object.values(costumeData) .map(c => new Costume_1.Costume(c, enka)); this.skillDepotId = candSkillDepotId !== null && candSkillDepotId !== void 0 ? candSkillDepotId : json.getAsNumber("skillDepotId"); const skillData = enka.cachedAssetsManager.getExcelData("AvatarSkillDepotExcelConfigData", this.skillDepotId); if (!skillData) throw new AssetsNotFoundError_1.AssetsNotFoundError("Skill Depot", this.skillDepotId); this._skillData = skillData; const skillDataJson = new config_file_js_1.JsonReader(ExcelTransformer_1.excelJsonOptions, skillData); this.arkhe = skillDataJson.getAsStringWithDefault(null, enka.cachedAssetsManager.getObjectKeysManager().characterArkheKey); // if the character is "Traveler" and no skillDepotId (which indicates its element type) provided, // `elementalBurst`, `elementalSkill`, and `element` cannot be retrieved. const energySkillId = skillDataJson.getAsNumberWithDefault(0, "energySkill"); const hasElement = energySkillId !== 0; this.elementalBurst = hasElement ? ElementalBurst_1.ElementalBurst.getById(energySkillId, enka) : null; this.element = (_b = (_a = this.elementalBurst) === null || _a === void 0 ? void 0 : _a.costElemType) !== null && _b !== void 0 ? _b : null; const _skills = skillDataJson.get("skills").mapArray((_, p) => p.getAsNumber()).map((skillId, index) => { if (!skillId) return null; if (index === 0) return NormalAttack_1.NormalAttack.getById(skillId, enka); if (index === 1) return ElementalSkill_1.ElementalSkill.getById(skillId, enka); return Skill_1.Skill.getById(skillId, enka); }).filter(ts_utils_1.nonNullable); if (this.elementalBurst) _skills.push(this.elementalBurst); this.skills = _skills; this.elementalSkill = (_c = _skills.find(s => s instanceof ElementalSkill_1.ElementalSkill)) !== null && _c !== void 0 ? _c : null; this.normalAttack = _skills.find(s => s instanceof NormalAttack_1.NormalAttack); this.passiveTalents = skillDataJson.get("inherentProudSkillOpens").filterArray((_, p) => p.has("proudSkillGroupId")).map(([, p]) => { const proudSkillGroupId = p.getAsNumber("proudSkillGroupId"); if (proudSkillGroupId === 0) return null; return PassiveTalent_1.PassiveTalent.getById(proudSkillGroupId * 100 + 1, enka); }).filter(ts_utils_1.nonNullable); this.constellations = skillDataJson.get("talents").mapArray((_, p) => p.getAsNumber()).filter(cId => cId !== 0).map(cId => Constellation_1.Constellation.getById(cId, enka)); } /** * @returns character's original name (Travelers -> Aether, Lumine) */ getOriginalName() { switch (this.id) { case 10000005: return new TextAssets_1.TextAssets(2329553598, this.enka); case 10000007: return new TextAssets_1.TextAssets(3241049361, this.enka); default: return this.name; } } /** * @param ascension ascension level between 0 and 6 */ getAscensionData(ascension) { return CharacterAscension_1.CharacterAscension.getById(new config_file_js_1.JsonReader(ExcelTransformer_1.excelJsonOptions, this._data).getAsNumber("avatarPromoteId"), ascension, this.enka); } /** * @param ascension ascension level between 0 and 6 * @param level character level between 1 and 90 */ getStats(ascension, level) { if (ascension < 0 || 6 < ascension) throw new Error("Ascension levels must be between 0 and 6."); if (level < 1 || 90 < level) throw new Error("Character levels must be between 1 and 90."); const curveData = this.enka.cachedAssetsManager.getExcelData("AvatarCurveExcelConfigData", level); if (!curveData) throw new AssetsNotFoundError_1.AssetsNotFoundError("Character curve data", level); const curve = new config_file_js_1.JsonReader(ExcelTransformer_1.excelJsonOptions, curveData).get("curveInfos"); const ascensionData = this.getAscensionData(ascension); const characterJson = new config_file_js_1.JsonReader(ExcelTransformer_1.excelJsonOptions, this._data); const baseValues = { "FIGHT_PROP_BASE_HP": characterJson.getAsNumber("hpBase"), "FIGHT_PROP_BASE_ATTACK": characterJson.getAsNumber("attackBase"), "FIGHT_PROP_BASE_DEFENSE": characterJson.getAsNumber("defenseBase"), "FIGHT_PROP_CRITICAL": characterJson.getAsNumber("critical"), "FIGHT_PROP_CRITICAL_HURT": characterJson.getAsNumber("criticalHurt"), }; const curves = characterJson.get("propGrowCurves"); const statPropertiesWithBaseValues = Object.entries(baseValues).map(([fightProp, baseValue]) => { var _a, _b, _c, _d; const curveJson = (_a = curves.findArray((_, c) => c.getAsString("type") === fightProp)) === null || _a === void 0 ? void 0 : _a[1]; const curveType = curveJson === null || curveJson === void 0 ? void 0 : curveJson.getAsString("growCurve"); const targetCurve = curveType ? (_b = curve.findArray((_, c) => c.getAsString("type") === curveType)) === null || _b === void 0 ? void 0 : _b[1] : null; const ascensionValue = (_d = (_c = ascensionData.addProps.find(p => p.fightProp === fightProp)) === null || _c === void 0 ? void 0 : _c.value) !== null && _d !== void 0 ? _d : 0; const value = baseValue * (targetCurve ? targetCurve.getAsNumber("value") : 1) + ascensionValue; return new StatProperty_1.StatProperty(fightProp, value, this.enka); }); const statPropertiesWithoutBaseValues = ascensionData.addProps.filter(p => !baseValues[p.fightProp]); const levelingProps = [...statPropertiesWithBaseValues, ...statPropertiesWithoutBaseValues]; const talents = this.passiveTalents.filter(t => t.requiredAscension <= ascension && t.addProps.length > 0); return StatProperty_1.StatProperty.sumStatProperties([...levelingProps, ...talents.flatMap(t => t.addProps)], this.enka); } static getById(id, enka, candSkillDepotId) { const data = enka.cachedAssetsManager.getExcelData("AvatarExcelConfigData", id); if (!data) throw new AssetsNotFoundError_1.AssetsNotFoundError("Character", id); // Characters return new CharacterData(data, enka, candSkillDepotId); } } exports.CharacterData = CharacterData;