diff --git a/css/bol.css b/css/bol.css index 00cb953e..8ff330bd 100644 --- a/css/bol.css +++ b/css/bol.css @@ -245,6 +245,9 @@ .bol input::placeholder { color: lightgray; } +.bol .property { + margin-top: 2px; +} /* ----------------------------------------- */ /* LOCAL FONTS */ /* ----------------------------------------- */ @@ -282,7 +285,14 @@ overflow-y: auto; } .items-list .item-header { - font-family: "CCMeanwhile", cursive; + font-family: 'Signika', sans-serif; + font-size: 1em; + color: #4b4a44; + background-color: lightgray; +} +.items-list .item-header .item-name { + font-family: "Wolfsbane2Expanded", cursive; + font-size: 1.5em; } .items-list .item { min-height: 30px; @@ -293,13 +303,41 @@ } .items-list .item .item-image { flex: 0 0 30px; - margin-right: 5px; + padding: 0; + margin: 0 5px 0 0; + height: 30px; + width: 30px; + min-height: 30px; + min-width: 30px; } .items-list .item .item-image img { + padding: 0; margin: 0; border: none; + height: 30px; + width: 30px; + min-height: 30px; + min-width: 30px; } -.items-list .item .item-name { +.items-list .item .item-image.roll-weapon, +.items-list .item .item-image.roll-career { + background-color: transparent; + background-image: url("../../../icons/svg/dice-target.svg") !important; + background-size: 30px 30px; + background-repeat: no-repeat; + background-position: center; + cursor: pointer; +} +.items-list .item .item-image.roll-weapon:hover, +.items-list .item .item-image.roll-career:hover { + background-color: gray; +} +.items-list .item .item-image.roll-weapon:hover img, +.items-list .item .item-image.roll-career:hover img { + visibility: hidden; +} +.items-list .item .item-name, +.items-list .item .item-field { margin: 0; } .items-list .item .item-controls-1 { @@ -315,8 +353,86 @@ .items-list .item .item-control { color: #4b4a44; } +/* ----------------------------------------- */ +/* Premade colors */ +/* ----------------------------------------- */ +.light { + color: lightgray; +} +.bg-light { + background: lightgray; +} +.darkgray { + color: #23221d; +} +.bg-darkgray { + background: #23221d; + color: #fff; +} +.darkbrown { + color: #464331c4; +} +.bg-darkbrown { + background: #464331c4; + color: #fff; +} +.darkslate { + color: darkslategray; +} +.bg-darkslate { + background: darkslategray; + color: #fff; +} +.darkgreen { + color: #003c1e; +} +.bg-darkgreen { + background: #003c1e; + color: #fff; +} +.darkblue { + color: midnightblue; +} +.bg-darkblue { + background: midnightblue; + color: #fff; +} +.blue { + color: #009ee0; +} +.bg-blue { + background: #009ee0; + color: #fff; +} +.green { + color: #44a12b; +} +.bg-green { + background: #44a12b; + color: #fff; +} +.black { + color: #000; +} +.bg-black { + background: #000; + color: #fff; +} +.red { + color: #cd071e; +} +.bg-red { + background: #cd071e; + color: #fff; +} +.purple { + color: purple; +} +.bg-purple { + background: purple; + color: #fff; +} .bol.sheet .window-content { - background: white; height: 100%; padding: 5px; overflow-y: hidden; @@ -395,10 +511,11 @@ min-height: 700px; height: 700px; } -.bol.sheet.actor .window-content { +.bol.sheet.actor .window-content form { background-image: url("/systems/bol/ui/logo.webp"); background-repeat: no-repeat; background-size: 190px 115px; + background-color: white; } .bol.sheet.actor .window-content form .sidebar { padding-top: 115px; @@ -496,7 +613,7 @@ .bol.sheet.actor .header-field-label, .bol.sheet.actor .stat-label { font-weight: bold; - font-family: "Wolfsbane2Expanded", serif; + font-family: "Wolfsbane2Expanded", cursive; font-size: 2rem; font-variant: small-caps; } @@ -526,6 +643,38 @@ min-width: 460px; min-height: 400px; } +.bol.sheet.item h1 input.itemname { + font-family: "Wolfsbane2Expanded", cursive; +} +.bol.sheet.item .item-properties { + flex: 0 0 150px; + margin: 5px 5px 5px 0; + padding-right: 5px; + border-right: 1px groove #eeede0; +} +.bol.sheet.item .item-properties .form-group { + margin: 0; +} +.bol.sheet.item .item-properties .form-group label { + line-height: 20px; +} +.bol.sheet.item .item-properties .form-group input { + text-align: right; +} +.bol.sheet.item .item-properties .properties-list { + list-style: none; + margin: 0; + padding: 0; +} +.bol.sheet.item .item-properties .properties-list li { + margin: 3px 0; + padding: 0 2px; + background: rgba(0, 0, 0, 0.05); + border: 1px groove #eeede0; + text-align: center; + font-size: 12px; + line-height: 18px; +} .editor, .editor-content { height: 100%; @@ -541,9 +690,8 @@ color: darkgreen; } .chat-message .chat-icon { - border: 0; - padding: 2px 6px 2px 2px; - float: left; + flex: 0 0 64px; + border: 1px outset lightgray; width: 64px; height: 64px; } diff --git a/lang/en.json b/lang/en.json index 9d6baad1..83fc1754 100644 --- a/lang/en.json +++ b/lang/en.json @@ -19,6 +19,7 @@ "BOL.resources.faith": "Foi", "BOL.resources.creation": "Création", "BOL.resources.power": "Pouvoir", + "BOL.resources.villainy": "Vilénie", "BOL.traits.xp": "Expérience", "BOL.ui.tab.stats": "Attributs", @@ -43,26 +44,45 @@ "BOL.ui.unequip": "Déséquiper", "BOL.ui.equip": "Equiper", "BOL.ui.delete": "Supprimer", + "BOL.ui.roll" : "Utiliser", + "BOL.ui.protection" : "Protection", + "BOL.ui.blocking" : "Blocage", + "BOL.ui.range" : "Portée", + "BOL.ui.quantity" : "Quantité", + "BOL.ui.weight" : "Poids", + "BOL.ui.price": "Prix", "BOL.featureCategory.origins": "Origines", "BOL.featureCategory.races": "Races", - "BOL.featureCategory.careers": "Carrieres", + "BOL.featureCategory.careers": "Carrières", "BOL.featureCategory.boons": "Avantages", - "BOL.featureCategory.flaws": "Desavantages", + "BOL.featureCategory.flaws": "Désavantages", "BOL.featureCategory.languages": "Langages", - "BOL.itemCategory.equipment": "Equipement", + "BOL.featureSubtypes.origin": "Origine", + "BOL.featureSubtypes.race": "Race", + "BOL.featureSubtypes.career": "Carrière", + "BOL.featureSubtypes.boon": "Avantage", + "BOL.featureSubtypes.flaw": "Désavantage", + "BOL.featureSubtypes.language": "Langage", + + "BOL.itemCategory.equipment": "Équipement", "BOL.itemCategory.consumable": "Consommable", "BOL.itemCategory.spell": "Sort", "BOL.itemCategory.mount": "Monture", "BOL.itemCategory.vehicle": "Véhicule", "BOL.itemCategory.other": "Autre", + "BOL.combatCategory.protections": "Protections", + "BOL.combatCategory.shields": "Boucliers", + "BOL.combatCategory.melee": "Armes de contact", + "BOL.combatCategory.ranged": "Armes à distance", + "BOL.equipmentCategory.weapon": "Arme", "BOL.equipmentCategory.protection": "Protection", "BOL.equipmentCategory.jewel": "Bijou", "BOL.equipmentCategory.scroll": "Parchemin", - "BOL.equipmentCategory.ammunition": "munition", + "BOL.equipmentCategory.ammunition": "Munition", "BOL.equipmentCategory.container": "Conteneur", "BOL.equipmentCategory.currency": "Monnaie", "BOL.equipmentCategory.other": "Autre", @@ -116,6 +136,14 @@ "BOL.itemSoak.formula": "Formule", "BOL.itemSoak.value": "Valeur", + "BOL.range.PointBlank": "Bout portant", + "BOL.range.Short": "Courte", + "BOL.range.Medium": "Moyenne", + "BOL.range.Long": "Long", + "BOL.range.VeryLong": "Très longue", + "BOL.range.Extreme": "Extrême", + "BOL.range.Maximum": "Maximale", + "Careers": "Carrieres", "Name": "Nom", diff --git a/lang/fr.json b/lang/fr.json index 9d6baad1..2f47a087 100644 --- a/lang/fr.json +++ b/lang/fr.json @@ -19,6 +19,7 @@ "BOL.resources.faith": "Foi", "BOL.resources.creation": "Création", "BOL.resources.power": "Pouvoir", + "BOL.resources.villainy": "Vilénie", "BOL.traits.xp": "Expérience", "BOL.ui.tab.stats": "Attributs", @@ -43,26 +44,50 @@ "BOL.ui.unequip": "Déséquiper", "BOL.ui.equip": "Equiper", "BOL.ui.delete": "Supprimer", + "BOL.ui.roll" : "Utiliser", + "BOL.ui.equipment" : "Équipement", + "BOL.ui.weapon" : "Arme", + "BOL.ui.melee" : "Arme de contact", + "BOL.ui.ranged" : "Arme à distance", + "BOL.ui.protection" : "Protection", + "BOL.ui.shield" : "Bouclier", + "BOL.ui.blocking" : "Blocage", + "BOL.ui.range" : "Portée", + "BOL.ui.quantity" : "Quantité", + "BOL.ui.weight" : "Poids", + "BOL.ui.price": "Prix", "BOL.featureCategory.origins": "Origines", "BOL.featureCategory.races": "Races", - "BOL.featureCategory.careers": "Carrieres", + "BOL.featureCategory.careers": "Carrières", "BOL.featureCategory.boons": "Avantages", - "BOL.featureCategory.flaws": "Desavantages", + "BOL.featureCategory.flaws": "Désavantages", "BOL.featureCategory.languages": "Langages", - "BOL.itemCategory.equipment": "Equipement", + "BOL.featureSubtypes.origin": "Origine", + "BOL.featureSubtypes.race": "Race", + "BOL.featureSubtypes.career": "Carrière", + "BOL.featureSubtypes.boon": "Avantage", + "BOL.featureSubtypes.flaw": "Désavantage", + "BOL.featureSubtypes.language": "Langage", + + "BOL.itemCategory.equipment": "Équipement", "BOL.itemCategory.consumable": "Consommable", "BOL.itemCategory.spell": "Sort", "BOL.itemCategory.mount": "Monture", "BOL.itemCategory.vehicle": "Véhicule", "BOL.itemCategory.other": "Autre", + "BOL.combatCategory.protections": "Protections", + "BOL.combatCategory.shields": "Boucliers", + "BOL.combatCategory.melee": "Armes de contact", + "BOL.combatCategory.ranged": "Armes à distance", + "BOL.equipmentCategory.weapon": "Arme", "BOL.equipmentCategory.protection": "Protection", "BOL.equipmentCategory.jewel": "Bijou", "BOL.equipmentCategory.scroll": "Parchemin", - "BOL.equipmentCategory.ammunition": "munition", + "BOL.equipmentCategory.ammunition": "Munition", "BOL.equipmentCategory.container": "Conteneur", "BOL.equipmentCategory.currency": "Monnaie", "BOL.equipmentCategory.other": "Autre", @@ -116,6 +141,14 @@ "BOL.itemSoak.formula": "Formule", "BOL.itemSoak.value": "Valeur", + "BOL.range.PointBlank": "Bout portant", + "BOL.range.Short": "Courte", + "BOL.range.Medium": "Moyenne", + "BOL.range.Long": "Long", + "BOL.range.VeryLong": "Très longue", + "BOL.range.Extreme": "Extrême", + "BOL.range.Maximum": "Maximale", + "Careers": "Carrieres", "Name": "Nom", diff --git a/module/actor/actor-sheet.js b/module/actor/actor-sheet.js index 4fa7ef10..2432c983 100644 --- a/module/actor/actor-sheet.js +++ b/module/actor/actor-sheet.js @@ -31,7 +31,6 @@ export class BoLActorSheet extends ActorSheet { html.find('.item-edit').click(ev => { const li = $(ev.currentTarget).parents(".item"); const item = this.actor.items.get(li.data("itemId")); - console.log(item); item.sheet.render(true); }); html.find('.roll-attribute').click(ev => { @@ -64,51 +63,17 @@ export class BoLActorSheet extends ActorSheet { /** @override */ getData(options) { - console.debug("getData"); - const actor = super.getData(options); - console.log(actor.data); - actor.data.details = actor.data.data.details; - actor.data.attributes = Object.values(actor.data.data.attributes); - actor.data.aptitudes = Object.values(actor.data.data.aptitudes); - actor.data.resources = Object.values(actor.data.data.resources); - actor.data.equipment = actor.data.items.filter(i => i.type === "item" || i.type == 'weapon' || i.type == 'armor'); - actor.data.weapons = duplicate(actor.data.items.filter(i => i.type == 'weapon' )); - actor.data.armors = duplicate(actor.data.items.filter(i => i.type == 'armor' )); - - actor.data.features = { - "careers" : { - "label" : "BOL.featureCategory.careers", - "ranked" : true, - "items" : actor.data.items.filter(i => i.type === "feature" && i.data.subtype === "career") - }, - "origins" : { - "label" : "BOL.featureCategory.origins", - "ranked" : false, - "items" : actor.data.items.filter(i => i.type === "feature" && i.data.subtype === "origin") - }, - "races" : { - "label" : "BOL.featureCategory.races", - "ranked" : false, - "items" : actor.data.items.filter(i => i.type === "feature" && i.data.subtype === "race") - }, - "boons" : { - "label" : "BOL.featureCategory.boons", - "ranked" : false, - "items" : actor.data.items.filter(i => i.type === "feature" && i.data.subtype === "boon") - }, - "flaws" : { - "label" : "BOL.featureCategory.flaws", - "ranked" : false, - "items" : actor.data.items.filter(i => i.type === "feature" && i.data.subtype === "flaw") - }, - "languages" : { - "label" : "BOL.featureCategory.languages", - "ranked" : false, - "items" : actor.data.items.filter(i => i.type === "feature" && i.data.subtype === "language") - } + const actorData = super.getData(options); + actorData.data = { + details : this.actor.details, + attributes : this.actor.attributes, + aptitudes : this.actor.aptitudes, + resources : this.actor.resources, + equipment : this.actor.equipment, + combat : this.actor.buildCombat(), + features : this.actor.buildFeatures() }; - - return actor; + return actorData; } /* -------------------------------------------- */ diff --git a/module/actor/actor.js b/module/actor/actor.js index 27db311d..7b398fee 100644 --- a/module/actor/actor.js +++ b/module/actor/actor.js @@ -10,9 +10,6 @@ export class BoLActor extends Actor { /** @override */ prepareData() { super.prepareData(); - - console.debug("prepareData"); - const actorData = this.data; // console.log(actorData); // const data = actorData.data; @@ -25,12 +22,11 @@ export class BoLActor extends Actor { } } - // /** - // * Prepare Character type specific data - // */ - /* -------------------------------------------- */ + /** + * Prepare Character type specific data + */ _prepareCharacterData(actorData) { - let newVitality = 10 + this.data.data.attributes.vigor.value; + let newVitality = 10 + this.data.data.attributes.vigor.value; if ( newVitality != this.data.data.resources.hp.max) { this.data.data.resources.hp.max = newVitality; this.update( { 'data.resources.hp.max': newVitality}); @@ -38,18 +34,153 @@ export class BoLActor extends Actor { } /* -------------------------------------------- */ - getBoons() { - return this.data.items.filter(i => i.type === "feature" && i.data.subtype === "boon"); + get itemData(){ + return Array.from(this.data.items.values()).map(i => i.data); + } + get details() { + return this.data.data.details; + } + get attributes() { + return Object.values(this.data.data.attributes); + } + get aptitudes() { + return Object.values(this.data.data.aptitudes); + } + get resources() { + return Object.values(this.data.data.resources); + } + get boons() { + return this.itemData.filter(i => i.type === "feature" && i.data.subtype === "boon"); + } + get flaws() { + return this.itemData.filter(i => i.type === "feature" && i.data.subtype === "flaw"); + } + get careers() { + return this.itemData.filter(i => i.type === "feature" && i.data.subtype === "career"); + } + get origins() { + return this.itemData.filter(i => i.type === "feature" && i.data.subtype === "origin"); + } + get races() { + return this.itemData.filter(i => i.type === "feature" && i.data.subtype === "race"); + } + get languages() { + return this.itemData.filter(i => i.type === "feature" && i.data.subtype === "language"); + } + get features() { + return this.itemData.filter(i => i.type === "feature"); + } + get equipment() { + return this.itemData.filter(i => i.type === "item"); + } + get weapons() { + return this.itemData.filter(i => i.type === "item" && i.data.subtype === "weapon"); + } + get armors() { + return this.itemData.filter(i => i.type === "item" && i.data.subtype === "armor" && i.data.worn === true); + } + get helms() { + return this.itemData.filter(i => i.type === "item" && i.data.subtype === "helm" && i.data.worn === true); + } + get shields() { + return this.itemData.filter(i => i.type === "item" && i.data.subtype === "shield" && i.data.worn === true); + } + get protections() { + return this.armors.concat(this.helms) + } + get melee() { + return this.weapons.filter(i => i.data.properties.melee === true && i.data.worn === true); + } + get ranged() { + return this.weapons.filter(i => i.data.properties.ranged === true && i.data.worn === true); + } + buildFeatures(){ + return { + "careers": { + "label": "BOL.featureCategory.careers", + "ranked": true, + "items": this.careers + }, + "origins": { + "label": "BOL.featureCategory.origins", + "ranked": false, + "items": this.origins + }, + "races": { + "label": "BOL.featureCategory.races", + "ranked": false, + "items": this.races + }, + "boons": { + "label": "BOL.featureCategory.boons", + "ranked": false, + "items": this.boons + }, + "flaws": { + "label": "BOL.featureCategory.flaws", + "ranked": false, + "items": this.flaws + }, + "languages": { + "label": "BOL.featureCategory.languages", + "ranked": false, + "items": this.languages + } + }; + } + buildCombat(){ + return { + "melee" : { + "label" : "BOL.combatCategory.melee", + "weapon" : true, + "protection" : false, + "blocking" : false, + "ranged" : false, + "items" : this.melee + }, + "ranged" : { + "label" : "BOL.combatCategory.ranged", + "weapon" : true, + "protection" : false, + "blocking" : false, + "ranged" : true, + "items" : this.ranged + }, + "protections" : { + "label" : "BOL.combatCategory.protections", + "weapon" : false, + "protection" : true, + "blocking" : false, + "ranged" : false, + "items" : this.protections + }, + "shields" : { + "label" : "BOL.combatCategory.shields", + "weapon" : false, + "protection" : false, + "blocking" : true, + "ranged" : false, + "items" : this.shields + } + }; } /* -------------------------------------------- */ - getFlaws() { - return this.data.items.filter(i => i.type === "feature" && i.data.subtype === "flaw"); + buildRollData(mode, title) { + return { + mode : mode, + title : title, + actorId: this.id, + actorImg: this.img, + boons : this.boons, + flaws : this.flaws, + d6Bonus: 0, + d6Malus: 0, + rollMode: game.settings.get("core", "rollMode"), + optionsBonusMalus: BoLUtility.buildListOptions(-8, +2), + bonusMalus: 0 + } } - /* -------------------------------------------- */ - getCareers() { - return this.data.items.filter(i => i.type === "feature" && i.data.subtype === "career"); - } - /* -------------------------------------------- */ + saveRollData( rollData) { this.currentRollData = rollData; } @@ -61,20 +192,8 @@ export class BoLActor extends Actor { attr = this.data.data.aptitudes[attrKey]; } if (attr) { - let rollData = { - mode : "attribute", - actorId: this.id, - actorImg: this.img, - attribute: duplicate(attr), - boons : this.getBoons(), - flaws : this.getFlaws(), - d6Bonus: 0, - d6Malus: 0, - rollMode: game.settings.get("core", "rollMode"), - title: game.i18n.localize(attr.label), - optionsBonusMalus: BoLUtility.buildListOptions(-8, +2), - bonusMalus: 0 - } + let rollData = this.buildRollData("attribute", game.i18n.localize(attr.label)); + rollData.attribute = duplicate(attr); let rollDialog = await BoLRollDialog.create( this, rollData); rollDialog.render( true ); } else { @@ -86,22 +205,10 @@ export class BoLActor extends Actor { async rollCareer( careerId ) { let career = BoLUtility.data(this.data.items.find( item => item.type == 'feature' && item.id == careerId)); if (career) { - let rollData = { - mode : "career", - actorId: this.id, - actorImg: this.img, - career : career, - rollAttribute: 'mind', - attributes : duplicate(this.data.data.attributes), - boons : this.getBoons(), - flaws : this.getFlaws(), - d6Bonus: 0, - d6Malus: 0, - rollMode: game.settings.get("core", "rollMode"), - title: `${career.name} : ${career.data.rank}`, - optionsBonusMalus: BoLUtility.buildListOptions(-8, +2), - bonusMalus: 0 - } + let rollData = this.buildRollData("career", `${career.name} : ${career.data.rank}`); + rollData.career = career; + rollData.rollAttribute = 'mind'; + rollData.attributes = duplicate(this.data.data.attributes); let rollDialog = await BoLRollDialog.create( this, rollData); rollDialog.render( true ); } else { @@ -111,35 +218,24 @@ export class BoLActor extends Actor { /* -------------------------------------------- */ async rollWeapon( weaponId ) { - let weapon = BoLUtility.data(this.data.items.find( item => item.type == 'weapon' && item.id == weaponId)); + let weapon = BoLUtility.data(this.data.items.find( item => item.type == 'item' && item.id == weaponId)); if (weapon) { let target = BoLUtility.getTarget(); - if ( !target) { - ui.notifications.warn("You must have a target to attack with a Weapon"); - return; - } - let objectDefender = BoLUtility.data(game.actors.get(target.data.actorId)); - objectDefender = mergeObject(objectDefender, target.data.actorData); - let rollData = { - mode : "weapon", - actorId: this.id, - actorImg: this.img, - weapon : weapon, - target: target, - isRanged: BoLUtility.isRangedWeapon( weapon ), - defender: objectDefender, - boons : this.getBoons(), - flaws : this.getFlaws(), - rollAttribute: 'agility', - attributes: duplicate(this.data.data.attributes), // For damage bonus - d6Bonus: 0, - d6Malus: 0, - rollMode: game.settings.get("core", "rollMode"), - title: weapon.name, - rangeModifier: 0, - optionsBonusMalus: BoLUtility.buildListOptions(-8, +2), - bonusMalus: 0 - } + // if ( !target) { + // ui.notifications.warn("You must have a target to attack with a Weapon"); + // return; + // } + let objectDefender = (target) ? BoLUtility.data(game.actors.get(target.data.actorId)) : null; + objectDefender = (objectDefender) ? mergeObject(objectDefender, target.data.actorData) : null; + let rollData = this.buildRollData("weapon", weapon.name); + rollData.weapon = weapon; + rollData.target = target; + rollData.isRanged = BoLUtility.isRangedWeapon( weapon ); + rollData.defender = objectDefender; + rollData.rollAttribute = 'agility'; + rollData.attributes = duplicate(this.data.data.attributes); // For damage bonus + rollData.rangeModifier = 0; + if ( weapon.data.type == 'melee') { rollData.aptitude = duplicate(this.data.data.aptitudes.melee); } else { diff --git a/module/bol.js b/module/bol.js index 01183488..b2058e0c 100644 --- a/module/bol.js +++ b/module/bol.js @@ -14,7 +14,8 @@ Hooks.once('init', async function () { game.bol = { BoLActor, - BoLItem + BoLItem, + config:BOL }; /** diff --git a/module/item/item-sheet.js b/module/item/item-sheet.js index 455dabe7..97d235f7 100644 --- a/module/item/item-sheet.js +++ b/module/item/item-sheet.js @@ -31,12 +31,14 @@ export class BoLItemSheet extends ItemSheet { /** @override */ getData() { - const objectData = BoLUtility.data(this.object); + const objectData = BoLUtility.data(this.item); + // const objectData = BoLUtility.data(this.object); - let itemData = foundry.utils.deepClone(BoLUtility.templateData(this.object)); + let itemData = foundry.utils.deepClone(BoLUtility.templateData(this.item)); let formData = { title: this.title, id: this.id, + config: game.bol.config, type: objectData.type, img: objectData.img, name: objectData.name, @@ -46,7 +48,9 @@ export class BoLItemSheet extends ItemSheet { limited: this.object.limited, options: this.options, owner: this.document.isOwner, - isGM: game.user.isGM + isGM: game.user.isGM, + itemProperties : this.item.itemProperties + } console.log("ITEMDATA", formData); this.options.editable = !(this.object.data.origin == "embeddedItem"); @@ -73,4 +77,5 @@ export class BoLItemSheet extends ItemSheet { if (!this.options.editable) return; // Roll handlers, click handlers, etc. would go here. } + } diff --git a/module/item/item.js b/module/item/item.js index 0da840eb..262e6149 100644 --- a/module/item/item.js +++ b/module/item/item.js @@ -8,11 +8,33 @@ export class BoLItem extends Item { */ prepareData() { super.prepareData(); - console.debug("Item prepareData"); + // console.debug("Item prepareData"); // Get the Item's data const itemData = this.data; - console.log(itemData); + // console.log(itemData); const actorData = this.actor ? this.actor.data : {}; const data = itemData.data; } + + get properties() { + return this.data.properties; + } + + /* -------------------------------------------- */ + + /** + * Get the Array of item properties which are used in the small sidebar of the description tab + * @return {Array} + * @private + */ + get itemProperties() { + const props = []; + if ( this.data.type === "item" ) { + const entries = Object.entries(this.data.data.properties); + props.push(...entries.filter(e => e[1] === true).map(e => { return game.bol.config.itemProperties[e[0]] })); + } + return props.filter(p => !!p); + } + + } diff --git a/module/system/bol-utility.js b/module/system/bol-utility.js index f9b0b14f..da69aa9a 100644 --- a/module/system/bol-utility.js +++ b/module/system/bol-utility.js @@ -33,12 +33,13 @@ export class BoLUtility { /* -------------------------------------------- */ static buildListOptions(min, max) { - let options = "" + let options = []; for (let i = min; i <= max; i++) { - options += `` + options.push(``); } - return options; + return options.join(""); } + /* -------------------------------------------- */ static async showDiceSoNice(roll, rollMode) { if (game.modules.get("dice-so-nice")?.active) { diff --git a/module/system/config.js b/module/system/config.js index 5f513c4c..54e557bc 100644 --- a/module/system/config.js +++ b/module/system/config.js @@ -19,7 +19,7 @@ BOL.itemCategories = { "other" : "BOL.itemCategory.other" } -BOL.equipmentCategory = { +BOL.equipmentCategories = { "weapon" : "BOL.equipmentCategory.weapon", "protection" : "BOL.equipmentCategory.protection", "jewel" : "BOL.equipmentCategory.jewel", @@ -30,20 +30,20 @@ BOL.equipmentCategory = { "other" : "BOL.equipmentCategory.other" } -BOL.protectionCategory = { +BOL.protectionCategories = { "armor" : "BOL.protectionCategory.armor", "shield" : "BOL.protectionCategory.shield", "helm" : "BOL.protectionCategory.helm", "other" : "BOL.protectionCategory.other" } -BOL.weaponCategory = { +BOL.weaponCategories = { "melee" : "BOL.weaponCategory.melee", "ranged" : "BOL.weaponCategory.ranged", "other" : "BOL.weaponCategory.other" } -BOL.itemProperty = { +BOL.itemProperties = { "equipable" : "BOL.itemProperty.equipable", "protection" : "BOL.itemProperty.protection", "blocking" : "BOL.itemProperty.blocking", @@ -61,10 +61,10 @@ BOL.itemProperty = { "ranged" : "BOL.itemProperty.ranged", "weapon" : "BOL.itemProperty.weapon", "reloadable" : "BOL.itemProperty.reloadable", - "worn" : "BOL.itemProperty.worn" + "worn" : "BOL.itemProperty.worn", } -BOL.itemStat = { +BOL.itemStats = { "quantity" : "BOL.itemStat.quantity", "weight" : "BOL.itemStat.weight", "price" : "BOL.itemStat.price", @@ -93,6 +93,15 @@ BOL.itemSoak = { "value" : "BOL.itemSoak.value" } +BOL.featureSubtypes = { + "origin" : "BOL.featureSubtypes.origin", + "race" : "BOL.featureSubtypes.race", + "career" : "BOL.featureSubtypes.career", + "boon" : "BOL.featureSubtypes.boon", + "flaw" : "BOL.featureSubtypes.flaw", + "language" : "BOL.featureSubtypes.language" +} + BOL.itemIcons = { "item": "icons/containers/chest/chest-worn-oak-tan.webp", "capacity": "icons/sundries/scrolls/scroll-plain-tan-red.webp", diff --git a/module/system/roll-dialog.js b/module/system/roll-dialog.js index 7000c954..c252847b 100644 --- a/module/system/roll-dialog.js +++ b/module/system/roll-dialog.js @@ -5,8 +5,9 @@ export class BoLRollDialog extends Dialog { /* -------------------------------------------- */ static async create(actor, rollData ) { - let options = { classes: ["BoL"], width: 600, height: 320, 'z-index': 99999 }; - let html = await renderTemplate(`systems/bol/templates/roll/roll-dialog-${rollData.mode}.hbs`, rollData); + let options = { classes: ["bol", "dialog"], width: 600, height: 320, 'z-index': 99999 }; + // let html = await renderTemplate(`systems/bol/templates/roll/roll-dialog-${rollData.mode}.hbs`, rollData); + let html = await renderTemplate(`systems/bol/templates/roll/roll-dialog.hbs`, rollData); return new BoLRollDialog(actor, rollData, html, options ); } diff --git a/module/system/templates.js b/module/system/templates.js index fe39b68d..c7eb41df 100644 --- a/module/system/templates.js +++ b/module/system/templates.js @@ -17,10 +17,16 @@ export const preloadHandlebarsTemplates = async function () { "systems/bol/templates/item/parts/item-header.hbs", "systems/bol/templates/item/parts/properties/feature-properties.hbs", "systems/bol/templates/item/parts/properties/equipment-properties.hbs", + "systems/bol/templates/item/parts/properties/protection-properties.hbs", + "systems/bol/templates/item/parts/properties/shield-properties.hbs", + "systems/bol/templates/item/parts/properties/weapon-properties.hbs", "systems/bol/templates/item/parts/properties/armor-properties.hbs", "systems/bol/templates/item/parts/properties/melee-properties.hbs", "systems/bol/templates/item/parts/properties/ranged-properties.hbs", - "systems/bol/templates/item/parts/properties/item-properties.hbs" + "systems/bol/templates/item/parts/properties/item-properties.hbs", + // DIALOGS + "systems/bol/templates/roll/parts/roll-dialog-modifiers.hbs", + "systems/bol/templates/roll/parts/roll-dialog-attribute.hbs" ]; // Load the template parts diff --git a/packs/equipment.db b/packs/equipment.db index 0703d9e3..9b99833e 100644 --- a/packs/equipment.db +++ b/packs/equipment.db @@ -15,7 +15,7 @@ {"_id":"cS2LGlXLZegvRGOo","name":"Arbalète lourde","type":"item","img":"icons/weapons/crossbows/crossbow-golden-bolt.webp","data":{"subtype":"weapon","description":"
plus lourde et plus puissante qu’une arbalète normale, l’arbalète lourde est peu usitée en Lémurie, sauf comme arme de siège portative. Il faut 2 rounds complets pour charger une arbalète lourde.
","properties":{"ranged":true,"melee":false,"spell":false,"protection":false,"weapon":true,"armor":false,"helm":false,"shield":false,"equipable":true,"stackable":false,"activable":false,"consumable":false,"magical":false,"concealable":false,"ignoreshield":false,"2H":false,"reloadable":true,"bow":false,"crossbow":false,"powder":false,"throwing":false,"bashing":false,"2h":true,"damage":"d6B","range":45,"reload":2},"quantity":null,"weight":null},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"EEnCVoPAR7pMjRym":3},"flags":{}} {"_id":"d7UV55xQXXfMiGQI","name":"Fronde","type":"item","img":"icons/weapons/slings/slingshot-wood.webp","data":{"subtype":"weapon","description":"simple pièce de cuir équipée de lanières, une fronde permet de projeter de petites pierres ou des billes de plomb avec une certaine force. C’est une arme peu coûteuse et facile à fabriquer. Il existe une version plus puissante, montée au bout d’un bâton (ce qui en fait une arme à deux mains), qui permet des tirs à plus longue portée.
","properties":{"ranged":true,"melee":false,"spell":false,"protection":false,"weapon":true,"armor":false,"helm":false,"shield":false,"equipable":true,"stackable":false,"activable":false,"consumable":false,"magical":false,"concealable":false,"ignoreshield":false,"2H":false,"reloadable":true,"bow":false,"crossbow":false,"powder":false,"throwing":false,"bashing":false,"damage":"d6M","range":9,"reload":0},"quantity":null,"weight":null},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"EEnCVoPAR7pMjRym":3},"flags":{}} {"_id":"jjdzMgx8zru2A28V","name":"Armure moyenne","type":"item","img":"icons/equipment/chest/breastplate-layered-leather-studded-black.webp","data":{"subtype":"armor","description":"Ce type d’armure, compromis entre la maniabilité de l’armure légère et la protection de l’armure lourde, est le choix favori des aventuriers qui s’attendent à affronter des combats de manière régulière. Il peut s’agir d’une armure de cuir couvrant la majeure partie du corps, avec des parties en cuir bouilli pour protéger les points vitaux, ou d’une armure mêlant le cuir et la cotte de mailles, ou encore d’une cuirasse en acier, simple mais efficace.
Un personnage portant une armure moyenne peut généralement en ôter certaines parties pour la transformer en armure légère s’il le souhaite.
Si votre personnage préfère éviter les combats mais sait qu’il risque de ne pas y couper, vous souhaiterez peut-être qu’il bénéficie au moins d’une petite protection. La catégorie des armures légères comprend les différentes sortes d’armures de cuir et les chemises de mailles. Votre personnage pourrait ainsi porter un robuste gilet et des brassards en cuir, ou un pourpoint doublé, accompagné de bottes et de gants en cuir souple. À moins que vous ne décidiez qu’il soit vêtu d’une légère chemise de mailles et de rien d’autre.
Une armure légère est généralement dissimulable (à moins d’être inspecté de près ou d’avoir affaire à l’œil exercé d’un soldat vétéran) et ne vous désigne pas au premier regard comme un guerrier.
Si votre personnage préfère éviter les combats mais sait qu’il risque de ne pas y couper, vous souhaiterez peut-être qu’il bénéficie au moins d’une petite protection. La catégorie des armures légères comprend les différentes sortes d’armures de cuir et les chemises de mailles. Votre personnage pourrait ainsi porter un robuste gilet et des brassards en cuir, ou un pourpoint doublé, accompagné de bottes et de gants en cuir souple. À moins que vous ne décidiez qu’il soit vêtu d’une légère chemise de mailles et de rien d’autre.
Une armure légère est généralement dissimulable (à moins d’être inspecté de près ou d’avoir affaire à l’œil exercé d’un soldat vétéran) et ne vous désigne pas au premier regard comme un guerrier.
Un personnage ne peut bénéficier de son bouclier que s’il est conscient de l’attaque qui le vise, et donc s’il est prêt à la parer.
","properties":{"ranged":false,"melee":false,"spell":false,"protection":true,"weapon":false,"armor":false,"helm":false,"shield":true,"equipable":true,"stackable":false,"activable":false,"consumable":false,"magical":false,"concealable":false,"ignoreshield":false,"2H":false,"reloadable":false,"bow":false,"crossbow":false,"powder":false,"throwing":false,"bashing":false,"blocking":{"malus":-1,"nbAttacksPerRound":"1"}},"quantity":null,"weight":null},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"EEnCVoPAR7pMjRym":3},"flags":{}} {"_id":"pncWIrD5z7mk6dbc","name":"Massue","type":"item","img":"icons/weapons/clubs/club-simple-stone-purple.webp","data":{"subtype":"weapon","description":"la version lourde du gourdin. Une massue consiste en un solide manche en bois dont l’extrémité, plus volumineuse, sert à fracasser le crâne de ses adversaires, d’où son autre nom de casse-tête.
","properties":{"ranged":false,"melee":true,"spell":false,"protection":false,"weapon":true,"armor":false,"helm":false,"shield":false,"equipable":true,"stackable":false,"activable":false,"consumable":false,"magical":false,"concealable":false,"ignoreshield":false,"2H":false,"reloadable":false,"bow":false,"crossbow":false,"powder":false,"throwing":false,"bashing":false,"throwable":true,"range":3,"damage":"d6"},"quantity":null,"weight":null},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"EEnCVoPAR7pMjRym":3},"flags":{}} {"_id":"qG5Jlhjjh7vDtBB1","name":"Fléau","type":"item","img":"icons/weapons/maces/flail-triple-grey.webp","data":{"subtype":"weapon","description":"un fléau consiste en un manche de bois prolongé d’une chaîne, à l’extrémité de laquelle est fixée une boule hérissée de pointes métalliques. Les fléaux ne sont pas des armes employées couramment en Lémurie, mais les gladiateurs en utilisent parfois dans les arènes. Les attaques au fléau ignorent le bonus en défense accordé par l’emploi d’un bouclier.
","properties":{"ranged":false,"melee":true,"spell":false,"protection":false,"weapon":true,"armor":false,"helm":false,"shield":false,"equipable":true,"stackable":false,"activable":false,"consumable":false,"magical":false,"concealable":false,"ignoreshield":true,"2H":false,"reloadable":false,"bow":false,"crossbow":false,"powder":false,"throwing":false,"bashing":false,"damage":"d6"},"quantity":null,"weight":null},"effects":[],"folder":null,"sort":0,"permission":{"default":0,"EEnCVoPAR7pMjRym":3},"flags":{}} diff --git a/styles/bol.less b/styles/bol.less index 6debb17d..4eda36d9 100644 --- a/styles/bol.less +++ b/styles/bol.less @@ -2,6 +2,7 @@ @import "global/forms"; @import "global/typography"; @import "global/item-list"; +@import "global/colors"; @logo-width: 190px; @logo-height: 115px; @@ -11,7 +12,6 @@ @attributes-height: 64px; @footer-height: 30px; @sidebar-width: 250px; -@colorOlive: #4b4a44; .bol { &.sheet { @@ -29,6 +29,8 @@ min-height: 400px; } } + &.dialog { + } } .editor, .editor-content { @@ -49,9 +51,10 @@ } .chat-message .chat-icon { - border: 0; - padding: 2px 6px 2px 2px; - float: left; + flex : 0 0 64px; + border: 1px outset lightgray; + //padding: 2px 6px 2px 2px; + //float: left; width: 64px; height: 64px; } diff --git a/styles/components/actor.less b/styles/components/actor.less index eb48869d..e50315d6 100644 --- a/styles/components/actor.less +++ b/styles/components/actor.less @@ -1,9 +1,11 @@ .window-content { - background-image: url("/systems/bol/ui/logo.webp"); - background-repeat: no-repeat; - background-size: @logo-width @logo-height; form { + background-image: url("/systems/bol/ui/logo.webp"); + background-repeat: no-repeat; + background-size: @logo-width @logo-height; + background-color: white; + .sidebar { //background-color: green; //background-color: red; diff --git a/styles/components/common.less b/styles/components/common.less index c3715f33..c2c256d8 100644 --- a/styles/components/common.less +++ b/styles/components/common.less @@ -1,5 +1,5 @@ .window-content { - background: white; + //background: white; height: 100%; padding: 5px; overflow-y: hidden; diff --git a/styles/components/item.less b/styles/components/item.less index e69de29b..36eacf6f 100644 --- a/styles/components/item.less +++ b/styles/components/item.less @@ -0,0 +1,40 @@ +h1 { + input.itemname { + font-family: @font-charname; + } +} + +.item-properties { + flex: 0 0 150px; + margin: 5px 5px 5px 0; + padding-right: 5px; + border-right: @borderGroove; + + .form-group { + margin: 0; + + label { + line-height: 20px; + } + + input { + text-align: right; + } + } + + .properties-list { + list-style: none; + margin: 0; + padding: 0; + + li { + margin: 3px 0; + padding: 0 2px; + background: rgba(0, 0, 0, 0.05); + border: @borderGroove; + text-align: center; + font-size: 12px; + line-height: 18px; + } + } +} diff --git a/styles/global/colors.less b/styles/global/colors.less new file mode 100644 index 00000000..1e9f6d0d --- /dev/null +++ b/styles/global/colors.less @@ -0,0 +1,137 @@ +@c-white: #fff; +@c-black: #000; +//@c-bright: whitesmoke; +@c-bright: #E2F1F1; +@c-lightg: lightgray; +@c-darkg: #23221d; +@c-dark: #3c3c3c; +@c-darkslate: darkslategray; +@c-darkgreen: #003c1e; +@c-lightgreen: mintcream; +@c-darkblue: midnightblue; +@c-blue: #009ee0; +@c-green: #44a12b; +@c-red: #cd071e; +@c-purple: purple; +@c-darkred: darkred; +@c-border:#736953a6; +//@c-darkbrown: rgba(70, 67, 49, 0.93); +@c-darkbrown: #464331c4; +@c-shadow:#00000052; +@c-linkshadow : gray; + +@colorDark: #191813; +@colorFaint: #c9c7b8; +@colorBeige: #b5b3a4; +@colorTan: #7a7971; +@colorOlive: #4b4a44; +@colorCrimson: #44191A; +@lightGreen: #609b60; +@borderGroove: 1px groove #eeede0; +@borderGrooveGreen: 2px groove #003700; +//@borderGrooveOriginal: 2px groove #eeede0; + +@colorSuccess : darkgreen; +@colorCritical : green; +@colorFailure : darkred; +@colorFumble : red; +@colorDamage : orangered; +@colorRoll : darkslategrey; + +@colorGold : #caad27; + +/* ----------------------------------------- */ +/* Premade colors */ +/* ----------------------------------------- */ + +.light { + //color:whitesmoke; + //color:antiquewhite; + color: @c-lightg; +} +.bg-light { + background: @c-lightg; +} + +.darkgray { + color: @c-darkg; +} +.bg-darkgray { + background: @c-darkg; + color: @c-white; +} + +.darkbrown { + color: @c-darkbrown; +} + +.bg-darkbrown { + background: @c-darkbrown; + color: @c-white; +} + +.darkslate { + color: @c-darkslate; +} +.bg-darkslate { + background: @c-darkslate; + color: @c-white; +} +.darkgreen { + color: @c-darkgreen; +} + +.bg-darkgreen { + background: @c-darkgreen; + color: @c-white; +} + +.darkblue { + color: @c-darkblue; +} + +.bg-darkblue { + background: @c-darkblue; + color: @c-white; +} + +.blue { + color: @c-blue; +} + +.bg-blue { + background: @c-blue; + color: @c-white; +} + +.green { + color: @c-green; +} +.bg-green { + background: @c-green; + color: @c-white; +} + +.black { + color: @c-black; +} +.bg-black { + background: @c-black; + color: @c-white; +} + +.red { + color: @c-red; +} +.bg-red { + background: @c-red; + color: @c-white; +} + +.purple { + color: @c-purple; +} +.bg-purple { + background: @c-purple; + color: @c-white; +} diff --git a/styles/global/forms.less b/styles/global/forms.less index 85d56615..9271fb96 100644 --- a/styles/global/forms.less +++ b/styles/global/forms.less @@ -200,4 +200,8 @@ input::placeholder { color: lightgray; } + + .property { + margin-top: 2px; + } } \ No newline at end of file diff --git a/styles/global/item-list.less b/styles/global/item-list.less index 82f32696..ae23bb6f 100644 --- a/styles/global/item-list.less +++ b/styles/global/item-list.less @@ -6,7 +6,15 @@ overflow-y: auto; .item-header { - font-family: @font-handwrite; + font-family: @font-primary; + font-size: 1em; + //font-weight: 500; + color: @colorOlive; + background-color: lightgray; + .item-name { + font-family: @font-tertiary; + font-size: 1.5em; + } } .item { @@ -19,14 +27,40 @@ .item-image { flex: 0 0 30px; - margin-right: 5px; + padding: 0; + margin: 0 5px 0 0; + height:30px; + width:30px; + min-height:30px; + min-width:30px; img { + padding: 0; margin: 0; border: none; + height:30px; + width:30px; + min-height:30px; + min-width:30px; + } + &.roll-weapon, + &.roll-career { + background-color: transparent; + background-image: url("../../../icons/svg/dice-target.svg") !important; + background-size: 30px 30px; + background-repeat: no-repeat; + background-position: center; + cursor: pointer; + &:hover { + background-color: gray; + img { + visibility: hidden; + } + } } } - .item-name { + .item-name, + .item-field { margin: 0; } @@ -43,19 +77,5 @@ .item-control { color: @colorOlive; } - //.item-buttons { - // display: flex; - // flex-wrap: wrap; - // flex-direction: row; - // align-items: center; - // flex: 2; - // justify-content: flex-start; - //} - //.item-button { - // line-height: 1; - // font-size: 11px; - // flex: none; - // width: auto; - //} } } diff --git a/styles/global/typography.less b/styles/global/typography.less index 949be94d..ad207bfe 100644 --- a/styles/global/typography.less +++ b/styles/global/typography.less @@ -27,6 +27,7 @@ @font-primary: 'Signika', sans-serif; @font-secondary: 'Contrail One', cursive; -@font-tertiary: "Wolfsbane2Expanded", serif; +@font-tertiary: "Wolfsbane2Expanded", cursive; +@font-header: "Wolfsbane2", cursive; @font-charname: "Wolfsbane2Expanded", cursive; @font-handwrite: "CCMeanwhile", cursive; diff --git a/system.json b/system.json index a15d199e..bbbe7344 100644 --- a/system.json +++ b/system.json @@ -74,10 +74,10 @@ ], "gridDistance": 1.5, "gridUnits": "m", - "primaryTokenAttribute": "traits.hp", - "secondaryTokenAttribute": "traits.hero", + "primaryTokenAttribute": "resources.hp", + "secondaryTokenAttribute": "resources.hero", "url": "https://github.com/ZigmundKreud/bol", "manifest": "https://raw.githubusercontent.com/ZigmundKreud/bol/master/system.json", "download": "https://github.com/ZigmundKreud/bol/archive/refs/heads/master.zip", "license": "LICENSE.txt" -} +} \ No newline at end of file diff --git a/template.json b/template.json index 1860daf6..d7dfcde9 100644 --- a/template.json +++ b/template.json @@ -119,6 +119,12 @@ "label" : "BOL.resources.power", "value": 0, "max": 0 + }, + "villainy" : { + "key" : "villainy", + "label" : "BOL.resources.villainy", + "value": 5, + "max": 5 } } } @@ -128,15 +134,13 @@ } }, "Item": { - "types": ["item", "feature", "weapon", "armor"], + "types": ["item", "feature"], "templates": { "base": { + "category" : null, "subtype" : "default", "description": "", - "properties" : { - "d6B": false, - "d6M": false - } + "properties" : {} }, "equipment" : { "quantity": 1, @@ -164,9 +168,7 @@ } }, "item": { - "templates": ["base", "equipment"], - "quantity": 1, - "weight": 0 + "templates": ["base", "equipment"] }, "weapon": { "type": "", @@ -197,7 +199,11 @@ }, "feature": { "rank": 0, - "templates": ["base"] + "templates": ["base"], + "properties" : { + "d6B": false, + "d6M": false + } } } } diff --git a/templates/actor/parts/tabs/actor-combat.hbs b/templates/actor/parts/tabs/actor-combat.hbs index ec123310..ab6ac31e 100644 --- a/templates/actor/parts/tabs/actor-combat.hbs +++ b/templates/actor/parts/tabs/actor-combat.hbs @@ -1,17 +1,23 @@ -