diff --git a/img/token/skills/SOURCES.txt b/img/token/skills/SOURCES.txt index a3317cf..28ac895 100644 --- a/img/token/skills/SOURCES.txt +++ b/img/token/skills/SOURCES.txt @@ -10,6 +10,7 @@ his.png: https://game-icons.net/1x1/delapouite/backward-time.html ins.png: https://game-icons.net/1x1/lorc/light-bulb.html itm.png: https://game-icons.net/1x1/lorc/one-eyed.html inv.png: https://game-icons.net/1x1/lorc/magnifying-glass.html +lor.png: https://game-icons.net/1x1/lorc/bookmarklet.html med.png: https://game-icons.net/1x1/delapouite/first-aid-kit.html nat.png: https://game-icons.net/1x1/delapouite/forest.html occ.png: https://game-icons.net/1x1/skoll/pentacle.html diff --git a/img/token/skills/lor.png b/img/token/skills/lor.png new file mode 100644 index 0000000..4d25e52 Binary files /dev/null and b/img/token/skills/lor.png differ diff --git a/src/systems/demonlord.js b/src/systems/demonlord.js index 2cabe4a..985ac49 100644 --- a/src/systems/demonlord.js +++ b/src/systems/demonlord.js @@ -134,4 +134,15 @@ export class demonlord{ rollItem(item) { return item.roll() } + + /** + * Ring Colors + */ + getSkillRingColor(token, skill) { + return; + } + + getSaveRingColor(token, save) { + return; + } } \ No newline at end of file diff --git a/src/systems/dnd35e.js b/src/systems/dnd35e.js index 32d1604..72bdc75 100644 --- a/src/systems/dnd35e.js +++ b/src/systems/dnd35e.js @@ -199,4 +199,15 @@ export class dnd35e{ rollItem(item) { return item.roll() } + + /** + * Ring Colors + */ + getSkillRingColor(token, skill) { + return; + } + + getSaveRingColor(token, save) { + return; + } } \ No newline at end of file diff --git a/src/systems/dnd5e.js b/src/systems/dnd5e.js index b32ee24..f0c27b4 100644 --- a/src/systems/dnd5e.js +++ b/src/systems/dnd5e.js @@ -1,5 +1,12 @@ import {compatibleCore} from "../misc.js"; +const proficiencyColors = { + 0: "#000000", + 0.5: "#804A00", + 1: "#C0C0C0", + 2: "#FFD700" +} + export class dnd5e{ constructor(){ @@ -202,4 +209,19 @@ export class dnd5e{ rollItem(item) { return item.roll() } + + /** + * Ring Colors + */ + getSkillRingColor(token, skill) { + const profLevel = token.actor.data.data?.skills[skill]?.proficient; + if (profLevel == undefined) return; + return proficiencyColors?.[profLevel]; + } + + getSaveRingColor(token, save) { + const profLevel = token.actor.data.data?.abilities[save]?.proficient; + if (profLevel == undefined) return; + return proficiencyColors?.[profLevel]; + } } \ No newline at end of file diff --git a/src/systems/forbidden-lands.js b/src/systems/forbidden-lands.js index 0eb1a00..98025a1 100644 --- a/src/systems/forbidden-lands.js +++ b/src/systems/forbidden-lands.js @@ -235,4 +235,15 @@ export class forbiddenlands{ sheet.rollSpecificAttack(item.id); return item.sendToChat(); } + + /** + * Ring Colors + */ + getSkillRingColor(token, skill) { + return; + } + + getSaveRingColor(token, save) { + return; + } } \ No newline at end of file diff --git a/src/systems/pf2e.js b/src/systems/pf2e.js index b013641..bb45f21 100644 --- a/src/systems/pf2e.js +++ b/src/systems/pf2e.js @@ -1,38 +1,58 @@ import {compatibleCore} from "../misc.js"; import {otherControls} from "../../MaterialDeck.js"; +const limitedSheets = ['loot', 'vehicle']; +const proficiencyColors = +{ + untrained: "#424242", + trained: "#171F69", + expert: "#3C005E", + master: "#664400", + legendary: "#5E0000" +}; + export class pf2e{ + constructor(){ } + tokenSpellData = new Map(); + getHP(token) { - const hp = token.actor.data.data.attributes.hp; + const hp = token.actor.attributes?.hp; return { - value: hp.value, - max: hp.max + value: (hp?.value == null) ? 0 : hp.value, + max: (hp?.max == null) ? 0 : hp.max } } getTempHP(token) { - const hp = token.actor.data.data.attributes.hp; + const hp = token.actor.attributes?.hp; return { - value: (hp.temp == null) ? 0 : hp.temp, - max: (hp.tempmax == null) ? 0 : hp.tempmax + value: (hp?.temp == null) ? 0 : hp.temp, + max: (hp?.tempmax == null) ? 0 : hp.tempmax } } getAC(token) { - return token.actor.data.data.attributes.ac.value; + const ac = token.actor.attributes?.ac; + return (ac?.value == null) ? 10 : ac?.value; } getShieldHP(token) { - return token.actor.data.data.attributes.shield.value; + const shieldhp = token.actor.attributes.shield + return (shieldhp?.value == null) ? 0 : shieldhp?.value; } getSpeed(token) { - let speed = `${token.actor.data.data.attributes.speed.total}'`; - const otherSpeeds = token.actor.data.data.attributes.speed.otherSpeeds; + if (this.isLimitedSheet(token.actor) || token.actor.type == 'hazard') { + if (token.actor.type == 'vehicle') { + return token.actor.data.data.details.speed; + } else return ''; + } + let speed = `${token.actor.attributes.speed?.total}'`; + const otherSpeeds = token.actor.attributes.speed?.otherSpeeds; if (otherSpeeds.length > 0) for (let os of otherSpeeds) speed += `\n${os.type} ${os.total}'`; @@ -40,14 +60,20 @@ export class pf2e{ } getInitiative(token) { - let initiativeModifier = token.actor.data.data.attributes?.initiative.totalModifier; - let initiativeAbility = token.actor.data.data.attributes?.initiative.ability; + if (this.isLimitedSheet(token.actor) || token.actor.type == 'familiar') return ''; + if (token.actor.type == 'hazard') { + let initiative = token.actor.attributes?.stealth?.value; + return `Init: Stealth (${initiative})`; + } + let initiative = token.actor.attributes.initiative; + let initiativeModifier = initiative?.totalModifier; + let initiativeLabel = initiative?.label.replace('iative',''); //Initiative is too long for the button if (initiativeModifier > 0) { initiativeModifier = `+${initiativeModifier}`; } else { initiativeModifier = this.getPerception(token); //NPCs won't have a valid Initiative value, so default to use Perception } - return (initiativeAbility != '') ? `(${initiativeAbility}): ${initiativeModifier}` : `(perception): ${initiativeModifier}`; + return `${initiativeLabel} (${initiativeModifier})`; } toggleInitiative(token) { @@ -63,46 +89,73 @@ export class pf2e{ } getPerception(token) { - let perception = token.actor.data.data.attributes?.perception.totalModifier; + if (this.isLimitedSheet(token.actor) || token.actor.type == 'hazard') return ''; + let perception = token.actor.attributes.perception?.totalModifier; return (perception >= 0) ? `+${perception}` : perception; } getAbility(token, ability) { + if (this.isLimitedSheet(token.actor) || token.actor.type == 'familiar') return ''; if (ability == undefined) ability = 'str'; - return token.actor.data.data.abilities?.[ability].value; + return token.actor.abilities?.[ability]?.value; } getAbilityModifier(token, ability) { + if (this.isLimitedSheet(token.actor) || token.actor.type == 'hazard' || token.actor.type == 'familiar') return ''; if (ability == undefined) ability = 'str'; - let val = token.actor.data.data.abilities?.[ability].mod; + let val = token.actor.abilities?.[ability]?.mod; return (val >= 0) ? `+${val}` : val; } getAbilitySave(token, ability) { - if (ability == undefined) ability = 'fortitude'; - else if (ability == 'fort') ability = 'fortitude'; - else if (ability == 'ref') ability = 'reflex'; - else if (ability == 'will') ability = 'will'; - let val = token.actor.data.data.saves?.[ability].value; + ability = this.fixSave(ability); + const save = this.findSave(token, ability); + if (save == undefined) return ''; + let val = save?.value; return (val >= 0) ? `+${val}` : val; } + findSave(token, ability) { + if (this.isLimitedSheet(token.actor)) return; + return token.actor.data.data.saves?.[ability]; + } + + fixSave(ability) { + if (ability == undefined) return 'fortitude'; + else if (ability == 'fort') return 'fortitude'; + else if (ability == 'ref') return 'reflex'; + else if (ability == 'will') return 'will'; + } + getSkill(token, skill) { + const tokenSkill = this.findSkill(token, skill); + if (tokenSkill == undefined) return ''; + + if (skill.startsWith('lor')) { + return `${tokenSkill.name}: +${tokenSkill.totalModifier}`; + } + + const val = tokenSkill.totalModifier; + return (val >= 0) ? `+${val}` : val; + } + + findSkill(token, skill) { + if (this.isLimitedSheet(token.actor)) return; if (skill == undefined) skill = 'acr'; if (skill.startsWith('lor')) { const index = parseInt(skill.split('_')[1])-1; const loreSkills = this.getLoreSkills(token); if (loreSkills.length > index) { - return `${loreSkills[index].name}: +${loreSkills[index].totalModifier}`; + return loreSkills[index]; } else { - return ''; + return; } } - const val = token.actor.data.data.skills?.[skill].totalModifier; - return (val >= 0) ? `+${val}` : val; + return token.actor.data.data.skills?.[skill]; } getLoreSkills(token) { + if (this.isLimitedSheet(token.actor)) return []; const skills = token.actor.data.data.skills; return Object.keys(skills).map(key => skills[key]).filter(s => s.lore == true); } @@ -142,9 +195,7 @@ export class pf2e{ const effect = this.getConditionValue(token,condition); if (effect == undefined) { if (delta > 0) { - const Condition = this.getConditionName(condition); - const newCondition = game.pf2e.ConditionManager.getCondition(Condition); - await game.pf2e.ConditionManager.addConditionToToken(newCondition, token); + await game.pf2e.ConditionManager.addConditionToToken(condition, token); } } else { try { @@ -166,19 +217,16 @@ export class pf2e{ async toggleCondition(token,condition) { if (condition == undefined) condition = 'removeAll'; if (condition == 'removeAll'){ - for( let effect of token.actor.items.filter(i => i.type == 'condition')) - await effect.delete(); + for( let existing of token.actor.items.filter(i => i.type == 'condition')) + await game.pf2e.ConditionManager.removeConditionFromToken(existing.data._id, token); } else { const effect = this.getCondition(token,condition); if (effect == undefined) { - const Condition = this.getConditionName(condition); - const newCondition = game.pf2e.ConditionManager.getCondition(Condition); - newCondition.data.sources.hud = !0, - await game.pf2e.ConditionManager.addConditionToToken(newCondition, token); + await game.pf2e.ConditionManager.addConditionToToken(condition, token); } else { - effect.delete(); + await game.pf2e.ConditionManager.removeConditionFromToken(effect.data._id, token); } } return true; @@ -188,19 +236,28 @@ export class pf2e{ * Roll */ roll(token,roll,options,ability,skill,save) { + if (this.isLimitedSheet(token.actor)) return; + options.skipDialog = true; if (roll == undefined) roll = 'skill'; if (ability == undefined) ability = 'str'; if (skill == undefined) skill = 'acr'; if (save == undefined) save = 'fort'; - if (roll == 'perception') token.actor.data.data.attributes.perception.roll(options); - if (roll == 'initiative') token.actor.rollInitiative(options); - if (roll == 'ability') token.actor.rollAbility(options, ability); + if (roll == 'perception') { + this.checkRoll(`Perception Check`, token.actor.perception, 'perception-check', token.actor); + } + if (roll == 'initiative') { + token.actor.rollInitiative({createCombatants:true, initiativeOptions: {skipDialog: true}}); + } + + if (roll == 'ability') return; //Ability Checks are not supported in pf2e else if (roll == 'save') { let ability = save; if (ability == 'fort') ability = 'fortitude'; else if (ability == 'ref') ability = 'reflex'; else if (ability == 'will') ability = 'will'; - token.actor.rollSave(options, ability); + if (token.actor.type == 'hazard' && ability == 'will') return; //Hazards don't have Will saves + let abilityName = ability.charAt(0).toUpperCase() + ability.slice(1); + this.checkRoll(`${abilityName} Saving Throw`, token.actor.saves?.[ability], 'saving-throw', token.actor); } else if (roll == 'skill') { if (skill.startsWith('lor')) { @@ -212,15 +269,23 @@ export class pf2e{ } else { return; } - } - token.actor.data.data.skills?.[skill].roll(options); + } + let skillName = token.actor.data.data.skills?.[skill].name; + skillName = skillName.charAt(0).toUpperCase() + skillName.slice(1); + this.checkRoll(`Skill Check: ${skillName}`, token.actor.skills?.[skill], 'skill-check', token.actor); } } + checkRoll(checkLabel,stat,type,actor) { + let checkModifier = new game.pf2e.CheckModifier(checkLabel, stat); + game.pf2e.Check.roll(checkModifier, {type:type, actor: actor, skipDialog: true}, null); + } + /** * Items */ getItems(token,itemType) { + if (this.isLimitedSheet(token.actor)) return []; if (itemType == undefined) itemType = 'any'; 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'); @@ -229,13 +294,14 @@ export class pf2e{ } getItemUses(item) { - return {available: item.data.data.quantity.value}; + return {available: item.quantity.value}; } /** * Features */ getFeatures(token,featureType) { + if (this.isLimitedSheet(token.actor)) return []; if (featureType == undefined) featureType = 'any'; 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'); @@ -244,7 +310,10 @@ export class pf2e{ if (featureType == 'action-int') return allItems.filter(i => i.type == 'action' && i.data.data.actionCategory?.value == 'interaction'); if (featureType == 'action-off') return allItems.filter(i => i.type == 'action' && i.data.data.actionCategory?.value == 'offensive'); if (featureType == 'strike') { //Strikes are not in the actor.items collection - let actions = token.actor.data.data.actions.filter(a=>a.type == 'strike'); + if (token.actor.type == 'hazard' || token.actor.type == 'familiar') { + return allItems.filter(i => i.type == 'melee' || i.type == 'ranged'); + } + let actions = token.actor.data.data.actions?.filter(a=>a.type == 'strike'); for (let a of actions) { a.img = a.imageUrl; a.data = { @@ -257,38 +326,188 @@ export class pf2e{ } getFeatureUses(item) { - if (item.data.type == 'class') return {available: item.actor.data.data.details.level.value}; + if (item.data.type == 'class') return {available: item.actor.details.level.value}; else return; } /** * Spells */ + buildSpellData(token) { + let spellData = [[],[],[],[],[],[],[],[],[],[],[],[]]; + let spellcastingEntries = token.actor.spellcasting; + const actorLevel = token.actor.data.data.details.level.value; + spellcastingEntries.forEach(spellCastingEntry => { + let highestSpellSlot = Math.ceil(actorLevel/2); + while (spellCastingEntry.data.data.slots?.[`slot${highestSpellSlot}`]?.max <= 0) highestSpellSlot--; + //Prepared (not flexible) + if (spellCastingEntry.data.data.prepared?.value == 'prepared' && !spellCastingEntry?.data.data?.prepared?.flexible == true) { + for (let slotLevel = 0; slotLevel < 11; slotLevel++) { + for (let slot = 0; slot < spellCastingEntry.data.data.slots?.[`slot${slotLevel}`].max; slot++) { + let spellId = spellCastingEntry.data.data.slots?.[`slot${slotLevel}`].prepared?.[slot].id; + let spell = spellCastingEntry.spells.get(spellId); + if (spellId != null) { + spellData[slotLevel].push(spell); + } + } + } + } else { + spellCastingEntry.spells.forEach( ses => { + if ((spellCastingEntry.data.data.prepared.value == 'spontaneous' || spellCastingEntry.data.data.prepared?.flexible == true) && ses.data.data.location.signature == true) { + let baseLevel = this.getSpellLevel(ses); + for (let level = baseLevel; level <= highestSpellSlot; level++) { + spellData[level].push(ses); + } + } else { + spellData[this.getSpellLevel(ses)].push(ses); + } + }); + } + }); + this.tokenSpellData.set(token.id, {spellData: spellData, timeStamp: Date.now()}); + return spellData; + } + + getSpellData(token) { + let existingSpellData = this.tokenSpellData.get(token.id); + if (existingSpellData == undefined) return this.buildSpellData(token); + let milisSinceCreation = Date.now() - existingSpellData.timeStamp; + if (milisSinceCreation > 10000) { + this.tokenSpellData.delete(token.id); + return this.buildSpellData(token); + } + return existingSpellData.spellData; + } + + getSpellLevel(spell) { + if (spell.isFocusSpell == true) return 11; + if (spell.isCantrip == true) return 0; + return spell.level; + } + getSpells(token,level) { + if (this.isLimitedSheet(token.actor)) return ''; if (level == undefined) level = 'any'; - const allItems = token.actor.items; - if (level == 'any') return allItems.filter(i => i.type == 'spell') - if (level == '0') return allItems.filter(i => i.type == 'spell' && i.isCantrip == true) - else return allItems.filter(i => i.type == 'spell' && i.level == level && i.isCantrip == false) + let spellData = this.getSpellData(token); + + if (level == 'f') return this.getUniqueSpells(spellData[11]); + if (level == 'any') return this.getUniqueSpells(spellData.flat()); + return this.getUniqueSpells(spellData[level]); + } + + getUniqueSpells(spells) { + return Array.from(new Set(spells)); } getSpellUses(token,level,item) { + if (this.isLimitedSheet(token.actor)) return ''; if (level == undefined || level == 'any') level = item.level; if (item.isCantrip == true) return; - const spellbook = token.actor.items.filter(i => i.data.type === 'spellcastingEntry')[0]; + if (item.isFocusSpell == true) return { + available: token.actor.data.data.resources.focus.value, + maximum: token.actor.data.data.resources.focus.max + } + const spellbook = this.findSpellcastingEntry(token.actor, item); if (spellbook == undefined) return; + if (spellbook.data.data.prepared.value == 'innate') { + return { + available: item.data.data.location.uses.value, + maximum: item.data.data.location.uses.max + } + } + if (spellbook.data.data.prepared.value == 'prepared') { + if (!spellbook.data.data.prepared?.flexible == true) { + let slotsExpended = 0; + let slotsPrepared = 0; + for (let slot = 0; slot < spellbook.data.data.slots?.[`slot${level}`].max; slot++) { + let slotEntry = spellbook.data.data.slots?.[`slot${level}`].prepared?.[slot]; + if (slotEntry.id == item.id) { + slotsPrepared++; + if (slotEntry?.expended == true) { + slotsExpended++; + } + } + } + return { + available: slotsPrepared - slotsExpended, + maximum: slotsPrepared + } + } + } return { available: spellbook.data.data.slots?.[`slot${level}`].value, maximum: spellbook.data.data.slots?.[`slot${level}`].max } } - rollItem(item) { + findSpellcastingEntry(actor, spell) { + let spellcastingEntries = actor.spellcasting; + let result; + spellcastingEntries.forEach(spellCastingEntry => { + if (spellCastingEntry.spells.get(spell.id) != undefined) { + result = spellCastingEntry; + } + }); + return result; + } + + rollItem(item, settings) { let variant = 0; if (otherControls.rollOption == 'map1') variant = 1; if (otherControls.rollOption == 'map2') variant = 2; + 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==='weapon' || item.type==='melee') return item.parent.data.data.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.actions.find(a=>a.name===item.name).variants[variant].roll({event}); + if (item.type === 'spell') { + const spellbook = this.findSpellcastingEntry(item.parent, item); + if (spellbook != undefined) { + let spellLvl = item.level; + if (settings.spellType == 'f' || settings.spellType == '0') { + const actorLevel = item.parent.data.data.details.level.value; + spellLvl = Math.ceil(actorLevel/2); + } else if (settings.spellType != 'any') { + spellLvl = settings.spellType; + } + if (spellbook.data.data.prepared.value == 'prepared' && !spellbook.data.data.prepared?.flexible == true) { + for (let slotId = 0; slotId < spellbook.data.data.slots?.[`slot${spellLvl}`].max; slotId++) { + let slotEntry = spellbook.data.data.slots?.[`slot${spellLvl}`].prepared?.[slotId]; + if (slotEntry.id == item.id) { + if (!slotEntry?.expended == true) { + return spellbook.cast(item, {slot: slotId, level: spellLvl}); + } + } + } + } else { + return spellbook.cast(item, { level: spellLvl}); + } + } + } return game.pf2e.rollItemMacro(item.id); } + + isLimitedSheet(actor) { + return limitedSheets.includes(actor.type); + } + + /** + * Ring Colors + */ + getSkillRingColor(token, skill) { + return this.getRingColor(this.findSkill(token, skill)); + } + + getSaveRingColor(token, save) { + save = this.fixSave(save); + return this.getRingColor(this.findSave(token, save)); + } + + getRingColor(stat) { + if (stat == undefined) return; + let statModifiers = stat?.modifiers || stat?._modifiers; + const profLevel = statModifiers?.find(m => m.type == 'proficiency')?.slug; + if (profLevel != undefined) { + return proficiencyColors?.[profLevel]; + } + return; + } } \ No newline at end of file diff --git a/src/systems/tokenHelper.js b/src/systems/tokenHelper.js index eed2f70..0bfa835 100644 --- a/src/systems/tokenHelper.js +++ b/src/systems/tokenHelper.js @@ -315,7 +315,17 @@ export class TokenHelper{ return this.system.getSpellUses(token,level,item); } - rollItem(item) { - return this.system.rollItem(item); + rollItem(item, settings) { + return this.system.rollItem(item, settings); + } + + /** + * Ring Colors + */ + getSkillRingColor(token,skill) { + return this.system.getSkillRingColor(token,skill); + } + getSaveRingColor(token,save) { + return this.system.getSaveRingColor(token,save); } } \ No newline at end of file diff --git a/src/systems/wfrp4e.js b/src/systems/wfrp4e.js index eefaee2..7b62cc0 100644 --- a/src/systems/wfrp4e.js +++ b/src/systems/wfrp4e.js @@ -168,5 +168,14 @@ export class wfrp4e { return; } + /** + * Ring Colors + */ + getSkillRingColor(token, skill) { + return; + } + getSaveRingColor(token, save) { + return; + } } \ No newline at end of file diff --git a/src/token.js b/src/token.js index abb2765..84b585c 100644 --- a/src/token.js +++ b/src/token.js @@ -198,8 +198,16 @@ export class TokenControl{ 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); - else if (stats == 'Skill') txt += tokenHelper.getSkill(token, settings.skill); + 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 */ @@ -444,7 +452,6 @@ export class TokenControl{ } else if (stats == 'Ability' || stats == 'AbilityMod' || stats == 'Save') { overlay = true; - ring = 1; let ability = (stats == 'Save') ? settings.save : settings.ability; if (ability == undefined) ability = 'str'; if (ability == 'con') iconSrc = "modules/MaterialDeck/img/token/abilities/cons.png"; @@ -452,10 +459,9 @@ export class TokenControl{ } else if (stats == 'Skill') { overlay = true; - ring = 1; let skill = settings.skill; if (skill == undefined) skill = 'acr'; - else iconSrc = "modules/MaterialDeck/img/token/skills/" + skill + ".png"; + else iconSrc = "modules/MaterialDeck/img/token/skills/" + (skill.startsWith('lor')? 'lor' : skill) + ".png"; } else if (settings.onClick == 'center' || settings.onClick == 'centerSelect') { overlay = true; @@ -835,7 +841,7 @@ export class TokenControl{ const item = items[itemNr]; if (item != undefined) { - tokenHelper.rollItem(item); + tokenHelper.rollItem(item, settings); } }