"use strict"; class PageFilterFeats extends PageFilter { // region static static _PREREQ_KEY_TO_FULL = { "other": "Special", "spellcasting2020": "Spellcasting", "spellcastingFeature": "Spellcasting", "spellcastingPrepared": "Spellcasting", }; // endregion constructor () { super(); this._asiFilter = new Filter({ header: "Ability Bonus", items: [ "str", "dex", "con", "int", "wis", "cha", ], displayFn: Parser.attAbvToFull, itemSortFn: null, }); this._categoryFilter = new Filter({ header: "Category", displayFn: StrUtil.toTitleCase, }); this._otherPrereqFilter = new Filter({ header: "Other", items: ["Ability", "Race", "Psionics", "Proficiency", "Special", "Spellcasting"], }); this._levelFilter = new Filter({ header: "Level", itemSortFn: SortUtil.ascSortNumericalSuffix, }); this._prerequisiteFilter = new MultiFilter({header: "Prerequisite", filters: [this._otherPrereqFilter, this._levelFilter]}); this._benefitsFilter = new Filter({ header: "Benefits", items: [ "Armor Proficiency", "Language Proficiency", "Skill Proficiency", "Spellcasting", "Tool Proficiency", "Weapon Proficiency", ], }); this._vulnerableFilter = FilterCommon.getDamageVulnerableFilter(); this._resistFilter = FilterCommon.getDamageResistFilter(); this._immuneFilter = FilterCommon.getDamageImmuneFilter(); this._defenceFilter = new MultiFilter({header: "Damage", filters: [this._vulnerableFilter, this._resistFilter, this._immuneFilter]}); this._conditionImmuneFilter = FilterCommon.getConditionImmuneFilter(); this._miscFilter = new Filter({header: "Miscellaneous", items: ["Has Info", "Has Images", "SRD", "Basic Rules", "Legacy"], isMiscFilter: true}); } static mutateForFilters (feat) { const ability = Renderer.getAbilityData(feat.ability); feat._fAbility = ability.asCollection.filter(a => !ability.areNegative.includes(a)); // used for filtering const prereqText = Renderer.utils.prerequisite.getHtml(feat.prerequisite, {isListMode: true}) || VeCt.STR_NONE; feat._fPrereqOther = [...new Set((feat.prerequisite || []).flatMap(it => Object.keys(it)))] .map(it => (this._PREREQ_KEY_TO_FULL[it] || it).uppercaseFirst()); if (feat.prerequisite) feat._fPrereqLevel = feat.prerequisite.filter(it => it.level != null).map(it => `Level ${it.level.level ?? it.level}`); feat._fBenifits = [ feat.resist ? "Damage Resistance" : null, feat.immune ? "Damage Immunity" : null, feat.conditionImmune ? "Condition Immunity" : null, feat.skillProficiencies ? "Skill Proficiency" : null, feat.additionalSpells ? "Spellcasting" : null, feat.armorProficiencies ? "Armor Proficiency" : null, feat.weaponProficiencies ? "Weapon Proficiency" : null, feat.toolProficiencies ? "Tool Proficiency" : null, feat.languageProficiencies ? "Language Proficiency" : null, ].filter(it => it); if (feat.skillToolLanguageProficiencies?.length) { if (feat.skillToolLanguageProficiencies.some(it => (it.choose || []).some(x => x.from || [].includes("anySkill")))) feat._fBenifits.push("Skill Proficiency"); if (feat.skillToolLanguageProficiencies.some(it => (it.choose || []).some(x => x.from || [].includes("anyTool")))) feat._fBenifits.push("Tool Proficiency"); if (feat.skillToolLanguageProficiencies.some(it => (it.choose || []).some(x => x.from || [].includes("anyLanguage")))) feat._fBenifits.push("Language Proficiency"); } feat._fMisc = feat.srd ? ["SRD"] : []; if (feat.basicRules) feat._fMisc.push("Basic Rules"); if (SourceUtil.isLegacySourceWotc(feat.source)) feat._fMisc.push("Legacy"); if (feat.hasFluff || feat.fluff?.entries) feat._fMisc.push("Has Info"); if (feat.hasFluffImages || feat.fluff?.images) feat._fMisc.push("Has Images"); if (feat.repeatable != null) feat._fMisc.push(feat.repeatable ? "Repeatable" : "Not Repeatable"); feat._slAbility = ability.asText || VeCt.STR_NONE; feat._slPrereq = prereqText; FilterCommon.mutateForFilters_damageVulnResImmune_player(feat); FilterCommon.mutateForFilters_conditionImmune_player(feat); } addToFilters (feat, isExcluded) { if (isExcluded) return; this._sourceFilter.addItem(feat.source); this._categoryFilter.addItem(feat.category); if (feat.prerequisite) this._levelFilter.addItem(feat._fPrereqLevel); this._vulnerableFilter.addItem(feat._fVuln); this._resistFilter.addItem(feat._fRes); this._immuneFilter.addItem(feat._fImm); this._conditionImmuneFilter.addItem(feat._fCondImm); this._benefitsFilter.addItem(feat._fBenifits); this._miscFilter.addItem(feat._fMisc); } async _pPopulateBoxOptions (opts) { opts.filters = [ this._sourceFilter, this._asiFilter, this._categoryFilter, this._prerequisiteFilter, this._benefitsFilter, this._defenceFilter, this._conditionImmuneFilter, this._miscFilter, ]; } toDisplay (values, ft) { return this._filterBox.toDisplay( values, ft.source, ft._fAbility, ft.category, [ ft._fPrereqOther, ft._fPrereqLevel, ], ft._fBenifits, [ ft._fVuln, ft._fRes, ft._fImm, ], ft._fCondImm, ft._fMisc, ); } } globalThis.PageFilterFeats = PageFilterFeats; class ModalFilterFeats extends ModalFilter { /** * @param opts * @param opts.namespace * @param [opts.isRadio] * @param [opts.allData] */ constructor (opts) { opts = opts || {}; super({ ...opts, modalTitle: `Feat${opts.isRadio ? "" : "s"}`, pageFilter: new PageFilterFeats(), }); } _$getColumnHeaders () { const btnMeta = [ {sort: "name", text: "Name", width: "4"}, {sort: "ability", text: "Ability", width: "3"}, {sort: "prerequisite", text: "Prerequisite", width: "3"}, {sort: "source", text: "Source", width: "1"}, ]; return ModalFilter._$getFilterColumnHeaders(btnMeta); } async _pLoadAllData () { return [ ...(await DataUtil.loadJSON(`${Renderer.get().baseUrl}data/feats.json`)).feat, ...((await PrereleaseUtil.pGetBrewProcessed()).feat || []), ...((await BrewUtil2.pGetBrewProcessed()).feat || []), ]; } _getListItem (pageFilter, feat, ftI) { const eleRow = document.createElement("div"); eleRow.className = "px-0 w-100 ve-flex-col no-shrink"; const hash = UrlUtil.URL_TO_HASH_BUILDER[UrlUtil.PG_FEATS](feat); const source = Parser.sourceJsonToAbv(feat.source); eleRow.innerHTML = `