Basic actor sheet

This commit is contained in:
2024-12-29 23:09:27 +01:00
parent cffd6827fd
commit 79ce247f57
47 changed files with 739 additions and 526 deletions
+20 -29
View File
@@ -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 {
+1
View File
@@ -29,4 +29,5 @@ exports.default = gulp.series(
watchUpdates
);
exports.css = css;
exports.watchUpdates = watchUpdates;
+8 -17
View File
@@ -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 <br> {save}",
"resource": "Jet de ressource <br> {resource}",
"save": "Save roll {save}",
"damage": "Jet de dégâts <br> {item}",
"attack": "Jet d'attaque <br> {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}. <br>Dégâts réels : {realDamage}"
"success": "Success",
"failure": "Failure",
"modifier": "Modifier",
"visibility": "Visibility"
},
"Tooltip": {
"skill": "Skills list",
+2
View File
@@ -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) => {
@@ -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
+178 -2
View File
@@ -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,
"hp ": 1,
"aether_points": -50,
"pain_save": 1,
+26
View File
@@ -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)
+128 -252
View File
@@ -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("<br>").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(`<br>Cible : ${this.targetName}`)
}
@@ -165,14 +165,17 @@ export default class LethalFantasyRoll extends Roll {
* @returns {Promise<Object|null>} 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
}
}
@@ -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"
} else if (options.rollType === ROLL_TYPE.RESOURCE) {
resultType = roll.total === 1 || roll.total === 2 ? "failure" : "success"
}
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)
let realDamage
if (options.rollType === ROLL_TYPE.DAMAGE) {
realDamage = Math.max(0, roll.total - parseInt(targetArmor, 10))
} else if (options.rollType === ROLL_TYPE.RESOURCE) {
//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
}
}
}
+22 -34
View File
@@ -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<null>} - 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<null>} - 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
+45 -30
View File
@@ -10,7 +10,7 @@ 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({
@@ -34,7 +34,7 @@ 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) ) {
if (bonus > Math.floor(this._source.skillTotal / 10)) {
ui.notifications.error(game.i18n.localize("LETHALFANTASY.Skill.error.weaponBonus"))
isError = true
}
@@ -44,10 +44,10 @@ export default class LethalFantasySkill extends foundry.abstract.TypeDataModel {
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)}`;
}
+1
View File
@@ -55,4 +55,5 @@ export default class LethalFantasySkill extends foundry.abstract.TypeDataModel {
get weaponCategory() {
return game.i18n.localize(CATEGORY[this.weaponType].label)
}
}
+167 -7
View File
@@ -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");
});
}
}
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
View File
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
View File
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
View File
Binary file not shown.
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
+5 -2
View File
@@ -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 {
+1
View File
@@ -1,3 +1,4 @@
@import "fonts.less";
@import "global.less";
.lethalfantasy {
+1 -1
View File
@@ -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");
+5 -30
View File
@@ -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);
}
}
+17 -1
View File
@@ -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": {
+22 -22
View File
@@ -79,15 +79,15 @@
<legend>{{localize "LETHALFANTASY.Label.Challenges"}}</legend>
<div class="character-challenges">
<div class="character-challenge">
<span class="name">{{localize "LETHALFANTASY.Label.challenges.strength"}}</span>
<span class="name"><a class="rollable" data-roll-type="challenge" data-roll-key="str"><i class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize "LETHALFANTASY.Label.challenges.strength"}}</a></span>
{{formField systemFields.challenges.fields.str.fields.value value=system.challenges.str.value disabled=isPlayMode
classes="rollable" data-challenge-id="str" }}
<span class="name">{{localize "LETHALFANTASY.Label.challenges.agility"}}</span>
}}
<span class="name"><a class="rollable" data-roll-type="challenge" data-roll-key="agility"><i class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize "LETHALFANTASY.Label.challenges.agility"}}</a></span>
{{formField systemFields.challenges.fields.agility.fields.value value=system.challenges.agility.value disabled=isPlayMode
classes="rollable" data-challenge-id="agility" }}
<span class="name">{{localize "LETHALFANTASY.Label.challenges.dying"}}</span>
}}
<span class="name"><a class="rollable" data-roll-type="challenge" data-roll-key="dying"><i class="lf-roll-small fa-solid fa-dice-d20"></i>{{localize "LETHALFANTASY.Label.challenges.dying"}}</a></span>
{{formField systemFields.challenges.fields.dying.fields.value value=system.challenges.dying.value
disabled=isPlayMode classes="rollable" data-challenge-id="dying" }}
disabled=isPlayMode }}
</div>
</div>
</fieldset>
@@ -114,68 +114,68 @@
<fieldset class="character-characteristics character-characteristics-{{ifThen isPlayMode 'play' 'edit'}}">
<legend>{{localize "LETHALFANTASY.Label.characteristics"}}</legend>
<div class="character-characteristic" data-drag="true">
<div class="character-characteristic" >
{{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"}}
</div>
<div class="character-characteristic" data-drag="true">
<div class="character-characteristic" >
{{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" }}
</div>
<div class="character-characteristic" data-drag="true">
<div class="character-characteristic" >
{{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"}}
</div>
<div class="character-characteristic" data-drag="true">
<div class="character-characteristic" >
{{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" }}
</div>
<div class="character-characteristic" data-drag="true">
<div class="character-characteristic" >
{{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"}}
</div>
<div class="character-characteristic" data-drag="true">
<div class="character-characteristic" >
{{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"}}
</div>
<div class="character-characteristic" data-drag="true">
<div class="character-characteristic" >
{{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"}}
</div>
<div class="character-characteristic" data-drag="true">
<div class="character-characteristic" >
{{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"}}
</div>
</fieldset>
+5 -2
View File
@@ -7,8 +7,11 @@
{{#each skills as |item|}}
<div class="skill " data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}">
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<div class="name" data-tooltip="{{{item.description}}}<br><br>{{item.path}}" data-tooltip-direction="UP">
{{item.name}} +{{item.system.skillTotal}}
<div class="name" >
{{item.name}}
</div>
<div class="score">
+{{item.system.skillTotal}}
</div>
<div class="controls">
<a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
+14 -21
View File
@@ -1,47 +1,40 @@
{{!log 'chat-message' this}}
<div class="{{cssClass}}">
<div class="intro-chat">
{{#if (ne actingCharImg "icons/svg/mystery-man.svg")}}
<div class="intro-img">
<img src="{{actingCharImg}}" data-tooltip="{{actingCharName}}" />
</div>
{{else}}
<div></div>
{{/if}}
<div class="intro-img">
<img src="{{actingCharImg}}" data-tooltip="{{actingCharName}}" />
</div>
<div class="intro-right">
<p class="introText" {{#if isSave}}data-tooltip="{{introTextTooltip}}"{{/if}}>{{{introText}}}
{{#if isSave}}
<br>
{{#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}}
</p>
<span>{{upperFirst rollType}} : {{upperCase rollTarget.rollKey}}</span>
{{#each diceResults as |result|}}
<span>{{result.dice}} : {{result.value}}</span>
{{/each}}
</div>
</div>
{{#if isSave}}
<div class="result">
{{#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}}
</div>
{{/if}}
{{#if isResource}}
<div class="result">
{{#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}}
</div>
{{/if}}
{{#if isDamage}}
<div>
{{#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}}
</div>
{{/if}}
+11 -49
View File
@@ -1,59 +1,21 @@
{{log "roll-dialog" this}}
<div class="tenebris-roll-dialog">
{{#if isSave}}
<div class="lethalfantasy-roll-dialog">
{{#if isChallenge}}
<fieldSet>
<legend>{{localize "TENEBRIS.Label.sauvegarde"}}</legend>
<div class="dialog-save">{{formula}}</div>
<legend>{{localize "LETHALFANTASY.Label.challenge"}}</legend>
{{log this}}
<div class="dialog-save">{{upperCase rollTarget.rollKey}} : {{formula}}</div>
</fieldSet>
<fieldSet class="dialog-avantages">
<legend>{{localize "TENEBRIS.Roll.avantagesDesavantages"}}</legend>
<input
type="range"
name="avantages"
min="1"
max="5"
value="{{rangeAdvantage}}"
data-tooltip="Double désavantage - Désavantage - Normal - Avantage - Double avantage"
data-tooltip-direction="UP"
data-tooltip-class="tooltip-avantages"
/>
<input id="selectAvantages" name="selectAvantages" readonly value="{{rollAdvantage}}">
</fieldSet>
<div class="dialog-aide-gene">
<fieldSet>
<legend>{{localize "TENEBRIS.Roll.aide"}}</legend>
<select name="aide">
{{selectOptions choiceAide}}
</select>
</fieldSet>
<fieldSet>
<legend>{{localize "TENEBRIS.Roll.gene"}}</legend>
<select name="gene">
{{selectOptions choiceGene}}
</select>
</fieldSet>
</div>
<fieldSet class="dialog-modificateur">
<legend>{{localize "TENEBRIS.Roll.adversite"}}</legend>
<select name="modificateur" {{#if hasTarget}}data-tooltip="Cible : {{targetName}}" data-tooltip-direction="UP"{{/if}}>
{{selectOptions choiceModificateur selected=malus}}
<fieldSet class="dialog-modifier">
<legend>{{localize "LETHALFANTASY.Roll.modifier"}}</legend>
<select name="modifier" data-tooltip-direction="UP">
{{selectOptions choiceModifier selected=modifier}}
</select>
</fieldSet>
{{/if}}
{{#if (or isDamage isAttack)}}
<fieldSet>
<legend>{{localize "TENEBRIS.Label.degats"}}</legend>
<div class="dialog-damage">{{damageDice}} {{#if damageDiceLowered}}limités par les dégâts max à {{damageDiceFinal}} {{/if}}</div>
</fieldSet>
{{/if}}
{{#if isResource}}
<fieldSet>
<legend>{{localize "TENEBRIS.Label.ressource"}}</legend>
<div class="dialog-resource">{{formula}}</div>
</fieldSet>
{{/if}}
<fieldSet>
<legend>{{localize "TENEBRIS.Roll.visibilite"}}</legend>
<legend>{{localize "LETHALFANTASY.Roll.visibility"}}</legend>
<select name="visibility">
{{selectOptions rollModes selected=visibility}}
</select>