mirror of
https://github.com/Kornstalx/5etools-mirror-2.github.io.git
synced 2025-10-28 20:45:35 -05:00
719 lines
20 KiB
JavaScript
719 lines
20 KiB
JavaScript
import {InitiativeTrackerConst} from "./dmscreen-initiativetracker-consts.js";
|
|
import {
|
|
InitiativeTrackerRowStatsColDataSerializer,
|
|
InitiativeTrackerStatColumnDataSerializer,
|
|
} from "./dmscreen-initiativetracker-serial.js";
|
|
import {InitiativeTrackerUtil} from "../../initiativetracker/initiativetracker-utils.js";
|
|
|
|
export const GROUP_BASE_STATS = "baseStats";
|
|
export const GROUP_SAVES = "saves";
|
|
export const GROUP_ABILITY_BONUS = "abilityBonus";
|
|
export const GROUP_ABILITY_SCORE = "abilityScore";
|
|
export const GROUP_SKILL = "skill";
|
|
export const GROUP_CHECKBOX = "checkbox";
|
|
export const GROUP_CUSTOM = "custom";
|
|
|
|
export const GROUP_DISPLAY_NAMES = {
|
|
[GROUP_BASE_STATS]: "General",
|
|
[GROUP_SAVES]: "Saving Throw",
|
|
[GROUP_ABILITY_BONUS]: "Ability Bonus",
|
|
[GROUP_ABILITY_SCORE]: "Ability Score",
|
|
[GROUP_SKILL]: "Skill",
|
|
[GROUP_CHECKBOX]: "Checkbox",
|
|
[GROUP_CUSTOM]: "Custom",
|
|
};
|
|
|
|
export const IS_PLAYER_VISIBLE_NONE = 0;
|
|
export const IS_PLAYER_VISIBLE_ALL = 1;
|
|
export const IS_PLAYER_VISIBLE_PLAYER_UNITS_ONLY = 2;
|
|
|
|
export const INITIATIVE_APPLICABILITY_NOT_APPLICABLE = 0;
|
|
const _INITIATIVE_APPLICABILITY_APPLICABLE = 1;
|
|
const _INITIATIVE_APPLICABILITY_EXACT = 2;
|
|
|
|
/** @abstract */
|
|
class _InitiativeTrackerStatColumnBase {
|
|
static _SERIALIZER_MAPPINGS = {
|
|
"entity.value": "v",
|
|
};
|
|
|
|
static _registerSerializerMappings () {
|
|
Object.entries(this._SERIALIZER_MAPPINGS)
|
|
.forEach(([kFull, kSerial]) => InitiativeTrackerRowStatsColDataSerializer.registerMapping({kFull, kSerial, isAllowDuplicates: true}));
|
|
return null;
|
|
}
|
|
|
|
static _ = this._registerSerializerMappings();
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/** Functions as an ID for the column type. */
|
|
static get POPULATE_WITH () { throw new Error("Unimplemented!"); }
|
|
|
|
/** UI group the column type belongs to. */
|
|
static GROUP;
|
|
|
|
static NAME;
|
|
static ABV_DEFAULT = "";
|
|
|
|
constructor (
|
|
{
|
|
id,
|
|
isEditable,
|
|
isPlayerVisible,
|
|
abbreviation,
|
|
} = {},
|
|
) {
|
|
this._id = id ?? CryptUtil.uid();
|
|
this._isEditable = isEditable ?? true;
|
|
this._isPlayerVisible = isPlayerVisible ?? false;
|
|
this._abbreviation = abbreviation ?? this.constructor.ABV_DEFAULT;
|
|
}
|
|
|
|
/**
|
|
* @param {?object} mon
|
|
* @param {?object} fluff
|
|
* @return {?*}
|
|
* @abstract
|
|
*/
|
|
_getInitialCellObj ({mon, fluff}) { throw new Error("Unimplemented!"); }
|
|
|
|
_getAsData () {
|
|
return {
|
|
id: this._id,
|
|
isEditable: this._isEditable,
|
|
isPlayerVisible: this._isPlayerVisible,
|
|
populateWith: this.constructor.POPULATE_WITH,
|
|
abbreviation: this._abbreviation,
|
|
};
|
|
}
|
|
|
|
getAsStateData () {
|
|
return this._getAsData();
|
|
}
|
|
|
|
getAsCollectionRowStateData () {
|
|
const data = this._getAsData();
|
|
const out = {
|
|
id: data.id,
|
|
entity: {
|
|
...data,
|
|
},
|
|
};
|
|
delete out.entity.id;
|
|
return out;
|
|
}
|
|
|
|
getPlayerFriendlyState ({cell}) {
|
|
return {id: cell.id, entity: cell.entity};
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/**
|
|
* @return {?object} `undefined` if the column should not auto-set at the start of the turn, or, a value the column should
|
|
* be auto-set to at the start of the turn.
|
|
*/
|
|
_getAutoTurnStartObject ({state, mon}) { return undefined; }
|
|
|
|
/**
|
|
* @return {?object} `undefined` if the column should not auto-set at the start of the round, or, a value the column should
|
|
* be auto-set to at the start of the round.
|
|
*/
|
|
_getAutoRoundStartObject ({state, mon}) { return undefined; }
|
|
|
|
_isNonNegativeDirection ({direction}) {
|
|
return ![InitiativeTrackerConst.DIR_FORWARDS, InitiativeTrackerConst.DIR_NEUTRAL].includes(direction);
|
|
}
|
|
|
|
onTurnStart ({state, direction, mon}) {
|
|
if (this._isNonNegativeDirection({direction})) return;
|
|
|
|
const obj = this._getAutoTurnStartObject({state, mon});
|
|
if (obj !== undefined) Object.assign(state.entity, obj);
|
|
}
|
|
|
|
onRoundStart ({state, direction, mon}) {
|
|
if (this._isNonNegativeDirection({direction})) return;
|
|
|
|
const obj = this._getAutoRoundStartObject({state, mon});
|
|
if (obj !== undefined) Object.assign(state.entity, obj);
|
|
}
|
|
|
|
$getRenderedHeader () {
|
|
return $(`<div class="dm-init__stat_head" ${this.constructor.NAME ? `title="${this.constructor.NAME}"` : ""}>${this._abbreviation}</div>`);
|
|
}
|
|
|
|
$getRendered ({comp, mon, networking = null}) {
|
|
const $ipt = ComponentUiUtil.$getIptStr(comp, "value")
|
|
.removeClass("input-xs")
|
|
.addClass("input-sm")
|
|
.addClass("dm-init__stat_ipt")
|
|
.addClass("ve-text-center")
|
|
.on("click", () => $ipt.select());
|
|
|
|
if (mon) {
|
|
comp._addHookBase("isEditable", () => {
|
|
$ipt.prop("disabled", !comp._state.isEditable);
|
|
})();
|
|
}
|
|
|
|
return $$`<div class="ve-flex-vh-center">${$ipt}</div>`;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/**
|
|
* @param {?object} mon
|
|
* @param {?object} fluff
|
|
* @param {?object} obj
|
|
*/
|
|
getInitialCellStateData ({mon = null, fluff = null, obj = null} = {}) {
|
|
return {
|
|
id: this._id,
|
|
entity: {
|
|
...(obj ?? (this._getInitialCellObj({mon, fluff}) || {})),
|
|
isEditable: this._isEditable,
|
|
},
|
|
};
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
getInitiativeInfo ({state}) {
|
|
return {
|
|
applicability: INITIATIVE_APPLICABILITY_NOT_APPLICABLE,
|
|
initiative: null,
|
|
};
|
|
}
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_HpFormula extends _InitiativeTrackerStatColumnBase {
|
|
static get POPULATE_WITH () { return "hpFormula"; }
|
|
static GROUP = GROUP_BASE_STATS;
|
|
static NAME = "HP Formula";
|
|
|
|
_getInitialCellObj ({mon, fluff}) {
|
|
if (!mon) return {value: null};
|
|
return {value: (mon.hp || {}).formula || ""};
|
|
}
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_ArmorClass extends _InitiativeTrackerStatColumnBase {
|
|
static get POPULATE_WITH () { return "armorClass"; }
|
|
static GROUP = GROUP_BASE_STATS;
|
|
static NAME = "Armor Class";
|
|
static ABV_DEFAULT = "AC";
|
|
|
|
_getInitialCellObj ({mon, fluff}) {
|
|
if (!mon) return {value: null};
|
|
return {value: mon.ac[0] ? (mon.ac[0].ac || mon.ac[0]) : null};
|
|
}
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_PassivePerception extends _InitiativeTrackerStatColumnBase {
|
|
static get POPULATE_WITH () { return "passivePerception"; }
|
|
static GROUP = GROUP_BASE_STATS;
|
|
static NAME = "Passive Perception";
|
|
static ABV_DEFAULT = "PP";
|
|
|
|
_getInitialCellObj ({mon, fluff}) {
|
|
if (!mon) return {value: null};
|
|
return {value: mon.passive};
|
|
}
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_Speed extends _InitiativeTrackerStatColumnBase {
|
|
static get POPULATE_WITH () { return "speed"; }
|
|
static GROUP = GROUP_BASE_STATS;
|
|
static NAME = "Speed";
|
|
static ABV_DEFAULT = "SPD";
|
|
|
|
_getInitialCellObj ({mon, fluff}) {
|
|
if (!mon) return {value: null};
|
|
return {
|
|
value: Math.max(0, ...Object.values(mon.speed || {})
|
|
.map(it => it.number ? it.number : it)
|
|
.filter(it => typeof it === "number")),
|
|
};
|
|
}
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_SpellDc extends _InitiativeTrackerStatColumnBase {
|
|
static get POPULATE_WITH () { return "spellDc"; }
|
|
static GROUP = GROUP_BASE_STATS;
|
|
static NAME = "Spell DC";
|
|
static ABV_DEFAULT = "DC";
|
|
|
|
_getInitialCellObj ({mon, fluff}) {
|
|
if (!mon) return {value: null};
|
|
return {
|
|
value: Math.max(
|
|
0,
|
|
...(mon.spellcasting || [])
|
|
.filter(it => it.headerEntries)
|
|
.map(it => {
|
|
return it.headerEntries
|
|
.map(it => {
|
|
const found = [0];
|
|
it
|
|
.replace(/DC (\d+)/g, (...m) => found.push(Number(m[1])))
|
|
.replace(/{@dc (\d+)}/g, (...m) => found.push(Number(m[1])));
|
|
return Math.max(...found);
|
|
})
|
|
.filter(Boolean);
|
|
})
|
|
.flat(),
|
|
),
|
|
};
|
|
}
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_Initiative extends _InitiativeTrackerStatColumnBase {
|
|
static get POPULATE_WITH () { return "initiative"; }
|
|
static GROUP = GROUP_BASE_STATS;
|
|
static NAME = "Initiative";
|
|
static ABV_DEFAULT = "INIT";
|
|
|
|
_getInitialCellObj ({mon, fluff}) {
|
|
if (!mon) return {value: null};
|
|
return {
|
|
value: Parser.getAbilityModifier(mon.dex),
|
|
};
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
getInitiativeInfo ({state}) {
|
|
return {
|
|
applicability: _INITIATIVE_APPLICABILITY_EXACT,
|
|
initiative: isNaN(state.entity?.value) ? 0 : Number(state.entity.value),
|
|
};
|
|
}
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_LegendaryActions extends _InitiativeTrackerStatColumnBase {
|
|
static _SERIALIZER_MAPPINGS = {
|
|
"entity.current": "cur",
|
|
"entity.max": "max",
|
|
};
|
|
|
|
static _ = this._registerSerializerMappings();
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
static get POPULATE_WITH () { return "legendaryActions"; }
|
|
static GROUP = GROUP_BASE_STATS;
|
|
static NAME = "Legendary Actions";
|
|
static ABV_DEFAULT = "LA";
|
|
|
|
getPlayerFriendlyState ({cell}) {
|
|
return {
|
|
...super.getPlayerFriendlyState({cell}),
|
|
entity: {
|
|
value: `${cell.entity.current || 0}/${cell.entity.max || 0}`,
|
|
},
|
|
};
|
|
}
|
|
|
|
_getInitialCellObj ({mon, fluff}) {
|
|
if (!mon) return {current: null, max: null};
|
|
const cnt = mon.legendaryActions ?? (mon.legendary ? 3 : null);
|
|
return {
|
|
current: cnt,
|
|
max: cnt,
|
|
};
|
|
}
|
|
|
|
_getAutoRoundStartObject ({state, mon}) {
|
|
return {current: state.entity.max};
|
|
}
|
|
|
|
$getRenderedHeader () {
|
|
return super.$getRenderedHeader()
|
|
.addClass("w-48p");
|
|
}
|
|
|
|
$getRendered ({comp, mon}) {
|
|
const $iptCurrent = ComponentUiUtil.$getIptNumber(
|
|
comp,
|
|
"current",
|
|
null,
|
|
{
|
|
isAllowNull: true,
|
|
fallbackOnNaN: null,
|
|
html: `<input class="form-control input-sm hp dm-init__row-input text-right w-24p mr-0 br-0">`,
|
|
},
|
|
)
|
|
.on("click", () => $iptCurrent.select());
|
|
|
|
const $iptMax = ComponentUiUtil.$getIptNumber(
|
|
comp,
|
|
"max",
|
|
null,
|
|
{
|
|
isAllowNull: true,
|
|
fallbackOnNaN: null,
|
|
html: `<input class="form-control input-sm hp-max dm-init__row-input w-24p mr-0 bl-0">`,
|
|
},
|
|
)
|
|
.on("click", () => $iptMax.select());
|
|
|
|
if (mon) {
|
|
comp._addHookBase("isEditable", () => {
|
|
$iptCurrent.prop("disabled", !comp._state.isEditable);
|
|
$iptMax.prop("disabled", !comp._state.isEditable);
|
|
})();
|
|
}
|
|
|
|
return $$`<div class="ve-flex relative mr-3p">
|
|
<div class="text-right">${$iptCurrent}</div>
|
|
<div class="dm-init__sep-fields-slash ve-flex-vh-center">/</div>
|
|
<div class="text-left">${$iptMax}</div>
|
|
</div>`;
|
|
}
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_Image extends _InitiativeTrackerStatColumnBase {
|
|
static _SERIALIZER_MAPPINGS = {
|
|
"entity.tokenUrl": "urlt",
|
|
"entity.imageHref": "hrefi",
|
|
};
|
|
|
|
static _ = this._registerSerializerMappings();
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
static get POPULATE_WITH () { return "image"; }
|
|
static GROUP = GROUP_BASE_STATS;
|
|
static NAME = "Image";
|
|
static ABV_DEFAULT = "IMG";
|
|
|
|
getPlayerFriendlyState ({cell}) {
|
|
return {
|
|
...super.getPlayerFriendlyState({cell}),
|
|
entity: {
|
|
type: "image",
|
|
tokenUrl: cell.entity.tokenUrl,
|
|
imageHref: cell.entity.imageHref,
|
|
},
|
|
};
|
|
}
|
|
|
|
_getInitialCellObj ({mon, fluff}) {
|
|
if (!mon) {
|
|
return {
|
|
tokenUrl: UrlUtil.link(Renderer.get().getMediaUrl("img", "blank-friendly.webp")),
|
|
imageHref: null,
|
|
};
|
|
}
|
|
|
|
return {
|
|
tokenUrl: Renderer.monster.getTokenUrl(mon),
|
|
imageHref: fluff?.images?.[0].href,
|
|
};
|
|
}
|
|
|
|
$getRendered ({comp, mon, networking = null}) {
|
|
const $ele = $$`<div class="mr-3p ve-flex-vh-center w-40p">
|
|
<img src="${comp._state.tokenUrl}" class="w-30p h-30p" alt="Token Image">
|
|
</div>`;
|
|
|
|
if (networking != null) {
|
|
$ele.title("Click to Show to Connected Players");
|
|
|
|
$ele
|
|
.on("click", () => {
|
|
networking.sendShowImageMessageToClients({
|
|
imageHref: InitiativeTrackerUtil.getImageOrTokenHref({imageHref: comp._state.imageHref, tokenUrl: comp._state.tokenUrl}),
|
|
});
|
|
});
|
|
|
|
// If no networking, assume this is an "edit" modal, and avoid binding events
|
|
Renderer.monster.hover.bindFluffImageMouseover({mon, $ele});
|
|
}
|
|
|
|
return $ele;
|
|
}
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_Save extends _InitiativeTrackerStatColumnBase {
|
|
static _ATT;
|
|
|
|
static get POPULATE_WITH () { return `${this._ATT}Save`; }
|
|
static GROUP = GROUP_SAVES;
|
|
static get NAME () { return `${Parser.attAbvToFull(this._ATT)} Save`; }
|
|
static get ABV_DEFAULT () { return this._ATT.toUpperCase(); }
|
|
|
|
_getInitialCellObj ({mon, fluff}) {
|
|
if (!mon) return {value: null};
|
|
return {
|
|
value: mon.save?.[this.constructor._ATT] ? mon.save[this.constructor._ATT] : Parser.getAbilityModifier(mon[this.constructor._ATT]),
|
|
};
|
|
}
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_AbilityBonus extends _InitiativeTrackerStatColumnBase {
|
|
static _ATT;
|
|
|
|
static get POPULATE_WITH () { return `${this._ATT}Bonus`; }
|
|
static GROUP = GROUP_ABILITY_BONUS;
|
|
static get NAME () { return `${Parser.attAbvToFull(this._ATT)} Bonus`; }
|
|
static get ABV_DEFAULT () { return this._ATT.toUpperCase(); }
|
|
|
|
_getInitialCellObj ({mon, fluff}) {
|
|
if (!mon) return {value: null};
|
|
return {
|
|
value: Parser.getAbilityModifier(mon[this.constructor._ATT]),
|
|
};
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
getInitiativeInfo ({state}) {
|
|
if (this.constructor._ATT !== "dex") return super.getInitiativeInfo({state});
|
|
return {
|
|
applicability: _INITIATIVE_APPLICABILITY_APPLICABLE,
|
|
initiative: isNaN(state.entity?.value) ? 0 : Number(state.entity.value),
|
|
};
|
|
}
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_AbilityScore extends _InitiativeTrackerStatColumnBase {
|
|
static _ATT;
|
|
|
|
static get POPULATE_WITH () { return `${this._ATT}Score`; }
|
|
static GROUP = GROUP_ABILITY_SCORE;
|
|
static get NAME () { return `${Parser.attAbvToFull(this._ATT)} Score`; }
|
|
static get ABV_DEFAULT () { return this._ATT.toUpperCase(); }
|
|
|
|
_getInitialCellObj ({mon, fluff}) {
|
|
if (!mon) return {value: null};
|
|
return {
|
|
value: mon[this.constructor._ATT],
|
|
};
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
getInitiativeInfo ({state}) {
|
|
if (this.constructor._ATT !== "dex") return super.getInitiativeInfo({state});
|
|
return {
|
|
applicability: _INITIATIVE_APPLICABILITY_APPLICABLE,
|
|
initiative: isNaN(state.entity?.value) ? 0 : Parser.getAbilityModifier(Number(state.entity.value)),
|
|
};
|
|
}
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_Skill extends _InitiativeTrackerStatColumnBase {
|
|
static _SKILL;
|
|
|
|
static get POPULATE_WITH () { return this._SKILL.toCamelCase(); }
|
|
static GROUP = GROUP_SKILL;
|
|
static get NAME () { return this._SKILL.toTitleCase(); }
|
|
static get ABV_DEFAULT () { return Parser.skillToShort(this._SKILL).toUpperCase(); }
|
|
|
|
_getInitialCellObj ({mon, fluff}) {
|
|
if (!mon) return {value: null};
|
|
return {
|
|
value: mon.skill?.[this.constructor._SKILL]
|
|
? mon.skill[this.constructor._SKILL]
|
|
: Parser.getAbilityModifier(mon[Parser.skillToAbilityAbv(this.constructor._SKILL)]),
|
|
};
|
|
}
|
|
}
|
|
|
|
class _InitiativeTrackerStatColumnCheckboxBase extends _InitiativeTrackerStatColumnBase {
|
|
static GROUP = GROUP_CHECKBOX;
|
|
|
|
static _AUTO_VALUE = undefined;
|
|
|
|
_getInitialCellObj ({mon, fluff}) { return {value: false}; }
|
|
|
|
$getRendered ({comp, mon}) {
|
|
const $cb = ComponentUiUtil.$getCbBool(comp, "value")
|
|
.addClass("dm-init__stat_ipt");
|
|
|
|
if (mon) {
|
|
comp._addHookBase("isEditable", () => {
|
|
$cb.prop("disabled", !comp._state.isEditable);
|
|
})();
|
|
}
|
|
|
|
return $$`<label class="dm-init__wrp-stat-cb h-100 ve-flex-vh-center">${$cb}</label>`;
|
|
}
|
|
}
|
|
|
|
class _InitiativeTrackerStatColumnCheckboxTurnBase extends _InitiativeTrackerStatColumnCheckboxBase {
|
|
_getAutoTurnStartObject ({state, mon}) { return {value: this.constructor._AUTO_VALUE}; }
|
|
}
|
|
|
|
class _InitiativeTrackerStatColumnCheckboxRoundBase extends _InitiativeTrackerStatColumnCheckboxBase {
|
|
_getAutoRoundStartObject ({state, mon}) { return {value: this.constructor._AUTO_VALUE}; }
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_Checkbox extends _InitiativeTrackerStatColumnCheckboxBase {
|
|
static get POPULATE_WITH () { return "cbNeutral"; }
|
|
static NAME = "Checkbox";
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_CheckboxAutoTurnLow extends _InitiativeTrackerStatColumnCheckboxTurnBase {
|
|
static get POPULATE_WITH () { return "cbAutoLow"; }
|
|
static NAME = "Checkbox; clears at start of turn";
|
|
|
|
static _AUTO_VALUE = false;
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_CheckboxAutoTurnHigh extends _InitiativeTrackerStatColumnCheckboxTurnBase {
|
|
static get POPULATE_WITH () { return "cbAutoHigh"; }
|
|
static NAME = "Checkbox; ticks at start of turn";
|
|
|
|
static _AUTO_VALUE = true;
|
|
|
|
_getInitialCellObj ({mon, fluff}) { return {value: true}; }
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_CheckboxAutoRoundLow extends _InitiativeTrackerStatColumnCheckboxRoundBase {
|
|
static get POPULATE_WITH () { return "cbAutoRoundLow"; }
|
|
static NAME = "Checkbox; clears at start of round";
|
|
|
|
static _AUTO_VALUE = false;
|
|
}
|
|
|
|
class InitiativeTrackerStatColumn_CheckboxAutoRoundHigh extends _InitiativeTrackerStatColumnCheckboxRoundBase {
|
|
static get POPULATE_WITH () { return "cbAutoRoundHigh"; }
|
|
static NAME = "Checkbox; ticks at start of round";
|
|
|
|
static _AUTO_VALUE = true;
|
|
|
|
_getInitialCellObj ({mon, fluff}) { return {value: true}; }
|
|
}
|
|
|
|
export class InitiativeTrackerStatColumn_Custom extends _InitiativeTrackerStatColumnBase {
|
|
static get POPULATE_WITH () { return ""; }
|
|
static GROUP = GROUP_CUSTOM;
|
|
static NAME = "(Custom)";
|
|
|
|
_getInitialCellObj ({mon, fluff}) { return {value: ""}; }
|
|
}
|
|
|
|
export class InitiativeTrackerStatColumnFactory {
|
|
static _COL_CLS_LOOKUP = {};
|
|
|
|
static _initLookup () {
|
|
[
|
|
InitiativeTrackerStatColumn_HpFormula,
|
|
InitiativeTrackerStatColumn_ArmorClass,
|
|
InitiativeTrackerStatColumn_PassivePerception,
|
|
InitiativeTrackerStatColumn_Speed,
|
|
InitiativeTrackerStatColumn_SpellDc,
|
|
InitiativeTrackerStatColumn_Initiative,
|
|
InitiativeTrackerStatColumn_LegendaryActions,
|
|
InitiativeTrackerStatColumn_Image,
|
|
].forEach(Cls => this._initLookup_addCls(Cls));
|
|
|
|
Parser.ABIL_ABVS
|
|
.forEach(abv => {
|
|
this._initLookup_addCls(class extends InitiativeTrackerStatColumn_Save { static _ATT = abv; });
|
|
});
|
|
|
|
Parser.ABIL_ABVS
|
|
.forEach(abv => {
|
|
this._initLookup_addCls(class extends InitiativeTrackerStatColumn_AbilityBonus { static _ATT = abv; });
|
|
});
|
|
|
|
Parser.ABIL_ABVS
|
|
.forEach(abv => {
|
|
this._initLookup_addCls(class extends InitiativeTrackerStatColumn_AbilityScore { static _ATT = abv; });
|
|
});
|
|
|
|
Object.keys(Parser.SKILL_TO_ATB_ABV)
|
|
.sort(SortUtil.ascSort)
|
|
.forEach(skill => {
|
|
this._initLookup_addCls(class extends InitiativeTrackerStatColumn_Skill { static _SKILL = skill; });
|
|
});
|
|
|
|
[
|
|
InitiativeTrackerStatColumn_Checkbox,
|
|
InitiativeTrackerStatColumn_CheckboxAutoTurnLow,
|
|
InitiativeTrackerStatColumn_CheckboxAutoTurnHigh,
|
|
InitiativeTrackerStatColumn_CheckboxAutoRoundLow,
|
|
InitiativeTrackerStatColumn_CheckboxAutoRoundHigh,
|
|
].forEach(Cls => this._initLookup_addCls(Cls));
|
|
}
|
|
|
|
static _initLookup_addCls (Cls) { this._COL_CLS_LOOKUP[Cls.POPULATE_WITH] = Cls; }
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
static getGroupedByUi () {
|
|
const out = [
|
|
[InitiativeTrackerStatColumn_Custom],
|
|
];
|
|
|
|
let groupPrev = GROUP_CUSTOM;
|
|
Object.values(this._COL_CLS_LOOKUP)
|
|
.forEach(Cls => {
|
|
if (groupPrev !== Cls.GROUP) out.push([]);
|
|
out.last().push(Cls);
|
|
groupPrev = Cls.GROUP;
|
|
});
|
|
|
|
return out;
|
|
}
|
|
|
|
/* -------------------------------------------- */
|
|
|
|
/**
|
|
* @param dataSerial
|
|
* @param data
|
|
* @return {_InitiativeTrackerStatColumnBase}
|
|
*/
|
|
static fromStateData ({dataSerial, data}) {
|
|
if (dataSerial && data) throw new Error(`Only one of "dataSerial" and "data" may be provided!`);
|
|
|
|
data = data ?? InitiativeTrackerStatColumnDataSerializer.fromSerial(dataSerial);
|
|
|
|
const Cls = this._COL_CLS_LOOKUP[data.populateWith] ?? InitiativeTrackerStatColumn_Custom;
|
|
return new Cls(data);
|
|
}
|
|
|
|
/**
|
|
* @param colName
|
|
* @return {_InitiativeTrackerStatColumnBase}
|
|
*/
|
|
static fromEncounterAdvancedColName ({colName}) {
|
|
colName = colName.toLowerCase().trim();
|
|
const Cls = Object.values(this._COL_CLS_LOOKUP)
|
|
.find(Cls => Cls.ABV_DEFAULT.toLowerCase() === colName)
|
|
|| InitiativeTrackerStatColumn_Custom;
|
|
|
|
return new Cls({
|
|
id: CryptUtil.uid(),
|
|
isEditable: true,
|
|
isPlayerVisible: IS_PLAYER_VISIBLE_PLAYER_UNITS_ONLY,
|
|
abbreviation: colName,
|
|
});
|
|
}
|
|
|
|
/**
|
|
* @param populateWith
|
|
* @return {_InitiativeTrackerStatColumnBase}
|
|
*/
|
|
static fromPopulateWith ({populateWith}) {
|
|
const Cls = this._COL_CLS_LOOKUP[populateWith] ?? InitiativeTrackerStatColumn_Custom;
|
|
return new Cls({});
|
|
}
|
|
|
|
/**
|
|
* @param data
|
|
* @return {_InitiativeTrackerStatColumnBase}
|
|
*/
|
|
static fromCollectionRowStateData ({data}) {
|
|
const flat = {id: data.id, ...data.entity};
|
|
return this.fromStateData({data: flat});
|
|
}
|
|
}
|
|
|
|
InitiativeTrackerStatColumnFactory._initLookup();
|