diff --git a/MaterialDeck.js b/MaterialDeck.js
index 76c9856..f4568f0 100644
--- a/MaterialDeck.js
+++ b/MaterialDeck.js
@@ -85,13 +85,13 @@ async function analyzeWSmessage(msg){
const event = data.event;
const context = data.context;
const coordinates = data.payload.coordinates;
- if (coordinates == undefined) coordinates = 0;
const settings = data.payload.settings;
if (data.data == 'init'){
}
if (event == 'willAppear' || event == 'didReceiveSettings'){
+ if (coordinates == undefined) return;
streamDeck.setScreen(action);
streamDeck.setContext(action,context,coordinates,settings);
@@ -118,6 +118,7 @@ async function analyzeWSmessage(msg){
}
else if (event == 'willDisappear'){
+ if (coordinates == undefined) return;
streamDeck.clearContext(action,coordinates,context);
}
@@ -488,6 +489,16 @@ Hooks.on('NotYourTurn', ()=>{
externalModules.updateAll();
})
+Hooks.on('pseudoclockSet', ()=>{
+ if (enableModule == false || ready == false) return;
+ externalModules.updateAll();
+})
+
+Hooks.on('about-time.clockRunningStatus', ()=>{
+ if (enableModule == false || ready == false) return;
+ externalModules.updateAll();
+})
+
Hooks.once('init', ()=>{
//CONFIG.debug.hooks = true;
registerSettings(); //in ./src/settings.js
diff --git a/changelog.md b/changelog.md
index e089b1b..4664f00 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,4 +1,32 @@
# Changelog Material Deck Module
+## v1.3.2 - 11-03-2021
+Additions:
+
+- Added support for the Multi Action provided by the SD app
+- External Modules Action => Added support for About Time
+- Token Action => Stats: Added 'Ability Scores', 'Ability Score Modifiers', 'Ability Score Saves' (dnd5e only) and 'Proficiency Bonus'
+- Token Action => Stats: Added 'HP (box)' option that displays a box with color that changes depending on the HP
+- Move Action: You can now choose what token should be moved, similar to the Token Action
+
+
+Fixes:
+
+- Playlist Action => Relative Offset: Fixed issue with displaying the target playlist name
+- Macro Action: Fixed Hotbar Uses for Shadow of the Demonlord
+
+
+Other:
+
+- Macro Action: Improved the way Hotbar Uses are displayed, it is now displayed in a box similar to how the module looks in Foundry
+- Made the way images are generated more flexible to make future additions easier
+
+
+
+
+Compatible server app and SD plugin:
+Material Server v1.0.2 (unchanged): https://github.com/CDeenen/MaterialServer/releases
+SD plugin v1.3.2 (must be updated!): https://github.com/CDeenen/MaterialDeck_SD/releases
+
### v1.3.1 - 27-02-2021
Additions:
@@ -31,7 +59,7 @@ Additions:
- External Modules => Added support for the 'Shared Vision' module
- External Modules => Added support for the 'Lock View' module
- External Modules => Added support for the 'Not Your Turn' module
-
Fixes:
- Token Action => OnClick: Fixed conditions for pf1e and dnd3.5e
diff --git a/lang/en.json b/lang/en.json
index 9eb6784..bb0f05d 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -168,6 +168,12 @@
"MaterialDeck.Perm.TOKEN.NON_OWNED.label": "Non-Owned and Non-Observer Tokens",
"MaterialDeck.Perm.TOKEN.NON_OWNED.hint": "Allow users access to tokens with non-owned or limited permission",
"MaterialDeck.Perm.TOKEN.OBSERVER.label": "Observer",
- "MaterialDeck.Perm.TOKEN.OBSERVER.hint": "Allow users access to tokens with observer permission"
+ "MaterialDeck.Perm.TOKEN.OBSERVER.hint": "Allow users access to tokens with observer permission",
+
+ "MaterialDeck.AboutTime.First": "st",
+ "MaterialDeck.AboutTime.Second": "nd",
+ "MaterialDeck.AboutTime.Third": "rd",
+ "MaterialDeck.AboutTime.Fourth": "th",
+ "MaterialDeck.AboutTime.Of": "of"
}
diff --git a/module.json b/module.json
index 76dc7b5..5310980 100644
--- a/module.json
+++ b/module.json
@@ -2,8 +2,8 @@
"name": "MaterialDeck",
"title": "Material Deck",
"description": "Material Deck allows you to control Foundry using an Elgato Stream Deck",
- "version": "1.3.1",
- "minimumSDversion": "1.3.1",
+ "version": "1.3.2",
+ "minimumSDversion": "1.3.2",
"minimumMSversion": "1.0.2",
"author": "CDeenen",
"esmodules": [
diff --git a/src/combattracker.js b/src/combattracker.js
index 543d076..19f5cc9 100644
--- a/src/combattracker.js
+++ b/src/combattracker.js
@@ -44,12 +44,12 @@ export class CombatTracker{
return;
}
else {
- streamDeck.setIcon(context,src,background);
+ streamDeck.setIcon(context,src,{background:background});
streamDeck.setTitle(txt,context);
}
}
else {
- streamDeck.setIcon(context,src,background);
+ streamDeck.setIcon(context,src,{background:background});
streamDeck.setTitle(txt,context);
}
}
@@ -63,7 +63,7 @@ export class CombatTracker{
tokenControl.pushData(tokenId,settings,context);
}
else {
- streamDeck.setIcon(context,src,background);
+ streamDeck.setIcon(context,src,{background:background});
streamDeck.setTitle(txt,context);
}
}
@@ -125,7 +125,7 @@ export class CombatTracker{
if (txt != "") txt += "\n";
if (settings.displayTurn) txt += "Turn\n"+turn;
}
- streamDeck.setIcon(context,src,background);
+ streamDeck.setIcon(context,src,{background:background});
streamDeck.setTitle(txt,context);
}
}
@@ -164,7 +164,7 @@ export class CombatTracker{
src = "modules/MaterialDeck/img/combattracker/stopcombat.png";
background = "#FF0000";
}
- streamDeck.setIcon(context,src,background);
+ streamDeck.setIcon(context,src,{background:background});
return;
}
if (game.combat.started == false) return;
diff --git a/src/external.js b/src/external.js
index 71f9184..0349e72 100644
--- a/src/external.js
+++ b/src/external.js
@@ -30,6 +30,7 @@ export class ExternalModules{
else if (module == 'mookAI') this.updateMookAI(settings,context);
else if (module == 'notYourTurn') this.updateNotYourTurn(settings,context);
else if (module == 'lockView') this.updateLockView(settings,context);
+ else if (module == 'aboutTime') this.updateAboutTime(settings,context);
}
keyPress(settings,context){
@@ -43,7 +44,7 @@ export class ExternalModules{
else if (module == 'mookAI') this.keyPressMookAI(settings,context);
else if (module == 'notYourTurn') this.keyPressNotYourTurn(settings,context);
else if (module == 'lockView') this.keyPressLockView(settings,context);
-
+ else if (module == 'aboutTime') this.keyPressAboutTime(settings,context);
}
getModuleEnable(moduleId){
@@ -124,8 +125,8 @@ export class ExternalModules{
name = game.i18n.localize("MaterialDeck.FxMaster.Clear");
}
- if (displayIcon) streamDeck.setIcon(context,icon,background,ring,ringColor);
- else streamDeck.setIcon(context, "", background,ring,ringColor);
+ if (displayIcon) streamDeck.setIcon(context,icon,{background:background,ring:ring,ringColor:ringColor});
+ else streamDeck.setIcon(context, "", {background:background,ring:ring,ringColor:ringColor});
if (displayName == 0) name = "";
streamDeck.setTitle(name,context);
}
@@ -269,7 +270,7 @@ export class ExternalModules{
if (this.gmScreenOpen) ring = 2;
if (settings.displayGmScreenIcon) src = "fas fa-book-reader";
- streamDeck.setIcon(context,src,background,ring,ringColor);
+ streamDeck.setIcon(context,src,{background:background,ring:ring,ringColor:ringColor});
if (settings.displayGmScreenName) txt = game.i18n.localize(`GMSCR.gmScreen.Open`);
streamDeck.setTitle(txt,context);
}
@@ -295,8 +296,8 @@ export class ExternalModules{
const ringColor = game.settings.get("trigger-happy", "enableTriggers") ? "#A600FF" : "#340057";
let txt = '';
- if (displayIcon) streamDeck.setIcon(context,"fas fa-grin-squint-tears",background,2,ringColor);
- else streamDeck.setIcon(context,'','#000000');
+ if (displayIcon) streamDeck.setIcon(context,"fas fa-grin-squint-tears",{background:background,ring:2,ringColor:ringColor});
+ else streamDeck.setIcon(context,'',{background:'#000000'});
if (displayName) txt = 'Trigger Happy';
streamDeck.setTitle(txt,context);
@@ -336,8 +337,8 @@ export class ExternalModules{
const ringColor = game.settings.get("SharedVision", "enable") ? "#A600FF" : "#340057";
let txt = '';
- if (displayIcon) streamDeck.setIcon(context,"fas fa-eye",background,2,ringColor);
- else streamDeck.setIcon(context,'','#000000');
+ if (displayIcon) streamDeck.setIcon(context,"fas fa-eye",{background:background,ring:2,ringColor:ringColor});
+ else streamDeck.setIcon(context,'',{background:'#000000'});
if (displayName) txt = 'Shared Vision';
streamDeck.setTitle(txt,context);
}
@@ -366,8 +367,8 @@ export class ExternalModules{
const background = "#000000";
let txt = '';
- if (displayIcon) streamDeck.setIcon(context,"fas fa-brain",'#000000');
- else streamDeck.setIcon(context,'','#000000');
+ if (displayIcon) streamDeck.setIcon(context,"fas fa-brain",{background:'#000000'});
+ else streamDeck.setIcon(context,'',{background:'#000000'});
if (displayName) txt = 'Mook AI';
streamDeck.setTitle(txt,context);
}
@@ -408,8 +409,8 @@ export class ExternalModules{
txt = "Block Non-Combat Movement";
ringColor = game.settings.get('NotYourTurn','nonCombat') ? "#A600FF": "#340057" ;
}
- if (displayIcon) streamDeck.setIcon(context,icon,background,2,ringColor);
- else streamDeck.setIcon(context,'','#000000');
+ if (displayIcon) streamDeck.setIcon(context,icon,{background:background,ring:2,ringColor:ringColor});
+ else streamDeck.setIcon(context,'',{background:'#000000'});
if (displayName == false) txt = '';
streamDeck.setTitle(txt,context);
}
@@ -431,6 +432,7 @@ export class ExternalModules{
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Lock View
//////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
updateLockView(settings,context) {
if (this.getModuleEnable("LockView") == false) return;
@@ -461,8 +463,8 @@ export class ExternalModules{
ringColor = canvas.scene.getFlag('LockView', 'boundingBox') ? "#A600FF": "#340057" ;
}
- if (displayIcon) streamDeck.setIcon(context,icon,background,2,ringColor);
- else streamDeck.setIcon(context,'','#000000');
+ if (displayIcon) streamDeck.setIcon(context,icon,{background:background,ring:2,ringColor:ringColor});
+ else streamDeck.setIcon(context,'',{background:'#000000'});
if (displayName == false) txt = '';
streamDeck.setTitle(txt,context);
}
@@ -483,6 +485,217 @@ export class ExternalModules{
Hooks.call("setLockView",msg);
}
+
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ //About Time
+ //////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ updateAboutTime(settings,context) {
+ if (this.getModuleEnable("about-time") == false) return;
+ if (game.user.isGM == false) return;
+
+ const displayTime = settings.aboutTimeDisplayTime ? settings.aboutTimeDisplayTime : 'none';
+ const displayDate = settings.aboutTimeDisplayDate ? settings.aboutTimeDisplayDate : 'none';
+ const background = settings.aboutTimeBackground ? settings.aboutTimeBackground : '#000000';
+ const ringOffColor = settings.aboutTimeOffRing ? settings.aboutTimeOffRing : '#000000';
+ const ringOnColor = settings.aboutTimeOnRing ? settings.aboutTimeOnRing : '#00FF00';
+
+ let ring = 0;
+ let ringColor = '#000000';
+ let txt = '';
+ let currentTime = game.Gametime.DTNow().longDateExtended();
+ let clock = 'none';
+
+ if (displayTime == 'clock') {
+ const hours = currentTime.hour > 12 ? currentTime.hour-12 : currentTime.hour;
+ clock = {
+ hours: hours,
+ minutes: currentTime.minute
+ }
+ }
+ else if (displayTime != 'none') {
+ let hours;
+ let AMPM = "";
+ if ((displayTime == 'compact12h' || displayTime == 'full12h' || displayTime == 'hours12h') && currentTime.hour > 12) {
+ hours = currentTime.hour - 12;
+ AMPM = " PM";
+ }
+ else if ((displayTime == 'compact12h' || displayTime == 'full12h' || displayTime == 'hours12h') && currentTime.hour <= 12) {
+ hours = currentTime.hour;
+ AMPM = " AM";
+ }
+ else {
+ hours = currentTime.hour;
+ }
+ if (displayTime == 'hours24h' || displayTime == 'hours12h') txt = hours;
+ else if (displayTime == 'minutes') txt = currentTime.minute;
+ else if (displayTime == 'seconds') txt = currentTime.second;
+ else {
+ if (currentTime.minute < 10) currentTime.minute = '0' + currentTime.minute;
+ if (currentTime.second < 10) currentTime.second = '0' + currentTime.second;
+ txt += hours + ':' + currentTime.minute;
+ if (displayTime == 'full24h' || displayTime == 'full12h') txt += ':' + currentTime.second;
+ }
+ if (displayTime == 'compact12h' || displayTime == 'full12h' || displayTime == 'hours12h') txt += AMPM;
+ }
+ if (displayTime != 'none' && displayTime != 'clock' && displayDate != 'none') txt += '\n';
+
+ if (displayDate == 'day') txt += currentTime.day;
+ else if (displayDate == 'dayName') txt += currentTime.dowString;
+ else if (displayDate == 'month') txt += currentTime.month;
+ else if (displayDate == 'monthName') txt += currentTime.monthString;
+ else if (displayDate == 'year') txt += currentTime.year;
+ else if (displayDate == 'small') txt += currentTime.day + '-' + currentTime.month;
+ else if (displayDate == 'smallInv') txt += currentTime.month + '-' + currentTime.day;
+ else if (displayDate == 'full') txt += currentTime.day + '-' + currentTime.month + '-' + currentTime.year;
+ else if (displayDate == 'fullInv') txt += currentTime.month + '-' + currentTime.day + '-' + currentTime.year;
+ else if (displayDate == 'text' || displayDate == 'textDay') {
+
+ if (displayDate == 'textDay') txt += currentTime.dowString + ' ';
+ txt += currentTime.day;
+ if (currentTime.day % 10 == 1 && currentTime != 11) txt += game.i18n.localize("MaterialDeck.AboutTime.First");
+ else if (currentTime.day % 10 == 2 && currentTime != 12) txt += game.i18n.localize("MaterialDeck.AboutTime.Second");
+ else if (currentTime.day % 10 == 3 && currentTime != 13) txt += game.i18n.localize("MaterialDeck.AboutTime.Third");
+ else txt += game.i18n.localize("MaterialDeck.AboutTime.Fourth");
+ txt += ' ' + game.i18n.localize("MaterialDeck.AboutTime.Of") + ' ' + currentTime.monthString + ', ' + currentTime.year;
+ }
+
+ if (settings.aboutTimeActive) {
+ const clockRunning = game.Gametime.isRunning();
+ ringColor = clockRunning ? ringOnColor : ringOffColor;
+ ring = 2;
+ }
+
+ streamDeck.setTitle(txt,context);
+ streamDeck.setIcon(context,'',{background:background,ring:ring,ringColor:ringColor, clock:clock});
+ }
+
+ keyPressAboutTime(settings,context) {
+ if (this.getModuleEnable("about-time") == false) return;
+ if (game.user.isGM == false) return;
+
+ const onClick = settings.aboutTimeOnClick ? settings.aboutTimeOnClick : 'none';
+ if (onClick == 'none') return;
+ else if (onClick == 'startStop') {
+ const clockRunning = game.Gametime.isRunning();
+ const startMode = settings.aboutTimeStartStopMode ? settings.aboutTimeStartStopMode : 'toggle';
+ if ((startMode == 'toggle' && clockRunning) || startMode == 'stop') game.Gametime.stopRunning();
+ else if ((startMode == 'toggle' && !clockRunning) || startMode == 'start') game.Gametime.startRunning();
+ }
+ else if (onClick == 'advance') {
+ const advanceMode = settings.aboutTimeAdvanceMode ? settings.aboutTimeAdvanceMode : 'dawn';
+ let now = Gametime.DTNow();
+ if (advanceMode == 'dawn') {
+ let newDT = now.add({
+ days: now.hours < 7 ? 0 : 1
+ }).setAbsolute({
+ hours: 7,
+ minutes: 0,
+ seconds: 0
+ });
+ Gametime.setAbsolute(newDT);
+ }
+ else if (advanceMode == 'noon') {
+ let newDT = now.add({
+ days: now.hours < 12 ? 0 : 1
+ }).setAbsolute({
+ hours: 12,
+ minutes: 0,
+ seconds: 0
+ });
+ Gametime.setAbsolute(newDT);
+ }
+ else if (advanceMode == 'dusk') {
+ let newDT = now.add({
+ days: now.hours < 20 ? 0 : 1
+ }).setAbsolute({
+ hours: 20,
+ minutes: 0,
+ seconds: 0
+ });
+ Gametime.setAbsolute(newDT);
+ }
+ else if (advanceMode == 'midnight') {
+ let newDT = Gametime.DTNow().add({
+ days: 1
+ }).setAbsolute({
+ hours: 0,
+ minutes: 0,
+ seconds: 0
+ });
+ Gametime.setAbsolute(newDT);
+ }
+ else if (advanceMode == '1s')
+ game.Gametime.advanceClock(1);
+ else if (advanceMode == '30s')
+ game.Gametime.advanceClock(30);
+
+ else if (advanceMode == '1m')
+ game.Gametime.advanceTime({ minutes: 1 });
+ else if (advanceMode == '5m')
+ game.Gametime.advanceTime({ minutes: 5 });
+ else if (advanceMode == '15m')
+ game.Gametime.advanceTime({ minutes: 15 });
+ else if (advanceMode == '1h')
+ game.Gametime.advanceTime({ hours: 1 });
+ }
+ else if (onClick == 'recede') {
+ const advanceMode = settings.aboutTimeAdvanceMode ? settings.aboutTimeAdvanceMode : 'dawn';
+ let now = Gametime.DTNow();
+ if (advanceMode == 'dawn') {
+ let newDT = now.add({
+ days: now.hours < 7 ? -1 : 0
+ }).setAbsolute({
+ hours: 7,
+ minutes: 0,
+ seconds: 0
+ });
+ Gametime.setAbsolute(newDT);
+ }
+ else if (advanceMode == 'noon') {
+ let newDT = now.add({
+ days: now.hours < 12 ? -1 : 0
+ }).setAbsolute({
+ hours: 12,
+ minutes: 0,
+ seconds: 0
+ });
+ Gametime.setAbsolute(newDT);
+ }
+ else if (advanceMode == 'dusk') {
+ let newDT = now.add({
+ days: now.hours < 20 ? -1 : 0
+ }).setAbsolute({
+ hours: 20,
+ minutes: 0,
+ seconds: 0
+ });
+ Gametime.setAbsolute(newDT);
+ }
+ else if (advanceMode == 'midnight') {
+ let newDT = Gametime.DTNow().add({
+ days: -1
+ }).setAbsolute({
+ hours: 0,
+ minutes: 0,
+ seconds: 0
+ });
+ Gametime.setAbsolute(newDT);
+ }
+ else if (advanceMode == '1s')
+ game.Gametime.advanceClock(-1);
+ else if (advanceMode == '30s')
+ game.Gametime.advanceClock(-30);
+
+ else if (advanceMode == '1m')
+ game.Gametime.advanceTime({ minutes: -1 });
+ else if (advanceMode == '5m')
+ game.Gametime.advanceTime({ minutes: -5 });
+ else if (advanceMode == '15m')
+ game.Gametime.advanceTime({ minutes: -15 });
+ else if (advanceMode == '1h')
+ game.Gametime.advanceTime({ hours: -1 });
+ }
+ }
}
diff --git a/src/macro.js b/src/macro.js
index 7ba2692..0fd1bfd 100644
--- a/src/macro.js
+++ b/src/macro.js
@@ -32,6 +32,7 @@ export class MacroControl{
let name = "";
let src = "";
let macroId = undefined;
+ let uses = undefined;
if (mode == 'macroBoard') { //Macro board
if ((MODULE.getPermission('MACRO','MACROBOARD') == false )) {
@@ -83,19 +84,12 @@ export class MacroControl{
if (macro != undefined) {
if (displayName) name = macro.name;
if (displayIcon) src = macro.img;
- if (MODULE.hotbarUses && displayUses) {
- const uses = await this.getUses(macro);
- if (uses != null){
- name += '\n(' + uses.available;
- if (uses.maximum != undefined) name += '/' + uses.maximum;
- name += ')';
- }
- }
+ if (MODULE.hotbarUses && displayUses) uses = await this.getUses(macro);
}
}
- streamDeck.setIcon(context,src,background,ring,ringColor);
+ streamDeck.setIcon(context,src,{background:background,ring:ring,ringColor:ringColor,uses:uses});
streamDeck.setTitle(name,context);
}
@@ -144,20 +138,14 @@ export class MacroControl{
}
}
let macro = undefined;
+ let uses = undefined;
if (macroId != undefined) macro = game.macros._source.find(p => p._id == macroId);
if (macro != undefined && macro != null) {
if (displayName) name += macro.name;
if (displayIcon) src += macro.img;
- if (MODULE.hotbarUses && displayUses) {
- const uses = await this.getUses(macro);
- if (uses != null){
- name += '\n(' + uses.available;
- if (uses.maximum != undefined) name += '/' + uses.maximum;
- name += ')';
- }
- }
+ if (MODULE.hotbarUses && displayUses) uses = await this.getUses(macro);
}
- streamDeck.setIcon(context,src,background);
+ streamDeck.setIcon(context,src,{background:background,uses:uses});
streamDeck.setTitle(name,context);
}
}
diff --git a/src/move.js b/src/move.js
index bced9cd..6a8bca9 100644
--- a/src/move.js
+++ b/src/move.js
@@ -49,20 +49,33 @@ export class Move{
else
url = "modules/MaterialDeck/img/move/rotateccw.png";
}
- streamDeck.setIcon(context,url,background);
+ streamDeck.setIcon(context,url,{background:background});
streamDeck.setTitle('',context);
}
keyPress(settings){
if (canvas.scene == null) return;
-
+ if ((MODULE.getPermission('MOVE','TOKEN') == false && mode == 'selectedToken') || (MODULE.getPermission('MOVE','CANVAS') == false && mode == 'canvas')) {
+ streamDeck.noPermission(context);
+ return;
+ }
+
const dir = settings.dir ? settings.dir : 'center';
const mode = settings.mode ? settings.mode : 'canvas';
const type = settings.type ? settings.type : 'move';
- if ((MODULE.getPermission('MOVE','TOKEN') == false && mode == 'selectedToken') || (MODULE.getPermission('MOVE','CANVAS') == false && mode == 'canvas')) {
- streamDeck.noPermission(context);
- return;
+ let token;
+ if (mode == 'selectedToken') {
+ const selection = settings.selection ? settings.selection : 'selected';
+ const tokenIdentifier = settings.tokenName ? settings.tokenName : '';
+
+ if (selection == 'selected') token = canvas.tokens.children[0].children.find(p => p.id == MODULE.selectedTokenId);
+ else if (selection != 'selected' && tokenIdentifier == '') {}
+ else if (selection == 'tokenName') token = canvas.tokens.children[0].children.find(p => p.name == tokenIdentifier);
+ else if (selection == 'actorName') token = canvas.tokens.children[0].children.find(p => p.actor.name == tokenIdentifier);
+ else if (selection == 'tokenId') token = canvas.tokens.children[0].children.find(p => p.id == tokenIdentifier);
+ else if (selection == 'actorId') token = canvas.tokens.children[0].children.find(p => p.actor.id == tokenIdentifier);
+ if (token == undefined) return;
}
if (type == 'move'){
@@ -80,15 +93,12 @@ export class Move{
}
else {
if (settings.mode == 'selectedToken')
- this.moveToken(MODULE.selectedTokenId,dir);
+ this.moveToken(token,dir);
else
this.moveCanvas(dir);
}
}
else if (type == 'rotate' && mode == 'selectedToken'){
- const token = canvas.tokens.children[0].children.find(p => p.id == MODULE.selectedTokenId);
- if (token == undefined) return;
-
const rotType = settings.rot ? settings.rot : 'to';
const value = isNaN(parseInt(settings.rotValue)) ? 0 : parseInt(settings.rotValue);
@@ -100,9 +110,7 @@ export class Move{
}
}
- async moveToken(tokenId,dir){
- if (tokenId == undefined) return;
- const token = canvas.tokens.children[0].children.find(p => p.id == tokenId);
+ async moveToken(token,dir){
const gridSize = canvas.scene.data.grid;
let x = token.x;
let y = token.y;
diff --git a/src/othercontrols.js b/src/othercontrols.js
index ad0002d..ec9080d 100644
--- a/src/othercontrols.js
+++ b/src/othercontrols.js
@@ -86,7 +86,7 @@ export class OtherControls{
}
else if (pauseFunction == 'toggle') //toggle
src = 'modules/MaterialDeck/img/other/pause/playpause.png';
- streamDeck.setIcon(context,src,background,2,ringColor,true);
+ streamDeck.setIcon(context,src,{background:background,ring:2,ringColor:ringColor,overlay:true});
streamDeck.setTitle('',context);
}
@@ -199,7 +199,7 @@ export class OtherControls{
}
}
}
- streamDeck.setIcon(context,src,background,2,ringColor);
+ streamDeck.setIcon(context,src,{background:background,ring:2,ringColor:ringColor});
streamDeck.setTitle(txt,context);
}
@@ -316,7 +316,7 @@ export class OtherControls{
txt += darkness;
}
streamDeck.setTitle(txt,context);
- streamDeck.setIcon(context,src,background);
+ streamDeck.setIcon(context,src,{background:background});
}
keyPressDarkness(settings) {
@@ -348,7 +348,7 @@ export class OtherControls{
if (settings.displayDiceName) txt = 'Roll: ' + settings.rollDiceFormula;
streamDeck.setTitle(txt,context);
- streamDeck.setIcon(context,'',background);
+ streamDeck.setIcon(context,'',{background:background});
}
keyPressRollDice(settings,context){
@@ -398,7 +398,7 @@ export class OtherControls{
}
const background = settings.background ? settings.background : '#000000';
- const table = game.tables.entities.find(p=>p.name == name);
+ const table = game.tables.getName(name);
let txt = settings.displayRollName ? table.name : '';
let src = settings.displayRollIcon ? table.data.img : '';
@@ -415,7 +415,7 @@ export class OtherControls{
}
streamDeck.setTitle(txt,context);
- streamDeck.setIcon(context,src,background);
+ streamDeck.setIcon(context,src,{background:background});
}
keyPressRollTable(settings){
@@ -424,7 +424,7 @@ export class OtherControls{
if (name == undefined) return;
const func = settings.rolltableFunction ? settings.rolltableFunction : 'open';
- const table = game.tables.entities.find(p=>p.name == name);
+ const table = game.tables.getName(name);
if (table != undefined) {
if (table.permission < 2 && MODULE.getPermission('OTHER','TABLES_ALL') == false ) return;
@@ -489,7 +489,7 @@ export class OtherControls{
const icon = settings.displaySidebarIcon ? this.getSidebarIcon(sidebarTab) : '';
streamDeck.setTitle(name,context);
- streamDeck.setIcon(context,icon,background,2,ringColor);
+ streamDeck.setIcon(context,icon,{background:background,ring:2,ringColor:ringColor});
}
keyPressSidebar(settings){
@@ -527,7 +527,7 @@ export class OtherControls{
const txt = settings.displayCompendiumName ? name : '';
streamDeck.setTitle(txt,context);
- streamDeck.setIcon(context,"",background,2,ringColor);
+ streamDeck.setIcon(context,"",{background:background,ring:2,ringColor:ringColor});
}
keyPressCompendium(settings){
@@ -567,7 +567,7 @@ export class OtherControls{
const txt = settings.displayCompendiumName ? name : '';
streamDeck.setTitle(txt,context);
- streamDeck.setIcon(context,"",background,2,ringColor);
+ streamDeck.setIcon(context,"",{background:background,ring:2,ringColor:ringColor});
}
keyPressJournal(settings){
@@ -594,7 +594,7 @@ export class OtherControls{
}
const background = settings.background ? settings.background : '#000000';
streamDeck.setTitle("",context);
- streamDeck.setIcon(context,"",background);
+ streamDeck.setIcon(context,"",{background:background});
}
keyPressChatMessage(settings){
diff --git a/src/playlist.js b/src/playlist.js
index 44b4056..7d7014b 100644
--- a/src/playlist.js
+++ b/src/playlist.js
@@ -24,6 +24,7 @@ export class PlaylistControl{
}
this.active = true;
const mode = settings.playlistMode ? settings.playlistMode : 'playlist';
+
if (mode == 'playlist'){
this.updatePlaylist(settings,context);
}
@@ -32,10 +33,11 @@ export class PlaylistControl{
}
else {
const src = 'modules/MaterialDeck/img/playlist/stop.png';
+ const background = settings.background ? settings.background : '#000000';
const ringColor = (game.playlists.playing.length > 0) ? '#00FF00' : '#000000';
const ring = (game.playlists.playing.length > 0) ? 2 : 1;
const txt = settings.displayPlaylistName ? this.getPlaylist(this.playlistOffset).name : '';
- streamDeck.setIcon(context,src,settings.background,ring,ringColor,true);
+ streamDeck.setIcon(context,src,{background:background,ring:ring,ringColor:ringColor,overlay:true});
streamDeck.setTitle(txt,context);
}
}
@@ -78,11 +80,11 @@ export class PlaylistControl{
let number = parseInt(this.playlistOffset + playlistOffset);
const nrOfPlaylists = parseInt(game.settings.get(MODULE.moduleName,'playlists').playlistNumber);
if (number < 0) number += nrOfPlaylists;
- else if (number > nrOfPlaylists) number -= nrOfPlaylists;
+ else if (number >= nrOfPlaylists) number -= nrOfPlaylists;
const targetPlaylist = this.getPlaylist(number);
if (targetPlaylist != undefined) name = targetPlaylist.name;
}
- streamDeck.setIcon(context,"",background,2,ringColor);
+ streamDeck.setIcon(context,"",{background:background,ring:2,ringColor:ringColor});
streamDeck.setTitle(name,context);
}
@@ -127,7 +129,7 @@ export class PlaylistControl{
//Relative Offset
else if (playlistType == 'relativeOffset') {
}
- streamDeck.setIcon(context,"",background,2,ringColor);
+ streamDeck.setIcon(context,"",{background:background,ring:2,ringColor:ringColor});
streamDeck.setTitle(name,context);
}
@@ -214,7 +216,7 @@ export class PlaylistControl{
let number = parseInt(this.playlistOffset + playlistOffset);
const nrOfPlaylists = parseInt(game.settings.get(MODULE.moduleName,'playlists').playlistNumber);
if (number < 0) number += nrOfPlaylists;
- else if (number > nrOfPlaylists) number -= nrOfPlaylists;
+ else if (number >= nrOfPlaylists) number -= nrOfPlaylists;
this.playlistOffset = number;
}
else {
diff --git a/src/scene.js b/src/scene.js
index bbcbcdf..6f9061c 100644
--- a/src/scene.js
+++ b/src/scene.js
@@ -115,7 +115,7 @@ export class SceneControl{
else ringColor = ringOffColor;
}
streamDeck.setTitle(name,context);
- streamDeck.setIcon(context,src,background,ring,ringColor);
+ streamDeck.setIcon(context,src,{background:background,ring:ring,ringColor:ringColor});
}
keyPress(settings){
diff --git a/src/soundboard.js b/src/soundboard.js
index 0cc48f2..3169d70 100644
--- a/src/soundboard.js
+++ b/src/soundboard.js
@@ -45,7 +45,7 @@ export class SoundboardControl{
if (settings.displayIcon && soundboardSettings.img != undefined) src = soundboardSettings.img[soundNr];
streamDeck.setTitle(txt,context);
- streamDeck.setIcon(context,src,background,2,ringColor);
+ streamDeck.setIcon(context,src,{background:background,ring:2,ringColor:ringColor});
}
else if (mode == 'offset') { //Offset
const ringOffColor = settings.offRing ? settings.offRing : '#000000';
@@ -57,18 +57,19 @@ export class SoundboardControl{
else ringColor = ringOffColor;
streamDeck.setTitle(txt,context);
- streamDeck.setIcon(context,"",background,2,ringColor);
+ streamDeck.setIcon(context,"",{background:background,ring:2,ringColor:ringColor});
}
else if (mode == 'stopAll') { //Stop all sounds
let src = 'modules/MaterialDeck/img/playlist/stop.png';
let soundPlaying = false;
+ const background = settings.background ? settings.background : '#000000';
for (let i=0; i 0){
ctx.fillStyle = background;
ctx.fillRect(0, 0, canvas.width, canvas.height);
@@ -341,8 +353,7 @@ export class StreamDeck{
}
}
else {
- ctx.fillStyle = background;
- ctx.fillRect(0, 0, canvas.width, canvas.height);
+
}
if (format == 'icon' && url != ""){
ctx.font = '600 90px "Font Awesome 5 Free"';
@@ -400,6 +411,76 @@ export class StreamDeck{
yStart = 0;
}
ctx.drawImage(img, xStart+margin, yStart+margin, renderableWidth - 2*margin, renderableHeight - 2*margin);
+ if (uses != undefined && (uses.available > 0 || uses.maximum != undefined)) {
+ let txt = uses.available;
+ if (uses.maximum != undefined) txt = uses.available + '/' + uses.maximum;
+ if (uses.maximum == undefined ) uses.maximum = 1;
+ ctx.beginPath();
+ ctx.lineWidth = 4;
+ let green = Math.ceil(255*(uses.available/uses.maximum));
+ let red = 255-green;
+ green = green.toString(16);
+ if (green.length == 1) green = "0"+green;
+ red = red.toString(16);
+ if (red.length == 1) red = "0"+red;
+ if (uses.available == 0) ctx.strokeStyle = "#c80000";
+ else ctx.strokeStyle = "#"+red.toString(16)+green.toString(16)+"00";
+ const rect = {height:35, paddingSides:20, paddingBottom: 4}
+ ctx.rect(rect.paddingSides, 144-rect.height-rect.paddingBottom,144-2*rect.paddingSides,rect.height);
+ ctx.globalAlpha = 0.5;
+ ctx.fillRect(rect.paddingSides, 144-rect.height-rect.paddingBottom,144-2*rect.paddingSides,rect.height);
+ ctx.globalAlpha = 1;
+ ctx.fillStyle = "white";
+ ctx.font = "24px Arial";
+ ctx.fillText(txt, (canvas.width - ctx.measureText(txt).width) / 2, 144-rect.height-rect.paddingBottom+25);
+ ctx.stroke();
+ }
+
+ if (data.options.clock != undefined) {
+ if (data.options.clock != false && data.options.clock != 'none') {
+ const hourAngle = (data.options.clock.hours+data.options.clock.minutes/60)*Math.PI/6;
+ const minuteAngle = data.options.clock.minutes*Math.PI/30;
+
+ ctx.translate(72,72);
+ //Draw outer circle
+ ctx.beginPath();
+ ctx.lineWidth = 6;
+ ctx.strokeStyle = "gray";
+ ctx.arc(0,0, 50, 0, 2 * Math.PI);
+ ctx.stroke();
+
+ //Draw hour marks
+ ctx.fillStyle = "gray";
+ ctx.beginPath();
+ for (let i=0; i<12; i++) {
+ ctx.fillRect(-2,40,4,10);
+ const angle = 2*Math.PI/12;
+ ctx.rotate(angle);
+ }
+
+
+ //Draw hour arm
+
+ ctx.rotate(Math.PI + hourAngle);
+ ctx.rotate(0);
+ ctx.fillRect(-4,0,8,30);
+ ctx.stroke();
+ // ctx.rotate 8*Math.PI/12;
+ ctx.beginPath();
+ ctx.rotate(-hourAngle + minuteAngle);
+ ctx.fillStyle = "lightgray";
+ ctx.fillRect(-2,0,4,40);
+ ctx.rotate(2*Math.PI/12);
+ ctx.stroke();
+
+ //Draw inner circle
+ ctx.beginPath();
+ ctx.arc(0,0, 5, 0, 2 * Math.PI);
+ ctx.fill();
+
+ }
+ }
+
var dataURL = canvas.toDataURL();
canvas.remove();
const nr = this.addToImageBuffer(dataURL,data);
@@ -409,7 +490,7 @@ export class StreamDeck{
}
getImageBufferId(data){
- return data.url+data.background+data.ring+data.ringColor+data.overlay;
+ return data.url+data.background+data.ring+data.ringColor+data.overlay+data.uses?.available+data.uses?.maximum;
}
addToImageBuffer(img,data){
@@ -449,7 +530,7 @@ export class StreamDeck{
const url = 'modules/MaterialDeck/img/black.png';
const background = '#000000';
const txt = showTxt ? 'no\npermission' : '';
- this.setIcon(context,url,background);
+ this.setIcon(context,url,{background:background});
this.setTitle(txt,context);
}
}
\ No newline at end of file
diff --git a/src/token.js b/src/token.js
index 80dc3ce..999cd8a 100644
--- a/src/token.js
+++ b/src/token.js
@@ -40,6 +40,7 @@ export class TokenControl{
let iconSrc = "";
let overlay = false;
let statsOld;
+ let uses = undefined;
if (validToken) {
if (token.owner == false && token.observer == true && MODULE.getPermission('TOKEN','OBSERVER') == false ) {
streamDeck.noPermission(context);
@@ -52,7 +53,6 @@ export class TokenControl{
tokenName = token.data.name;
if (name) txt += tokenName;
- if (name && stats != 'none') txt += "\n";
const permission = token.actor?.permission;
if (settings.combat){
@@ -71,7 +71,7 @@ export class TokenControl{
}
if (icon) iconSrc = token.data.img;
-
+ if (name && stats != 'none' && stats != 'HPbox') txt += "\n";
if (stats == 'custom'){
const custom = settings.custom ? settings.custom : '';
let split = custom.split('[');
@@ -95,6 +95,12 @@ export class TokenControl{
if (stats == 'HP') {
txt += attributes.hp.value + "/" + attributes.hp.max;
}
+ else if (stats == 'HPbox') {
+ uses = {
+ available: attributes.hp.value,
+ maximum: attributes.hp.max
+ }
+ }
else if (stats == 'TempHP') {
txt += attributes.hp.temp;
if (attributes.hp.tempmax != null)
@@ -135,10 +141,30 @@ export class TokenControl{
else if (stats == 'Init') txt += attributes.init.total;
else if (stats == 'PassivePerception') txt += token.actor.data.data.skills.prc.passive;
else if (stats == 'PassiveInvestigation') txt += token.actor.data.data.skills.inv.passive;
+ else if (stats == 'Ability') {
+ const ability = settings.ability ? settings.ability : 'str';
+ txt += token.actor.data.data.abilities?.[ability].value;
+ }
+ else if (stats == 'AbilityMod') {
+ const ability = settings.ability ? settings.ability : 'str';
+ txt += token.actor.data.data.abilities?.[ability].mod;
+ }
+ else if (stats == 'AbilitySave') {
+ const ability = settings.ability ? settings.ability : 'str';
+ txt += token.actor.data.data.abilities?.[ability].save;
+ }
+ else if (stats == 'Prof') txt += token.actor.data.data.attributes.prof;
}
+
else if (game.system.id == 'D35E' || game.system.id == 'pf1'){
let attributes = token.actor.data.data.attributes;
if (stats == 'HP') txt += attributes.hp.value + "/" + attributes.hp.max;
+ else if (stats == 'HPbox') {
+ uses = {
+ available: attributes.hp.value,
+ maximum: attributes.hp.max
+ }
+ }
else if (stats == 'TempHP') {
if (attributes.hp.temp == null) txt += '0';
else txt += attributes.hp.temp;
@@ -166,10 +192,29 @@ export class TokenControl{
txt += speed;
}
else if (stats == 'Init') txt += attributes.init.total;
+ else if (stats == 'Ability') {
+ const ability = settings.ability ? settings.ability : 'str';
+ txt += token.actor.data.data.abilities?.[ability].value;
+ }
+ else if (stats == 'AbilityMod') {
+ const ability = settings.ability ? settings.ability : 'str';
+ txt += token.actor.data.data.abilities?.[ability].mod;
+ }
+ else if (stats == 'AbilitySave') {
+ const ability = settings.ability ? settings.ability : 'str';
+ txt += token.actor.data.data.abilities?.[ability].save;
+ }
+ else if (stats == 'Prof') txt += token.actor.data.data.attributes.prof;
}
else if (game.system.id == 'pf2e'){
let attributes = token.actor.data.data.attributes;
if (stats == 'HP') txt += attributes.hp.value + "/" + attributes.hp.max;
+ else if (stats == 'HPbox') {
+ uses = {
+ available: attributes.hp.value,
+ maximum: attributes.hp.max
+ }
+ }
else if (stats == 'TempHP') {
if (attributes.hp.temp == null) txt += '0';
else {
@@ -194,9 +239,23 @@ export class TokenControl{
else if (game.system.id == 'demonlord'){
let characteristics = token.actor.data.data.characteristics;
if (stats == 'HP') txt += characteristics.health.value + "/" + characteristics.health.max;
+ else if (stats == 'HPbox') {
+ uses = {
+ available: characteristics.health.value,
+ maximum: characteristics.health.max
+ }
+ }
else if (stats == 'AC') txt += characteristics.defense;
else if (stats == 'Speed') txt += characteristics.speed;
else if (stats == 'Init') txt += token.actor.data.data.fastturn ? "FAST" : "SLOW";
+ else if (stats == 'Ability') {
+ const ability = settings.ability ? settings.ability : 'strength';
+ txt += token.actor.data.data.attributes?.[ability].value;
+ }
+ else if (stats == 'AbilityMod') {
+ const ability = settings.ability ? settings.ability : 'strength';
+ txt += token.actor.data.data.attributes?.[ability].modifier;
+ }
}
else {
//Other systems
@@ -448,10 +507,12 @@ export class TokenControl{
else if (stats == 'PassiveInvestigation')
iconSrc = "modules/MaterialDeck/img/black.png";
}
- streamDeck.setIcon(context,iconSrc,background,ring,ringColor,overlay);
+ streamDeck.setIcon(context,iconSrc,{background:background,ring:ring,ringColor:ringColor,overlay:overlay,uses:uses});
streamDeck.setTitle(txt,context);
}
-
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
async keyPress(settings){
const tokenId = MODULE.selectedTokenId;