Add D30, spells, miracles and ranged defense roll

This commit is contained in:
2025-01-05 22:14:44 +01:00
parent dbd27b837f
commit 5fc40b2b18
39 changed files with 460 additions and 81 deletions

View File

@@ -566,8 +566,33 @@ i.lethalfantasy {
}
.lethalfantasy .tab.character-spells .spells .spell {
display: flex;
align-items: center;
gap: 10px;
}
.lethalfantasy .tab.character-spells .spells .spell .item-img {
width: 32px;
height: 32px;
}
.lethalfantasy .tab.character-spells .spells .spell .name {
min-width: 12rem;
}
.lethalfantasy .tab.character-spells .miracles {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
}
.lethalfantasy .tab.character-spells .miracles .miracle {
display: flex;
align-items: center;
gap: 10px;
}
.lethalfantasy .tab.character-spells .miracles .miracle .item-img {
width: 32px;
height: 32px;
}
.lethalfantasy .tab.character-spells .miracles .miracle .name {
min-width: 12rem;
}
.lethalfantasy .tab.character-spells .appris {
font-weight: bold;
}

View File

@@ -478,6 +478,10 @@
"Platinums": "Platinum"
},
"Label": {
"rangeDefenseDialog": "Range defense dialog",
"rangeDefenseRoll": "Range defense roll",
"rangedAttackDefense": "Ranged attack defense",
"miracles": "Miracles",
"biodata": "Biodata",
"titleChallenge": "Challenge",
"titleSave": "Save",

View File

@@ -1,4 +1,5 @@
import LethalFantasyActorSheet from "./base-actor-sheet.mjs"
import LethalFantasyRoll from "../../documents/roll.mjs"
export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet {
/** @override */
@@ -13,6 +14,7 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
},
actions: {
createEquipment: LethalFantasyCharacterSheet.#onCreateEquipment,
rangedAttackDefense: LethalFantasyCharacterSheet.#onRangedAttackDefense,
},
}
@@ -48,12 +50,15 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
* @returns {Record<string, Partial<ApplicationTab>>}
*/
#getTabs() {
const tabs = {
let tabs = {
skills: { id: "skills", group: "sheet", icon: "fa-solid fa-shapes", label: "LETHALFANTASY.Label.skills" },
weapons: { id: "weapons", group: "sheet", icon: "fa-solid fa-swords", label: "LETHALFANTASY.Label.weapons" },
spells: { id: "spells", group: "sheet", icon: "fa-sharp-duotone fa-solid fa-wand-magic-sparkles", label: "LETHALFANTASY.Label.spells" },
biography: { id: "biography", group: "sheet", icon: "fa-solid fa-book", label: "LETHALFANTASY.Label.biography" },
}
if (this.actor.system.biodata.magicUser) {
tabs.spells = { id: "spells", group: "sheet", icon: "fa-sharp-duotone fa-solid fa-wand-magic-sparkles", label: "LETHALFANTASY.Label.spells" }
}
for (const v of Object.values(tabs)) {
v.active = this.tabGroups[v.group] === v.id
v.cssClass = v.active ? "active" : ""
@@ -95,6 +100,7 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
case "spells":
context.tab = context.tabs.spells
context.spells = doc.itemTypes.spell
context.miracles = doc.itemTypes.miracle
context.hasSpells = context.spells.length > 0
break
case "weapons":
@@ -135,21 +141,20 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
await this.document.addPath(item)
}
static async #onRangedAttackDefense(event, target) {
const hasTarget = false
let roll = await LethalFantasyRoll.promptRangedDefense({
actorId: this.actor.id,
actorName: this.actor.name,
actorImage: this.actor.img
})
if (!roll) return null
await roll.toMessage({}, { rollMode: roll.options.rollMode })
}
/**
* Creates a new attack item directly from the sheet and embeds it into the document.
* @param {Event} event The initiating click event.
* @param {HTMLElement} target The current target of the event listener.
*/
static #onCreateEquipment(event, target) {
// Création d'une armure
if (event.shiftKey) {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("LETHALFANTASY.Label.newArmor"), type: "armor" }])
}
// Création d'une arme
else {
this.document.createEmbeddedDocuments("Item", [{ name: game.i18n.localize("LETHALFANTASY.Label.newWeapon"), type: "weapon" }])
}
}
getBestWeaponClassSkill(skills, rollType, multiplier = 1.0) {
@@ -168,7 +173,7 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
goodSkill = s
}
}
if (rollType.includes("weapon-damage") ) {
if (rollType.includes("weapon-damage")) {
if (s.system.weaponBonus.damage > maxValue) {
maxValue = Number(s.system.weaponBonus.damage)
goodSkill = s
@@ -209,6 +214,14 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
rollTarget.rollKey = rollKey
rollTarget.rollDice = event.target.dataset?.rollDice
break
case "spell":
rollTarget = this.actor.items.find((i) => i.type === "spell" && i.id === rollKey)
rollTarget.rollKey = rollKey
break
case "miracle":
rollTarget = this.actor.items.find((i) => i.type === "miracle" && i.id === rollKey)
rollTarget.rollKey = rollKey
break
case "skill":
rollTarget = this.actor.items.find((i) => i.type === "skill" && i.id === rollKey)
rollTarget.rollKey = rollKey
@@ -260,6 +273,11 @@ export default class LethalFantasyCharacterSheet extends LethalFantasyActorSheet
ui.notifications.error(game.i18n.localize("LETHALFANTASY.Notifications.rollTypeNotFound") + String(rollType))
break
}
// In all cases
rollTarget.magicUser = this.actor.system.biodata.magicUser
rollTarget.actorModifiers = foundry.utils.duplicate(this.actor.system.modifiers)
await this.document.system.roll(rollType, rollTarget)
}
// #endregion

View File

@@ -42,6 +42,43 @@ export const MONEY = {
}
}
export const MOVEMENT_CHOICES = {
"none": {label: "None (D8E)", value: "D8"},
"walk": {label: "Walk (D10E)", value: "D10"},
"jog": {label: "Jog (D12E)", value: "D12"},
"run": {label: "Run (D20E)", value: "D20"},
"incombat": {label: "In Combat (D12E)", value: "D12"}
}
export const MOVE_DIRECTION_CHOICES = {
"none": {label: "None (+0)", value: "0"},
"away": {label: "Away (+4)", value: "+4"},
"toward": {label: "Toward (+0)", value: "0"},
"lateral": {label: "Lateral (+10)", value: "+10"}
}
export const SIZE_CHOICES = {
"tiny": {label: "Tiny (+10)", value: "+10"},
"small": {label: "Small (+5)", value: "+5"},
"medium": {label: "Medium (+0)", value: "0"},
"huge": {label: "Huge (-10)", value: "-10"}
}
export const RANGE_CHOICES = {
"pointblank": {label: "Point Blank (-5)", value: "-5"},
"short": {label: "Short (+0)", value: "0"},
"medium": {label: "Medium (+8)", value: "+8"},
"long": {label: "Long (+15)", value: "+15"},
"extreme": {label: "Extreme (+20)", value: "+20"},
"beyondskill": {label: "Beyond Skill (+25)", value: "+25"}
}
export const ATTACKER_AIM_CHOICES = {
"simple": {label: "Simple (+0)", value: "0"},
"careful": {label: "Careful (-4)", value: "-4"},
"focused": {label: "Focused (-8)", value: "-8"}
}
export const DICE_VALUES = {
"d3": "D3",
"d4": "D4",
@@ -151,4 +188,9 @@ export const SYSTEM = {
CHOICE_MODIFIERS,
CHOICE_DICE,
DEV_MODE,
MOVEMENT_CHOICES,
MOVE_DIRECTION_CHOICES,
SIZE_CHOICES,
RANGE_CHOICES,
ATTACKER_AIM_CHOICES
}

View File

@@ -88,6 +88,10 @@ export default class LethalFantasyRoll extends Roll {
return this.options.rollTarget
}
get D30result() {
return this.options.D30result
}
/**
* Prompt the user with a dialog to configure and execute a roll.
*
@@ -112,8 +116,11 @@ export default class LethalFantasyRoll extends Roll {
let modifierFormula = "1d0"
let hasModifier = true
let hasChangeDice = false
let hasD30 = false
if (options.rollType === "challenge" || options.rollType === "save") {
options.rollName = options.rollTarget.rollKey
hasD30 = options.rollType === "save"
if (options.rollTarget.rollKey === "dying") {
dice = options.rollTarget.value
maxValue = Number(options.rollTarget.value.match(/\d+/)[0])
@@ -123,6 +130,7 @@ export default class LethalFantasyRoll extends Roll {
dice = "1D20"
maxValue = 20
}
} else if (options.rollType === "skill") {
options.rollName = options.rollTarget.name
dice = "1D100"
@@ -131,7 +139,9 @@ export default class LethalFantasyRoll extends Roll {
hasModifier = true
hasChangeDice = false
options.rollTarget.value = options.rollTarget.system.skillTotal
} else if (options.rollType === "weapon-attack" || options.rollType === "weapon-defense") {
hasD30 = true
options.rollName = options.rollTarget.name
dice = "1D20"
baseFormula = "D20"
@@ -145,6 +155,29 @@ export default class LethalFantasyRoll extends Roll {
options.rollTarget.value = options.rollTarget.combat.defenseModifier + options.rollTarget.weaponSkillModifier
options.rollTarget.charModifier = options.rollTarget.combat.defenseModifier
}
} else if (options.rollType === "spell") {
hasD30 = true
options.rollName = options.rollTarget.name
dice = "1D20"
baseFormula = "D20"
maxValue = 20
hasModifier = true
hasChangeDice = false
options.rollTarget.value = options.rollTarget.actorModifiers.levelSpellModifier + options.rollTarget.actorModifiers.intSpellModifier
options.rollTarget.charModifier = options.rollTarget.actorModifiers.intSpellModifier
} else if (options.rollType === "miracle") {
hasD30 = true
options.rollName = options.rollTarget.name
dice = "1D20"
baseFormula = "D20"
maxValue = 20
hasModifier = true
hasChangeDice = false
options.rollTarget.value = options.rollTarget.actorModifiers.levelMiracleModifier + options.rollTarget.actorModifiers.chaMiracleModifier
options.rollTarget.charModifier = options.rollTarget.actorModifiers.chaMiracleModifier
} else if (options.rollType.includes("weapon-damage")) {
options.rollName = options.rollTarget.name
hasModifier = true
@@ -174,7 +207,6 @@ export default class LethalFantasyRoll extends Roll {
default: "public",
})
const choiceModifier = SYSTEM.CHOICE_MODIFIERS
const choiceDice = SYSTEM.CHOICE_DICE
@@ -197,6 +229,7 @@ export default class LethalFantasyRoll extends Roll {
dice,
hasTarget: options.hasTarget,
modifier,
saveSpell: false,
targetName
}
console.log("dialogContext", dialogContext)
@@ -230,8 +263,10 @@ export default class LethalFantasyRoll extends Roll {
let titleFormula = ""
dice = rollContext.changeDice || dice
if (hasModifier) {
let bonus = Number(options.rollTarget.value)
let bonus = Number(options.rollTarget.value)
fullModifier = rollContext.modifier === "" ? 0 : parseInt(rollContext.modifier, 10) + bonus
fullModifier += (rollContext.saveSpell) ? options.rollTarget.actorModifiers.saveModifier : 0
if (fullModifier === 0) {
modifierFormula = "0"
} else {
@@ -282,13 +317,18 @@ export default class LethalFantasyRoll extends Roll {
if (Hooks.call("fvtt-lethal-fantasy.preRoll", options, rollData) === false) return
const rollBase = new this(baseFormula, options.data, rollData)
await rollBase.evaluate()
const rollModifier = new Roll(modifierFormula, options.data, rollData)
await rollModifier.evaluate()
rollModifier.evaluate()
await rollBase.evaluate()
if (hasD30) {
let rollD30 = await new Roll("1D30").evaluate()
options.D30result = rollD30.total
}
let rollTotal = -1
let diceResults = []
let resultType
let diceResult = rollBase.dice[0].results[0].result
diceResults.push({ dice: `${dice}`, value: diceResult })
let diceSum = diceResult
@@ -314,6 +354,7 @@ export default class LethalFantasyRoll extends Roll {
rollBase.options.diceResults = diceResults
rollBase.options.rollTarget = options.rollTarget
rollBase.options.titleFormula = titleFormula
rollBase.options.D30result = options.D30result
/**
* A hook event that fires after the roll has been made.
@@ -329,6 +370,130 @@ export default class LethalFantasyRoll extends Roll {
return rollBase
}
static async promptRangedDefense(rollTarget) {
const rollModes = Object.fromEntries(Object.entries(CONFIG.Dice.rollModes).map(([key, value]) => [key, game.i18n.localize(value)]))
const fieldRollMode = new foundry.data.fields.StringField({
choices: rollModes,
blank: false,
default: "public",
})
let dialogContext = {
movementChoices : SYSTEM.MOVEMENT_CHOICES,
moveDirectionChoices : SYSTEM.MOVE_DIRECTION_CHOICES,
sizeChoices : SYSTEM.SIZE_CHOICES,
rangeChoices : SYSTEM.RANGE_CHOICES,
attackerAimChoices : SYSTEM.ATTACKER_AIM_CHOICES,
movement: "none",
moveDirection: "none",
size: "medium",
range: "short",
attackerAim: "simple",
fieldRollMode,
rollModes
}
console.log("CTX", dialogContext)
const content = await renderTemplate("systems/fvtt-lethal-fantasy/templates/range-defense-dialog.hbs", dialogContext)
const label = game.i18n.localize("LETHALFANTASY.Label.rangeDefenseRoll")
const rollContext = await foundry.applications.api.DialogV2.wait({
window: { title: "Range Defense" },
classes: ["lethalfantasy"],
content,
buttons: [
{
label: label,
callback: (event, button, dialog) => {
const output = Array.from(button.form.elements).reduce((obj, input) => {
if (input.name) obj[input.name] = input.value
return obj
}, {})
return output
},
},
],
rejectClose: false // Click on Close button will not launch an error
})
console.log("RollContext", rollContext)
// Build the final modifier
let fullModifier = Number(rollContext.moveDirection) +
Number(rollContext.size) +
Number(rollContext.range) +
Number(rollContext.attackerAim)
console.log("Modifier", fullModifier)
let modifierFormula
if (fullModifier === 0) {
modifierFormula = "0"
} else {
let modAbs = Math.abs(fullModifier)
modifierFormula = `d${modAbs + 1} - 1`
}
// If the user cancels the dialog, exit
if (rollContext === null) return
let rollData = {...rollContext}
let options = {...rollContext}
options.rollName = "Ranged Defense"
const rollBase = new this(rollContext.movement, options.data, rollData)
const rollModifier = new Roll(modifierFormula, options.data, rollData)
rollModifier.evaluate()
await rollBase.evaluate()
let rollD30 = await new Roll("1D30").evaluate()
options.D30result = rollD30.total
let dice = rollContext.movement
let maxValue = Number(dice.match(/\d+$/)[0]) // Update the max value agains
let rollTotal = -1
let diceResults = []
let resultType
let diceResult = rollBase.dice[0].results[0].result
diceResults.push({ dice: `${dice}`, value: diceResult })
let diceSum = diceResult
while (diceResult === maxValue) {
let r = await new Roll(baseFormula).evaluate()
diceResult = r.dice[0].results[0].result
diceResults.push({ dice: `${dice}-1`, value: diceResult - 1 })
diceSum += (diceResult - 1)
}
if (fullModifier !== 0) {
diceResults.push({ dice: `${rollModifier.formula}`, value: rollModifier.total })
if (fullModifier < 0) {
rollTotal = Math.max(diceSum - rollModifier.total, 0)
} else {
rollTotal = diceSum + rollModifier.total
}
} else {
rollTotal = diceSum
}
rollBase.options.resultType = resultType
rollBase.options.rollTotal = rollTotal
rollBase.options.diceResults = diceResults
rollBase.options.rollTarget = options.rollTarget
rollBase.options.titleFormula = `${dice}E + ${modifierFormula}`
rollBase.options.D30result = options.D30result
rollBase.options.rollName = "Ranged Defense"
/**
* A hook event that fires after the roll has been made.
* @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.
*/
return rollBase
}
/**
* Creates a title based on the given type.
*
@@ -352,6 +517,8 @@ export default class LethalFantasyRoll extends Roll {
return `${game.i18n.localize("LETHALFANTASY.Label.weapon-damage-small")}`
case "weapon-damage-medium":
return `${game.i18n.localize("LETHALFANTASY.Label.weapon-damage-medium")}`
case "spell":
return `${game.i18n.localize("LETHALFANTASY.Label.spell")}`
default:
return game.i18n.localize("LETHALFANTASY.Label.titleStandard")
}
@@ -409,6 +576,7 @@ export default class LethalFantasyRoll extends Roll {
hasTarget: this.hasTarget,
targetName: this.targetName,
targetArmor: this.targetArmor,
D30result: this.D30result,
isPrivate: isPrivate
}
cardData.cssClass = cardData.css.join(" ")

View File

@@ -90,8 +90,18 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
age: new fields.NumberField({ ...requiredInteger, initial: 15, min: 6 }),
height: new fields.NumberField({ ...requiredInteger, initial: 170, min: 50 }),
eyes: new fields.StringField({ required: true, nullable: false, initial: "" }),
hair: new fields.StringField({ required: true, nullable: false, initial: "" })
hair: new fields.StringField({ required: true, nullable: false, initial: "" }),
magicUser: new fields.BooleanField({ initial: false }),
})
schema.modifiers = new fields.SchemaField({
levelSpellModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
saveModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
levelMiracleModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
intSpellModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
chaMiracleModifier: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
})
schema.developmentPoints = new fields.SchemaField({
total: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 }),
remaining: new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
@@ -133,25 +143,36 @@ export default class LethalFantasyCharacter extends foundry.abstract.TypeDataMod
grit += this.characteristics[c].value
}
}
this.modifiers.saveModifier = Math.floor((Number(this.biodata.level) / 5))
this.modifiers.levelSpellModifier = Math.floor((Number(this.biodata.level) / 5))
this.modifiers.levelMiracleModifier = Math.floor((Number(this.biodata.level) / 5))
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 intDef = SYSTEM.CHARACTERISTICS_TABLES.int.find(s => s.value === this.characteristics.int.value)
this.modifiers.intSpellModifier = intDef.arkane_casting_mod
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
this.saves.dodge.value = dexDef.dodge + this.modifiers.saveModifier
let wisDef = SYSTEM.CHARACTERISTICS_TABLES.wis.find(s => s.value === this.characteristics.wis.value)
this.saves.will.value = wisDef.willpower_save
this.saves.will.value = wisDef.willpower_save + this.modifiers.saveModifier
let chaDef = SYSTEM.CHARACTERISTICS_TABLES.cha.find(s => s.value === this.characteristics.cha.value)
this.modifiers.chaMiracleModifier = chaDef.divine_miracle_bonus
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.pain.value = conDef.pain_save + this.modifiers.saveModifier
this.saves.toughness.value = conDef.toughness_save + this.modifiers.saveModifier
this.challenges.dying.value = conDef.stabilization_dice
this.saves.contagion.value = this.characteristics.con.value
this.saves.poison.value = this.characteristics.con.value
this.saves.contagion.value = this.characteristics.con.value + this.modifiers.saveModifier
this.saves.poison.value = this.characteristics.con.value + this.modifiers.saveModifier
this.combat.attackModifier = 0
for (let chaKey of SYSTEM.CHARACTERISTIC_ATTACK) {

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
packs/lf-gifts/MANIFEST-000078 LFS Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
packs/lf-skills/MANIFEST-000082 LFS Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -476,7 +476,33 @@
gap: 10px;
.spell {
display: flex;
align-items: center;
gap: 10px;
.item-img {
width: 32px;
height: 32px;
}
.name {
min-width: 12rem;
}
}
}
.miracles {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 10px;
.miracle {
display: flex;
align-items: center;
gap: 10px;
.item-img {
width: 32px;
height: 32px;
}
.name {
min-width: 12rem;
}
}
}

View File

@@ -35,6 +35,25 @@
<span class="name">Hair</span>
{{formInput systemFields.biodata.fields.hair value=system.biodata.hair }}
</div>
<div class="biodata-elem">
<span class="name">Magic User</span>
{{formInput systemFields.biodata.fields.magicUser value=system.biodata.magicUser }}
</div>
<div class="biodata-elem">
<span class="name">Save bonus (1/5levels)</span>
{{formInput systemFields.modifiers.fields.saveModifier value=system.modifiers.saveModifier disabled=true}}
</div>
{{#if system.biodata.magicUser}}
<div class="biodata-elem">
<span class="name">Spell bonus (1/5levels)</span>
{{formInput systemFields.modifiers.fields.levelSpellModifier value=system.modifiers.levelSpellModifier disabled=true}}
</div>
<div class="biodata-elem">
<span class="name">Miracle bonus (1/5levels)</span>
{{formInput systemFields.modifiers.fields.levelMiracleModifier value=system.modifiers.levelMiracleModifier disabled=true}}
</div>
{{/if}}
</div>

View File

@@ -6,11 +6,38 @@
data-action="createSpell"></i></a>{{/if}}</legend>
<div class="spells">
{{#each spells as |item|}}
{{!log 'weapon' this}}
<div class="spell" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true"
data-drag-type="spell">
<div class="name" data-tooltip="{{{item.system.description}}}">
<div class="spell" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true" >
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<div class="name" >
<a class="rollable" data-roll-type="spell" data-roll-key="{{item.id}}">
<i class="lf-roll-small fa-solid fa-dice-d20"></i>
{{item.name}}
</a>
</div>
<div class="controls">
<a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-edit"></i></a>
<a data-tooltip="{{localize 'LETHALFANTASY.Delete'}}" data-action="delete" data-item-id="{{item.id}}"
data-item-uuid="{{item.uuid}}"><i class="fas fa-trash"></i></a>
</div>
</div>
{{/each}}
</div>
</fieldset>
<fieldset>
<legend>{{localize "LETHALFANTASY.Label.miracles"}}{{#if isEditMode}}<a class="action" data-tooltip="{{localize "
LETHALFANTASY.Tooltip.addMiracle"}}" data-tooltip-direction="UP"><i class="fas fa-plus"
data-action="createMiracle"></i></a>{{/if}}</legend>
<div class="miracles">
{{#each miracles as |item|}}
<div class="miracle" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true" >
<img class="item-img" src="{{item.img}}" data-tooltip="{{item.name}}" />
<div class="name" >
<a class="rollable" data-roll-type="miracle" data-roll-key="{{item.id}}">
<i class="lf-roll-small fa-solid fa-dice-d20"></i>
{{item.name}}
</a>
</div>
<div class="controls">
<a data-tooltip="{{localize 'LETHALFANTASY.Edit'}}" data-action="edit" data-item-id="{{item.id}}"

View File

@@ -1,8 +1,9 @@
<section class="tab character-{{tab.id}} {{tab.cssClass}}" data-tab="{{tab.id}}" data-group="{{tab.group}}">
<button class="action" data-action="rangedAttackDefense">{{localize "LETHALFANTASY.Label.rangedAttackDefense"}}</button>
<fieldset>
<legend>{{localize "LETHALFANTASY.Label.weapons"}}</legend>
<div class="weapons">
{{#each weapons as |item|}}
<div class="weapon" data-item-id="{{item.id}}" data-item-uuid="{{item.uuid}}" data-drag="true"

View File

@@ -1,6 +0,0 @@
<div class="tenebris ask-roll">
<h4 class="ask-roll-title">{{title}}<br>{{text}}</h4>
<a class="ask-roll-dice" data-type="{{rollType}}" data-value="{{value}}" data-avantage="{{avantage}}">
<i class="fas fa-dice-d20" title="{{localize 'TENEBRIS.Manager.roll'}}"></i> {{localize 'TENEBRIS.Manager.roll'}}
</a>
</div>

View File

@@ -1,17 +0,0 @@
{{!log 'chat-fortune' this}}
<div class="tenebris fortune">
<div class="intro-chat">
{{#if (ne actingCharImg "icons/svg/mystery-man.svg")}}
<div class="intro-img">
<img src="{{actingCharImg}}" data-tooltip="{{name}}" />
</div>
{{/if}}
<div class="intro-right">
<p class="introText">{{localize "TENEBRIS.Chat.askFortune" name=name}}</p>
</div>
</div>
{{#if isGM}}
<a class="button control" data-action="accept-fortune" data-tooltip="Accepter"><i class="fa-solid fa-check"></i></a>
<div class="fortune-accepted" style="display: none;">Accepté !</div>
{{/if}}
</div>

View File

@@ -45,9 +45,16 @@
{{/if}}
</div>
{{/if}}
{{#unless isPrivate}}
<div class="dice-result">
<h4 class="dice-total">{{total}}</h4>
</div>
{{#if D30result}}
<div class="dice-result">
<h4 class="dice-total">D30 result: {{D30result}}</h4>
</div>
{{/if}}
{{/unless}}
</div>

View File

@@ -0,0 +1,35 @@
<div class="lethalfantasy-range-defense-dialog">
<fieldSet class="">
<legend>{{localize "LETHALFANTASY.Label.rangeDefenseDialog"}}</legend>
<select name="movement" data-tooltip-direction="UP">
{{selectOptions movementChoices selected=movement}}
</select>
<select name="moveDirection" data-tooltip-direction="UP">
{{selectOptions moveDirectionChoices selected=moveDirection}}
</select>
<select name="size" data-tooltip-direction="UP">
{{selectOptions sizeChoices selected=size}}
</select>
<select name="range" data-tooltip-direction="UP">
{{selectOptions rangeChoices selected=range}}
</select>
<select name="attackerAim" data-tooltip-direction="UP">
{{selectOptions attackerAimChoices selected=attackerAim}}
</select>
</fieldSet>
<fieldSet>
<legend>{{localize "LETHALFANTASY.Roll.visibility"}}</legend>
<select name="visibility">
{{selectOptions rollModes selected=visibility}}
</select>
</fieldSet>
</div>

View File

@@ -1,4 +1,3 @@
{{log "roll-dialog" this}}
<div class="lethalfantasy-roll-dialog">
<fieldSet class="">
@@ -16,12 +15,22 @@
{{/if}}
</fieldSet>
{{#if hasModifier}}
<fieldSet class="dialog-modifier">
<legend>{{localize "LETHALFANTASY.Roll.modifierBonusMalus"}}</legend>
<select name="modifier" data-tooltip-direction="UP">
{{selectOptions choiceModifier selected=modifier}}
</select>
{{#if (eq rollType "save")}}
{{#if rollTarget.magicUser}}
<div>
<span>Save against spell (+{{rollTarget.actorModifiers.saveModifier}}) ?</span>
<input type="checkbox" name="saveSpell" value="saveSpell">
</div>
{{/if}}
{{/if}}
</fieldSet>
{{/if}}