Skip to content

Commit

Permalink
Merge pull request #317 from FoxLee/active-effect-statuses
Browse files Browse the repository at this point in the history
Status Conditions for Active Effects
  • Loading branch information
EndlesNights authored Oct 22, 2023
2 parents 64ef5e6 + 5b4b318 commit d6fd196
Show file tree
Hide file tree
Showing 8 changed files with 204 additions and 37 deletions.
9 changes: 8 additions & 1 deletion lang/en-au.json
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@
"DND4EBETA.ComponentMaterial": "Material",
"DND4EBETA.ComponentSomatic": "Somatic",
"DND4EBETA.ComponentVerbal": "Verbal",
"DND4EBETA.Condition": "Condition",
"DND4EBETA.ConBlinded": "Blinded",
"DND4EBETA.Concentration": "Concentration",
"DND4EBETA.ConCharmed": "Charmed",
Expand Down Expand Up @@ -1060,6 +1061,7 @@
"DND4EBETA.SpokenPrimordial": "Primordial",
"DND4EBETA.SpokenSupernal": "Supernal",
"DND4EBETA.Stance": "Stance",
"DND4EBETA.StatusConditions": "Status Conditions",
"DND4EBETA.SubclassName": "Subclass Name",
"DND4EBETA.SubName": "Class Name Attack 1",
"DND4EBETA.Summoning": "Summoning",
Expand Down Expand Up @@ -1421,12 +1423,15 @@
"EFFECTDESC.hidden": "The creature is hidden or disguised.",
"EFFECTDESC.sneaking": "The creature is being stealthy. It is hidden (invisible and silent) from creatures that fail to detect it.",
"EFFECTDESC.torch": "The creature is holding a light source.",
"DND4EUI.AttributeKey": "Attribute Key",
"ERROR.4eCopyStatusDetails": "Could not copy status details. This is expected if you have changed the standard list of status conditions since adding one to this effect.",
"DND4EUI.AddNew": "Add New",
"DND4EUI.All": "All",
"DND4EUI.AttributeKey": "Attribute Key",
"DND4EUI.Data Type": "Data Type",
"DND4EUI.Delete": "Delete",
"DND4EUI.GroupBy": "Group By",
"DND4EUI.HowSelectMultiple": "Hold ctrl/cmd to select multiple",
"DND4EUI.Icon": "Icon",
"DND4EUI.Import": "Import",
"DND4EUI.ImportJSONInput": "Input JSON to import in the field below",
"DND4EUI.ImportJSONUpload": "Upload JSON",
Expand All @@ -1436,6 +1441,8 @@
"DND4EUI.ShowImage": "Show image",
"DND4EUI.SortBy": "Sort By",
"DND4EUI.StringEnterValues": "Enter values (separate entries with semicolons)",
"DND4EUI.UnknownCondition.Label": "Unknown value",
"DND4EUI.UnknownCondition.Tip": "No match was found for this id in the current status conditions configuration.",
"DND4EUI.Yes": "Yes",
"SETTINGS.4eAutoCollapseCardL": "Automatically collapse Item Card descriptions in the Chat Log",
"SETTINGS.4eAutoCollapseCardN": "Collapse Item Cards in Chat",
Expand Down
14 changes: 13 additions & 1 deletion lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@
"DND4EBETA.ComponentMaterial": "Material",
"DND4EBETA.ComponentSomatic": "Somatic",
"DND4EBETA.ComponentVerbal": "Verbal",
"DND4EBETA.Condition": "Condition",
"DND4EBETA.ConBlinded": "Blinded",
"DND4EBETA.Concentration": "Concentration",
"DND4EBETA.ConCharmed": "Charmed",
Expand Down Expand Up @@ -1060,6 +1061,7 @@
"DND4EBETA.SpokenPrimordial": "Primordial",
"DND4EBETA.SpokenSupernal": "Supernal",
"DND4EBETA.Stance": "Stance",
"DND4EBETA.StatusConditions": "Status Conditions",
"DND4EBETA.SubclassName": "Subclass Name",
"DND4EBETA.SubName": "Class Name Attack 1",
"DND4EBETA.Summoning": "Summoning",
Expand All @@ -1078,6 +1080,8 @@
"DND4EBETA.Sustain": "Sustain",
"DND4EBETA.Target": "Target",
"DND4EBETA.TargetAll": "Affect All Targets",
"DND4EBETA.TargetAllies": "Affect All Allies",
"DND4EBETA.TargetEnemies": "Affect All Enemies",
"DND4EBETA.TargetHit": "Affect Hit Targets",
"DND4EBETA.TargetMiss": "Affect Miss Targets",
"DND4EBETA.TargetSelf": "Affect Self",
Expand Down Expand Up @@ -1419,12 +1423,15 @@
"EFFECTDESC.hidden": "The creature is hidden or disguised.",
"EFFECTDESC.sneaking": "The creature is being stealthy. It is hidden (invisible and silent) from creatures that fail to detect it.",
"EFFECTDESC.torch": "The creature is holding a light source.",
"DND4EUI.AttributeKey": "Attribute Key",
"ERROR.4eCopyStatusDetails": "Could not copy status details. This is expected if you have changed the standard list of status conditions since adding one to this effect.",
"DND4EUI.AddNew": "Add New",
"DND4EUI.All": "All",
"DND4EUI.AttributeKey": "Attribute Key",
"DND4EUI.Data Type": "Data Type",
"DND4EUI.Delete": "Delete",
"DND4EUI.GroupBy": "Group By",
"DND4EUI.HowSelectMultiple": "Hold ctrl/cmd to select multiple",
"DND4EUI.Icon": "Icon",
"DND4EUI.Import": "Import",
"DND4EUI.ImportJSONInput": "Input JSON to import in the field below",
"DND4EUI.ImportJSONUpload": "Upload JSON",
Expand All @@ -1434,6 +1441,8 @@
"DND4EUI.ShowImage": "Show image",
"DND4EUI.SortBy": "Sort By",
"DND4EUI.StringEnterValues": "Enter values (separate entries with semicolons)",
"DND4EUI.Unknown": "Unknown value",
"DND4EUI.UnknownCondition.Tip": "No match was found for this id in the current status conditions configuration.",
"DND4EUI.Yes": "Yes",
"SETTINGS.4eAutoCollapseCardL": "Automatically collapse Item Card descriptions in the Chat Log",
"SETTINGS.4eAutoCollapseCardN": "Collapse Item Cards in Chat",
Expand Down Expand Up @@ -1496,6 +1505,9 @@
"MIGRATION.4eBegin": "Applying DnD4E System Migration for version {version}. Please be patient and do not close your game or shut down your server.",
"MIGRATION.4eComplete": "DnD4E System Migration to version {version} completed!",
"MIGRATION.4eVersionTooOldWarning": "Your DnD4e system data is from too old a Foundry version and cannot be reliably migrated to the latest version. The process will be attempted, but errors may occur.",
"SHEET.Character.Basic": "Basic Character Sheet",
"SHEET.NPC": "NPC Sheet",
"SHEET.Item": "Item Sheet",
"TYPES.Actor.NPC": "NPC",
"TYPES.Actor.Player Character": "Player Character",
"TYPES.Item.backpack": "Container",
Expand Down
80 changes: 74 additions & 6 deletions module/effects/effects-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export default class ActiveEffectConfig4e extends ActiveEffectConfig {

data.config = CONFIG.DND4EBETA;
data.powerParent = (["power", "consumable"].includes(this.object.parent.type));
data.config.statusEffects = CONFIG.statusEffects;

return data;
}
Expand All @@ -29,6 +30,7 @@ export default class ActiveEffectConfig4e extends ActiveEffectConfig {
activateListeners(html) {
super.activateListeners(html);
html.find(".effect-dot-control").click(this._onEffectDotControl.bind(this));
html.find(".effect-status-control").click(this._onEffectStatusControl.bind(this));
html.find(".refreshes").change(this._refresh.bind(this));
}

Expand All @@ -53,6 +55,31 @@ export default class ActiveEffectConfig4e extends ActiveEffectConfig {

/* ----------------------------------------- */

/**
* Handling for mouse clicks on status control buttons - adapted from _onEffectControl
* Delegate responsibility out to action-specific handlers depending on the button action.
* @param {MouseEvent} event The originating click event
*/
_onEffectStatusControl(event) {
event.preventDefault();
const button = event.currentTarget;
switch ( button.dataset.action ) {
case "copy-name":
case "copy-icon":
case "copy-desc":
case "copy-all":
const statusId = button.closest(".effect-status").getAttribute("data-status-id");
return this._copyStatusDetails(statusId,button.dataset.action).then(() => this.render());
case "add":
return this._addEffectStatus();
case "delete":
button.closest(".effect-status").remove();
return this.submit({preventClose: true}).then(() => this.render());
}
}

/* ----------------------------------------- */

/**
* Handle adding a new dot to the dots array - adapted from _addEffectChange
*/
Expand All @@ -64,6 +91,51 @@ export default class ActiveEffectConfig4e extends ActiveEffectConfig {
}});
}

