3 Commits

Author SHA1 Message Date
Cristian Deenen
9a7088a310 v1.4.11 2022-09-05 01:42:15 +02:00
Material Foundry
033a7351e4 Merge pull request #97 from kyamsil/update_pf2e_3.8.2
Updating pf2e again
2022-09-01 03:14:07 +02:00
kyamsil
be7f837f7d Updating pf2e again 2022-06-12 20:24:30 +01:00
40 changed files with 2174 additions and 1391 deletions

45
.github/workflows/main.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: Release Creation
on:
release:
types: [published]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
# get part of the tag after the `v`
- name: Extract tag version number
id: get_version
uses: battila7/get-version-action@v2
# Substitute the Manifest and Download URLs in the module.json
- name: Substitute Manifest and Download Links For Versioned Ones
id: sub_manifest_link_version
uses: microsoft/variable-substitution@v1
with:
files: 'module.json'
env:
version: ${{steps.get_version.outputs.version-without-v}}
url: https://github.com/${{github.repository}}
manifest: https://github.com/${{github.repository}}/releases/latest/download/module.json
download: https://github.com/${{github.repository}}/releases/download/${{github.event.release.tag_name}}/module.zip
# Create a zip file with all files required by the module to add to the release
- run: zip -r ./module.zip MaterialDeck.js module.json README.md DEVGUIDE.md changelog.md css/ wiki/ img/ lang/ src/ templates/
# Create a release for this specific version
- name: Update Release with Files
id: create_version_release
uses: ncipollo/release-action@v1
with:
allowUpdates: true # Set this to false if you want to prevent updating existing releases
name: ${{ github.event.release.name }}
draft: ${{ github.event.release.unpublished }}
prerelease: ${{ github.event.release.prerelease }}
token: ${{ secrets.GITHUB_TOKEN }}
artifacts: './module.json, ./module.zip'
tag: ${{ github.event.release.tag_name }}
body: ${{ github.event.release.body }}

View File

