Files
MaterialDeck/src/actions/token.js
Cristian Deenen 9a7088a310 v1.4.11
2022-09-05 01:42:15 +02:00

988 lines
49 KiB
JavaScript

import { streamDeck, macroControl, otherControls, tokenHelper, getPermission } from "../../MaterialDeck.js";
import { compatibleCore } from "../misc.js";
export class TokenControl{
constructor(){
this.active = false;
this.wildcardOffset = 0;
this.itemOffset = 0;
}
async update(tokenId=null){
if (this.active == false) return;
for (let device of streamDeck.buttonContext) {
if (device?.buttons == undefined) continue;
for (let i=0; i<device.buttons.length; i++){
const data = device.buttons[i];
if (data == undefined || data.action != 'token') continue;
await this.pushData(tokenId,data.settings,data.context,device.device);
}
}
}
async pushData(tokenId,settings,context,device,ring=0,ringColor='#000000'){
const name = settings.displayName ? settings.displayName : false;
const icon = settings.icon ? settings.icon : 'none';
const background = settings.background ? settings.background : "#000000";
let stats = settings.stats ? settings.stats : 'none';
const selection = settings.selection ? settings.selection : 'selected';
const tokenIdentifier = settings.tokenName ? settings.tokenName : '';
const prependTitle = settings.prependTitle ? settings.prependTitle : '';
const mode = settings.tokenMode ? settings.tokenMode : 'token';
let validToken = false;
let token;
if (settings.combatTrackerMode) token = tokenHelper.getTokenFromTokenId(tokenId);
else token = tokenHelper.getToken(selection,tokenIdentifier);
if (token != undefined) validToken = true;
let txt = "";
let iconSrc = "";
let overlay = false;
let statsOld;
let uses = undefined;
let hp = undefined;
if (validToken) {
if (token.owner == false && token.observer == true && getPermission('TOKEN','OBSERVER') == false ) {
streamDeck.noPermission(context,device);
return;
}
if (token.owner == false && token.observer == false && getPermission('TOKEN','NON_OWNED') == false ) {
streamDeck.noPermission(context,device);
return;
}
if (mode == 'token') {
if (name) txt += tokenHelper.getTokenName(token);
txt += prependTitle;
const permission = token.actor?.permission;
if (settings.combat){
if (permission == 0 && getPermission('COMBAT','DISPLAY_ALL_NAMES') == false) txt = "";
else if (permission == 1 && getPermission('COMBAT','DISPLAY_LIMITED_NAME') == false) txt = "";
else if (permission == 2 && getPermission('COMBAT','DISPLAY_OBSERVER_NAME') == false) txt = "";
if (permission == 0 && stats == 'HP') stats = 'none';
else if (stats == 'HP' && permission == 1 && getPermission('COMBAT','DISPLAY_LIMITED_HP') == false) stats = 'none';
else if (stats == 'HP' && permission == 2 && getPermission('COMBAT','DISPLAY_OBSERVER_HP') == false) stats = 'none';
else if (stats != 'HP' && permission < 3 && getPermission('COMBAT','DISPLAY_NON_OWNED_STATS') == false) stats = 'none';
}
else if (getPermission('TOKEN','STATS') == false) {
statsOld = stats;
stats = 'none';
}
if (icon == 'tokenIcon') iconSrc = tokenHelper.getTokenIcon(token);
else if (icon == 'actorIcon') iconSrc = tokenHelper.getActorIcon(token);
if (name && stats != 'none' && stats != 'HPbox') txt += "\n";
if (stats == 'custom'){
const custom = settings.custom ? settings.custom : '';
let split = custom.split('[');
for (let i=0; i<split.length; i++) split[i] = split[i].split(']');
for (let i=0; i<split.length; i++)
for (let j=0; j<split[i].length; j++){
if (split[i][j][0] != '@') txt += split[i][j];
else {
const dataPath = split[i][j].split('@')[1].split('.');
let data = token;
for (let i=0; i<dataPath.length; i++)
data = data?.[dataPath[i]];
if (data == undefined) txt += '[undef]';
else txt += data;
}
}
}
if (stats == 'HP' || stats == 'Wounds') {
const hp = tokenHelper.getHP(token);
txt += hp.value + "/" + hp.max;
if (icon == 'stats')
uses = {
available: hp.value,
maximum: hp.max,
heart: "#FF0000"
};
}
if (stats == 'Agility') { /* forbidden-lands */
const wits = tokenHelper.getAgility(token);
txt += wits.value + "/" + wits.max;
if (icon == 'stats')
uses = {
available: wits.value,
maximum: wits.max,
heart: "#FF0000"
};
}
if (stats == 'Wits') { /* forbidden-lands */
const wits = tokenHelper.getWits(token);
txt += wits.value + "/" + wits.max;
if (icon == 'stats')
uses = {
available: wits.value,
maximum: wits.max,
heart: "#FF0000"
};
}
if (stats == 'Empathy') { /* forbidden-lands */
const wits = tokenHelper.getEmpathy(token);
txt += wits.value + "/" + wits.max;
if (icon == 'stats')
uses = {
available: wits.value,
maximum: wits.max,
heart: "#FF0000"
};
}
if (stats == 'WillPower') { /* forbidden-lands */
const wits = tokenHelper.getWillPower(token);
txt += wits.value + "/" + wits.max;
if (icon == 'stats')
uses = {
available: wits.value,
maximum: wits.max,
heart: "#FF0000"
};
}
if (stats == 'CriticalWounds') { /* WFRP4e */
const criticalWounds = tokenHelper.getCriticalWounds(token);
txt += criticalWounds.value + "/" + criticalWounds.max;
if (icon == 'stats')
uses = {
available: criticalWounds.value,
maximum: criticalWounds.max,
heart: "#FF0000"
};
}
else if (stats == 'HPbox') {
const hp = tokenHelper.getHP(token);
uses = {
available: hp.value,
maximum: hp.max
}
}
else if (stats == 'TempHP') {
const tempHP = tokenHelper.getTempHP(token);
txt += (tempHP.max == 0) ? tempHP.value : `${tempHP.value}/${tempHP.max}`;
if (icon == 'stats')
uses = {
available: tempHP.value,
maximum: tempHP.max,
heart: "#00FF00"
};
}
else if (stats == 'Stamina') { //starfinder
const stamina = tokenHelper.getStamina(token);
txt += `${stamina.value}/${stamina.max}`;
}
else if (stats == 'KinAC') { //starfinder
txt += tokenHelper.getKinAC(token);
}
else if (stats == 'AC') txt += tokenHelper.getAC(token);
else if (stats == 'ShieldHP') txt += tokenHelper.getShieldHP(token);
else if (stats == 'Speed') txt += tokenHelper.getSpeed(token);
else if (stats == 'Init') txt += tokenHelper.getInitiative(token);
else if (stats == 'PassivePerception') txt += tokenHelper.getPassivePerception(token);
else if (stats == 'PassiveInvestigation') txt += tokenHelper.getPassiveInvestigation(token);
else if (stats == 'Ability') txt += tokenHelper.getAbility(token, settings.ability);
else if (stats == 'AbilityMod') txt += tokenHelper.getAbilityModifier(token, settings.ability);
else if (stats == 'Save') {
txt += tokenHelper.getAbilitySave(token, settings.save);
ringColor = tokenHelper.getSaveRingColor(token, settings.save);
if (ringColor != undefined) ring = 2;
}
else if (stats == 'Skill') {
txt += tokenHelper.getSkill(token, settings.skill);
ringColor = tokenHelper.getSkillRingColor(token, settings.skill);
if (ringColor != undefined) ring = 2;
}
else if (stats == 'Prof') txt += tokenHelper.getProficiency(token);
else if (stats == 'Fate') txt += tokenHelper.getFate(token) /* WFRP4e */
else if (stats == 'Fortune') txt += tokenHelper.getFortune(token) /* WFRP4e */
else if (stats == 'Corruption') txt += tokenHelper.getCorruption(token) /* WFRP4e */
else if (stats == 'Advantage') txt += tokenHelper.getAdvantage(token) /* WFRP4e */
else if (stats == 'Resolve') txt += tokenHelper.getResolve(token) /* WFRP4e */
else if (stats == 'Resilience') txt += tokenHelper.getResilience(token) /* WFRP4e */
else if (stats == 'Perception') txt += tokenHelper.getPerception(token) /* PF2E */
else if (stats == 'Condition') { /* PF2E */
const valuedCondition = tokenHelper.getConditionValue(token, settings.condition);
if (valuedCondition != undefined) {
txt += valuedCondition?.value;
}
}
if (settings.onClick == 'visibility') { //toggle visibility
if (getPermission('TOKEN','VISIBILITY') == false ) {
streamDeck.noPermission(context,device);
return;
}
ring = 1;
if (compatibleCore('10.0') ? token.document.hidden : token.data.hidden){
ring = 2;
ringColor = "#FF7B00";
}
if (icon == 'stats') {
iconSrc = window.CONFIG.controlIcons.visibility;
overlay = true;
}
}
else if (settings.onClick == 'combatState') { //toggle combat state
if (getPermission('TOKEN','COMBAT') == false ) {
streamDeck.noPermission(context,device);
return;
}
ring = 1;
if (token.inCombat){
ring = 2;
ringColor = "#FF7B00";
}
if (icon == 'stats') {
iconSrc = window.CONFIG.controlIcons.combat;
overlay = true;
}
}
else if (settings.onClick == 'target') { //target token
ring = 1;
if (token.isTargeted){
ring = 2;
ringColor = "#FF7B00";
}
if (icon == 'stats') {
iconSrc = "fas fa-bullseye";
}
}
else if (settings.onClick == 'condition') { //handle condition
if (getPermission('TOKEN','CONDITIONS') == false ) {
streamDeck.noPermission(context,device);
return;
}
ring = 1;
overlay = true;
if (icon == 'stats') {
iconSrc = tokenHelper.getConditionIcon(settings.condition);
if (tokenHelper.getConditionActive(token,settings.condition)) {
ring = 2;
ringColor = "#FF7B00";
}
}
}
else if (settings.onClick == 'cubCondition') { //Combat Utility Belt conditions
if (getPermission('TOKEN','CONDITIONS') == false ) {
streamDeck.noPermission(context,device);
return;
}
ring = 1;
overlay = true;
const condition = settings.cubConditionName;
if (condition == undefined || condition == '') return;
if (icon == 'stats') {
iconSrc = CONFIG.statusEffects.find(e => e.label === condition).icon;
if (tokenHelper.getConditionActive(token,condition)){
ring = 2;
ringColor = "#FF7B00";
}
}
}
else if (settings.onClick == 'wildcard') { //wildcard images
if (getPermission('TOKEN','WILDCARD') == false ) {
streamDeck.noPermission(context,device);
return;
}
if (icon != 'stats') return;
const method = settings.wildcardMethod ? settings.wildcardMethod : 'iterate';
let value = parseInt(settings.wildcardValue);
if (isNaN(value)) value = 1;
const images = await token.actor.getTokenImages();
let currentImgNr = 0
let imgNr;
for (let i=0; i<images.length; i++)
if (images[i] == tokenHelper.getTokenIcon(token)){
currentImgNr = i;
break;
}
if (method == 'iterate'){
imgNr = currentImgNr + value + this.wildcardOffset;
while (imgNr >= images.length) imgNr -= images.length;
while (imgNr < 0) imgNr += images.length;
iconSrc = images[imgNr];
}
else if (method == 'set'){
imgNr = value - 1 + this.wildcardOffset;
if (value >= images.length) iconSrc = "modules/MaterialDeck/img/black.png";
else iconSrc = images[imgNr];
ring = 1;
if (currentImgNr == imgNr) {
ring = 2;
ringColor = "#FF7B00";
}
}
else return;
}
else if (settings.onClick == 'initiative') //Initiative
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
else {
txt += prependTitle;
const allItems = token.actor.items;
let itemNr = settings.itemNr ? settings.itemNr - 1 : 0;
itemNr += this.itemOffset;
const displayUses = settings.displayUses ? settings.displayUses : false;
const displayName = settings.displayInventoryName ? settings.displayInventoryName : false;
const displayIcon = settings.displayInventoryIcon ? settings.displayInventoryIcon : false;
const selectionMode = settings.inventorySelection ? settings.inventorySelection : 'order';
let items = allItems;
let item;
if (mode == 'inventory') {
items = tokenHelper.getItems(token,settings.inventoryType);
items = this.sortItems(items);
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);
}
else if (mode == 'features') {
items = tokenHelper.getFeatures(token,settings.featureType);
items = this.sortItems(items);
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);
}
else if (mode == 'spellbook') {
items = tokenHelper.getSpells(token,settings.spellType);
items = this.sortItems(items);
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 (item != undefined) {
if (displayIcon) iconSrc = item.img;
if (displayName) txt = item.name;
}
}
}
//No valid token found:
else {
if (mode == 'token') {
iconSrc += "";
if (settings.onClick == 'visibility') { //toggle visibility
if (getPermission('TOKEN','VISIBILITY') == false ) {
streamDeck.noPermission(context,device);
return;
}
if (icon == 'stats') {
iconSrc = window.CONFIG.controlIcons.visibility;
ring = 2;
overlay = true;
}
}
else if (settings.onClick == 'combatState') { //toggle combat state
if (getPermission('TOKEN','COMBAT') == false ) {
streamDeck.noPermission(context,device);
return;
}
if (icon == 'stats') {
iconSrc = window.CONFIG.controlIcons.combat;
ring = 2;
overlay = true;
}
}
else if (settings.onClick == 'target') { //target token
if (icon == 'stats') {
iconSrc = "fas fa-bullseye";
ring = 2;
overlay = true;
}
}
else if (settings.onClick == 'condition') { //toggle condition
if (getPermission('TOKEN','CONDITIONS') == false ) {
streamDeck.noPermission(context,device);
return;
}
ring = 1;
overlay = true;
if (icon == 'stats') iconSrc = tokenHelper.getConditionIcon(settings.condition);
}
else if (settings.onClick == 'cubCondition') { //Combat Utility Belt conditions
if (getPermission('TOKEN','CONDITIONS') == false ) {
streamDeck.noPermission(context,device);
return;
}
const condition = settings.cubConditionName;
if (condition == undefined || condition == '') return;
if (icon == 'stats') {
iconSrc = CONFIG.statusEffects.find(e => e.label === condition).icon;
}
ring = 1;
overlay = true;
}
}
}
if (icon == 'stats' && mode != 'offset' && mode != 'offsetRel'){
if (getPermission('TOKEN','STATS') == false) stats = statsOld;
if (stats == 'HP') //HP
iconSrc = "modules/MaterialDeck/img/token/hp_empty.png";
if (stats == 'TempHP') //Temp HP
iconSrc = "modules/MaterialDeck/img/token/temp_hp_empty.png";
else if (stats == 'AC' || stats == 'ShieldHP' || stats == 'KinAC') //AC
iconSrc = "modules/MaterialDeck/img/token/ac.webp";
else if (stats == 'Speed') //Speed
iconSrc = "modules/MaterialDeck/img/token/speed.webp";
else if (stats == 'Init' || settings.onClick == 'initiative') //Initiative
iconSrc = "modules/MaterialDeck/img/token/init.png";
else if (stats == 'PassivePerception') {
iconSrc = "modules/MaterialDeck/img/token/skills/prc.png";
overlay = true;
ring = 1;
}
else if (stats == 'PassiveInvestigation') {
iconSrc = "modules/MaterialDeck/img/token/skills/inv.png";
overlay = true;
ring = 1;
}
else if (stats == 'Ability' || stats == 'AbilityMod' || stats == 'Save') {
overlay = true;
let ability = (stats == 'Save') ? settings.save : settings.ability;
if (ability == undefined) ability = 'str';
if (ability == 'con') iconSrc = "modules/MaterialDeck/img/token/abilities/cons.png";
else iconSrc = "modules/MaterialDeck/img/token/abilities/" + ability + ".png";
}
else if (stats == 'Skill') {
overlay = true;
let skill = settings.skill;
if (skill == undefined) skill = 'acr';
else iconSrc = "modules/MaterialDeck/img/token/skills/" + (skill.startsWith('lor')? 'lor' : skill) + ".png";
}
else if (settings.onClick == 'center' || settings.onClick == 'centerSelect') {
overlay = true;
iconSrc = "modules/MaterialDeck/img/move/center.png";
}
else if (settings.onClick == 'move') {
overlay = true;
const dir = settings.dir ? settings.dir : 'center';
if (dir == 'up') //up
iconSrc = "modules/MaterialDeck/img/move/up.png";
else if (dir == 'down') //down
iconSrc = "modules/MaterialDeck/img/move/down.png";
else if (dir == 'right') //right
iconSrc = "modules/MaterialDeck/img/move/right.png";
else if (dir == 'left') //left
iconSrc = "modules/MaterialDeck/img/move/left.png";
else if (dir == 'upRight')
iconSrc = "modules/MaterialDeck/img/move/upright.png";
else if (dir == 'upLeft')
iconSrc = "modules/MaterialDeck/img/move/upleft.png";
else if (dir == 'downRight')
iconSrc = "modules/MaterialDeck/img/move/downright.png";
else if (dir == 'downLeft')
iconSrc = "modules/MaterialDeck/img/move/downleft.png";
}
else if (settings.onClick == 'rotate') {
overlay = true;
const value = isNaN(parseInt(settings.rotValue)) ? 0 : parseInt(settings.rotValue);
if (value >= 0)
iconSrc = "modules/MaterialDeck/img/move/rotatecw.png";
else
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.setTitle(txt,context);
}
sortItems(items) {
let sorted = Object.values(items);
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;
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
async keyPress(settings){
const tokenId = canvas.tokens.controlled[0]?.id;
const selection = settings.selection ? settings.selection : 'selected';
const tokenIdentifier = settings.tokenName ? settings.tokenName : '';
const mode = settings.tokenMode ? settings.tokenMode : 'token';
let token = tokenHelper.getToken(selection,tokenIdentifier);
if (token == undefined) return;
if (token.owner == false && token.observer == true && getPermission('TOKEN','OBSERVER') == false ) return;
if (token.owner == false && token.observer == false && getPermission('TOKEN','NON_OWNED') == false ) return;
if (mode == 'token') {
const onClick = settings.onClick ? settings.onClick : 'doNothing';
if (onClick == 'doNothing') //Do nothing
return;
else if (onClick == 'select'){ //select token
token.control();
}
else if (onClick == 'center'){ //center on token
let location = token.getCenter(token.x,token.y);
canvas.animatePan(location);
}
else if (onClick == 'centerSelect'){ //center on token and select
const location = token.getCenter(token.x,token.y);
canvas.animatePan(location);
token.control();
}
else if (onClick == 'move') { //move token
tokenHelper.moveToken(token,settings.dir);
}
else if (onClick == 'rotate') { //rotate token
tokenHelper.rotateToken(token,settings.rot,settings.rotValue);
}
else if (onClick == 'charSheet'){ //Open character sheet
const element = document.getElementById(token.actor.sheet.id);
if (element == null) token.actor.sheet.render(true);
else token.actor.sheet.close();
}
else if (onClick == 'tokenConfig') { //Open token config
const element = document.getElementById(token.sheet.id);
if (element == null) token.sheet.render(true);
else token.sheet.close();
}
else if (onClick == 'visibility') { //Toggle visibility
if (getPermission('TOKEN','VISIBILITY') == false ) return;
token.toggleVisibility();
}
else if (onClick == 'combatState') { //Toggle combat state
if (getPermission('TOKEN','COMBAT') == false ) return;
token.toggleCombat();
}
else if (onClick == 'target') { //Target token
token.setTarget(!token.isTargeted,{releaseOthers:false});
}
else if (onClick == 'condition') { //Handle condition
if (getPermission('TOKEN','CONDITIONS') == false ) return;
const func = settings.conditionFunction ? settings.conditionFunction : 'toggle';
if (func == 'toggle'){ //toggle
await tokenHelper.toggleCondition(token,settings.condition);
this.update(tokenId);
}
else if (func == 'increase'){ //increase
await tokenHelper.modifyConditionValue(token, settings.condition, +1)
this.update(tokenId);
}
else if (func == 'decrease'){ //decrease
await tokenHelper.modifyConditionValue(token, settings.condition, -1)
this.update(tokenId);
}
}
else if (onClick == 'cubCondition') { //Combat Utility Belt conditions
if (getPermission('TOKEN','CONDITIONS') == false ) return;
const condition = settings.cubConditionName;
if (condition == undefined || condition == '') return;
const effect = CONFIG.statusEffects.find(e => e.label === condition);
await token.toggleEffect(effect);
this.update(tokenId);
}
else if (onClick == 'vision'){
if (getPermission('TOKEN','VISION') == false ) return;
let sight = {};
let light = {
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;
}
token.document.update(data);
}
else if (onClick == 'initiative'){
tokenHelper.toggleInitiative(token);
}
else if (onClick == 'wildcard') { //wildcard images
if (getPermission('TOKEN','WILDCARD') == false ) return;
const method = settings.wildcardMethod ? settings.wildcardMethod : 'iterate';
let value = parseInt(settings.wildcardValue);
if (isNaN(value)) value = 1;
const images = await token.actor.getTokenImages();
let imgNr;
let iconSrc;
if (method == 'iterate'){
let currentImgNr = 0
for (let i=0; i<images.length; i++)
if (images[i] == tokenHelper.getTokenIcon(token)){
currentImgNr = i;
break;
}
imgNr = currentImgNr + value + this.wildcardOffset;
while (imgNr >= images.length) imgNr -= images.length;
while (imgNr < 0) imgNr += images.length;
}
else if (method == 'set'){
imgNr = value - 1 + this.wildcardOffset;
if (value >= images.length || value < 1) return;
}
else if (method == 'offset'){
this.wildcardOffset = value;
this.update(canvas.tokens.controlled[0]?.id);
}
else return;
iconSrc = images[imgNr];
token.document.update({img: iconSrc});
}
else if (onClick == 'macro') { //call a macro
const settingsNew = {
target: token,
macroMode: settings.macroMode,
macroNumber: settings.macroId,
macroArgs: settings.macroArgs
}
macroControl.keyPress(settingsNew);
}
else if (onClick == 'roll') { //roll skill/save/ability
const rollMode = settings.rollMode ? settings.rollMode : 'default';
let options;
if (rollMode == 'default')
options = {
fastForward: (otherControls.rollOption != 'dialog'),
advantage: (otherControls.rollOption == 'advantage'),
disadvantage: (otherControls.rollOption == 'disadvantage')
}
else if (rollMode == 'normal') options = {fastForward:true}
else if (rollMode == 'advantage') options = {fastForward:true,advantage:true}
else if (rollMode == 'disadvantage') options = {fastForward:true,disadvantage:true}
tokenHelper.roll(token,settings.roll,options,settings.rollAbility,settings.rollSkill,settings.rollSave)
if (otherControls.rollOption != 'dialog') otherControls.setRollOption('normal');
}
else if (onClick == 'custom') {//custom onClick function
if (getPermission('TOKEN','CUSTOM') == false ) return;
const formula = settings.customOnClickFormula ? settings.customOnClickFormula : '';
if (formula == '') return;
let targetArrayTemp;
let formulaArrayTemp;
let split1 = formula.split(';');
for (let i=0; i<split1.length; i++){
let macro = false;
let furnaceArguments = "";
let split2 = split1[i].split(' = ');
targetArrayTemp = split2[0];
formulaArrayTemp = split2[1];
let targetArray = this.splitCustom(targetArrayTemp);
for (let i=0; i<targetArray.length; i++){
if (targetArray[i][0] == '@') {
const dataPath = targetArray[i].split('@')[1].split('.');
targetArray[i] = dataPath;
if (dataPath == 'macro') {
macro = true;
}
}
else if (macro) {
const data = targetArray[i].split('[');
if (data != undefined && data.length > 1) targetArray[i] = data[1];
if (i > 1) {
if (furnaceArguments != "") furnaceArguments += " ";
furnaceArguments += "\"" + targetArray[i] + "\"";
}
}
}
if (macro) {
const settingsNew = {
target: token,
macroMode: 'name',
macroNumber: targetArray[1],
macroArgs: furnaceArguments
}
macroControl.keyPress(settingsNew);
continue;
}
let formulaArray = this.splitCustom(formulaArrayTemp);
let value = 0;
let previousOperation = '+';
if (formulaArray.length == 1 && formulaArray[0][0] == '[')
value = formulaArray[0].split('[')[1];
else if (formulaArray.length == 1)
value = formulaArray[0];
else {
for (let i=0; i<formulaArray.length; i++){
let val;
if (formulaArray[i][0] == '@') {
let dataPath;
if (formulaArray[i] == '@this') dataPath = targetArray[0];
else dataPath = formulaArray[i].split('@')[1].split('.');
let data = token;
for (let j=0; j<dataPath.length; j++)
data = data?.[dataPath[j]];
if (data == undefined) return;
formulaArray[i] = data;
val = data;
}
else if (isNaN(formulaArray[i])) {
previousOperation = formulaArray[i];
if (previousOperation == '++') value++;
else if (previousOperation == '--') value--;
continue;
}
else
val = parseFloat(formulaArray[i]);
if (previousOperation == '+') value += val;
else if (previousOperation == '-') value -= val;
else if (previousOperation == '*') value *= val;
else if (previousOperation == '/') value /= val;
else if (previousOperation == '**') value **= val;
else if (previousOperation == '%') value %= val;
else if (previousOperation == '<' && value >= val) {value = val-1;}
else if (previousOperation == '>' && value <= val) {value = val+1;}
else if (previousOperation == '<=' && value > val) {value = val;}
else if (previousOperation == '>=' && value < val) {value = val;}
}
}
for (let i=0; i<targetArray.length; i++){
const dataPath = targetArray[i];
let data;
if (dataPath[0] == 'actor') {
let actor = token.actor;
if (dataPath[1] == 'data'){
let path = '';
for (let j=2; j<targetArray[i].length; j++){
if (path != '') path += '.';
path += targetArray[i][j];
}
await actor.update({[path]:value})
}
else {
let path = '';
for (let j=1; j<targetArray[i].length; j++){
if (path != '') path += '.';
path += targetArray[i][j];
}
await actor.update({[path]:value})
}
this.update(token.id);
}
else {
data = token;
let path = '';
for (let j=1; j<targetArray[i].length; j++){
if (path != '') path += '.';
path += targetArray[i][j];
}
await token.document.update({[path]:value});
this.update(token.id);
}
}
}
}
}
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 {
const allItems = token.actor.items;
const itemNr = settings.itemNr ? settings.itemNr - 1 : 0;
const selectionMode = settings.inventorySelection ? settings.inventorySelection : 'order';
let items = allItems;
if (mode == 'inventory') {
items = tokenHelper.getItems(token,settings.inventoryType);
}
else if (mode == 'features') {
items = tokenHelper.getFeatures(token,settings.featureType);
}
else if (mode == 'spellbook') {
items = tokenHelper.getSpells(token,settings.spellType);
}
items = this.sortItems(items);
let item;
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) {
tokenHelper.rollItem(item, settings, otherControls.rollOption);
}
}
}
splitCustom(string){
const split = string.split('[');
let array1 = [];
for (let i=0; i<split.length; i++){
if (i>0 && split[i][0] != '@' && split[i] != "" && isNaN(split[i])) split[i] = '['+split[i]
const split2 = split[i].split(']');
for (let j=0; j<split2.length; j++){
array1.push(split2[j]);
}
}
let array2 = [];
for (let i=0; i<array1.length; i++){
if (array1[i][0] == '[') {
array2.push(array1[i]);
continue;
}
const split3 = array1[i].split(' ');
for (let j=0; j<split3.length; j++){
array2.push(split3[j]);
}
}
let array3 = [];
for (let i=0; i<array2.length; i++){
if (array2[i] == "") continue;
array3.push(array2[i]);
}
return array3;
}
pf2eCondition(condition){
return "systems/pf2e/icons/conditions-2/" + condition + ".png";
}
}