/* ----------------------------------------- */

/**
* Handle adding a new status to the statuses array - adapted from _addEffectChange
*/
async _addEffectStatus() {
const i = this.document.statuses.size;
return this.submit({preventClose: true, updateData: {
[`statuses.${i}`] : "none"
}});
}

/* ----------------------------------------- */

/**
* Copy fluff to effect from status condition config
*/
async _copyStatusDetails(statusId,scope="copy-all") {
if(!statusId) return;

const statuses = CONFIG.statusEffects;

try{
//I remembered error handling this time! This should be expected to fail if the status id isn't found, such as if you have remapped your conditions since setting up the effect.

const statusIndex = statuses.findIndex((x) => x.id == statusId);
let effectUpdates = {};

if(scope == "copy-name" || scope == "copy-all"){
effectUpdates.name = game.i18n.localize(statuses[statusIndex].label);
}
if(scope == "copy-icon" || scope == "copy-all"){
effectUpdates.icon = statuses[statusIndex].icon;
}
if(scope == "copy-desc" || scope == "copy-all"){
effectUpdates.description = game.i18n.localize(statuses[statusIndex].description);
}

return this.submit({preventClose: true, updateData: effectUpdates });

} catch(err) {
ui.notifications.error(game.i18n.localize('ERROR.4eCopyStatusDetails'));
}
}

