mirror of
https://github.com/Kornstalx/5etools-mirror-2.github.io.git
synced 2025-10-28 20:45:35 -05:00
324 lines
8.2 KiB
JavaScript
324 lines
8.2 KiB
JavaScript
"use strict";
|
|
|
|
class UtilGenTables {
|
|
static _getTableSectionIndex (sectionOrders, chapterName, sectionName) {
|
|
((sectionOrders[chapterName] =
|
|
sectionOrders[chapterName] || {})[sectionName] =
|
|
sectionOrders[chapterName][sectionName] || 1);
|
|
const val = sectionOrders[chapterName][sectionName];
|
|
sectionOrders[chapterName][sectionName]++;
|
|
return val;
|
|
}
|
|
|
|
/**
|
|
* @param opts
|
|
* @param opts.sectionOrders
|
|
* @param opts.path
|
|
* @param opts.tmpMeta
|
|
* @param opts.section
|
|
* @param opts.data
|
|
* @param opts.stacks
|
|
* @param opts.isRequireIncludes
|
|
*/
|
|
static _doSearch (opts) {
|
|
const {sectionOrders, path, tmpMeta, section, data, stacks, isRequireIncludes} = opts;
|
|
|
|
if (data.data && data.data.tableIgnore) return;
|
|
|
|
if (data.entries) {
|
|
const nxtSection = data.name || section;
|
|
if (data.name || data.page) {
|
|
const {name, page} = data;
|
|
path.push({name, page});
|
|
}
|
|
data.entries.forEach(ent => this._doSearch({...opts, section: nxtSection, data: ent}));
|
|
if (data.name || data.page) path.pop();
|
|
} else if (data.items) {
|
|
if (data.name || data.page) {
|
|
const {name, page} = data;
|
|
path.push({name, page});
|
|
}
|
|
data.items.forEach(item => this._doSearch({...opts, data: item}));
|
|
if (data.name || data.page) path.pop();
|
|
} else if (data.type === "table" || data.type === "tableGroup") {
|
|
if (isRequireIncludes && !(data.data && data.data[VeCt.ENTDATA_TABLE_INCLUDE])) return;
|
|
|
|
const cpy = MiscUtil.copy(data);
|
|
|
|
cpy._tmpMeta = MiscUtil.copy(tmpMeta);
|
|
cpy.path = MiscUtil.copy(path);
|
|
cpy.section = section;
|
|
cpy.sectionIndex = this._getTableSectionIndex(sectionOrders, tmpMeta.name, section);
|
|
|
|
stacks[data.type].push(cpy);
|
|
}
|
|
}
|
|
|
|
static _getCleanSectionName (name) {
|
|
return name.replace(/^(?:Step )?[-\d]+[:.]?\s*/, "");
|
|
}
|
|
|
|
static _isSectionInTitle (sections, title) {
|
|
const lowTitle = title.toLowerCase();
|
|
return sections.some(section => lowTitle.includes(section.toLowerCase()));
|
|
}
|
|
|
|
static _mutDataAddPage (table) {
|
|
for (let i = table.path.length - 1; i >= 0; --i) {
|
|
if (table.path[i].page) {
|
|
table.page = table.path[i].page;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static _mutCleanData (table) {
|
|
delete table.path;
|
|
delete table.section;
|
|
delete table.sectionIndex;
|
|
|
|
if (table._tmpMeta.metaType === "adventure-book") {
|
|
table.chapter = table._tmpMeta;
|
|
delete table._tmpMeta;
|
|
|
|
// clean chapter
|
|
if (table.data && table.data.tableChapterIgnore) {
|
|
delete table.chapter;
|
|
} else {
|
|
const chapterOut = {};
|
|
chapterOut.name = table.chapter.name;
|
|
chapterOut.ordinal = table.chapter.ordinal;
|
|
chapterOut.index = table.chapter.index;
|
|
table.chapter = chapterOut;
|
|
}
|
|
} else if (table._tmpMeta.metaType === "class") {
|
|
table.parentEntity = {
|
|
type: table._tmpMeta.metaType,
|
|
name: table._tmpMeta.className,
|
|
source: table._tmpMeta.classSource,
|
|
};
|
|
delete table._tmpMeta;
|
|
} else if (table._tmpMeta.metaType === "subclass") {
|
|
table.parentEntity = {
|
|
type: table._tmpMeta.metaType,
|
|
name: table._tmpMeta.subclassName,
|
|
shortName: table._tmpMeta.subclassShortName,
|
|
source: table._tmpMeta.subclassSource,
|
|
className: table._tmpMeta.className,
|
|
classSource: table._tmpMeta.classSource,
|
|
};
|
|
delete table._tmpMeta;
|
|
} else {
|
|
table.parentEntity = {
|
|
type: table._tmpMeta.metaType,
|
|
name: table._tmpMeta.name,
|
|
source: table._tmpMeta.source,
|
|
};
|
|
delete table._tmpMeta;
|
|
}
|
|
|
|
if (table.type === "table") delete table.type;
|
|
delete table.data;
|
|
|
|
if (table.name) table.name = Renderer.stripTags(table.name);
|
|
}
|
|
|
|
/**
|
|
* @param doc
|
|
* @param opts
|
|
* @param opts.headProp
|
|
* @param opts.bodyProp
|
|
* @param [opts.isRequireIncludes]
|
|
*/
|
|
static getAdventureBookTables (doc, opts) {
|
|
const sectionOrders = {};
|
|
const stacks = {table: [], tableGroup: []};
|
|
|
|
if (!(doc[opts.headProp] && doc[opts.bodyProp])) return;
|
|
|
|
doc[opts.bodyProp].data.forEach((chapter, ixChapter) => {
|
|
const tmpMeta = MiscUtil.copy(doc[opts.headProp].contents[ixChapter]);
|
|
tmpMeta.index = ixChapter;
|
|
tmpMeta.metaType = "adventure-book";
|
|
|
|
const path = [];
|
|
this._doSearch({
|
|
sectionOrders,
|
|
path,
|
|
tmpMeta: tmpMeta,
|
|
section: doc[opts.headProp].name,
|
|
data: chapter,
|
|
stacks: stacks,
|
|
isRequireIncludes: opts.isRequireIncludes,
|
|
});
|
|
});
|
|
|
|
stacks.table.forEach(tbl => {
|
|
const cleanSectionNames = tbl.path.filter(ent => ent.name).map(ent => this._getCleanSectionName(ent.name));
|
|
|
|
if (tbl.data && tbl.data.tableNamePrefix && tbl.caption) {
|
|
tbl.name = `${tbl.data.tableNamePrefix}; ${tbl.caption}`;
|
|
} else if (tbl.data && tbl.data.tableName) {
|
|
tbl.name = tbl.data.tableName;
|
|
} else if (tbl.caption) {
|
|
if (this._isSectionInTitle(cleanSectionNames, tbl.caption) || (tbl.data && tbl.data.skipSectionPrefix)) {
|
|
tbl.name = tbl.caption;
|
|
} else {
|
|
tbl.name = cleanSectionNames.length ? `${cleanSectionNames.last()}; ${tbl.caption}` : tbl.caption;
|
|
}
|
|
} else {
|
|
// If this is the only table in this section, remove the numerical suffix
|
|
if (tbl.sectionIndex === 1 && sectionOrders[tbl._tmpMeta.name][tbl.section] === 2) {
|
|
tbl.name = cleanSectionNames.last();
|
|
} else {
|
|
tbl.name = `${cleanSectionNames.last()}; ${tbl.sectionIndex}`;
|
|
}
|
|
}
|
|
|
|
this._mutDataAddPage(tbl);
|
|
tbl.source = doc[opts.headProp].source || doc[opts.headProp].id;
|
|
this._mutCleanData(tbl);
|
|
});
|
|
|
|
stacks.tableGroup.forEach(tg => {
|
|
const cleanSections = tg.path.filter(ent => ent.name).map(ent => this._getCleanSectionName(ent.name));
|
|
if (!tg.name) throw new Error("Group had no name!");
|
|
|
|
if (!this._isSectionInTitle(cleanSections, tg.name)) {
|
|
tg.name = `${cleanSections.last()}; ${tg.name}`;
|
|
}
|
|
|
|
this._mutDataAddPage(tg);
|
|
tg.source = doc[opts.headProp].source || doc[opts.headProp].id;
|
|
this._mutCleanData(tg);
|
|
});
|
|
|
|
return stacks;
|
|
}
|
|
|
|
static getClassTables (cls) {
|
|
const sectionOrders = {};
|
|
const stacks = {table: [], tableGroup: []};
|
|
const path = [];
|
|
|
|
cls.classFeatures.forEach((lvl, lvlI) => {
|
|
const tmpMeta = {
|
|
metaType: "class",
|
|
className: cls.name,
|
|
classSource: cls.source || Parser.SRC_PHB,
|
|
level: lvlI + 1,
|
|
};
|
|
|
|
lvl.forEach(feat => this._doSearch({
|
|
sectionOrders,
|
|
path,
|
|
tmpMeta,
|
|
section: cls.name,
|
|
data: feat,
|
|
stacks: stacks,
|
|
isRequireIncludes: true,
|
|
|
|
// Used to deduplicate headers
|
|
name: cls.name,
|
|
}));
|
|
});
|
|
|
|
stacks.table.forEach(it => {
|
|
it.name = it.caption;
|
|
it.source = it._tmpMeta.subclassSource || it._tmpMeta.classSource;
|
|
it.srd = !!cls.srd;
|
|
|
|
this._mutDataAddPage(it);
|
|
this._mutCleanData(it);
|
|
});
|
|
|
|
return stacks;
|
|
}
|
|
|
|
static getSubclassTables (sc) {
|
|
const sectionOrders = {};
|
|
const stacks = {table: [], tableGroup: []};
|
|
const path = [];
|
|
|
|
sc.subclassFeatures.forEach(lvl => {
|
|
const level = lvl[0].level;
|
|
|
|
const tmpMeta = {
|
|
metaType: "subclass",
|
|
className: sc.className,
|
|
classSource: sc.classSource || Parser.SRC_PHB,
|
|
level,
|
|
subclassName: sc.name,
|
|
subclassShortName: sc.shortName,
|
|
subclassSource: sc.source || sc.classSource || Parser.SRC_PHB,
|
|
|
|
// Used to deduplicate headers
|
|
name: sc.name,
|
|
};
|
|
|
|
lvl.forEach(feat => this._doSearch({
|
|
sectionOrders,
|
|
path,
|
|
tmpMeta,
|
|
section: sc.className,
|
|
data: feat,
|
|
stacks: stacks,
|
|
isRequireIncludes: true,
|
|
}));
|
|
});
|
|
|
|
stacks.table.forEach(it => {
|
|
it.name = it.caption;
|
|
it.source = it._tmpMeta.subclassSource || it._tmpMeta.classSource;
|
|
it.srd = !!sc.srd;
|
|
|
|
this._mutDataAddPage(it);
|
|
this._mutCleanData(it);
|
|
});
|
|
|
|
return stacks;
|
|
}
|
|
|
|
static getGenericTables (entity, metaType, ...props) {
|
|
const sectionOrders = {};
|
|
const stacks = {table: [], tableGroup: []};
|
|
const path = [];
|
|
|
|
props.forEach(prop => {
|
|
if (!entity[prop]) return;
|
|
const tmpMeta = {
|
|
metaType: metaType,
|
|
name: entity.name,
|
|
source: entity.source,
|
|
};
|
|
|
|
entity[prop].forEach(ent => {
|
|
this._doSearch({
|
|
sectionOrders,
|
|
path,
|
|
tmpMeta,
|
|
section: entity.name,
|
|
data: ent,
|
|
stacks: stacks,
|
|
isRequireIncludes: true,
|
|
|
|
// Used to deduplicate headers
|
|
name: entity.name,
|
|
});
|
|
});
|
|
});
|
|
|
|
stacks.table.forEach(it => {
|
|
it.name = it.caption;
|
|
it.source = it._tmpMeta.source;
|
|
|
|
this._mutDataAddPage(it);
|
|
this._mutCleanData(it);
|
|
});
|
|
|
|
return stacks;
|
|
}
|
|
}
|
|
|
|
globalThis.UtilGenTables = UtilGenTables;
|