Skip to content

Commit

Permalink
Flow & Microtasks helped me get back into it!
Browse files Browse the repository at this point in the history
  • Loading branch information
Eunomiac committed Oct 30, 2023
1 parent 948f16a commit ac616e6
Show file tree
Hide file tree
Showing 22 changed files with 702 additions and 294 deletions.
151 changes: 111 additions & 40 deletions module/BladesRoll.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,22 @@ function isValidConsequenceData(val, isRecurring = false) {
}
return true;
}
function isParticipantSection(section) {
return [
RollModSection.roll,
RollModSection.position,
RollModSection.effect
].includes(section);
}
function isParticipantSubSection(subSection) {
if (subSection.startsWith("Group_")) {
return true;
}
if (["Assist", "Setup"].includes(subSection)) {
return true;
}
return false;
}
function pruneConfig(cfg) {
return expandObject(U.objFilter(flattenObject(cfg), (v) => !(v instanceof BladesActor) && !(v instanceof BladesItem)));
}
Expand Down Expand Up @@ -164,29 +180,36 @@ class BladesRollMod {
this._heldStatus = val;
}
get flagParams() { return [C.SYSTEM_ID, `rollCollab.rollModsData.${this.id}`]; }
getFlag() { return this.rollInstance.document.getFlag(...this.flagParams); }
get userStatus() {
getUserStatusFlag() {
return this.rollInstance.document.getFlag(...this.flagParams);
}
set userStatus(val) {
async setUserStatusFlag(val) {
if (val === this.userStatus) {
return;
}
if (!val || val === this.baseStatus) {
this.rollInstance.document.unsetFlag(...this.flagParams).then(() => socketlib.system.executeForEveryone("renderRollCollab", this.rollInstance.rollID));
await this.rollInstance.document.unsetFlag(...this.flagParams);
}
else {
if ([RollModStatus.ForcedOn, RollModStatus.ForcedOff, RollModStatus.Hidden].includes(val)
&& !game.user.isGM) {
return;
}
if (this.userStatus
&& [RollModStatus.ForcedOn, RollModStatus.ForcedOff, RollModStatus.Hidden].includes(this.userStatus)
&& !game.user.isGM) {
const lockedToGM = [
RollModStatus.ForcedOn,
RollModStatus.ForcedOff,
RollModStatus.Hidden
];
if (!game.user.isGM
&& (lockedToGM.includes(val)
|| (this.userStatus && lockedToGM.includes(this.userStatus)))) {
return;
}
this.rollInstance.document.setFlag(...this.flagParams, val).then(() => socketlib.system.executeForEveryone("renderRollCollab", this.rollInstance.rollID));
await this.rollInstance.document.setFlag(...this.flagParams, val);
}
await socketlib.system.executeForEveryone("renderRollCollab", this.rollInstance.rollID);
}
get userStatus() {
return this.getUserStatusFlag();
}
set userStatus(val) {
this.setUserStatusFlag(val);
}
get sourceName() { return this._sourceName; }
get isConditional() {
Expand Down Expand Up @@ -453,19 +476,44 @@ class BladesRollMod {
}
});
}
get selectOptions() {
if (this.modType !== "teamwork") {
return null;
}
if (this.name === "Assist" || this.name === "Setup") {
return this.rollInstance.rollParticipantSelectOptions[this.name];
}
else if (this.name.startsWith("Group_")) {
return this.rollInstance.rollParticipantSelectOptions.Group;
}
return null;
}
get selectedParticipant() {
if (this.modType !== "teamwork") {
return null;
}
return this.rollInstance.getRollParticipant(this.section, this.name);
}
get tooltip() {
return this._tooltip.replace(/%COLON%/g, ":")
.replace(/%DOC_NAME%/g, this.sideString ?? "an Ally")
.replace(/@OPPOSITION_NAME@/g, this.rollInstance.rollOpposition?.rollOppName ?? "Your Opposition");
let parsedTooltip = this._tooltip.replace(/%COLON%/g, ":");
if (parsedTooltip.includes("%DOC_NAME%")) {
parsedTooltip = parsedTooltip.replace(/%DOC_NAME%/g, this.selectedParticipant
? this.selectedParticipant.rollParticipantName
: "an Ally");
}
if (parsedTooltip.includes("@OPPOSITION_NAME@")) {
parsedTooltip = parsedTooltip.replace(/@OPPOSITION_NAME@/g, this.rollInstance.rollOpposition
? this.rollInstance.rollOpposition.rollOppName
: "Your Opposition");
}
return parsedTooltip;
}
get sideString() {
if (this._sideString) {
return this._sideString;
}
const rollParticipantCategoryData = this.rollInstance.rollParticipants?.[this.section];
if (rollParticipantCategoryData && this.name in rollParticipantCategoryData) {
const rollParticipant = rollParticipantCategoryData[this.name];
return rollParticipant.rollParticipantName;
if (this.selectedParticipant) {
return this.selectedParticipant.rollParticipantName;
}
return undefined;
}
Expand Down Expand Up @@ -1513,11 +1561,14 @@ class BladesRoll extends DocumentSheet {
const sectionFlagData = participantFlagData[rollSection];
if (sectionFlagData) {
const sectionParticipants = {};
(Object.keys(sectionFlagData)).forEach((participantType) => {
const subSectionFlagData = sectionFlagData[participantType];
Object.entries(sectionFlagData).forEach(([subSection, subSectionFlagData]) => {
if (subSectionFlagData) {
sectionParticipants[participantType] =
new BladesRollParticipant(this, subSectionFlagData);
sectionParticipants[subSection] =
new BladesRollParticipant(this, {
...subSectionFlagData,
rollParticipantSection: rollSection,
rollParticipantSubSection: subSection
});
}
});
rollParticipants[rollSection] = sectionParticipants;
Expand All @@ -1528,6 +1579,25 @@ class BladesRoll extends DocumentSheet {
get rollParticipants() {
return this._rollParticipants;
}
getRollParticipant(section, subSection) {
if (isParticipantSection(section) && isParticipantSubSection(subSection)) {
const sectionData = this.rollParticipants?.[section];
if (sectionData) {
return sectionData[subSection] ?? null;
}
}
return null;
}
get rollParticipantSelectOptions() {
const nonPrimaryPCs = BladesPC.All
.filter((actor) => actor.hasTag(Tag.PC.ActivePC) && actor.id !== this.rollPrimary.rollPrimaryID)
.map((actor) => ({ value: actor.id, display: actor.name }));
return {
Assist: nonPrimaryPCs,
Setup: nonPrimaryPCs,
Group: nonPrimaryPCs
};
}
get rollType() { return this.flagData.rollType; }
get rollSubType() { return this.flagData.rollSubType; }
get rollDowntimeAction() { return this.flagData.rollDowntimeAction; }
Expand Down Expand Up @@ -1770,7 +1840,7 @@ class BladesRoll extends DocumentSheet {
};
const mergedSourceFactors = U.objMerge(U.objMerge(defaultFactors, this.rollPrimary.rollFactors, { isMutatingOk: false }), this.flagData.rollFactorToggles.source, { isMutatingOk: false });
const mergedOppFactors = this.rollOpposition
? U.objMerge(U.objMerge(defaultFactors, this.rollPrimary.rollFactors, { isMutatingOk: false }), this.flagData.rollFactorToggles.opposition, { isMutatingOk: false })
? U.objMerge(U.objMerge(defaultFactors, this.rollOpposition.rollFactors, { isMutatingOk: false }), this.flagData.rollFactorToggles.opposition, { isMutatingOk: false })
: {};
return {
source: Object.fromEntries(Object.entries(mergedSourceFactors)
Expand Down Expand Up @@ -2121,10 +2191,8 @@ class BladesRoll extends DocumentSheet {
diceTotal: finalDicePool,
rollOpposition: this.rollOpposition,
rollParticipants: this.rollParticipants,
rollParticipantOptions: this.rollParticipantSelectOptions,
rollEffects: Object.values(Effect),
teamworkDocs: game.actors
.filter((actor) => actor.hasTag(Tag.PC.ActivePC))
.map((actor) => ({ value: actor.id, display: actor.name })),
rollTraitValOverride: this.rollTraitValOverride,
rollFactorPenaltiesNegated: this.rollFactorPenaltiesNegated,
posRollMods: Object.fromEntries(Object.values(RollModSection)
Expand Down Expand Up @@ -2615,20 +2683,20 @@ class BladesRoll extends DocumentSheet {
await this.document.setFlag(C.SYSTEM_ID, "rollCollab.rollFactorToggles", factorToggleData)
.then(() => socketlib.system.executeForEveryone("renderRollCollab", this.rollID));
}
async _gmControlSelect(event) {
async _onSelectChange(event) {
event.preventDefault();
const elem$ = $(event.currentTarget);
const section = elem$.data("rollSection");
const subSection = elem$.data("rollSubSection");
const selectedOption = elem$.val();
if (typeof selectedOption !== "string") {
return;
const elem = event.currentTarget;
const { docType } = elem.dataset;
if (elem.value !== "" && docType?.startsWith("BladesRollParticipant")) {
const [_, section, subSection] = docType.split(".");
await this.addRollParticipant(elem.value, section, subSection);
}
if (selectedOption === "false") {
await this.document.unsetFlag(C.SYSTEM_ID, `rollCollab.rollParticipantData.${section}.${subSection}`);
else {
await U.EventHandlers.onSelectChange(this, event);
socketlib.system.executeForEveryone("renderRollCollab", this.rollID);
}
await this.addRollParticipant(selectedOption, section, subSection);
}

get resistanceStressCost() {
const dieVals = this.dieVals;
if (this.rollResult === RollResult.critical) {
Expand Down Expand Up @@ -2671,6 +2739,9 @@ class BladesRoll extends DocumentSheet {
html.find("[data-action='roll']").on({
click: () => this.resolveRoll()
});
html
.find("select[data-action='player-select']")
.on({ change: this._onSelectChange.bind(this) });
if (!game.user.isGM) {
return;
}
Expand Down Expand Up @@ -2699,9 +2770,9 @@ class BladesRoll extends DocumentSheet {
html.find("[data-action=\"gm-toggle-factor\"").on({
click: this._gmControlToggleFactor.bind(this)
});
html.find("select[data-action=\"gm-select\"]").on({
change: this._gmControlSelect.bind(this)
});
html
.find("select[data-action='gm-select']")
.on({ change: this._onSelectChange.bind(this) });
}

_canDragDrop() {
Expand Down
6 changes: 5 additions & 1 deletion module/core/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -462,7 +462,11 @@ const C = {
gBLUE: "rgba(128, 185, 255, 1)"
},
Loadout: {
selections: ["BITD.Light", "BITD.Normal", "BITD.Heavy", "BITD.Encumbered"],
selections: [
{ value: "Light", display: "Light" },
{ value: "Normal", display: "Normal" },
{ value: "Heavy", display: "Heavy" }
],
levels: ["BITD.Light", "BITD.Normal", "BITD.Heavy", "BITD.Encumbered", "BITD.OverMax"]
},
AttributeTooltips: {
Expand Down
18 changes: 10 additions & 8 deletions module/core/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export async function preloadHandlebarsTemplates() {
"systems/eunos-blades/templates/components/dotline.hbs",
"systems/eunos-blades/templates/components/armor.hbs",
"systems/eunos-blades/templates/components/comp.hbs",
"systems/eunos-blades/templates/components/select.hbs",
"systems/eunos-blades/templates/components/portrait.hbs",
"systems/eunos-blades/templates/components/clock.hbs",
"systems/eunos-blades/templates/components/roll-collab-mod.hbs",
Expand All @@ -38,9 +39,9 @@ const handlebarHelpers = {
},
test(param1, operator, param2) {
const stringMap = {
"true": true,
"false": false,
"null": null,
true: true,
false: false,
null: null,
undefined
};
if (["!", "not", "=??"].includes(String(param1))) {
Expand Down Expand Up @@ -118,10 +119,10 @@ const handlebarHelpers = {
"*": (p1, p2) => U.pInt(p1) * U.pInt(p2),
"/": (p1, p2) => U.pInt(p1) / U.pInt(p2),
"%": (p1, p2) => U.pInt(p1) % U.pInt(p2),
"max": (p1, p2) => Math.max(U.pInt(p1), U.pInt(p2)),
"min": (p1, p2) => Math.min(U.pInt(p1), U.pInt(p2)),
"ceil": (p1) => Math.ceil(U.pFloat(p1)),
"floor": (p1) => Math.floor(U.pFloat(p1))
max: (p1, p2) => Math.max(U.pInt(p1), U.pInt(p2)),
min: (p1, p2) => Math.min(U.pInt(p1), U.pInt(p2)),
ceil: (p1) => Math.ceil(U.pFloat(p1)),
floor: (p1) => Math.floor(U.pFloat(p1))
};
const [param1, operator, param2] = typeof params[0] === "string" && params[0] in calcs
? [params[1], params[0]]
Expand Down Expand Up @@ -255,7 +256,8 @@ const handlebarHelpers = {
return html;
},
repturf: (turfsAmount, options) => {
let html = options.fn(this), turfsAmountInt = parseInt(turfsAmount, 10);
let html = options.fn(this);
let turfsAmountInt = parseInt(turfsAmount, 10);
if (turfsAmountInt > 6) {
turfsAmountInt = 6;
}
Expand Down
60 changes: 57 additions & 3 deletions module/core/utilities.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,11 @@ const UUIDLOG = [];

const GMID = () => game?.user?.find((user) => user.isGM)?.id ?? false;
const isNumber = (ref) => typeof ref === "number" && !isNaN(ref);
const isNumberString = (ref) => typeof ref === "string"
&& !isNaN(parseFloat(ref))
&& isFinite(parseFloat(ref));
const isBooleanString = (ref) => typeof ref === "string"
&& (ref === "true" || ref === "false");
const isArray = (ref) => Array.isArray(ref);
const isSimpleObj = (ref) => ref === Object(ref) && !isArray(ref);
const isList = (ref) => ref === Object(ref) && !isArray(ref);
Expand Down Expand Up @@ -1170,7 +1175,55 @@ const escapeHTML = (str) => (typeof str === "string"
.replace(/[`']/g, "'")
: str);

const sleep = (duration) => new Promise((resolve) => { setTimeout(resolve, duration >= 100 ? duration : duration * 1000); });
const sleep = (duration) => new Promise((resolve) => {
setTimeout(resolve, duration >= 100 ? duration : duration * 1000);
});
const EventHandlers = {
onSelectChange: async (inst, event) => {
const elem = event.currentTarget;
const { action, dtype, target, flagTarget } = elem.dataset;
if (!action) {
throw new Error("Select elements require a data-action attribute.");
}
if (!target && !flagTarget) {
throw new Error("Select elements require a 'data-target' or 'data-flag-target' attribute.");
}
const dataType = lCase(dtype);
let value;
switch (dataType) {
case "number":
value = pFloat(elem.value);
break;
case "boolean":
value = lCase(`${elem.value}`) === "true";
break;
case "string":
value = `${elem.value}`;
break;
default: {
if (isNumberString(value)) {
throw new Error("You must set 'data-dtype=\"Number\"' for <select> elements with number values.");
}
if (isBooleanString(value)) {
throw new Error("You must set 'data-dtype=\"Boolean\"' for <select> elements with boolean values.");
}
value = `${elem.value}`;
break;
}
}
if (target) {
await inst.document.update({ [target]: value });
}
else if (flagTarget) {
if (elem.value === "") {
await inst.document.unsetFlag(C.SYSTEM_ID, flagTarget);
}
else {
await inst.document.setFlag(C.SYSTEM_ID, flagTarget, value);
}
}
}
};
const isDocID = (docRef, isUUIDok = true) => {
return typeof docRef === "string" && (isUUIDok
? /^(.*\.)?[A-Za-z0-9]{16}$/.test(docRef)
Expand Down Expand Up @@ -1208,7 +1261,7 @@ function displayImageSelector(callback, pathRoot = `systems/${C.SYSTEM_ID}/asset
}
export default {
GMID, getUID,
isNumber, isSimpleObj, isList, isArray, isFunc, isInt, isFloat, isPosInt, isIterable,
isNumber, isNumberString, isBooleanString, isSimpleObj, isList, isArray, isFunc, isInt, isFloat, isPosInt, isIterable,
isHTMLCode, isRGBColor, isHexColor,
isUndefined, isDefined, isEmpty, hasItems, isInstance, isNullish,
areEqual, areFuzzyEqual,
Expand Down Expand Up @@ -1250,5 +1303,6 @@ export default {
getSiblings,
escapeHTML,
sleep,
isDocID, loc, getSetting, getTemplatePath, displayImageSelector
EventHandlers,
isDocID, loc, getSetting, getTemplatePath, displayImageSelector,
};
8 changes: 8 additions & 0 deletions module/sheets/BladesSheet.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/* ****▌███████████████████████████████████████████████████████████████████████████▐**** *\
|* ▌█░░░░░░░░░ Euno's Blades in the Dark for Foundry VTT ░░░░░░░░░░░█▐ *|
|* ▌██████████████████░░░░░░░░░░░░░ by Eunomiac ░░░░░░░░░░░░░██████████████████▐ *|
|* ▌█ License █ v0.1.0 ██▐ *|
|* ▌████░░░░ ░░░░█████▐ *|
\* ****▌███████████████████████████████████████████████████████████████████████████▐**** */

"use strict";
Loading

0 comments on commit ac616e6

Please sign in to comment.