/* ----------------------------------------- */
/* I'm really worried that I had to override this method from the core class.
I'm afraid it might mess up module compatibility or something!
Expand All @@ -74,18 +146,14 @@ export default class ActiveEffectConfig4e extends ActiveEffectConfig {
let data = foundry.utils.expandObject(fd.object);
if ( updateData ) foundry.utils.mergeObject(data, updateData);
data.changes = Array.from(Object.values(data.changes || {}));
data.statuses = Array.from(Object.values(data.statuses || {})).filter(x => x);
//The form throws an error if it's updated while there is an unselected status condition row. I can't find a way to catch it, so instead I'm just trimming

data.flags.dnd4e.dots = Array.from(Object.values(data.flags.dnd4e.dots || {}));
if (data.flags.dnd4e.dots.length){
for (let [i, dot] of data.flags.dnd4e.dots.entries()){
data.flags.dnd4e.dots[i].amount = dot.amount;
data.flags.dnd4e.dots[i].typesArray = dot.typesArray.sort();
/*if(!dot.type) {
data.flags.dnd4e.dots[i].typesArray = ['physical'];
} else {
let type = dot.type.toLowerCase().replaceAll(/( and )|(;(?! ))|(; )|(, )|(,(?! ))|([^;,]) (?!and)/g,"$6|");
data.flags.dnd4e.dots[i].typesArray = type.split("|").sort();
}*/
}
}

Expand Down
24 changes: 22 additions & 2 deletions module/helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -1252,6 +1252,26 @@ export async function handleAutoDoTs(data) {
await actor.autoDoTsSocket(data.tokenID);
}