@@ -7,7 +7,7 @@ In addition to this repo, you will also need to check out the [MaterialDeck_SD g
### Make a new system.js file ### Make a new system.js file
In the [src/systems](src/systems) directory, create a new system file by copying and pasting a similar system to it; for example, `cp demonlord.js wfrp4.js` In the [src/systems](src/systems) directory, create a new system file by copying and pasting a similar system to it, or use template.js; for example, `cp demonlord.js wfrp4.js`
You then need to go through all the functions in there and make sure that the correct data is set. You then need to go through all the functions in there and make sure that the correct data is set.
### Update TokenHelper ### Update TokenHelper

View File

@@ -1,15 +1,19 @@
import { registerSettings } from "./src/settings.js"; import { registerSettings } from "./src/settings.js";
import { StreamDeck } from "./src/streamDeck.js"; import { StreamDeck } from "./src/streamDeck.js";
import {TokenControl} from "./src/token.js"; import { TokenControl } from "./src/actions/token.js";
import {MacroControl} from "./src/macro.js"; import { MacroControl } from "./src/actions/macro.js";
import {CombatTracker} from "./src/combattracker.js"; import { CombatTracker } from "./src/actions/combattracker.js";
import {PlaylistControl} from "./src/playlist.js"; import { PlaylistControl } from "./src/actions/playlist.js";
import {SoundboardControl} from "./src/soundboard.js"; import { SoundboardControl } from "./src/actions/soundboard.js";
import {OtherControls} from "./src/othercontrols.js"; import { OtherControls } from "./src/actions/othercontrols.js";
import {ExternalModules} from "./src/external.js"; import { ExternalModules } from "./src/actions/external.js";
import {SceneControl} from "./src/scene.js"; import { SceneControl } from "./src/actions/scene.js";
import {downloadUtility, compatibleCore, compareVersions} from "./src/misc.js"; import { downloadUtility, compareVersions, compatibleCore } from "./src/misc.js";
import { TokenHelper } from "./src/systems/tokenHelper.js"; import { TokenHelper } from "./src/systems/tokenHelper.js";
export const minimumSDversion = "1.4.11";
export const minimumMSversion = "1.0.2";
export var streamDeck; export var streamDeck;
export var tokenControl; export var tokenControl;
export var macroControl; export var macroControl;
@@ -20,21 +24,15 @@ export var otherControls;
export var externalModules; export var externalModules;
export var sceneControl; export var sceneControl;
export var tokenHelper; export var tokenHelper;
export const moduleName = "MaterialDeck"; export const moduleName = "MaterialDeck";
export let gamingSystem = "dnd5e"; export let gamingSystem = "dnd5e";
let ready = false;
export let hotbarUses = false; export let hotbarUses = false;
export let calculateHotbarUses; export let calculateHotbarUses;
let controlTokenTimer;
export let sdVersion; export let sdVersion;
export let msVersion; export let msVersion;
let ready = false;
let controlTokenTimer;
let updateDialog; let updateDialog;
//CONFIG.debug.hooks = true; //CONFIG.debug.hooks = true;
@@ -67,33 +65,58 @@ async function analyzeWSmessage(msg){
const msg = { const msg = {
target: "SD", target: "SD",
type: "init", type: "init",
system: gamingSystem system: getGamingSystem(),
coreVersion: game.version.split('.')[0]
} }
ws.send(JSON.stringify(msg)); ws.send(JSON.stringify(msg));
if (data.MSversion) msVersion = data.MSversion; if (data.MSversion) msVersion = data.MSversion;
if (data.SDversion) sdVersion = data.SDversion;
console.log("streamdeck connected to server", msVersion); console.log("streamdeck connected to server", msVersion);
streamDeck.resetImageBuffer(); streamDeck.resetImageBuffer();
} }
if (data.type == "version" && data.source == "SD") { if (data.type == "version" && data.source == "SD") {
let minimumSDversion;
let minimumMSversion;
if (compatibleCore("0.8.5")) {
minimumSDversion = game.modules.get("MaterialDeck").data.flags.minimumSDversion.replace('v','');
minimumMSversion = game.modules.get("MaterialDeck").data.flags.minimumMSversion;
}
else {
minimumSDversion = game.modules.get("MaterialDeck").data.minimumSDversion.replace('v','');
minimumMSversion = game.modules.get("MaterialDeck").data.minimumMSversion;
}
sdVersion = data.version; sdVersion = data.version;
if (!compareVersions(minimumSDversion,data.version) && updateDialog == undefined) { const sdCompatible = compareVersions(minimumSDversion,sdVersion);
const msCompatible = compareVersions(minimumMSversion,msVersion);
if ((!sdCompatible || !msCompatible) && updateDialog == undefined) {
let content = "";
if (!sdCompatible && !msCompatible)
content = game.i18n.localize("MaterialDeck.SdMsUpdateRequired")
else if (!sdCompatible)
content = game.i18n.localize("MaterialDeck.SdUpdateRequired")
else
content = game.i18n.localize("MaterialDeck.MsUpdateRequired")
const sd = sdCompatible ? 'display:none' : ''
const ms = msCompatible ? 'display:none' : ''
content += `
<table>
<tr>
<th style='width:40%'>
<th style='width:30%'>${game.i18n.localize("MaterialDeck.DownloadUtility.Current")}</th>
<th style='width:30%'>${game.i18n.localize("MaterialDeck.DownloadUtility.Minimum")}</th>
</tr>
<tr style="${sd}">
<td>Stream Deck Plugin</td>
<td><center>${sdVersion}</center></td>
<td><center>${minimumSDversion}</center></td>
</tr>
<tr style="${ms}">
<td>Material Server</th>
<td><center>${msVersion}</center></td>
<td><center>${minimumMSversion}</center></td>
<tr>
</table>
`
//else if (!sdCompatible) contents += `The Stream Deck plugin version you're using is v${data.version}, which is incompatible with this version of the module.<br>Update to v${minimumSDversion} or newer.`;
updateDialog = new Dialog({ updateDialog = new Dialog({
title: "Material Deck: Update Needed", title: "Material Deck: Update Needed",
content: "<p>The Stream Deck plugin version you're using is v" + data.version + ", which is incompatible with this version of the module.<br>Update to v" + minimumSDversion + " or newer.</p>", content,
buttons: { buttons: {
download: { download: {
icon: '<i class="fas fa-download"></i>', icon: '<i class="fas fa-download"></i>',
@@ -224,7 +247,8 @@ function startWebsocket() {
const msg2 = { const msg2 = {
target: "SD", target: "SD",
type: "init", type: "init",
system: gamingSystem system: getGamingSystem(),
coreVersion: game.version.split('.')[0]
} }
ws.send(JSON.stringify(msg2)); ws.send(JSON.stringify(msg2));
clearInterval(wsInterval); clearInterval(wsInterval);
@@ -278,6 +302,11 @@ export function getPermission(action,func) {
else return settings.permissions?.[action]?.[func]?.[role]; else return settings.permissions?.[action]?.[func]?.[role];
} }
function getGamingSystem() {
const systemOverride = game.settings.get(moduleName,'systemOverride');
gamingSystem = (systemOverride == undefined || systemOverride == null || systemOverride == '') ? game.system.id : systemOverride;
return gamingSystem;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
@@ -290,11 +319,10 @@ export function getPermission(action,func) {
* Attempt to open the websocket * Attempt to open the websocket
*/ */
Hooks.once('ready', async()=>{ Hooks.once('ready', async()=>{
registerSettings(); await registerSettings();
enableModule = (game.settings.get(moduleName,'Enable')) ? true : false; enableModule = (game.settings.get(moduleName,'Enable')) ? true : false;
const systemOverride = game.settings.get(moduleName,'systemOverride'); getGamingSystem();
gamingSystem = systemOverride != '' ? systemOverride : game.system.id;
soundboard = new SoundboardControl(); soundboard = new SoundboardControl();
streamDeck = new StreamDeck(); streamDeck = new StreamDeck();
@@ -435,7 +463,7 @@ Hooks.on('onActorSetCondition',(data)=>{
Hooks.on('controlToken',(token,controlled)=>{ Hooks.on('controlToken',(token,controlled)=>{
if (enableModule == false || ready == false) return; if (enableModule == false || ready == false) return;
if (controlled) { if (controlled) {
tokenControl.update(token.data._id); tokenControl.update(compatibleCore('10.0') ? token.id : token.data._id);
if (controlTokenTimer != undefined) { if (controlTokenTimer != undefined) {
clearTimeout(controlTokenTimer); clearTimeout(controlTokenTimer);
controlTokenTimer = undefined; controlTokenTimer = undefined;
@@ -459,9 +487,7 @@ Hooks.on('renderHotbar', (hotbar)=>{
Hooks.on('render', (app)=>{ Hooks.on('render', (app)=>{
if (enableModule == false || ready == false) return; if (enableModule == false || ready == false) return;
if (compatibleCore("0.8.1") == false) return;
if (app.id == "hotbar" && macroControl != undefined) macroControl.hotbar(app.macros); if (app.id == "hotbar" && macroControl != undefined) macroControl.hotbar(app.macros);
}); });
Hooks.on('renderCombatTracker',()=>{ Hooks.on('renderCombatTracker',()=>{
@@ -486,6 +512,11 @@ Hooks.on('closeplaylistConfigForm', (form)=>{
playlistControl.updateAll(); playlistControl.updateAll();
}); });
Hooks.on('lightingRefresh',()=>{
if (enableModule == false || ready == false) return;
if (tokenControl != undefined) tokenControl.update();
});
Hooks.on('pauseGame',()=>{ Hooks.on('pauseGame',()=>{
if (enableModule == false || ready == false) return; if (enableModule == false || ready == false) return;
otherControls.updateAll(); otherControls.updateAll();
@@ -610,6 +641,7 @@ Hooks.on('updateTile',()=>{
Hooks.once('init', ()=>{ Hooks.once('init', ()=>{
//CONFIG.debug.hooks = true; //CONFIG.debug.hooks = true;
//registerSettings(); //in ./src/settings.js //registerSettings(); //in ./src/settings.js
}); });
Hooks.once('canvasReady',()=>{ Hooks.once('canvasReady',()=>{

View File

@@ -1,11 +1,56 @@
# Changelog Material Deck Module # Changelog Material Deck Module
### v1.4.11 - 05-09-2022
Fixes:
<ul>
<li>Fixed system autodetection bug, where it would not always correctly detect the system</li>
<li>Token Action => Stats/On Click: Pf2e intimidation did not work</li>
<li>Playlist Action => Fix unrestricted playback and 'play playlist'</li>
<li>User Config: Fix settings saving issue</li>
</ul>
Additions:
<ul>
<li>Token Action => Inventory: Added roll options to roll for to hit and damage (dnd5e only)</li>
<li>Token Action => Inventory/Features/Spellbook: Select by name or id</li>
<li>Token Action => Features: Added option to filter active and passive abilities (dnd5e only)</li>
<li>Token Action => Items/Spells/Features: Add offset options</li>
<li>Token Action => OnClick => SetVision: Added checkboxes to configure what settings should be changed</li>
<li>Combat Tracker => Function: Added option to roll initiative for combatants</li>
<li>Combat Tracker => OnClick: Added target and untarget token option</li>
<li>Other Actions => Darkness Control: Added 'Transition to Day' and 'Transition to Night' options</li>
<li>Other Actions => Darkness Control: Added animation time option for darkness changes</li>
</ul>
Other:
<ul>
<li>Made compatible with Foundry v10 (see notes below), dropped compatibility with Foundry v8</li>
<li>Token Action => On Click => Call Macro: Removed macro target, since I can't get it to work properly</li>
<li>Token Action => On Click => Movement: Tokens now snap to the grid when moved</li>
<li>Token Action => OnClick => SetVision: update configuration to v9/v10 standards</li>
<li>Token Action => Handle Conditions: Removed the increase/decrease option for all systems but pf2e (it only works in pf2e)</li>
<li>System Override: Changed to a dropdown menu with all supported systems, instead of a string field</li>
<li>All ui elements and classes have been given unique identifiers to prevent module incompatibilities</li>
</ul>
V10 Compatibility Notes:
<ul>
<li>The following systems have been tested in v10: dnd5e, pf1e, forbidden lands, wfrp4. Other systems have not been updated to v10 yet at the time of this update</li>
<li>Changing the token vision mode through MD does not work properly, appears to be a bug in Foundry</li>
<li>Wildcard images currently don't seem to work in v10, so they have not been tested</li>
</ul>
<b>Compatible server app and SD plugin:</b><br>
Material Server v1.0.2+ (unchanged): https://github.com/CDeenen/MaterialServer/releases <br>
SD plugin v1.4.11 (<b>must be updated!</b>): https://github.com/CDeenen/MaterialDeck_SD/releases<br>
### v1.4.10 - 30-05-2022 ### v1.4.10 - 30-05-2022
Fixes: Fixes:
<ul> <ul>
<li>Stream Deck plugin v1.4.10 was not properly recognized as compatible</li> <li>Stream Deck plugin v1.4.10 was not properly recognized as compatible</li>
</ul> </ul>
Additions; Additions:
<ul> <ul>
<li>Material Server version is now displayed in the Download Utility (MS v1.1.0+)</li> <li>Material Server version is now displayed in the Download Utility (MS v1.1.0+)</li>
</ul> </ul>

175
css/style.css Normal file
View File

@@ -0,0 +1,175 @@
/*
* Device Config
*/
.materialDeck_devConf_columnLabel {
max-width:30%;
min-width:30%;
text-align: left;
}
.materialDeck_devConf_columnId {
max-width:25%;
min-width:25%;
text-align: left;
text-overflow: hidden;
}
.materialDeck_devConf_columnCB {
width:10%;
text-align: left;
}
/*
* Download Utility
*/
.materialDeck_dlUtil_columnLabel {
width:25%;
text-align: left;
}
.materialDeck_dlUtil_columnVersion {
width:15%;
text-align: left;
}
.materialDeck_dlUtil_columnOS {
width:15%;
}
.materialDeck_dlUtil_columnButton {
width:15%;
}
.materialDeck_dlUtil_button {
width:100%;
}
/*
* Macro Config
*/
.materialDeck_macroConfig_boxed {
border: 1px solid black ;
border-radius: 5px ;
max-width: 166px;
padding: 5px;
margin:2px;
width:10%;
}
.materialDeck_macroConfig_navigationDiv {
width:100%;
display:flex;
flex-direction:row;
}
.materialDeck_macroConfig_navigation {
flex:1;
max-width: 8%;
}
.materialDeck_macroConfig_p {
width:84%;
text-align:center;
padding: 0px 0;
font-size: 20px;
}
.materialDeck_macroConfig_background {
display:flex;
flex-direction:row;
padding-top:10px;
}
/*
* Playlist Config
*/
.materialDeck_plConfig_select {
width: 35%;
max-width: 35%;
}
/*
* Soundboard Config
*/
.materialDeck_sbConfig_boxed {
border: 1px solid black ;
border-radius: 5px ;
max-width: 166px;
height: 300px;
padding: 5px;
margin:2px;
width:10%
}
.materialDeck_sbConfig_navigationDiv {
flex:1;
width:100%;
display:flex;
flex-direction:row;
}
.materialDeck_sbConfig_navigation {
flex:1;
}
.materialDeck_sbConfig_p {
flex:15;
text-align:center;
padding: 0px 0;
font-size: 20px
}
/*
* User Permission Config
*/
header.materialDeck_uPerm_table-header {
background: rgba(0, 0, 0, 0.5);
padding: 5px;
border: 1px solid #191813;
text-align: center;
color: #f0f0e0;
font-weight: bold;
text-shadow: 1px 1px #000;
}
ul.materialDeck_uPerm_permissions-list {
list-style: none;
margin: 0;
padding: 0;
overflow: hidden auto;
scrollbar-width: thin;
}
li.materialDeck_uPerm_permission {
padding: 5px;
border-bottom: 1px solid #7a7971;
}
li.materialDeck_uPerm_permission .form-fields {
justify-content: space-around;
}
li.materialDeck_uPerm_permission input[type="checkbox"] {
margin: 0;
}
.materialDeck_uPerm_index {
flex: 0 0 200px;
text-align: left;
font-weight: bold;
}
.materialDeck_uPerm_hint {
flex: 0 0 100%;
color: #4b4a44;
font-size: 13px;
margin: 5px 0 0;
}
/*
* Help Menu
*/
.materialDeck_helpMenu_expandable {
cursor: pointer;
}
.materialDeck_helpMenu_collapsed {
display:none;
}
.materialDeck_helpMenu_expandableIcon {
border: none;
}

BIN
img/.thumb/down.png.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
img/.thumb/right.png.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
img/down.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.0 KiB

BIN
img/right.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

View File

@@ -22,7 +22,7 @@
"MaterialDeck.Sett.NrOfConnMessages": "Number of Connection Warnings", "MaterialDeck.Sett.NrOfConnMessages": "Number of Connection Warnings",
"MaterialDeck.Sett.NrOfConnMessagesHint": "Sets the number of times a connection warning is displayed if Material Deck cannot connect to Material Server. If set to 0, it will give not be limited.", "MaterialDeck.Sett.NrOfConnMessagesHint": "Sets the number of times a connection warning is displayed if Material Deck cannot connect to Material Server. If set to 0, it will give not be limited.",
"MaterialDeck.Sett.SystemOverride": "System Override", "MaterialDeck.Sett.SystemOverride": "System Override",
"MaterialDeck.Sett.SystemOverrideHint": "Overrides the automatic gaming system detection. Unsupported systems default to dnd5e, but if an unsupported system is similar to a different system you can specify that system here. Leave empty for system autodetection.", "MaterialDeck.Sett.SystemOverrideHint": "Overrides the automatic gaming system detection. Unsupported systems default to dnd5e, but if an unsupported system is similar to a different system you can specify that system here.",
"MaterialDeck.PL.Unrestricted": "Unrestricted", "MaterialDeck.PL.Unrestricted": "Unrestricted",
"MaterialDeck.PL.OneTrackPlaylist": "One track per playlist", "MaterialDeck.PL.OneTrackPlaylist": "One track per playlist",
@@ -211,5 +211,9 @@
"MaterialDeck.DownloadUtility.Source": "Source", "MaterialDeck.DownloadUtility.Source": "Source",
"MaterialDeck.DownloadUtility.Profiles": "Profiles", "MaterialDeck.DownloadUtility.Profiles": "Profiles",
"MaterialDeck.DownloadUtility.Name": "Name", "MaterialDeck.DownloadUtility.Name": "Name",
"MaterialDeck.DownloadUtility.Refresh": "Refresh" "MaterialDeck.DownloadUtility.Refresh": "Refresh",
"MaterialDeck.SdMsUpdateRequired": "The Stream Deck plugin and Material Server version you are using are incompatible with this version of the module.<br>Please update them.",
"MaterialDeck.SdUpdateRequired": "The Stream Deck plugin you are using is incompatible with this version of the module.<br>Please update it.",
"MaterialDeck.MsUpdateRequired": "The Material Server version you are using is incompatible with this version of the module.<br>Please update it."
} }

View File

@@ -2,7 +2,7 @@
"name": "MaterialDeck", "name": "MaterialDeck",
"title": "Material Deck", "title": "Material Deck",
"description": "Material Deck allows you to control Foundry using an Elgato Stream Deck", "description": "Material Deck allows you to control Foundry using an Elgato Stream Deck",
"version": "1.4.10", "version": "1.4.11",
"author": "CDeenen", "author": "CDeenen",
"authors": { "authors": {
"name": "CDeenen", "name": "CDeenen",
@@ -11,18 +11,15 @@
"patreon": "MaterialFoundry", "patreon": "MaterialFoundry",
"reddit": "CDeenen123" "reddit": "CDeenen123"
}, },
"flags": { "esmodules": ["./MaterialDeck.js"],
"minimumSDversion": "1.4.7", "styles": ["./css/style.css"],
"minimumMSversion": "1.0.2"
},
"minimumSDversion": "1.4.7",
"minimumMSversion": "1.0.2",
"esmodules": [
"./MaterialDeck.js"
],
"socket": true, "socket": true,
"minimumCoreVersion": "0.7.5", "minimumCoreVersion": "9",
"compatibleCoreVersion": "9", "compatibleCoreVersion": "10",
"compatibility": {
"minimum": "9",
"verified": "10"
},
"languages": [ "languages": [
{ {
"lang": "en", "lang": "en",

View File

@@ -1,6 +1,4 @@
import * as MODULE from "../MaterialDeck.js"; import { streamDeck, tokenControl, getPermission } from "../../MaterialDeck.js";
import {streamDeck, tokenControl} from "../MaterialDeck.js";
import {compatibleCore} from "./misc.js";
export class CombatTracker{ export class CombatTracker{
constructor(){ constructor(){
@@ -32,7 +30,7 @@ export class CombatTracker{
settings.icon = settings.displayIcon ? 'tokenIcon' : 'none'; settings.icon = settings.displayIcon ? 'tokenIcon' : 'none';
if (mode == 'combatants'){ if (mode == 'combatants'){
if (MODULE.getPermission('COMBAT','DISPLAY_COMBATANTS') == false) { if (getPermission('COMBAT','DISPLAY_COMBATANTS') == false) {
streamDeck.noPermission(context,device,device,false,"combat tracker"); streamDeck.noPermission(context,device,device,false,"combat tracker");
return; return;
} }
@@ -44,7 +42,7 @@ export class CombatTracker{
const combatant = initiativeOrder[nr] const combatant = initiativeOrder[nr]
if (combatant != undefined){ if (combatant != undefined){
const tokenId = compatibleCore("0.8.1") ? combatant.data.tokenId : combatant.tokenId; const tokenId = combatant.data.tokenId;
tokenControl.pushData(tokenId,settings,context,device,combatantState,'#cccc00'); tokenControl.pushData(tokenId,settings,context,device,combatantState,'#cccc00');
return; return;
} }
@@ -59,12 +57,12 @@ export class CombatTracker{
} }
} }
else if (mode == 'currentCombatant'){ else if (mode == 'currentCombatant'){
if (MODULE.getPermission('COMBAT','DISPLAY_COMBATANTS') == false) { if (getPermission('COMBAT','DISPLAY_COMBATANTS') == false) {
streamDeck.noPermission(context,device,device); streamDeck.noPermission(context,device,device);
return; return;
} }
if (combat != null && combat != undefined && combat.started){ if (combat != null && combat != undefined && combat.started){
const tokenId = compatibleCore("0.8.1") ? combat.combatant.data.tokenId : combat.combatant.tokenId; const tokenId = combat.combatant.data.tokenId;
tokenControl.pushData(tokenId,settings,context,device); tokenControl.pushData(tokenId,settings,context,device);
} }
else { else {
@@ -74,15 +72,15 @@ export class CombatTracker{
} }
else if (mode == 'function'){ else if (mode == 'function'){
if (ctFunction == 'turnDisplay' && MODULE.getPermission('COMBAT','TURN_DISPLAY') == false) { if (ctFunction == 'turnDisplay' && getPermission('COMBAT','TURN_DISPLAY') == false) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
else if (ctFunction == 'endTurn' && MODULE.getPermission('COMBAT','END_TURN') == false) { else if (ctFunction == 'endTurn' && getPermission('COMBAT','END_TURN') == false) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
else if (ctFunction != 'turnDisplay' && ctFunction != 'endTurn' && MODULE.getPermission('COMBAT','OTHER_FUNCTIONS') == false) { else if (ctFunction != 'turnDisplay' && ctFunction != 'endTurn' && getPermission('COMBAT','OTHER_FUNCTIONS') == false) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -130,6 +128,8 @@ export class CombatTracker{
if (settings.displayRound && settings.displayTurn) txt += "\n"; if (settings.displayRound && settings.displayTurn) txt += "\n";
if (settings.displayTurn) txt += "Turn\n"+turn; if (settings.displayTurn) txt += "Turn\n"+turn;
} }
else if (ctFunction == 'rollInitiative' || ctFunction == 'rollInitiativeNPC')
src = "modules/MaterialDeck/img/token/init.png";
streamDeck.setIcon(context,device,src,{background:background}); streamDeck.setIcon(context,device,src,{background:background});
streamDeck.setTitle(txt,context); streamDeck.setTitle(txt,context);
@@ -145,20 +145,19 @@ export class CombatTracker{
if (combat == null || combat == undefined) return; if (combat == null || combat == undefined) return;
const ctFunction = settings.combatTrackerFunction ? settings.combatTrackerFunction : 'startStop'; const ctFunction = settings.combatTrackerFunction ? settings.combatTrackerFunction : 'startStop';
if (ctFunction == 'turnDisplay' && MODULE.getPermission('COMBAT','TURN_DISPLAY') == false) { if (ctFunction == 'turnDisplay' && getPermission('COMBAT','TURN_DISPLAY') == false) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
else if (ctFunction == 'endTurn' && MODULE.getPermission('COMBAT','END_TURN') == false) { else if (ctFunction == 'endTurn' && getPermission('COMBAT','END_TURN') == false) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
else if (ctFunction != 'turnDisplay' && ctFunction != 'endTurn' && MODULE.getPermission('COMBAT','OTHER_FUNCTIONS') == false) { else if (ctFunction != 'turnDisplay' && ctFunction != 'endTurn' && getPermission('COMBAT','OTHER_FUNCTIONS') == false) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
else if (ctFunction == 'startStop'){
if (ctFunction == 'startStop'){
let src; let src;
let background; let background;
if (game.combat.started){ if (game.combat.started){
@@ -169,8 +168,10 @@ export class CombatTracker{
} }
return; return;
} }
if (game.combat.started == false) return; else if (ctFunction == 'rollInitiative' && getPermission('COMBAT','OTHER_FUNCTIONS')) game.combat.rollAll();
else if (ctFunction == 'rollInitiativeNPC' && getPermission('COMBAT','OTHER_FUNCTIONS')) game.combat.rollNPC();
if (game.combat.started == false) return;
if (ctFunction == 'nextTurn') await game.combat.nextTurn(); if (ctFunction == 'nextTurn') await game.combat.nextTurn();
else if (ctFunction == 'prevTurn') await game.combat.previousTurn(); else if (ctFunction == 'prevTurn') await game.combat.previousTurn();
else if (ctFunction == 'nextRound') await game.combat.nextRound(); else if (ctFunction == 'nextRound') await game.combat.nextRound();
@@ -181,7 +182,6 @@ export class CombatTracker{
const token = canvas.tokens.placeables.filter(token => token.id == game.combat.combatant.token.id)[0]; const token = canvas.tokens.placeables.filter(token => token.id == game.combat.combatant.token.id)[0];
if (token.can(game.userId,"control")) token.control(); if (token.can(game.userId,"control")) token.control();
} }
} }
else { else {
const onClick = settings.onClick ? settings.onClick : 'doNothing'; const onClick = settings.onClick ? settings.onClick : 'doNothing';
@@ -193,12 +193,12 @@ export class CombatTracker{
if (nr == undefined || nr < 1) nr = 0; if (nr == undefined || nr < 1) nr = 0;
const combatant = initiativeOrder[nr] const combatant = initiativeOrder[nr]
if (combatant == undefined) return; if (combatant == undefined) return;
tokenId = compatibleCore("0.8.1") ? combatant.data.tokenId : combatant.tokenId; tokenId = combatant.data.tokenId;
} }
} }
else if (mode == 'currentCombatant') else if (mode == 'currentCombatant')
if (combat != null && combat != undefined && combat.started) if (combat != null && combat != undefined && combat.started)
tokenId = compatibleCore("0.8.1") ? combat.combatant.data.tokenId : combat.combatant.tokenId; tokenId = combat.combatant.data.tokenId;
let token = (canvas.tokens.children[0] != undefined) ? canvas.tokens.children[0].children.find(p => p.id == tokenId) : undefined; let token = (canvas.tokens.children[0] != undefined) ? canvas.tokens.children[0].children.find(p => p.id == tokenId) : undefined;
if (token == undefined) return; if (token == undefined) return;
@@ -226,6 +226,12 @@ export class CombatTracker{
if (element == null) token.sheet.render(true); if (element == null) token.sheet.render(true);
else token.sheet.close(); else token.sheet.close();
} }
else if (onClick == 'rollInitiative') {
token.actor.rollInitiative({rerollInitiative:true});
}
else if (onClick == 'target') {
token.setTarget(!token.isTargeted,{releaseOthers:false})
}
} }
} }

View File

@@ -1,4 +1,5 @@
import {streamDeck} from "../MaterialDeck.js"; import { streamDeck } from "../../MaterialDeck.js";
import { compatibleCore } from "../misc.js";
export class ExternalModules{ export class ExternalModules{
soundscapeSettings = { soundscapeSettings = {
@@ -113,14 +114,14 @@ export class ExternalModules{
let name = ''; let name = '';
if (type == 'weatherControls') { if (type == 'weatherControls') {
const effect = (settings.weatherEffect == undefined) ? 'leaves' : settings.weatherEffect; const effect = (settings.weatherEffect == undefined) ? 'leaves' : settings.weatherEffect;
name = CONFIG.fxmaster.weather[effect].label; name = compatibleCore('10.0') ? game.i18n.localize(CONFIG.fxmaster.particleEffects[effect].label) : CONFIG.fxmaster.weather[effect].label;
icon = CONFIG.fxmaster.weather[effect].icon; icon = compatibleCore('10.0') ? CONFIG.fxmaster.particleEffects[effect].icon : CONFIG.fxmaster.weather[effect].icon;
ring = canvas.scene.getFlag("fxmaster", "effects")?.[`core_${effect}`] ? 2 : 1; ring = canvas.scene.getFlag("fxmaster", "effects")?.[`core_${effect}`] ? 2 : 1;
ringColor = ring < 2 ? '#000000' : "#00ff00"; ringColor = ring < 2 ? '#000000' : "#00ff00";
} }
else if (type == 'filters') { else if (type == 'filters') {
const filter = (settings.fxMasterFilter == undefined) ? 'underwater' : settings.fxMasterFilter; const filter = (settings.fxMasterFilter == undefined) ? 'underwater' : settings.fxMasterFilter;
name = CONFIG.fxmaster.filters[filter].label; name = compatibleCore('10.0') ? game.i18n.localize(CONFIG.fxmaster.filterEffects[filter].label) : CONFIG.fxmaster.filters[filter].label;
background = "#340057"; background = "#340057";
if (displayIcon){ if (displayIcon){
if (filter == 'lightning') icon = "fas fa-bolt"; if (filter == 'lightning') icon = "fas fa-bolt";
@@ -174,7 +175,7 @@ export class ExternalModules{
applyColor: (settings.fxWeatherEnColor == undefined) ? false : settings.fxWeatherEnColor applyColor: (settings.fxWeatherEnColor == undefined) ? false : settings.fxWeatherEnColor
} }
Hooks.call("fxmaster.switchWeather", { Hooks.call(compatibleCore('10.0') ? "fxmaster.switchParticleEffect" : "fxmaster.switchWeather", {
name: `core_${effect}`, name: `core_${effect}`,
type: effect, type: effect,
options, options,

View File

@@ -1,6 +1,5 @@
import * as MODULE from "../MaterialDeck.js"; import { moduleName, streamDeck, getPermission, hotbarUses } from "../../MaterialDeck.js";
import {streamDeck} from "../MaterialDeck.js"; import { compatibleCore } from "../misc.js";
import {compatibleCore} from "./misc.js";
export class MacroControl{ export class MacroControl{
constructor(){ constructor(){
@@ -39,7 +38,7 @@ export class MacroControl{
let uses = undefined; let uses = undefined;
if (mode == 'macroBoard') { //Macro board if (mode == 'macroBoard') { //Macro board
if ((MODULE.getPermission('MACRO','MACROBOARD') == false )) { if ((getPermission('MACRO','MACROBOARD') == false )) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -57,8 +56,8 @@ export class MacroControl{
else { //Execute macro else { //Execute macro
macroNumber += this.offset - 1; macroNumber += this.offset - 1;
if (macroNumber < 0) macroNumber = 0; if (macroNumber < 0) macroNumber = 0;
macroId = game.settings.get(MODULE.moduleName,'macroSettings').macros[macroNumber]; macroId = game.settings.get(moduleName,'macroSettings').macros[macroNumber];
background = game.settings.get(MODULE.moduleName,'macroSettings').color[macroNumber]; background = game.settings.get(moduleName,'macroSettings').color[macroNumber];
if (background == undefined) background = '#000000'; if (background == undefined) background = '#000000';
ring = 0; ring = 0;
} }
@@ -69,11 +68,11 @@ export class MacroControl{
macroId = macro?.id; macroId = macro?.id;
} }
else { //Macro Hotbar else { //Macro Hotbar
if ((MODULE.getPermission('MACRO','HOTBAR') == false )) { if ((getPermission('MACRO','HOTBAR') == false )) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
if (mode == 'hotbar') macroId = game.user.data.hotbar[macroNumber]; if (mode == 'hotbar') macroId = compatibleCore('10.0') ? game.user.hotbar[macroNumber] : game.user.data.hotbar[macroNumber];
else { else {
let macros; let macros;
if (mode == 'customHotbar' && game.modules.get('custom-hotbar') != undefined) if (mode == 'customHotbar' && game.modules.get('custom-hotbar') != undefined)
@@ -91,7 +90,7 @@ export class MacroControl{
if (macro != undefined) { if (macro != undefined) {
if (displayName) name = macro.name; if (displayName) name = macro.name;
if (displayIcon) src = macro.img; if (displayIcon) src = macro.img;
if (MODULE.hotbarUses && displayUses) uses = await this.getUses(macro); if (hotbarUses && displayUses) uses = await this.getUses(macro);
} }
} }
else { else {
@@ -126,7 +125,7 @@ export class MacroControl{
let macroNumber = data.settings.macroNumber; let macroNumber = data.settings.macroNumber;
if(macroNumber == undefined || isNaN(parseInt(macroNumber))) macroNumber = 1; if(macroNumber == undefined || isNaN(parseInt(macroNumber))) macroNumber = 1;
if ((MODULE.getPermission('MACRO','HOTBAR') == false )) { if ((getPermission('MACRO','HOTBAR') == false )) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -150,7 +149,7 @@ export class MacroControl{
if (macro != undefined && macro != null) { if (macro != undefined && macro != null) {
if (displayName) name += macro.name; if (displayName) name += macro.name;
if (displayIcon) src += macro.img; if (displayIcon) src += macro.img;
if (MODULE.hotbarUses && displayUses) uses = await this.getUses(macro); if (hotbarUses && displayUses) uses = await this.getUses(macro);
} }
streamDeck.setIcon(context,device,src,{background:background,uses:uses}); streamDeck.setIcon(context,device,src,{background:background,uses:uses});
streamDeck.setTitle(name,context); streamDeck.setTitle(name,context);
@@ -165,11 +164,11 @@ export class MacroControl{
let target = settings.target ? settings.target : undefined; let target = settings.target ? settings.target : undefined;
if (mode == 'hotbar' || mode == 'visibleHotbar' || mode == 'customHotbar'){ if (mode == 'hotbar' || mode == 'visibleHotbar' || mode == 'customHotbar'){
if ((MODULE.getPermission('MACRO','HOTBAR') == false )) return; if ((getPermission('MACRO','HOTBAR') == false )) return;
this.executeHotbar(macroNumber,mode); this.executeHotbar(macroNumber,mode,target);
} }
else if (mode == 'name') { else if (mode == 'name') {
if ((MODULE.getPermission('MACRO','BY_NAME') == false )) return; if ((getPermission('MACRO','BY_NAME') == false )) return;
const macroName = settings.macroNumber; const macroName = settings.macroNumber;
const macro = game.macros.getName(macroName); const macro = game.macros.getName(macroName);
@@ -177,16 +176,13 @@ export class MacroControl{
const args = settings.macroArgs ? settings.macroArgs : ""; const args = settings.macroArgs ? settings.macroArgs : "";
let furnaceEnabled = false; let advancedMacrosEnabled = false;
let furnace = game.modules.get("furnace");
if (furnace != undefined && furnace.active && compatibleCore("0.8.1")==false) furnaceEnabled = true;
let advancedMacros = game.modules.get("advanced-macros"); let advancedMacros = game.modules.get("advanced-macros");
if (advancedMacros != undefined && advancedMacros.active) furnaceEnabled = true; if (advancedMacros != undefined && advancedMacros.active) advancedMacrosEnabled = true;
if (args == "" || args == " ") furnaceEnabled = false; if (args == "" || args == " ") advancedMacrosEnabled = false;
if (furnaceEnabled == false) macro.execute({token:target}); if (advancedMacrosEnabled == false) macro.execute({token:target});
else { else {
let chatData = { let chatData = {
user: game.user._id, user: game.user._id,
@@ -198,7 +194,7 @@ export class MacroControl{
} }
else { else {
if ((MODULE.getPermission('MACRO','MACROBOARD') == false )) return; if ((getPermission('MACRO','MACROBOARD') == false )) return;
if (settings.macroBoardMode == 'offset') { if (settings.macroBoardMode == 'offset') {
let macroOffset = settings.macroOffset; let macroOffset = settings.macroOffset;
if (macroOffset == undefined) macroOffset = 0; if (macroOffset == undefined) macroOffset = 0;
@@ -210,9 +206,9 @@ export class MacroControl{
} }
} }
executeHotbar(macroNumber,mode){ executeHotbar(macroNumber,mode,target){
let macroId let macroId
if (mode == 'hotbar') macroId = game.user.data.hotbar[macroNumber]; if (mode == 'hotbar') macroId = compatibleCore('10.0') ? game.user.hotbar[macroNumber] : game.user.data.hotbar[macroNumber];
else { else {
let macros; let macros;
if (mode == 'customHotbar' && game.modules.get('custom-hotbar') != undefined) { if (mode == 'customHotbar' && game.modules.get('custom-hotbar') != undefined) {
@@ -224,29 +220,26 @@ export class MacroControl{
} }
if (macroId == undefined) return; if (macroId == undefined) return;
let macro = game.macros.get(macroId); let macro = game.macros.get(macroId);
macro.execute(); macro.execute({token:target});
} }
executeBoard(macroNumber){ executeBoard(macroNumber){
macroNumber = parseInt(macroNumber); macroNumber = parseInt(macroNumber);
macroNumber += this.offset - 1; macroNumber += this.offset - 1;
if (macroNumber < 0) macroNumber = 0; if (macroNumber < 0) macroNumber = 0;
var macroId = game.settings.get(MODULE.moduleName,'macroSettings').macros[macroNumber]; var macroId = game.settings.get(moduleName,'macroSettings').macros[macroNumber];
if (macroId != undefined){ if (macroId != undefined){
let macro = game.macros.get(macroId); let macro = game.macros.get(macroId);
if (macro != undefined && macro != null) { if (macro != undefined && macro != null) {
const args = game.settings.get(MODULE.moduleName,'macroSettings').args; const args = game.settings.get(moduleName,'macroSettings').args;
let furnaceEnabled = false; let advancedMacrosEnabled = false;
let furnace = game.modules.get("furnace");
if (furnace != undefined && furnace.active && compatibleCore("0.8.1")==false) furnaceEnabled = true;
let advancedMacros = game.modules.get("advanced-macros"); let advancedMacros = game.modules.get("advanced-macros");
if (advancedMacros != undefined && advancedMacros.active) furnaceEnabled = true; if (advancedMacros != undefined && advancedMacros.active) advancedMacrosEnabled = true;
if (args == undefined || args[macroNumber] == undefined || args[macroNumber] == "") furnaceEnabled = false; if (args == undefined || args[macroNumber] == undefined || args[macroNumber] == "") advancedMacrosEnabled = false;
if (furnaceEnabled == false) macro.execute(); if (advancedMacrosEnabled == false) macro.execute();
else { else {
let chatData = { let chatData = {
user: game.user._id, user: game.user._id,

View File

@@ -1,6 +1,5 @@
import * as MODULE from "../MaterialDeck.js"; import { streamDeck, gamingSystem, getPermission } from "../../MaterialDeck.js";
import {streamDeck, gamingSystem} from "../MaterialDeck.js"; import { compatibleCore } from "../misc.js";
import {compatibleCore} from "./misc.js";
export class OtherControls{ export class OtherControls{
constructor(){ constructor(){
@@ -94,7 +93,7 @@ export class OtherControls{
////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////
updatePause(settings,context,device,options={}){ updatePause(settings,context,device,options={}){
if (MODULE.getPermission('OTHER','PAUSE') == false ) { if (getPermission('OTHER','PAUSE') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -119,7 +118,7 @@ export class OtherControls{
} }
keyPressPause(settings){ keyPressPause(settings){
if (MODULE.getPermission('OTHER','PAUSE') == false ) return; if (getPermission('OTHER','PAUSE') == false ) return;
const pauseFunction = settings.pauseFunction ? settings.pauseFunction : 'pause'; const pauseFunction = settings.pauseFunction ? settings.pauseFunction : 'pause';
@@ -186,7 +185,7 @@ export class OtherControls{
} }
else { else {
let viewPosition = canvas.scene._viewPosition; let viewPosition = canvas.scene._viewPosition;
const gridSize = canvas.scene.data.grid; const gridSize = compatibleCore('10.0') ? canvas.scene.grid.size : canvas.scene.data.grid;
viewPosition.duration = 100; viewPosition.duration = 100;
if (dir == 'up') viewPosition.y -= gridSize; if (dir == 'up') viewPosition.y -= gridSize;
@@ -220,7 +219,7 @@ export class OtherControls{
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
updateControl(settings,context,device,options={}){ updateControl(settings,context,device,options={}){
if (MODULE.getPermission('OTHER','CONTROL') == false ) { if (getPermission('OTHER','CONTROL') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -248,12 +247,12 @@ export class OtherControls{
streamDeck.noPermission(context,device,false); streamDeck.noPermission(context,device,false);
return; return;
} }
if (tool == 'open'){ //open category //if (tool == 'open'){ //open category
txt = game.i18n.localize(selectedControl.title); txt = game.i18n.localize(selectedControl.title);
src = selectedControl.icon; src = selectedControl.icon;
if (activeControl == selectedControl.name) if (activeControl == selectedControl.name)
ringColor = "#FF7B00"; ringColor = "#FF7B00";
} //}
} }
} }
else if (control == 'dispTools'){ //displayed tools else if (control == 'dispTools'){ //displayed tools
@@ -330,7 +329,7 @@ export class OtherControls{
} }
keyPressControl(settings){ keyPressControl(settings){
if (MODULE.getPermission('OTHER','CONTROL') == false ) return; if (getPermission('OTHER','CONTROL') == false ) return;
if (canvas.scene == null) return; if (canvas.scene == null) return;
const control = settings.control ? settings.control : 'dispControls'; const control = settings.control ? settings.control : 'dispControls';
const tool = settings.tool ? settings.tool : 'open'; const tool = settings.tool ? settings.tool : 'open';
@@ -346,9 +345,12 @@ export class OtherControls{
streamDeck.noPermission(context,device,false); streamDeck.noPermission(context,device,false);
return; return;
} }
if (compatibleCore('10.0')) {
ui.controls.initialize({layer: selectedControl.layer});
}
else {
ui.controls.activeControl = selectedControl.name; ui.controls.activeControl = selectedControl.name;
selectedControl.activeTool = selectedControl.activeTool; selectedControl.activeTool = selectedControl.activeTool;
if (compatibleCore("0.8.2")) {
for (let layer of canvas.layers) { for (let layer of canvas.layers) {
if (layer.options == undefined) continue; if (layer.options == undefined) continue;
if (layer.options.name == selectedControl.layer) { if (layer.options.name == selectedControl.layer) {
@@ -357,7 +359,6 @@ export class OtherControls{
} }
} }
} }
else canvas.getLayer(selectedControl.layer).activate();
} }
} }
else if (control == 'dispTools'){ //displayed tools else if (control == 'dispTools'){ //displayed tools
@@ -383,10 +384,17 @@ export class OtherControls{
else if (selectedTool.button){ else if (selectedTool.button){
selectedTool.onClick(); selectedTool.onClick();
} }
else else {
if (compatibleCore('10.0')) {
ui.controls.initialize({layer: selectedControl.layer, tool: selectedTool.name});
}
else {
selectedControl.activeTool = selectedTool.name; selectedControl.activeTool = selectedTool.name;
} }
} }
}
}
} }
else if (control == 'controlsOffset') { else if (control == 'controlsOffset') {
const offsetType = settings.controlsOffsetType ? settings.controlsOffsetType : 'absoluteOffset'; const offsetType = settings.controlsOffsetType ? settings.controlsOffsetType : 'absoluteOffset';
@@ -406,9 +414,12 @@ export class OtherControls{
return; return;
} }
if (tool == 'open'){ //open category if (tool == 'open'){ //open category
if (compatibleCore('10.0')) {
ui.controls.initialize({layer: selectedControl.layer});
}
else {
ui.controls.activeControl = control; ui.controls.activeControl = control;
selectedControl.activeTool = selectedControl.activeTool; selectedControl.activeTool = selectedControl.activeTool;
if (compatibleCore("0.8.2")) {
for (let layer of canvas.layers) { for (let layer of canvas.layers) {
if (layer.options == undefined) continue; if (layer.options == undefined) continue;
if (layer.options.name == selectedControl.layer) { if (layer.options.name == selectedControl.layer) {
@@ -417,7 +428,7 @@ export class OtherControls{
} }
} }
} }
else canvas.getLayer(selectedControl.layer).activate();
} }
else { else {
const selectedTool = selectedControl.tools.find(t => t.name == tool); const selectedTool = selectedControl.tools.find(t => t.name == tool);
@@ -426,8 +437,21 @@ export class OtherControls{
streamDeck.noPermission(context,device,false); streamDeck.noPermission(context,device,false);
return; return;
} }
if (compatibleCore('10.0')) {
if (selectedTool.toggle) {
ui.controls.initialize({layer: selectedControl.layer});
selectedTool.active = !selectedTool.active;
selectedTool.onClick(selectedTool.active);
}
else if (selectedTool.button){
ui.controls.initialize({layer: selectedControl.layer});
selectedTool.onClick();
}
else
ui.controls.initialize({layer: selectedControl.layer, tool: selectedTool.name});
}
else {
ui.controls.activeControl = control; ui.controls.activeControl = control;
if (compatibleCore("0.8.2")) {
for (let layer of canvas.layers) { for (let layer of canvas.layers) {
if (layer.options == undefined) continue; if (layer.options == undefined) continue;
if (layer.options.name == selectedControl.layer) { if (layer.options.name == selectedControl.layer) {
@@ -435,8 +459,6 @@ export class OtherControls{
break; break;
} }
} }
}
else canvas.getLayer(selectedControl.layer).activate();
if (selectedTool.toggle) { if (selectedTool.toggle) {
selectedTool.active = !selectedTool.active; selectedTool.active = !selectedTool.active;
selectedTool.onClick(selectedTool.active); selectedTool.onClick(selectedTool.active);
@@ -447,6 +469,8 @@ export class OtherControls{
else else
selectedControl.activeTool = tool; selectedControl.activeTool = tool;
} }
}
} }
} }
} }
@@ -456,7 +480,7 @@ export class OtherControls{
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
updateDarkness(settings,context,device,options={}){ updateDarkness(settings,context,device,options={}){
if (MODULE.getPermission('OTHER','DARKNESS') == false ) { if (getPermission('OTHER','DARKNESS') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -476,7 +500,7 @@ export class OtherControls{
} }
else if (func == 'disp'){ //display darkness else if (func == 'disp'){ //display darkness
src = 'modules/MaterialDeck/img/other/darkness/darkness.png'; src = 'modules/MaterialDeck/img/other/darkness/darkness.png';
const darkness = canvas.scene != null ? Math.floor(canvas.scene.data.darkness*100)/100 : ''; const darkness = canvas.scene != null ? compatibleCore('10.0') ? Math.floor(canvas.scene.darkness*100)/100 : Math.floor(canvas.scene.data.darkness*100)/100 : '';
txt += darkness; txt += darkness;
} }
streamDeck.setTitle(txt,context); streamDeck.setTitle(txt,context);
@@ -485,39 +509,48 @@ export class OtherControls{
keyPressDarkness(settings) { keyPressDarkness(settings) {
if (canvas.scene == null) return; if (canvas.scene == null) return;
if (MODULE.getPermission('OTHER','DARKNESS') == false ) return; if (getPermission('OTHER','DARKNESS') == false ) return;
const func = settings.darknessFunction ? settings.darknessFunction : 'value'; const func = settings.darknessFunction ? settings.darknessFunction : 'value';
const value = parseFloat(settings.darknessValue) ? parseFloat(settings.darknessValue) : 0; const value = parseFloat(settings.darknessValue) ? parseFloat(settings.darknessValue) : 0;
const animateDarkness = parseInt(settings.darknessAnimation) ? parseInt(settings.darknessAnimation) : 500;
if (func == 'value') //value if (func == 'value') //value
canvas.scene.update({darkness: value}); canvas.scene.update({darkness: value}, {animateDarkness});
else if (func == 'incDec'){ //increase/decrease else if (func == 'incDec'){ //increase/decrease
let darkness = canvas.scene.data.darkness - value; let darkness = compatibleCore('10.0') ? canvas.scene.darkness - value : canvas.scene.data.darkness - value;
if (darkness > 1) darkness = 1; if (darkness > 1) darkness = 1;
if (darkness < 0) darkness = 0; if (darkness < 0) darkness = 0;
canvas.scene.update({darkness: darkness}); canvas.scene.update({darkness: darkness}, {animateDarkness});
}
else if (func == 'transitionDay') {
canvas.scene.update({darkness: 0}, {animateDarkness: 10000})
}
else if (func == 'transitionNight') {
canvas.scene.update({darkness: 1}, {animateDarkness: 10000})
} }
} }
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
updateRollDice(settings,context,device,options={}){ updateRollDice(settings,context,device,options={}){
if (MODULE.getPermission('OTHER','DICE') == false ) { if (getPermission('OTHER','DICE') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
const background = settings.background ? settings.background : '#000000'; const background = settings.background ? settings.background : '#000000';
let txt = ''; let txt = '';
const formula = settings.rollDiceFormula ? settings.rollDiceFormula : '1d20 + 7';
if (settings.displayDiceName) txt = 'Roll: ' + settings.rollDiceFormula; if (settings.displayDiceName) txt = 'Roll: ' + formula;
streamDeck.setTitle(txt,context); streamDeck.setTitle(txt,context);
streamDeck.setIcon(context,device,'',{background:background}); streamDeck.setIcon(context,device,'',{background:background});
} }
keyPressRollDice(settings,context,device){ keyPressRollDice(settings,context,device){
if (MODULE.getPermission('OTHER','DICE') == false ) return; if (getPermission('OTHER','DICE') == false ) return;
if (settings.rollDiceFormula == undefined || settings.rollDiceFormula == '') return; const formula = settings.rollDiceFormula ? settings.rollDiceFormula : '1d20 + 7';
if (formula == '') return;
const rollFunction = settings.rollDiceFunction ? settings.rollDiceFunction : 'public'; const rollFunction = settings.rollDiceFunction ? settings.rollDiceFunction : 'public';
let actor; let actor;
@@ -527,8 +560,8 @@ export class OtherControls{
if (actor != undefined) tokenControlled = true; if (actor != undefined) tokenControlled = true;
let r; let r;
if (tokenControlled) r = new Roll(settings.rollDiceFormula,actor.getRollData()); if (tokenControlled) r = new Roll(formula,actor.getRollData());
else r = new Roll(settings.rollDiceFormula); else r = new Roll(formula);
r.evaluate({async:false}); r.evaluate({async:false});
@@ -539,12 +572,12 @@ export class OtherControls{
r.toMessage(r,{rollMode:"selfroll"}) r.toMessage(r,{rollMode:"selfroll"})
} }
else if (rollFunction == 'sd'){ else if (rollFunction == 'sd'){
let txt = settings.displayDiceName ? 'Roll: '+settings.rollDiceFormula + '\nResult: ' : ''; let txt = settings.displayDiceName ? 'Roll: '+formula + '\nResult: ' : '';
txt += r.total; txt += r.total;
streamDeck.setTitle(txt,context); streamDeck.setTitle(txt,context);
let data = this.rollData let data = this.rollData
data[context] = { data[context] = {
formula: settings.rollDiceFormula, formula: formula,
result: txt result: txt
} }
this.rollData = data; this.rollData = data;
@@ -556,7 +589,7 @@ export class OtherControls{
updateRollTable(settings,context,device,options={}){ updateRollTable(settings,context,device,options={}){
const name = settings.rollTableName; const name = settings.rollTableName;
if (name == undefined) return; if (name == undefined) return;
if (MODULE.getPermission('OTHER','TABLES') == false ) { if (getPermission('OTHER','TABLES') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -566,14 +599,14 @@ export class OtherControls{
if (table == undefined) return; if (table == undefined) return;
let txt = settings.displayRollName ? table.name : ''; let txt = settings.displayRollName ? table.name : '';
let src = settings.displayRollIcon ? table.data.img : ''; let src = settings.displayRollIcon ? (compatibleCore('10.0') ? table.img : table.data.img) : '';
if (table == undefined) { if (table == undefined) {
src = ''; src = '';
txt = ''; txt = '';
} }
else { else {
if (table.permission < 2 && MODULE.getPermission('OTHER','TABLES_ALL') == false ) { if (table.permission < 2 && getPermission('OTHER','TABLES_ALL') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -584,7 +617,7 @@ export class OtherControls{
} }
keyPressRollTable(settings){ keyPressRollTable(settings){
if (MODULE.getPermission('OTHER','TABLES') == false ) return; if (getPermission('OTHER','TABLES') == false ) return;
const name = settings.rollTableName; const name = settings.rollTableName;
if (name == undefined) return; if (name == undefined) return;
@@ -592,7 +625,7 @@ export class OtherControls{
const table = game.tables.getName(name); const table = game.tables.getName(name);
if (table != undefined) { if (table != undefined) {
if (table.permission < 2 && MODULE.getPermission('OTHER','TABLES_ALL') == false ) return; if (table.permission < 2 && getPermission('OTHER','TABLES_ALL') == false ) return;
if (func == 'open'){ //open if (func == 'open'){ //open
const element = document.getElementById(table.sheet.id); const element = document.getElementById(table.sheet.id);
if (element == null) table.sheet.render(true); if (element == null) table.sheet.render(true);
@@ -609,6 +642,21 @@ export class OtherControls{
getSidebarName(nr){ getSidebarName(nr){
let name; let name;
if (compatibleCore('10.0')) {
if (nr == 'chat') name = game.i18n.localize("DOCUMENT.ChatMessages");
else if (nr == 'combat') name = game.i18n.localize("DOCUMENT.Combats");
else if (nr == 'scenes') name = game.i18n.localize("DOCUMENT.Scenes");
else if (nr == 'actors') name = game.i18n.localize("DOCUMENT.Actors");
else if (nr == 'items') name = game.i18n.localize("DOCUMENT.Items");
else if (nr == 'journal') name = game.i18n.localize("DOCUMENT.JournalEntries");
else if (nr == 'tables') name = game.i18n.localize("DOCUMENT.RollTables");
else if (nr == 'cards') name = game.i18n.localize("DOCUMENT.Cards");
else if (nr == 'playlists') name = game.i18n.localize("DOCUMENT.Playlists");
else if (nr == 'compendium') name = game.i18n.localize("SIDEBAR.TabCompendium");
else if (nr == 'settings') name = game.i18n.localize("SIDEBAR.TabSettings");
else if (nr == 'collapse') name = game.i18n.localize("SIDEBAR.CollapseToggle");
}
else {
if (nr == 'chat') name = game.i18n.localize("SIDEBAR.TabChat"); if (nr == 'chat') name = game.i18n.localize("SIDEBAR.TabChat");
else if (nr == 'combat') name = game.i18n.localize("SIDEBAR.TabCombat"); else if (nr == 'combat') name = game.i18n.localize("SIDEBAR.TabCombat");
else if (nr == 'scenes') name = game.i18n.localize("SIDEBAR.TabScenes"); else if (nr == 'scenes') name = game.i18n.localize("SIDEBAR.TabScenes");
@@ -621,6 +669,7 @@ export class OtherControls{
else if (nr == 'compendium') name = game.i18n.localize("SIDEBAR.TabCompendium"); else if (nr == 'compendium') name = game.i18n.localize("SIDEBAR.TabCompendium");
else if (nr == 'settings') name = game.i18n.localize("SIDEBAR.TabSettings"); else if (nr == 'settings') name = game.i18n.localize("SIDEBAR.TabSettings");
else if (nr == 'collapse') name = game.i18n.localize("SIDEBAR.CollapseToggle"); else if (nr == 'collapse') name = game.i18n.localize("SIDEBAR.CollapseToggle");
}
return name; return name;
} }
@@ -629,11 +678,11 @@ export class OtherControls{
if (nr == 'chat') icon = window.CONFIG.ChatMessage.sidebarIcon; if (nr == 'chat') icon = window.CONFIG.ChatMessage.sidebarIcon;
else if (nr == 'combat') icon = window.CONFIG.Combat.sidebarIcon; else if (nr == 'combat') icon = window.CONFIG.Combat.sidebarIcon;
else if (nr == 'scenes') icon = window.CONFIG.Scene.sidebarIcon; else if (nr == 'scenes') icon = window.CONFIG.Scene.sidebarIcon;
else if (nr == 'actors') icon = "fas fa-users"; else if (nr == 'actors') icon = window.CONFIG.Actor.sidebarIcon;
else if (nr == 'items') icon = window.CONFIG.Item.sidebarIcon; else if (nr == 'items') icon = window.CONFIG.Item.sidebarIcon;
else if (nr == 'journal') icon = window.CONFIG.JournalEntry.sidebarIcon; else if (nr == 'journal') icon = window.CONFIG.JournalEntry.sidebarIcon;
else if (nr == 'tables') icon = window.CONFIG.RollTable.sidebarIcon; else if (nr == 'tables') icon = window.CONFIG.RollTable.sidebarIcon;
else if (nr == 'cards') icon = "fas fa-id-badge"; else if (nr == 'cards') icon = window.CONFIG.Cards.sidebarIcon;
else if (nr == 'playlists') icon = window.CONFIG.Playlist.sidebarIcon; else if (nr == 'playlists') icon = window.CONFIG.Playlist.sidebarIcon;
else if (nr == 'compendium') icon = "fas fa-atlas"; else if (nr == 'compendium') icon = "fas fa-atlas";
else if (nr == 'settings') icon = "fas fa-cogs"; else if (nr == 'settings') icon = "fas fa-cogs";
@@ -642,7 +691,7 @@ export class OtherControls{
} }
updateSidebar(settings,context,device,options={}){ updateSidebar(settings,context,device,options={}){
if (MODULE.getPermission('OTHER','SIDEBAR') == false ) { if (getPermission('OTHER','SIDEBAR') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -666,7 +715,7 @@ export class OtherControls{
} }
keyPressSidebar(settings){ keyPressSidebar(settings){
if (MODULE.getPermission('OTHER','SIDEBAR') == false ) return; if (getPermission('OTHER','SIDEBAR') == false ) return;
const sidebarTab = settings.sidebarTab ? settings.sidebarTab : 'chat'; const sidebarTab = settings.sidebarTab ? settings.sidebarTab : 'chat';
const popOut = settings.sidebarPopOut ? settings.sidebarPopOut : false; const popOut = settings.sidebarPopOut ? settings.sidebarPopOut : false;
@@ -718,17 +767,17 @@ export class OtherControls{
updateCompendium(settings,context,device,options={}){ updateCompendium(settings,context,device,options={}){
const name = settings.compendiumName; const name = settings.compendiumName;
if (name == undefined) return; if (name == undefined) return;
if (MODULE.getPermission('OTHER','COMPENDIUM') == false ) { if (getPermission('OTHER','COMPENDIUM') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
const compendium = game.packs.find(p=>p.metadata.label == name); const compendium = game.packs.find(p=>p.metadata.label == name);
if (compendium == undefined) return; if (compendium == undefined) return;
if (compendium.private && MODULE.getPermission('OTHER','COMPENDIUM_ALL') == false) { if (compendium.private && getPermission('OTHER','COMPENDIUM_ALL') == false) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
const rendered = compatibleCore("0.8.5") ? compendium.apps[0].rendered : compendium.rendered; const rendered = compendium.apps[0].rendered;
const background = settings.background ? settings.background : '#000000'; const background = settings.background ? settings.background : '#000000';
const ringOffColor = settings.offRing ? settings.offRing : '#000000'; const ringOffColor = settings.offRing ? settings.offRing : '#000000';
const ringOnColor = settings.onRing ? settings.onRing : '#00FF00'; const ringOnColor = settings.onRing ? settings.onRing : '#00FF00';
@@ -742,13 +791,13 @@ export class OtherControls{
keyPressCompendium(settings){ keyPressCompendium(settings){
let name = settings.compendiumName; let name = settings.compendiumName;
if (name == undefined) return; if (name == undefined) return;
if (MODULE.getPermission('OTHER','COMPENDIUM') == false ) return; if (getPermission('OTHER','COMPENDIUM') == false ) return;
const compendium = game.packs.find(p=>p.metadata.label == name); const compendium = game.packs.find(p=>p.metadata.label == name);
const rendered = compatibleCore("0.8.5") ? compendium.apps[0].rendered : compendium.rendered; const rendered = compendium.apps[0].rendered;
if (compendium == undefined) return; if (compendium == undefined) return;
if (compendium.private && MODULE.getPermission('OTHER','COMPENDIUM_ALL') == false) return; if (compendium.private && getPermission('OTHER','COMPENDIUM_ALL') == false) return;
else if (rendered) compatibleCore("0.8.5") ? compendium.apps[0].close() : compendium.close(); else if (rendered) compendium.apps[0].close();
else compendium.render(true); else compendium.render(true);
} }
@@ -761,11 +810,11 @@ export class OtherControls{
const journal = game.journal.getName(name); const journal = game.journal.getName(name);
if (journal == undefined) return; if (journal == undefined) return;
if (MODULE.getPermission('OTHER','JOURNAL') == false ) { if (getPermission('OTHER','JOURNAL') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
if (journal.permission < 2 && MODULE.getPermission('OTHER','JOURNAL_ALL') == false ) { if (journal.permission < 2 && getPermission('OTHER','JOURNAL_ALL') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -795,8 +844,8 @@ export class OtherControls{
const journal = game.journal.getName(name); const journal = game.journal.getName(name);
if (journal == undefined) return; if (journal == undefined) return;
if (MODULE.getPermission('OTHER','JOURNAL') == false ) return; if (getPermission('OTHER','JOURNAL') == false ) return;
if (journal.permission < 2 && MODULE.getPermission('OTHER','JOURNAL_ALL') == false ) return; if (journal.permission < 2 && getPermission('OTHER','JOURNAL_ALL') == false ) return;
if (journal.sheet.rendered == false) journal.sheet.render(true); if (journal.sheet.rendered == false) journal.sheet.render(true);
else journal.sheet.close(); else journal.sheet.close();
@@ -805,7 +854,7 @@ export class OtherControls{
////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////
updateChatMessage(settings,context,device,options={}){ updateChatMessage(settings,context,device,options={}){
if (MODULE.getPermission('OTHER','CHAT') == false ) { if (getPermission('OTHER','CHAT') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -815,7 +864,7 @@ export class OtherControls{
} }
keyPressChatMessage(settings){ keyPressChatMessage(settings){
if (MODULE.getPermission('OTHER','CHAT') == false ) return; if (getPermission('OTHER','CHAT') == false ) return;
const message = settings.chatMessage ? settings.chatMessage : ''; const message = settings.chatMessage ? settings.chatMessage : '';
let chatData = { let chatData = {

View File

@@ -1,6 +1,4 @@
import * as MODULE from "../MaterialDeck.js"; import { moduleName, streamDeck, getPermission } from "../../MaterialDeck.js";
import {streamDeck} from "../MaterialDeck.js";
import {compatibleCore} from "./misc.js";
export class PlaylistControl{ export class PlaylistControl{
constructor(){ constructor(){
@@ -22,7 +20,7 @@ export class PlaylistControl{
} }
update(settings,context,device){ update(settings,context,device){
if (MODULE.getPermission('PLAYLIST','PLAY') == false ) { if (getPermission('PLAYLIST','PLAY') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -84,7 +82,7 @@ export class PlaylistControl{
let playlistOffset = parseInt(settings.offset); let playlistOffset = parseInt(settings.offset);
if (isNaN(playlistOffset)) playlistOffset = 0; if (isNaN(playlistOffset)) playlistOffset = 0;
let number = parseInt(this.playlistOffset + playlistOffset); let number = parseInt(this.playlistOffset + playlistOffset);
const nrOfPlaylists = parseInt(game.settings.get(MODULE.moduleName,'playlists').playlistNumber); const nrOfPlaylists = parseInt(game.settings.get(moduleName,'playlists').playlistNumber);
if (number < 0) number += nrOfPlaylists; if (number < 0) number += nrOfPlaylists;
else if (number >= nrOfPlaylists) number -= nrOfPlaylists; else if (number >= nrOfPlaylists) number -= nrOfPlaylists;
const targetPlaylist = this.getPlaylist(number); const targetPlaylist = this.getPlaylist(number);
@@ -116,7 +114,7 @@ export class PlaylistControl{
let playlist = this.getPlaylist(playlistNr); let playlist = this.getPlaylist(playlistNr);
if (playlist != undefined){ if (playlist != undefined){
const track = compatibleCore("0.8.1") ? playlist.sounds.contents[trackNr] : playlist.sounds[trackNr]; const track = playlist.sounds.contents[trackNr];
if (track != undefined){ if (track != undefined){
if (track.playing) if (track.playing)
ringColor = ringOnColor; ringColor = ringOnColor;
@@ -157,7 +155,7 @@ export class PlaylistControl{
} }
else { else {
let playing = game.playlists.playing; let playing = game.playlists.playing;
let settings = game.settings.get(MODULE.moduleName,'playlists'); let settings = game.settings.get(moduleName,'playlists');
let selectedPlaylists = settings.selectedPlaylist; let selectedPlaylists = settings.selectedPlaylist;
for (let i=0; i<playing.length; i++){ for (let i=0; i<playing.length; i++){
const playlistNr = selectedPlaylists.findIndex(p => p == playing[i]._id); const playlistNr = selectedPlaylists.findIndex(p => p == playing[i]._id);
@@ -189,14 +187,14 @@ export class PlaylistControl{
} }
getPlaylist(num){ getPlaylist(num){
let selectedPlaylists = game.settings.get(MODULE.moduleName,'playlists').selectedPlaylist; let selectedPlaylists = game.settings.get(moduleName,'playlists').selectedPlaylist;
if (selectedPlaylists != undefined) if (selectedPlaylists != undefined)
return game.playlists.get(selectedPlaylists[num]); return game.playlists.get(selectedPlaylists[num]);
else return undefined; else return undefined;
} }
keyPress(settings,context,device){ keyPress(settings,context,device){
if (MODULE.getPermission('PLAYLIST','PLAY') == false ) return; if (getPermission('PLAYLIST','PLAY') == false ) return;
let playlistNr = settings.playlistNr; let playlistNr = settings.playlistNr;
if (playlistNr == undefined || playlistNr < 1) playlistNr = 1; if (playlistNr == undefined || playlistNr < 1) playlistNr = 1;
playlistNr--; playlistNr--;
@@ -222,7 +220,7 @@ export class PlaylistControl{
if (playlistMode == 'playlist') if (playlistMode == 'playlist')
this.playPlaylist(playlist,playlistNr); this.playPlaylist(playlist,playlistNr);
else { else {
const track = compatibleCore("0.8.1") ? playlist.sounds.contents[trackNr] : playlist.sounds[trackNr]; const track = playlist.sounds.contents[trackNr];
if (track != undefined){ if (track != undefined){
this.playTrack(track,playlist,playlistNr); this.playTrack(track,playlist,playlistNr);
} }
@@ -251,7 +249,7 @@ export class PlaylistControl{
let playlistOffset = parseInt(settings.offset); let playlistOffset = parseInt(settings.offset);
if (isNaN(playlistOffset)) playlistOffset = 0; if (isNaN(playlistOffset)) playlistOffset = 0;
let number = parseInt(this.playlistOffset + playlistOffset); let number = parseInt(this.playlistOffset + playlistOffset);
const nrOfPlaylists = parseInt(game.settings.get(MODULE.moduleName,'playlists').playlistNumber); const nrOfPlaylists = parseInt(game.settings.get(moduleName,'playlists').playlistNumber);
if (number < 0) number += nrOfPlaylists; if (number < 0) number += nrOfPlaylists;
else if (number >= nrOfPlaylists) number -= nrOfPlaylists; else if (number >= nrOfPlaylists) number -= nrOfPlaylists;
this.playlistOffset = number; this.playlistOffset = number;
@@ -281,12 +279,15 @@ export class PlaylistControl{
playlist.stopAll(); playlist.stopAll();
return; return;
} }
let mode = game.settings.get(MODULE.moduleName,'playlists').playlistMode[playlistNr]; let mode = game.settings.get(moduleName,'playlists').playlistMode[playlistNr];
const originalPlayMode = playlist.mode;
await playlist.update({mode: CONST.PLAYLIST_MODES.SEQUENTIAL});
if (mode == 0) { if (mode == 0) {
mode = game.settings.get(MODULE.moduleName,'playlists').playMode; mode = game.settings.get(moduleName,'playlists').playMode;
if (mode == 2) await this.stopAll(); if (mode == 2) await this.stopAll(true);
} }
playlist.playAll(); playlist.playAll();
await playlist.update({mode: originalPlayMode});
} }
async playTrack(track,playlist,playlistNr){ async playTrack(track,playlist,playlistNr){
@@ -301,23 +302,25 @@ export class PlaylistControl{
return; return;
} }
let play; let play;
const originalPlayMode = playlist.mode;
if (track.playing) if (track.playing)
play = false; play = false;
else { else {
play = true; play = true;
let mode = game.settings.get(MODULE.moduleName,'playlists').playlistMode[playlistNr]; let mode = game.settings.get(moduleName,'playlists').playlistMode[playlistNr];
if (mode == 0) { if (mode == 0) {
mode = game.settings.get(MODULE.moduleName,'playlists').playMode; mode = game.settings.get(moduleName,'playlists').playMode;
if (mode == 1) await playlist.stopAll(); if (mode == 0) await playlist.update({mode: CONST.PLAYLIST_MODES.SIMULTANEOUS});
else if (mode == 2) await this.stopAll(); else if (mode == 1) await playlist.stopAll();
else if (mode == 2) await this.stopAll(true);
} }
else if (mode == 2) await playlist.stopAll(); else if (mode == 2) await playlist.stopAll(true);
} }
if (compatibleCore("0.8.1") && play) await playlist.playSound(track); if (play) await playlist.playSound(track);
else if (compatibleCore("0.8.1")) await playlist.stopSound(track); else await playlist.stopSound(track);
else await playlist.updateEmbeddedEntity("PlaylistSound", {_id: track._id, playing: play});
playlist.update({playing: play}); playlist.update({playing: play});
await playlist.update({mode: originalPlayMode});
} }
} }

View File

@@ -1,6 +1,5 @@
import * as MODULE from "../MaterialDeck.js"; import { streamDeck, getPermission } from "../../MaterialDeck.js";
import {streamDeck} from "../MaterialDeck.js"; import { compatibleCore } from "../misc.js";
import {compatibleCore} from "./misc.js";
export class SceneControl{ export class SceneControl{
constructor(){ constructor(){
@@ -34,7 +33,7 @@ export class SceneControl{
let src = ""; let src = "";
let name = ""; let name = "";
if (func == 'visible') { //visible scenes if (func == 'visible') { //visible scenes
if (MODULE.getPermission('SCENE','VISIBLE') == false ) { if (getPermission('SCENE','VISIBLE') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -47,12 +46,12 @@ export class SceneControl{
if (scene != undefined){ if (scene != undefined){
ringColor = scene.isView ? ringOnColor : ringOffColor; ringColor = scene.isView ? ringOnColor : ringOffColor;
if (settings.displaySceneName) name = scene.name; if (settings.displaySceneName) name = scene.name;
if (settings.displaySceneIcon) src = scene.img; if (settings.displaySceneIcon) src = compatibleCore('10.0') ? scene.background.src : scene.img;
if (scene.active) name += "\n(Active)"; if (scene.active) name += "\n(Active)";
} }
} }
else if (func == 'dir') { //from directory else if (func == 'dir') { //from directory
if (MODULE.getPermission('SCENE','DIRECTORY') == false ) { if (getPermission('SCENE','DIRECTORY') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -61,33 +60,39 @@ export class SceneControl{
nr--; nr--;
let sceneList = []; let sceneList = [];
if (compatibleCore('10.0')) {
sceneList = ui.scenes.documents;
}
else {
for (let i=0; i<ui.scenes.tree.children.length; i++){ for (let i=0; i<ui.scenes.tree.children.length; i++){
const scenesInFolder = compatibleCore("0.8.1") ? ui.scenes.tree.children[i].contents : ui.scenes.tree.children[i].entities; const scenesInFolder = ui.scenes.tree.children[i].contents;
for (let j=0; j<scenesInFolder.length; j++) for (let j=0; j<scenesInFolder.length; j++)
sceneList.push(scenesInFolder[j]) sceneList.push(scenesInFolder[j])
} }
for (let i=0; i<ui.scenes.tree.content.length; i++) for (let i=0; i<ui.scenes.tree.content.length; i++)
sceneList.push(ui.scenes.tree.content[i]) sceneList.push(ui.scenes.tree.content[i])
}
const scene = sceneList[nr+this.sceneOffset]; const scene = sceneList[nr+this.sceneOffset];
if (scene != undefined){ if (scene != undefined){
if (scene.isView) if (scene.isView)
ringColor = ringOnColor; ringColor = ringOnColor;
else if (scene.data.navigation && scene.data.permission.default == 0) else if ((compatibleCore('10.0') && scene.navigation && scene.permission.default == 0) || (!compatibleCore('10.0') && scene.data.navigation && scene.data.permission.default == 0))
ringColor = '#000791'; ringColor = '#000791';
else if (scene.data.navigation) else if ((compatibleCore('10.0') && scene.navigation) || (!compatibleCore('10.0') && scene.data.navigation))
ringColor = '#2d2d2d'; ringColor = '#2d2d2d';
else else
ringColor = ringOffColor; ringColor = ringOffColor;
if (settings.displaySceneName) name = scene.name; if (settings.displaySceneName) name = scene.name;
if (settings.displaySceneIcon) src = scene.img; if (settings.displaySceneIcon) src = compatibleCore('10.0') ? scene.background.src : scene.img;
if (scene.active) name += "\n(Active)"; if (scene.active) name += "\n(Active)";
} }
} }
else if (func == 'any') { //by name else if (func == 'any') { //by name
if (MODULE.getPermission('SCENE','NAME') == false ) { if (getPermission('SCENE','NAME') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -97,19 +102,19 @@ export class SceneControl{
if (scene != undefined){ if (scene != undefined){
ringColor = scene.isView ? ringOnColor : ringOffColor; ringColor = scene.isView ? ringOnColor : ringOffColor;
if (settings.displaySceneName) name = scene.name; if (settings.displaySceneName) name = scene.name;
if (settings.displaySceneIcon) src = scene.img; if (settings.displaySceneIcon) src = compatibleCore('10.0') ? scene.background.src : scene.img;
if (scene.active) name += "\n(Active)"; if (scene.active) name += "\n(Active)";
} }
} }
else if (func == 'active'){ else if (func == 'active'){
if (MODULE.getPermission('SCENE','ACTIVE') == false ) { if (getPermission('SCENE','ACTIVE') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
const scene = game.scenes.active; const scene = game.scenes.active;
if (scene == undefined) return; if (scene == undefined) return;
if (settings.displaySceneName) name = scene.name; if (settings.displaySceneName) name = scene.name;
if (settings.displaySceneIcon) src = scene.img; if (settings.displaySceneIcon) src = compatibleCore('10.0') ? scene.background.src : scene.img;
ring = 0; ring = 0;
} }
else if (func == 'offset'){ else if (func == 'offset'){
@@ -126,7 +131,7 @@ export class SceneControl{
const func = settings.sceneFunction ? settings.sceneFunction : 'visible'; const func = settings.sceneFunction ? settings.sceneFunction : 'visible';
if (func == 'visible'){ //visible scenes if (func == 'visible'){ //visible scenes
if (MODULE.getPermission('SCENE','VISIBLE') == false ) return; if (getPermission('SCENE','VISIBLE') == false ) return;
const viewFunc = settings.sceneViewFunction ? settings.sceneViewFunction : 'view'; const viewFunc = settings.sceneViewFunction ? settings.sceneViewFunction : 'view';
let nr = parseInt(settings.sceneNr); let nr = parseInt(settings.sceneNr);
if (isNaN(nr) || nr < 1) nr = 1; if (isNaN(nr) || nr < 1) nr = 1;
@@ -147,20 +152,25 @@ export class SceneControl{
} }
} }
else if (func == 'dir') { //from directory else if (func == 'dir') { //from directory
if (MODULE.getPermission('SCENE','DIRECTORY') == false ) return; if (getPermission('SCENE','DIRECTORY') == false ) return;
const viewFunc = settings.sceneViewFunction ? settings.sceneViewFunction : 'view'; const viewFunc = settings.sceneViewFunction ? settings.sceneViewFunction : 'view';
let nr = parseInt(settings.sceneNr); let nr = parseInt(settings.sceneNr);
if (isNaN(nr) || nr < 1) nr = 1; if (isNaN(nr) || nr < 1) nr = 1;
nr--; nr--;
let sceneList = []; let sceneList = [];
if (compatibleCore('10.0')) {
sceneList = ui.scenes.documents;
}
else {
for (let i=0; i<ui.scenes.tree.children.length; i++){ for (let i=0; i<ui.scenes.tree.children.length; i++){
const scenesInFolder = compatibleCore("0.8.1") ? ui.scenes.tree.children[i].contents : ui.scenes.tree.children[i].entities; const scenesInFolder = ui.scenes.tree.children[i].contents;
for (let j=0; j<scenesInFolder.length; j++) for (let j=0; j<scenesInFolder.length; j++)
sceneList.push(scenesInFolder[j]) sceneList.push(scenesInFolder[j])
} }
for (let i=0; i<ui.scenes.tree.content.length; i++) for (let i=0; i<ui.scenes.tree.content.length; i++)
sceneList.push(ui.scenes.tree.content[i]) sceneList.push(ui.scenes.tree.content[i])
}
const scene = sceneList[nr+this.sceneOffset]; const scene = sceneList[nr+this.sceneOffset];
@@ -179,7 +189,7 @@ export class SceneControl{
} }
else if (func == 'any'){ //by name else if (func == 'any'){ //by name
if (MODULE.getPermission('SCENE','NAME') == false ) return; if (getPermission('SCENE','NAME') == false ) return;
if (settings.sceneName == undefined || settings.sceneName == '') return; if (settings.sceneName == undefined || settings.sceneName == '') return;
const scenes = game.scenes.entries; const scenes = game.scenes.entries;
let scene = game.scenes.getName(settings.sceneName); let scene = game.scenes.getName(settings.sceneName);
@@ -199,7 +209,7 @@ export class SceneControl{
} }
} }
else if (func == 'active'){ else if (func == 'active'){
if (MODULE.getPermission('SCENE','ACTIVE') == false ) return; if (getPermission('SCENE','ACTIVE') == false ) return;
const scene = game.scenes.active; const scene = game.scenes.active;
if (scene == undefined) return; if (scene == undefined) return;
scene.view(); scene.view();

View File

@@ -1,6 +1,4 @@
import * as MODULE from "../MaterialDeck.js"; import { moduleName, streamDeck, getPermission } from "../../MaterialDeck.js";
import {streamDeck} from "../MaterialDeck.js";
import {compatibleCore} from "./misc.js";
export class SoundboardControl{ export class SoundboardControl{
constructor(){ constructor(){
@@ -22,7 +20,7 @@ export class SoundboardControl{
} }
update(settings,context,device){ update(settings,context,device){
if (MODULE.getPermission('SOUNDBOARD','PLAY') == false ) { if (getPermission('SOUNDBOARD','PLAY') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -40,7 +38,7 @@ export class SoundboardControl{
soundNr--; soundNr--;
soundNr += this.offset; soundNr += this.offset;
let soundboardSettings = game.settings.get(MODULE.moduleName, 'soundboardSettings'); let soundboardSettings = game.settings.get(moduleName, 'soundboardSettings');
ringColor = (this.activeSounds[soundNr]==undefined) ? soundboardSettings.colorOff[soundNr] : soundboardSettings.colorOn[soundNr]; ringColor = (this.activeSounds[soundNr]==undefined) ? soundboardSettings.colorOff[soundNr] : soundboardSettings.colorOn[soundNr];
if (settings.displayName && soundboardSettings.name != undefined) txt = soundboardSettings.name[soundNr]; if (settings.displayName && soundboardSettings.name != undefined) txt = soundboardSettings.name[soundNr];
@@ -76,7 +74,7 @@ export class SoundboardControl{
} }
keyPressDown(settings){ keyPressDown(settings){
if (MODULE.getPermission('SOUNDBOARD','PLAY') == false ) return; if (getPermission('SOUNDBOARD','PLAY') == false ) return;
const mode = settings.soundboardMode ? settings.soundboardMode : 'playSound'; const mode = settings.soundboardMode ? settings.soundboardMode : 'playSound';
if (mode == 'playSound') { //Play sound if (mode == 'playSound') { //Play sound
@@ -85,7 +83,7 @@ export class SoundboardControl{
soundNr--; soundNr--;
soundNr += this.offset; soundNr += this.offset;
const playMode = game.settings.get(MODULE.moduleName,'soundboardSettings').mode[soundNr]; const playMode = game.settings.get(moduleName,'soundboardSettings').mode[soundNr];
const repeat = (playMode > 0) ? true : false; const repeat = (playMode > 0) ? true : false;
const play = (this.activeSounds[soundNr] == undefined) ? true : false; const play = (this.activeSounds[soundNr] == undefined) ? true : false;
@@ -107,7 +105,7 @@ export class SoundboardControl{
} }
keyPressUp(settings){ keyPressUp(settings){
if (MODULE.getPermission('SOUNDBOARD','PLAY') == false ) return; if (getPermission('SOUNDBOARD','PLAY') == false ) return;
const mode = settings.soundboardMode ? settings.soundboardMode : 'playSound'; const mode = settings.soundboardMode ? settings.soundboardMode : 'playSound';
if (mode != 'playSound') return; if (mode != 'playSound') return;
@@ -117,14 +115,14 @@ export class SoundboardControl{
soundNr--; soundNr--;
soundNr += this.offset; soundNr += this.offset;
const playMode = game.settings.get(MODULE.moduleName,'soundboardSettings').mode[soundNr]; const playMode = game.settings.get(moduleName,'soundboardSettings').mode[soundNr];
if (playMode == 2) if (playMode == 2)
this.prePlaySound(soundNr,false,false); this.prePlaySound(soundNr,false,false);
} }
async prePlaySound(soundNr,repeat,play){ async prePlaySound(soundNr,repeat,play){
const soundBoardSettings = game.settings.get(MODULE.moduleName,'soundboardSettings'); const soundBoardSettings = game.settings.get(moduleName,'soundboardSettings');
const playlistId = (soundBoardSettings.selectedPlaylists != undefined) ? soundBoardSettings.selectedPlaylists[soundNr] : undefined; const playlistId = (soundBoardSettings.selectedPlaylists != undefined) ? soundBoardSettings.selectedPlaylists[soundNr] : undefined;
let src; let src;
if (playlistId == "" || playlistId == undefined) return; if (playlistId == "" || playlistId == undefined) return;
@@ -144,12 +142,12 @@ export class SoundboardControl{
const soundId = soundBoardSettings.sounds[soundNr]; const soundId = soundBoardSettings.sounds[soundNr];
const sounds = game.playlists.get(playlistId).sounds; const sounds = game.playlists.get(playlistId).sounds;
if (sounds == undefined) return; if (sounds == undefined) return;
const sound = compatibleCore("0.8.1") ? sounds.find(p => p.id == soundId) : sounds.find(p => p._id == soundId); const sound = sounds.find(p => p.id == soundId);
if (sound == undefined) return; if (sound == undefined) return;
src = sound.path; src = sound.path;
} }
let volume = game.settings.get(MODULE.moduleName,'soundboardSettings').volume[soundNr]/100; let volume = game.settings.get(moduleName,'soundboardSettings').volume[soundNr]/100;
volume = AudioHelper.inputToVolume(volume); volume = AudioHelper.inputToVolume(volume);
let payload = { let payload = {
@@ -169,7 +167,6 @@ export class SoundboardControl{
if (play){ if (play){
volume *= game.settings.get("core", "globalAmbientVolume"); volume *= game.settings.get("core", "globalAmbientVolume");
if (compatibleCore("0.8.1")) {
let newSound = new Sound(src); let newSound = new Sound(src);
if(newSound.loaded == false) await newSound.load({autoplay:true}); if(newSound.loaded == false) await newSound.load({autoplay:true});
newSound.on('end', ()=>{ newSound.on('end', ()=>{
@@ -181,21 +178,6 @@ export class SoundboardControl{
newSound.play({loop:repeat,volume:volume}); newSound.play({loop:repeat,volume:volume});
this.activeSounds[soundNr] = newSound; this.activeSounds[soundNr] = newSound;
} }
else {
let howl = new Howl({src, volume, loop: repeat, onend: (id)=>{
if (repeat == false){
this.activeSounds[soundNr] = undefined;
this.updateAll();
}
},
onstop: ()=>{
this.activeSounds[soundNr] = undefined;
this.updateAll();
}});
howl.play();
this.activeSounds[soundNr] = howl;
}
}
else { else {
if (this.activeSounds[soundNr] != undefined) this.activeSounds[soundNr].stop(); if (this.activeSounds[soundNr] != undefined) this.activeSounds[soundNr].stop();
this.activeSounds[soundNr] = undefined; this.activeSounds[soundNr] = undefined;

View File

@@ -1,11 +1,11 @@
import * as MODULE from "../MaterialDeck.js"; import { streamDeck, macroControl, otherControls, tokenHelper, getPermission } from "../../MaterialDeck.js";
import {streamDeck, macroControl, otherControls, tokenHelper} from "../MaterialDeck.js"; import { compatibleCore } from "../misc.js";
import { compatibleCore } from "./misc.js";
export class TokenControl{ export class TokenControl{
constructor(){ constructor(){
this.active = false; this.active = false;
this.wildcardOffset = 0; this.wildcardOffset = 0;
this.itemOffset = 0;
} }
async update(tokenId=null){ async update(tokenId=null){
@@ -43,11 +43,11 @@ export class TokenControl{
let uses = undefined; let uses = undefined;
let hp = undefined; let hp = undefined;
if (validToken) { if (validToken) {
if (token.owner == false && token.observer == true && MODULE.getPermission('TOKEN','OBSERVER') == false ) { if (token.owner == false && token.observer == true && getPermission('TOKEN','OBSERVER') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
if (token.owner == false && token.observer == false && MODULE.getPermission('TOKEN','NON_OWNED') == false ) { if (token.owner == false && token.observer == false && getPermission('TOKEN','NON_OWNED') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -58,16 +58,16 @@ export class TokenControl{
const permission = token.actor?.permission; const permission = token.actor?.permission;
if (settings.combat){ if (settings.combat){
if (permission == 0 && MODULE.getPermission('COMBAT','DISPLAY_ALL_NAMES') == false) txt = ""; if (permission == 0 && getPermission('COMBAT','DISPLAY_ALL_NAMES') == false) txt = "";
else if (permission == 1 && MODULE.getPermission('COMBAT','DISPLAY_LIMITED_NAME') == false) txt = ""; else if (permission == 1 && getPermission('COMBAT','DISPLAY_LIMITED_NAME') == false) txt = "";
else if (permission == 2 && MODULE.getPermission('COMBAT','DISPLAY_OBSERVER_NAME') == false) txt = ""; else if (permission == 2 && getPermission('COMBAT','DISPLAY_OBSERVER_NAME') == false) txt = "";
if (permission == 0 && stats == 'HP') stats = 'none'; if (permission == 0 && stats == 'HP') stats = 'none';
else if (stats == 'HP' && permission == 1 && MODULE.getPermission('COMBAT','DISPLAY_LIMITED_HP') == false) stats = 'none'; else if (stats == 'HP' && permission == 1 && getPermission('COMBAT','DISPLAY_LIMITED_HP') == false) stats = 'none';
else if (stats == 'HP' && permission == 2 && MODULE.getPermission('COMBAT','DISPLAY_OBSERVER_HP') == false) stats = 'none'; else if (stats == 'HP' && permission == 2 && getPermission('COMBAT','DISPLAY_OBSERVER_HP') == false) stats = 'none';
else if (stats != 'HP' && permission < 3 && MODULE.getPermission('COMBAT','DISPLAY_NON_OWNED_STATS') == false) stats = 'none'; else if (stats != 'HP' && permission < 3 && getPermission('COMBAT','DISPLAY_NON_OWNED_STATS') == false) stats = 'none';
} }
else if (MODULE.getPermission('TOKEN','STATS') == false) { else if (getPermission('TOKEN','STATS') == false) {
statsOld = stats; statsOld = stats;
stats = 'none'; stats = 'none';
} }
@@ -231,12 +231,12 @@ export class TokenControl{
} }
if (settings.onClick == 'visibility') { //toggle visibility if (settings.onClick == 'visibility') { //toggle visibility
if (MODULE.getPermission('TOKEN','VISIBILITY') == false ) { if (getPermission('TOKEN','VISIBILITY') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
ring = 1; ring = 1;
if (token.data.hidden){ if (compatibleCore('10.0') ? token.document.hidden : token.data.hidden){
ring = 2; ring = 2;
ringColor = "#FF7B00"; ringColor = "#FF7B00";
} }
@@ -246,7 +246,7 @@ export class TokenControl{
} }
} }
else if (settings.onClick == 'combatState') { //toggle combat state else if (settings.onClick == 'combatState') { //toggle combat state
if (MODULE.getPermission('TOKEN','COMBAT') == false ) { if (getPermission('TOKEN','COMBAT') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -271,7 +271,7 @@ export class TokenControl{
} }
} }
else if (settings.onClick == 'condition') { //handle condition else if (settings.onClick == 'condition') { //handle condition
if (MODULE.getPermission('TOKEN','CONDITIONS') == false ) { if (getPermission('TOKEN','CONDITIONS') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -286,7 +286,7 @@ export class TokenControl{
} }
} }
else if (settings.onClick == 'cubCondition') { //Combat Utility Belt conditions else if (settings.onClick == 'cubCondition') { //Combat Utility Belt conditions
if (MODULE.getPermission('TOKEN','CONDITIONS') == false ) { if (getPermission('TOKEN','CONDITIONS') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -303,7 +303,7 @@ export class TokenControl{
} }
} }
else if (settings.onClick == 'wildcard') { //wildcard images else if (settings.onClick == 'wildcard') { //wildcard images
if (MODULE.getPermission('TOKEN','WILDCARD') == false ) { if (getPermission('TOKEN','WILDCARD') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -316,7 +316,7 @@ export class TokenControl{
let currentImgNr = 0 let currentImgNr = 0
let imgNr; let imgNr;
for (let i=0; i<images.length; i++) for (let i=0; i<images.length; i++)
if (images[i] == token.data.img){ if (images[i] == tokenHelper.getTokenIcon(token)){
currentImgNr = i; currentImgNr = i;
break; break;
} }
@@ -342,32 +342,61 @@ export class TokenControl{
else if (settings.onClick == 'initiative') //Initiative else if (settings.onClick == 'initiative') //Initiative
iconSrc = "modules/MaterialDeck/img/token/init.png"; iconSrc = "modules/MaterialDeck/img/token/init.png";
} }
else if (mode == 'offset') {
iconSrc = "modules/MaterialDeck/img/black.png";
const itemOffset = settings.itemOffset ? settings.itemOffset : 0;
ringColor = settings.offRing ? settings.offRing : '#000000';
const ringOnColor = settings.onRing ? settings.onRing : '#00FF00';
ring = 1;
if (itemOffset == this.itemOffset) {
ring = 2;
ringColor = ringOnColor;
}
}
else if (mode == 'offsetRel') {
}
else if (mode == 'dispOffset') {
iconSrc = "modules/MaterialDeck/img/black.png";
const prependTitle = settings.offsetPrepend ? settings.offsetPrepend : '';
txt += prependTitle + this.itemOffset;
}
//Items //Items
else { else {
txt += prependTitle; txt += prependTitle;
const allItems = token.actor.items; const allItems = token.actor.items;
const itemNr = settings.itemNr ? settings.itemNr - 1 : 0; let itemNr = settings.itemNr ? settings.itemNr - 1 : 0;
itemNr += this.itemOffset;
const displayUses = settings.displayUses ? settings.displayUses : false; const displayUses = settings.displayUses ? settings.displayUses : false;
const displayName = settings.displayInventoryName ? settings.displayInventoryName : false; const displayName = settings.displayInventoryName ? settings.displayInventoryName : false;
const displayIcon = settings.displayInventoryIcon ? settings.displayInventoryIcon : false; const displayIcon = settings.displayInventoryIcon ? settings.displayInventoryIcon : false;
const selectionMode = settings.inventorySelection ? settings.inventorySelection : 'order';
let items = allItems; let items = allItems;
let item; let item;
if (mode == 'inventory') { if (mode == 'inventory') {
items = tokenHelper.getItems(token,settings.inventoryType); items = tokenHelper.getItems(token,settings.inventoryType);
items = this.sortItems(items); items = this.sortItems(items);
item = items[itemNr]; if (selectionMode == 'order') item = items[itemNr];
else if (selectionMode == 'name') item = items.filter(i => i.name == settings.itemName)[0];
else if (selectionMode == 'id') item = items.filter(i => i.id == settings.itemName)[0];
if (item != undefined && displayUses) uses = tokenHelper.getItemUses(item); if (item != undefined && displayUses) uses = tokenHelper.getItemUses(item);
} }
else if (mode == 'features') { else if (mode == 'features') {
items = tokenHelper.getFeatures(token,settings.featureType); items = tokenHelper.getFeatures(token,settings.featureType);
items = this.sortItems(items); items = this.sortItems(items);
item = items[itemNr]; if (selectionMode == 'order') item = items[itemNr];
else if (selectionMode == 'name') item = items.filter(i => i.name == settings.itemName)[0];
else if (selectionMode == 'id') item = items.filter(i => i.id == settings.itemName)[0];
if (item != undefined && displayUses) uses = tokenHelper.getFeatureUses(item); if (item != undefined && displayUses) uses = tokenHelper.getFeatureUses(item);
} }
else if (mode == 'spellbook') { else if (mode == 'spellbook') {
items = tokenHelper.getSpells(token,settings.spellType); items = tokenHelper.getSpells(token,settings.spellType);
items = this.sortItems(items); items = this.sortItems(items);
item = items[itemNr]; if (selectionMode == 'order') item = items[itemNr];
else if (selectionMode == 'name') item = items.filter(i => i.name == settings.itemName)[0];
else if (selectionMode == 'id') item = items.filter(i => i.id == settings.itemName)[0];
if (displayUses && item != undefined) uses = tokenHelper.getSpellUses(token,settings.spellType,item); if (displayUses && item != undefined) uses = tokenHelper.getSpellUses(token,settings.spellType,item);
} }
if (item != undefined) { if (item != undefined) {
@@ -382,7 +411,7 @@ export class TokenControl{
if (mode == 'token') { if (mode == 'token') {
iconSrc += ""; iconSrc += "";
if (settings.onClick == 'visibility') { //toggle visibility if (settings.onClick == 'visibility') { //toggle visibility
if (MODULE.getPermission('TOKEN','VISIBILITY') == false ) { if (getPermission('TOKEN','VISIBILITY') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -393,7 +422,7 @@ export class TokenControl{
} }
} }
else if (settings.onClick == 'combatState') { //toggle combat state else if (settings.onClick == 'combatState') { //toggle combat state
if (MODULE.getPermission('TOKEN','COMBAT') == false ) { if (getPermission('TOKEN','COMBAT') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -411,7 +440,7 @@ export class TokenControl{
} }
} }
else if (settings.onClick == 'condition') { //toggle condition else if (settings.onClick == 'condition') { //toggle condition
if (MODULE.getPermission('TOKEN','CONDITIONS') == false ) { if (getPermission('TOKEN','CONDITIONS') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -420,7 +449,7 @@ export class TokenControl{
if (icon == 'stats') iconSrc = tokenHelper.getConditionIcon(settings.condition); if (icon == 'stats') iconSrc = tokenHelper.getConditionIcon(settings.condition);
} }
else if (settings.onClick == 'cubCondition') { //Combat Utility Belt conditions else if (settings.onClick == 'cubCondition') { //Combat Utility Belt conditions
if (MODULE.getPermission('TOKEN','CONDITIONS') == false ) { if (getPermission('TOKEN','CONDITIONS') == false ) {
streamDeck.noPermission(context,device); streamDeck.noPermission(context,device);
return; return;
} }
@@ -435,8 +464,8 @@ export class TokenControl{
} }
} }
if (icon == 'stats'){ if (icon == 'stats' && mode != 'offset' && mode != 'offsetRel'){
if (MODULE.getPermission('TOKEN','STATS') == false) stats = statsOld; if (getPermission('TOKEN','STATS') == false) stats = statsOld;
if (stats == 'HP') //HP if (stats == 'HP') //HP
iconSrc = "modules/MaterialDeck/img/token/hp_empty.png"; iconSrc = "modules/MaterialDeck/img/token/hp_empty.png";
if (stats == 'TempHP') //Temp HP if (stats == 'TempHP') //Temp HP
@@ -503,13 +532,15 @@ export class TokenControl{
iconSrc = "modules/MaterialDeck/img/move/rotateccw.png"; iconSrc = "modules/MaterialDeck/img/move/rotateccw.png";
} }
} }
streamDeck.setIcon(context,device,iconSrc,{background:background,ring:ring,ringColor:ringColor,overlay:overlay,uses:uses,hp:hp}); streamDeck.setIcon(context,device,iconSrc,{background:background,ring:ring,ringColor:ringColor,overlay:overlay,uses:uses,hp:hp});
streamDeck.setTitle(txt,context); streamDeck.setTitle(txt,context);
} }
sortItems(items) { sortItems(items) {
let sorted = Object.values(items); let sorted = Object.values(items);
sorted.sort((a,b) => a.data.sort - b.data.sort); if (compatibleCore('10.0')) sorted.sort((a,b) => a.sort - b.sort);
else sorted.sort((a,b) => a.data.sort - b.data.sort);
return sorted; return sorted;
} }
@@ -522,13 +553,11 @@ export class TokenControl{
const tokenIdentifier = settings.tokenName ? settings.tokenName : ''; const tokenIdentifier = settings.tokenName ? settings.tokenName : '';
const mode = settings.tokenMode ? settings.tokenMode : 'token'; const mode = settings.tokenMode ? settings.tokenMode : 'token';
let token; let token = tokenHelper.getToken(selection,tokenIdentifier);
if (selection == 'selected') token = canvas.tokens.controlled[0];
else token = tokenHelper.getToken(selection,tokenIdentifier);
if (token == undefined) return; if (token == undefined) return;
if (token.owner == false && token.observer == true && MODULE.getPermission('TOKEN','OBSERVER') == false ) return; if (token.owner == false && token.observer == true && getPermission('TOKEN','OBSERVER') == false ) return;
if (token.owner == false && token.observer == false && MODULE.getPermission('TOKEN','NON_OWNED') == false ) return; if (token.owner == false && token.observer == false && getPermission('TOKEN','NON_OWNED') == false ) return;
if (mode == 'token') { if (mode == 'token') {
@@ -565,18 +594,18 @@ export class TokenControl{
else token.sheet.close(); else token.sheet.close();
} }
else if (onClick == 'visibility') { //Toggle visibility else if (onClick == 'visibility') { //Toggle visibility
if (MODULE.getPermission('TOKEN','VISIBILITY') == false ) return; if (getPermission('TOKEN','VISIBILITY') == false ) return;
token.toggleVisibility(); token.toggleVisibility();
} }
else if (onClick == 'combatState') { //Toggle combat state else if (onClick == 'combatState') { //Toggle combat state
if (MODULE.getPermission('TOKEN','COMBAT') == false ) return; if (getPermission('TOKEN','COMBAT') == false ) return;
token.toggleCombat(); token.toggleCombat();
} }
else if (onClick == 'target') { //Target token else if (onClick == 'target') { //Target token
token.setTarget(!token.isTargeted,{releaseOthers:false}); token.setTarget(!token.isTargeted,{releaseOthers:false});
} }
else if (onClick == 'condition') { //Handle condition else if (onClick == 'condition') { //Handle condition
if (MODULE.getPermission('TOKEN','CONDITIONS') == false ) return; if (getPermission('TOKEN','CONDITIONS') == false ) return;
const func = settings.conditionFunction ? settings.conditionFunction : 'toggle'; const func = settings.conditionFunction ? settings.conditionFunction : 'toggle';
if (func == 'toggle'){ //toggle if (func == 'toggle'){ //toggle
@@ -594,7 +623,7 @@ export class TokenControl{
} }
else if (onClick == 'cubCondition') { //Combat Utility Belt conditions else if (onClick == 'cubCondition') { //Combat Utility Belt conditions
if (MODULE.getPermission('TOKEN','CONDITIONS') == false ) return; if (getPermission('TOKEN','CONDITIONS') == false ) return;
const condition = settings.cubConditionName; const condition = settings.cubConditionName;
if (condition == undefined || condition == '') return; if (condition == undefined || condition == '') return;
const effect = CONFIG.statusEffects.find(e => e.label === condition); const effect = CONFIG.statusEffects.find(e => e.label === condition);
@@ -602,57 +631,108 @@ export class TokenControl{
this.update(tokenId); this.update(tokenId);
} }
else if (onClick == 'vision'){ else if (onClick == 'vision'){
if (MODULE.getPermission('TOKEN','VISION') == false ) return; if (getPermission('TOKEN','VISION') == false ) return;
const token = canvas.tokens.children[0].children.find(p => p.id == tokenId);
if (token == undefined) return;
let tokenData = token.data;
const dimVision = parseInt(settings.dimVision); let sight = {};
const brightVision = parseInt(settings.brightVision); let light = {
const sightAngle = parseInt(settings.sightAngle); animation: {}
const dimRadius = parseInt(settings.dimRadius);
const brightRadius = parseInt(settings.brightRadius);
const emissionAngle = parseInt(settings.emissionAngle);
const lightColor = settings.lightColor ? settings.lightColor : '#000000';
const colorIntensity = isNaN(parseInt(settings.colorIntensity)) ? 0 : parseInt(settings.colorIntensity)/100;
const animationType = settings.animationType ? settings.animationType : 'none';
const animationSpeed = isNaN(parseInt(settings.animationSpeed)) ? 1 : parseInt(settings.animationSpeed);
const animationIntensity = isNaN(parseInt(settings.animationIntensity)) ? 1 : parseInt(settings.animationIntensity);
let data = {};
if (isNaN(dimVision)==false) data.dimSight = dimVision;
if (isNaN(brightVision)==false) data.brightSight = brightVision;
if (isNaN(sightAngle)==false) data.sightAngle = sightAngle;
let light = {};
if (isNaN(dimRadius)==false) light.dim = dimRadius;
if (isNaN(brightRadius)==false) light.bright = brightRadius;
if (isNaN(emissionAngle)==false) light.angle = emissionAngle;
light.color = lightColor;
light.alpha = Math.sqrt(colorIntensity).toNearest(0.05)
let animation = {
type: '',
speed: tokenData.light.animation.speed,
intensity: tokenData.light.animation.intensity
};
if (animationType != 'none'){
animation.type = animationType;
animation.intensity = animationIntensity;
animation.speed = animationSpeed;
} }
light.animation = animation;
//Vision basic config
if (settings.visionEnabled && settings.visionEnabled != 'noChange') {
if (compatibleCore('10.0')) {
if (settings.visionEnabled == 'toggle')
sight.enabled = !token.document.sight.enabled;
else
sight.enabled = settings.visionEnabled == 'enable';
}
else {
if (settings.visionEnabled == 'toggle')
sight.vision = !token.data.vision;
else
sight.vision = settings.visionEnabled == 'enable';
}
}
if (settings.visionRange && isNaN(settings.visionRange) == false) sight.range = parseInt(settings.visionRange);
if (settings.visionDimRange && isNaN(settings.visionDimRange) == false) sight.dimSight = parseInt(settings.visionDimRange);
if (settings.visionBrightRange && isNaN(settings.visionBrightRange) == false) sight.brightSight = parseInt(settings.visionBrightRange);
if (compatibleCore('10.0') && settings.visionAngle && isNaN(settings.visionAngle) == false) sight.angle = parseInt(settings.visionAngle);
else if (!compatibleCore('10.0') && settings.visionAngle && isNaN(settings.visionAngle) == false) sight.sightAngle = parseInt(settings.visionAngle);
if (settings.visionMode && settings.visionMode != 'noChange') sight.visionMode = settings.visionMode;
//Vision detection modes
let detectionModes = token.document.detectionModes;
if (settings.visionDetectionModeEnable && settings.visionDetectionModeEnable != 'noChange' && settings.visionDetectionModeNumber && detectionModes[settings.visionDetectionModeNumber-1] != undefined) {
if (settings.visionDetectionModeEnable == 'toggle')
detectionModes[settings.visionDetectionModeNumber-1].enabled = !detectionModes[settings.visionDetectionModeNumber-1].enabled;
else if (settings.visionDetectionModeEnable == 'enable')
detectionModes[settings.visionDetectionModeNumber-1].enabled = true;
else if (settings.visionDetectionModeEnable == 'disable')
detectionModes[settings.visionDetectionModeNumber-1].enabled = false;
detectionModes = detectionModes;
}
//Vision advanced options
if (settings.visionColorEnable) sight.color = settings.visionColor ? (settings.visionColor == '#000000' ? null : settings.visionColor) : null;
if (settings.visionAttenuationEnable) sight.attenuation = settings.visionAttenuation ? parseFloat(settings.visionAttenuation) : 0;
if (settings.visionBrightnessEnable) sight.brightness = settings.visionBrightness ? parseFloat(settings.visionBrightness) : 0;
if (settings.visionSaturationEnable) sight.saturation = settings.visionSaturation ? parseFloat(settings.visionSaturation) : 0;
if (settings.visionContrastEnable) sight.contrast = settings.visionContrast ? parseFloat(settings.visionContrast) : 0;
//Light basic config
if (settings.lightDimRadius && isNaN(settings.lightDimRadius) == false) light.dim = parseInt(settings.lightDimRadius);
if (settings.lightBrightRadius && isNaN(settings.lightBrightRadius) == false) light.bright = parseInt(settings.lightBrightRadius);
if (settings.lightEmissionAngle && isNaN(settings.lightEmissionAngle) == false) light.angle = parseInt(settings.lightEmissionAngle);
if (settings.lightColorEnable) light.color = settings.lightColor ? (settings.lightColor == '#000000' ? null : settings.lightColor) : null;
if (settings.lightColorIntensityEnable) light.alpha = settings.lightColorIntensity ? parseFloat(settings.lightColorIntensity) : 0;
//Light animation
if (settings.lightAnimationType && settings.lightAnimationType != 'noChange') light.animation.type = settings.lightAnimationType == 'none' ? null : settings.lightAnimationType;
if (settings.lightAnimationSpeedEnable) light.animation.speed = settings.lightAnimationSpeed ? parseFloat(settings.lightAnimationSpeed) : 5;
if (settings.lightAnimationReverseDirection && settings.lightAnimationReverseDirection != 'noChange') {
if (settings.lightAnimationReverseDirection == 'toggle')
light.animation.reverse = compatibleCore('10.0') ? !token.document.light.animation.reverse : !token.data.light.animation.reverse;
else if (settings.lightAnimationReverseDirection == 'enable')
light.animation.reverse = true;
else if (settings.lightAnimationReverseDirection == 'disable')
light.animation.reverse = false;
}
if (settings.lightAnimationIntensityEnable) light.animation.intensity = settings.lightAnimationIntensity ? parseFloat(settings.lightAnimationIntensity) : 5;
//Light advanced options
if (settings.lightColorationTechnique && settings.lightColorationTechnique != 'noChange') light.coloration = parseInt(settings.lightColorationTechnique);
if (settings.lightLuminosityEnable) light.luminosity = settings.lightLuminosity ? parseFloat(settings.lightLuminosity) : 0.5;
if (settings.lightGradualIllumination && settings.lightGradualIllumination != 'noChange') {
if (settings.lightGradualIllumination == 'toggle')
light.gradual = !token.data.light.gradual;
else if (settings.lightGradualIllumination == 'enable')
light.gradual = true;
else if (settings.lightGradualIllumination == 'disable')
light.gradual = false;
}
if (settings.lightAttenuationEnable) light.attenuation = settings.lightAttenuation ? parseFloat(settings.lightAttenuation) : 0.5;
if (settings.lightSaturationEnable) light.saturation = settings.lightSaturation ? parseFloat(settings.lightSaturation) : 0;
if (settings.lightContrastEnable) light.contrast = settings.lightContrast ? parseFloat(settings.lightContrast) : 0;
if (settings.lightShadowsEnable) light.shadows = settings.lightShadows ? parseFloat(settings.lightShadows) : 0;
let data;
if (compatibleCore('10.0')) {
data = {
sight,
light
}
}
else {
data = sight;
data.light = light; data.light = light;
if (compatibleCore('0.8.1')) token.document.update(data); }
else token.update(data); token.document.update(data);
} }
else if (onClick == 'initiative'){ else if (onClick == 'initiative'){
tokenHelper.toggleInitiative(token); tokenHelper.toggleInitiative(token);
} }
else if (onClick == 'wildcard') { //wildcard images else if (onClick == 'wildcard') { //wildcard images
if (MODULE.getPermission('TOKEN','WILDCARD') == false ) return; if (getPermission('TOKEN','WILDCARD') == false ) return;
const method = settings.wildcardMethod ? settings.wildcardMethod : 'iterate'; const method = settings.wildcardMethod ? settings.wildcardMethod : 'iterate';
let value = parseInt(settings.wildcardValue); let value = parseInt(settings.wildcardValue);
if (isNaN(value)) value = 1; if (isNaN(value)) value = 1;
@@ -663,7 +743,7 @@ export class TokenControl{
if (method == 'iterate'){ if (method == 'iterate'){
let currentImgNr = 0 let currentImgNr = 0
for (let i=0; i<images.length; i++) for (let i=0; i<images.length; i++)
if (images[i] == token.data.img){ if (images[i] == tokenHelper.getTokenIcon(token)){
currentImgNr = i; currentImgNr = i;
break; break;
} }
@@ -684,8 +764,7 @@ export class TokenControl{
else return; else return;
iconSrc = images[imgNr]; iconSrc = images[imgNr];
if (compatibleCore('0.8.1')) token.document.update({img: iconSrc}); token.document.update({img: iconSrc});
else token.update({img: iconSrc})
} }
else if (onClick == 'macro') { //call a macro else if (onClick == 'macro') { //call a macro
const settingsNew = { const settingsNew = {
@@ -712,7 +791,7 @@ export class TokenControl{
if (otherControls.rollOption != 'dialog') otherControls.setRollOption('normal'); if (otherControls.rollOption != 'dialog') otherControls.setRollOption('normal');
} }
else if (onClick == 'custom') {//custom onClick function else if (onClick == 'custom') {//custom onClick function
if (MODULE.getPermission('TOKEN','CUSTOM') == false ) return; if (getPermission('TOKEN','CUSTOM') == false ) return;
const formula = settings.customOnClickFormula ? settings.customOnClickFormula : ''; const formula = settings.customOnClickFormula ? settings.customOnClickFormula : '';
if (formula == '') return; if (formula == '') return;
@@ -828,8 +907,7 @@ export class TokenControl{
if (path != '') path += '.'; if (path != '') path += '.';
path += targetArray[i][j]; path += targetArray[i][j];
} }
if (compatibleCore('0.8.1')) await token.document.update({[path]:value}); await token.document.update({[path]:value});
else await token.update({[path]:value})
this.update(token.id); this.update(token.id);
} }
@@ -837,9 +915,20 @@ export class TokenControl{
} }
} }
} }
else if (mode == 'offset') {
const itemOffset = settings.itemOffset ? settings.itemOffset : 0;
this.itemOffset = parseInt(itemOffset);
this.update(tokenId);
}
else if (mode == 'offsetRel') {
const itemOffset = settings.itemOffset ? settings.itemOffset : 0;
this.itemOffset += parseInt(itemOffset);
this.update(tokenId);
}
else { else {
const allItems = token.actor.items; const allItems = token.actor.items;
const itemNr = settings.itemNr ? settings.itemNr - 1 : 0; const itemNr = settings.itemNr ? settings.itemNr - 1 : 0;
const selectionMode = settings.inventorySelection ? settings.inventorySelection : 'order';
let items = allItems; let items = allItems;
if (mode == 'inventory') { if (mode == 'inventory') {
items = tokenHelper.getItems(token,settings.inventoryType); items = tokenHelper.getItems(token,settings.inventoryType);
@@ -851,10 +940,12 @@ export class TokenControl{
items = tokenHelper.getSpells(token,settings.spellType); items = tokenHelper.getSpells(token,settings.spellType);
} }
items = this.sortItems(items); items = this.sortItems(items);
let item;
const item = items[itemNr]; if (selectionMode == 'order') item = items[itemNr];
else if (selectionMode == 'name') item = items.filter(i => i.name == settings.itemName)[0];
else if (selectionMode == 'id') item = items.filter(i => i.id == settings.itemName)[0];
if (item != undefined) { if (item != undefined) {
tokenHelper.rollItem(item, settings); tokenHelper.rollItem(item, settings, otherControls.rollOption);
} }
} }

View File

@@ -1,9 +1,9 @@
import {sdVersion, msVersion, moduleName, getPermission, enableModule, streamDeck} from "../MaterialDeck.js"; import { sdVersion, msVersion, moduleName, getPermission, enableModule, streamDeck, macroControl,soundboard,playlistControl, minimumMSversion, minimumSDversion } from "../MaterialDeck.js";
import {macroControl,soundboard,playlistControl} from "../MaterialDeck.js";
export function compareVersions(checkedVersion, requiredVersion) { export function compareVersions(checkedVersion, requiredVersion) {
requiredVersion = requiredVersion.split("."); requiredVersion = requiredVersion.split(".");
checkedVersion = checkedVersion.split("."); checkedVersion = checkedVersion.split(".");
for (let i=0; i<3; i++) { for (let i=0; i<3; i++) {
requiredVersion[i] = isNaN(parseInt(requiredVersion[i])) ? 0 : parseInt(requiredVersion[i]); requiredVersion[i] = isNaN(parseInt(requiredVersion[i])) ? 0 : parseInt(requiredVersion[i]);
checkedVersion[i] = isNaN(parseInt(checkedVersion[i])) ? 0 : parseInt(checkedVersion[i]); checkedVersion[i] = isNaN(parseInt(checkedVersion[i])) ? 0 : parseInt(checkedVersion[i]);
@@ -18,18 +18,17 @@ export function compareVersions(checkedVersion, requiredVersion) {
} }
export function compatibleCore(compatibleVersion){ export function compatibleCore(compatibleVersion){
const split = compatibleVersion.split(".");
if (split.length == 2) compatibleVersion = `0.${compatibleVersion}`;
let coreVersion = game.version == undefined ? game.data.version : `0.${game.version}`; let coreVersion = game.version == undefined ? game.data.version : `0.${game.version}`;
return compareVersions(compatibleVersion, coreVersion); return compareVersions(compatibleVersion, coreVersion);
/* }
coreVersion = coreVersion.split(".");
compatibleVersion = compatibleVersion.split("."); export function compatibleSystem(compatibleVersion){
if (compatibleVersion[0] > coreVersion[0]) return false; const split = compatibleVersion.split(".");
if (compatibleVersion[0] < coreVersion[0]) return true; if (split.length == 2) compatibleVersion = `0.${compatibleVersion}`;
if (compatibleVersion[1] > coreVersion[1]) return false; let coreVersion = game.system.data.version;
if (compatibleVersion[1] < coreVersion[1]) return true; return compareVersions(compatibleVersion, coreVersion);
if (compatibleVersion[2] > coreVersion[2]) return false;
return true;
*/
} }
export class playlistConfigForm extends FormApplication { export class playlistConfigForm extends FormApplication {
@@ -97,7 +96,7 @@ export class playlistConfigForm extends FormApplication {
} }
return { return {
playlists: compatibleCore("0.8.1") ? game.playlists.contents : game.playlists.entities, playlists: game.playlists.contents,
numberOfPlaylists: numberOfPlaylists, numberOfPlaylists: numberOfPlaylists,
playlistData: playlistData, playlistData: playlistData,
playMode: playMode playMode: playMode
@@ -175,7 +174,7 @@ export class macroConfigForm extends FormApplication {
*/ */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
id: "macro-config", id: "materialDeck_macroConfig",
title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.MacroConfig"), title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.MacroConfig"),
template: "./modules/MaterialDeck/templates/macroConfig.html", template: "./modules/MaterialDeck/templates/macroConfig.html",
classes: ["sheet"] classes: ["sheet"]
@@ -201,12 +200,12 @@ export class macroConfigForm extends FormApplication {
if (args == undefined) args = []; if (args == undefined) args = [];
//Check if the Furnace is installed and enabled //Check if the Furnace is installed and enabled
let furnaceEnabled = false;
let height = 95; let height = 95;
let furnace = game.modules.get("furnace"); let advancedMacrosEnabled = false;
let advancedMacros = game.modules.get("advanced-macros"); let advancedMacros = game.modules.get("advanced-macros");
if ((furnace != undefined && furnace.active && compatibleCore("0.8.1")==false) || (advancedMacros != undefined && advancedMacros.active)) { if (advancedMacros != undefined && advancedMacros.active) advancedMacrosEnabled = true;
furnaceEnabled = true; if (advancedMacrosEnabled) {
advancedMacrosEnabled = true;
height += 50; height += 50;
} }
@@ -245,7 +244,7 @@ export class macroConfigForm extends FormApplication {
macros: game.macros, macros: game.macros,
selectedMacros: selectedMacros, selectedMacros: selectedMacros,
macroData: macroData, macroData: macroData,
furnace: furnaceEnabled, furnace: advancedMacrosEnabled,
macroRange: `${this.page*32 + 1} - ${this.page*32 + 32}`, macroRange: `${this.page*32 + 1} - ${this.page*32 + 32}`,
prevDisabled: this.page == 0 ? 'disabled' : '', prevDisabled: this.page == 0 ? 'disabled' : '',
totalMacros: Math.max(Math.ceil(selectedMacros.length/32)*32, this.page*32 + 32) totalMacros: Math.max(Math.ceil(selectedMacros.length/32)*32, this.page*32 + 32)
@@ -263,12 +262,12 @@ export class macroConfigForm extends FormApplication {
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
const navNext = html.find("button[id='navNext']"); const navNext = html.find("button[name='navNext']");
const navPrev = html.find("button[id='navPrev']"); const navPrev = html.find("button[name='navPrev']");
const clearAll = html.find("button[id='clearAll']"); const clearAll = html.find("button[name='clearAll']");
const clearPage = html.find("button[id='clearPage']"); const clearPage = html.find("button[name='clearPage']");
const importBtn = html.find("button[id='import']"); const importBtn = html.find("button[name='import']");
const exportBtn = html.find("button[id='export']"); const exportBtn = html.find("button[name='export']");
const macro = html.find("select[name='macros']"); const macro = html.find("select[name='macros']");
const args = html.find("input[name='args']"); const args = html.find("input[name='args']");
const color = html.find("input[name='colorPicker']"); const color = html.find("input[name='colorPicker']");
@@ -359,21 +358,21 @@ export class macroConfigForm extends FormApplication {
}) })
macro.on("change", event => { macro.on("change", event => {
let id = event.target.id.replace('macros',''); let id = event.target.id.replace('materialDeck_macroConfig_macros','');
let settings = game.settings.get(moduleName,'macroSettings'); let settings = game.settings.get(moduleName,'macroSettings');
settings.macros[id-1]=event.target.value; settings.macros[id-1]=event.target.value;
this.updateSettings(settings); this.updateSettings(settings);
}); });
args.on("change", event => { args.on("change", event => {
let id = event.target.id.replace('args',''); let id = event.target.id.replace('materialDeck_macroConfig_args','');
let settings = game.settings.get(moduleName,'macroSettings'); let settings = game.settings.get(moduleName,'macroSettings');
settings.args[id-1]=event.target.value; settings.args[id-1]=event.target.value;
this.updateSettings(settings); this.updateSettings(settings);
}); });
color.on("change", event => { color.on("change", event => {
let id = event.target.id.replace('colorpicker',''); let id = event.target.id.replace('materialDeck_macroConfig_colorpicker','');
let settings = game.settings.get(moduleName,'macroSettings'); let settings = game.settings.get(moduleName,'macroSettings');
settings.color[id-1]=event.target.value; settings.color[id-1]=event.target.value;
this.updateSettings(settings); this.updateSettings(settings);
@@ -453,7 +452,7 @@ export class soundboardConfigForm extends FormApplication {
*/ */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
id: "soundboard-config", id: "materialDeck_soundboardConfig",
title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.SoundboardConfig"), title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.SoundboardConfig"),
template: "./modules/MaterialDeck/templates/soundboardConfig.html", template: "./modules/MaterialDeck/templates/soundboardConfig.html",
classes: ["sheet"], classes: ["sheet"],
@@ -489,7 +488,7 @@ export class soundboardConfigForm extends FormApplication {
playlists.push({id:"none",name:game.i18n.localize("MaterialDeck.None")}); playlists.push({id:"none",name:game.i18n.localize("MaterialDeck.None")});
playlists.push({id:"FP",name:game.i18n.localize("MaterialDeck.FilePicker")}) playlists.push({id:"FP",name:game.i18n.localize("MaterialDeck.FilePicker")})
const playlistArray = compatibleCore("0.8.1") ? game.playlists.contents : game.playlists.entities; const playlistArray = game.playlists.contents;
for (let playlist of playlistArray) for (let playlist of playlistArray)
playlists.push({id: playlist.id, name: playlist.name}) playlists.push({id: playlist.id, name: playlist.name})
@@ -515,7 +514,7 @@ export class soundboardConfigForm extends FormApplication {
else if (this.settings.selectedPlaylists[iteration] == 'FP') selectedPlaylist = 'FP'; else if (this.settings.selectedPlaylists[iteration] == 'FP') selectedPlaylist = 'FP';
else { else {
//Get the playlist //Get the playlist
const playlistArray = compatibleCore("0.8.1") ? game.playlists.contents : game.playlists.entities; const playlistArray = game.playlists.contents;
let pl = playlistArray.find(p => p.id == this.settings.selectedPlaylists[iteration]) let pl = playlistArray.find(p => p.id == this.settings.selectedPlaylists[iteration])
if (pl == undefined){ if (pl == undefined){
@@ -524,19 +523,12 @@ export class soundboardConfigForm extends FormApplication {
} }
else { else {
//Add the sound name and id to the sounds array //Add the sound name and id to the sounds array
if (compatibleCore("0.8.1"))
for (let sound of pl.sounds.contents) for (let sound of pl.sounds.contents)
sounds.push({ sounds.push({
name: sound.name, name: sound.name,
id: sound.id id: sound.id
}); });
else {
for (let sound of pl.sounds)
sounds.push({
name: sound.name,
id: sound._id
});
}
//Get the playlist id //Get the playlist id
selectedPlaylist = pl.id; selectedPlaylist = pl.id;
} }
@@ -557,8 +549,8 @@ export class soundboardConfigForm extends FormApplication {
sound: this.settings.sounds[iteration], sound: this.settings.sounds[iteration],
sounds: sounds, sounds: sounds,
srcPath: this.settings.src[iteration], srcPath: this.settings.src[iteration],
colorOn: this.settings.colorOn[iteration], colorOn: this.settings.colorOn[iteration] == 0 ? '#000000' : this.settings.colorOn[iteration],
colorOff: this.settings.colorOff[iteration], colorOff: this.settings.colorOff[iteration] == 0 ? '#000000' : this.settings.colorOff[iteration],
mode: this.settings.mode[iteration], mode: this.settings.mode[iteration],
volume: this.settings.volume[iteration], volume: this.settings.volume[iteration],
imgPath: this.settings.img[iteration], imgPath: this.settings.img[iteration],
@@ -597,12 +589,12 @@ export class soundboardConfigForm extends FormApplication {
async activateListeners(html) { async activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
const navNext = html.find("button[id='navNext']"); const navNext = html.find("button[name='navNext']");
const navPrev = html.find("button[id='navPrev']"); const navPrev = html.find("button[name='navPrev']");
const clearAll = html.find("button[id='clearAll']"); const clearAll = html.find("button[name='clearAll']");
const clearPage = html.find("button[id='clearPage']"); const clearPage = html.find("button[name='clearPage']");
const importBtn = html.find("button[id='import']"); const importBtn = html.find("button[name='import']");
const exportBtn = html.find("button[id='export']"); const exportBtn = html.find("button[name='export']");
const nameField = html.find("input[name='namebox']"); const nameField = html.find("input[name='namebox']");
const playlistSelect = html.find("select[name='playlist']"); const playlistSelect = html.find("select[name='playlist']");
const soundSelect = html.find("select[name='sounds']"); const soundSelect = html.find("select[name='sounds']");
@@ -697,7 +689,7 @@ export class soundboardConfigForm extends FormApplication {
}) })
nameField.on("change",event => { nameField.on("change",event => {
let id = event.target.id.replace('name','')-1; let id = event.target.id.replace('materialDeck_sbConfig_name','')-1;
this.settings.name[id]=event.target.value; this.settings.name[id]=event.target.value;
this.updateSettings(this.settings); this.updateSettings(this.settings);
}); });
@@ -707,7 +699,7 @@ export class soundboardConfigForm extends FormApplication {
//Listener for when the playlist is changed //Listener for when the playlist is changed
playlistSelect.on("change", event => { playlistSelect.on("change", event => {
//Get the sound number //Get the sound number
const iteration = event.target.id.replace('playlists',''); const iteration = event.target.id.replace('materialDeck_sbConfig_playlists','');
//Get the selected playlist and the sounds of that playlist //Get the selected playlist and the sounds of that playlist
let selectedPlaylist; let selectedPlaylist;
@@ -718,24 +710,24 @@ export class soundboardConfigForm extends FormApplication {
selectedPlaylist = 'FP'; selectedPlaylist = 'FP';
//Show the file picker //Show the file picker
document.querySelector(`#fp${iteration}`).style=''; document.querySelector(`#materialDeck_sbConfig_fp${iteration}`).style='';
//Hide the sound selector //Hide the sound selector
document.querySelector(`#ss${iteration}`).style='display:none'; document.querySelector(`#materialDeck_sbConfig_ss${iteration}`).style='display:none';
} }
else { else {
//Hide the file picker //Hide the file picker
document.querySelector(`#fp${iteration}`).style='display:none'; document.querySelector(`#materialDeck_sbConfig_fp${iteration}`).style='display:none';
//Show the sound selector //Show the sound selector
document.querySelector(`#ss${iteration}`).style=''; document.querySelector(`#materialDeck_sbConfig_ss${iteration}`).style='';
const playlistArray = compatibleCore("0.8.1") ? game.playlists.contents : game.playlists.entities; const playlistArray = game.playlists.contents;
const pl = playlistArray.find(p => p.id == event.target.value) const pl = playlistArray.find(p => p.id == event.target.value)
selectedPlaylist = pl.id; selectedPlaylist = pl.id;
//Get the sound select element //Get the sound select element
let SSpicker = document.getElementById(`soundSelect${iteration}`); let SSpicker = document.getElementById(`materialDeck_sbConfig_soundSelect${iteration}`);
//Empty ss element //Empty ss element
SSpicker.options.length=0; SSpicker.options.length=0;
@@ -746,20 +738,12 @@ export class soundboardConfigForm extends FormApplication {
optionNone.innerHTML = game.i18n.localize("MaterialDeck.None"); optionNone.innerHTML = game.i18n.localize("MaterialDeck.None");
SSpicker.appendChild(optionNone); SSpicker.appendChild(optionNone);
if (compatibleCore("0.8.1"))
for (let sound of pl.sounds.contents) { for (let sound of pl.sounds.contents) {
let newOption = document.createElement('option'); let newOption = document.createElement('option');
newOption.value = sound.id; newOption.value = sound.id;
newOption.innerHTML = sound.name; newOption.innerHTML = sound.name;
SSpicker.appendChild(newOption); SSpicker.appendChild(newOption);
} }
else
for (let sound of pl.sounds) {
let newOption = document.createElement('option');
newOption.value = sound._id;
newOption.innerHTML = sound.name;
SSpicker.appendChild(newOption);
}
} }
//Save the new playlist to this.settings, and update the settings //Save the new playlist to this.settings, and update the settings
@@ -769,43 +753,43 @@ export class soundboardConfigForm extends FormApplication {
} }
soundSelect.on("change", event => { soundSelect.on("change", event => {
let id = event.target.id.replace('soundSelect','')-1; let id = event.target.id.replace('materialDeck_sbConfig_soundSelect','')-1;
this.settings.sounds[id]=event.target.value; this.settings.sounds[id]=event.target.value;
this.updateSettings(this.settings); this.updateSettings(this.settings);
}); });
soundFP.on("change",event => { soundFP.on("change",event => {
let id = event.target.id.replace('srcPath','')-1; let id = event.target.id.replace('materialDeck_sbConfig_srcPath','')-1;
this.settings.src[id]=event.target.value; this.settings.src[id]=event.target.value;
this.updateSettings(this.settings); this.updateSettings(this.settings);
}); });
imgFP.on("change",event => { imgFP.on("change",event => {
let id = event.target.id.replace('imgPath','')-1; let id = event.target.id.replace('materialDeck_sbConfig_imgPath','')-1;
this.settings.img[id]=event.target.value; this.settings.img[id]=event.target.value;
this.updateSettings(this.settings); this.updateSettings(this.settings);
}); });
onCP.on("change",event => { onCP.on("change",event => {
let id = event.target.id.replace('colorOn','')-1; let id = event.target.id.replace('materialDeck_sbConfig_colorOn','')-1;
this.settings.colorOn[id]=event.target.value; this.settings.colorOn[id]=event.target.value;
this.updateSettings(this.settings); this.updateSettings(this.settings);
}); });
offCP.on("change",event => { offCP.on("change",event => {
let id = event.target.id.replace('colorOff','')-1; let id = event.target.id.replace('materialDeck_sbConfig_colorOff','')-1;
this.settings.colorOff[id]=event.target.value; this.settings.colorOff[id]=event.target.value;
this.updateSettings(this.settings); this.updateSettings(this.settings);
}); });
playMode.on("change",event => { playMode.on("change",event => {
let id = event.target.id.replace('playmode','')-1; let id = event.target.id.replace('materialDeck_sbConfig_playmode','')-1;
this.settings.mode[id]=event.target.value; this.settings.mode[id]=event.target.value;
this.updateSettings(this.settings); this.updateSettings(this.settings);
}); });
volume.on("change",event => { volume.on("change",event => {
let id = event.target.id.replace('volume','')-1; let id = event.target.id.replace('materialDeck_sbConfig_volume','')-1;
this.settings.volume[id]=event.target.value; this.settings.volume[id]=event.target.value;
this.updateSettings(this.settings); this.updateSettings(this.settings);
}); });
@@ -904,7 +888,7 @@ export class exportConfigForm extends FormApplication {
*/ */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
id: "MD_Export", id: "materialDeck_Export",
title: "Material Deck: " + game.i18n.localize("MaterialDeck.ExportDialog.Title"), title: "Material Deck: " + game.i18n.localize("MaterialDeck.ExportDialog.Title"),
template: "./modules/MaterialDeck/templates/exportDialog.html", template: "./modules/MaterialDeck/templates/exportDialog.html",
width: 500, width: 500,
@@ -967,7 +951,7 @@ export class importConfigForm extends FormApplication {
*/ */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
id: "MD_Import", id: "materialDeck_Import",
title: "Material Deck: " + game.i18n.localize("MaterialDeck.ImportDialog.Title"), title: "Material Deck: " + game.i18n.localize("MaterialDeck.ImportDialog.Title"),
template: "./modules/MaterialDeck/templates/importDialog.html", template: "./modules/MaterialDeck/templates/importDialog.html",
width: 500, width: 500,
@@ -1005,7 +989,7 @@ export class importConfigForm extends FormApplication {
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
const upload = html.find("input[id='uploadJson']"); const upload = html.find("input[id='materialDeck_import_uploadJson']");
upload.on('change',(event) => { upload.on('change',(event) => {
event.preventDefault(); event.preventDefault();
@@ -1052,7 +1036,7 @@ export class downloadUtility extends FormApplication {
*/ */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
id: "MD_DownloadUtility", id: "materialDeck_downloadUtility",
title: "Material Deck: " + game.i18n.localize("MaterialDeck.DownloadUtility.Title"), title: "Material Deck: " + game.i18n.localize("MaterialDeck.DownloadUtility.Title"),
template: "./modules/MaterialDeck/templates/downloadUtility.html", template: "./modules/MaterialDeck/templates/downloadUtility.html",
width: 500, width: 500,
@@ -1078,23 +1062,12 @@ export class downloadUtility extends FormApplication {
} }
if (this.localMSversion == undefined) this.localMSversion = 'unknown'; if (this.localMSversion == undefined) this.localMSversion = 'unknown';
let minimumSdVersion;
let minimumMsVersion;
if (compatibleCore("0.8.5")) {
minimumSdVersion = game.modules.get("MaterialDeck").data.flags.minimumSDversion.replace('v','');
minimumMsVersion = game.modules.get("MaterialDeck").data.flags.minimumMSversion;
}
else {
minimumSdVersion = game.modules.get("MaterialDeck").data.minimumSDversion.replace('v','');
minimumMsVersion = game.modules.get("MaterialDeck").data.minimumMSversion;
}
return { return {
minimumSdVersion, minimumSdVersion: minimumSDversion,
localSdVersion: this.localSDversion, localSdVersion: this.localSDversion,
masterSdVersion: this.masterSDversion, masterSdVersion: this.masterSDversion,
sdDlDisable: this.masterSDversion == undefined, sdDlDisable: this.masterSDversion == undefined,
minimumMsVersion, minimumMsVersion: minimumMSversion,
localMsVersion: this.localMSversion, localMsVersion: this.localMSversion,
masterMsVersion: this.masterMSversion, masterMsVersion: this.masterMSversion,
msDlDisable: this.masterMSversion == undefined, msDlDisable: this.masterMSversion == undefined,
@@ -1115,20 +1088,20 @@ export class downloadUtility extends FormApplication {
activateListeners(html) { activateListeners(html) {
super.activateListeners(html); super.activateListeners(html);
const downloadSd = html.find("button[id='downloadSd']"); const downloadSd = html.find("button[id='materialDeck_dlUtil_downloadSd']");
const downloadMs = html.find("button[id='downloadMs']"); const downloadMs = html.find("button[id='materialDeck_dlUtil_downloadMs']");
const downloadProfile = html.find("button[name='downloadProfile']") const downloadProfile = html.find("button[name='downloadProfile']")
const refresh = html.find("button[id='refresh']"); const refresh = html.find("button[id='materialDeck_dlUtil_refresh']");
downloadSd.on('click', () => { downloadSd.on('click', () => {
const version = document.getElementById('masterSdVersion').innerHTML; const version = document.getElementById('materialDeck_dlUtil_masterSdVersion').innerHTML;
if (version == '' || version == undefined || version == 'Error') return; if (version == '' || version == undefined || version == 'Error') return;
const url = `https://github.com/CDeenen/MaterialDeck_SD/releases/download/v${version}/com.cdeenen.materialdeck.streamDeckPlugin`; const url = `https://github.com/CDeenen/MaterialDeck_SD/releases/download/v${version}/com.cdeenen.materialdeck.streamDeckPlugin`;
this.downloadURI(url,'com.cdeenen.materialdeck.streamDeckPlugin') this.downloadURI(url,'com.cdeenen.materialdeck.streamDeckPlugin')
}) })
downloadMs.on('click', () => { downloadMs.on('click', () => {
const version = document.getElementById('masterMsVersion').innerHTML; const version = document.getElementById('materialDeck_dlUtil_masterMsVersion').innerHTML;
const os = document.getElementById('os').value; const os = document.getElementById('materialDeck_dlUtil_os').value;
if (version == '' || version == undefined || version == 'Error') return; if (version == '' || version == undefined || version == 'Error') return;
let name = `MaterialServer-${os}.zip`; let name = `MaterialServer-${os}.zip`;
let url; let url;
@@ -1137,13 +1110,13 @@ export class downloadUtility extends FormApplication {
this.downloadURI(url,name) this.downloadURI(url,name)
}) })
downloadProfile.on('click',(event) => { downloadProfile.on('click',(event) => {
let id = event.currentTarget.id.replace('dlProfile-',''); let id = event.currentTarget.id.replace('materialDeck_dlUtil_dlProfile-','');
this.downloadURI(this.profiles[id].url,`${this.profiles[id].label}.streamDeckProfile`); this.downloadURI(this.profiles[id].url,`${this.profiles[id].label}.streamDeckProfile`);
}) })
refresh.on('click', () => { refresh.on('click', () => {
document.getElementById('masterSdVersion').value = 'Getting data'; document.getElementById('materialDeck_dlUtil_masterSdVersion').value = 'Getting data';
this.checkForUpdate('SD'); this.checkForUpdate('SD');
document.getElementById('masterMsVersion').value = 'Getting data'; document.getElementById('materialDeck_dlUtil_masterMsVersion').value = 'Getting data';
this.checkForUpdate('MS'); this.checkForUpdate('MS');
this.getReleaseData(); this.getReleaseData();
}) })
@@ -1170,14 +1143,10 @@ export class downloadUtility extends FormApplication {
const data = JSON.parse(request.responseText); const data = JSON.parse(request.responseText);
parent.releaseAssets = data.assets; parent.releaseAssets = data.assets;
parent.render(true); parent.render(true);
if (type.indexOf("text") !== 1) { if (type.indexOf("text") !== 1) return;
return;
} }
} }
} request.onerror = function () {}
request.onerror = function () {
}
} }
checkForUpdate(reqType) { checkForUpdate(reqType) {
@@ -1185,7 +1154,7 @@ export class downloadUtility extends FormApplication {
let url; let url;
if (reqType == 'SD') url = 'https://raw.githubusercontent.com/CDeenen/MaterialDeck_SD/master/Plugin/com.cdeenen.materialdeck.sdPlugin/manifest.json'; if (reqType == 'SD') url = 'https://raw.githubusercontent.com/CDeenen/MaterialDeck_SD/master/Plugin/com.cdeenen.materialdeck.sdPlugin/manifest.json';
else if (reqType == 'MS') url = 'https://raw.githubusercontent.com/CDeenen/MaterialServer/master/package.json'; else if (reqType == 'MS') url = 'https://raw.githubusercontent.com/CDeenen/MaterialServer/master/package.json';
const elementId = reqType == 'SD' ? 'masterSdVersion' : 'masterMsVersion'; const elementId = reqType == 'SD' ? 'materialDeck_dlUtil_masterSdVersion' : 'materialDeck_dlUtil_masterMsVersion';
var request = new XMLHttpRequest(); var request = new XMLHttpRequest();
request.open('GET', url, true); request.open('GET', url, true);
@@ -1199,7 +1168,6 @@ export class downloadUtility extends FormApplication {
parent.render(true); parent.render(true);
return; return;
} }
} }
} }
request.onerror = function () { request.onerror = function () {
@@ -1220,7 +1188,7 @@ export class deviceConfig extends FormApplication {
*/ */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
id: "MD_DeviceConfig", id: "materialDeck_deviceConfig",
title: "Material Deck: " + game.i18n.localize("MaterialDeck.DeviceConfig.Title"), title: "Material Deck: " + game.i18n.localize("MaterialDeck.DeviceConfig.Title"),
template: "./modules/MaterialDeck/templates/deviceConfig.html", template: "./modules/MaterialDeck/templates/deviceConfig.html",
width: 500, width: 500,
@@ -1282,7 +1250,7 @@ export class deviceConfig extends FormApplication {
super.activateListeners(html); super.activateListeners(html);
html.find("input[name='enable']").on('change', (event) => { html.find("input[name='enable']").on('change', (event) => {
const id = event.currentTarget.id; const id = event.currentTarget.id.replace('materialDeck_devConf_','');;
for (let d of this.devices) { for (let d of this.devices) {
if (d.id == id) { if (d.id == id) {
let dConfig = game.settings.get(moduleName, 'devices'); let dConfig = game.settings.get(moduleName, 'devices');

View File

@@ -1,4 +1,4 @@
import * as MODULE from "../MaterialDeck.js"; import { moduleName, isEmpty } from "../MaterialDeck.js";
import { playlistConfigForm, macroConfigForm, soundboardConfigForm, downloadUtility, deviceConfig } from "./misc.js"; import { playlistConfigForm, macroConfigForm, soundboardConfigForm, downloadUtility, deviceConfig } from "./misc.js";
let userPermissions = {}; let userPermissions = {};
@@ -70,7 +70,7 @@ export const registerSettings = async function() {
//world,global,client //world,global,client
//Enabled the module //Enabled the module
game.settings.register(MODULE.moduleName,'Enable', { game.settings.register(moduleName,'Enable', {
name: "MaterialDeck.Sett.Enable", name: "MaterialDeck.Sett.Enable",
scope: "client", scope: "client",
config: true, config: true,
@@ -82,20 +82,31 @@ export const registerSettings = async function() {
/** /**
* System override * System override
*/ */
game.settings.register(MODULE.moduleName,'systemOverride', { game.settings.register(moduleName,'systemOverride', {
name: "MaterialDeck.Sett.SystemOverride", name: "MaterialDeck.Sett.SystemOverride",
hint: "MaterialDeck.Sett.SystemOverrideHint", hint: "MaterialDeck.Sett.SystemOverrideHint",
scope: "client", scope: "client",
config: true, config: true,
default: "", default: "",
type: String, type: String,
choices: {
"": "Autodetect",
"D35E": "Dungeons & Dragons 3.5e",
"dnd5e": "Dungeons & Dragons 5e",
"forbidden-lands": "Forbidden Lands",
"pf1": "Pathfinder 1e",
"pf2e": "Pathfinder 2e",
"demonlord": "Shadow of the Demon Lord",
"sfrpg": "Starfinder",
"wfrp4e": "Warhammer Fantasy Roleplay 4e",
},
onChange: x => window.location.reload() onChange: x => window.location.reload()
}); });
/** /**
* Sets the ip address of the server * Sets the ip address of the server
*/ */
game.settings.register(MODULE.moduleName,'address', { game.settings.register(moduleName,'address', {
name: "MaterialDeck.Sett.ServerAddr", name: "MaterialDeck.Sett.ServerAddr",
hint: "MaterialDeck.Sett.ServerAddrHint", hint: "MaterialDeck.Sett.ServerAddrHint",
scope: "client", scope: "client",
@@ -105,7 +116,7 @@ export const registerSettings = async function() {
onChange: x => window.location.reload() onChange: x => window.location.reload()
}); });
game.settings.register(MODULE.moduleName, 'imageBuffer', { game.settings.register(moduleName, 'imageBuffer', {
name: "MaterialDeck.Sett.ImageBuffer", name: "MaterialDeck.Sett.ImageBuffer",
hint: "MaterialDeck.Sett.ImageBufferHint", hint: "MaterialDeck.Sett.ImageBufferHint",
default: 100, default: 100,
@@ -116,7 +127,7 @@ export const registerSettings = async function() {
}); });
game.settings.register(MODULE.moduleName, 'imageBrightness', { game.settings.register(moduleName, 'imageBrightness', {
name: "MaterialDeck.Sett.ImageBrightness", name: "MaterialDeck.Sett.ImageBrightness",
hint: "MaterialDeck.Sett.ImageBrightnessHint", hint: "MaterialDeck.Sett.ImageBrightnessHint",
default: 50, default: 50,
@@ -127,7 +138,7 @@ export const registerSettings = async function() {
}); });
game.settings.register(MODULE.moduleName, 'nrOfConnMessages', { game.settings.register(moduleName, 'nrOfConnMessages', {
name: "MaterialDeck.Sett.NrOfConnMessages", name: "MaterialDeck.Sett.NrOfConnMessages",
hint: "MaterialDeck.Sett.NrOfConnMessagesHint", hint: "MaterialDeck.Sett.NrOfConnMessagesHint",
default: 5, default: 5,
@@ -139,59 +150,61 @@ export const registerSettings = async function() {
}); });
//Create the Help button //Create the Help button
game.settings.registerMenu(MODULE.moduleName, 'helpMenu',{ game.settings.registerMenu(moduleName, 'helpMenu',{
name: "MaterialDeck.Sett.Help", name: "MaterialDeck.Sett.Help",
label: "MaterialDeck.Sett.Help", label: "MaterialDeck.Sett.Help",
type: helpMenu, type: helpMenu,
restricted: false restricted: false
}); });
game.settings.registerMenu(MODULE.moduleName, 'downloadUtility',{ game.settings.registerMenu(moduleName, 'downloadUtility',{
name: "MaterialDeck.DownloadUtility.Title", name: "MaterialDeck.DownloadUtility.Title",
label: "MaterialDeck.DownloadUtility.Title", label: "MaterialDeck.DownloadUtility.Title",
type: downloadUtility, type: downloadUtility,
restricted: false restricted: false
}); });
game.settings.registerMenu(MODULE.moduleName, 'deviceConfig',{ game.settings.registerMenu(moduleName, 'deviceConfig',{
name: "MaterialDeck.DeviceConfig.Title", name: "MaterialDeck.DeviceConfig.Title",
label: "MaterialDeck.DeviceConfig.Title", label: "MaterialDeck.DeviceConfig.Title",
type: deviceConfig, type: deviceConfig,
restricted: false restricted: false
}); });
game.settings.register(MODULE.moduleName, 'devices', { game.settings.register(moduleName, 'devices', {
name: "devices", name: "devices",
scope: "client", scope: "client",
type: Object, type: Object,
config: false config: false
}); });
game.settings.registerMenu(MODULE.moduleName, 'permissionConfig',{ game.settings.registerMenu(moduleName, 'permissionConfig',{
name: "MaterialDeck.Sett.Permission", name: "MaterialDeck.Sett.Permission",
label: "MaterialDeck.Sett.Permission", label: "MaterialDeck.Sett.Permission",
type: userPermission, type: userPermission,
restricted: true restricted: true
}); });
game.settings.register(MODULE.moduleName, 'userPermission', { game.settings.register(moduleName, 'userPermission', {
name: "userPermission", name: "userPermission",
label: "",
scope: "world", scope: "world",
type: Object, type: Object,
config: false config: false,
default: {}
}); });
/** /**
* Playlist soundboard * Playlist soundboard
*/ */
game.settings.registerMenu(MODULE.moduleName, 'playlistConfigMenu',{ game.settings.registerMenu(moduleName, 'playlistConfigMenu',{
name: "MaterialDeck.Sett.PlaylistConfig", name: "MaterialDeck.Sett.PlaylistConfig",
label: "MaterialDeck.Sett.PlaylistConfig", label: "MaterialDeck.Sett.PlaylistConfig",
type: playlistConfigForm, type: playlistConfigForm,
restricted: false restricted: false
}); });
game.settings.register(MODULE.moduleName, 'playlists', { game.settings.register(moduleName, 'playlists', {
name: "selectedPlaylists", name: "selectedPlaylists",
scope: "world", scope: "world",
type: Object, type: Object,
@@ -202,21 +215,22 @@ export const registerSettings = async function() {
/** /**
* Macro Board * Macro Board
*/ */
game.settings.registerMenu(MODULE.moduleName, 'macroConfigMenu',{ game.settings.registerMenu(moduleName, 'macroConfigMenu',{
name: "MaterialDeck.Sett.MacroConfig", name: "MaterialDeck.Sett.MacroConfig",
label: "MaterialDeck.Sett.MacroConfig", label: "MaterialDeck.Sett.MacroConfig",
type: macroConfigForm, type: macroConfigForm,
restricted: false restricted: false
}); });
game.settings.register(MODULE.moduleName, 'macroSettings', { game.settings.register(moduleName, 'macroSettings', {
name: "macroSettings", name: "macroSettings",
scope: "world", scope: "world",
type: Object, type: Object,
config: false config: false,
default: {}
}); });
game.settings.register(MODULE.moduleName, 'macroArgs', { game.settings.register(moduleName, 'macroArgs', {
name: "macroArgs", name: "macroArgs",
scope: "world", scope: "world",
type: Object, type: Object,
@@ -226,7 +240,7 @@ export const registerSettings = async function() {
/** /**
* Soundboard * Soundboard
*/ */
game.settings.register(MODULE.moduleName, 'soundboardSettings', { game.settings.register(moduleName, 'soundboardSettings', {
name: "soundboardSettings", name: "soundboardSettings",
scope: "world", scope: "world",
type: Object, type: Object,
@@ -234,15 +248,16 @@ export const registerSettings = async function() {
config: false config: false
}); });
game.settings.registerMenu(MODULE.moduleName, 'soundboardConfigMenu',{ game.settings.registerMenu(moduleName, 'soundboardConfigMenu',{
name: "MaterialDeck.Sett.SoundboardConfig", name: "MaterialDeck.Sett.SoundboardConfig",
label: "MaterialDeck.Sett.SoundboardConfig", label: "MaterialDeck.Sett.SoundboardConfig",
type: soundboardConfigForm, type: soundboardConfigForm,
restricted: false restricted: false
}); });
let permissionSettings = game.settings.get(MODULE.moduleName,'userPermission'); let permissionSettings = game.settings.get(moduleName,'userPermission');
if (permissionSettings == undefined || permissionSettings == null || MODULE.isEmpty(permissionSettings)) {
if (permissionSettings == undefined || permissionSettings == null || isEmpty(permissionSettings)) {
permissionSettings = { permissionSettings = {
enable: defaultEnable, enable: defaultEnable,
permissions: defaultUserPermissions permissions: defaultUserPermissions
@@ -254,7 +269,7 @@ export const registerSettings = async function() {
if (permissionSettings.permissions.MACRO.BY_NAME == undefined) permissionSettings.permissions.MACRO.BY_NAME = [false,false,true,true]; if (permissionSettings.permissions.MACRO.BY_NAME == undefined) permissionSettings.permissions.MACRO.BY_NAME = [false,false,true,true];
} }
if (game.user.isGM) if (game.user.isGM)
game.settings.set(MODULE.moduleName,'userPermission',permissionSettings); game.settings.set(moduleName,'userPermission',permissionSettings);
} }
@@ -311,7 +326,7 @@ export class helpMenu extends FormApplication {
*/ */
static get defaultOptions() { static get defaultOptions() {
return mergeObject(super.defaultOptions, { return mergeObject(super.defaultOptions, {
id: "userPermissionConfig", id: "materialDeck_userPermissionConfig",
title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.Permission"), title: "Material Deck: "+game.i18n.localize("MaterialDeck.Sett.Permission"),
template: "./modules/MaterialDeck/templates/userPermissionConfig.html", template: "./modules/MaterialDeck/templates/userPermissionConfig.html",
width: 660, width: 660,
@@ -324,8 +339,8 @@ export class helpMenu extends FormApplication {
* Provide data to the template * Provide data to the template
*/ */
async getData() { async getData() {
let settings = game.settings.get(MODULE.moduleName,'userPermission'); let settings = game.settings.get(moduleName,'userPermission');
if (settings == undefined || settings == null || MODULE.isEmpty(settings)) { if (settings == undefined || settings == null || isEmpty(settings)) {
settings = { settings = {
enable: defaultEnable, enable: defaultEnable,
permissions: defaultUserPermissions permissions: defaultUserPermissions
@@ -335,7 +350,12 @@ export class helpMenu extends FormApplication {
const actions = Object.entries(duplicate(settings.permissions)).reduce((arr, e) => { const actions = Object.entries(duplicate(settings.permissions)).reduce((arr, e) => {
const perms = Object.entries(duplicate(e[1])).reduce((arr, p) => { const perms = Object.entries(duplicate(e[1])).reduce((arr, p) => {
let perm = {}; let perm = {};
perm.roles = [p[1][0],p[1][1],p[1][2],p[1][3]] perm.roles = [
{role:'player',en:p[1][0]},
{role:'trusted',en:p[1][1]},
{role:'assistent',en:p[1][2]},
{role:'gm',en:p[1][3]}
]
perm.id = p[0]; perm.id = p[0];
perm.label = game.i18n.localize("MaterialDeck.Perm."+e[0]+"."+p[0]+".label"); perm.label = game.i18n.localize("MaterialDeck.Perm."+e[0]+"."+p[0]+".label");
perm.hint = game.i18n.localize("MaterialDeck.Perm."+e[0]+"."+p[0]+".hint"); perm.hint = game.i18n.localize("MaterialDeck.Perm."+e[0]+"."+p[0]+".hint");
@@ -355,14 +375,21 @@ export class helpMenu extends FormApplication {
if (actions[i].id == 'MOVE') if (actions[i].id == 'MOVE')
actions.splice(i,1); actions.splice(i,1);
} }
const enable = [
{role:'player',en:settings.enable[0]},
{role:'trusted',en:settings.enable[1]},
{role:'assistent',en:settings.enable[2]},
{role:'gm',en:settings.enable[3]}
]
return { return {
roles: Object.keys(CONST.USER_ROLES).reduce((obj, r) => { roles: Object.keys(CONST.USER_ROLES).reduce((obj, r) => {
if ( r === "NONE" ) return obj; if ( r === "NONE" ) return obj;
obj[r] = `USER.Role${r.titleCase()}`; obj[r] = `USER.Role${r.titleCase()}`;
return obj; return obj;
}, {}), }, {}),
actions: actions, actions,
enable: settings.enable enable
} }
} }
@@ -372,12 +399,28 @@ export class helpMenu extends FormApplication {
* @param {*} formData * @param {*} formData
*/ */
async _updateObject(event, formData) { async _updateObject(event, formData) {
let permissions = expandObject(formData);
let settings = {}; let settings = {};
settings.enable = permissions.ENABLE; let permissions = expandObject(formData);
for (const [key, value] of Object.entries(permissions)) {
const val = value;
let conf = {};
if (key == 'ENABLE') {
settings.enable = [value.player, value.trusted, value.assistent, value.gm];
}
else {
conf = {};
for (const [key, value] of Object.entries(val)) {
const arr = [value.player, value.trusted, value.assistent, value.gm];
conf[key] = arr;
}
}
permissions[key] = conf;
}
delete permissions.ENABLE; delete permissions.ENABLE;
settings.permissions = permissions; settings.permissions = permissions;
// game.settings.set(MODULE.moduleName,'userPermission',settings); game.settings.set(moduleName,'userPermission',settings);
} }
async activateListeners(html) { async activateListeners(html) {
@@ -396,7 +439,7 @@ export class helpMenu extends FormApplication {
enable: defaultEnable, enable: defaultEnable,
permissions: defaultUserPermissions permissions: defaultUserPermissions
} }
await game.settings.set(MODULE.moduleName,'userPermission',settings); await game.settings.set(moduleName,'userPermission',settings);
this.render(); this.render();
ui.notifications.info(game.i18n.localize("MaterialDeck.Perm.DefaultNotification")); ui.notifications.info(game.i18n.localize("MaterialDeck.Perm.DefaultNotification"));
} }

View File

@@ -1,4 +1,4 @@
import * as MODULE from "../MaterialDeck.js"; import { moduleName, sendWS, tokenControl, macroControl, combatTracker, playlistControl, soundboard, otherControls, externalModules, sceneControl } from "../MaterialDeck.js";
export class StreamDeck{ export class StreamDeck{
constructor() { constructor() {
@@ -90,14 +90,14 @@ export class StreamDeck{
} }
if (this.getActive(action) == false){ if (this.getActive(action) == false){
if (action == 'token') MODULE.tokenControl.active = false; if (action == 'token') tokenControl.active = false;
else if (action == 'macro') MODULE.macroControl.active = false; else if (action == 'macro') macroControl.active = false;
else if (action == 'combattracker') MODULE.combatTracker.active = false; else if (action == 'combattracker') combatTracker.active = false;
else if (action == 'playlist') MODULE.playlistControl.active = false; else if (action == 'playlist') playlistControl.active = false;
else if (action == 'soundboard') MODULE.soundboard.active = false; else if (action == 'soundboard') soundboard.active = false;
else if (action == 'other') MODULE.otherControls.active = false; else if (action == 'other') otherControls.active = false;
else if (action == 'external') MODULE.externalModules.active = false; else if (action == 'external') externalModules.active = false;
else if (action == 'scene') MODULE.sceneControl.active = false; else if (action == 'scene') sceneControl.active = false;
} }
} }
@@ -204,7 +204,7 @@ export class StreamDeck{
target: 0 target: 0
} }
}; };
MODULE.sendWS(JSON.stringify(msg)); sendWS(JSON.stringify(msg));
} }
setColor(context,color = '#000000'){ setColor(context,color = '#000000'){
@@ -216,7 +216,7 @@ export class StreamDeck{
format: 'color', format: 'color',
background: color background: color
}; };
MODULE.sendWS(JSON.stringify(msg)); sendWS(JSON.stringify(msg));
} }
setImage(image,context,device,nr,id){ setImage(image,context,device,nr,id){
@@ -232,7 +232,7 @@ export class StreamDeck{
target: 0 target: 0
} }
}; };
MODULE.sendWS(JSON.stringify(json)); sendWS(JSON.stringify(json));
} }
setBufferImage(context,device,nr,id){ setBufferImage(context,device,nr,id){
@@ -247,7 +247,7 @@ export class StreamDeck{
target: 0 target: 0
} }
}; };
MODULE.sendWS(JSON.stringify(json)); sendWS(JSON.stringify(json));
} }
setIcon(context,device,src='',options = {}){ setIcon(context,device,src='',options = {}){
@@ -301,6 +301,8 @@ export class StreamDeck{
let format = split[split.length-1].split('?')[0]; let format = split[split.length-1].split('?')[0];
split = split[0].split(' '); split = split[0].split(' ');
if (split[0] == 'fas' || split[0] == 'far' || split[0] == 'fal' || split[0] == 'fad') format = 'icon'; if (split[0] == 'fas' || split[0] == 'far' || split[0] == 'fal' || split[0] == 'fad') format = 'icon';
let split2 = split[0].split('-');
if (split2[0] == 'fa') format = 'icon';
let msg = { let msg = {
target: "SD", target: "SD",
event: 'setIcon', event: 'setIcon',
@@ -326,7 +328,7 @@ export class StreamDeck{
action: action, action: action,
state: state state: state
}; };
MODULE.sendWS(JSON.stringify(msg)); sendWS(JSON.stringify(msg));
} }
setProfile(action,device){ setProfile(action,device){
@@ -343,7 +345,7 @@ export class StreamDeck{
profile: profile profile: profile
} }
}; };
MODULE.sendWS(JSON.stringify(json)); sendWS(JSON.stringify(json));
} }
setPluginId(id){ setPluginId(id){
@@ -439,7 +441,7 @@ export class StreamDeck{
img.onload = () => { img.onload = () => {
if (format == 'color') ctx.filter = "opacity(0)"; if (format == 'color') ctx.filter = "opacity(0)";
if (data.overlay == true) ctx.filter = "brightness(" + game.settings.get(MODULE.moduleName,'imageBrightness') + "%)"; if (data.overlay == true) ctx.filter = "brightness(" + game.settings.get(moduleName,'imageBrightness') + "%)";
//ctx.filter = "brightness(0) saturate(100%) invert(38%) sepia(62%) saturate(2063%) hue-rotate(209deg) brightness(90%) contrast(95%)"; //ctx.filter = "brightness(0) saturate(100%) invert(38%) sepia(62%) saturate(2063%) hue-rotate(209deg) brightness(90%) contrast(95%)";
var imageAspectRatio = img.width / img.height; var imageAspectRatio = img.width / img.height;
var canvasAspectRatio = canvas.width / canvas.height; var canvasAspectRatio = canvas.width / canvas.height;
@@ -564,7 +566,7 @@ export class StreamDeck{
addToImageBuffer(img,data){ addToImageBuffer(img,data){
const id = this.getImageBufferId(data); const id = this.getImageBufferId(data);
const maxBufferSize = game.settings.get(MODULE.moduleName,'imageBuffer'); const maxBufferSize = game.settings.get(moduleName,'imageBuffer');
if (maxBufferSize == 0) return false; if (maxBufferSize == 0) return false;
if (this.imageBufferCounter > maxBufferSize) this.imageBufferCounter = 0; if (this.imageBufferCounter > maxBufferSize) this.imageBufferCounter = 0;
@@ -581,7 +583,7 @@ export class StreamDeck{
} }
checkImageBuffer(data){ checkImageBuffer(data){
if (game.settings.get(MODULE.moduleName,'imageBuffer') == 0) return false; if (game.settings.get(moduleName,'imageBuffer') == 0) return false;
const id = this.getImageBufferId(data); const id = this.getImageBufferId(data);
for (let i=0; i<this.imageBuffer.length; i++){ for (let i=0; i<this.imageBuffer.length; i++){

View File

@@ -2,11 +2,19 @@ import {compatibleCore} from "../misc.js";
export class demonlord{ export class demonlord{
constructor(){ constructor(){
console.log("Material Deck: Using system 'Shadow of the Demon Lord'");
}
getActorData(token) {
return compatibleCore('10.0') ? token.actor.system : token.actor.data.data;
}
getItemData(item) {
return compatibleCore('10.0') ? item.system : item.data.data;
} }
getHP(token) { getHP(token) {
const hp = token.actor.data.data.characteristics.health; const hp = this.getActorData(token).characteristics.health;
return { return {
value: hp.value, value: hp.value,
max: hp.max max: hp.max
@@ -18,7 +26,7 @@ export class demonlord{
} }
getAC(token) { getAC(token) {
return token.actor.data.data.characteristics.defense; return this.getActorData(token).characteristics.defense;
} }
getShieldHP(token) { getShieldHP(token) {
@@ -26,11 +34,11 @@ export class demonlord{
} }
getSpeed(token) { getSpeed(token) {
return token.actor.data.data.characteristics.speed; return this.getActorData(token).characteristics.speed;
} }
getInitiative(token) { getInitiative(token) {
return token.actor.data.data.fastturn ? "FAST" : "SLOW"; return this.getActorData(token).fastturn ? "FAST" : "SLOW";
} }
toggleInitiative(token) { toggleInitiative(token) {
@@ -50,12 +58,12 @@ export class demonlord{
getAbility(token, ability) { getAbility(token, ability) {
if (ability == undefined) ability = 'strength'; if (ability == undefined) ability = 'strength';
return token.actor.data.data.attributes?.[ability].value; return this.getActorData(token).attributes?.[ability].value;
} }
getAbilityModifier(token, ability) { getAbilityModifier(token, ability) {
if (ability == undefined) ability = 'str'; if (ability == undefined) ability = 'str';
let val = token.actor.data.data.attributes?.[ability].modifier; let val = this.getActorData(token).attributes?.[ability].modifier;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
@@ -65,7 +73,7 @@ export class demonlord{
getSkill(token, skill) { getSkill(token, skill) {
if (skill == undefined) skill = 'acr'; if (skill == undefined) skill = 'acr';
const val = token.actor.data.data.skills?.[skill].total; const val = this.getActorData(token).skills?.[skill].total;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
@@ -114,7 +122,7 @@ export class demonlord{
} }
getItemUses(item) { getItemUses(item) {
return {available: item.data.data.quantity}; return {available: getItemData(item).quantity};
} }
/** /**
@@ -124,7 +132,7 @@ export class demonlord{
if (level == undefined) level = 'any'; if (level == undefined) level = 'any';
const allItems = token.actor.items; const allItems = token.actor.items;
if (level == 'any') return allItems.filter(i => i.type == 'spell') if (level == 'any') return allItems.filter(i => i.type == 'spell')
else return allItems.filter(i => i.type == 'spell' && i.data.data.rank == level) else return allItems.filter(i => i.type == 'spell' && getItemData(i).rank == level)
} }
getSpellUses(token,level,item) { getSpellUses(token,level,item) {

View File

@@ -2,11 +2,19 @@ import {compatibleCore} from "../misc.js";
export class dnd35e{ export class dnd35e{
constructor(){ constructor(){
console.log("Material Deck: Using system 'Dungeons & Dragons 3.5e'/'Pathfinder 1e'");
}
getActorData(token) {
return compatibleCore('10.0') ? token.actor.system : token.actor.data.data;
}
getItemData(item) {
return compatibleCore('10.0') ? item.system : item.data.data;
} }
getHP(token) { getHP(token) {
const hp = token.actor.data.data.attributes.hp; const hp = this.getActorData(token).attributes.hp;
return { return {
value: hp.value, value: hp.value,
max: hp.max max: hp.max
@@ -14,7 +22,7 @@ export class dnd35e{
} }
getTempHP(token) { getTempHP(token) {
const hp = token.actor.data.data.attributes.hp; const hp = this.getActorData(token).attributes.hp;
return { return {
value: (hp.temp == null) ? 0 : hp.temp, value: (hp.temp == null) ? 0 : hp.temp,
max: (hp.tempmax == null) ? 0 : hp.tempmax max: (hp.tempmax == null) ? 0 : hp.tempmax
@@ -22,7 +30,7 @@ export class dnd35e{
} }
getAC(token) { getAC(token) {
return token.actor.data.data.attributes.ac.normal.total; return this.getActorData(token).attributes.ac.normal.total;
} }
getShieldHP(token) { getShieldHP(token) {
@@ -30,7 +38,7 @@ export class dnd35e{
} }
getSpeed(token) { getSpeed(token) {
const movement = token.actor.data.data.attributes.speed; const movement = this.getActorData(token).attributes.speed;
let speed = ""; let speed = "";
if (movement.burrow.total > 0) speed += `Burrow: ${movement.burrow.total}Ft`; if (movement.burrow.total > 0) speed += `Burrow: ${movement.burrow.total}Ft`;
if (movement.climb.total > 0) { if (movement.climb.total > 0) {
@@ -53,7 +61,7 @@ export class dnd35e{
} }
getInitiative(token) { getInitiative(token) {
let initiative = token.actor.data.data.attributes.init.total; let initiative = this.getActorData(token).attributes.init.total;
return (initiative >= 0) ? `+${initiative}` : initiative; return (initiative >= 0) ? `+${initiative}` : initiative;
} }
@@ -71,29 +79,29 @@ export class dnd35e{
getAbility(token, ability) { getAbility(token, ability) {
if (ability == undefined) ability = 'str'; if (ability == undefined) ability = 'str';
return token.actor.data.data.abilities?.[ability].value; return this.getActorData(token).abilities?.[ability].value;
} }
getAbilityModifier(token, ability) { getAbilityModifier(token, ability) {
if (ability == undefined) ability = 'str'; if (ability == undefined) ability = 'str';
let val = token.actor.data.data.abilities?.[ability].mod; let val = this.getActorData(token).abilities?.[ability].mod;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
getAbilitySave(token, ability) { getAbilitySave(token, ability) {
if (ability == undefined) ability = 'fort'; if (ability == undefined) ability = 'fort';
let val = token.actor.data.data.attributes.savingThrows?.[ability].total; let val = this.getActorData(token).attributes.savingThrows?.[ability].total;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
getSkill(token, skill) { getSkill(token, skill) {
if (skill == undefined) skill = 'apr'; if (skill == undefined) skill = 'apr';
const val = token.actor.data.data.skills?.[skill].mod; const val = this.getActorData(token).skills?.[skill].mod;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
getProficiency(token) { getProficiency(token) {
const val = token.actor.data.data.attributes.prof; const val = this.getActorData(token).attributes.prof;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
@@ -133,7 +141,10 @@ export class dnd35e{
if (roll == 'ability') token.actor.rollAbilityTest(ability,options); if (roll == 'ability') token.actor.rollAbilityTest(ability,options);
else if (roll == 'save') token.actor.rollSavingThrow(save, null, null,options); else if (roll == 'save') token.actor.rollSavingThrow(save, null, null,options);
else if (roll == 'skill') token.actor.rollSkill(skill,options); else if (roll == 'skill') token.actor.rollSkill(skill,options);
else if (roll == 'initiative') token.actor.rollInitiative(options); else if (roll == 'initiative') {
options.rerollInitiative = true;
token.actor.rollInitiative(options);
}
else if (roll == 'grapple') token.actor.rollGrapple(options); else if (roll == 'grapple') token.actor.rollGrapple(options);
else if (roll == 'bab') token.actor.rollBAB(options); else if (roll == 'bab') token.actor.rollBAB(options);
else if (roll == 'melee') token.actor.rollMelee(options); else if (roll == 'melee') token.actor.rollMelee(options);
@@ -147,16 +158,16 @@ export class dnd35e{
if (itemType == undefined) itemType = 'any'; if (itemType == undefined) itemType = 'any';
const allItems = token.actor.items; const allItems = token.actor.items;
if (itemType == 'any') return allItems.filter(i => i.type == 'weapon' || i.type == 'equipment' || i.type == 'consumable' || i.type == 'loot' || i.type == 'container'); if (itemType == 'any') return allItems.filter(i => i.type == 'weapon' || i.type == 'equipment' || i.type == 'consumable' || i.type == 'loot' || i.type == 'container');
else if (game.system.id == 'D35E' && itemType == 'container') return allItems.filter(i => i.type == 'loot' && i.data.data.subType == itemType); else if (game.system.id == 'D35E' && itemType == 'container') return allItems.filter(i => i.type == 'loot' && this.getItemData(i).subType == itemType);
else { else {
if (itemType == 'gear' || itemType == 'ammo' || itemType == 'misc' || itemType == 'tradeGoods') if (itemType == 'gear' || itemType == 'ammo' || itemType == 'misc' || itemType == 'tradeGoods')
return allItems.filter(i => i.type == 'loot' && i.data.data.subType == itemType); return allItems.filter(i => i.type == 'loot' && this.getItemData(i).subType == itemType);
else return allItems.filter(i => i.type == itemType); else return allItems.filter(i => i.type == itemType);
} }
} }
getItemUses(item) { getItemUses(item) {
return {available: item.data.data.quantity}; return {available: this.getItemData(item).quantity};
} }
/** /**
@@ -170,10 +181,10 @@ export class dnd35e{
} }
getFeatureUses(item) { getFeatureUses(item) {
if (item.data.type == 'class') return {available: item.data.data.levels}; if (item.data.type == 'class') return {available: this.getItemData(item).levels};
else return { else return {
available: item.data.data.uses.value, available: this.getItemData(item).uses.value,
maximum: item.data.data.uses.max maximum: this.getItemData(item).uses.max
}; };
} }
@@ -184,12 +195,12 @@ export class dnd35e{
if (level == undefined) level = 'any'; if (level == undefined) level = 'any';
const allItems = token.actor.items; const allItems = token.actor.items;
if (level == 'any') return allItems.filter(i => i.type == 'spell') if (level == 'any') return allItems.filter(i => i.type == 'spell')
else return allItems.filter(i => i.type == 'spell' && i.data.data.level == level) else return allItems.filter(i => i.type == 'spell' && this.getItemData(i).level == level)
} }
getSpellUses(token,level,item) { getSpellUses(token,level,item) {
if (level == undefined) level = 'any'; if (level == undefined) level = 'any';
if (item.data.data.level == 0) return; if (this.getItemData(item).level == 0) return;
return { return {
available: item.charges, available: item.charges,
maximum: item.maxCharges maximum: item.maxCharges

View File

@@ -9,11 +9,19 @@ const proficiencyColors = {
export class dnd5e{ export class dnd5e{
constructor(){ constructor(){
console.log("Material Deck: Using system 'Dungeons & Dragons 5e'");
}
getActorData(token) {
return compatibleCore('10.0') ? token.actor.system : token.actor.data.data;
}
getItemData(item) {
return compatibleCore('10.0') ? item.system : item.data.data;
} }
getHP(token) { getHP(token) {
const hp = token.actor.data.data.attributes.hp; const hp = this.getActorData(token).attributes.hp;
return { return {
value: hp.value, value: hp.value,
max: hp.max max: hp.max
@@ -21,7 +29,7 @@ export class dnd5e{
} }
getTempHP(token) { getTempHP(token) {
const hp = token.actor.data.data.attributes.hp; const hp = this.getActorData(token).attributes.hp;
return { return {
value: (hp.temp == null) ? 0 : hp.temp, value: (hp.temp == null) ? 0 : hp.temp,
max: (hp.tempmax == null) ? 0 : hp.tempmax max: (hp.tempmax == null) ? 0 : hp.tempmax
@@ -29,7 +37,7 @@ export class dnd5e{
} }
getAC(token) { getAC(token) {
return token.actor.data.data.attributes.ac.value; return this.getActorData(token).attributes.ac.value;
} }
getShieldHP(token) { getShieldHP(token) {
@@ -37,9 +45,9 @@ export class dnd5e{
} }
getSpeed(token) { getSpeed(token) {
const movement = token.actor.data.data.attributes.movement; const movement = this.getActorData(token).attributes.movement;
let speed = ""; let speed = "";
if (movement != undefined){
if (movement.burrow > 0) speed += `${game.i18n.localize("DND5E.MovementBurrow")}: ${movement.burrow + movement.units}`; if (movement.burrow > 0) speed += `${game.i18n.localize("DND5E.MovementBurrow")}: ${movement.burrow + movement.units}`;
if (movement.climb > 0) { if (movement.climb > 0) {
if (speed.length > 0) speed += '\n'; if (speed.length > 0) speed += '\n';
@@ -61,17 +69,12 @@ export class dnd5e{
if (speed.length > 0) speed += '\n'; if (speed.length > 0) speed += '\n';
speed += `${game.i18n.localize("DND5E.MovementWalk")}: ${movement.walk + movement.units}`; speed += `${game.i18n.localize("DND5E.MovementWalk")}: ${movement.walk + movement.units}`;
} }
}
else {
const spd = token.actor.data.data.attributes.speed;
speed = spd.value;
if (spd.special.length > 0) speed + "\n" + spd.special;
}
return speed; return speed;
} }
getInitiative(token) { getInitiative(token) {
let initiative = token.actor.data.data.attributes.init.total; let initiative = this.getActorData(token).attributes.init.total;
return (initiative >= 0) ? `+${initiative}` : initiative; return (initiative >= 0) ? `+${initiative}` : initiative;
} }
@@ -80,38 +83,38 @@ export class dnd5e{
} }
getPassivePerception(token) { getPassivePerception(token) {
return token.actor.data.data.skills.prc.passive; return this.getActorData(token).skills.prc.passive;
} }
getPassiveInvestigation(token) { getPassiveInvestigation(token) {
return token.actor.data.data.skills.inv.passive; return this.getActorData(token).skills.inv.passive;
} }
getAbility(token, ability) { getAbility(token, ability) {
if (ability == undefined) ability = 'str'; if (ability == undefined) ability = 'str';
return token.actor.data.data.abilities?.[ability].value; return this.getActorData(token).abilities?.[ability].value;
} }
getAbilityModifier(token, ability) { getAbilityModifier(token, ability) {
if (ability == undefined) ability = 'str'; if (ability == undefined) ability = 'str';
let val = token.actor.data.data.abilities?.[ability].mod; let val = this.getActorData(token).abilities?.[ability].mod;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
getAbilitySave(token, ability) { getAbilitySave(token, ability) {
if (ability == undefined) ability = 'str'; if (ability == undefined) ability = 'str';
let val = token.actor.data.data.abilities?.[ability].save; let val = this.getActorData(token).abilities?.[ability].save;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
getSkill(token, skill) { getSkill(token, skill) {
if (skill == undefined) skill = 'acr'; if (skill == undefined) skill = 'acr';
const val = token.actor.data.data.skills?.[skill].total; const val = this.getActorData(token).skills?.[skill].total;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
getProficiency(token) { getProficiency(token) {
const val = token.actor.data.data.attributes.prof; const val = this.getActorData(token).attributes.prof;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
@@ -151,7 +154,10 @@ export class dnd5e{
if (roll == 'ability') token.actor.rollAbilityTest(ability,options); if (roll == 'ability') token.actor.rollAbilityTest(ability,options);
else if (roll == 'save') token.actor.rollAbilitySave(save,options); else if (roll == 'save') token.actor.rollAbilitySave(save,options);
else if (roll == 'skill') token.actor.rollSkill(skill,options); else if (roll == 'skill') token.actor.rollSkill(skill,options);
else if (roll == 'initiative') token.actor.rollInitiative(options); else if (roll == 'initiative') {
options.rerollInitiative = true;
token.actor.rollInitiative(options);
}
else if (roll == 'deathSave') token.actor.rollDeathSave(options); else if (roll == 'deathSave') token.actor.rollDeathSave(options);
} }
@@ -166,7 +172,7 @@ export class dnd5e{
} }
getItemUses(item) { getItemUses(item) {
return {available: item.data.data.quantity}; return {available: this.getItemData(item).quantity};
} }
/** /**
@@ -175,15 +181,18 @@ export class dnd5e{
getFeatures(token,featureType) { getFeatures(token,featureType) {
if (featureType == undefined) featureType = 'any'; if (featureType == undefined) featureType = 'any';
const allItems = token.actor.items; const allItems = token.actor.items;
if (featureType == 'any') return allItems.filter(i => i.type == 'class' || i.type == 'feat') if (featureType == 'any') return allItems.filter(i => i.type == 'class' || i.type == 'feat')
else if (featureType == 'activeAbilities') return allItems.filter(i => i.type == 'feat' && i.labels.featType == 'Action')
else if (featureType == 'passiveAbilities') return allItems.filter(i => i.type == 'feat' && i.labels.featType == 'Passive')
else return allItems.filter(i => i.type == featureType) else return allItems.filter(i => i.type == featureType)
} }
getFeatureUses(item) { getFeatureUses(item) {
if (item.data.type == 'class') return {available: item.data.data.levels}; if (item.type == 'class') return {available: this.getItemData(item).levels};
else return { else return {
available: item.data.data.uses.value, available: this.getItemData(item).uses.value,
maximum: item.data.data.uses.max maximum: this.getItemData(item).uses.max
}; };
} }
@@ -194,33 +203,65 @@ export class dnd5e{
if (level == undefined) level = 'any'; if (level == undefined) level = 'any';
const allItems = token.actor.items; const allItems = token.actor.items;
if (level == 'any') return allItems.filter(i => i.type == 'spell') if (level == 'any') return allItems.filter(i => i.type == 'spell')
else return allItems.filter(i => i.type == 'spell' && i.data.data.level == level) else return allItems.filter(i => i.type == 'spell' && this.getItemData(i).level == level)
} }
getSpellUses(token,level,item) { getSpellUses(token,level,item) {
if (level == undefined) level = 'any'; if (level == undefined || level == 'any') level = this.getItemData(item).level;
if (item.data.data.level == 0) return; if (this.getItemData(item).level == 0) return;
return { return {
available: token.actor.data.data.spells?.[`spell${level}`].value, available: this.getActorData(token).spells?.[`spell${level}`].value,
maximum: token.actor.data.data.spells?.[`spell${level}`].max maximum: this.getActorData(token).spells?.[`spell${level}`].max
} }
} }
rollItem(item) { rollItem(item, settings, rollOption) {
return item.roll() let options = {
fastForward: rollOption != 'dialog',
advantage: rollOption == 'advantage',
disadvantage: rollOption == 'disadvantage'
}
if (settings.inventoryType == 'weapon') {
if (settings.weaponRollMode == 'attack') {
options.fastForward = true;
return item.rollAttack(options);
}
else if (settings.weaponRollMode == 'damage' || settings.weaponRollMode == 'versatile') {
options.fastForward = true;
return item.rollDamage({
options,
critical:false,
versatile: settings.weaponRollMode == 'versatile'
});
}
else if (settings.weaponRollMode == 'damageCrit' || settings.weaponRollMode == 'versatileCrit') {
options.fastForward = true;
return item.rollDamage({
options,
critical:true,
versatile: settings.weaponRollMode == 'versatile' || settings.weaponRollMode == 'versatileCrit'
});
}
else if (settings.weaponRollMode == 'otherFormula') {
return item.rollFormula(options);
}
}
if (compatibleCore('10.0')) item.use(options)
else item.roll(options)
} }
/** /**
* Ring Colors * Ring Colors
*/ */
getSkillRingColor(token, skill) { getSkillRingColor(token, skill) {
const profLevel = token.actor.data.data?.skills[skill]?.proficient; const profLevel = this.getActorData(token).skills[skill]?.proficient;
if (profLevel == undefined) return; if (profLevel == undefined) return;
return proficiencyColors?.[profLevel]; return proficiencyColors?.[profLevel];
} }
getSaveRingColor(token, save) { getSaveRingColor(token, save) {
const profLevel = token.actor.data.data?.abilities[save]?.proficient; const profLevel = this.getActorData(token).abilities[save]?.proficient;
if (profLevel == undefined) return; if (profLevel == undefined) return;
return proficiencyColors?.[profLevel]; return proficiencyColors?.[profLevel];
} }

View File

@@ -2,29 +2,35 @@ import {compatibleCore} from "../misc.js";
export class forbiddenlands{ export class forbiddenlands{
constructor(){ constructor(){
console.log("Material Deck: Using system 'Forbidden Lands'");
}
getActorData(token) {
return compatibleCore('10.0') ? token.actor.system : token.actor.data.data;
}
getItemData(item) {
return compatibleCore('10.0') ? item.system : item.data.data;
} }
getHP(token) { getHP(token) {
const hp = token.actor.data.data.attribute.strength; const hp = this.getActorData(token).attribute.strength;
return { return {
value: hp.value, value: hp.value,
max: hp.max max: hp.max
} }
} }
getAgility(token) { getAgility(token) {
const agility = token.actor.data.data.attribute.agility; const agility = this.getActorData(token).attribute.agility;
return { return {
value: agility.value, value: agility.value,
max: agility.max max: agility.max
} }
} }
getWits(token) { getWits(token) {
const wits = token.actor.data.data.attribute.wits; const wits = this.getActorData(token).attribute.wits;
return { return {
value: wits.value, value: wits.value,
max: wits.max max: wits.max
@@ -32,7 +38,7 @@ export class forbiddenlands{
} }
getEmpathy(token) { getEmpathy(token) {
const empathy = token.actor.data.data.attribute.empathy; const empathy = this.getActorData(token).attribute.empathy;
return { return {
value: empathy.value, value: empathy.value,
max: empathy.max max: empathy.max
@@ -40,7 +46,7 @@ export class forbiddenlands{
} }
getWillPower(token) { getWillPower(token) {
const wp = token.actor.data.data.bio.willpower; const wp = this.getActorData(token).bio.willpower;
return { return {
value: wp.value, value: wp.value,
max: wp.max max: wp.max
@@ -49,15 +55,9 @@ export class forbiddenlands{
getTempHP(token) { getTempHP(token) {
return 0; return 0;
const hp = token.actor.data.data.attributes.hp;
return {
value: (hp.temp == null) ? 0 : hp.temp,
max: (hp.tempmax == null) ? 0 : hp.tempmax
}
} }
getAC(token) { getAC(token) {
const totalArmor = token.actor.itemTypes.armor.reduce((sum, armor) => { const totalArmor = token.actor.itemTypes.armor.reduce((sum, armor) => {
if (armor.itemProperties.part === "shield") return sum; if (armor.itemProperties.part === "shield") return sum;
const value = armor.itemProperties.bonus.value; const value = armor.itemProperties.bonus.value;
@@ -76,8 +76,6 @@ export class forbiddenlands{
getInitiative(token) { getInitiative(token) {
return 0; return 0;
let initiative = token.actor.data.data.attributes.init.total;
return (initiative >= 0) ? `+${initiative}` : initiative;
} }
toggleInitiative(token) { toggleInitiative(token) {
@@ -86,17 +84,15 @@ export class forbiddenlands{
getPassivePerception(token) { getPassivePerception(token) {
return 0; return 0;
return token.actor.data.data.skills.prc.passive;
} }
getPassiveInvestigation(token) { getPassiveInvestigation(token) {
return; return;
return token.actor.data.data.skills.inv.passive;
} }
getAbility(token, ability) { getAbility(token, ability) {
if (ability == undefined) ability = 'strength'; if (ability == undefined) ability = 'strength';
return token.actor.data.data.attribute?.[ability].value; return this.getActorData(token).attribute?.[ability].value;
} }
getAbilityModifier(token, ability) { getAbilityModifier(token, ability) {
@@ -116,8 +112,6 @@ export class forbiddenlands{
getProficiency(token) { getProficiency(token) {
return; return;
const val = token.actor.data.data.attributes.prof;
return (val >= 0) ? `+${val}` : val;
} }
getConditionIcon(condition) { getConditionIcon(condition) {
@@ -181,9 +175,9 @@ export class forbiddenlands{
getItemUses(item) { getItemUses(item) {
if (item.type == 'monsterAttack') return; if (item.type == 'monsterAttack') return;
if (item.type == 'rawMaterial') return {available: item.data.data.quantity}; if (item.type == 'rawMaterial') return {available: this.getItemData(item).quantity};
return {available: item.data.data.bonus.value, return {available: this.getItemData(item).bonus.value,
maximum: item.data.data.bonus.max}; maximum: this.getItemData(item).bonus.max};
} }
/** /**
@@ -197,10 +191,10 @@ export class forbiddenlands{
} }
getFeatureUses(item) { getFeatureUses(item) {
if (item.data.type == 'class') return {available: item.data.data.levels}; if (item.data.type == 'class') return {available: this.getItemData(item).levels};
else return { else return {
available: item.data.data.uses.value, available: this.getItemData(item).uses.value,
maximum: item.data.data.uses.max maximum: this.getItemData(item).uses.max
}; };
} }
@@ -211,15 +205,15 @@ export class forbiddenlands{
if (level == undefined) level = 'any'; if (level == undefined) level = 'any';
const allItems = token.actor.items; const allItems = token.actor.items;
if (level == 'any') return allItems.filter(i => i.type == 'spell') if (level == 'any') return allItems.filter(i => i.type == 'spell')
else return allItems.filter(i => i.type == 'spell' && i.data.data.level == level) else return allItems.filter(i => i.type == 'spell' && this.getItemData(i).level == level)
} }
getSpellUses(token,level,item) { getSpellUses(token,level,item) {
if (level == undefined) level = 'any'; if (level == undefined) level = 'any';
if (item.data.data.level == 0) return; if (this.getItemData(item).level == 0) return;
return { return {
available: token.actor.data.data.spells?.[`spell${level}`].value, available: this.getActorData(token).spells?.[`spell${level}`].value,
maximum: token.actor.data.data.spells?.[`spell${level}`].max maximum: this.getActorData(token).spells?.[`spell${level}`].max
} }
} }

View File

@@ -1,5 +1,5 @@
import {compatibleCore} from "../misc.js";
import { otherControls } from "../../MaterialDeck.js"; import { otherControls } from "../../MaterialDeck.js";
import { compatibleCore } from "../misc.js";
const limitedSheets = ['loot', 'vehicle']; const limitedSheets = ['loot', 'vehicle'];
const proficiencyColors = const proficiencyColors =
@@ -14,11 +14,19 @@ const proficiencyColors =
export class pf2e{ export class pf2e{
constructor(){ constructor(){
console.log("Material Deck: Using system 'Pathfinder 2e'");
} }
tokenSpellData = new Map(); tokenSpellData = new Map();
getActorData(token) {
return compatibleCore('10.0') ? token.actor.system : token.actor.data.data;
}
getItemData(item) {
return compatibleCore('10.0') ? item.system : item.data.data;
}
getHP(token) { getHP(token) {
const hp = token.actor.attributes?.hp; const hp = token.actor.attributes?.hp;
return { return {
@@ -48,7 +56,7 @@ export class pf2e{
getSpeed(token) { getSpeed(token) {
if (this.isLimitedSheet(token.actor) || token.actor.type == 'hazard') { if (this.isLimitedSheet(token.actor) || token.actor.type == 'hazard') {
if (token.actor.type == 'vehicle') { if (token.actor.type == 'vehicle') {
return token.actor.data.data.details.speed; return this.getActorData(token).details.speed;
} else return ''; } else return '';
} }
let speed = `${token.actor.attributes.speed?.total}'`; let speed = `${token.actor.attributes.speed?.total}'`;
@@ -117,7 +125,7 @@ export class pf2e{
findSave(token, ability) { findSave(token, ability) {
if (this.isLimitedSheet(token.actor)) return; if (this.isLimitedSheet(token.actor)) return;
return token.actor.data.data.saves?.[ability]; return this.getActorData(token).saves?.[ability];
} }
fixSave(ability) { fixSave(ability) {
@@ -151,12 +159,12 @@ export class pf2e{
return; return;
} }
} }
return token.actor.data.data.skills?.[skill]; return this.getActorData(token).skills?.[skill];
} }
getLoreSkills(token) { getLoreSkills(token) {
if (this.isLimitedSheet(token.actor)) return []; if (this.isLimitedSheet(token.actor)) return [];
const skills = token.actor.data.data.skills; const skills = this.getActorData(token).skills;
return Object.keys(skills).map(key => skills[key]).filter(s => s.lore == true); return Object.keys(skills).map(key => skills[key]).filter(s => s.lore == true);
} }
@@ -270,7 +278,7 @@ export class pf2e{
return; return;
} }
} }
let skillName = token.actor.data.data.skills?.[skill].name; let skillName = this.getActorData(token).skills?.[skill].name;
skillName = skillName.charAt(0).toUpperCase() + skillName.slice(1); skillName = skillName.charAt(0).toUpperCase() + skillName.slice(1);
this.checkRoll(`Skill Check: ${skillName}`, token.actor.skills?.[skill], 'skill-check', token.actor); this.checkRoll(`Skill Check: ${skillName}`, token.actor.skills?.[skill], 'skill-check', token.actor);
} }
@@ -294,7 +302,7 @@ export class pf2e{
} }
getItemUses(item) { getItemUses(item) {
return {available: item.quantity.value}; return {available: item.quantity};
} }
/** /**
@@ -304,16 +312,25 @@ export class pf2e{
if (this.isLimitedSheet(token.actor)) return []; if (this.isLimitedSheet(token.actor)) return [];
if (featureType == undefined) featureType = 'any'; if (featureType == undefined) featureType = 'any';
const allItems = token.actor.items; const allItems = token.actor.items;
if (featureType == 'any') return allItems.filter(i => i.type == 'ancestry' || i.type == 'background' || i.type == 'class' || i.type == 'feat' || i.type == 'action'); if (featureType == 'any') return allItems.filter(i => i.type == 'ancestry' || i.type == 'background' || i.type == 'class' || i.type == 'feat' || i.type == 'action' || i.type == 'heritage' || i.type == 'deity' || i.type == '');
if (featureType == 'feat-any') return allItems.filter(i => i.type == 'feat');
if (featureType == 'ancestryfeature') return allItems.filter(i => i.type == 'feat' && i.featType == 'ancestryfeature');
if (featureType == 'classfeature') return allItems.filter(i => i.type == 'feat' && i.featType == 'classfeature');
if (featureType == 'feat-anc') return allItems.filter(i => i.type == 'feat' && i.featType == 'ancestry');
if (featureType == 'feat-arc') return allItems.filter(i => i.type == 'feat' && i.featType == 'archetype' && i.name.indexOf('Dedication') < 0);
if (featureType == 'feat-ded') return allItems.filter(i => i.type == 'feat' && i.featType == 'archetype' && i.name.indexOf('Dedication') > 0);
if (featureType == 'feat-cla') return allItems.filter(i => i.type == 'feat' && i.featType == 'class');
if (featureType == 'feat-gen') return allItems.filter(i => i.type == 'feat' && i.featType == 'general');
if (featureType == 'feat-ski') return allItems.filter(i => i.type == 'feat' && i.featType == 'skill');
if (featureType == 'action-any') return allItems.filter(i => i.type == 'action'); if (featureType == 'action-any') return allItems.filter(i => i.type == 'action');
if (featureType == 'action-def') return allItems.filter(i => i.type == 'action' && i.data.data.actionCategory?.value == 'defensive'); if (featureType == 'action-def') return allItems.filter(i => i.type == 'action' && this.getItemData(i).actionCategory?.value == 'defensive');
if (featureType == 'action-int') return allItems.filter(i => i.type == 'action' && i.data.data.actionCategory?.value == 'interaction'); if (featureType == 'action-int') return allItems.filter(i => i.type == 'action' && this.getItemData(i).actionCategory?.value == 'interaction');
if (featureType == 'action-off') return allItems.filter(i => i.type == 'action' && i.data.data.actionCategory?.value == 'offensive'); if (featureType == 'action-off') return allItems.filter(i => i.type == 'action' && this.getItemData(i).actionCategory?.value == 'offensive');
if (featureType == 'strike') { //Strikes are not in the actor.items collection if (featureType == 'strike') { //Strikes are not in the actor.items collection
if (token.actor.type == 'hazard' || token.actor.type == 'familiar') { if (token.actor.type == 'hazard' || token.actor.type == 'familiar') {
return allItems.filter(i => i.type == 'melee' || i.type == 'ranged'); return allItems.filter(i => i.type == 'melee' || i.type == 'ranged');
} }
let actions = token.actor.data.data.actions?.filter(a=>a.type == 'strike'); let actions = this.getActorData(token).actions?.filter(a=>a.type == 'strike');
for (let a of actions) { for (let a of actions) {
a.img = a.imageUrl; a.img = a.imageUrl;
a.data = { a.data = {
@@ -326,7 +343,7 @@ export class pf2e{
} }
getFeatureUses(item) { getFeatureUses(item) {
if (item.data.type == 'class') return {available: item.actor.details.level.value}; if (item.data.type == 'class') return {available: item.parent.data.data.details.level.value};
else return; else return;
} }
@@ -336,7 +353,7 @@ export class pf2e{
buildSpellData(token) { buildSpellData(token) {
let spellData = [[],[],[],[],[],[],[],[],[],[],[],[]]; let spellData = [[],[],[],[],[],[],[],[],[],[],[],[]];
let spellcastingEntries = token.actor.spellcasting; let spellcastingEntries = token.actor.spellcasting;
const actorLevel = token.actor.data.data.details.level.value; const actorLevel = this.getActorData(token).details.level.value;
spellcastingEntries.forEach(spellCastingEntry => { spellcastingEntries.forEach(spellCastingEntry => {
let highestSpellSlot = Math.ceil(actorLevel/2); let highestSpellSlot = Math.ceil(actorLevel/2);
while (spellCastingEntry.data.data.slots?.[`slot${highestSpellSlot}`]?.max <= 0) highestSpellSlot--; while (spellCastingEntry.data.data.slots?.[`slot${highestSpellSlot}`]?.max <= 0) highestSpellSlot--;
@@ -404,15 +421,15 @@ export class pf2e{
if (level == undefined || level == 'any') level = item.level; if (level == undefined || level == 'any') level = item.level;
if (item.isCantrip == true) return; if (item.isCantrip == true) return;
if (item.isFocusSpell == true) return { if (item.isFocusSpell == true) return {
available: token.actor.data.data.resources.focus.value, available: this.getActorData(token).resources.focus.value,
maximum: token.actor.data.data.resources.focus.max maximum: this.getActorData(token).resources.focus.max
} }
const spellbook = this.findSpellcastingEntry(token.actor, item); const spellbook = this.findSpellcastingEntry(token.actor, item);
if (spellbook == undefined) return; if (spellbook == undefined) return;
if (spellbook.data.data.prepared.value == 'innate') { if (spellbook.data.data.prepared.value == 'innate') {
return { return {
available: item.data.data.location.uses.value, available: this.getItemData(item).location.uses.value,
maximum: item.data.data.location.uses.max maximum: this.getItemData(item).location.uses.max
} }
} }
if (spellbook.data.data.prepared.value == 'prepared') { if (spellbook.data.data.prepared.value == 'prepared') {
@@ -457,7 +474,7 @@ export class pf2e{
if (otherControls.rollOption == 'map2') variant = 2; if (otherControls.rollOption == 'map2') variant = 2;
if (item?.parent?.type == 'hazard' && item.type==='melee') return item.rollNPCAttack({}, variant+1); if (item?.parent?.type == 'hazard' && item.type==='melee') return item.rollNPCAttack({}, variant+1);
if (item.type==='strike') return item.variants[variant].roll({event}); if (item.type==='strike') return item.variants[variant].roll({event});
if (item?.parent?.type !== 'hazard' && (item.type==='weapon' || item.type==='melee')) return item.parent.actions.find(a=>a.name===item.name).variants[variant].roll({event}); if (item?.parent?.type !== 'hazard' && (item.type==='weapon' || item.type==='melee')) return item.parent.data.data.actions.find(a=>a.name===item.name).variants[variant].roll({event});
if (item.type === 'spell') { if (item.type === 'spell') {
const spellbook = this.findSpellcastingEntry(item.parent, item); const spellbook = this.findSpellcastingEntry(item.parent, item);
if (spellbook != undefined) { if (spellbook != undefined) {

View File

@@ -9,11 +9,19 @@ const proficiencyColors = {
export class starfinder{ export class starfinder{
constructor(){ constructor(){
console.log("Material Deck: Using system 'Starfinder'");
}
getActorData(token) {
return compatibleCore('10.0') ? token.actor.system : token.actor.data.data;
}
getItemData(item) {
return compatibleCore('10.0') ? item.system : item.data.data;
} }
getHP(token) { getHP(token) {
const hp = token.actor.data.data.attributes.hp; const hp = this.getActorData(token).attributes.hp;
return { return {
value: hp.value, value: hp.value,
max: hp.max max: hp.max
@@ -25,7 +33,7 @@ export class starfinder{
} }
getStamina(token) { getStamina(token) {
const stamina = token.actor.data.data.attributes.sp; const stamina = this.getActorData(token).attributes.sp;
return { return {
value: stamina.value, value: stamina.value,
max: stamina.max max: stamina.max
@@ -33,11 +41,11 @@ export class starfinder{
} }
getAC(token) { getAC(token) {
return token.actor.data.data.attributes.eac.value; return this.getActorData(token).attributes.eac.value;
} }
getKinAC(token) { getKinAC(token) {
return token.actor.data.data.attributes.kac.value; return this.getActorData(token).attributes.kac.value;
} }
getShieldHP(token) { getShieldHP(token) {
@@ -45,7 +53,7 @@ export class starfinder{
} }
getSpeed(token) { getSpeed(token) {
const movement = token.actor.data.data.attributes.speed; const movement = this.getActorData(token).attributes.speed;
let speed = ""; let speed = "";
if (movement.burrowing.value > 0) speed += `Burrow: ${movement.burrowing.value}Ft`; if (movement.burrowing.value > 0) speed += `Burrow: ${movement.burrowing.value}Ft`;
if (movement.climbing.value > 0) { if (movement.climbing.value > 0) {
@@ -68,7 +76,7 @@ export class starfinder{
} }
getInitiative(token) { getInitiative(token) {
let initiative = token.actor.data.data.attributes.init.total; let initiative = this.getActorData(token).attributes.init.total;
return (initiative >= 0) ? `+${initiative}` : initiative; return (initiative >= 0) ? `+${initiative}` : initiative;
} }
@@ -86,25 +94,25 @@ export class starfinder{
getAbility(token, ability) { getAbility(token, ability) {
if (ability == undefined) ability = 'str'; if (ability == undefined) ability = 'str';
return token.actor.data.data.abilities?.[ability].value; return this.getActorData(token).abilities?.[ability].value;
} }
getAbilityModifier(token, ability) { getAbilityModifier(token, ability) {
if (ability == undefined) ability = 'str'; if (ability == undefined) ability = 'str';
let val = token.actor.data.data.abilities?.[ability].mod; let val = this.getActorData(token).abilities?.[ability].mod;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
getAbilitySave(token, ability) { getAbilitySave(token, ability) {
if (ability == undefined) ability = 'fort'; if (ability == undefined) ability = 'fort';
else if (ability == 'ref') ability = 'reflex'; else if (ability == 'ref') ability = 'reflex';
let val = token.actor.data.data.attributes?.[ability].bonus; let val = this.getActorData(token).attributes?.[ability].bonus;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
getSkill(token, skill) { getSkill(token, skill) {
if (skill == undefined) skill = 'acr'; if (skill == undefined) skill = 'acr';
const val = token.actor.data.data.skills?.[skill].mod; const val = this.getActorData(token).skills?.[skill].mod;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
@@ -148,7 +156,10 @@ export class starfinder{
if (roll == 'ability') token.actor.rollAbilityTest(ability,options); if (roll == 'ability') token.actor.rollAbilityTest(ability,options);
else if (roll == 'save') token.actor.rollAbilitySave(save,options); else if (roll == 'save') token.actor.rollAbilitySave(save,options);
else if (roll == 'skill') token.actor.rollSkill(skill,options); else if (roll == 'skill') token.actor.rollSkill(skill,options);
else if (roll == 'initiative') token.actor.rollInitiative(options); else if (roll == 'initiative') {
options.rerollInitiative = true;
token.actor.rollInitiative(options);
}
else if (roll == 'deathSave') token.actor.rollDeathSave(options); else if (roll == 'deathSave') token.actor.rollDeathSave(options);
} }
@@ -164,7 +175,7 @@ export class starfinder{
} }
getItemUses(item) { getItemUses(item) {
return {available: item.data.data.quantity}; return {available: this.getItemData(item).quantity};
} }
/** /**
@@ -183,10 +194,10 @@ export class starfinder{
} }
getFeatureUses(item) { getFeatureUses(item) {
if (item.data.type == 'class') return {available: item.data.data.levels}; if (item.data.type == 'class') return {available: this.getItemData(item).levels};
else return { else return {
available: item.data.data.uses.value, available: this.getItemData(item).uses.value,
maximum: item.data.data.uses.max maximum: this.getItemData(item).uses.max
}; };
} }
@@ -197,16 +208,16 @@ export class starfinder{
if (level == undefined) level = 'any'; if (level == undefined) level = 'any';
const allItems = token.actor.items; const allItems = token.actor.items;
if (level == 'any') return allItems.filter(i => i.type == 'spell') if (level == 'any') return allItems.filter(i => i.type == 'spell')
else if (level == 'innate') return allItems.filter(i => i.type == 'spell' && i.data.data.preparation.mode == 'innate'); else if (level == 'innate') return allItems.filter(i => i.type == 'spell' && this.getItemData(i).preparation.mode == 'innate');
else return allItems.filter(i => i.type == 'spell' && i.data.data.preparation.mode == '' && i.data.data.level == level) else return allItems.filter(i => i.type == 'spell' && this.getItemData(i).preparation.mode == '' && this.getItemData(i).level == level)
} }
getSpellUses(token,level,item) { getSpellUses(token,level,item) {
if (level == undefined) level = 'any'; if (level == undefined) level = 'any';
if (item.data.data.level == 0) return; if (this.getItemData(item).level == 0) return;
const spellSlots = token.actor.data.data.spells; const spellSlots = this.getActorData(token).spells;
const allowedClasses = item.data.data.allowedClasses; const allowedClasses = this.getItemData(item).allowedClasses;
let uses = {available: 0, maximum: 0}; let uses = {available: 0, maximum: 0};
if (allowedClasses.myst && spellSlots?.[`spell${level}`].perClass?.mystic?.max > uses.maximum) if (allowedClasses.myst && spellSlots?.[`spell${level}`].perClass?.mystic?.max > uses.maximum)
@@ -229,13 +240,13 @@ export class starfinder{
* Ring Colors * Ring Colors
*/ */
getSkillRingColor(token, skill) { getSkillRingColor(token, skill) {
const profLevel = token.actor.data.data?.skills[skill]?.proficient; const profLevel = this.getActorData(token)?.skills[skill]?.proficient;
if (profLevel == undefined) return; if (profLevel == undefined) return;
return proficiencyColors?.[profLevel]; return proficiencyColors?.[profLevel];
} }
getSaveRingColor(token, save) { getSaveRingColor(token, save) {
const profLevel = token.actor.data.data?.abilities[save]?.proficient; const profLevel = this.getActorData(token)?.abilities[save]?.proficient;
if (profLevel == undefined) return; if (profLevel == undefined) return;
return proficiencyColors?.[profLevel]; return proficiencyColors?.[profLevel];
} }

325
src/systems/template.js Normal file
View File

@@ -0,0 +1,325 @@
/**
* This is a template for adding a new gaming system.
* Edit it to suit your system, for inspiration, look at other system files.
* Functions that are unused in your system can be left empty, but don't delete the function.
*
* Use the compatibleCore function to get the right value for the Foundry core:
* return compatibleCore('10.0') ? [value in v10+] : [value pre v10];
*
* Use the compatibleSystem function to get the right value for the gaming system version:
* return compatibleSystem('1.6.3') ? [value in v1.6.3+] : [value pre v1.6.3];
*/
import { compatibleCore, compatibleSystem } from "../misc";
/**
* Proficiency colors to show if a token is proficient in for example a skill
*/
const proficiencyColors = {
0: "#000000",
0.5: "#804A00",
1: "#C0C0C0",
2: "#FFD700"
}
//Rename 'template' to the name of your system
export class template{
constructor(){
console.log("Material Deck: Using system 'SystemName'");
}
getActorData(token) {
return compatibleCore('10.0') ? token.actor.system : token.actor.data.data;
}
getItemData(item) {
return compatibleCore('10.0') ? item.system : item.data.data;
}
/**
* Returns the HP of the token
* @param {Token} token Token instance to get the HP from
* @returns {object} Token hp value and max: {value: ##, max: ##}
*/
getHP(token) {
return;
}
/**
* Returns the temporary HP of the token
* @param {Token} token Token instance to get the temp HP from
* @returns {object} Token temp hp value and max: {value: ##, max: ##}
*/
getTempHP(token) {
return;
}
/**
* Returns the armor class of the token
* @param {Token} token Token instance to get the AC from
* @returns {number} AC value
*/
getAC(token) {
return;
}
/**
* Returns the shield HP of the token
* @param {Token} token Token instance to get the shield HP from
* @returns {number} Shield HP
*/
getShieldHP(token) {
return;
}
/**
* Returns a string with movement speeds of the token
* @param {Token} token Token instance to get the speed from
* @returns {string} Movement speed string
*/
getSpeed(token) {
return;
}
/**
* Returns the initiative of the token
* @param {Token} token Token instance to get the initiative from
* @returns {number} Initiative value
*/
getInitiative(token) {
return;
}
/**
* Toggles the initiative of the token
* @param {Token} token Token instance to toggle the initiative for
*/
toggleInitiative(token) {
}
/**
* Returns the passive perception of the token
* @param {Token} token Token instance to get the passive perception from
* @returns {number} Passive perception value
*/
getPassivePerception(token) {
return;
}
/**
* Returns the passive investigation of the token
* @param {Token} token Token instance to get the passive investigation from
* @returns {number} Passive investigation value
*/
getPassiveInvestigation(token) {
return;
}
/**
* Returns the ability value of the token
* @param {Token} token Token instance to get the ability value from
* @param {string} ability Ability to get the value from
* @returns {number} Ability value
*/
getAbility(token, ability) {
if (ability == undefined) ability = ''; //default ability
return;
}
/**
* Returns the ability modifier of the token
* @param {Token} token Token instance to get the ability modifier from
* @param {string} ability Ability to get the value from
* @returns {number} Ability modifier
*/
getAbilityModifier(token, ability) {
if (ability == undefined) ability = ''; //default ability
return;
}
/**
* Returns the ability save of the token
* @param {Token} token Token instance to get the ability save from
* @param {string} ability Ability to get the value from
* @returns {number} Ability save
*/
getAbilitySave(token, ability) {
if (ability == undefined) ability = ''; //default ability
return;
}
/**
* Returns the skill value of the token
* @param {Token} token Token instance to get the skill value from
* @param {string} skill Skill to get the value from
* @returns {number} Skill value
*/
getSkill(token, skill) {
if (skill == undefined) skill = '';
return;
}
/**
* Returns the proficiency value of the token
* @param {Token} token Token instance to get the proficiency from
* @returns {number} Proficiency value
*/
getProficiency(token) {
return;
}
/**
* Returns the icon location of a condition
* @param {string} condition Name of the condition
* @returns {string} Icon location
*/
getConditionIcon(condition) {
if (condition == undefined) condition = 'removeAll';
if (condition == 'removeAll') return;
else return;
}
/**
* Returns whether a condition is active on the token
* @param {Token} token Token instance to get the value from
* @param {string} condition Name of the condition
* @returns {boolean} Condition is active or not
*/
getConditionActive(token,condition) {
if (condition == undefined) condition = 'removeAll';
return;
}
/**
* Toggles a condition on a token
* @param {Token} token Token instance to get the value from
* @param {string} condition Name of the condition
*/
async toggleCondition(token,condition) {
if (condition == undefined) condition = 'removeAll';
}
/**
* Roll for a token
* @param {Token} token Token instance to roll for
* @param {string} roll Roll type (ability/save/skill/initiative/deathSave)
* @param {bbject} options Roll options
* @param {string} ability Name of the ability to roll
* @param {string} skill Name of the skill to roll
* @param {string} save Name of the save to roll
*/
roll(token,roll,options,ability,skill,save) {
if (roll == undefined) roll = 'ability';
if (ability == undefined) ability = ''; //default ability
if (skill == undefined) skill = ''; //default skill
if (save == undefined) save = ''; //default save
if (roll == 'ability')
else if (roll == 'save')
else if (roll == 'skill')
else if (roll == 'initiative')
else if (roll == 'deathSave')
}
/**
* Get array of items
* @param {Token} token Token instance to get the items from
* @param {string} itemType Item type
* @returns {array} Array of items
*/
getItems(token,itemType) {
if (itemType == undefined) itemType = 'any';
if (itemType == 'any') return ;
else return ;
}
/**
* Returns uses/quantity of an item
* @param {Item} item Item instance to get the uses/quantity from
* @returns {object} Uses/quantity available {available: ###, maximum: ###}
*/
getItemUses(item) {
return;
}
/**
* Returns the features of a token
* @param {Token} token Token instance to get the features from
* @param {string} featureType Feature types to return
* @returns {array} Array of features
*/
getFeatures(token,featureType) {
if (featureType == undefined) featureType = 'any';
if (featureType == 'any') return;
else return;
}
/**
* Returns uses/quantity of a feature
* @param {Item} item Item/feature instance to get the uses/quantity from
* @returns {object} Uses/quantity available {available: ###, maximum: ###}
*/
getFeatureUses(item) {
return {};
}
/**
* Returns the spells of a token
* @param {Token} token Token instance to get the spells from
* @param {string} level Spell level
* @returns {array} Array of spells
*/
getSpells(token,level) {
if (level == undefined) level = 'any';
if (level == 'any') return;
else return;
}
/**
* Returns the spell uses of a specific spell for a token
* @param {Token} token Token instance to get the spell uses from
* @param {string} level Spell level
* @param {Item} item Spell instance to get the uses from
* @returns {object} Spell uses left: {available: ###, maximum: ###}
*/
getSpellUses(token,level,item) {
return {
}
}
/**
* Roll an item
* @param {Token} item Item instance to roll
* @param {object} settings Settings of the action
* @param {object} rollOption Roll options
*/
rollItem(item, settings, rollOption) {
}
/**
* Returns a color to display proficiency for skills
* @param {Token} token Token instance to get the proficiency from
* @param {string} skill Skill name
* @returns {string} Hex color string from proficiencyColors array
*/
getSkillRingColor(token, skill) {
const profLevel = ;
if (profLevel == undefined) return;
return proficiencyColors?.[profLevel];
}
/**
* Returns a color to display proficiency for saves
* @param {Token} token Token instance to get the proficiency from
* @param {string} save Save name
* @returns {string} Hex color string from proficiencyColors array
*/
getSaveRingColor(token, save) {
const profLevel = ;
if (profLevel == undefined) return;
return proficiencyColors?.[profLevel];
}
}

View File

@@ -58,7 +58,7 @@ export class TokenHelper{
moveToken(token,dir){ moveToken(token,dir){
if (dir == undefined) dir = 'up'; if (dir == undefined) dir = 'up';
const gridSize = canvas.scene.data.grid; const gridSize = compatibleCore('10.0') ? canvas.scene.grid.size : canvas.scene.data.grid;
let x = token.x; let x = token.x;
let y = token.y; let y = token.y;
@@ -88,8 +88,10 @@ export class TokenHelper{
} }
if (game.user.isGM == false && game.paused) return; if (game.user.isGM == false && game.paused) return;
if (game.user.isGM == false && (token.can(game.user,"control") == false || token.checkCollision(token.getCenter(x, y)))) return; if (game.user.isGM == false && (token.can(game.user,"control") == false || token.checkCollision(token.getCenter(x, y)))) return;
if (compatibleCore("0.8.1")) token.document.update({x:x,y:y}); let coords = canvas.grid.getCenter(x,y);
else token.update({x:x,y:y}); coords[0] -= canvas.grid.size/2;
coords[1] -= canvas.grid.size/2;
token.document.update({x:coords[0],y:coords[1]});
}; };
rotateToken(token,move,value) { rotateToken(token,move,value) {
@@ -97,11 +99,10 @@ export class TokenHelper{
value = isNaN(parseInt(value)) ? 0 : parseInt(value); value = isNaN(parseInt(value)) ? 0 : parseInt(value);
let rotationVal; let rotationVal;
if (move == 'by') rotationVal = token.data.rotation + value; if (move == 'by') rotationVal = compatibleCore('10.0') ? token.document.rotation + value : token.data.rotation + value;
else rotationVal = value; else rotationVal = value;
if (compatibleCore("0.8.1")) token.document.update({rotation: rotationVal}); token.document.update({rotation: rotationVal});
else token.update({rotation: rotationVal});
} }
/////////////////////////////////////////////// ///////////////////////////////////////////////
@@ -127,11 +128,11 @@ export class TokenHelper{
//////////////////////////////////////////////////// ////////////////////////////////////////////////////
getTokenIcon(token) { getTokenIcon(token) {
return token.data.img; return compatibleCore('10.0') ? token.document.texture.src : token.data.img;
} }
getActorIcon(token) { getActorIcon(token) {
return token.actor.data.img; return compatibleCore('10.0') ? token.actor.img : token.actor.data.img;
} }
/*********************************************************************** /***********************************************************************
@@ -328,8 +329,8 @@ export class TokenHelper{
return this.system.getSpellUses(token,level,item); return this.system.getSpellUses(token,level,item);
} }
rollItem(item, settings) { rollItem(item, settings, rollOption) {
return this.system.rollItem(item, settings); return this.system.rollItem(item, settings, rollOption);
} }
/** /**

View File

@@ -2,20 +2,27 @@ import {compatibleCore} from "../misc.js";
export class wfrp4e { export class wfrp4e {
constructor(){ constructor(){
console.log("Material Deck: Using system 'Warhammer Fantasy Roleplaying 4e'");
}
getActorData(token) {
return compatibleCore('10.0') ? token.actor.system : token.actor.data.data;
}
getItemData(item) {
return compatibleCore('10.0') ? item.system : item.data.data;
} }
getFate(token) { getFate(token) {
return token.actor.data.data.status.fate.value return this.getActorData(token).status.fate.value
} }
getFortune(token) { getFortune(token) {
return token.actor.data.data.status.fortune.value return this.getActorData(token).status.fortune.value
} }
getWounds(token) { getWounds(token) {
const wounds = token.actor.data.data.status.wounds const wounds = this.getActorData(token).status.wounds
return { return {
value: wounds.value, value: wounds.value,
max: wounds.max max: wounds.max
@@ -24,7 +31,7 @@ export class wfrp4e {
} }
getCriticalWounds(token) { getCriticalWounds(token) {
const criticalWounds = token.actor.data.data.status.criticalWounds const criticalWounds = this.getActorData(token).status.criticalWounds
return { return {
value: criticalWounds.value, value: criticalWounds.value,
max: criticalWounds.max max: criticalWounds.max
@@ -32,19 +39,19 @@ export class wfrp4e {
} }
getCorruption(token) { getCorruption(token) {
return token.actor.data.data.status.corruption.value return this.getActorData(token).status.corruption.value
} }
getAdvantage(token) { getAdvantage(token) {
return token.actor.data.data.status.advantage.value return this.getActorData(token).status.advantage.value
} }
getResolve(token) { getResolve(token) {
return token.actor.data.data.status.resolve.value return this.getActorData(token).status.resolve.value
} }
getResilience(token) { getResilience(token) {
return token.actor.data.data.status.resilience.value return this.getActorData(token).status.resilience.value
} }
getAbility(token, abilityName) { getAbility(token, abilityName) {
@@ -53,7 +60,7 @@ export class wfrp4e {
getCharacteristics(token, characteristicName) { getCharacteristics(token, characteristicName) {
if (characteristicName == undefined ) characteristicName = `AG`; if (characteristicName == undefined ) characteristicName = `AG`;
const characteristic = token.actor.data.data.characteristics[characteristicName.toLowerCase()] const characteristic = this.getActorData(token).characteristics[characteristicName.toLowerCase()]
const val = characteristic.value; const val = characteristic.value;
return (val >= 0) ? `+${val}` : val; return (val >= 0) ? `+${val}` : val;
} }
@@ -74,7 +81,7 @@ export class wfrp4e {
} }
getFeatureUses(item) { getFeatureUses(item) {
return {available: `+${item.data.data.total.value}`}; return {available: `+${this.getItemData(item).total.value}`};
} }
getHP(token) { getHP(token) {
@@ -86,7 +93,7 @@ export class wfrp4e {
} }
getSpeed(token) { getSpeed(token) {
return token.actor.data.data.details.move.value; return this.getActorData(token).details.move.value;
} }
@@ -125,7 +132,7 @@ export class wfrp4e {
getItemUses(item) { getItemUses(item) {
if ( item.type == 'ammunition') { if ( item.type == 'ammunition') {
return {available: item.data.data.quantity.value}; return {available: this.getItemData(item).quantity.value};
} }
else { else {
return; return;

View File

@@ -1,41 +1,18 @@
<form autocomplete="off" onsubmit="event.preventDefault()"> <form autocomplete="off" onsubmit="event.preventDefault()">
<style>
.columnLabel {
max-width:30%;
min-width:30%;
text-align: left;
}
.columnId {
max-width:25%;
min-width:25%;
text-align: left;
text-overflow: hidden;
}
.columnCB {
width:10%;
text-align: left;
}
</style>
<table style="width:100%; min-width:400px"> <table style="width:100%; min-width:400px">
<tr> <tr>
<th class='columnLabel'>{{localize "MaterialDeck.Name"}}</th> <th class='materialDeck_devConf_columnLabel'>{{localize "MaterialDeck.Name"}}</th>
<th class='columnLabel'>{{localize "MaterialDeck.Type"}}</th> <th class='materialDeck_devConf_columnLabel'>{{localize "MaterialDeck.Type"}}</th>
<th class='columnId'>{{localize "MaterialDeck.Id"}}</th> <th class='materialDeck_devConf_columnId'>{{localize "MaterialDeck.Id"}}</th>
<th class='columnCB'>{{localize "MaterialDeck.Perm.ENABLE.ENABLE.label"}}</th> <th class='materialDeck_devConf_columnCB'>{{localize "MaterialDeck.Perm.ENABLE.ENABLE.label"}}</th>
</tr> </tr>
{{#each devices as |d|}} {{#each devices as |d|}}
<tr> <tr>
<td class='columnLabel'>{{d.name}}</td> <td class='materialDeck_devConf_columnLabel'>{{d.name}}</td>
<td class='columnLabel'>{{d.type}}</td> <td class='materialDeck_devConf_columnLabel'>{{d.type}}</td>
<td class='columnId'><input type="text" value={{d.id}} disabled></td> <td class='materialDeck_devConf_columnId'><input type="text" value={{d.id}} disabled></td>
<td class='columnCB'><input type="checkbox" name="enable" id={{d.id}} {{checked d.en}}></td> <td class='materialDeck_devConf_columnCB'><input type="checkbox" name="enable" id="materialDeck_devConf_{{d.id}}" {{checked d.en}}></td>
</tr> </tr>
{{/each}} {{/each}}
</table> </table>
</form> </form>

View File

@@ -1,56 +1,36 @@
<form autocomplete="off" onsubmit="event.preventDefault()"> <form autocomplete="off" onsubmit="event.preventDefault()">
<style>
.columnLabel {
width:25%;
text-align: left;
}
.columnVersion {
width:15%;
text-align: left;
}
.columnOS {
width:15%;
}
.columnButton {
width:15%;
}
.btn {
width:100%;
}
</style>
<h2>{{localize "MaterialDeck.DownloadUtility.Plugin"}}</h2> <h2>{{localize "MaterialDeck.DownloadUtility.Plugin"}}</h2>
<table style="width:100%; min-width:400px"> <table style="width:100%; min-width:400px">
<tr> <tr>
<th class='columnLabel'></th> <th class='materialDeck_dlUtil_columnLabel'></th>
<th class='columnVersion'>{{localize "MaterialDeck.DownloadUtility.Current"}}</th> <th class='materialDeck_dlUtil_columnVersion'>{{localize "MaterialDeck.DownloadUtility.Current"}}</th>
<th class='columnVersion'>{{localize "MaterialDeck.DownloadUtility.Minimum"}}</th> <th class='materialDeck_dlUtil_columnVersion'>{{localize "MaterialDeck.DownloadUtility.Minimum"}}</th>
<th class='columnVersion'>{{localize "MaterialDeck.DownloadUtility.Latest"}}</th> <th class='materialDeck_dlUtil_columnVersion'>{{localize "MaterialDeck.DownloadUtility.Latest"}}</th>
<th class='columnOS'>{{localize "MaterialDeck.DownloadUtility.OS"}}</th> <th class='materialDeck_dlUtil_columnOS'>{{localize "MaterialDeck.DownloadUtility.OS"}}</th>
<th class='columnButton'>{{localize "MaterialDeck.DownloadUtility.Download"}}</th> <th class='materialDeck_dlUtil_columnButton'>{{localize "MaterialDeck.DownloadUtility.Download"}}</th>
</tr> </tr>
<tr> <tr>
<td class='columnLabel'>{{localize "MaterialDeck.DownloadUtility.SDplugin"}}</td> <td class='materialDeck_dlUtil_columnLabel'>{{localize "MaterialDeck.DownloadUtility.SDplugin"}}</td>
<td class='columnVersion'>{{localSdVersion}}</td> <td class='materialDeck_dlUtil_columnVersion'>{{localSdVersion}}</td>
<td class='columnVersion'>{{minimumSdVersion}}</td> <td class='materialDeck_dlUtil_columnVersion'>{{minimumSdVersion}}</td>
<td class='columnVersion' id='masterSdVersion'>{{masterSdVersion}}</td> <td class='materialDeck_dlUtil_columnVersion' id='materialDeck_dlUtil_masterSdVersion'>{{masterSdVersion}}</td>
<td class='columnOS'></td> <td class='materialDeck_dlUtil_columnOS'></td>
<td class='columnButton'> <td class='materialDeck_dlUtil_columnButton'>
<button type="button" class='btn' id='downloadSd' {{#if sdDlDisable}}disabled{{/if}}> <button type="button" class='materialDeck_dlUtil_button' id='materialDeck_dlUtil_downloadSd' {{#if sdDlDisable}}disabled{{/if}}>
<i class="fas fa-download"></i> <i class="fas fa-download"></i>
</button> </button>
</td> </td>
</tr> </tr>
<tr> <tr>
<td class='columnLabel'>{{localize "MaterialDeck.DownloadUtility.MSserver"}}</td> <td class='materialDeck_dlUtil_columnLabel'>{{localize "MaterialDeck.DownloadUtility.MSserver"}}</td>
<td class='columnVersion'>{{localMsVersion}}</td> <td class='materialDeck_dlUtil_columnVersion'>{{localMsVersion}}</td>
<td class='columnVersion'>{{minimumMsVersion}}</td> <td class='materialDeck_dlUtil_columnVersion'>{{minimumMsVersion}}</td>
<td class='columnVersion' id='masterMsVersion'>{{masterMsVersion}}</td> <td class='materialDeck_dlUtil_columnVersion' id='materialDeck_dlUtil_masterMsVersion'>{{masterMsVersion}}</td>
<td class='columnOS'> <td class='materialDeck_dlUtil_columnOS'>
<select id="os" default="" {{#if msDlDisable}}disabled{{/if}}> <select id="materialDeck_dlUtil_os" default="" {{#if msDlDisable}}disabled{{/if}}>
<option value="win32-x64">{{localize "MaterialDeck.DownloadUtility.Windows"}}</option> <option value="win32-x64">{{localize "MaterialDeck.DownloadUtility.Windows"}}</option>
<option value="macos-x64">{{localize "MaterialDeck.DownloadUtility.MacosIntel"}}</option> <option value="macos-x64">{{localize "MaterialDeck.DownloadUtility.MacosIntel"}}</option>
<option value="macos-arm64">{{localize "MaterialDeck.DownloadUtility.MacosM1"}}</option> <option value="macos-arm64">{{localize "MaterialDeck.DownloadUtility.MacosM1"}}</option>
@@ -58,8 +38,8 @@
<option value="source">{{localize "MaterialDeck.DownloadUtility.Source"}}</option> <option value="source">{{localize "MaterialDeck.DownloadUtility.Source"}}</option>
</select> </select>
</td> </td>
<td class='columnButton'> <td class='materialDeck_dlUtil_columnButton'>
<button type="button" class='btn' id='downloadMs' {{#if msDlDisable}}disabled{{/if}}> <button type="button" class='materialDeck_dlUtil_button' id='materialDeck_dlUtil_downloadMs' {{#if msDlDisable}}disabled{{/if}}>
<i class="fas fa-download"></i> <i class="fas fa-download"></i>
</button> </button>
</td> </td>
@@ -71,14 +51,14 @@
<table style="width:100%; min-width:400px"> <table style="width:100%; min-width:400px">
<tr> <tr>
<th style='text-align: left;'>{{localize "MaterialDeck.DownloadUtility.Name"}}</th> <th style='text-align: left;'>{{localize "MaterialDeck.DownloadUtility.Name"}}</th>
<th class='columnButton'>{{localize "MaterialDeck.DownloadUtility.Download"}}</th> <th class='materialDeck_dlUtil_columnButton'>{{localize "MaterialDeck.DownloadUtility.Download"}}</th>
</tr> </tr>
<div id='profileContents'> <div id='profileContents'>
{{#each profiles as |p|}} {{#each profiles as |p|}}
<tr> <tr>
<td>{{p.label}}</td> <td>{{p.label}}</td>
<td class='columnButton'> <td class='materialDeck_dlUtil_columnButton'>
<button type="button" class='btn' id='dlProfile-{{p.id}}' name='downloadProfile' {{#if ../profileDlDisable}}disabled{{/if}}> <button type="button" class='materialDeck_dlUtil_button' id='materialDeck_dlUtil_dlProfile-{{p.id}}' name='downloadProfile' {{#if ../profileDlDisable}}disabled{{/if}}>
<i class="fas fa-download"></i> <i class="fas fa-download"></i>
</button> </button>
</td> </td>
@@ -87,7 +67,7 @@
</div> </div>
</table> </table>
<button type="button" id='refresh'> <button type="button" id='materialDeck_dlUtil_refresh'>
<i class="fas fa-redo"></i> <i class="fas fa-redo"></i>
{{localize "MaterialDeck.DownloadUtility.Refresh"}} {{localize "MaterialDeck.DownloadUtility.Refresh"}}
</button> </button>

View File

@@ -3,7 +3,7 @@
<div class="form-group"> <div class="form-group">
<label>{{localize "MaterialDeck.Filename"}}: </label> <label>{{localize "MaterialDeck.Filename"}}: </label>
<input type="text" name="name" value="{{name}}" id="name" style="width:100%;" > <input type="text" name="name" value="{{name}}" style="width:100%;" >
</div> </div>
<button type="submit" name="submit"> <button type="submit" name="submit">

View File

@@ -1,8 +1,21 @@
<form autocomplete="off" onsubmit="event.preventDefault()"> <form autocomplete="off" onsubmit="event.preventDefault()">
<script>
for (let element of document.getElementsByClassName("materialDeck_helpMenu_expandable")) {
element.addEventListener("click",(event) => {
let thisElement = event.target;
if (event.target.className == "materialDeck_helpMenu_expandableIcon") thisElement = event.target.parentElement;
let nextElement = thisElement.nextElementSibling;
const collapse = nextElement.className == "materialDeck_helpMenu_collapsed" ? false : true;
nextElement.className = collapse ? "materialDeck_helpMenu_collapsed" : "";
thisElement.children[0].src = collapse ? "modules/MaterialDeck/img/right.png" : "modules/MaterialDeck/img/down.png";
})
}
</script>
<div style="width:1200px"> <div style="width:1200px">
<h1>Introduction</h1> <h1 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/down.png" class="materialDeck_helpMenu_expandableIcon" style="width:20px">Introduction</h1>
<div class="">
Material Deck is a Foundry VTT module that allows you to control certain Foundry functions using an Elgato Stream Deck. Material Deck is a Foundry VTT module that allows you to control certain Foundry functions using an Elgato Stream Deck.
A Stream Deck is a device that has physical buttons with displays behind them. Material Deck uses this to, for example, A Stream Deck is a device that has physical buttons with displays behind them. Material Deck uses this to, for example,
control playlists, execute macros, display and control the combat tracker.<br><br> control playlists, execute macros, display and control the combat tracker.<br><br>
@@ -12,18 +25,25 @@
<br> <br>
Material Deck is a very large module with tons of features and ways of customizing your experience. This menu will only cover the basics to get you started, Material Deck is a very large module with tons of features and ways of customizing your experience. This menu will only cover the basics to get you started,
the full documentation can be found on <a href="https://github.com/CDeenen/MaterialDeck/wiki">Github</a>. Please also check the <a href="https://github.com/CDeenen/MaterialDeck/wiki/FAQ">FAQ</a> which answers some common questions, including some basic troubleshooting.<br> the full documentation can be found on <a href="https://github.com/CDeenen/MaterialDeck/wiki">Github</a>. Please also check the <a href="https://github.com/CDeenen/MaterialDeck/wiki/FAQ">FAQ</a> which answers some common questions, including some basic troubleshooting.<br>
</div>
<h1>Latest Releases</h1> <h1 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:20px">Latest Releases</h1>
<div class="materialDeck_helpMenu_collapsed">
<a href="https://github.com/CDeenen/MaterialDeck/releases">Module</a><br> <a href="https://github.com/CDeenen/MaterialDeck/releases">Module</a><br>
<a href="https://github.com/CDeenen/MaterialDeck_SD/releases">Stream Deck</a><br> <a href="https://github.com/CDeenen/MaterialDeck_SD/releases">Stream Deck</a><br>
<a href="https://github.com/CDeenen/MaterialServer/releases">Server</a><br> <a href="https://github.com/CDeenen/MaterialServer/releases">Server</a><br>
You can use the download utility in the module settings to download the Stream Deck plugin, Stream Deck profiles and Material Server. You can use the download utility in the module settings to download the Stream Deck plugin, Stream Deck profiles and Material Server.
</div>
<h1>Getting Started</h1> <h1 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:20px">Getting Started</h1>
Besides installing this module, you also need to install and run some other things. <div class="materialDeck_helpMenu_collapsed">
Besides installing this module, you also need to install and run some other things.<br>
After setting up the module settings I suggest you just play around with one of the profiles to see that happens when you press buttons and do things in Foundry.
Most things should be pretty self explanatory. After that you could look into customizing your experience, as you can read about below.
<h2>Installing the Stream Deck Software and Plugin</h2> <h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Installing the Stream Deck Software and Plugin</h2>
YOu have to download and install the <a href="https://www.elgato.com/en/gaming/downloads">Stream Deck software</a>. <div class="materialDeck_helpMenu_collapsed">
You have to download and install the <a href="https://www.elgato.com/en/gaming/downloads">Stream Deck software</a>.
You then need to install the plugin. There is a delay between when the plugin get's updated and the update being pushed in the store. You then need to install the plugin. There is a delay between when the plugin get's updated and the update being pushed in the store.
If you try to install the plugin right after an update, you might not have the latest version. Manual installation is better in that case. If you try to install the plugin right after an update, you might not have the latest version. Manual installation is better in that case.
<br> <br>
@@ -41,29 +61,33 @@
<li>Double-click the file, this should open the Stream Deck software</li> <li>Double-click the file, this should open the Stream Deck software</li>
<li>Press 'Install' in the pop-up</li> <li>Press 'Install' in the pop-up</li>
</ol> </ol>
</div>
<h2>Installing a Stream Deck Profile (optional)</h2> <h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Installing a Stream Deck Profile (optional)</h2>
<div class="materialDeck_helpMenu_collapsed">
You can create your own profile, but it is recommended to start with one of the pre-made profiles. Currently, there is a profile for the normal and XL Stream Deck variants. You can create your own profile, but it is recommended to start with one of the pre-made profiles. Currently, there is a profile for the normal and XL Stream Deck variants.
<ol> <ol>
<li>Download the latest plugin file using the download utility in the module settings, or download one (ending with .streamDeckProfile) from <a href="https://github.com/CDeenen/MaterialDeck_SD/releases">here</a></li> <li>Download the latest plugin file using the download utility in the module settings, or download one (ending with .streamDeckProfile) from <a href="https://github.com/CDeenen/MaterialDeck_SD/releases">here</a></li>
<li>Double-click the file, this should load the profile into the Stream Deck software</li> <li>Double-click the file, this should load the profile into the Stream Deck software</li>
</ol> </ol>
</div>
<h2>Downloading and Starting Material Server</h2> <h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Downloading and Starting Material Server</h2>
<div class="materialDeck_helpMenu_collapsed">
Material Server acts as a bridge application, bridging the communication between the Stream Deck and Material Deck. Material Server acts as a bridge application, bridging the communication between the Stream Deck and Material Deck.
<ol> <ol>
<li>Download the latest version for your operating system <a href="https://github.com/CDeenen/MaterialServer/releases">here</a></li> <li>Download the latest version for your operating system <a href="https://github.com/CDeenen/MaterialServer/releases">here</a> or through the download utility</li>
<li>Download and install the <a href="https://github.com/CDeenen/MaterialServer/blob/master/README.md#prerequisites">prerequisites</a></li>
<li>Extract the archive</li> <li>Extract the archive</li>
<li>Double-click the file to start the server</li> <li>Run 'materialserver.exe' (Windows) or 'materialserver' (MacOS and Linux)</li>
</ol> </ol>
<b>You need to always have Material Server running when you want to use Material Deck</b> <b>You need to always have Material Server running when you want to use Material Deck</b><br>
<br> <br>
<br> <a href="https://github.com/CDeenen/MaterialServer/wiki">Material Server documentation</a>
After setting up the module settings I suggest you just play around with one of the profiles to see that happens when you press buttons and do things in Foundry. </div>
Most things should be pretty self explanatory. After that you could look into customizing your experience, as you can read about below.
<h1>Module Setup</h1> </div>
<h1 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:20px">Module Setup</h1>
<div class="materialDeck_helpMenu_collapsed">
<img src="modules/MaterialDeck/wiki/img/ModuleSettings.png" align="right" HSPACE="5" width="450"> <img src="modules/MaterialDeck/wiki/img/ModuleSettings.png" align="right" HSPACE="5" width="450">
There are four buttons at the top: There are four buttons at the top:
<ul> <ul>
@@ -92,7 +116,8 @@
<BR CLEAR="right" /> <BR CLEAR="right" />
<h2>User Permission Configuration</h2> <h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">User Permission Configuration</h2>
<div class="materialDeck_helpMenu_collapsed">
<img src="modules/MaterialDeck/wiki/img/PermissionConfig.png" align="right" HSPACE="5" width="450"> <img src="modules/MaterialDeck/wiki/img/PermissionConfig.png" align="right" HSPACE="5" width="450">
Using the 'User Permission Configuration' screen, the GM can configure what Material Deck functions users have access to.<br> Using the 'User Permission Configuration' screen, the GM can configure what Material Deck functions users have access to.<br>
Each action has various settings, and these settings can be set for each user role.<br> Each action has various settings, and these settings can be set for each user role.<br>
@@ -101,8 +126,10 @@
<br> <br>
<BR CLEAR="right" /> <BR CLEAR="right" />
</div>
<h2>Download Utility</h2> <h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Download Utility</h2>
<div class="materialDeck_helpMenu_collapsed">
<img src="modules/MaterialDeck/wiki/img/DownloadUtility.png" align="right" HSPACE="5" width="350"> <img src="modules/MaterialDeck/wiki/img/DownloadUtility.png" align="right" HSPACE="5" width="350">
The download utility allows you to easily check the current version of the Stream Deck plugin and Material Server, and gives you the option to download the latest version.<br> The download utility allows you to easily check the current version of the Stream Deck plugin and Material Server, and gives you the option to download the latest version.<br>
Please note that the current version of Material Server is at the moment not supported.<br> Please note that the current version of Material Server is at the moment not supported.<br>
@@ -112,8 +139,10 @@
The refresh button at the bottom refreshes the page in case there was a connection issue. The refresh button at the bottom refreshes the page in case there was a connection issue.
<BR CLEAR="right" /> <BR CLEAR="right" />
</div>
<h2>Playlist Configuration</h2> <h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Playlist Configuration</h2>
<div class="materialDeck_helpMenu_collapsed">
<img src="modules/MaterialDeck/wiki/img/PlaylistConfig.png" align="right" HSPACE="5" width="350"> <img src="modules/MaterialDeck/wiki/img/PlaylistConfig.png" align="right" HSPACE="5" width="350">
The playlist configuration screen configures the playlists that you control using the <a href="https://github.com/CDeenen/MaterialDeck/wiki/Playlist-Action">Playlist action</a>.<br> The playlist configuration screen configures the playlists that you control using the <a href="https://github.com/CDeenen/MaterialDeck/wiki/Playlist-Action">Playlist action</a>.<br>
There are 2 sections: 'Settings', and 'Playlists'. There are 2 sections: 'Settings', and 'Playlists'.
@@ -141,8 +170,10 @@
For each playlist you can set the play mode, which overrides the default play mode for that specific playlist.<br> For each playlist you can set the play mode, which overrides the default play mode for that specific playlist.<br>
<br> <br>
<b>Note:</b> While you can assign the same playlist to multiple playlists in this configuration screen, only the play method of the first instance will be applied. <b>Note:</b> While you can assign the same playlist to multiple playlists in this configuration screen, only the play method of the first instance will be applied.
</div>
<h2>Macro Configuration</h2> <h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Macro Configuration</h2>
<div class="materialDeck_helpMenu_collapsed">
The Macro Configuration screen is to configure the macroboard for the <a href="https://github.com/CDeenen/MaterialDeck/wiki/Macro-Action">Macro action</a>.<br> The Macro Configuration screen is to configure the macroboard for the <a href="https://github.com/CDeenen/MaterialDeck/wiki/Macro-Action">Macro action</a>.<br>
<br> <br>
The screen is divided into 32 boxes, each labeled 'Macro #', where each represents a single macro and its settings. This screen will be refered to as a page. The screen is divided into 32 boxes, each labeled 'Macro #', where each represents a single macro and its settings. This screen will be refered to as a page.
@@ -171,8 +202,10 @@
or you might run into issues. or you might run into issues.
<img src="modules/MaterialDeck/wiki/img/MacroConfig.png" align="center" HSPACE="5" width="100%"> <img src="modules/MaterialDeck/wiki/img/MacroConfig.png" align="center" HSPACE="5" width="100%">
</div>
<h2>Soundboard Configuration</h2> <h2 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:15px">Soundboard Configuration</h2>
<div class="materialDeck_helpMenu_collapsed">
The Soundboard Configuration screen is used to configure the soundboard for the <a href="https://github.com/CDeenen/MaterialDeck/wiki/Soundboard-Action">Soundboard action</a>.<br> The Soundboard Configuration screen is used to configure the soundboard for the <a href="https://github.com/CDeenen/MaterialDeck/wiki/Soundboard-Action">Soundboard action</a>.<br>
<br> <br>
Similar to the Macro Configuration screen, the screen is divided into boxes, each labeled 'Sound #', where each represents a single sound and its settings. This screen will be refered to as a page. Similar to the Macro Configuration screen, the screen is divided into boxes, each labeled 'Sound #', where each represents a single sound and its settings. This screen will be refered to as a page.
@@ -215,8 +248,11 @@
or you might run into issues. or you might run into issues.
<img src="modules/MaterialDeck/wiki/img/SoundboardConfig.png" align="center" HSPACE="5" width="100%"> <img src="modules/MaterialDeck/wiki/img/SoundboardConfig.png" align="center" HSPACE="5" width="100%">
</div>
</div>
<h1>Customization</h1> <h1 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:20px">Customization</h1>
<div class="materialDeck_helpMenu_collapsed">
Material Deck is extremely flexible, but most of this flexibility must be performed in the Stream Deck software.<br> Material Deck is extremely flexible, but most of this flexibility must be performed in the Stream Deck software.<br>
Some basic instructions on using the software can be found <a href="https://github.com/CDeenen/MaterialDeck/wiki/Getting-Started#basic-stream-deck-setup-instructions">here</a>.<br> Some basic instructions on using the software can be found <a href="https://github.com/CDeenen/MaterialDeck/wiki/Getting-Started#basic-stream-deck-setup-instructions">here</a>.<br>
<br> <br>
@@ -237,15 +273,18 @@
<li><a href="https://github.com/CDeenen/MaterialDeck/wiki/Soundboard-Action">Soundboard Action</a></li> <li><a href="https://github.com/CDeenen/MaterialDeck/wiki/Soundboard-Action">Soundboard Action</a></li>
<li><a href="https://github.com/CDeenen/MaterialDeck/wiki/Token-Action">Token Action</a></li> <li><a href="https://github.com/CDeenen/MaterialDeck/wiki/Token-Action">Token Action</a></li>
</ul> </ul>
</div>
<h1>Feedback</h1>
If you have any suggestions or bugs to report, feel free to create an issue, contact me on Discord (Cris#6864), or send me an email: cdeenen@outlook.com.
<h1>Credits</h1> <h1 class="materialDeck_helpMenu_expandable"><img src="modules/MaterialDeck/img/right.png" class="materialDeck_helpMenu_expandableIcon" style="width:20px">Feedback & Credits</h1>
<div class="materialDeck_helpMenu_collapsed">
If you have any suggestions or bugs to report, feel free to create an issue, contact me on Discord (Cris#6864), or send me an email: cdeenen@outlook.com.<br>
<br>
<b>Author:</b> Cristian Deenen (Cris#6864 on Discord)<br> <b>Author:</b> Cristian Deenen (Cris#6864 on Discord)<br>
<br> <br>
Special thanks to Asmodeus#7588 who made this module possible by generously donating a Stream Deck XL Special thanks to Asmodeus#7588 who made this module possible by generously donating a Stream Deck XL
<br> <br>
Please consider supporting me on <a href="https://www.patreon.com/materialfoundry">Patreon</a>, and feel free to join the Material Foundry <a href="https://discord.gg/3hd4G6TkmA">Discord</a> server. Please consider supporting me on <a href="https://www.patreon.com/materialfoundry">Patreon</a>, and feel free to join the Material Foundry <a href="https://discord.gg/3hd4G6TkmA">Discord</a> server.
</div> </div>
</div>
</form> </form>

View File

@@ -4,7 +4,7 @@
<div class="form-group upload-file"> <div class="form-group upload-file">
<label><i class="fas fa-upload fa-fw"></i> {{ localize "FILES.Upload" }}</label> <label><i class="fas fa-upload fa-fw"></i> {{ localize "FILES.Upload" }}</label>
<input type="file" name="upload" id="uploadJson"> <input type="file" name="upload" id="materialDeck_import_uploadJson">
</div> </div>
<button type="submit" name="submit"> <button type="submit" name="submit">

View File

@@ -1,25 +1,12 @@
<form autocomplete="off" onsubmit="event.preventDefault()"> <form autocomplete="off" onsubmit="event.preventDefault()">
<style> <div class="materialDeck_macroConfig_navigationDiv">
.boxed { <button type="button" class="materialDeck_macroConfig_navigation" name="navPrev" {{prevDisabled}}>
border: 1px solid black ;
border-radius: 5px ;
max-width: 166px;
height: {{height}}px;
}
.navigation {
flex:1;
max-width: 8%;
}
</style>
<div class="navigationDiv" style="width:100%; display:flex; flex-direction:row;">
<button type="button" class="navigation" id="navPrev" {{prevDisabled}}>
<i class="fas fa-arrow-left"></i> <i class="fas fa-arrow-left"></i>
</button> </button>
<p style="width:84%; text-align:center; padding: 0px 0; font-size: 20px"><b> <p class="materialDeck_macroConfig_p"><b>
{{localize "MaterialDeck.Perm.MACRO.label"}}: {{macroRange}} {{localize "MaterialDeck.Of"}} {{totalMacros}} {{localize "MaterialDeck.Perm.MACRO.label"}}: {{macroRange}} {{localize "MaterialDeck.Of"}} {{totalMacros}}
</b></p> </b></p>
<button type="button" class="navigation" id="navNext"> <button type="button" class="materialDeck_macroConfig_navigation" name="navNext">
<i class="fas fa-arrow-right"></i> <i class="fas fa-arrow-right"></i>
</button> </button>
</div> </div>
@@ -28,12 +15,12 @@
{{#each macroData}} {{#each macroData}}
<div class="form-group" style="width:100%"> <div class="form-group" style="width:100%">
{{#each this.dataThis}} {{#each this.dataThis}}
<div class="boxed" style="padding: 5px; margin:2px; width:10%"> <div class="materialDeck_macroConfig_boxed">
<div style="text-align:center;"> <div style="text-align:center;">
{{localize "MaterialDeck.Macro"}} {{this.iteration}} {{localize "MaterialDeck.Macro"}} {{this.iteration}}
</div> </div>
<div> <div>
<select name="macros" class="macros-select" id="macros{{this.iteration}}" default="" style="width:100%;"> <select name="macros" class="macros-select" id="materialDeck_macroConfig_macros{{this.iteration}}" default="" style="width:100%;">
{{#select this.macro}} {{#select this.macro}}
<option value="">{{localize "MaterialDeck.None"}}</option> <option value="">{{localize "MaterialDeck.None"}}</option>
{{#each ../../macros}} {{#each ../../macros}}
@@ -44,30 +31,30 @@
</div> </div>
{{#if ../../furnace}} {{#if ../../furnace}}
<label>{{localize "MaterialDeck.FurnaceArgs"}}</label> <label>{{localize "MaterialDeck.FurnaceArgs"}}</label>
<input type="text" name="args" id="args{{this.iteration}}" value="{{this.args}}"> <input type="text" name="args" id="materialDeck_macroConfig_args{{this.iteration}}" value="{{this.args}}">
{{/if}} {{/if}}
<div class="flex-container" style="display:flex;flex-direction:row;padding-top:10px"> <div class="flex-container materialDeck_macroConfig_background">
<label style="flex:1">{{localize "MaterialDeck.Background"}}</label> <label style="flex:1">{{localize "MaterialDeck.Background"}}</label>
<input style="flex:1" type="color" name="colorPicker" id="colorpicker{{this.iteration}}" data-dtype="String" value="{{this.color}}"> <input style="flex:1" type="color" name="colorPicker" id="materialDeck_macroConfig_colorpicker{{this.iteration}}" data-dtype="String" value="{{this.color}}">
</div> </div>
</div> </div>
{{/each}} {{/each}}
</div> </div>
{{/each}} {{/each}}
<hr> <hr>
<div class="navigationDiv" style="width:100%; display:flex; flex-direction:row;"> <div class="materialDeck_macroConfig_navigationDiv">
<button type="button" class="navigation" id="clearPage"> <button type="button" class="materialDeck_macroConfig_navigation" name="clearPage">
<i></i>{{localize "MaterialDeck.ClearPage"}} <i></i>{{localize "MaterialDeck.ClearPage"}}
</button> </button>
<button type="button" class="navigation" id="clearAll"> <button type="button" class="materialDeck_macroConfig_navigation" name="clearAll">
<i></i>{{localize "MaterialDeck.ClearAll"}} <i></i>{{localize "MaterialDeck.ClearAll"}}
</button> </button>
<p style="width:68%;"></p> <p style="width:68%;"></p>
<button type="button" class="navigation" id="import"> <button type="button" class="materialDeck_macroConfig_navigation" name="import">
<i></i>{{localize "MaterialDeck.Import"}} <i></i>{{localize "MaterialDeck.Import"}}
</button> </button>
<button type="button" class="navigation" id="export"> <button type="button" class="materialDeck_macroConfig_navigation" name="export">
<i></i>{{localize "MaterialDeck.Export"}} <i></i>{{localize "MaterialDeck.Export"}}
</button> </button>
</div> </div>

View File

@@ -4,7 +4,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{{localize "MaterialDeck.PL.Mode"}}</label> <label>{{localize "MaterialDeck.PL.Mode"}}</label>
<select name="playMode" class="playMode" default=""> <select name="playMode" class="materialDeck_plConfig_select" default="">
{{#select playMode}} {{#select playMode}}
<option value="0">{{localize "MaterialDeck.PL.Unrestricted"}}</option> <option value="0">{{localize "MaterialDeck.PL.Unrestricted"}}</option>
<option value="1">{{localize "MaterialDeck.PL.OneTrackPlaylist"}}</option> <option value="1">{{localize "MaterialDeck.PL.OneTrackPlaylist"}}</option>
@@ -14,7 +14,7 @@
</div> </div>
<div class="form-group"> <div class="form-group">
<label>{{localize "MaterialDeck.PL.Nr"}}</label> <label>{{localize "MaterialDeck.PL.Nr"}}</label>
<input type="number" id="numberOfPlaylists" name="plNum" min="0" max="127" value={{numberOfPlaylists}}> <input type="number" class="materialDeck_plConfig_select" id="numberOfPlaylists" name="plNum" min="0" max="127" value={{numberOfPlaylists}}>
</div> </div>
<div> <div>
<h2>{{localize "MaterialDeck.Playlists"}}</h2> <h2>{{localize "MaterialDeck.Playlists"}}</h2>
@@ -22,7 +22,7 @@
{{#each playlistData}} {{#each playlistData}}
<div class="form-group"> <div class="form-group">
<label>{{localize "MaterialDeck.Playlist"}} {{this.iteration}}</label> <label>{{localize "MaterialDeck.Playlist"}} {{this.iteration}}</label>
<select name="selectedPlaylist" class="playlist-select" id="playlist{{this.iteration}}" default=""> <select name="selectedPlaylist" class="materialDeck_plConfig_select" id="playlist{{this.iteration}}" default="">
{{#select this.playlist}} {{#select this.playlist}}
<option value="">{{localize "MaterialDeck.None"}}</option> <option value="">{{localize "MaterialDeck.None"}}</option>
{{#each ../playlists}} {{#each ../playlists}}
@@ -31,7 +31,7 @@
{{/select}} {{/select}}
</select> </select>
&nbsp; &nbsp;
<select name="playlistMode" class="playlistMode" id="playlistMode{{this.iteration}}" default=""> <select name="playlistMode" class="materialDeck_plConfig_select" id="playlistMode{{this.iteration}}" default="">
{{#select this.playlistMode}} {{#select this.playlistMode}}
<option value="0">{{localize "MaterialDeck.PL.Mode"}}</option> <option value="0">{{localize "MaterialDeck.PL.Mode"}}</option>
<option value="1">{{localize "MaterialDeck.PL.Unrestricted"}}</option> <option value="1">{{localize "MaterialDeck.PL.Unrestricted"}}</option>

View File

@@ -1,25 +1,13 @@
<form autocomplete="off" onsubmit="event.preventDefault()"> <form autocomplete="off" onsubmit="event.preventDefault()">
<style>
.boxed {
border: 1px solid black ;
border-radius: 5px ;
max-width: 166px;
height: 300px;
}
.navigation { <div class="materialDeck_sbConfig_navigationDiv">
flex:1; <button type="button" class="materialDeck_sbConfig_navigation" name="navPrev" {{prevDisabled}}>
}
</style>
<div class="navigation" style="width:100%; display:flex; flex-direction:row;">
<button type="button" class="navigation" id="navPrev" {{prevDisabled}}>
<i class="fas fa-arrow-left"></i> <i class="fas fa-arrow-left"></i>
</button> </button>
<p style="flex:15; text-align:center; padding: 0px 0; font-size: 20px"><b> <p class="materialDeck_sbConfig_p"><b>
{{localize "MaterialDeck.Sounds"}}: {{soundRange}} {{localize "MaterialDeck.Of"}} {{totalSounds}} {{localize "MaterialDeck.Sounds"}}: {{soundRange}} {{localize "MaterialDeck.Of"}} {{totalSounds}}
</b></p> </b></p>
<button type="button" class="navigation" id="navNext"> <button type="button" class="materialDeck_sbConfig_navigation" name="navNext">
<i class="fas fa-arrow-right"></i> <i class="fas fa-arrow-right"></i>
</button> </button>
</div> </div>
@@ -28,20 +16,20 @@
{{#each soundData}} {{#each soundData}}
<div class="form-group" style="width:100%"> <div class="form-group" style="width:100%">
{{#each this.dataThis}} {{#each this.dataThis}}
<div class="boxed" style="padding: 5px; margin:2px; width:10%"> <div class="materialDeck_sbConfig_boxed">
<div style="text-align:center;"> <div style="text-align:center;">
{{localize "MaterialDeck.Sound"}} {{this.iteration}} {{localize "MaterialDeck.Sound"}} {{this.iteration}}
</div> </div>
<div style="text-align:center;"> <div style="text-align:center;">
{{localize "MaterialDeck.Name"}} {{localize "MaterialDeck.Name"}}
</div> </div>
<input type="text" name="namebox" value="{{this.name}}" id="name{{this.iteration}}" style="width:100%;" > <input type="text" name="namebox" value="{{this.name}}" id="materialDeck_sbConfig_name{{this.iteration}}" style="width:100%;" >
<div style="text-align:center;"> <div style="text-align:center;">
{{localize "MaterialDeck.Playlist"}} {{localize "MaterialDeck.Playlist"}}
</div> </div>
<div> <div>
<select name="playlist" class="playlist-select" default="" style="width:100%;" id="playlists{{this.iteration}}"> <select name="playlist" class="playlist-select" default="" style="width:100%;" id="materialDeck_sbConfig_playlists{{this.iteration}}">
{{#select this.selectedPlaylist}} {{#select this.selectedPlaylist}}
{{#each ../../playlists}} {{#each ../../playlists}}
<option value="{{this.id}}">{{this.name}}</option> <option value="{{this.id}}">{{this.name}}</option>
@@ -53,8 +41,8 @@
<div style="text-align:center;"> <div style="text-align:center;">
{{localize "MaterialDeck.Sound"}} {{localize "MaterialDeck.Sound"}}
</div> </div>
<div class="form-fields" id="ss{{this.iteration}}" style="{{this.styleSS}}"> <div class="form-fields" id="materialDeck_sbConfig_ss{{this.iteration}}" style="{{this.styleSS}}">
<select name="sounds" class="sounds-select" default="" style="width:100%;" id="soundSelect{{this.iteration}}"> <select name="sounds" class="sounds-select" default="" style="width:100%;" id="materialDeck_sbConfig_soundSelect{{this.iteration}}">
{{#select this.sound}} {{#select this.sound}}
<option value="">{{localize "MaterialDeck.None"}}</option> <option value="">{{localize "MaterialDeck.None"}}</option>
{{#each sounds}} {{#each sounds}}
@@ -63,11 +51,11 @@
{{/select}} {{/select}}
</select> </select>
</div> </div>
<div class="form-fields" id="fp{{this.iteration}}" style="{{this.styleFP}}"> <div class="form-fields" id="materialDeck_sbConfig_fp{{this.iteration}}" style="{{this.styleFP}}">
<button type="button" class="file-picker" data-type="audio" data-target="src{{this.iteration}}" title="Browse Files" tabindex="-1"> <button type="button" class="file-picker" data-type="audio" data-target="src{{this.iteration}}" title="Browse Files" tabindex="-1">
<i class="fas fa-file-import fa-fw"></i> <i class="fas fa-file-import fa-fw"></i>
</button> </button>
<input class="image" type="text" name="src{{this.iteration}}" name2="soundSrc" id="srcPath{{this.iteration}}" placeholder="path/audio.mp3" value={{this.srcPath}}> <input class="image" type="text" name="src{{this.iteration}}" name2="soundSrc" id="materialDeck_sbConfig_srcPath{{this.iteration}}" placeholder="path/audio.mp3" value={{this.srcPath}}>
</div> </div>
<div style="text-align:center;"> <div style="text-align:center;">
{{localize "MaterialDeck.Icon"}} {{localize "MaterialDeck.Icon"}}
@@ -76,18 +64,18 @@
<button type="button" class="file-picker" data-type="image" data-target="img{{this.iteration}}" title="Browse Files" tabindex="-1"> <button type="button" class="file-picker" data-type="image" data-target="img{{this.iteration}}" title="Browse Files" tabindex="-1">
<i class="fas fa-file-import fa-fw"></i> <i class="fas fa-file-import fa-fw"></i>
</button> </button>
<input class="image" type="text" name="img{{this.iteration}}" name2="imgSrc" id="imgPath{{this.iteration}}" placeholder="path/image.png" value={{this.imgPath}}> <input class="image" type="text" name="img{{this.iteration}}" name2="imgSrc" id="materialDeck_sbConfig_imgPath{{this.iteration}}" placeholder="path/image.png" value={{this.imgPath}}>
</div> </div>
<div class="flex-container" style="display:flex;flex-direction:row;padding-top:5px"> <div class="flex-container" style="display:flex;flex-direction:row;padding-top:5px">
<label style="flex:1">{{localize "MaterialDeck.On"}}&nbsp;&nbsp;&nbsp;</label> <label style="flex:1">{{localize "MaterialDeck.On"}}&nbsp;&nbsp;&nbsp;</label>
<input style="flex:1" type="color" id="colorOn{{this.iteration}}" name="colorOn" style="flex:4" data-dtype="String" value="{{this.colorOn}}"> <input style="flex:1" type="color" id="materialDeck_sbConfig_colorOn{{this.iteration}}" name="colorOn" style="flex:4" data-dtype="String" value="{{this.colorOn}}">
<label style="flex:1">&nbsp;{{localize "MaterialDeck.Off"}}&nbsp;&nbsp;</label> <label style="flex:1">&nbsp;{{localize "MaterialDeck.Off"}}&nbsp;&nbsp;</label>
<input style="flex:1" type="color" id="colorOff{{this.iteration}}" name="colorOff" style="flex:4" data-dtype="String" value="{{this.colorOff}}"> <input style="flex:1" type="color" id="materialDeck_sbConfig_colorOff{{this.iteration}}" name="colorOff" style="flex:4" data-dtype="String" value="{{this.colorOff}}">
</div> </div>
<div class="form-group options"> <div class="form-group options">
<label>{{localize "MaterialDeck.Playback"}}</label> <label>{{localize "MaterialDeck.Playback"}}</label>
<select name="mode" id="playmode{{this.iteration}}" style="flex:1"> <select name="mode" id="materialDeck_sbConfig_playmode{{this.iteration}}" style="flex:1">
{{#select this.mode}} {{#select this.mode}}
<option value="0">{{localize "MaterialDeck.Once"}}</option> <option value="0">{{localize "MaterialDeck.Once"}}</option>
<option value="1">{{localize "MaterialDeck.Repeat"}}</option> <option value="1">{{localize "MaterialDeck.Repeat"}}</option>
@@ -97,7 +85,7 @@
</div> </div>
<div class="form-group options"> <div class="form-group options">
<label>{{localize "MaterialDeck.Volume"}}</label> <label>{{localize "MaterialDeck.Volume"}}</label>
<input type="range" min="0" max="100" value={{this.volume}} class="slider" name="volume" id="volume{{this.iteration}}"> <input type="range" min="0" max="100" value={{this.volume}} class="slider" name="volume" id="materialDeck_sbConfig_volume{{this.iteration}}">
</div> </div>
</div> </div>
@@ -105,18 +93,18 @@
</div> </div>
{{/each}} {{/each}}
<hr> <hr>
<div class="navigation" style="width:100%; display:flex; flex-direction:row;"> <div class="materialDeck_sbConfig_navigationDiv">
<button type="button" class="navigation" id="clearPage"> <button type="button" class="materialDeck_sbConfig_navigation" name="clearPage">
<i></i>{{localize "MaterialDeck.ClearPage"}} <i></i>{{localize "MaterialDeck.ClearPage"}}
</button> </button>
<button type="button" class="navigation" id="clearAll"> <button type="button" class="materialDeck_sbConfig_navigation" name="clearAll">
<i></i>{{localize "MaterialDeck.ClearAll"}} <i></i>{{localize "MaterialDeck.ClearAll"}}
</button> </button>
<p style="flex:15;"></p> <p style="flex:15;"></p>
<button type="button" class="navigation" id="import"> <button type="button" class="materialDeck_sbConfig_navigation" name="import">
<i></i>{{localize "MaterialDeck.Import"}} <i></i>{{localize "MaterialDeck.Import"}}
</button> </button>
<button type="button" class="navigation" id="export"> <button type="button" class="materialDeck_sbConfig_navigation" name="export">
<i></i>{{localize "MaterialDeck.Export"}} <i></i>{{localize "MaterialDeck.Export"}}
</button> </button>
</div> </div>

View File

@@ -1,98 +1,49 @@
<form autocomplete="off" onsubmit="event.preventDefault();"> <form autocomplete="off" onsubmit="event.preventDefault();">
<style>
header.table-header {
background: rgba(0, 0, 0, 0.5);
padding: 5px;
border: 1px solid #191813;
text-align: center;
color: #f0f0e0;
font-weight: bold;
text-shadow: 1px 1px #000;
}
ul.permissions-list {
list-style: none;
margin: 0;
padding: 0;
overflow: hidden auto;
scrollbar-width: thin;
}
li.permission {
padding: 5px;
border-bottom: 1px solid #7a7971;
}
li.permission .form-fields {
justify-content: space-around;
}
li.permission input[type="checkbox"] {
margin: 0;
}
.index {
flex: 0 0 200px;
text-align: left;
font-weight: bold;
}
.hint {
flex: 0 0 100%;
color: #4b4a44;
font-size: 13px;
margin: 5px 0 0;
}
.form-fields {
justify-content: space-around;
}
</style>
<p class="notes">{{localize "MaterialDeck.Perm.Instructions"}}</p> <p class="notes">{{localize "MaterialDeck.Perm.Instructions"}}</p>
<hr> <hr>
<div class="form-group"> <div class="form-group">
<h2>{{ localize "MaterialDeck.Perm.ENABLE.label" }}</h2> <h2>{{ localize "MaterialDeck.Perm.ENABLE.label" }}</h2>
</div> </div>
<header class="table-header flexrow"> <header class="materialDeck_uPerm_table-header flexrow">
<label class="index">{{ localize "PERMISSION.Permission" }}</label> <label class="materialDeck_uPerm_index">{{ localize "PERMISSION.Permission" }}</label>
{{#each roles as |rl r|}} {{#each roles as |rl r|}}
<label>{{ localize rl}}</label> <label>{{ localize rl}}</label>
{{/each}} {{/each}}
</header> </header>
<li class="materialDeck_uPerm_permission form-group">
<li class="permission form-group"> <label class="materialDeck_uPerm_index">{{ localize "MaterialDeck.Perm.ENABLE.ENABLE.label" }}</label>
<label class="index">{{ localize "MaterialDeck.Perm.ENABLE.ENABLE.label" }}</label>
<div class="form-fields"> <div class="form-fields">
{{#each enable as |r|}} {{#each enable as |r|}}
<input type="checkbox" name="ENABLE" {{checked r}}> <input type="checkbox" name="ENABLE.{{r.role}}" {{checked r.en}}>
{{/each}} {{/each}}
</div> </div>
<p class="hint">{{ localize "MaterialDeck.Perm.ENABLE.ENABLE.hint" }}</p> <p class="hint materialDeck_uPerm_hint">{{ localize "MaterialDeck.Perm.ENABLE.ENABLE.hint" }}</p>
</li> </li>
{{#each actions as |a|}} {{#each actions as |a|}}
<div class="form-group"> <div class="form-group">
<h2>{{ localize a.label }}</h2> <h2>{{ localize a.label }}</h2>
</div> </div>
<header class="table-header flexrow"> <header class="materialDeck_uPerm_table-header flexrow">
<label class="index">{{ localize "PERMISSION.Permission" }}</label> <label class="materialDeck_uPerm_index">{{ localize "PERMISSION.Permission" }}</label>
{{#each ../roles as |rl r|}} {{#each ../roles as |rl r|}}
<label>{{ localize rl}}</label> <label>{{ localize rl}}</label>
{{/each}} {{/each}}
</header> </header>
<ul class="permissions-list"> <ul class="materialDeck_uPerm_permissions-list">
{{#each a.permissions as |p|}} {{#each a.permissions as |p|}}
<li class="permission form-group"> <li class="materialDeck_uPerm_permission form-group">
<label class="index">{{ localize p.label }}</label> <label class="materialDeck_uPerm_index">{{ localize p.label }}</label>
<div class="form-fields"> <div class="form-fields">
{{#each p.roles as |r|}} {{#each p.roles as |r|}}
<input type="checkbox" id="{{p.id}}" name="{{a.id}}.{{p.id}}" {{checked r}}> <input type="checkbox" name="{{a.id}}.{{p.id}}.{{r.role}}" {{checked r.en}}>
{{/each}} {{/each}}
</div> </div>
<p class="hint">{{ localize p.hint }}</p> <p class="hint materialDeck_uPerm_hint">{{ localize p.hint }}</p>
</li> </li>
{{/each}} {{/each}}
</ul> </ul>