- ,
val = RollModStatus.Hidden;
}
- Object.assign(
- rollModData,
- {[key]: ["value"].includes(key)
- ? U.pInt(val)
- : (["effectKeys", "conditionalRollTypes", "autoRollTypes,", "conditionalRollTraits", "autoRollTraits"].includes(key)
- ? [val].flat()
- : (val as string).replace(/%COLON%/g, ":"))}
- );
+ function extractValue(key: string, val: string | string[]): any {
+ if (["value"].includes(key)) {
+ return U.pInt(val);
+ } else if (["effectKeys", "conditionalRollTypes", "autoRollTypes,", "conditionalRollTraits", "autoRollTraits"].includes(key)) {
+ return [val].flat();
+ } else {
+ return (val as string).replace(/%COLON%/g, ":");
+ }
+ }
+ Object.assign(rollModData, {[key]: extractValue(key, val)});
+
+ // Object.assign(
+ // rollModData,
+ // {[key]: ["value"].includes(key)
+ // ? U.pInt(val)
+ // : (["effectKeys", "conditionalRollTypes", "autoRollTypes,", "conditionalRollTraits", "autoRollTraits"].includes(key)
+ // ? [val].flat()
+ // : (val as string).replace(/%COLON%/g, ":"))}
+ // );
});
return rollModData;
});
// Add roll mods from COHORT harm
- // [[/1d/, RollModCategory.roll] as const, [/Less Effect/, RollModCategory.effect] as const].forEach(([effectPat, effectCat]) => {
- // const {one: harmConditionOne, two: harmConditionTwo} = Object.values(this.system.harm ?? {})
- // .find((harmData) => effectPat.test(harmData.effect)) ?? {};
- // const harmString = U.objCompact([harmConditionOne, harmConditionTwo === "" ? null : harmConditionTwo]).join(" & ");
- // if (harmString.length > 0) {
- // rollModsData.push({
- // id: `Harm-negative-${effectCat}`,
- // name: harmString,
- // category: effectCat,
- // posNeg: "negative",
- // base_status: RollModStatus.ToggledOn,
- // modType: "harm",
- // value: 1,
- // tooltip: [
- // `
Harm: ${harmString}
`,
- // effectCat === RollModCategory.roll
- // ? "If your injuries apply to the situation at hand, you suffer −1d to your roll.
"
- // : "If your injuries apply to the situation at hand, you suffer −1 effect."
- // ].join("")
- // });
- // }
- // });
-
- // eLog.checkLog3("rollCollab", `Roll Mods (${this.name})`, {system: this.system.roll_mods, rollMods});
return rollModsData;
}
- get rollFactors(): Partial> {
- const factorsMap: Partial> = {
- [BladesItemType.ability]: [],
- [BladesItemType.background]: [],
- [BladesItemType.cohort_gang]: [Factor.quality, Factor.scale],
- [BladesItemType.cohort_expert]: [Factor.quality, Factor.scale],
- [BladesItemType.crew_ability]: [],
- [BladesItemType.crew_reputation]: [],
- [BladesItemType.crew_playbook]: [],
- [BladesItemType.crew_upgrade]: [],
- [BladesItemType.feature]: [],
- [BladesItemType.heritage]: [],
- [BladesItemType.gear]: [Factor.quality],
- [BladesItemType.playbook]: [],
- [BladesItemType.preferred_op]: [],
- [BladesItemType.stricture]: [],
- [BladesItemType.vice]: [],
- [BladesItemType.project]: [Factor.quality],
- [BladesItemType.ritual]: [Factor.magnitude],
- [BladesItemType.design]: [Factor.quality]
- };
- if (!factorsMap[this.type]) { return {} }
+ // #endregion
- const factors = factorsMap[this.type];
+ // #region BladesRollCollab.OppositionDoc Implementation
+ get rollOppID() { return this.id }
+ get rollOppDoc() { return this }
+ get rollOppImg() { return this.img! }
+ get rollOppName() { return this.name! }
+ get rollOppSubName() { return "" }
+ get rollOppType() { return this.type }
- const factorData: Partial> = {};
- factors!.forEach((factor, i) => {
- const factorTotal = this.getFactorTotal(factor);
- factorData[factor] = {
- name: factor,
- value: factorTotal,
- max: factorTotal,
- baseVal: factorTotal,
- display: [Factor.tier, Factor.quality].includes(factor) ? U.romanizeNum(factorTotal) : `${factorTotal}`,
- isActive: i === 0,
- isPrimary: i === 0,
- isDominant: false,
- highFavorsPC: true,
- cssClasses: `factor-gold${i === 0 ? " factor-main" : ""}`
- };
- });
+ get rollOppModsData(): BladesRollCollab.RollModData[] { return [] }
+ // #endregion
+
+ // #region BladesRollCollab.ParticipantDoc Implementation
+ get rollParticipantID() { return this.id }
+ get rollParticipantDoc() { return this }
+ get rollParticipantIcon() { return this.img! }
+ get rollParticipantName() { return this.name! }
+ get rollParticipantType() { return this.type }
+
+ get rollParticipantModsData(): BladesRollCollab.RollModData[] { return [] }
+ // #endregion
- return factorData;
- }
// #endregion
// #region PREPARING DERIVED DATA
override prepareDerivedData() {
super.prepareDerivedData();
- // if (BladesItem.IsType(this, BladesItemType.ability)) { this._prepareAbilityData(this.system) }
- // if (BladesItem.IsType(this, BladesItemType.background)) { this._prepareBackgroundData(this.system) }
if (BladesItem.IsType(this, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { this._prepareCohortData(this.system) }
- // if (BladesItem.IsType(this, BladesItemType.crew_ability)) { this._prepareCrewAbilityData(this.system) }
- // if (BladesItem.IsType(this, BladesItemType.crew_reputation)) { this._prepareCrewReputationData(this.system) }
if (BladesItem.IsType(this, BladesItemType.crew_playbook)) { this._preparePlaybookData(this.system) }
- // if (BladesItem.IsType(this, BladesItemType.crew_upgrade)) { this._prepareCrewUpgradeData(this.system) }
- // if (BladesItem.IsType(this, BladesItemType.feature)) { this._prepareFeatureData(this.system) }
- // if (BladesItem.IsType(this, BladesItemType.heritage)) { this._prepareHeritageData(this.system) }
if (BladesItem.IsType(this, BladesItemType.gear)) { this._prepareGearData(this.system) }
if (BladesItem.IsType(this, BladesItemType.playbook)) { this._preparePlaybookData(this.system) }
- // if (BladesItem.IsType(this, BladesItemType.preferred_op)) { this._preparePreferredOpData(this.system) }
- // if (BladesItem.IsType(this, BladesItemType.stricture)) { this._prepareStrictureData(this.system) }
- // if (BladesItem.IsType(this, BladesItemType.vice)) { this._prepareViceData(this.system) }
- // if (BladesItem.IsType(this, BladesItemType.project)) { this._prepareProjectData(this.system) }
- // if (BladesItem.IsType(this, BladesItemType.ritual)) { this._prepareRitualData(this.system) }
- // if (BladesItem.IsType(this, BladesItemType.design)) { this._prepareDesignData(this.system) }
}
@@ -411,13 +323,6 @@ class BladesItem extends Item implements BladesDocument- ,
.map((subtype) => subtype.trim())
.filter((subtype) => /[A-Za-z]/.test(subtype) && subtypes.includes(subtype)));
- // Add parent-crew's elite subtype upgrades
- // if (BladesActor.IsType(this.parent, BladesActorType.crew)) {
- // elite_subtypes.push(...this.parent.upgrades
- // .map((upgrade) => (upgrade.name ?? "").trim().replace(/^Elite /, ""))
- // .filter((upgradeName) => subtypes.includes(upgradeName)));
- // }
-
system.subtypes = Object.fromEntries(subtypes.map((subtype, i) => [`${i + 1}`, subtype]));
system.elite_subtypes = Object.fromEntries(elite_subtypes.map((subtype, i) => [`${i + 1}`, subtype]));
system.edges = Object.fromEntries(Object.values(system.edges ?? [])
diff --git a/ts/blades-roll-collab.ts b/ts/blades-roll-collab.ts
index 9e8c6e58..ccf00b8f 100644
--- a/ts/blades-roll-collab.ts
+++ b/ts/blades-roll-collab.ts
@@ -1,11 +1,8 @@
// #region IMPORTS ~
import U from "./core/utilities.js";
-import C, {BladesActorType, BladesItemType, RollType, RollSubType, RollModStatus, RollModCategory, Action, DowntimeAction, Attribute, Position, Effect, Factor, RollResult, Harm, ConsequenceType} from "./core/constants.js";
+import C, {BladesActorType, BladesItemType, RollType, RollSubType, RollModStatus, RollModCategory, Action, DowntimeAction, Attribute, Position, Effect, Factor, RollResult, ConsequenceType} from "./core/constants.js";
import BladesActor from "./blades-actor.js";
import BladesPC from "./documents/actors/blades-pc.js";
-import BladesNPC from "./documents/actors/blades-npc.js";
-import BladesFaction from "./documents/actors/blades-faction.js";
-import BladesCrew from "./documents/actors/blades-crew.js";
import BladesItem from "./blades-item.js";
import BladesActiveEffect from "./blades-active-effect.js";
import {ApplyTooltipListeners} from "./core/gsap.js";
@@ -1163,17 +1160,6 @@ type EffectData = {
value: string
};
-// function getRollModStatus(mod: BladesRollMod) {
-// return {
-// status: mod.status,
-// user_status: mod.user_status,
-// held_status: mod.held_status,
-// base_status: mod.base_status
-// };
-// }
-// function stringifyRollModStatus(mod: BladesRollMod) {
-// return JSON.stringify(getRollModStatus(mod));
-// }
function compareRollModStatus(mod: BladesRollMod, lastStatusData: string) {
const lastStatus = JSON.parse(lastStatusData) as Record<"status"|"user_status"|"held_status"|"base_status",RollModStatus|undefined>;
const statusChangeData: Partial> = {};
@@ -1272,7 +1258,7 @@ export class BladesRollMod {
let stressCost = 0;
costKeys.forEach((key) => {
const [thisParam] = (key.split(/-/) ?? []).slice(1);
- const [_, valStr] = (thisParam.match(/([A-Za-z]+)([0-9]*)/) ?? []).slice(1);
+ const [_, valStr] = (thisParam.match(/([A-Za-z]+)(\d*)/) ?? []).slice(1);
stressCost += U.pInt(valStr);
});
return stressCost;
@@ -1395,17 +1381,17 @@ export class BladesRollMod {
const payableKeys = holdKeys
.filter((key) => {
const [thisParam] = (key.split(/-/) ?? []).slice(1);
- const [traitStr, valStr] = (thisParam.match(/([A-Za-z]+)([0-9]*)/) ?? []).slice(1);
+ const [traitStr, valStr] = (thisParam.match(/([A-Za-z]+)(\d*)/) ?? []).slice(1);
switch (traitStr) {
case "SpecialArmor": {
- return BladesActor.IsType(this.rollInstance!.rollSource?.rollSourceDoc, BladesActorType.pc)
- && this.rollInstance!.rollSource!.rollSourceDoc.system.armor.active.special
- && !this.rollInstance!.rollSource!.rollSourceDoc.system.armor.checked.special;
+ return BladesActor.IsType(this.rollInstance!.rollPrimary?.rollPrimaryDoc, BladesActorType.pc)
+ && this.rollInstance!.rollPrimary!.rollPrimaryDoc.system.armor.active.special
+ && !this.rollInstance!.rollPrimary!.rollPrimaryDoc.system.armor.checked.special;
}
case "Stress": {
const val = U.pInt(valStr);
- return BladesActor.IsType(this.rollInstance!.rollSource?.rollSourceDoc, BladesActorType.pc)
- && this.rollInstance!.rollSource!.rollSourceDoc.system.stress.max - this.rollInstance!.rollSource!.rollSourceDoc.system.stress.value >= val;
+ return BladesActor.IsType(this.rollInstance!.rollPrimary?.rollPrimaryDoc, BladesActorType.pc)
+ && this.rollInstance!.rollPrimary!.rollPrimaryDoc.system.stress.max - this.rollInstance!.rollPrimary!.rollPrimaryDoc.system.stress.value >= val;
}
// no default
}
@@ -1440,8 +1426,6 @@ export class BladesRollMod {
}
case "Consequence": {
/* Should cancel roll entirely? */
- // return this.rollInstance.rollType === RollType.Resistance
- // && Boolean(this.rollInstance.rollConsequence);
return;
}
case "HarmLevel": {
@@ -1474,7 +1458,7 @@ export class BladesRollMod {
break;
}
case "Increase": {
- const [traitStr, valStr] = (thisParam.match(/([A-Za-z]+)([0-9]*)/) ?? []).slice(1);
+ const [traitStr, valStr] = (thisParam.match(/([A-Za-z]+)(\d*)/) ?? []).slice(1);
this.rollInstance.tempGMBoosts[traitStr as "Dice" | Factor | "Result"] = U.pInt(valStr);
return;
}
@@ -1498,25 +1482,25 @@ export class BladesRollMod {
switch (this.category) {
case RollModCategory.roll: {
if (this.name === "Assist") {
- const docID = this.rollInstance.document.getFlag("eunos-blades", "rollCollab.docSelections.roll.Assist") as string | false | undefined;
+ const docID = this.rollInstance.document.getFlag("eunos-blades", "rollCollab.docSelections.roll.Assist") as MaybeStringOrFalse;
if (!docID) { return undefined }
- return (game.actors.get(docID) ?? game.items.get(docID) ?? {}).name ?? undefined;
+ return (game.actors.get(docID) ?? game.items.get(docID))?.name ?? undefined;
}
return undefined;
}
case RollModCategory.position: {
if (this.name === "Setup") {
- const docID = this.rollInstance.document.getFlag("eunos-blades", "rollCollab.docSelections.position.Setup") as string | false | undefined;
+ const docID = this.rollInstance.document.getFlag("eunos-blades", "rollCollab.docSelections.position.Setup") as MaybeStringOrFalse;
if (!docID) { return undefined }
- return (game.actors.get(docID) ?? game.items.get(docID) ?? {}).name ?? undefined;
+ return (game.actors.get(docID) ?? game.items.get(docID))?.name ?? undefined;
}
return undefined;
}
case RollModCategory.effect: {
if (this.name === "Setup") {
- const docID = this.rollInstance.document.getFlag("eunos-blades", "rollCollab.docSelections.effect.Setup") as string | false | undefined;
+ const docID = this.rollInstance.document.getFlag("eunos-blades", "rollCollab.docSelections.effect.Setup") as MaybeStringOrFalse;
if (!docID) { return undefined }
- return (game.actors.get(docID) ?? game.items.get(docID) ?? {}).name ?? undefined;
+ return (game.actors.get(docID) ?? game.items.get(docID))?.name ?? undefined;
}
return undefined;
}
@@ -1557,14 +1541,21 @@ export class BladesRollMod {
return holdKeys.map((key) => {
const [thisParam] = (key.split(/-/) ?? []).slice(1);
- const [traitStr, valStr] = (thisParam.match(/([A-Za-z]+)([0-9]*)/) ?? []).slice(1);
+ const [traitStr, valStr] = (thisParam.match(/([A-Za-z]+)(\d*)/) ?? []).slice(1);
+
+ let label = this.name;
+ if (this.isBasicPush) {
+ if (this.posNeg === "negative") {
+ label = `${this.name} (To Act)`;
+ } else {
+ const effect = this.category === RollModCategory.roll ? "+1d" : "+1 effect";
+ label = `${this.name} (${effect})`;
+ }
+ }
+
return {
id: this.id,
- label: this.isBasicPush
- ? (this.posNeg === "negative"
- ? `${this.name} (To Act)`
- : `${this.name} (${this.category === RollModCategory.roll ? "+1d" : "+1 effect"})`)
- : this.name,
+ label: label,
costType: traitStr,
costAmount: valStr ? U.pInt(valStr) : 1
};
@@ -1612,39 +1603,109 @@ export class BladesRollMod {
}
// #endregion
+
+class BladesRollPrimary implements BladesRollCollab.PrimaryDocData {
+
+ static IsDoc(doc: unknown): doc is BladesRollCollab.PrimaryDoc {
+ return BladesActor.IsType(doc, BladesActorType.pc, BladesActorType.crew)
+ || BladesItem.IsType(doc, BladesItemType.cohort_expert, BladesItemType.cohort_gang, BladesItemType.gm_tracker);
+ }
+
+ rollInstance: BladesRollCollab;
+ rollPrimaryID: string|undefined;
+ rollPrimaryDoc: BladesRollCollab.PrimaryDoc|undefined;
+ rollPrimaryName: string;
+ rollPrimaryType: string;
+ rollPrimaryImg: string;
+
+ rollModsData: BladesRollCollab.RollModData[];
+ rollFactors: Partial>;
+
+ constructor(rollInstance: BladesRollCollab, {rollPrimaryID, rollPrimaryDoc, rollPrimaryName, rollPrimaryType, rollPrimaryImg, rollModsData, rollFactors}: Partial = {}) {
+ // Identify ID, Doc, Name, SubName, Type & Image, to best of ability
+ this.rollInstance = rollInstance;
+ let doc: BladesDoc|undefined = rollPrimaryDoc;
+ if (!doc && rollPrimaryID) {
+ doc = game.items.get(rollPrimaryID) ?? game.actors.get(rollPrimaryID);
+ }
+ if (!doc && rollPrimaryName) {
+ doc = game.items.getName(rollPrimaryName) ?? game.actors.getName(rollPrimaryName);
+ }
+
+ if (BladesRollPrimary.IsDoc(doc)) {
+ this.rollPrimaryDoc = doc;
+ }
+
+ if (BladesRollPrimary.IsDoc(this.rollPrimaryDoc)) {
+ this.rollPrimaryID = this.rollPrimaryDoc.rollPrimaryID;
+ this.rollPrimaryName = rollPrimaryName ?? this.rollPrimaryDoc.rollPrimaryName;
+ this.rollPrimaryType = this.rollPrimaryDoc.rollPrimaryType;
+ this.rollPrimaryImg = rollPrimaryImg ?? this.rollPrimaryDoc.rollPrimaryImg ?? "";
+ this.rollModsData = [
+ ...rollModsData ?? [],
+ ...this.rollPrimaryDoc.rollModsData ?? []
+ ];
+ this.rollFactors = Object.assign(
+ this.rollPrimaryDoc.rollFactors,
+ rollFactors ?? {}
+ );
+ } else {
+ if (!rollPrimaryName) { throw new Error("Must include a rollPrimaryName when constructing a BladesRollPrimary object.") }
+ if (!rollPrimaryImg) { throw new Error("Must include a rollPrimaryImg when constructing a BladesRollPrimary object.") }
+ if (!rollPrimaryType) { throw new Error("Must include a rollPrimaryType when constructing a BladesRollPrimary object.") }
+ if (!rollFactors) { throw new Error("Must include a rollFactors when constructing a BladesRollPrimary object.") }
+
+ this.rollPrimaryID = rollPrimaryID;
+ this.rollPrimaryName = rollPrimaryName;
+ this.rollPrimaryType = rollPrimaryType;
+ this.rollPrimaryImg = rollPrimaryImg;
+ this.rollModsData = rollModsData ?? [];
+ this.rollFactors = rollFactors;
+ }
+ }
+}
+
class BladesRollOpposition implements BladesRollCollab.OppositionDocData {
+ static IsDoc(doc: unknown): doc is BladesRollCollab.OppositionDoc {
+ return BladesActor.IsType(doc, BladesActorType.npc, BladesActorType.faction)
+ || BladesItem.IsType(doc, BladesItemType.cohort_expert, BladesItemType.cohort_gang, BladesItemType.gm_tracker, BladesItemType.project, BladesItemType.design, BladesItemType.ritual);
+ }
+
rollInstance: BladesRollCollab;
rollOppID: string|undefined;
- rollOppDoc: BladesDoc|undefined;
+ rollOppDoc: BladesRollCollab.OppositionDoc|undefined;
rollOppName: string;
rollOppSubName: string;
rollOppType: string;
rollOppImg: string;
- rollModsData: BladesRollCollab.RollModData[]|undefined;
+ rollOppModsData: BladesRollCollab.RollModData[]|undefined;
rollFactors: Partial>;
- constructor(rollInstance: BladesRollCollab, {rollOppID, rollOppDoc, rollOppName, rollOppSubName, rollOppType, rollOppImg, rollModsData, rollFactors}: Partial = {}) {
+ constructor(rollInstance: BladesRollCollab, {rollOppID, rollOppDoc, rollOppName, rollOppSubName, rollOppType, rollOppImg, rollOppModsData, rollFactors}: Partial = {}) {
// Identify ID, Doc, Name, SubName, Type & Image, to best of ability
- this.rollOppDoc = rollOppDoc;
this.rollInstance = rollInstance;
- if (!this.rollOppDoc) {
- if (rollOppID) {
- this.rollOppDoc = game.items.get(rollOppID) ?? game.actors.get(rollOppID);
- }
- if (rollOppName) {
- this.rollOppDoc = game.items.getName(rollOppName) ?? game.actors.getName(rollOppName);
- }
+ let doc: BladesDoc|undefined = rollOppDoc;
+ if (!doc && rollOppID) {
+ doc = game.items.get(rollOppID) ?? game.actors.get(rollOppID);
+ }
+ if (!doc && rollOppName) {
+ doc = game.items.getName(rollOppName) ?? game.actors.getName(rollOppName);
+ }
+
+ if (BladesRollOpposition.IsDoc(doc)) {
+ this.rollOppDoc = doc;
}
- if (this.rollOppDoc) {
+
+ if (BladesRollOpposition.IsDoc(this.rollOppDoc)) {
this.rollOppID = this.rollOppDoc.rollOppID;
this.rollOppName = rollOppName ?? this.rollOppDoc.rollOppName;
this.rollOppSubName = rollOppSubName ?? this.rollOppDoc.rollOppSubName;
this.rollOppType = this.rollOppDoc.rollOppType;
this.rollOppImg = rollOppImg ?? this.rollOppDoc.rollOppImg ?? "";
- this.rollModsData = [
- ...rollModsData ?? [],
- ...this.rollOppDoc.rollModsData ?? []
+ this.rollOppModsData = [
+ ...rollOppModsData ?? [],
+ ...this.rollOppDoc.rollOppModsData ?? []
];
this.rollFactors = Object.assign(
this.rollOppDoc.rollFactors,
@@ -1661,66 +1722,74 @@ class BladesRollOpposition implements BladesRollCollab.OppositionDocData {
this.rollOppSubName = rollOppSubName;
this.rollOppType = rollOppType;
this.rollOppImg = rollOppImg ?? "";
- this.rollModsData = rollModsData ?? [];
+ this.rollOppModsData = rollOppModsData ?? [];
this.rollFactors = rollFactors;
}
- if (this.rollModsData.length === 0) {
- this.rollModsData = undefined;
+ if (this.rollOppModsData.length === 0) {
+ this.rollOppModsData = undefined;
}
}
}
-class BladesRollSource implements BladesRollCollab.SourceDocData {
+class BladesRollParticipant implements BladesRollCollab.ParticipantDocData {
rollInstance: BladesRollCollab;
- rollSourceID: string|undefined;
- rollSourceDoc: BladesDoc|undefined;
- rollSourceName: string;
- rollSourceType: string;
- rollSourceImg: string;
+ rollParticipantID: string|undefined;
+ rollParticipantDoc: BladesRollCollab.ParticipantDoc|undefined;
+ rollParticipantName: string;
+ rollParticipantType: string;
+ rollParticipantIcon: string;
- rollModsData: BladesRollCollab.RollModData[];
+ rollParticipantModsData: BladesRollCollab.RollModData[]|undefined; // As applied to MAIN roll when this participant involved
rollFactors: Partial>;
- constructor(rollInstance: BladesRollCollab, {rollSourceID, rollSourceDoc, rollSourceName, rollSourceType, rollSourceImg, rollModsData, rollFactors}: Partial = {}) {
+ constructor(rollInstance: BladesRollCollab, {rollParticipantID, rollParticipantDoc, rollParticipantName, rollParticipantType, rollParticipantIcon, rollParticipantModsData, rollFactors}: Partial = {}) {
// Identify ID, Doc, Name, SubName, Type & Image, to best of ability
- this.rollSourceDoc = rollSourceDoc;
this.rollInstance = rollInstance;
- if (!this.rollSourceDoc) {
- if (rollSourceID) {
- this.rollSourceDoc = game.items.get(rollSourceID) ?? game.actors.get(rollSourceID);
- }
- if (rollSourceName) {
- this.rollSourceDoc = game.items.getName(rollSourceName) ?? game.actors.getName(rollSourceName);
- }
+ let doc: BladesDoc|undefined = rollParticipantDoc;
+ if (!doc && rollParticipantID) {
+ doc = game.items.get(rollParticipantID) ?? game.actors.get(rollParticipantID);
}
- if (this.rollSourceDoc) {
- this.rollSourceID = this.rollSourceDoc.rollSourceID;
- this.rollSourceName = rollSourceName ?? this.rollSourceDoc.rollSourceName;
- this.rollSourceType = this.rollSourceDoc.rollSourceType;
- this.rollSourceImg = rollSourceImg ?? this.rollSourceDoc.rollSourceImg ?? "";
- this.rollModsData = [
- ...rollModsData ?? [],
- ...this.rollSourceDoc.rollModsData ?? []
+ if (!doc && rollParticipantName) {
+ doc = game.items.getName(rollParticipantName) ?? game.actors.getName(rollParticipantName);
+ }
+
+ if (BladesActor.IsType(doc, BladesActorType.pc, BladesActorType.crew, BladesActorType.npc)
+ || BladesItem.IsType(doc, BladesItemType.cohort_expert, BladesItemType.cohort_gang, BladesItemType.gm_tracker)) {
+ this.rollParticipantDoc = doc as BladesRollCollab.ParticipantDoc;
+ }
+
+ if (this.rollParticipantDoc) {
+ this.rollParticipantID = this.rollParticipantDoc.rollParticipantID;
+ this.rollParticipantName = rollParticipantName ?? this.rollParticipantDoc.rollParticipantName ?? this.rollParticipantDoc.name!;
+ this.rollParticipantIcon = rollParticipantIcon ?? this.rollParticipantDoc.rollParticipantIcon ?? this.rollParticipantDoc.img!;
+ this.rollParticipantType = this.rollParticipantDoc.rollParticipantType;
+ this.rollParticipantModsData = [
+ ...rollParticipantModsData ?? [],
+ ...this.rollParticipantDoc.rollParticipantModsData ?? []
];
this.rollFactors = Object.assign(
- this.rollSourceDoc.rollFactors,
+ this.rollParticipantDoc.rollFactors,
rollFactors ?? {}
);
} else {
- if (!rollSourceName) { throw new Error("Must include a rollSourceName when constructing a BladesRollSource object.") }
- if (!rollSourceImg) { throw new Error("Must include a rollSourceImg when constructing a BladesRollSource object.") }
- if (!rollSourceType) { throw new Error("Must include a rollSourceType when constructing a BladesRollSource object.") }
- if (!rollFactors) { throw new Error("Must include a rollFactors when constructing a BladesRollSource object.") }
-
- this.rollSourceID = rollSourceID;
- this.rollSourceName = rollSourceName;
- this.rollSourceType = rollSourceType;
- this.rollSourceImg = rollSourceImg;
- this.rollModsData = rollModsData ?? [];
+ if (!rollParticipantName) { throw new Error("Must include a rollParticipantName when constructing a BladesRollParticipant object.") }
+ if (!rollParticipantType) { throw new Error("Must include a rollParticipantType when constructing a BladesRollParticipant object.") }
+ if (!rollParticipantIcon) { throw new Error("Must include a rollParticipantIcon when constructing a BladesRollParticipant object.") }
+ if (!rollFactors) { throw new Error("Must include a rollFactors when constructing a BladesRollParticipant object.") }
+
+ this.rollParticipantID = rollParticipantID;
+ this.rollParticipantName = rollParticipantName;
+ this.rollParticipantType = rollParticipantType;
+ this.rollParticipantIcon = rollParticipantIcon;
+ this.rollParticipantModsData = rollParticipantModsData ?? [];
this.rollFactors = rollFactors;
}
+ if (this.rollParticipantModsData.length === 0) {
+ this.rollParticipantModsData = undefined;
+ }
}
+
}
// #region *** CLASS *** BladesRollCollab
@@ -1877,8 +1946,8 @@ class BladesRollCollab extends DocumentSheet {
return {
rollID: randomID(),
rollType: RollType.Action,
- rollSourceType: BladesActorType.pc,
- rollSourceID: "",
+ rollPrimaryType: BladesActorType.pc,
+ rollPrimaryID: "",
rollTrait: Factor.tier,
rollModsData: {},
rollPositionInitial: Position.risky,
@@ -2007,8 +2076,8 @@ class BladesRollCollab extends DocumentSheet {
}
static async NewRoll(config: BladesRollCollab.Config) {
- if (game.user.isGM && BladesActor.IsType(config.rollSource, BladesActorType.pc)) {
- const rSource: BladesPC = config.rollSource;
+ if (game.user.isGM && BladesActor.IsType(config.rollPrimary, BladesActorType.pc)) {
+ const rSource: BladesPC = config.rollPrimary;
if (rSource.primaryUser?.id) {
config.userID = rSource.primaryUser.id;
}
@@ -2028,14 +2097,13 @@ class BladesRollCollab extends DocumentSheet {
eLog.error("rollCollab", `[RenderRollCollab()] Invalid rollType: ${flagUpdateData.rollType}`, config);
return;
}
- const rollSourceData: BladesRollCollab.SourceDocData|undefined = config.rollSource ?? user.character;
- // const rollSource = rollSourceData ? new BladesRollSource(this, rollSourceData) : undefined;
- if (!rollSourceData) {
- eLog.error("rollCollab", "[RenderRollCollab()] Invalid rollSource", {rollSourceData, config});
+ const rollPrimaryData: BladesRollCollab.PrimaryDocData|undefined = config.rollPrimary ?? (user.character as BladesPC|undefined);
+ if (!rollPrimaryData) {
+ eLog.error("rollCollab", "[RenderRollCollab()] Invalid rollPrimary", {rollPrimaryData, config});
return;
}
- flagUpdateData.rollSourceID = rollSourceData.rollSourceID;
- flagUpdateData.rollSourceType = rollSourceData.rollSourceType;
+ flagUpdateData.rollPrimaryID = rollPrimaryData.rollPrimaryID;
+ flagUpdateData.rollPrimaryType = rollPrimaryData.rollPrimaryType;
if (U.isInt(config.rollTrait)) {
flagUpdateData.rollTrait = config.rollTrait;
} else if (!config.rollTrait) {
@@ -2099,23 +2167,23 @@ class BladesRollCollab extends DocumentSheet {
return this.document.getFlag(C.SYSTEM_ID, "rollCollab") as BladesRollCollab.FlagData;
}
- _rollSource?: BladesRollSource;
- get rollSource(): BladesRollSource | undefined {
- if (!this._rollSource) {
- if (this.rData.rollSourceData) {
- this._rollSource = new BladesRollSource(this, this.rData.rollSourceData);
+ _rollPrimary?: BladesRollPrimary;
+ get rollPrimary(): BladesRollPrimary | undefined {
+ if (!this._rollPrimary) {
+ if (this.rData.rollPrimaryData) {
+ this._rollPrimary = new BladesRollPrimary(this, this.rData.rollPrimaryData);
}
}
- if (this._rollSource instanceof BladesRollSource) {
- return this._rollSource;
+ if (this._rollPrimary instanceof BladesRollPrimary) {
+ return this._rollPrimary;
}
return undefined;
}
- set rollSource(val: BladesRollCollab.SourceDocData | undefined) {
+ set rollPrimary(val: BladesRollCollab.PrimaryDocData | undefined) {
if (val === undefined) {
- this._rollSource = undefined;
+ this._rollPrimary = undefined;
} else {
- this._rollSource = new BladesRollSource(this, val);
+ this._rollPrimary = new BladesRollPrimary(this, val);
}
}
@@ -2151,22 +2219,22 @@ class BladesRollCollab extends DocumentSheet {
get rollTraitValOverride(): number | undefined { return this._rollTraitValOverride }
set rollTraitValOverride(val: number | undefined) { this._rollTraitValOverride = val }
get rollTraitData(): NamedValueMax & {gmTooltip?: string, pcTooltip?: string} {
- if (BladesActor.IsType(this.rollSource?.rollSourceDoc, BladesActorType.pc)) {
+ if (BladesActor.IsType(this.rollPrimary?.rollPrimaryDoc, BladesActorType.pc)) {
if (isAction(this.rollTrait)) {
return {
name: this.rollTrait,
- value: this.rollTraitValOverride ?? this.rollSource!.rollSourceDoc.actions[this.rollTrait],
- max: this.rollTraitValOverride ?? this.rollSource!.rollSourceDoc.actions[this.rollTrait],
- pcTooltip: this.rollSource!.rollSourceDoc.rollTraitPCTooltipActions,
+ value: this.rollTraitValOverride ?? this.rollPrimary!.rollPrimaryDoc.actions[this.rollTrait],
+ max: this.rollTraitValOverride ?? this.rollPrimary!.rollPrimaryDoc.actions[this.rollTrait],
+ pcTooltip: this.rollPrimary!.rollPrimaryDoc.rollTraitPCTooltipActions,
gmTooltip: C.ActionTooltipsGM[this.rollTrait]
};
}
if (isAttribute(this.rollTrait)) {
return {
name: this.rollTrait,
- value: this.rollTraitValOverride ?? this.rollSource!.rollSourceDoc.attributes[this.rollTrait],
- max: this.rollTraitValOverride ?? this.rollSource!.rollSourceDoc.attributes[this.rollTrait],
- pcTooltip: this.rollSource!.rollSourceDoc.rollTraitPCTooltipAttributes,
+ value: this.rollTraitValOverride ?? this.rollPrimary!.rollPrimaryDoc.attributes[this.rollTrait],
+ max: this.rollTraitValOverride ?? this.rollPrimary!.rollPrimaryDoc.attributes[this.rollTrait],
+ pcTooltip: this.rollPrimary!.rollPrimaryDoc.rollTraitPCTooltipAttributes,
gmTooltip: C.AttributeTooltips[this.rollTrait]
};
}
@@ -2181,14 +2249,14 @@ class BladesRollCollab extends DocumentSheet {
if (isFactor(this.rollTrait)) {
return {
name: U.tCase(this.rollTrait),
- value: this.rollTraitValOverride ?? this.rollSource?.rollFactors[this.rollTrait]?.value ?? 0,
- max: this.rollTraitValOverride ?? this.rollSource?.rollFactors[this.rollTrait]?.max ?? 10
+ value: this.rollTraitValOverride ?? this.rollPrimary?.rollFactors[this.rollTrait]?.value ?? 0,
+ max: this.rollTraitValOverride ?? this.rollPrimary?.rollFactors[this.rollTrait]?.max ?? 10
};
}
throw new Error(`[get rollTraitData] Invalid rollTrait: '${this.rollTrait}'`);
}
get rollTraitOptions(): Array<{ name: string, value: BladesRollCollab.RollTrait }> {
- if (BladesActor.IsType(this.rollSource, BladesActorType.pc)) {
+ if (BladesActor.IsType(this.rollPrimary, BladesActorType.pc)) {
if (isAction(this.rollTrait)) {
return Object.values(Action)
.map((action) => ({
@@ -2277,10 +2345,13 @@ class BladesRollCollab extends DocumentSheet {
}
_roll?: Roll;
- get roll(): Roll { return (this._roll ??= new Roll(`${this.isRollingZero ? 2 : this.finalDicePool}d6`, {})) }
+ get roll(): Roll {
+ this._roll ??= new Roll(`${this.isRollingZero ? 2 : this.finalDicePool}d6`, {});
+ return this._roll;
+ }
get rollFactors(): Record<"source" | "opposition", Partial>> {
- const sourceFactors: Partial> = Object.fromEntries((Object.entries(this.rollSource?.rollFactors ?? {}) as Array<[Factor, BladesRollCollab.FactorData]>)
+ const sourceFactors: Partial> = Object.fromEntries((Object.entries(this.rollPrimary?.rollFactors ?? {}) as Array<[Factor, BladesRollCollab.FactorData]>)
.map(([factor, factorData]) => [
factor,
{
@@ -2297,7 +2368,7 @@ class BladesRollCollab extends DocumentSheet {
baseVal: 0,
cssClasses: "factor-gold",
isActive: factorData.isActive ?? false,
- isPrimary: factorData.isPrimary ?? factor === Factor.tier ?? false,
+ isPrimary: factorData.isPrimary ?? (factor === Factor.tier),
isDominant: factorData.isDominant ?? false,
highFavorsPC: factorData.highFavorsPC ?? true
};
@@ -2315,8 +2386,6 @@ class BladesRollCollab extends DocumentSheet {
}
});
- // if (!this.rollOpposition) { return {source: sourceFactors, opposition: sourceFactors} }
-
const rollOppFactors = ((this.rollOpposition as any)?.rollFactors as Record | undefined)
?? Object.fromEntries(([
Factor.tier,
@@ -2332,7 +2401,7 @@ class BladesRollCollab extends DocumentSheet {
baseVal: 0,
cssClasses: "factor-gold",
isActive: false,
- isPrimary: factor === Factor.tier ?? false,
+ isPrimary: factor === Factor.tier,
isDominant: false,
highFavorsPC: true
} as BladesRollCollab.FactorData
@@ -2357,7 +2426,7 @@ class BladesRollCollab extends DocumentSheet {
baseVal: 0,
cssClasses: "factor-gold",
isActive: factorData.isActive ?? false,
- isPrimary: factorData.isPrimary ?? factor === Factor.tier ?? false,
+ isPrimary: factorData.isPrimary ?? (factor === Factor.tier),
isDominant: factorData.isDominant ?? false,
highFavorsPC: factorData.highFavorsPC ?? true
};
@@ -2389,31 +2458,19 @@ class BladesRollCollab extends DocumentSheet {
this.rollMods = modsData.map((modData) => new BladesRollMod(modData, this));
- // this.logModStatus();
const initReport: Record>|null>> = {};
/* *** PASS ONE: DISABLE PASS *** */
- // initReport["[PASS 1.0] *** DISABLE PASS ***"] = this.getStatusSummary();
-
- let checkDisableMods = [...this.rollMods];
- // ... Conditional Status Pass
- checkDisableMods = checkDisableMods
- .filter((rollMod) => !rollMod.setConditionalStatus());
- // initReport["[PASS 1.1] Conditional Status Pass"] = this.getStatusChanges();
-
- // ... AutoReveal/AutoEnable Pass
- checkDisableMods = checkDisableMods
- .filter((rollMod) => !rollMod.setAutoStatus());
- // initReport["[PASS 1.2] Auto Status Pass"] = this.getStatusChanges();
-
- // ... Payable Pass
- checkDisableMods = checkDisableMods
+ this.rollMods
+ // ... Conditional Status Pass
+ .filter((rollMod) => !rollMod.setConditionalStatus())
+ // ... AutoReveal/AutoEnable Pass
+ .filter((rollMod) => !rollMod.setAutoStatus())
+ // ... Payable Pass
.filter((rollMod) => !rollMod.setPayableStatus());
- // initReport["[PASS 1.3] Payable Status Pass"] = this.getStatusChanges();
/* *** PASS TWO: FORCE-ON PASS *** */
- // initReport["[PASS 2.0] *** FORCE-ON PASS ***"] = this.getStatusSummary();
const parseForceOnKeys = (mod: BladesRollMod) => {
const holdKeys = mod.effectKeys.filter((key) => /^ForceOn/.test(key));
@@ -2422,8 +2479,8 @@ class BladesRollCollab extends DocumentSheet {
while (holdKeys.length) {
const thisTarget = holdKeys.pop()!.split(/-/)!.pop()!;
if (thisTarget === "BestAction") {
- if (BladesActor.IsType(this.rollSource?.rollSourceDoc, BladesActorType.pc)) {
- this.rollTraitValOverride = Math.max(...Object.values(this.rollSource!.rollSourceDoc.actions));
+ if (BladesActor.IsType(this.rollPrimary?.rollPrimaryDoc, BladesActorType.pc)) {
+ this.rollTraitValOverride = Math.max(...Object.values(this.rollPrimary!.rollPrimaryDoc.actions));
}
continue;
}
@@ -2449,10 +2506,8 @@ class BladesRollCollab extends DocumentSheet {
}
};
this.getActiveRollMods().forEach((rollMod) => parseForceOnKeys(rollMod));
- // initReport["[PASS 2.1] Force-On Pass"] = this.getStatusChanges();
/* *** PASS THREE: PUSH-CHECK PASS *** */
- // initReport["[PASS 3.0] *** PUSH-CHECK PASS ***"] = this.getStatusSummary();
// IF ROLL FORCED ...
if (this.isForcePushed()) {
@@ -2460,7 +2515,6 @@ class BladesRollCollab extends DocumentSheet {
this.getInactivePushMods()
.filter((mod) => !mod.isBasicPush)
.forEach((mod) => { mod.held_status = RollModStatus.ForcedOff });
- // initReport["[PASS 3.1] Forced-Off 'Is-Push' Pass"] = this.getStatusChanges();
}
// ... BY CATEGORY ...
@@ -2473,25 +2527,20 @@ class BladesRollCollab extends DocumentSheet {
bargainMod.held_status = RollModStatus.ForcedOff;
}
}
- // initReport[`[PASS 3.2.${i+1}] {${U.uCase(cat)}}: Force-Off Bargain Pass`] = this.getStatusChanges();
} else {
// Otherwise, hide all Is-Push mods
this.getInactivePushMods(cat)
.filter((mod) => !mod.isBasicPush)
.forEach((mod) => { mod.held_status = RollModStatus.Hidden});
- // initReport[`[PASS 3.2.${i+1}] {${U.uCase(cat)}}: Hide 'Is-Push' Mods`] = this.getStatusChanges();
}
});
/* *** PASS FOUR: Relevancy Pass *** */
- // initReport["[PASS 4] *** RELEVANCY PASS ***"] = this.getStatusSummary();
this.getVisibleRollMods()
.forEach((mod) => { mod.setRelevancyStatus() });
- // initReport["[PASS 4] 1. Relevancy Status Pass"] = this.getStatusChanges();
/* *** PASS FIVE: Overpayment Pass *** */
- // initReport["[PASS 5] *** OVERPAYMENT PASS ***"] = this.getStatusSummary();
// ... If 'Cost-SpecialArmor' active, ForceOff other visible Cost-SpecialArmor mods
const activeArmorCostMod = this.getActiveRollMods().find((mod) => mod.effectKeys.includes("Cost-SpecialArmor"));
@@ -2501,8 +2550,6 @@ class BladesRollCollab extends DocumentSheet {
.forEach((mod) => { mod.held_status = RollModStatus.ForcedOff });
}
- // initReport["[PASS 5.1] Special Armor Force-Off Pass"] = this.getStatusChanges();
-
eLog.checkLog2("rollMods", "*** initRollMods() PASS ***", initReport);
}
@@ -2533,13 +2580,13 @@ class BladesRollCollab extends DocumentSheet {
const effectPush = this.getRollModByID("Push-positive-effect");
const negatePushCostMods = this.getActiveRollMods(RollModCategory.after, "positive")
.filter((mod) => mod.effectKeys.includes("Negate-PushCost"));
- return ((harmPush && harmPush.isActive && harmPush.stressCost) || 0)
- + ((rollPush && rollPush.isActive && rollPush.stressCost) || 0)
- + ((effectPush && effectPush.isActive && effectPush.stressCost) || 0)
+ return ((harmPush?.isActive && harmPush?.stressCost) || 0)
+ + ((rollPush?.isActive && rollPush?.stressCost) || 0)
+ + ((effectPush?.isActive && effectPush?.stressCost) || 0)
- (negatePushCostMods.length * 2);
}
- get rollCostData(): Array<{ id: string, label: string, costType: string, costAmount: number }> {
+ get rollCostData(): BladesRollCollab.CostData[] {
return this.getActiveRollMods()
.map((rollMod) => rollMod.costs ?? [])
.flat();
@@ -2551,7 +2598,7 @@ class BladesRollCollab extends DocumentSheet {
&& (!posNeg || rollMod.posNeg === posNeg));
if (modMatches.length === 0) { return undefined }
if (modMatches.length > 1) {
- // eLog.error("rollMods", `Too Many Mods (${modMatches.length}) Match ${name}/${cat}/${posNeg}: [${modMatches.map((rollMod) => rollMod.id).join(", ")}]`);
+
return undefined;
}
return modMatches[0];
@@ -2633,71 +2680,334 @@ class BladesRollCollab extends DocumentSheet {
// #region *** GETDATA *** ~
- // _lastStatusData: Record = {};
- // logModStatus() {
- // if (!CONFIG.debug.logging) { return }
- // this._lastStatusData = {};
- // this.rollMods.forEach((mod) => {
- // this._lastStatusData[mod.id] = stringifyRollModStatus(mod);
- // });
- // }
- // getStatusSummary() {
- // if (!CONFIG.debug.logging) { return {} }
- // const statusData: Record> = {};
- // this.rollMods.forEach((mod) => {
- // statusData[mod.id] = {
- // mod,
- // ...getRollModStatus(mod)
- // };
- // });
- // return statusData;
- // }
- // getStatusChanges() {
- // if (!CONFIG.debug.logging) { return {} }
- // const statusChanges: Record>|null> = {};
- // this.rollMods.forEach((mod) => {
- // const changeData = compareRollModStatus(mod, this._lastStatusData[mod.id]);
- // if (!U.isEmpty(changeData)) {
- // statusChanges[mod.id] = changeData;
- // }
- // });
- // this.logModStatus();
- // return statusChanges;
- // }
+ /**
+ * Retrieve the data for rendering the base RollCollab sheet.
+ * @returns {Promise