Handlebars.registerHelper('contains', function(lunch, lunchbox) {
return lunchbox.includes(lunch);
/* "Contains" Handlebars Helper: checks if a value exists in an array.
*
* @param {String} lunch The value to find
* @param {Array} lunchbox The array to search
* @param {String} meal (optional) A key to pair with lunch
* @returns {boolean} true if lunch exists in lunchbox.
* If meal is provided, lunchbox is assumed to contain objects,
* and will search for one where meal = lunch.
*
* I don't know why, but meal is apparently the helper object,
* if not given? Not a null, which would have been useful :\
* Anyway the type check shoudl take care of it.
/* */
Handlebars.registerHelper('contains', function(lunch, lunchbox, meal) {
try{
if(typeof meal != "string") return lunchbox.includes(lunch);
const lunchLocation = lunchbox.findIndex((x) => x[meal] == lunch);
if(lunchLocation > 0) return true;
return false;
} catch(err) {
return "Contains helper spat up. Did you give it the right parameter types?";
}
});
20 changes: 10 additions & 10 deletions styles/dnd4eBeta-DarkMode.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
--color-text-light-primary:#c9c7b8;
--color-text-light-heading:#e9e7d6;
--color-text-light-highlight:#f7f5e8;
--color-text-good:#0fe75f;
--color-text-bad:#ff6060;
}
input::placeholder,.placeholder::after{
color:var(--color-text-light-primary);
Expand Down Expand Up @@ -176,6 +178,11 @@ img[src$="svg"].rollable:hover{
.dnd4eBeta.sheet .npc .sheet-header .automath img{
filter:unset;
}
.active-effect-sheet .effect-dot:not(:last-child),
.active-effect-sheet .effect-status:not(:last-child),
.active-effect-sheet .effect-change:not(:last-child){
border-bottom:1px solid rgba(255,255,255,0.1);
}

/** CHAT **/

Expand All @@ -186,18 +193,11 @@ a.content-link, a.inline-roll{
background:var(--color-bg-input);
border-color:var(--color-border-light-tertiary);
}
.dice-roll .hit-prediction.critical,
.dice-roll .hit-prediction.probable-hit,
.dot-report .damage-taken.resistant-full,
.dot-report .damage-taken.healing{
color:#0fe75f;
}
.dice-roll .hit-prediction.fumble,
.dice-roll .hit-prediction.probable-miss,
.dot-report .damage-taken:not(.resistant-full,.healing){
color:#ff6060;
.chat-message.whisper{
background:rgba(219,219,251,0.23);
}


/** JOURNALS **/

.sheet.journal-entry .journal-entry-content{
Expand Down
42 changes: 31 additions & 11 deletions styles/dnd4eBeta.css
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ textarea{
--color-bg-input:rgba(0,0,0,0.075);
--color-bg-select:rgba(0,0,0,0.075);
--color-label:var(--color-text-dark-secondary);
--color-text-good:green;
--color-text-bad:red;
--gradient-4e:linear-gradient(90deg, #c3c2b7, #c3c2b718);
--background-atwill:-o-linear-gradient(45deg, #125f15, #55aa2e);
--background-atwill:linear-gradient(45deg, #125f15, #55aa2e);
Expand Down Expand Up @@ -413,7 +415,7 @@ textarea{
margin-left:15px;
border-right:var(--border-heavy);
height:100%;
/* overflow-y:auto; */
overflow-y:auto;
}
.dnd4eBeta .section--abilities{
margin-right:15px;
Expand Down Expand Up @@ -464,8 +466,6 @@ textarea{
.dnd4eBeta .section--skills{
margin-right:15px;
margin-top:10px;
overflow-y: auto;
height:calc(100% - 195px);
}
.dnd4eBeta .section--skills .skill--block{
min-height:27px;
Expand Down Expand Up @@ -2184,18 +2184,38 @@ font-size:12px;
.active-effect-sheet .effects-header>:first-child{
padding-left:4px;
}
.active-effect-sheet .dots-list{
.active-effect-sheet .dots-list,
.active-effect-sheet .statuses-list{
list-style:none;
margin:0;
padding:0;
margin-bottom:2em;
}
.active-effect-sheet .effect-dot{
.active-effect-sheet .effect-dot,
.active-effect-sheet .effect-status{
align-items:center;
padding:3px 1px;
}
.active-effect-sheet .effect-dot:not(:last-child){
border-bottom:1px solid var(--color-border-light-primary);
.active-effect-sheet .effect-dot:not(:last-child),
.active-effect-sheet .effect-status:not(:last-child),
.active-effect-sheet .effect-change:not(:last-child){
border-bottom:1px solid rgba(0,0,0,0.1);
}
.active-effect-sheet .effect-status .status-select{
flex-basis:8.5em;
margin-right:4px;
}
.active-effect-sheet .effect-status .status-controls{
flex-basis:19.5em;
}
.active-effect-sheet .effect-status .status-select select{
width:100%;
}
.active-effect-sheet .effect-status button{
border-radius:3px;
font-size:80%;
line-height:1;
padding:0.5em;
}


Expand Down Expand Up @@ -2612,10 +2632,10 @@ span.flavor-text.probable-miss{
border:1px solid #6e0000;
}
.dice-roll .dice-total.critical{
color:green;
color:var(--color-text-good);
}
.dice-roll .dice-total.fumble{
color:red;
color:var(--color-text-bad);
}
.dice-roll .hit-prediction::before{
content:"\1F894";
Expand All @@ -2625,13 +2645,13 @@ span.flavor-text.probable-miss{
.dice-roll .hit-prediction.fumble,
.dice-roll .hit-prediction.probable-miss,
.dot-report .damage-taken:not(.resistant-full,.healing){
color:red;
color:var(--color-text-bad);
}
.dice-roll .hit-prediction.critical,
.dice-roll .hit-prediction.probable-hit,
.dot-report .damage-taken.resistant-full,
.dot-report .damage-taken.healing{
color:green;
color:var(--color-text-good);
}
.dot-report .damage-taken{
font-weight:bold;
Expand Down
Loading

0 comments on commit d6fd196

Please sign in to comment.