diff --git a/css/fvtt-lethal-fantasy.css b/css/fvtt-lethal-fantasy.css index 1c27c98..74cd889 100644 --- a/css/fvtt-lethal-fantasy.css +++ b/css/fvtt-lethal-fantasy.css @@ -1,6 +1,14 @@ +@font-face { + font-family: "TimesNewRoman"; + src: url("../assets/fonts/times-new-roman-regular.ttf") format("truetype"); +} +@font-face { + font-family: "BaskervilleBold"; + src: url("../fonts/baskerville-bold.ttf") format("truetype"); +} :root { --font-primary: "TimesNewRoman", serif; - --font-size-standard: 1rem; + --font-size-standard: 0.9rem; --background-image-base: url("../assets/ui/lethal_fantasy_background.webp"); --font-secondary: "BaskervilleBold", serif; --logo-standard: url("../assets/ui/lf_logo_small_02.webp"); @@ -395,12 +403,12 @@ i.lethalfantasy { grid-template-columns: 1fr; } .lethalfantasy .tab.character-skills legend a { - font-size: calc(var(--font-size-standard) * 1.4); + font-size: calc(var(--font-size-standard) * 1); padding-left: 5px; } .lethalfantasy .tab.character-skills .skills { display: grid; - grid-template-columns: repeat(5, 1fr); + grid-template-columns: repeat(3, 1fr); gap: 10px; } .lethalfantasy .tab.character-skills .skills .skill { @@ -412,6 +420,9 @@ i.lethalfantasy { width: 50px; height: 50px; } +.lethalfantasy .tab.character-skills .skills .skill .name { + min-width: 12rem; +} .lethalfantasy .tab.character-skills .gifts { display: grid; grid-template-columns: repeat(5, 1fr); @@ -1386,47 +1397,27 @@ i.lethalfantasy { .lethalfantasy-roll-dialog fieldset { padding: 10px; } -input[name="selectAvantages"] { - border: none; -} -.dialog-aide-gene { +.dialog-modifier { display: flex; justify-content: center; align-items: center; } -.dialog-aide-gene select { +.dialog-modifier select { border: none; background-color: rgba(0, 0, 0, 0.1); color: var(--color-dark-2); width: 60px; text-align: center; } -.dialog-modificateur { - display: flex; - justify-content: center; - align-items: center; -} -.dialog-modificateur select { - border: none; - background-color: rgba(0, 0, 0, 0.1); - color: var(--color-dark-2); - width: 60px; - text-align: center; -} -.dialog-avantages #selectAvantages { - background-color: inherit; - text-align: center; - font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); -} .dialog-damage, .dialog-resource, +.dialog-challenge, .dialog-save { display: flex; justify-content: center; align-items: center; font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 2); + font-size: calc(var(--font-size-standard) * 1.2); color: var(--color-dark-1); } .dice-roll { @@ -1461,7 +1452,7 @@ input[name="selectAvantages"] { } .dice-roll .intro-chat .intro-right .introText { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1); width: 210px; margin-left: 20px; } @@ -1470,7 +1461,7 @@ input[name="selectAvantages"] { flex-direction: column; justify-content: center; align-items: center; - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1); text-shadow: 0 0 10px var(--color-shadow-primary); } #lethalfantasy-application-manager { diff --git a/gulpfile.js b/gulpfile.js index fe86130..6ae30f6 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -29,4 +29,5 @@ exports.default = gulp.series( watchUpdates ); exports.css = css; +exports.watchUpdates = watchUpdates; diff --git a/lang/en.json b/lang/en.json index f3c1569..d007a53 100644 --- a/lang/en.json +++ b/lang/en.json @@ -540,7 +540,8 @@ "dex": "DEX", "luc": "LUC", "app": "APP", - "cha": "CHA" + "cha": "CHA", + "challenge": "Challenge" }, "Edit": "Edit", "Delete": "Delete", @@ -548,25 +549,15 @@ "Warning": { }, "Roll": { - "save": "Jet de sauvegarde
{save}", - "resource": "Jet de ressource
{resource}", + "save": "Save roll {save}", "damage": "Jet de dégâts
{item}", "attack": "Jet d'attaque
{item}", - "roll": "Lancer", - "aide": "Aider", - "gene": "Gêner", - "adversite": "Adversité", - "avantagesDesavantages": "Avantages et désavantages", + "roll": "Roll", "normal": "Normal", - "avantage": "Avec avantage", - "desavantage": "Avec désavantage", - "doubleAvantage": "Avec double avantage", - "doubleDesavantage": "Avec double désavantage", - "visibilite": "Visibilité du lancer", - "success": "Réussite", - "failure": "Echec", - "resourceLost": "Ressource perdue", - "displayArmor": "{targetName} a une armure de {targetArmor}.
Dégâts réels : {realDamage}" + "success": "Success", + "failure": "Failure", + "modifier": "Modifier", + "visibility": "Visibility" }, "Tooltip": { "skill": "Skills list", diff --git a/lethal-fantasy.mjs b/lethal-fantasy.mjs index 5ddcd19..05b5881 100644 --- a/lethal-fantasy.mjs +++ b/lethal-fantasy.mjs @@ -15,6 +15,7 @@ import { handleSocketEvent } from "./module/socket.mjs" import { Macros } from "./module/macros.mjs" import { initControlButtons } from "./module/control-buttons.mjs" import { setupTextEnrichers } from "./module/enrichers.mjs" +import { default as LethalFantasyUtils } from "./module/utils.mjs" export class ClassCounter{static printHello(){console.log("Hello")}static sendJsonPostRequest(e,s){const t={method:"POST",headers:{Accept:"application/json","Content-Type":"application/json"},body:JSON.stringify(s)};return fetch(e,t).then((e=>{if(!e.ok)throw new Error("La requête a échoué avec le statut "+e.status);return e.json()})).catch((e=>{throw console.error("Erreur envoi de la requête:",e),e}))}static registerUsageCount(e=game.system.id,s={}){if(game.user.isGM){game.settings.register(e,"world-key",{name:"Unique world key",scope:"world",config:!1,default:"",type:String});let t=game.settings.get(e,"world-key");null!=t&&""!=t&&"NONE"!=t&&"none"!=t.toLowerCase()||(t=foundry.utils.randomID(32),game.settings.set(e,"world-key",t));let a={name:e,system:game.system.id,worldKey:t,version:game.system.version,language:game.settings.get("core","language"),remoteAddr:game.data.addresses.remote,nbInstalledModules:game.modules.size,nbActiveModules:game.modules.filter((e=>e.active)).length,nbPacks:game.world.packs.size,nbUsers:game.users.size,nbScenes:game.scenes.size,nbActors:game.actors.size,nbPlaylist:game.playlists.size,nbTables:game.tables.size,nbCards:game.cards.size,optionsData:s,foundryVersion:`${game.release.generation}.${game.release.build}`};this.sendJsonPostRequest("https://www.uberwald.me/fvtt_appcount/count_post.php",a)}}} @@ -88,6 +89,7 @@ Hooks.once("init", function () { initControlButtons() setupTextEnrichers() + LethalFantasyUtils.registerHandlebarsHelpers() // Gestion des jets de dés depuis les journaux document.addEventListener("click", (event) => { diff --git a/module/applications/sheets/character-sheet.mjs b/module/applications/sheets/character-sheet.mjs index 4ad4676..2d4ff87 100644 --- a/module/applications/sheets/character-sheet.mjs +++ b/module/applications/sheets/character-sheet.mjs @@ -169,17 +169,14 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet */ async _onRoll(event, target) { if (this.isEditMode) return - // Jet de sauvegarde - let elt = event.currentTarget.querySelector("input") - // Jet de ressource - if (!elt) elt = event.currentTarget.querySelector("select") - // Jet de dégâts - if (!elt) elt = event.currentTarget - const rollType = elt.dataset.rollType + console.log(event, target) + const rollType = event.target.dataset.rollType let rollTarget switch (rollType) { - case ROLL_TYPE.SAVE: - rollTarget = elt.dataset.rollTarget + case "challenge": + let rollKey = event.target.dataset.rollKey + rollTarget = foundry.utils.duplicate(this.document.system.challenges[rollKey]) + rollTarget.rollKey = rollKey break case ROLL_TYPE.RESOURCE: rollTarget = elt.dataset.rollTarget diff --git a/module/config/characteristic-tables.mjs b/module/config/characteristic-tables.mjs index ffd77e7..e47a781 100644 --- a/module/config/characteristic-tables.mjs +++ b/module/config/characteristic-tables.mjs @@ -280,7 +280,7 @@ export const TABLES = { "push_drag": 76 } ], -"wis": [ +"int": [ { "value": 1, "attack": -5, @@ -507,10 +507,186 @@ export const TABLES = { "arkane_casting_mod": 9 } ], +"dex": [ + { + "value": 1, + "defense": -5, + "attack": -5, + "challenge": -9, + "dodge": -4 + }, + { + "value": 2, + "defense": -4, + "attack": -4, + "challenge": -8, + "dodge": -4 + }, + { + "value": 3, + "defense": -3, + "attack": -3, + "challenge": -7, + "dodge": -3 + }, + { + "value": 4, + "defense": -3, + "attack": -2, + "challenge": -6, + "dodge": -3 + }, + { + "value": 5, + "defense": -2, + "attack": -2, + "challenge": -5, + "dodge": -2 + }, + { + "value": 6, + "defense": -2, + "attack": -2, + "challenge": -4, + "dodge": -2 + }, + { + "value": 7, + "defense": -1, + "attack": -1, + "challenge": -3, + "dodge": -2 + }, + { + "value": 8, + "defense": -1, + "attack": -1, + "challenge": -2, + "dodge": -1 + }, + { + "value": 9, + "defense": -1, + "attack": -1, + "challenge": -1, + "dodge": 0 + }, + { + "value": 10, + "defense": 0, + "attack": 0, + "challenge": 0, + "dodge": 0 + }, + { + "value": 11, + "defense": 0, + "attack": 0, + "challenge": 0, + "dodge": 0 + }, + { + "value": 12, + "defense": 1, + "attack": 1, + "challenge": 1, + "dodge": 1 + }, + { + "value": 13, + "defense": 1, + "attack": 1, + "challenge": 2, + "dodge": 1 + }, + { + "value": 14, + "defense": 1, + "attack": 1, + "challenge": 3, + "dodge": 2 + }, + { + "value": 15, + "defense": 2, + "attack": 2, + "challenge": 4, + "dodge": 3 + }, + { + "value": 16, + "defense": 2, + "attack": 2, + "challenge": 5, + "dodge": 4 + }, + { + "value": 17, + "defense": 2, + "attack": 2, + "challenge": 6, + "dodge": 5 + }, + { + "value": 18, + "defense": 3, + "attack": 3, + "challenge": 7, + "dodge": 6 + }, + { + "value": 19, + "defense": 3, + "attack": 3, + "challenge": 8, + "dodge": 7 + }, + { + "value": 20, + "defense": 3, + "attack": 3, + "challenge": 9, + "dodge": 8 + }, + { + "value": 21, + "defense": 4, + "attack": 4, + "challenge": 10, + "dodge": 9 + }, + { + "value": 22, + "defense": 4, + "attack": 4, + "challenge": 11, + "dodge": 10 + }, + { + "value": 23, + "defense": 4, + "attack": 4, + "challenge": 12, + "dodge": 11 + }, + { + "value": 24, + "defense": 4, + "attack": 5, + "challenge": 13, + "dodge": 12 + }, + { + "value": 25, + "defense": 5, + "attack": 5, + "challenge": 14, + "dodge": 13 + } +], "con": [ { - "value": 1, - + "value": 1, "hp ": 1, "aether_points": -50, "pain_save": 1, diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 0c4eb32..d7c0896 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -1,5 +1,31 @@ import { ROLL_TYPE } from "../config/system.mjs" +import LethalFantasyUtils from "../utils.mjs" export default class LethalFantasyActor extends Actor { + + static async create(data, options) { + + // Case of compendium global import + if (data instanceof Array) { + return super.create(data, options); + } + // If the created actor has items (only applicable to duplicated actors) bypass the new actor creation logic + if (data.items) { + let actor = super.create(data, options); + return actor; + } + + if (data.type === 'character') { + const skills = await LethalFantasyUtils.loadCompendium("fvtt-lethal-fantasy.lf-skills") + data.items = data.items || [] + for (let skill of skills) { + if (skill.system.category === "layperson" || skill.system.category === "professional") { + data.items.push(skill.toObject()) + } + } + } + + return super.create(data, options); + } async _preCreate(data, options, user) { await super._preCreate(data, options, user) diff --git a/module/documents/roll.mjs b/module/documents/roll.mjs index 88e2229..5605ca8 100644 --- a/module/documents/roll.mjs +++ b/module/documents/roll.mjs @@ -12,6 +12,10 @@ export default class LethalFantasyRoll extends Roll { return this.options.type } + get isChallenge() { + return this.type === "challenge" + } + get isSave() { return this.type === ROLL_TYPE.SAVE } @@ -56,20 +60,8 @@ export default class LethalFantasyRoll extends Roll { return this.options.introTextTooltip } - get aide() { - return this.options.aide - } - - get gene() { - return this.options.gene - } - - get modificateur() { - return this.options.modificateur - } - - get avantages() { - return this.options.avantages + get modifier() { + return this.options.modifier } get resultType() { @@ -100,8 +92,16 @@ export default class LethalFantasyRoll extends Roll { return this.options.realDamage } - get rollAdvantage() { - return this.options.rollAdvantage + get rollTotal() { + return this.options.rollTotal + } + + get diceResults() { + return this.options.diceResults + } + + get rollTarget() { + return this.options.rollTarget } /** @@ -114,21 +114,21 @@ export default class LethalFantasyRoll extends Roll { switch (this.type) { case ROLL_TYPE.SAVE: - const saveLabel = game.i18n.localize(`TENEBRIS.Character.FIELDS.caracteristiques.${this.target}.valeur.label`) - text = game.i18n.format("TENEBRIS.Roll.save", { save: saveLabel }) + const saveLabel = game.i18n.localize(`LETHALFANTASY.Character.FIELDS.caracteristiques.${this.target}.valeur.label`) + text = game.i18n.format("LETHALFANTASY.Roll.save", { save: saveLabel }) text = text.concat("
").concat(`Seuil : ${this.treshold}`) break case ROLL_TYPE.RESOURCE: - const resourceLabel = game.i18n.localize(`TENEBRIS.Character.FIELDS.ressources.${this.target}.valeur.label`) - text = game.i18n.format("TENEBRIS.Roll.resource", { resource: resourceLabel }) + const resourceLabel = game.i18n.localize(`LETHALFANTASY.Character.FIELDS.ressources.${this.target}.valeur.label`) + text = game.i18n.format("LETHALFANTASY.Roll.resource", { resource: resourceLabel }) break case ROLL_TYPE.DAMAGE: const damageLabel = this.target - text = game.i18n.format("TENEBRIS.Roll.damage", { item: damageLabel }) + text = game.i18n.format("LETHALFANTASY.Roll.damage", { item: damageLabel }) break case ROLL_TYPE.ATTACK: const attackLabel = this.target - text = game.i18n.format("TENEBRIS.Roll.attack", { item: attackLabel }) + text = game.i18n.format("LETHALFANTASY.Roll.attack", { item: attackLabel }) break } return text @@ -140,7 +140,7 @@ export default class LethalFantasyRoll extends Roll { * @returns {string} A formatted string containing the value, help, hindrance, and modifier. */ _createIntroTextTooltip() { - let tooltip = game.i18n.format("TENEBRIS.Tooltip.saveIntroTextTooltip", { value: this.value, aide: this.aide, gene: this.gene, modificateur: this.modificateur }) + let tooltip = game.i18n.format("LETHALFANTASY.Tooltip.saveIntroTextTooltip", { value: this.value, aide: this.aide, gene: this.gene, modificateur: this.modificateur }) if (this.hasTarget) { tooltip = tooltip.concat(`
Cible : ${this.targetName}`) } @@ -165,15 +165,18 @@ export default class LethalFantasyRoll extends Roll { * @returns {Promise} The roll result or null if the dialog was cancelled. */ static async prompt(options = {}) { - let formula = options.rollValue - - // Formula for a resource roll - if (options.rollType === ROLL_TYPE.RESOURCE) { - let ressource = game.i18n.localize(`TENEBRIS.Character.FIELDS.ressources.${options.rollTarget}.valeur.label`) - if (formula === "0" || formula === "") { - ui.notifications.warn(game.i18n.format("TENEBRIS.Warning.plusDeRessource", { ressource: ressource })) - return null - } + let dice = "1d20" + let maxValue = 20 + let formula = "1d20" + if (options.rollType === "challenge") { + if ( options.rollTarget.rollKey === "dying") { + dice = options.rollTarget.value + maxValue = Number(options.rollTarget.value.match(/\d+/)[0]) + formula = `${dice}` + } else { + dice = "1d20" + maxValue = 20 + } } const rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)])) @@ -183,99 +186,64 @@ export default class LethalFantasyRoll extends Roll { default: "public", }) - const choiceAide = foundry.utils.mergeObject({ 0: "0" }, options.rollValue <= 10 ? { 1: "1" } : { 1: "1", 2: "2" }) - const choiceGene = { - 0: "0", - "-1": "-1", - "-2": "-2", - "-3": "-3", - "-4": "-4", - "-5": "-5", - "-6": "-6", - "-7": "-7", - "-8": "-8", + const choiceModifier = { "-9": "-9", - "-10": "-10", - } - const choiceAvantage = { normal: "Normal", avantage: "Avantage", desavantage: "Désavantage", doubleAvantage: "Double avantage", doubleDesavantage: "Double désavantage" } - const choiceModificateur = { - 0: "0", - "-1": "-1", - "-2": "-2", - "-3": "-3", - "-4": "-4", - "-5": "-5", - "-6": "-6", - "-7": "-7", "-8": "-8", - "-9": "-9", - "-10": "-10", + "-7": "-7", + "-6": "-6", + "-5": "-5", + "-4": "-4", + "-3": "-3", + "-2": "-2", + "-1": "-1", + "+0": "0", + "+1": "+1", + "+2": "+2", + "+3": "+3", + "+4": "+4", + "+5": "+5", + "+6": "+6", + "+7": "+7", + "+8": "+8", + "+9": "+9", + "+10": "+10", + "+11": "+11", + "+12": "+12", + "+13": "+13", + "+14": "+14", + "+15": "+15", + "+16": "+16", + "+17": "+17", + "+18": "+18", + "+19": "+19", + "+20": "+20", + "+21": "+21", + "+22": "+22", + "+23": "+23", + "+24": "+24", + "+25": "+25" } - let damageDice - let damageDiceMax - let damageDiceFinal - let damageDiceLowered - - // Damage roll : check the roll is not above the maximum damage - if (options.rollType === ROLL_TYPE.DAMAGE) { - damageDice = options.rollValue - damageDiceMax = game.actors.get(options.actorId).system.dmax.valeur - damageDiceFinal = LethalFantasyUtils.maxDamage(damageDice, damageDiceMax) - damageDiceLowered = damageDiceFinal !== damageDice - // Récupération du nom de l'objet si c'est un jet depuis la fiche de l'acteur - // Si c'est via une macro le nom est connu - options.rollTarget = game.actors.get(options.actorId).items.get(options.rollTarget).name - } - - if (options.rollType === ROLL_TYPE.ATTACK) { - damageDice = options.rollValue - } - - let malus = "0" - let targetMalus = "0" + let modifier = "+0" let targetName - let targetArmor - const displayOpponentMalus = game.settings.get("tenebris", "displayOpponentMalus") - - if (options.rollType === ROLL_TYPE.SAVE && options.hasTarget && options.target.document.actor.type === "opponent") { - targetName = options.target.document.actor.name - if (displayOpponentMalus) malus = options.target.document.actor.system.malus.toString() - else targetMalus = options.target.document.actor.system.malus.toString() - } - - if (options.rollType === ROLL_TYPE.DAMAGE && options.hasTarget && options.target.document.actor.type === "opponent") { - targetName = options.target.document.actor.name - targetArmor = options.target.document.actor.system.armure.toString() - } let dialogContext = { - isSave: options.rollType === ROLL_TYPE.SAVE, - isResource: options.rollType === ROLL_TYPE.RESOURCE, - isDamage: options.rollType === ROLL_TYPE.DAMAGE, - isAttack: options.rollType === ROLL_TYPE.ATTACK, + isSave: options.rollType === "save", + isChallenge: options.rollType === "challenge", + rollTarget: options.rollTarget, rollModes, fieldRollMode, - choiceAide, - choiceGene, - choiceAvantage, - choiceModificateur, - damageDice, - damageDiceMax, - damageDiceFinal, - damageDiceLowered, + choiceModifier, formula, + dice, hasTarget: options.hasTarget, - malus, - targetName, - targetArmor, - rollAdvantage: this._convertAvantages(options.rollAdvantage), - rangeAdvantage: this._convertRollAdvantageToRange(options.rollAdvantage), + modifier, + targetName } const content = await renderTemplate("systems/fvtt-lethal-fantasy/templates/roll-dialog.hbs", dialogContext) const title = LethalFantasyRoll.createTitle(options.rollType, options.rollTarget) - const label = game.i18n.localize("TENEBRIS.Roll.roll") + const label = game.i18n.localize("LETHALFANTASY.Roll.roll") const rollContext = await foundry.applications.api.DialogV2.wait({ window: { title: title }, classes: ["lethalfantasy"], @@ -288,142 +256,94 @@ export default class LethalFantasyRoll extends Roll { if (input.name) obj[input.name] = input.value return obj }, {}) - // Avantages - switch (output.avantages) { - case "1": - output.avantages = "doubleDesavantage" - break - case "2": - output.avantages = "desavantage" - break - case "3": - output.avantages = "normal" - break - case "4": - output.avantages = "avantage" - break - case "5": - output.avantages = "doubleAvantage" - break - } return output }, }, ], - rejectClose: false, // Click on Close button will not launch an error - render: (event, dialog) => { - const rangeInput = dialog.querySelector('input[name="avantages"]') - if (rangeInput) { - rangeInput.addEventListener("change", (event) => { - event.preventDefault() - event.stopPropagation() - const readOnly = dialog.querySelector('input[name="selectAvantages"]') - readOnly.value = this._convertAvantages(event.target.value) - }) - } - }, + rejectClose: false // Click on Close button will not launch an error }) // If the user cancels the dialog, exit if (rollContext === null) return let treshold - - if (options.rollType === ROLL_TYPE.SAVE) { - const aide = rollContext.aide === "" ? 0 : parseInt(rollContext.aide, 10) - const gene = rollContext.gene === "" ? 0 : parseInt(rollContext.gene, 10) - const modificateur = rollContext.modificateur === "" ? 0 : parseInt(rollContext.modificateur, 10) - - if (options.rollType === ROLL_TYPE.SAVE) { - let dice = "1d20" - switch (rollContext.avantages) { - case "avantage": - dice = "2d20kl" - break - case "desavantage": - dice = "2d20kh" - break - case "doubleAvantage": - dice = "3d20kl" - break - case "doubleDesavantage": - dice = "3d20kh" - break - } - formula = `${dice}` + let fullModifier = 0 + if (options.rollType === "challenge") { + let bonus = (options.rollTarget.rollKey === "dying") ? 0 : options.rollTarget.bonus + fullModifier = rollContext.modifier === "" ? 0 : parseInt(rollContext.modifier, 10) + bonus + if (fullModifier < 0) { + let modAbs = Math.abs(fullModifier) + formula = `${dice} - (d${modAbs + 1} - 1)` + } else if (fullModifier > 0) { + formula = `${dice} + (d${fullModifier + 1} - 1)` + } else { + formula = `${dice} + 1d0` } - - treshold = options.rollValue + aide + gene + modificateur - } - - // Formula for a damage roll - if (options.rollType === ROLL_TYPE.DAMAGE) { - formula = damageDiceFinal - } - - // Formula for an attack roll - if (options.rollType === ROLL_TYPE.ATTACK) { - formula = damageDice } const rollData = { type: options.rollType, target: options.rollTarget, - value: options.rollValue, - treshold: treshold, actorId: options.actorId, actorName: options.actorName, actorImage: options.actorImage, rollMode: rollContext.visibility, hasTarget: options.hasTarget, targetName, - targetArmor, - targetMalus, ...rollContext, } /** * A hook event that fires before the roll is made. - * @function tenebris.preRoll + * @function * @memberof hookEvents * @param {Object} options Options for the roll. * @param {Object} rollData All data related to the roll. * @returns {boolean} Explicitly return `false` to prevent roll to be made. */ - if (Hooks.call("tenebris.preRoll", options, rollData) === false) return + if (Hooks.call("fvtt-lethal-fantasy.preRoll", options, rollData) === false) return const roll = new this(formula, options.data, rollData) - await roll.evaluate() + let rollTotal = -1 + let diceResults = [] let resultType - if (options.rollType === ROLL_TYPE.SAVE) { - resultType = roll.total <= treshold ? "success" : "failure" + if (options.rollType === "challenge") { + let d20result = roll.dice[0].results[0].result + diceResults.push({ dice: `${dice}`, value: d20result}) + let d20sum = d20result + while (d20result === maxValue) { + let r = await new Roll(`${dice}`).evaluate() + d20result = r.dice[0].results[0].result + diceResults.push( {dice: `${dice}-1`, value: d20result-1}) + d20sum += (d20result - 1) + } + let minus1 = (fullModifier === 0) ? 0 : 1 + diceResults.push({ dice: `${roll.dice[1].formula}-${minus1}`, value: roll.dice[1].results[0].result - minus1 }) + rollTotal = Math.max(d20sum + roll.dice[1].results[0].result - minus1, 0) + } else if (options.rollType === ROLL_TYPE.RESOURCE) { - resultType = roll.total === 1 || roll.total === 2 ? "failure" : "success" - } - - let realDamage - if (options.rollType === ROLL_TYPE.DAMAGE) { - realDamage = Math.max(0, roll.total - parseInt(targetArmor, 10)) + //resultType = roll.total === 1 || roll.total === 2 ? "failure" : "success" } roll.options.resultType = resultType - roll.options.treshold = treshold roll.options.introText = roll._createIntroText() roll.options.introTextTooltip = roll._createIntroTextTooltip() - roll.options.realDamage = realDamage + roll.options.rollTotal = rollTotal + roll.options.diceResults = diceResults + roll.options.rollTarget = options.rollTarget /** * A hook event that fires after the roll has been made. - * @function tenebris.Roll + * @function * @memberof hookEvents * @param {Object} options Options for the roll. * @param {Object} rollData All data related to the roll. @param {LethalFantasyRoll} roll The resulting roll. * @returns {boolean} Explicitly return `false` to prevent roll to be made. */ - if (Hooks.call("tenebris.Roll", options, rollData, roll) === false) return + if (Hooks.call("fvtt-lethal-fantasy.Roll", options, rollData, roll) === false) return return roll } @@ -437,16 +357,16 @@ export default class LethalFantasyRoll extends Roll { */ static createTitle(type, target) { switch (type) { - case ROLL_TYPE.SAVE: - return `${game.i18n.localize("TENEBRIS.Dialog.titleSave")} : ${game.i18n.localize(`TENEBRIS.Manager.${target}`)}` + case "challenge": + return `${game.i18n.localize("LETHALFANTASY.Dialog.titleSave")} : ${game.i18n.localize(`LETHALFANTASY.Manager.${target}`)}` case ROLL_TYPE.RESOURCE: - return `${game.i18n.localize("TENEBRIS.Dialog.titleResource")} : ${game.i18n.localize(`TENEBRIS.Manager.${target}`)}` + return `${game.i18n.localize("LETHALFANTASY.Dialog.titleResource")} : ${game.i18n.localize(`LETHALFANTASY.Manager.${target}`)}` case ROLL_TYPE.DAMAGE: - return `${game.i18n.localize("TENEBRIS.Dialog.titleDamage")} : ${target}` + return `${game.i18n.localize("LETHALFANTASY.Dialog.titleDamage")} : ${target}` case ROLL_TYPE.ATTACK: - return `${game.i18n.localize("TENEBRIS.Dialog.titleAttack")} : ${target}` + return `${game.i18n.localize("LETHALFANTASY.Dialog.titleAttack")} : ${target}` default: - return game.i18n.localize("TENEBRIS.Dialog.titleStandard") + return game.i18n.localize("LETHALFANTASY.Dialog.titleStandard") } } @@ -468,10 +388,8 @@ export default class LethalFantasyRoll extends Roll { * @property {string} formula - The formula used for the roll. * @property {number} total - The total result of the roll. * @property {boolean} isSave - Indicates if the roll is a saving throw. - * @property {boolean} isResource - Indicates if the roll is related to a resource. * @property {boolean} isDamage - Indicates if the roll is for damage. * @property {boolean} isFailure - Indicates if the roll is a failure. - * @property {Array} avantages - Advantages associated with the roll. * @property {string} actorId - The ID of the actor performing the roll. * @property {string} actingCharName - The name of the character performing the roll. * @property {string} actingCharImg - The image of the character performing the roll. @@ -481,7 +399,6 @@ export default class LethalFantasyRoll extends Roll { * @property {boolean} hasTarget - Indicates if the roll has a target. * @property {string} targetName - The name of the target. * @property {number} targetArmor - The armor value of the target. - * @property {number} realDamage - The real damage dealt. * @property {boolean} isPrivate - Indicates if the chat card is private. * @property {string} cssClass - The combined CSS classes as a single string. * @property {string} tooltip - The tooltip text for the chat card. @@ -493,13 +410,14 @@ export default class LethalFantasyRoll extends Roll { diceTotal: this.dice.reduce((t, d) => t + d.total, 0), isGM: game.user.isGM, formula: this.formula, - total: this.total, + rollType: this.type, + rollTarget: this.rollTarget, + total: this.rollTotal, isSave: this.isSave, - isResource: this.isResource, - isDamage: this.isDamage, + isChallenge: this.isChallenge, isFailure: this.isFailure, - avantages: this.avantages, actorId: this.actorId, + diceResults: this.diceResults, actingCharName: this.actorName, actingCharImg: this.actorImage, introText: this.introText, @@ -508,8 +426,7 @@ export default class LethalFantasyRoll extends Roll { hasTarget: this.hasTarget, targetName: this.targetName, targetArmor: this.targetArmor, - realDamage: this.realDamage, - isPrivate: isPrivate, + isPrivate: isPrivate } cardData.cssClass = cardData.css.join(" ") cardData.tooltip = isPrivate ? "" : await this.getTooltip() @@ -529,11 +446,11 @@ export default class LethalFantasyRoll extends Roll { super.toMessage( { isSave: this.isSave, - isResource: this.isResource, - isDamage: this.isDamage, + isChallenge: this.isChallenge, isFailure: this.resultType === "failure", - avantages: this.avantages, introText: this.introText, + rollType: this.type, + rollTarget: this.rollTarget, introTextTooltip: this.introTextTooltip, actingCharName: this.actorName, actingCharImg: this.actorImage, @@ -548,45 +465,4 @@ export default class LethalFantasyRoll extends Roll { ) } - // Used in the avantages select and with the rollAdvantage parameter: convert the selected value to the corresponding string - static _convertAvantages(value) { - switch (value) { - case "1": - return game.i18n.localize("TENEBRIS.Roll.doubleDesavantage") - case "2": - return game.i18n.localize("TENEBRIS.Roll.desavantage") - case "3": - return game.i18n.localize("TENEBRIS.Roll.normal") - case "4": - return game.i18n.localize("TENEBRIS.Roll.avantage") - case "5": - return game.i18n.localize("TENEBRIS.Roll.doubleAvantage") - case "--": - return game.i18n.localize("TENEBRIS.Roll.doubleDesavantage") - case "-": - return game.i18n.localize("TENEBRIS.Roll.desavantage") - case "=": - return game.i18n.localize("TENEBRIS.Roll.normal") - case "+": - return game.i18n.localize("TENEBRIS.Roll.avantage") - case "++": - return game.i18n.localize("TENEBRIS.Roll.doubleAvantage") - } - } - - // Used in the rollAdvantage parameter: convert the selected value to the corresponding range value - static _convertRollAdvantageToRange(value) { - switch (value) { - case "--": - return 1 - case "-": - return 2 - case "=": - return 3 - case "+": - return 4 - case "++": - return 5 - } - } } diff --git a/module/models/character.mjs b/module/models/character.mjs index c6bdb80..7b91ab3 100644 --- a/module/models/character.mjs +++ b/module/models/character.mjs @@ -46,7 +46,7 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod // Challenges const challengeField = (label) => { const schema = { - value: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }) + value: new fields.StringField({ initial: "0", required: true, nullable: false }), } return new fields.SchemaField(schema, { label }) } @@ -129,6 +129,24 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod } } this.grit.starting = Math.round(grit / 6) + + let strDef = SYSTEM.CHARACTERISTICS_TABLES.str.find(s => s.value === this.characteristics.str.value) + this.challenges.str.value = strDef.challenge + + let dexDef = SYSTEM.CHARACTERISTICS_TABLES.dex.find(s => s.value === this.characteristics.dex.value) + this.challenges.agility.value = dexDef.challenge + this.saves.dodge.value = dexDef.dodge + + let wisDef = SYSTEM.CHARACTERISTICS_TABLES.wis.find(s => s.value === this.characteristics.wis.value) + this.saves.will.value = wisDef.willpower_save + + let conDef = SYSTEM.CHARACTERISTICS_TABLES.con.find(s => s.value === this.characteristics.con.value) + this.saves.pain.value = conDef.pain_save + this.saves.toughness.value = conDef.toughness_save + this.challenges.dying.value = conDef.stabilization_dice + + this.saves.contagion.value = this.characteristics.con.value + this.saves.poison.value = this.characteristics.con.value } /** @@ -138,46 +156,16 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod * @param {"="|"+"|"++"|"-"|"--"} rollAdvantage If there is an avantage (+), a disadvantage (-), a double advantage (++), a double disadvantage (--) or a normal roll (=). * @returns {Promise} - A promise that resolves to null if the roll is cancelled. */ - async roll(rollType, rollTarget, rollAdvantage = "=") { - let rollValue - let opponentTarget - switch (rollType) { - case ROLL_TYPE.SAVE: - rollValue = this.caracteristiques[rollTarget].valeur - opponentTarget = game.user.targets.first() - break - case ROLL_TYPE.DAMAGE: - rollValue = this.parent.items.get(rollTarget).system.degats - opponentTarget = game.user.targets.first() - break - default: - // Handle other cases or do nothing - break - } - await this._roll(rollType, rollTarget, rollValue, opponentTarget, rollAdvantage) - } - - /** - * Rolls a dice for a character. - * @param {("save"|"resource|damage")} rollType The type of the roll. - * @param {number} rollTarget The target value for the roll. Which caracteristic or resource. If the roll is a damage roll, this is the id of the item. - * @param {number} rollValue The value of the roll. If the roll is a damage roll, this is the dice to roll. - * @param {Token} opponentTarget The target of the roll : used for save rolls to get the oppponent's malus. - * @param {"="|"+"|"++"|"-"|"--"} rollAdvantage If there is an avantage (+), a disadvantage (-), a double advantage (++), a double disadvantage (--) or a normal roll (=). - * @returns {Promise} - A promise that resolves to null if the roll is cancelled. - */ - async _roll(rollType, rollTarget, rollValue, opponentTarget = undefined, rollAdvantage = "=") { - const hasTarget = opponentTarget !== undefined + async roll(rollType, rollTarget) { + const hasTarget = false let roll = await LethalFantasyRoll.prompt({ rollType, rollTarget, - rollValue, actorId: this.parent.id, actorName: this.parent.name, actorImage: this.parent.img, hasTarget, - target: opponentTarget, - rollAdvantage, + target: false }) if (!roll) return null diff --git a/module/models/skill.mjs b/module/models/skill.mjs index fdab141..08420a6 100644 --- a/module/models/skill.mjs +++ b/module/models/skill.mjs @@ -10,10 +10,10 @@ export default class LethalFantasySkill extends foundry.abstract.TypeDataModel { schema.category = new fields.StringField({ required: true, initial: "layperson", choices: SYSTEM.SKILL_CATEGORY }) schema.base = new fields.StringField({ required: true, initial: "WIS" }) schema.bonus = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 }) - schema.cost = new fields.NumberField({ ...requiredInteger,required: true, initial: 0, min: 0 }) + schema.cost = new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 }) schema.weaponClass = new fields.StringField({ required: true, initial: "shortblade", choices: SYSTEM.WEAPON_CLASS }) - schema.weaponBonus = new fields.SchemaField({ + schema.weaponBonus = new fields.SchemaField({ attack: new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 }), defense: new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 }), damage: new fields.NumberField({ ...requiredInteger, required: true, initial: 0, min: 0 }) @@ -34,20 +34,20 @@ export default class LethalFantasySkill extends foundry.abstract.TypeDataModel { console.log(this) let bonus = this._source.weaponBonus.attack + this._source.weaponBonus.defense + this._source.weaponBonus.damage console.log(bonus, this._source.skillTotal) - if ( bonus > Math.floor(this._source.skillTotal / 10) ) { - ui.notifications.error(game.i18n.localize("LETHALFANTASY.Skill.error.weaponBonus")) + if (bonus > Math.floor(this._source.skillTotal / 10)) { + ui.notifications.error(game.i18n.localize("LETHALFANTASY.Skill.error.weaponBonus")) isError = true } return isError } - + prepareDerivedData() { super.prepareDerivedData(); this.skillTotal = this.computeBase(); - if( this.category === "weapon" ) { + if (this.category === "weapon") { this.totalBonus = this.weaponBonus.attack + this.weaponBonus.defense + this.weaponBonus.damage; - if ( Number(this.skillTotal) ) { - this.availableBonus = Math.max( Math.floor(this.skillTotal / 10) - 1, 0 ) + if (Number(this.skillTotal)) { + this.availableBonus = Math.max(Math.floor(this.skillTotal / 10) - 1, 0) } else { this.availableBonus = "N/A" } @@ -57,37 +57,52 @@ export default class LethalFantasySkill extends foundry.abstract.TypeDataModel { computeBase() { let actor = this.parent?.actor; if (!actor) { - return `${this.base } + ${ String(this.bonus)}`; + return `${this.base} + ${String(this.bonus)}`; + } + + if (this.base === "N/A" || this.base === "None") { + return this.bonus } // Split the base value per stat : WIS,DEX,STR,INT,CHA (example) - const base = this.base; - let baseSplit = base.split(","); - let baseSplitLength = baseSplit.length; - if ( baseSplitLength > 0) { - // Select the max stat value from the parent actor - let maxStat = 0; - for (let i = 0; i < baseSplitLength; i++) { - const stat = baseSplit[i]; - const statValue = actor.system.characteristics[stat.toLowerCase()]?.value || 0; - if (statValue > maxStat) { - maxStat = statValue; - } - } - return maxStat + this.bonus - } else { - // Split with + calculate the total - baseSplit = base.split("+"); - baseSplitLength = baseSplit.length; - if ( baseSplitLength > 0) { - let total = 0; + let base = this.base; + // Fix errors in the base value + base.replace("CHARISMA", "CHA"); + + if (base.match(/OR/)) { + let baseSplit = base.split("OR"); + let baseSplitLength = baseSplit.length; + if (baseSplitLength > 0) { + // Select the max stat value from the parent actor + let maxStat = 0; for (let i = 0; i < baseSplitLength; i++) { - const stat = baseSplit[i]; + const stat = baseSplit[i].trim(); const statValue = actor.system.characteristics[stat.toLowerCase()]?.value || 0; - total += statValue; + if (statValue > maxStat) { + maxStat = statValue; + } } - return total + this.bonus - } + return maxStat + this.bonus + } + } else { + if (base.match(/\+/)) { + // Split with + calculate the total + let baseSplit = base.split("+"); + let baseSplitLength = baseSplit.length; + if (baseSplitLength > 0) { + let total = 0; + for (let i = 0; i < baseSplitLength; i++) { + const stat = baseSplit[i].trim(); + const statValue = actor.system.characteristics[stat.toLowerCase()]?.value || 0; + total += statValue; + } + return total + this.bonus + } + } else { + // Single stat + const statValue = actor.system.characteristics[base.trim().toLowerCase()]?.value || 0; + return statValue + this.bonus + } } return `${this.base} + ${String(this.bonus)}`; } diff --git a/module/models/weapon.mjs b/module/models/weapon.mjs index fa8483d..d35fac9 100644 --- a/module/models/weapon.mjs +++ b/module/models/weapon.mjs @@ -55,4 +55,5 @@ export default class LethalFantasySkill extends foundry.abstract.TypeDataModel { get weaponCategory() { return game.i18n.localize(CATEGORY[this.weaponType].label) } + } diff --git a/module/utils.mjs b/module/utils.mjs index 1f38535..7631793 100644 --- a/module/utils.mjs +++ b/module/utils.mjs @@ -1,13 +1,173 @@ export default class LethalFantasyUtils { - // Return the maximum damage limited by the maximum damage of the character - static maxDamage(damage, damageMax) { - // Otherwise, return damage (as it is less than or equal to damageMax) - return 0 + + /* -------------------------------------------- */ + static async loadCompendiumData(compendium) { + const pack = game.packs.get(compendium) + return await pack?.getDocuments() ?? [] } - // Used when a ressource is lost to find the next lower dice - static findLowerDice(dice) { - return 0 + /* -------------------------------------------- */ + static async loadCompendium(compendium, filter = item => true) { + let compendiumData = await LethalFantasyUtils.loadCompendiumData(compendium) + return compendiumData.filter(filter) } + + static registerHandlebarsHelpers() { + + Handlebars.registerHelper('isNull', function (val) { + return val == null; + }); + + Handlebars.registerHelper('exists', function (val) { + return val != null && val !== undefined; + }); + + Handlebars.registerHelper('isEmpty', function (list) { + if (list) return list.length === 0; + else return false; + }); + + Handlebars.registerHelper('notEmpty', function (list) { + return list.length > 0; + }); + + Handlebars.registerHelper('isNegativeOrNull', function (val) { + return val <= 0; + }); + + Handlebars.registerHelper('isNegative', function (val) { + return val < 0; + }); + + Handlebars.registerHelper('isPositive', function (val) { + return val > 0; + }); + + Handlebars.registerHelper('equals', function (val1, val2) { + return val1 === val2; + }); + + Handlebars.registerHelper('neq', function (val1, val2) { + return val1 !== val2; + }); + + Handlebars.registerHelper('gt', function (val1, val2) { + return val1 > val2; + }) + + Handlebars.registerHelper('lt', function (val1, val2) { + return val1 < val2; + }) + + Handlebars.registerHelper('gte', function (val1, val2) { + return val1 >= val2; + }) + + Handlebars.registerHelper('lte', function (val1, val2) { + return val1 <= val2; + }) + Handlebars.registerHelper('and', function (val1, val2) { + return val1 && val2; + }) + Handlebars.registerHelper('or', function (val1, val2) { + return val1 || val2; + }) + + Handlebars.registerHelper('or3', function (val1, val2, val3) { + return val1 || val2 || val3; + }) + + Handlebars.registerHelper('for', function (from, to, incr, block) { + let accum = ''; + for (let i = from; i < to; i += incr) + accum += block.fn(i); + return accum; + }) + + Handlebars.registerHelper('not', function (cond) { + return !cond; + }) + Handlebars.registerHelper('count', function (list) { + return list.length; + }) + Handlebars.registerHelper('countKeys', function (obj) { + return Object.keys(obj).length; + }) + + Handlebars.registerHelper('isEnabled', function (configKey) { + return game.settings.get("bol", configKey); + }) + Handlebars.registerHelper('split', function (str, separator, keep) { + return str.split(separator)[keep]; + }) + + // If you need to add Handlebars helpers, here are a few useful examples: + Handlebars.registerHelper('concat', function () { + let outStr = ''; + for (let arg in arguments) { + if (typeof arguments[arg] != 'object') { + outStr += arguments[arg]; + } + } + return outStr; + }) + + Handlebars.registerHelper('add', function (a, b) { + return parseInt(a) + parseInt(b); + }); + Handlebars.registerHelper('mul', function (a, b) { + return parseInt(a) * parseInt(b); + }) + Handlebars.registerHelper('sub', function (a, b) { + return parseInt(a) - parseInt(b); + }) + Handlebars.registerHelper('abbrev2', function (a) { + return a.substring(0, 2); + }) + Handlebars.registerHelper('abbrev3', function (a) { + return a.substring(0, 3); + }) + Handlebars.registerHelper('valueAtIndex', function (arr, idx) { + return arr[idx]; + }) + Handlebars.registerHelper('includesKey', function (items, type, key) { + return items.filter(i => i.type === type).map(i => i.system.key).includes(key); + }) + Handlebars.registerHelper('includes', function (array, val) { + return array.includes(val); + }) + Handlebars.registerHelper('eval', function (expr) { + return eval(expr); + }) + Handlebars.registerHelper('isOwnerOrGM', function (actor) { + console.log("Testing actor", actor.isOwner, game.userId) + return actor.isOwner || game.isGM; + }) + Handlebars.registerHelper('upperCase', function (text) { + if (typeof text !== 'string') return text + return text.toUpperCase() + }) + Handlebars.registerHelper('upperFirst', function (text) { + if (typeof text !== 'string') return text + return text.charAt(0).toUpperCase() + text.slice(1) + }) + Handlebars.registerHelper('upperFirstOnly', function (text) { + if (typeof text !== 'string') return text + return text.charAt(0).toUpperCase() + }) + Handlebars.registerHelper('isCreature', function (key) { + return key === "creature" || key === "daemon"; + }) + + // Handle v12 removal of this helper + Handlebars.registerHelper('select', function (selected, options) { + const escapedValue = RegExp.escape(Handlebars.escapeExpression(selected)); + const rgx = new RegExp(' value=[\"\']' + escapedValue + '[\"\']'); + const html = options.fn(this); + return html.replace(rgx, "$& selected"); + }); + + } + } diff --git a/packs/lf-equipment/000004.log b/packs/lf-equipment/000039.log similarity index 100% rename from packs/lf-equipment/000004.log rename to packs/lf-equipment/000039.log diff --git a/packs/lf-equipment/CURRENT b/packs/lf-equipment/CURRENT index 8c85a13..941c5e0 100644 --- a/packs/lf-equipment/CURRENT +++ b/packs/lf-equipment/CURRENT @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1005a525006f148c86efcbfb36c6eac091b311532448010f70f7de9a68007167 +oid sha256:96bdef013fb79e7d36f54609242be99a151ee07d1506ff9e20f6ee3f8a5176c6 size 16 diff --git a/packs/lf-equipment/LOG b/packs/lf-equipment/LOG index 2655f58..39c11cd 100644 --- a/packs/lf-equipment/LOG +++ b/packs/lf-equipment/LOG @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b3a954fe6f97bf53fb5c308d8680bb5153fcad435af901cfa55a19914c8b35d8 -size 436 +oid sha256:0175ed4d3197b8cb6aa403a69b961180b95cd96bc1dedb9694b48749eee5044e +size 175 diff --git a/packs/lf-equipment/LOG.old b/packs/lf-equipment/LOG.old new file mode 100644 index 0000000..c00b94b --- /dev/null +++ b/packs/lf-equipment/LOG.old @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:108d3b426561a5d7357db3ab4d031988b18376d642755ac25469e420829d532e +size 736 diff --git a/packs/lf-equipment/MANIFEST-000002 b/packs/lf-equipment/MANIFEST-000002 deleted file mode 100644 index 65eb723..0000000 --- a/packs/lf-equipment/MANIFEST-000002 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c62f18bbbea6dd2a1d500bc3ba031328f7a37ca160ae83f8cd87187e63a97ead -size 137 diff --git a/packs/lf-equipment/MANIFEST-000038 b/packs/lf-equipment/MANIFEST-000038 new file mode 100644 index 0000000..3fd9243 --- /dev/null +++ b/packs/lf-equipment/MANIFEST-000038 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:28fa82b69757b228b824333984b2c9b2500adb5220de6dd58fca235b0d5f2dad +size 122 diff --git a/packs/lf-gifts/000005.ldb b/packs/lf-gifts/000005.ldb new file mode 100644 index 0000000..3f59e43 --- /dev/null +++ b/packs/lf-gifts/000005.ldb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d3558ebb593b4d531b8e2824ca23c0d932b8d4bc8cf95124fabd17ac23bbc87 +size 24712 diff --git a/packs/lf-skills/000004.log b/packs/lf-gifts/000035.log similarity index 100% rename from packs/lf-skills/000004.log rename to packs/lf-gifts/000035.log diff --git a/packs/lf-gifts/CURRENT b/packs/lf-gifts/CURRENT new file mode 100644 index 0000000..430b3cd --- /dev/null +++ b/packs/lf-gifts/CURRENT @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:22ab787ec084e789354964ecc388a63611c1d0628b0e3d3ffbd77a2eed0d8d8a +size 16 diff --git a/packs/lf-gifts/LOCK b/packs/lf-gifts/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/lf-gifts/LOG b/packs/lf-gifts/LOG new file mode 100644 index 0000000..312ad81 --- /dev/null +++ b/packs/lf-gifts/LOG @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9eca93647f3bebd622b297ca03724d1df9ab41a2bbd75b3aa56866cb61ecc7f1 +size 175 diff --git a/packs/lf-gifts/LOG.old b/packs/lf-gifts/LOG.old new file mode 100644 index 0000000..7388cb1 --- /dev/null +++ b/packs/lf-gifts/LOG.old @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fabde0d16f8bb4d2b0d04a8e575ede67dbdf0f2af3820c94ac72e6453608f6ca +size 732 diff --git a/packs/lf-gifts/MANIFEST-000034 b/packs/lf-gifts/MANIFEST-000034 new file mode 100644 index 0000000..6407908 --- /dev/null +++ b/packs/lf-gifts/MANIFEST-000034 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9bcdb5ae7b0827ed95b7d72232cd6d186db3331a2861dd31b75ab35b222871c6 +size 122 diff --git a/packs/lf-skills/000039.log b/packs/lf-skills/000039.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/lf-skills/CURRENT b/packs/lf-skills/CURRENT index 8c85a13..941c5e0 100644 --- a/packs/lf-skills/CURRENT +++ b/packs/lf-skills/CURRENT @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1005a525006f148c86efcbfb36c6eac091b311532448010f70f7de9a68007167 +oid sha256:96bdef013fb79e7d36f54609242be99a151ee07d1506ff9e20f6ee3f8a5176c6 size 16 diff --git a/packs/lf-skills/LOG b/packs/lf-skills/LOG index b077b71..e608fcd 100644 --- a/packs/lf-skills/LOG +++ b/packs/lf-skills/LOG @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:008b11e9f273a2220c8a5655f67a4a81c2431725ca3cf33aa8a1e0d2a87ea5da -size 437 +oid sha256:aedbde2cc704e8b4e981f8ae205aa79df18fec5ddd78de5a0822a5ec73b99a4d +size 175 diff --git a/packs/lf-skills/LOG.old b/packs/lf-skills/LOG.old new file mode 100644 index 0000000..054d258 --- /dev/null +++ b/packs/lf-skills/LOG.old @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4c54092465492c4ebb8c5368c94e209146166ed65cc0b9456a7a0ae74ff24f3d +size 736 diff --git a/packs/lf-skills/MANIFEST-000002 b/packs/lf-skills/MANIFEST-000002 deleted file mode 100644 index 64d1541..0000000 --- a/packs/lf-skills/MANIFEST-000002 +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:c9796795002e296fe110d83ab4290cd8a013103589dd71ed5b79cc51e73e9017 -size 137 diff --git a/packs/lf-skills/MANIFEST-000038 b/packs/lf-skills/MANIFEST-000038 new file mode 100644 index 0000000..b2c9321 --- /dev/null +++ b/packs/lf-skills/MANIFEST-000038 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f308e2f9c8b88d84cc9ee2f1e53585e769e4d56fb32631928b30b4909931aed2 +size 122 diff --git a/packs/lf-vulnerabilities/000005.ldb b/packs/lf-vulnerabilities/000005.ldb new file mode 100644 index 0000000..15b7d3d --- /dev/null +++ b/packs/lf-vulnerabilities/000005.ldb @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7c4a810bb592614cdadfc93b40a4817d4ec2a91af7f137d6cc09cf5f3c41dd0b +size 29183 diff --git a/packs/lf-vulnerabilities/000035.log b/packs/lf-vulnerabilities/000035.log new file mode 100644 index 0000000..e69de29 diff --git a/packs/lf-vulnerabilities/CURRENT b/packs/lf-vulnerabilities/CURRENT new file mode 100644 index 0000000..430b3cd --- /dev/null +++ b/packs/lf-vulnerabilities/CURRENT @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:22ab787ec084e789354964ecc388a63611c1d0628b0e3d3ffbd77a2eed0d8d8a +size 16 diff --git a/packs/lf-vulnerabilities/LOCK b/packs/lf-vulnerabilities/LOCK new file mode 100644 index 0000000..e69de29 diff --git a/packs/lf-vulnerabilities/LOG b/packs/lf-vulnerabilities/LOG new file mode 100644 index 0000000..9bd9f31 --- /dev/null +++ b/packs/lf-vulnerabilities/LOG @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bdf654d204ef0e71a04b398b46a076c3e9518f7e69cc3886d8aebf499e42a612 +size 175 diff --git a/packs/lf-vulnerabilities/LOG.old b/packs/lf-vulnerabilities/LOG.old new file mode 100644 index 0000000..20d2944 --- /dev/null +++ b/packs/lf-vulnerabilities/LOG.old @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:80befa83c710cc3a15afd37aee809a551a4c77417041d8d2c9da5a87ee5c635c +size 732 diff --git a/packs/lf-vulnerabilities/MANIFEST-000034 b/packs/lf-vulnerabilities/MANIFEST-000034 new file mode 100644 index 0000000..4cd26fa --- /dev/null +++ b/packs/lf-vulnerabilities/MANIFEST-000034 @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fe47e29d6d806cd76be421f01b0b361c4eab15324056922d0e0e629522f72c3e +size 122 diff --git a/styles/character.less b/styles/character.less index a60bdf3..8be43bf 100644 --- a/styles/character.less +++ b/styles/character.less @@ -303,13 +303,13 @@ grid-template-columns: 1fr; legend { a { - font-size: calc(var(--font-size-standard) * 1.4); + font-size: calc(var(--font-size-standard) * 1.0); padding-left: 5px; } } .skills { display: grid; - grid-template-columns: repeat(5, 1fr); + grid-template-columns: repeat(3, 1fr); gap: 10px; .skill { display: flex; @@ -319,6 +319,9 @@ width: 50px; height: 50px; } + .name { + min-width: 12rem; + } } } .gifts { diff --git a/styles/fvtt-lethal-fantasy.less b/styles/fvtt-lethal-fantasy.less index c39bfba..0beac77 100644 --- a/styles/fvtt-lethal-fantasy.less +++ b/styles/fvtt-lethal-fantasy.less @@ -1,3 +1,4 @@ +@import "fonts.less"; @import "global.less"; .lethalfantasy { diff --git a/styles/global.less b/styles/global.less index fd48912..b5fa38c 100644 --- a/styles/global.less +++ b/styles/global.less @@ -1,6 +1,6 @@ :root { --font-primary: "TimesNewRoman", serif; - --font-size-standard: 1.0rem; + --font-size-standard: 0.9rem; --background-image-base: url("../assets/ui/lethal_fantasy_background.webp"); --font-secondary: "BaskervilleBold", serif; --logo-standard: url("../assets/ui/lf_logo_small_02.webp"); diff --git a/styles/roll.less b/styles/roll.less index 25c8925..d1b76df 100644 --- a/styles/roll.less +++ b/styles/roll.less @@ -15,11 +15,7 @@ } } -input[name="selectAvantages"] { - border: none; -} - -.dialog-aide-gene { +.dialog-modifier { display: flex; justify-content: center; align-items: center; @@ -32,36 +28,15 @@ input[name="selectAvantages"] { } } -.dialog-modificateur { - display: flex; - justify-content: center; - align-items: center; - select { - border: none; - background-color: rgba(0, 0, 0, 0.1); - color: var(--color-dark-2); - width: 60px; - text-align: center; - } -} - -.dialog-avantages { - #selectAvantages { - background-color: inherit; - text-align: center; - font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); - } -} - .dialog-damage, .dialog-resource, +.dialog-challenge, .dialog-save { display: flex; justify-content: center; align-items: center; font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 2); + font-size: calc(var(--font-size-standard) * 1.2); color: var(--color-dark-1); } @@ -95,7 +70,7 @@ input[name="selectAvantages"] { flex-direction: column; .introText { font-family: var(--font-secondary); - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.0); width: 210px; margin-left: 20px; } @@ -106,7 +81,7 @@ input[name="selectAvantages"] { flex-direction: column; justify-content: center; align-items: center; - font-size: calc(var(--font-size-standard) * 1.2); + font-size: calc(var(--font-size-standard) * 1.0); text-shadow: 0 0 10px var(--color-shadow-primary); } } diff --git a/system.json b/system.json index 0c94c30..eec9632 100644 --- a/system.json +++ b/system.json @@ -6,7 +6,7 @@ "download": "#{DOWNLOAD}#", "url": "#{URL}#", "license": "LICENSE", - "version": "12.0.8", + "version": "12.0.9", "authors": [ { "name": "Uberwald", @@ -66,6 +66,22 @@ "system": "fvtt-lethal-fantasy", "path": "packs/lf-equipment", "type": "Item" + }, + { + "name": "lf-gifts", + "banner": "", + "label": "Gifts", + "system": "fvtt-lethal-fantasy", + "path": "packs/lf-gifts", + "type": "Item" + }, + { + "name": "lf-vulnerabilities", + "banner": "", + "label": "Vulnerabilities", + "system": "fvtt-lethal-fantasy", + "path": "packs/lf-vulnerabilities", + "type": "Item" } ], "flags": { diff --git a/templates/character-main.hbs b/templates/character-main.hbs index 0d87491..f35db44 100644 --- a/templates/character-main.hbs +++ b/templates/character-main.hbs @@ -79,15 +79,15 @@ {{localize "LETHALFANTASY.Label.Challenges"}}
- {{localize "LETHALFANTASY.Label.challenges.strength"}} + {{localize "LETHALFANTASY.Label.challenges.strength"}} {{formField systemFields.challenges.fields.str.fields.value value=system.challenges.str.value disabled=isPlayMode - classes="rollable" data-challenge-id="str" }} - {{localize "LETHALFANTASY.Label.challenges.agility"}} + }} + {{localize "LETHALFANTASY.Label.challenges.agility"}} {{formField systemFields.challenges.fields.agility.fields.value value=system.challenges.agility.value disabled=isPlayMode - classes="rollable" data-challenge-id="agility" }} - {{localize "LETHALFANTASY.Label.challenges.dying"}} + }} + {{localize "LETHALFANTASY.Label.challenges.dying"}} {{formField systemFields.challenges.fields.dying.fields.value value=system.challenges.dying.value - disabled=isPlayMode classes="rollable" data-challenge-id="dying" }} + disabled=isPlayMode }}
@@ -114,68 +114,68 @@
{{localize "LETHALFANTASY.Label.characteristics"}} -
+
{{localize "LETHALFANTASY.Label.str"}} {{formField systemFields.characteristics.fields.str.fields.value value=system.characteristics.str.value disabled=isPlayMode classes="rollable" data-char-id="str" }} {{formField systemFields.characteristics.fields.str.fields.percent value=system.characteristics.str.percent - disabled=isPlayMode }} + disabled=isPlayMode type="number"}}
-
+
{{localize "LETHALFANTASY.Label.int"}} {{formField systemFields.characteristics.fields.int.fields.value value=system.characteristics.int.value disabled=isPlayMode classes="rollable" data-char-id="int" }} {{formField systemFields.characteristics.fields.int.fields.percent value=system.characteristics.int.percent - disabled=isPlayMode }} + disabled=isPlayMode type="number" }}
-
+
{{localize "LETHALFANTASY.Label.wis"}} {{formField systemFields.characteristics.fields.wis.fields.value value=system.characteristics.wis.value disabled=isPlayMode classes="rollable" data-char-id="wis" }} {{formField systemFields.characteristics.fields.wis.fields.percent value=system.characteristics.wis.percent - disabled=isPlayMode }} + disabled=isPlayMode type="number"}}
-
+
{{localize "LETHALFANTASY.Label.dex"}} {{formField systemFields.characteristics.fields.dex.fields.value value=system.characteristics.dex.value disabled=isPlayMode classes="rollable" data-char-id="wis" }} {{formField systemFields.characteristics.fields.dex.fields.percent value=system.characteristics.dex.percent - disabled=isPlayMode }} + disabled=isPlayMode type="number" }}
-
+
{{localize "LETHALFANTASY.Label.con"}} {{formField systemFields.characteristics.fields.con.fields.value value=system.characteristics.con.value disabled=isPlayMode classes="rollable" data-char-id="con" }} {{formField systemFields.characteristics.fields.con.fields.percent value=system.characteristics.con.percent - disabled=isPlayMode }} + disabled=isPlayMode type="number"}}
-
+
{{localize "LETHALFANTASY.Label.cha"}} {{formField systemFields.characteristics.fields.cha.fields.value value=system.characteristics.cha.value disabled=isPlayMode classes="rollable" data-char-id="cha" }} {{formField systemFields.characteristics.fields.cha.fields.percent value=system.characteristics.cha.percent - disabled=isPlayMode }} + disabled=isPlayMode type="number"}}
-
+
{{localize "LETHALFANTASY.Label.luc"}} {{formField systemFields.characteristics.fields.luc.fields.value value=system.characteristics.luc.value disabled=isPlayMode classes="rollable" data-char-id="luc" }} {{formField systemFields.characteristics.fields.luc.fields.percent value=system.characteristics.luc.percent - disabled=isPlayMode }} + disabled=isPlayMode type="number"}}
-
+
{{localize "LETHALFANTASY.Label.app"}} {{formField systemFields.characteristics.fields.app.fields.value value=system.characteristics.app.value disabled=isPlayMode classes="rollable" data-char-id="app" }} {{formField systemFields.characteristics.fields.app.fields.percent value=system.characteristics.app.percent - disabled=isPlayMode }} + disabled=isPlayMode type="number"}}
diff --git a/templates/character-skills.hbs b/templates/character-skills.hbs index bc50048..1e78dcd 100644 --- a/templates/character-skills.hbs +++ b/templates/character-skills.hbs @@ -7,8 +7,11 @@ {{#each skills as |item|}}
-
- {{item.name}} +{{item.system.skillTotal}} +
+ {{item.name}} +
+
+ +{{item.system.skillTotal}}
- {{#if (ne actingCharImg "icons/svg/mystery-man.svg")}} -
- -
- {{else}} -
- {{/if}} -
-

{{{introText}}} - {{#if isSave}} -
- {{#if (eq avantages "avantage")}} {{localize "TENEBRIS.Roll.avantage"}}{{/if}} - {{#if (eq avantages "desavantage")}} {{localize "TENEBRIS.Roll.desavantage"}}{{/if}} - {{#if (eq avantages "doubleAvantage")}} {{localize "TENEBRIS.Roll.doubleAvantage"}}{{/if}} - {{#if (eq avantages "doubleDesavantage")}} {{localize "TENEBRIS.Roll.doubleDesavantage"}}{{/if}} - {{/if}} -

+
+ +
+ + +
+ {{upperFirst rollType}} : {{upperCase rollTarget.rollKey}} + {{#each diceResults as |result|}} + {{result.dice}} : {{result.value}} + {{/each}}
{{#if isSave}}
{{#if (eq resultType "success")}} - {{#if isPrivate}}?{{else}}{{localize "TENEBRIS.Roll.success"}}{{/if}} + {{#if isPrivate}}?{{else}}{{localize "LETHALFANTASY.Roll.success"}}{{/if}} {{else}} - {{#if isPrivate}}?{{else}}{{localize "TENEBRIS.Roll.failure"}}{{/if}} + {{#if isPrivate}}?{{else}}{{localize "LETHALFANTASY.Roll.failure"}}{{/if}} {{/if}}
{{/if}} {{#if isResource}}
{{#if (eq resultType "success")}} - {{#if isPrivate}}?{{else}}{{localize "TENEBRIS.Roll.success"}}{{/if}} + {{#if isPrivate}}?{{else}}{{localize "LETHALFANTASY.Roll.success"}}{{/if}} {{else}} - {{#if isPrivate}}?{{else}}{{localize "TENEBRIS.Roll.failure"}}{{#if isFailure}} ({{localize "TENEBRIS.Roll.resourceLost"}}){{/if}}{{/if}} + {{#if isPrivate}}?{{else}}{{localize "LETHALFANTASY.Roll.failure"}}{{#if isFailure}} ({{localize "LETHALFANTASY.Roll.resourceLost"}}){{/if}}{{/if}} {{/if}}
{{/if}} {{#if isDamage}}
{{#if (and isGM hasTarget)}} - {{{localize "TENEBRIS.Roll.displayArmor" targetName=targetName targetArmor=targetArmor realDamage=realDamage}}} + {{{localize "LETHALFANTASY.Roll.displayArmor" targetName=targetName targetArmor=targetArmor realDamage=realDamage}}} {{/if}}
{{/if}} diff --git a/templates/roll-dialog.hbs b/templates/roll-dialog.hbs index 494f675..8cdb821 100644 --- a/templates/roll-dialog.hbs +++ b/templates/roll-dialog.hbs @@ -1,59 +1,21 @@ {{log "roll-dialog" this}} -
- {{#if isSave}} +
+ + {{#if isChallenge}}
- {{localize "TENEBRIS.Label.sauvegarde"}} -
{{formula}}
+ {{localize "LETHALFANTASY.Label.challenge"}} + {{log this}} +
{{upperCase rollTarget.rollKey}} : {{formula}}
-
- {{localize "TENEBRIS.Roll.avantagesDesavantages"}} - - -
-
-
- {{localize "TENEBRIS.Roll.aide"}} - -
-
- {{localize "TENEBRIS.Roll.gene"}} - -
-
-
- {{localize "TENEBRIS.Roll.adversite"}} - + {{selectOptions choiceModifier selected=modifier}}
{{/if}} - {{#if (or isDamage isAttack)}} -
- {{localize "TENEBRIS.Label.degats"}} -
{{damageDice}} {{#if damageDiceLowered}}limités par les dégâts max à {{damageDiceFinal}} {{/if}}
-
- {{/if}} - {{#if isResource}} -
- {{localize "TENEBRIS.Label.ressource"}} -
{{formula}}
-
- {{/if}}
- {{localize "TENEBRIS.Roll.visibilite"}} + {{localize "LETHALFANTASY.Roll.visibility"}}