- Profils raciaux appliqués automatiquement - DsN opératonnel - Gestion plus fine des fils/orbes
This commit is contained in:
+46
-1
@@ -233,6 +233,9 @@
|
||||
.fvtt-les-oublies .sheet-grid-2 {
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
.fvtt-les-oublies .sheet-grid-3 {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
.fvtt-les-oublies .sheet-card {
|
||||
background: linear-gradient(180deg, var(--lo-panel), var(--lo-panel-heavy)), linear-gradient(135deg, rgba(255, 255, 255, 0.24), transparent);
|
||||
border: 1px solid rgba(133, 99, 74, 0.5);
|
||||
@@ -362,6 +365,46 @@
|
||||
.fvtt-les-oublies .group-block + .group-block {
|
||||
margin-top: var(--lo-space-lg);
|
||||
}
|
||||
.fvtt-les-oublies .reserve-card .reserve-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: var(--lo-space-sm);
|
||||
margin-bottom: var(--lo-space-sm);
|
||||
}
|
||||
.fvtt-les-oublies .reserve-panel {
|
||||
min-width: 0;
|
||||
padding: 0.55rem 0.65rem;
|
||||
border-radius: var(--lo-radius-lg);
|
||||
background: linear-gradient(180deg, rgba(255, 250, 243, 0.7), rgba(230, 214, 185, 0.6));
|
||||
border: 1px solid rgba(130, 98, 71, 0.2);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.fvtt-les-oublies .reserve-panel h3 {
|
||||
margin-bottom: 0.45rem;
|
||||
}
|
||||
.fvtt-les-oublies .transfer-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
margin-top: 0.45rem;
|
||||
}
|
||||
.fvtt-les-oublies .transfer-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
gap: 0.4rem;
|
||||
align-items: center;
|
||||
}
|
||||
.fvtt-les-oublies .transfer-row strong {
|
||||
min-width: 0;
|
||||
font-size: var(--lo-font-body);
|
||||
}
|
||||
.fvtt-les-oublies .transfer-row input[type="number"] {
|
||||
width: 3.6rem;
|
||||
min-width: 3.6rem;
|
||||
}
|
||||
.fvtt-les-oublies .transfer-row .item-controls {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
.fvtt-les-oublies .group-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -723,8 +766,10 @@
|
||||
}
|
||||
@media (max-width: 900px) {
|
||||
.fvtt-les-oublies .sheet-grid-2,
|
||||
.fvtt-les-oublies .sheet-grid-3,
|
||||
.fvtt-les-oublies .profile-grid,
|
||||
.fvtt-les-oublies .creation-slots {
|
||||
.fvtt-les-oublies .creation-slots,
|
||||
.fvtt-les-oublies .reserve-card .reserve-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
.fvtt-les-oublies .hero-banner {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -169,6 +169,14 @@
|
||||
"creditCauchemar": "Crédits Cauchemar",
|
||||
"pointsSonges": "Points de Songes",
|
||||
"pointsCauchemar": "Points de Cauchemar",
|
||||
"threadReserves": "Fils et globes",
|
||||
"personalReserve": "Réserve personnelle",
|
||||
"companyReserve": "Réserve de compagnie",
|
||||
"threadSonges": "Fils de Songes",
|
||||
"threadCauchemar": "Fils de Cauchemar",
|
||||
"emptyGlobes": "Globes vides",
|
||||
"toCompany": "→ Compagnie",
|
||||
"toActor": "← Perso",
|
||||
"degats": "Dégâts",
|
||||
"sortilegesSonges": "Sortilèges de Songes",
|
||||
"sortilegesCauchemar": "Sortilèges de Cauchemar",
|
||||
|
||||
@@ -214,6 +214,10 @@
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.sheet-grid-3 {
|
||||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||
}
|
||||
|
||||
.sheet-card {
|
||||
background:
|
||||
linear-gradient(180deg, var(--lo-panel), var(--lo-panel-heavy)),
|
||||
@@ -379,6 +383,54 @@
|
||||
margin-top: var(--lo-space-lg);
|
||||
}
|
||||
|
||||
.reserve-card .reserve-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||
gap: var(--lo-space-sm);
|
||||
margin-bottom: var(--lo-space-sm);
|
||||
}
|
||||
|
||||
.reserve-panel {
|
||||
min-width: 0;
|
||||
padding: 0.55rem 0.65rem;
|
||||
border-radius: var(--lo-radius-lg);
|
||||
background: linear-gradient(180deg, rgba(255, 250, 243, 0.7), rgba(230, 214, 185, 0.6));
|
||||
border: 1px solid rgba(130, 98, 71, 0.2);
|
||||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.reserve-panel h3 {
|
||||
margin-bottom: 0.45rem;
|
||||
}
|
||||
|
||||
.transfer-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 0.35rem;
|
||||
margin-top: 0.45rem;
|
||||
}
|
||||
|
||||
.transfer-row {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr) auto auto;
|
||||
gap: 0.4rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.transfer-row strong {
|
||||
min-width: 0;
|
||||
font-size: var(--lo-font-body);
|
||||
}
|
||||
|
||||
.transfer-row input[type="number"] {
|
||||
width: 3.6rem;
|
||||
min-width: 3.6rem;
|
||||
}
|
||||
|
||||
.transfer-row .item-controls {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.group-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -833,8 +885,10 @@
|
||||
|
||||
@media (max-width: 900px) {
|
||||
.sheet-grid-2,
|
||||
.sheet-grid-3,
|
||||
.profile-grid,
|
||||
.creation-slots {
|
||||
.creation-slots,
|
||||
.reserve-card .reserve-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ export default class LesOubliesActorSheet extends HandlebarsApplicationMixin(fou
|
||||
openCombatPreset: LesOubliesActorSheet.#onOpenCombatPreset,
|
||||
openThreadHarvest: LesOubliesActorSheet.#onOpenThreadHarvest,
|
||||
openLinkedActor: LesOubliesActorSheet.#onOpenLinkedActor,
|
||||
transferThread: LesOubliesActorSheet.#onTransferThread,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -217,4 +218,26 @@ export default class LesOubliesActorSheet extends HandlebarsApplicationMixin(fou
|
||||
const actor = game.actors.get(actorId)
|
||||
if (actor) actor.sheet.render(true)
|
||||
}
|
||||
|
||||
static async #onTransferThread(event, target) {
|
||||
const resourceKey = target.dataset.resourceKey
|
||||
const direction = target.dataset.direction || "toCompany"
|
||||
if (!resourceKey || !this.document?.transferThreadReserve) return
|
||||
|
||||
const row = target.closest("[data-transfer-row]")
|
||||
const amountField = row?.querySelector?.("[data-transfer-amount]")
|
||||
const amount = Math.max(Math.trunc(Number(amountField?.value ?? 1)), 0)
|
||||
if (amount < 1) {
|
||||
ui.notifications.warn("Indiquez une quantité à transférer.")
|
||||
return
|
||||
}
|
||||
|
||||
const success = await this.document.transferThreadReserve(resourceKey, amount, direction)
|
||||
if (!success) {
|
||||
ui.notifications.warn("Transfert impossible avec les réserves actuelles.")
|
||||
return
|
||||
}
|
||||
|
||||
this.render()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ export default class LesOubliesCompagnieSheet extends LesOubliesActorSheet {
|
||||
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-oublies/templates/actor-compagnie-sheet-v4.hbs",
|
||||
template: "systems/fvtt-les-oublies/templates/actor-compagnie-sheet-v5.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import LesOubliesItemSheet from "./base-item-sheet.mjs"
|
||||
export default class LesOubliesCompetenceSheet extends LesOubliesItemSheet {
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-oublies/templates/item-competence-sheet.hbs",
|
||||
template: "systems/fvtt-les-oublies/templates/item-competence-sheet-v2.hbs",
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export default class LesOubliesPersonnageSheet extends LesOubliesActorSheet {
|
||||
|
||||
static PARTS = {
|
||||
sheet: {
|
||||
template: "systems/fvtt-les-oublies/templates/actor-personnage-sheet-v14.hbs",
|
||||
template: "systems/fvtt-les-oublies/templates/actor-personnage-sheet-v18.hbs",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ import { LesOubliesRolls } from "./les-oublies-rolls.js"
|
||||
|
||||
export class LesOubliesActor extends Actor {
|
||||
static CREATION_ITEM_TYPES = new Set(["race", "tribu", "metier"])
|
||||
static THREAD_RESOURCE_KEYS = new Set(["songesThreads", "cauchemarThreads", "emptyGlobes"])
|
||||
|
||||
prepareDerivedData() {
|
||||
super.prepareDerivedData()
|
||||
@@ -22,6 +23,18 @@ export class LesOubliesActor extends Actor {
|
||||
system.cauchemar.max = totals.cauchemarPoints
|
||||
system.songes.points = Math.clamp(Number(system.songes.points ?? totals.songesPoints), 0, totals.songesPoints)
|
||||
system.cauchemar.points = Math.clamp(Number(system.cauchemar.points ?? totals.cauchemarPoints), 0, totals.cauchemarPoints)
|
||||
system.reserves.songesThreads = Math.max(Number(system.reserves?.songesThreads ?? 0), 0)
|
||||
system.reserves.cauchemarThreads = Math.max(Number(system.reserves?.cauchemarThreads ?? 0), 0)
|
||||
system.reserves.emptyGlobes = Math.max(Number(system.reserves?.emptyGlobes ?? 0), 0)
|
||||
return
|
||||
}
|
||||
|
||||
if (this.type === "compagnie") {
|
||||
const system = this.system
|
||||
system.power.sharedDreamPoints = Math.max(Number(system.power?.sharedDreamPoints ?? 0), 0)
|
||||
system.reserves.songesThreads = Math.max(Number(system.reserves?.songesThreads ?? 0), 0)
|
||||
system.reserves.cauchemarThreads = Math.max(Number(system.reserves?.cauchemarThreads ?? 0), 0)
|
||||
system.reserves.emptyGlobes = Math.max(Number(system.reserves?.emptyGlobes ?? 0), 0)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -62,6 +75,7 @@ export class LesOubliesActor extends Actor {
|
||||
async assignCreationItem(sourceItem) {
|
||||
if (!sourceItem || !LesOubliesActor.CREATION_ITEM_TYPES.has(sourceItem.type)) return null
|
||||
|
||||
const previousItem = this.getCreationItem(sourceItem.type)
|
||||
const itemData = sourceItem.toObject()
|
||||
delete itemData._id
|
||||
|
||||
@@ -77,12 +91,19 @@ export class LesOubliesActor extends Actor {
|
||||
[`system.references.${sourceItem.type}Id`]: createdItem.id,
|
||||
})
|
||||
|
||||
if (sourceItem.type === "race") {
|
||||
await this.syncRaceProfiles({ currentRace: createdItem })
|
||||
await this.syncRaceDomains({ currentRace: createdItem, previousRace: previousItem })
|
||||
}
|
||||
|
||||
return createdItem
|
||||
}
|
||||
|
||||
async clearCreationItem(type) {
|
||||
if (!LesOubliesActor.CREATION_ITEM_TYPES.has(type)) return
|
||||
|
||||
const previousItem = this.getCreationItem(type)
|
||||
|
||||
const existingIds = this.getEmbeddedItems(type).map((item) => item.id)
|
||||
if (existingIds.length) {
|
||||
await this.deleteEmbeddedDocuments("Item", existingIds, { renderSheet: false })
|
||||
@@ -91,6 +112,11 @@ export class LesOubliesActor extends Actor {
|
||||
await this.update({
|
||||
[`system.references.${type}Id`]: "",
|
||||
})
|
||||
|
||||
if (type === "race") {
|
||||
await this.syncRaceProfiles({ currentRace: null })
|
||||
await this.syncRaceDomains({ currentRace: null, previousRace: previousItem })
|
||||
}
|
||||
}
|
||||
|
||||
getCompagnie() {
|
||||
@@ -98,10 +124,94 @@ export class LesOubliesActor extends Actor {
|
||||
return compagnieId ? game.actors.get(compagnieId) ?? null : null
|
||||
}
|
||||
|
||||
getThreadReserveOwner(source = "actor") {
|
||||
if (source === "company" || source === "compagnie") return this.getCompagnie()
|
||||
return this
|
||||
}
|
||||
|
||||
getThreadReserves(source = "actor") {
|
||||
const owner = this.getThreadReserveOwner(source)
|
||||
return {
|
||||
owner,
|
||||
songesThreads: Math.max(Number(owner?.system?.reserves?.songesThreads ?? 0), 0),
|
||||
cauchemarThreads: Math.max(Number(owner?.system?.reserves?.cauchemarThreads ?? 0), 0),
|
||||
emptyGlobes: Math.max(Number(owner?.system?.reserves?.emptyGlobes ?? 0), 0),
|
||||
}
|
||||
}
|
||||
|
||||
async transferThreadReserve(resourceKey, amount, direction = "toCompany") {
|
||||
if (!LesOubliesActor.THREAD_RESOURCE_KEYS.has(resourceKey)) return false
|
||||
const company = this.getCompagnie()
|
||||
if (!company) return false
|
||||
|
||||
const transferAmount = Math.max(Math.trunc(Number(amount ?? 0)), 0)
|
||||
if (transferAmount < 1) return false
|
||||
|
||||
const fromActor = direction === "toCompany" ? this : company
|
||||
const toActor = direction === "toCompany" ? company : this
|
||||
const current = Math.max(Number(fromActor.system?.reserves?.[resourceKey] ?? 0), 0)
|
||||
if (current < transferAmount) return false
|
||||
|
||||
const path = `system.reserves.${resourceKey}`
|
||||
const targetCurrent = Math.max(Number(toActor.system?.reserves?.[resourceKey] ?? 0), 0)
|
||||
|
||||
await fromActor.update({ [path]: current - transferAmount })
|
||||
await toActor.update({ [path]: targetCurrent + transferAmount })
|
||||
return true
|
||||
}
|
||||
|
||||
getCompetenceByKey(skillKey) {
|
||||
return this.getEmbeddedItems("competence").find((item) => item.system.key === skillKey) ?? null
|
||||
}
|
||||
|
||||
getRaceLanguageDomains(race = this.getCreationItem("race")) {
|
||||
return LesOubliesUtility.uniqueStrings(race?.system?.languageDomains ?? [])
|
||||
}
|
||||
|
||||
getRaceProfiles(race = this.getCreationItem("race")) {
|
||||
const profiles = LesOubliesUtility.createEmptyProfiles()
|
||||
for (const key of Object.keys(profiles)) {
|
||||
profiles[key] = Math.trunc(Number(race?.system?.profiles?.[key] ?? 0))
|
||||
}
|
||||
return profiles
|
||||
}
|
||||
|
||||
async syncRaceProfiles({ currentRace = this.getCreationItem("race") } = {}) {
|
||||
if (this.type !== "personnage") return false
|
||||
const profiles = this.getRaceProfiles(currentRace)
|
||||
const updateData = Object.fromEntries(
|
||||
Object.entries(profiles).map(([key, value]) => [`system.profils.${key}`, value]),
|
||||
)
|
||||
await this.update(updateData)
|
||||
if (currentRace) {
|
||||
ui.notifications.info(`Profils raciaux appliqués depuis ${currentRace.name}.`)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async syncRaceDomains({ currentRace = this.getCreationItem("race"), previousRace = null } = {}) {
|
||||
if (this.type !== "personnage") return false
|
||||
|
||||
const competence = this.getCompetenceByKey("langues")
|
||||
if (!competence) return false
|
||||
|
||||
const currentAutoDomains = LesOubliesUtility.uniqueStrings(competence.system.fixedDomains ?? [])
|
||||
const previousRaceDomains = previousRace
|
||||
? this.getRaceLanguageDomains(previousRace)
|
||||
: currentAutoDomains
|
||||
const autoDomainsToReplace = currentAutoDomains.length ? currentAutoDomains : previousRaceDomains
|
||||
const nextAutoDomains = this.getRaceLanguageDomains(currentRace)
|
||||
const manualDomains = LesOubliesUtility.uniqueStrings(
|
||||
(competence.system.domains ?? []).filter((domain) => !autoDomainsToReplace.includes(domain)),
|
||||
)
|
||||
|
||||
await competence.update({
|
||||
"system.fixedDomains": nextAutoDomains,
|
||||
"system.domains": LesOubliesUtility.uniqueStrings([...manualDomains, ...nextAutoDomains]),
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
getSkillScoreByKey(skillKey) {
|
||||
const competence = this.getCompetenceByKey(skillKey)
|
||||
return competence ? this.computeSkillValue(competence) : 0
|
||||
@@ -119,6 +229,8 @@ export class LesOubliesActor extends Actor {
|
||||
item,
|
||||
finalValue: this.computeSkillValue(item),
|
||||
profileLabel: LESOUBLIES_CONFIG.profileLabels[item.system.profileKey] ?? item.system.profileKey,
|
||||
domains: LesOubliesUtility.uniqueStrings(item.system.domains ?? []),
|
||||
fixedDomains: LesOubliesUtility.uniqueStrings(item.system.fixedDomains ?? []),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -146,6 +258,8 @@ export class LesOubliesActor extends Actor {
|
||||
cauchemarMax: this.system.cauchemar?.max ?? this.system.cauchemar?.points ?? 0,
|
||||
songesPoints: this.system.songes?.points ?? 0,
|
||||
cauchemarPoints: this.system.cauchemar?.points ?? 0,
|
||||
reserves: this.getThreadReserves(),
|
||||
companyReserves: this.getThreadReserves("company"),
|
||||
race: this.getCreationItem("race"),
|
||||
tribu: this.getCreationItem("tribu"),
|
||||
metier: this.getCreationItem("metier"),
|
||||
|
||||
@@ -439,7 +439,12 @@ export class LesOubliesRolls {
|
||||
|
||||
const data = await this.#promptSpellOptions(actor, spell)
|
||||
if (!data) return null
|
||||
const activation = await this.#withActorLock(`spell:${actor.id}`, async () => {
|
||||
const paymentMode = String(data.paymentMode || "points")
|
||||
const paymentSource = this.#normalizeThreadReserveSource(data.paymentSource)
|
||||
const paymentOwner = paymentMode === "fils"
|
||||
? this.#getThreadReserveOwner(actor, paymentSource)
|
||||
: actor
|
||||
const activation = await this.#withActorLock(`spell:${paymentOwner?.id ?? actor.id}:${paymentMode}`, async () => {
|
||||
const skill = actor.getCompetenceByKey?.(spell.system.skillKey) ?? null
|
||||
const skillBase = Number(skill?.system?.base ?? 0)
|
||||
if (skillBase < 1) {
|
||||
@@ -450,7 +455,6 @@ export class LesOubliesRolls {
|
||||
const métierMatch = this.#actorMatchesSpellGrant(actor, spell)
|
||||
const surcharge = !métierMatch
|
||||
const effectiveCost = Number(data.actualCost ?? 0) * (surcharge ? 2 : 1)
|
||||
const paymentMode = String(data.paymentMode || "points")
|
||||
if (paymentMode === "points") {
|
||||
const resource = spell.system.polarity || "songes"
|
||||
const available = Number(actor.system?.[resource]?.points ?? 0)
|
||||
@@ -468,9 +472,43 @@ export class LesOubliesRolls {
|
||||
[`system.${resource}.points`]: Math.max(available - effectiveCost, 0),
|
||||
})
|
||||
}
|
||||
} else {
|
||||
const reserve = this.#getThreadReserveState(actor, paymentSource)
|
||||
if (!reserve.owner) {
|
||||
ui.notifications.warn("Aucune réserve de compagnie n'est liée à ce personnage.")
|
||||
return null
|
||||
}
|
||||
|
||||
const resourceKey = this.#getThreadResourceKey(spell.system.polarity)
|
||||
const available = Number(reserve[resourceKey] ?? 0)
|
||||
if (available < effectiveCost) {
|
||||
ui.notifications.warn(game.i18n.format("LESOUBLIES.rolls.notEnoughResourceDetailed", {
|
||||
resource: `${effectiveCost > 1 ? "fils" : "fil"} de ${spell.system.polarity === "cauchemar" ? "Cauchemar" : "Songes"}`,
|
||||
actor: reserve.label,
|
||||
required: effectiveCost,
|
||||
available,
|
||||
}))
|
||||
return null
|
||||
}
|
||||
|
||||
if (effectiveCost > 0) {
|
||||
await reserve.owner.update({
|
||||
[`system.reserves.${resourceKey}`]: Math.max(available - effectiveCost, 0),
|
||||
"system.reserves.emptyGlobes": Number(reserve.emptyGlobes ?? 0) + effectiveCost,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return { métierMatch, surcharge, effectiveCost, paymentMode }
|
||||
return {
|
||||
métierMatch,
|
||||
surcharge,
|
||||
effectiveCost,
|
||||
paymentMode,
|
||||
paymentSource,
|
||||
paymentSourceLabel: paymentMode === "fils"
|
||||
? this.#getThreadReserveLabel(actor, paymentSource)
|
||||
: actor.name,
|
||||
}
|
||||
})
|
||||
if (!activation) return null
|
||||
|
||||
@@ -487,6 +525,7 @@ export class LesOubliesRolls {
|
||||
costLabel: activation.paymentMode === "points"
|
||||
? `${activation.effectiveCost} point${activation.effectiveCost > 1 ? "s" : ""} de ${spell.system.polarity === "cauchemar" ? "Cauchemar" : "Songes"}`
|
||||
: `${activation.effectiveCost} fil${activation.effectiveCost > 1 ? "s" : ""} de ${spell.system.polarity === "cauchemar" ? "Cauchemar" : "Songes"}`,
|
||||
paymentSourceLabel: activation.paymentSourceLabel,
|
||||
métierMatch: activation.métierMatch,
|
||||
surcharge: activation.surcharge,
|
||||
notes: data.notes?.trim() || "",
|
||||
@@ -578,6 +617,17 @@ export class LesOubliesRolls {
|
||||
if (!data) return null
|
||||
|
||||
const threadCount = Math.max(Number(data.threadCount ?? 1), 1)
|
||||
const destinationSource = this.#normalizeThreadReserveSource(data.destinationSource)
|
||||
const destinationReserve = this.#getThreadReserveState(actor, destinationSource)
|
||||
if (!destinationReserve.owner) {
|
||||
ui.notifications.warn("Aucune réserve de compagnie n'est liée à ce personnage.")
|
||||
return null
|
||||
}
|
||||
if (Number(destinationReserve.emptyGlobes ?? 0) < threadCount) {
|
||||
ui.notifications.warn(`${destinationReserve.label} ne dispose pas de suffisamment de globes vides pour stocker cette récolte.`)
|
||||
return null
|
||||
}
|
||||
|
||||
const damageTaken = threadCount
|
||||
const difficulty = -3 * (threadCount - 1)
|
||||
const result = await this.resolveTest(actor, {
|
||||
@@ -599,8 +649,11 @@ export class LesOubliesRolls {
|
||||
if (!result) return null
|
||||
|
||||
await this.#applyDamageToActor(actor, damageTaken)
|
||||
const durationRoll = await (new Roll("1d12")).evaluate()
|
||||
const effectRoll = await (new Roll("1d12")).evaluate()
|
||||
if (result.success) {
|
||||
await this.#storeHarvestedThreads(actor, destinationSource, data.threadType, threadCount)
|
||||
}
|
||||
const durationRoll = await this.#evaluateDisplayedRoll("1d12")
|
||||
const effectRoll = await this.#evaluateDisplayedRoll("1d12")
|
||||
const effectIndex = Number(effectRoll.total ?? 1)
|
||||
result.metadata.action.harvest = {
|
||||
threadType: data.threadType,
|
||||
@@ -611,6 +664,8 @@ export class LesOubliesRolls {
|
||||
sideEffectRoll: effectIndex,
|
||||
sideEffectText: HARVEST_SIDE_EFFECTS[effectIndex],
|
||||
sleeperLabel: data.sleeperLabel?.trim() || "Dormeur non précisé",
|
||||
destinationLabel: destinationReserve.label,
|
||||
stored: result.success,
|
||||
}
|
||||
|
||||
return this.#createChatMessage(actor, result)
|
||||
@@ -1129,17 +1184,20 @@ export class LesOubliesRolls {
|
||||
const polarityLabel = spell.system.polarity === "cauchemar"
|
||||
? game.i18n.localize("LESOUBLIES.ui.cauchemar")
|
||||
: game.i18n.localize("LESOUBLIES.ui.songes")
|
||||
const threadReserves = this.#getThreadDialogState(actor)
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-les-oublies/templates/dialog-spell-activation.hbs",
|
||||
"systems/fvtt-les-oublies/templates/dialog-spell-activation-v2.hbs",
|
||||
{
|
||||
actor,
|
||||
spell,
|
||||
resources: this.#getDialogResources(actor),
|
||||
threadReserves,
|
||||
isMetierMatch,
|
||||
effectiveCostLabel: `${effectiveCost} point${effectiveCost > 1 ? "s" : ""} de ${polarityLabel}`,
|
||||
values: {
|
||||
actualCost: Number(spell.system.cost ?? 0),
|
||||
paymentMode: "points",
|
||||
paymentSource: "actor",
|
||||
targetLabel: "",
|
||||
notes: "",
|
||||
},
|
||||
@@ -1151,6 +1209,9 @@ export class LesOubliesRolls {
|
||||
title: `Activer ${spell.name}`,
|
||||
},
|
||||
content,
|
||||
render: (_event, dialog) => {
|
||||
this.#bindSpellPaymentSelection(dialog, { actor, spell, effectiveCost })
|
||||
},
|
||||
buttons: [
|
||||
{
|
||||
action: "activate",
|
||||
@@ -1161,8 +1222,9 @@ export class LesOubliesRolls {
|
||||
if (!form) return null
|
||||
const data = this.#formToObject(form)
|
||||
return {
|
||||
actualCost: Number(data.actualCost ?? spell.system.cost ?? 0),
|
||||
actualCost: Math.max(Number(data.actualCost ?? spell.system.cost ?? 0), 0),
|
||||
paymentMode: String(data.paymentMode || "points"),
|
||||
paymentSource: String(data.paymentSource || "actor"),
|
||||
targetLabel: String(data.targetLabel || ""),
|
||||
notes: String(data.notes || ""),
|
||||
}
|
||||
@@ -1338,16 +1400,19 @@ export class LesOubliesRolls {
|
||||
}
|
||||
|
||||
static async #promptThreadHarvestOptions(actor) {
|
||||
const threadReserves = this.#getThreadDialogState(actor)
|
||||
const content = await foundry.applications.handlebars.renderTemplate(
|
||||
"systems/fvtt-les-oublies/templates/dialog-thread-harvest.hbs",
|
||||
"systems/fvtt-les-oublies/templates/dialog-thread-harvest-v2.hbs",
|
||||
{
|
||||
actor,
|
||||
rollModes: this.getRollModes(),
|
||||
extraDieModes: this.getExtraDieModes(),
|
||||
resources: this.#getDialogResources(actor),
|
||||
threadReserves,
|
||||
values: {
|
||||
threadType: "songes",
|
||||
threadCount: 1,
|
||||
destinationSource: "actor",
|
||||
rollMode: this.getDefaultRollMode(actor),
|
||||
extraDie: "",
|
||||
sleeperLabel: "",
|
||||
@@ -1373,6 +1438,7 @@ export class LesOubliesRolls {
|
||||
return {
|
||||
threadType: String(data.threadType || "songes"),
|
||||
threadCount: Number(data.threadCount ?? 1),
|
||||
destinationSource: String(data.destinationSource || "actor"),
|
||||
rollMode: String(data.rollMode || this.getDefaultRollMode(actor)),
|
||||
extraDie: String(data.extraDie || ""),
|
||||
sleeperLabel: String(data.sleeperLabel || ""),
|
||||
@@ -1443,12 +1509,14 @@ export class LesOubliesRolls {
|
||||
|
||||
static async #rollExplodingDie({ type, index, source = "base" }) {
|
||||
const faces = []
|
||||
const rolls = []
|
||||
let total = 0
|
||||
let lastFace = 12
|
||||
|
||||
while (lastFace === 12) {
|
||||
const roll = await (new Roll("1d12")).evaluate()
|
||||
const roll = await this.#evaluateDisplayedRoll("1d12")
|
||||
lastFace = Number(roll.total ?? 0)
|
||||
rolls.push(roll)
|
||||
faces.push(lastFace)
|
||||
total += lastFace
|
||||
}
|
||||
@@ -1461,6 +1529,7 @@ export class LesOubliesRolls {
|
||||
source,
|
||||
sourceLabel: source === "extra" ? game.i18n.localize("LESOUBLIES.rolls.extraDie") : null,
|
||||
faces,
|
||||
rolls,
|
||||
firstFace: faces[0] ?? 0,
|
||||
total,
|
||||
exploded: faces.length > 1,
|
||||
@@ -1468,6 +1537,39 @@ export class LesOubliesRolls {
|
||||
}
|
||||
}
|
||||
|
||||
static async #evaluateDisplayedRoll(formula) {
|
||||
const roll = await (new Roll(formula)).evaluate()
|
||||
await this.#showDiceSoNice(roll)
|
||||
return roll
|
||||
}
|
||||
|
||||
static async #showDiceSoNice(roll) {
|
||||
if (!game.modules.get("dice-so-nice")?.active) return
|
||||
if (!game.dice3d?.showForRoll) return
|
||||
|
||||
const coreRollMode = game.settings.get("core", "rollMode")
|
||||
let whisper = null
|
||||
let blind = false
|
||||
|
||||
switch (coreRollMode) {
|
||||
case "blindroll":
|
||||
blind = true
|
||||
case "gmroll":
|
||||
whisper = ChatMessage.getWhisperRecipients("GM").map((user) => user.id)
|
||||
break
|
||||
case "selfroll":
|
||||
whisper = [game.user.id]
|
||||
break
|
||||
case "publicroll":
|
||||
case "roll":
|
||||
default:
|
||||
whisper = null
|
||||
break
|
||||
}
|
||||
|
||||
await game.dice3d.showForRoll(roll, game.user, true, whisper, blind)
|
||||
}
|
||||
|
||||
static #needsSelection(dice) {
|
||||
return new Set(dice.map((die) => die.type)).size > 1
|
||||
}
|
||||
@@ -1571,9 +1673,106 @@ export class LesOubliesRolls {
|
||||
songesPoints: Number(context.system.songes?.points ?? 0),
|
||||
cauchemarValue: Number(context.system.cauchemar?.value ?? 0),
|
||||
cauchemarPoints: Number(context.system.cauchemar?.points ?? 0),
|
||||
songesThreads: Number(context.system.reserves?.songesThreads ?? 0),
|
||||
cauchemarThreads: Number(context.system.reserves?.cauchemarThreads ?? 0),
|
||||
emptyGlobes: Number(context.system.reserves?.emptyGlobes ?? 0),
|
||||
}
|
||||
}
|
||||
|
||||
static #normalizeThreadReserveSource(source) {
|
||||
return ["company", "compagnie"].includes(String(source || "").toLowerCase()) ? "company" : "actor"
|
||||
}
|
||||
|
||||
static #getThreadReserveOwner(actor, source = "actor") {
|
||||
return this.#normalizeThreadReserveSource(source) === "company"
|
||||
? actor?.getCompagnie?.() ?? null
|
||||
: actor
|
||||
}
|
||||
|
||||
static #getThreadReserveLabel(actor, source = "actor") {
|
||||
const normalized = this.#normalizeThreadReserveSource(source)
|
||||
if (normalized === "actor") return "Réserve personnelle"
|
||||
const company = this.#getThreadReserveOwner(actor, normalized)
|
||||
return company ? `Réserve de compagnie — ${company.name}` : "Réserve de compagnie"
|
||||
}
|
||||
|
||||
static #getThreadResourceKey(polarity) {
|
||||
return polarity === "cauchemar" ? "cauchemarThreads" : "songesThreads"
|
||||
}
|
||||
|
||||
static #getThreadReserveState(actor, source = "actor") {
|
||||
const owner = this.#getThreadReserveOwner(actor, source)
|
||||
return {
|
||||
owner,
|
||||
source: this.#normalizeThreadReserveSource(source),
|
||||
label: this.#getThreadReserveLabel(actor, source),
|
||||
songesThreads: Math.max(Number(owner?.system?.reserves?.songesThreads ?? 0), 0),
|
||||
cauchemarThreads: Math.max(Number(owner?.system?.reserves?.cauchemarThreads ?? 0), 0),
|
||||
emptyGlobes: Math.max(Number(owner?.system?.reserves?.emptyGlobes ?? 0), 0),
|
||||
}
|
||||
}
|
||||
|
||||
static #getThreadDialogState(actor) {
|
||||
const actorReserve = this.#getThreadReserveState(actor, "actor")
|
||||
const companyReserve = this.#getThreadReserveState(actor, "company")
|
||||
const options = [
|
||||
{ value: "actor", label: actorReserve.label },
|
||||
]
|
||||
if (companyReserve.owner) options.push({ value: "company", label: companyReserve.label })
|
||||
return {
|
||||
actor: actorReserve,
|
||||
company: companyReserve,
|
||||
options,
|
||||
hasCompany: Boolean(companyReserve.owner),
|
||||
}
|
||||
}
|
||||
|
||||
static async #storeHarvestedThreads(actor, destinationSource, threadType, threadCount) {
|
||||
const reserve = this.#getThreadReserveState(actor, destinationSource)
|
||||
if (!reserve.owner || threadCount < 1) return false
|
||||
const resourceKey = this.#getThreadResourceKey(threadType)
|
||||
await reserve.owner.update({
|
||||
[`system.reserves.${resourceKey}`]: Number(reserve[resourceKey] ?? 0) + threadCount,
|
||||
"system.reserves.emptyGlobes": Math.max(Number(reserve.emptyGlobes ?? 0) - threadCount, 0),
|
||||
})
|
||||
return true
|
||||
}
|
||||
|
||||
static #bindSpellPaymentSelection(dialog, { actor, spell, effectiveCost }) {
|
||||
const root = this.#getDialogElement(dialog)
|
||||
const form = root?.querySelector("form")
|
||||
if (!form) return
|
||||
|
||||
const modeField = form.elements.namedItem("paymentMode")
|
||||
const sourceField = form.elements.namedItem("paymentSource")
|
||||
const effectiveCostField = root.querySelector("[data-effective-cost]")
|
||||
const sourceWrapper = root.querySelector("[data-payment-source]")
|
||||
const sourceHint = root.querySelector("[data-payment-source-hint]")
|
||||
|
||||
const update = () => {
|
||||
const paymentMode = modeField instanceof HTMLSelectElement ? String(modeField.value || "points") : "points"
|
||||
const paymentSource = sourceField instanceof HTMLSelectElement ? String(sourceField.value || "actor") : "actor"
|
||||
const polarityLabel = spell.system.polarity === "cauchemar" ? "Cauchemar" : "Songes"
|
||||
if (effectiveCostField instanceof HTMLInputElement) {
|
||||
effectiveCostField.value = paymentMode === "points"
|
||||
? `${effectiveCost} point${effectiveCost > 1 ? "s" : ""} de ${polarityLabel}`
|
||||
: `${effectiveCost} fil${effectiveCost > 1 ? "s" : ""} de ${polarityLabel}`
|
||||
}
|
||||
if (sourceWrapper instanceof HTMLElement) {
|
||||
sourceWrapper.hidden = paymentMode !== "fils"
|
||||
}
|
||||
if (sourceHint instanceof HTMLElement) {
|
||||
sourceHint.textContent = paymentMode === "fils"
|
||||
? `${this.#getThreadReserveLabel(actor, paymentSource)} utilisée. Les globes vidés y retournent automatiquement.`
|
||||
: "La dépense se fait dans les points de Songes ou de Cauchemar du personnage."
|
||||
}
|
||||
}
|
||||
|
||||
if (modeField instanceof HTMLSelectElement) modeField.addEventListener("change", update)
|
||||
if (sourceField instanceof HTMLSelectElement) sourceField.addEventListener("change", update)
|
||||
update()
|
||||
}
|
||||
|
||||
static #createSpentResource(extraDie) {
|
||||
if (!extraDie) return null
|
||||
return {
|
||||
|
||||
@@ -97,6 +97,12 @@ export class LesOubliesUtility {
|
||||
return [...documents].sort((left, right) => left.name.localeCompare(right.name, "fr"))
|
||||
}
|
||||
|
||||
static uniqueStrings(values = []) {
|
||||
return [...new Set((Array.isArray(values) ? values : [])
|
||||
.map((value) => String(value ?? "").trim())
|
||||
.filter(Boolean))]
|
||||
}
|
||||
|
||||
static async prepareEnrichedHtml(documentName, type, systemData) {
|
||||
const htmlFields = game.system.documentTypes?.[documentName]?.[type]?.htmlFields ?? []
|
||||
const enriched = {}
|
||||
|
||||
@@ -21,6 +21,11 @@ export default class CompagnieDataModel extends foundry.abstract.TypeDataModel {
|
||||
label: new fields.StringField({ initial: "" }),
|
||||
details: new fields.StringField({ initial: "" }),
|
||||
}), { initial: [] }),
|
||||
reserves: new fields.SchemaField({
|
||||
songesThreads: new fields.NumberField({ initial: 0, integer: true, min: 0 }),
|
||||
cauchemarThreads: new fields.NumberField({ initial: 0, integer: true, min: 0 }),
|
||||
emptyGlobes: new fields.NumberField({ initial: 0, integer: true, min: 0 }),
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,11 @@ export default class PersonnageDataModel extends foundry.abstract.TypeDataModel
|
||||
money: new fields.SchemaField({
|
||||
ecorces: new fields.NumberField({ initial: 0, integer: true, min: 0 }),
|
||||
}),
|
||||
reserves: new fields.SchemaField({
|
||||
songesThreads: new fields.NumberField({ initial: 0, integer: true, min: 0 }),
|
||||
cauchemarThreads: new fields.NumberField({ initial: 0, integer: true, min: 0 }),
|
||||
emptyGlobes: new fields.NumberField({ initial: 0, integer: true, min: 0 }),
|
||||
}),
|
||||
flagsNarratifs: new fields.SchemaField({
|
||||
ombreDuTourment: new fields.BooleanField({ initial: false }),
|
||||
isCaptain: new fields.BooleanField({ initial: false }),
|
||||
|
||||
Binary file not shown.
Binary file not shown.
+1
-1
@@ -1 +1 @@
|
||||
2026/05/03-20:13:00.428719 7f25c15fe6c0 Delete type=3 #1
|
||||
2026/05/04-08:07:36.049759 7ff4349fd6c0 Delete type=3 #1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -1 +1 @@
|
||||
2026/05/03-20:13:00.445629 7f2577fff6c0 Delete type=3 #1
|
||||
2026/05/04-08:07:36.080095 7ff3e7fff6c0 Delete type=3 #1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
2026/05/03-20:13:00.492466 7f25c15fe6c0 Delete type=3 #1
|
||||
2026/05/04-08:07:36.144804 7ff4349fd6c0 Delete type=3 #1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
2026/05/03-20:13:00.461618 7f25c1dff6c0 Delete type=3 #1
|
||||
2026/05/04-08:07:36.101347 7ff4359ff6c0 Delete type=3 #1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -1 +1 @@
|
||||
2026/05/03-20:13:00.538848 7f25c0dfd6c0 Delete type=3 #1
|
||||
2026/05/04-08:07:36.206891 7ff4351fe6c0 Delete type=3 #1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
2026/05/03-20:13:00.476671 7f25c0dfd6c0 Delete type=3 #1
|
||||
2026/05/04-08:07:36.123812 7ff4351fe6c0 Delete type=3 #1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -1 +1 @@
|
||||
2026/05/03-20:13:00.509155 7f2577fff6c0 Delete type=3 #1
|
||||
2026/05/04-08:07:36.166025 7ff3e7fff6c0 Delete type=3 #1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
2026/05/03-20:13:00.554628 7f25c15fe6c0 Delete type=3 #1
|
||||
2026/05/04-08:07:36.229139 7ff4349fd6c0 Delete type=3 #1
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1
-1
@@ -1 +1 @@
|
||||
2026/05/03-20:13:00.523663 7f25c1dff6c0 Delete type=3 #1
|
||||
2026/05/04-08:07:36.186743 7ff4359ff6c0 Delete type=3 #1
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,128 @@
|
||||
<section class="{{cssClass}} les-oublies-sheet compagnie-sheet" autocomplete="off">
|
||||
<header class="sheet-header hero-banner">
|
||||
<img class="profile-img" data-edit="img" data-action="editImage" src="{{actor.img}}" title="{{actor.name}}" />
|
||||
<div class="header-fields hero-copy">
|
||||
<button class="mode-button mode-button--icon" type="button" data-action="toggleSheet" title="{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}" aria-label="{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}">
|
||||
<i class="fa-solid {{#if isEditMode}}fa-eye{{else}}fa-pen-to-square{{/if}}"></i>
|
||||
</button>
|
||||
<h1 class="sheet-title"><input name="name" type="text" value="{{actor.name}}" placeholder="Nom de compagnie" {{#if isPlayMode}}disabled{{/if}} /></h1>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav class="sheet-tabs" aria-label="Navigation de la fiche">
|
||||
{{#each tabs as |tab|}}
|
||||
<button type="button" class="sheet-tab-button {{tab.cssClass}}" data-action="switchTab" data-tab="{{tab.id}}">
|
||||
<i class="{{tab.icon}}"></i>
|
||||
<span>{{tab.label}}</span>
|
||||
</button>
|
||||
{{/each}}
|
||||
</nav>
|
||||
|
||||
<section class="sheet-tab {{tabs.power.cssClass}}" data-tab="power">
|
||||
<section class="sheet-card summary-card">
|
||||
<h2>{{localize "LESOUBLIES.labels.pouvoir"}}</h2>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.powerName"}}</label>
|
||||
<input name="system.power.name" type="text" value="{{system.power.name}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.reserveSongesCompagnie"}}</label>
|
||||
<input name="system.power.sharedDreamPoints" type="number" value="{{system.power.sharedDreamPoints}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<h3>{{localize "LESOUBLIES.labels.threadReserves"}}</h3>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadSonges"}}</label>
|
||||
<input name="system.reserves.songesThreads" type="number" value="{{system.reserves.songesThreads}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadCauchemar"}}</label>
|
||||
<input name="system.reserves.cauchemarThreads" type="number" value="{{system.reserves.cauchemarThreads}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.emptyGlobes"}}</label>
|
||||
<input name="system.reserves.emptyGlobes" type="number" value="{{system.reserves.emptyGlobes}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.activation"}}</label>
|
||||
<input name="system.power.activationCondition" type="text" value="{{system.power.activationCondition}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.capitaineVisible"}}</label>
|
||||
<input name="system.power.captainVisible" type="checkbox" {{checked system.power.captainVisible}} {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.capitaineTemoin"}}</label>
|
||||
<input name="system.power.captainNeedsWitness" type="checkbox" {{checked system.power.captainNeedsWitness}} {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
{{formInput systemFields.power.fields.description enriched=enriched.power.description value=system.power.description name="system.power.description" toggled=true}}
|
||||
<div class="section-title-row">
|
||||
<h3>Items de pouvoir</h3>
|
||||
<button type="button" data-action="createItem" data-type="pouvoircompagnie">+ {{localize "TYPES.Item.pouvoircompagnie"}}</button>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#each powers as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{item.system.activationCondition}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{#if primaryPower}}
|
||||
<div class="help-text">{{primaryPower.name}} — {{primaryPower.system.activationCondition}}</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.members.cssClass}}" data-tab="members">
|
||||
<div class="sheet-grid sheet-grid-2">
|
||||
<section class="sheet-card ledger-card">
|
||||
<h2>{{localize "LESOUBLIES.ui.membres"}}</h2>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.capitaine"}}</label>
|
||||
<select name="system.captainId" {{#if isPlayMode}}disabled{{/if}}>
|
||||
<option value="">—</option>
|
||||
{{#each choiceSets.captainOptions as |option|}}
|
||||
<option value="{{option.value}}" {{#if (eq option.value @root.system.captainId)}}selected{{/if}}>{{option.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.ombreDuTourment"}}</label>
|
||||
<select name="system.ombreDuTourmentId" {{#if isPlayMode}}disabled{{/if}}>
|
||||
<option value="">—</option>
|
||||
{{#each choiceSets.shadowOptions as |option|}}
|
||||
<option value="{{option.value}}" {{#if (eq option.value @root.system.ombreDuTourmentId)}}selected{{/if}}>{{option.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<p class="help-text">Sélectionnez le capitaine et l'ombre du tourment parmi les personnages du monde.</p>
|
||||
{{#if captain}}<p><strong>Capitaine :</strong> {{captain.name}}</p>{{/if}}
|
||||
{{#if shadow}}<p><strong>Ombre :</strong> {{shadow.name}}</p>{{/if}}
|
||||
<ul class="reference-list">
|
||||
{{#each members as |member|}}
|
||||
<li>{{member.name}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section class="sheet-card ledger-card">
|
||||
<h2>{{localize "LESOUBLIES.labels.liensNarratifs"}}</h2>
|
||||
<p class="help-text">{{localize "LESOUBLIES.ui.readOnlyCollection"}}</p>
|
||||
<ul class="reference-list">
|
||||
{{#each links as |link|}}
|
||||
<li><strong>{{link.label}}</strong> — {{link.sourceLabel}} -> {{link.targetLabel}} {{link.details}}</li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.notes.cssClass}}" data-tab="notes">
|
||||
<section class="sheet-card notes-card">
|
||||
<h2>{{localize "LESOUBLIES.labels.description"}}</h2>
|
||||
{{formInput systemFields.description enriched=enriched.description value=system.description name="system.description" toggled=true}}
|
||||
<h2>{{localize "LESOUBLIES.labels.notes"}}</h2>
|
||||
{{formInput systemFields.notes enriched=enriched.notes value=system.notes name="system.notes" toggled=true}}
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
@@ -0,0 +1,358 @@
|
||||
<section class="{{cssClass}} les-oublies-sheet personnage-sheet" autocomplete="off">
|
||||
<header class="sheet-header hero-banner">
|
||||
<img class="profile-img" data-edit="img" data-action="editImage" src="{{actor.img}}" title="{{actor.name}}" />
|
||||
<div class="header-fields hero-copy">
|
||||
<button class="mode-button mode-button--icon" type="button" data-action="toggleSheet" title="{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}" aria-label="{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}">
|
||||
<i class="fa-solid {{#if isEditMode}}fa-eye{{else}}fa-pen-to-square{{/if}}"></i>
|
||||
</button>
|
||||
<h1 class="sheet-title"><input name="name" type="text" value="{{actor.name}}" placeholder="Nom" {{#if isPlayMode}}disabled{{/if}} /></h1>
|
||||
<div class="sheet-actions">
|
||||
<button type="button" data-action="openInitiative">{{localize "LESOUBLIES.rolls.initiative"}}</button>
|
||||
<button type="button" data-action="openThreadHarvest">Récolte de fils</button>
|
||||
</div>
|
||||
<div class="creation-slots creation-slots--header" data-creation-drop-zone>
|
||||
{{#each creationSlots as |slot|}}
|
||||
<article class="creation-slot creation-slot--compact {{#if slot.item}}is-filled{{else}}is-empty{{/if}}" data-drop-creation-type="{{slot.type}}">
|
||||
<div class="creation-slot-header">
|
||||
<div>
|
||||
<p class="creation-slot-kicker">{{slot.label}}</p>
|
||||
{{#if slot.item}}
|
||||
<strong class="creation-slot-name">{{slot.item.name}}</strong>
|
||||
{{else}}
|
||||
<strong class="creation-slot-name">Glisser ici</strong>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if slot.item}}
|
||||
<div class="item-controls item-controls--compact">
|
||||
<button type="button" data-action="editItem" data-item-id="{{slot.item.id}}">Mod.</button>
|
||||
{{#unless @root.isPlayMode}}
|
||||
<button type="button" data-action="removeCreationItem" data-type="{{slot.type}}">X</button>
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav class="sheet-tabs" aria-label="Navigation de la fiche">
|
||||
{{#each tabs as |tab|}}
|
||||
<button type="button" class="sheet-tab-button {{tab.cssClass}}" data-action="switchTab" data-tab="{{tab.id}}">
|
||||
<i class="{{tab.icon}}"></i>
|
||||
<span>{{tab.label}}</span>
|
||||
</button>
|
||||
{{/each}}
|
||||
</nav>
|
||||
|
||||
<section class="sheet-tab {{tabs.overview.cssClass}}" data-tab="overview">
|
||||
<div class="sheet-grid sheet-grid-3">
|
||||
<section class="sheet-card summary-card">
|
||||
<h2>{{localize "LESOUBLIES.ui.derivedOverview"}}</h2>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.taille"}}</label>
|
||||
<select name="system.size.value" {{#if isPlayMode}}disabled{{/if}}>
|
||||
{{#each choiceSets.personnageSizeOptions as |option|}}
|
||||
<option value="{{option.value}}" {{#if (eq option.value @root.system.size.value)}}selected{{/if}}>{{option.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
<span>{{derived.sizeLabel}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.ui.vie"}}</label>
|
||||
<input name="system.hp.value" type="number" value="{{system.hp.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
<span>/ {{derived.hpMax}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.ui.songes"}}</label>
|
||||
<input name="system.songes.value" type="number" value="{{system.songes.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
<span>{{system.songes.points}} / {{system.songes.max}} pts</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.detteSonges"}}</label>
|
||||
<input name="system.songes.debt" type="number" value="{{system.songes.debt}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.creditSonges"}}</label>
|
||||
<input name="system.songes.xpCredit" type="number" value="{{system.songes.xpCredit}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.ui.cauchemar"}}</label>
|
||||
<input name="system.cauchemar.value" type="number" value="{{system.cauchemar.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
<span>{{system.cauchemar.points}} / {{system.cauchemar.max}} pts</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.detteCauchemar"}}</label>
|
||||
<input name="system.cauchemar.debt" type="number" value="{{system.cauchemar.debt}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.creditCauchemar"}}</label>
|
||||
<input name="system.cauchemar.xpCredit" type="number" value="{{system.cauchemar.xpCredit}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.xp"}}</label>
|
||||
<input name="system.experience.value" type="number" value="{{system.experience.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.ecorces"}}</label>
|
||||
<input name="system.money.ecorces" type="number" value="{{system.money.ecorces}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.ombreDuTourment"}}</label>
|
||||
<input name="system.flagsNarratifs.ombreDuTourment" type="checkbox" {{checked system.flagsNarratifs.ombreDuTourment}} {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sheet-card ledger-card reserve-card">
|
||||
<h2>{{localize "LESOUBLIES.labels.threadReserves"}}</h2>
|
||||
<div class="reserve-grid">
|
||||
<div class="reserve-panel">
|
||||
<h3>{{localize "LESOUBLIES.labels.personalReserve"}}</h3>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadSonges"}}</label>
|
||||
<input name="system.reserves.songesThreads" type="number" value="{{system.reserves.songesThreads}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadCauchemar"}}</label>
|
||||
<input name="system.reserves.cauchemarThreads" type="number" value="{{system.reserves.cauchemarThreads}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.emptyGlobes"}}</label>
|
||||
<input name="system.reserves.emptyGlobes" type="number" value="{{system.reserves.emptyGlobes}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="reserve-panel reserve-panel--company">
|
||||
<h3>{{localize "LESOUBLIES.labels.companyReserve"}}</h3>
|
||||
{{#if derived.compagnie}}
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadSonges"}}</label>
|
||||
<span>{{derived.companyReserves.songesThreads}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadCauchemar"}}</label>
|
||||
<span>{{derived.companyReserves.cauchemarThreads}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.emptyGlobes"}}</label>
|
||||
<span>{{derived.companyReserves.emptyGlobes}}</span>
|
||||
</div>
|
||||
|
||||
<div class="transfer-list">
|
||||
<div class="transfer-row" data-transfer-row>
|
||||
<strong>{{localize "LESOUBLIES.labels.threadSonges"}}</strong>
|
||||
<input type="number" min="1" value="1" data-transfer-amount />
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="transferThread" data-direction="toCompany" data-resource-key="songesThreads">{{localize "LESOUBLIES.labels.toCompany"}}</button>
|
||||
<button type="button" data-action="transferThread" data-direction="toActor" data-resource-key="songesThreads">{{localize "LESOUBLIES.labels.toActor"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="transfer-row" data-transfer-row>
|
||||
<strong>{{localize "LESOUBLIES.labels.threadCauchemar"}}</strong>
|
||||
<input type="number" min="1" value="1" data-transfer-amount />
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="transferThread" data-direction="toCompany" data-resource-key="cauchemarThreads">{{localize "LESOUBLIES.labels.toCompany"}}</button>
|
||||
<button type="button" data-action="transferThread" data-direction="toActor" data-resource-key="cauchemarThreads">{{localize "LESOUBLIES.labels.toActor"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="transfer-row" data-transfer-row>
|
||||
<strong>{{localize "LESOUBLIES.labels.emptyGlobes"}}</strong>
|
||||
<input type="number" min="1" value="1" data-transfer-amount />
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="transferThread" data-direction="toCompany" data-resource-key="emptyGlobes">{{localize "LESOUBLIES.labels.toCompany"}}</button>
|
||||
<button type="button" data-action="transferThread" data-direction="toActor" data-resource-key="emptyGlobes">{{localize "LESOUBLIES.labels.toActor"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="help-text">Liez une compagnie pour gérer une réserve commune de fils et de globes.</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-text">Les dépenses en fils rendent automatiquement autant de globes vides à la réserve utilisée.</p>
|
||||
</section>
|
||||
|
||||
<section class="sheet-card creation-card">
|
||||
<h2>{{localize "LESOUBLIES.labels.compagnie"}}</h2>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.compagnie"}}</label>
|
||||
<select name="system.references.compagnieId" {{#if isPlayMode}}disabled{{/if}}>
|
||||
<option value="">—</option>
|
||||
{{#each choiceSets.companyOptions as |option|}}
|
||||
<option value="{{option.value}}" {{#if (eq option.value @root.system.references.compagnieId)}}selected{{/if}}>{{option.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<p class="help-text"><strong>{{localize "LESOUBLIES.labels.compagnie"}} :</strong> {{#if derived.compagnie}}{{derived.compagnie.name}}{{else}}—{{/if}}</p>
|
||||
{{#if activeCompanyPower}}
|
||||
<p class="help-text"><strong>{{localize "LESOUBLIES.labels.pouvoirCompagnieActif"}} :</strong> {{activeCompanyPower.name}} — {{activeCompanyPower.system.activationCondition}}</p>
|
||||
{{/if}}
|
||||
{{#if derived.compagnie}}
|
||||
<div class="embed-buttons">
|
||||
<button type="button" data-action="openLinkedActor" data-actor-id="{{derived.compagnie.id}}">Ouvrir la compagnie</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.skills.cssClass}}" data-tab="skills">
|
||||
<section class="sheet-card ledger-card skills-ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.competences"}}</h2>
|
||||
<button type="button" data-action="createItem" data-type="competence">+ {{localize "TYPES.Item.competence"}}</button>
|
||||
</div>
|
||||
<div class="skills-columns">
|
||||
{{#each skillColumns as |column|}}
|
||||
<div class="skills-column">
|
||||
{{#each column as |group|}}
|
||||
<div class="group-block skills-group">
|
||||
<div class="group-header">
|
||||
<h3>{{group.label}}</h3>
|
||||
<label class="profile-badge">
|
||||
<span>{{localize "LESOUBLIES.labels.profil"}}</span>
|
||||
<input name="system.profils.{{group.id}}" type="number" value="{{group.profileValue}}" {{#if @root.isPlayMode}}disabled{{/if}} />
|
||||
</label>
|
||||
</div>
|
||||
<div class="item-list skills-item-list">
|
||||
{{#each group.items as |entry|}}
|
||||
<article class="item-card skill-card">
|
||||
<div class="skill-card-main">
|
||||
<strong>{{entry.item.name}}</strong>
|
||||
<span class="skill-summary">Base {{entry.item.system.base}} · {{group.label}} {{group.profileValue}} · {{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</span>
|
||||
</div>
|
||||
<div class="item-controls skill-controls">
|
||||
<button type="button" data-action="rollSkill" data-item-id="{{entry.item.id}}">{{localize "LESOUBLIES.ui.roll"}}</button>
|
||||
<button type="button" data-action="editItem" data-item-id="{{entry.item.id}}">Edit</button>
|
||||
<button type="button" data-action="deleteItem" data-item-id="{{entry.item.id}}">Delete</button>
|
||||
</div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.actions.cssClass}}" data-tab="actions">
|
||||
<section class="sheet-card ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.combat"}}</h2>
|
||||
<div class="embed-buttons">
|
||||
<button type="button" data-action="openCombatPreset" data-preset="encourager">Encourager</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="intimider">Intimider</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="evaluer">Évaluer</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="maitriser">Maîtriser</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="seDeplacer">Se déplacer</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#if equippedWeapons.length}}
|
||||
{{#each equippedWeapons as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.arme"}} - {{item.system.damage}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="useWeapon" data-item-id="{{item.id}}">Attaque</button><button type="button" data-action="resolveWeaponDamage" data-item-id="{{item.id}}">Dégâts</button><button type="button" data-action="toggleEquipped" data-item-id="{{item.id}}">Retirer</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<p class="help-text">Aucune arme équipée.</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sheet-card ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.magie"}}</h2>
|
||||
<button type="button" data-action="createItem" data-type="sortilege">+ {{localize "TYPES.Item.sortilege"}}</button>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#each spells as |item|}}
|
||||
<article class="item-card">
|
||||
<div>
|
||||
<strong>{{item.name}}</strong>
|
||||
<div>{{item.system.tradition}} / {{item.system.polarity}} / coût {{item.system.cost}}</div>
|
||||
</div>
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="useSpell" data-item-id="{{item.id}}">Activer</button>
|
||||
<button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button>
|
||||
<button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button>
|
||||
</div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.equipment.cssClass}}" data-tab="equipment">
|
||||
<section class="sheet-card ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.equipement"}}</h2>
|
||||
<div class="embed-buttons">
|
||||
<button type="button" data-action="createItem" data-type="arme">+ {{localize "TYPES.Item.arme"}}</button>
|
||||
<button type="button" data-action="createItem" data-type="armure">+ {{localize "TYPES.Item.armure"}}</button>
|
||||
<button type="button" data-action="createItem" data-type="equipement">+ {{localize "TYPES.Item.equipement"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#each weapons as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.arme"}} - {{item.system.damage}}{{#if item.system.equipped}} - Équipée{{/if}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="toggleEquipped" data-item-id="{{item.id}}">{{#if item.system.equipped}}Retirer{{else}}Équiper{{/if}}</button><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
{{#each armors as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.armure"}} - Prot {{item.system.protection}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
{{#each equipment as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.equipement"}} - {{item.system.category}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.notes.cssClass}}" data-tab="notes">
|
||||
<section class="sheet-card creation-card identity-card identity-card--compact">
|
||||
<h2>{{localize "LESOUBLIES.labels.identite"}}</h2>
|
||||
<div class="identity-grid">
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.age"}}</label>
|
||||
<input name="system.biodata.age" type="number" value="{{system.biodata.age}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.sexe"}}</label>
|
||||
<input name="system.biodata.sexe" type="text" value="{{system.biodata.sexe}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.motsCles"}}</label>
|
||||
<input name="system.biodata.motscles" type="text" value="{{system.biodata.motscles}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.capitaine"}}</label>
|
||||
<input name="system.flagsNarratifs.isCaptain" type="checkbox" {{checked system.flagsNarratifs.isCaptain}} {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="sheet-card notes-card">
|
||||
<h2>{{localize "LESOUBLIES.ui.notes"}}</h2>
|
||||
<label>{{localize "LESOUBLIES.labels.description"}}</label>
|
||||
{{formInput systemFields.biodata.fields.description enriched=enriched.biodata.description value=system.biodata.description name="system.biodata.description" toggled=true}}
|
||||
<label>{{localize "LESOUBLIES.labels.notes"}}</label>
|
||||
{{formInput systemFields.biodata.fields.notes enriched=enriched.biodata.notes value=system.biodata.notes name="system.biodata.notes" toggled=true}}
|
||||
<label>{{localize "LESOUBLIES.labels.gmnotes"}}</label>
|
||||
{{formInput systemFields.biodata.fields.gmnotes enriched=enriched.biodata.gmnotes value=system.biodata.gmnotes name="system.biodata.gmnotes" toggled=true}}
|
||||
<label>{{localize "LESOUBLIES.labels.liensNarratifs"}}</label>
|
||||
{{formInput systemFields.visions enriched=enriched.visions value=system.visions name="system.visions" toggled=true}}
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
@@ -0,0 +1,360 @@
|
||||
<section class="{{cssClass}} les-oublies-sheet personnage-sheet" autocomplete="off">
|
||||
<header class="sheet-header hero-banner">
|
||||
<img class="profile-img" data-edit="img" data-action="editImage" src="{{actor.img}}" title="{{actor.name}}" />
|
||||
<div class="header-fields hero-copy">
|
||||
<button class="mode-button mode-button--icon" type="button" data-action="toggleSheet" title="{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}" aria-label="{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}">
|
||||
<i class="fa-solid {{#if isEditMode}}fa-eye{{else}}fa-pen-to-square{{/if}}"></i>
|
||||
</button>
|
||||
<h1 class="sheet-title"><input name="name" type="text" value="{{actor.name}}" placeholder="Nom" {{#if isPlayMode}}disabled{{/if}} /></h1>
|
||||
<div class="sheet-actions">
|
||||
<button type="button" data-action="openInitiative">{{localize "LESOUBLIES.rolls.initiative"}}</button>
|
||||
<button type="button" data-action="openThreadHarvest">Récolte de fils</button>
|
||||
</div>
|
||||
<div class="creation-slots creation-slots--header" data-creation-drop-zone>
|
||||
{{#each creationSlots as |slot|}}
|
||||
<article class="creation-slot creation-slot--compact {{#if slot.item}}is-filled{{else}}is-empty{{/if}}" data-drop-creation-type="{{slot.type}}">
|
||||
<div class="creation-slot-header">
|
||||
<div>
|
||||
<p class="creation-slot-kicker">{{slot.label}}</p>
|
||||
{{#if slot.item}}
|
||||
<strong class="creation-slot-name">{{slot.item.name}}</strong>
|
||||
{{else}}
|
||||
<strong class="creation-slot-name">Glisser ici</strong>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if slot.item}}
|
||||
<div class="item-controls item-controls--compact">
|
||||
<button type="button" data-action="editItem" data-item-id="{{slot.item.id}}">Mod.</button>
|
||||
{{#unless @root.isPlayMode}}
|
||||
<button type="button" data-action="removeCreationItem" data-type="{{slot.type}}">X</button>
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav class="sheet-tabs" aria-label="Navigation de la fiche">
|
||||
{{#each tabs as |tab|}}
|
||||
<button type="button" class="sheet-tab-button {{tab.cssClass}}" data-action="switchTab" data-tab="{{tab.id}}">
|
||||
<i class="{{tab.icon}}"></i>
|
||||
<span>{{tab.label}}</span>
|
||||
</button>
|
||||
{{/each}}
|
||||
</nav>
|
||||
|
||||
<section class="sheet-tab {{tabs.overview.cssClass}}" data-tab="overview">
|
||||
<div class="sheet-grid sheet-grid-2">
|
||||
<section class="sheet-card summary-card">
|
||||
<h2>{{localize "LESOUBLIES.ui.derivedOverview"}}</h2>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.taille"}}</label>
|
||||
<select name="system.size.value" {{#if isPlayMode}}disabled{{/if}}>
|
||||
{{#each choiceSets.personnageSizeOptions as |option|}}
|
||||
<option value="{{option.value}}" {{#if (eq option.value @root.system.size.value)}}selected{{/if}}>{{option.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
<span>{{derived.sizeLabel}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.ui.vie"}}</label>
|
||||
<input name="system.hp.value" type="number" value="{{system.hp.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
<span>/ {{derived.hpMax}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.ui.songes"}}</label>
|
||||
<input name="system.songes.value" type="number" value="{{system.songes.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
<span>{{system.songes.points}} / {{system.songes.max}} pts</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.detteSonges"}}</label>
|
||||
<input name="system.songes.debt" type="number" value="{{system.songes.debt}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.creditSonges"}}</label>
|
||||
<input name="system.songes.xpCredit" type="number" value="{{system.songes.xpCredit}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.ui.cauchemar"}}</label>
|
||||
<input name="system.cauchemar.value" type="number" value="{{system.cauchemar.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
<span>{{system.cauchemar.points}} / {{system.cauchemar.max}} pts</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.detteCauchemar"}}</label>
|
||||
<input name="system.cauchemar.debt" type="number" value="{{system.cauchemar.debt}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.creditCauchemar"}}</label>
|
||||
<input name="system.cauchemar.xpCredit" type="number" value="{{system.cauchemar.xpCredit}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.xp"}}</label>
|
||||
<input name="system.experience.value" type="number" value="{{system.experience.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.ecorces"}}</label>
|
||||
<input name="system.money.ecorces" type="number" value="{{system.money.ecorces}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.ombreDuTourment"}}</label>
|
||||
<input name="system.flagsNarratifs.ombreDuTourment" type="checkbox" {{checked system.flagsNarratifs.ombreDuTourment}} {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sheet-card creation-card">
|
||||
<h2>{{localize "LESOUBLIES.labels.compagnie"}}</h2>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.compagnie"}}</label>
|
||||
<select name="system.references.compagnieId" {{#if isPlayMode}}disabled{{/if}}>
|
||||
<option value="">—</option>
|
||||
{{#each choiceSets.companyOptions as |option|}}
|
||||
<option value="{{option.value}}" {{#if (eq option.value @root.system.references.compagnieId)}}selected{{/if}}>{{option.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<p class="help-text"><strong>{{localize "LESOUBLIES.labels.compagnie"}} :</strong> {{#if derived.compagnie}}{{derived.compagnie.name}}{{else}}—{{/if}}</p>
|
||||
{{#if activeCompanyPower}}
|
||||
<p class="help-text"><strong>{{localize "LESOUBLIES.labels.pouvoirCompagnieActif"}} :</strong> {{activeCompanyPower.name}} — {{activeCompanyPower.system.activationCondition}}</p>
|
||||
{{/if}}
|
||||
{{#if derived.compagnie}}
|
||||
<div class="embed-buttons">
|
||||
<button type="button" data-action="openLinkedActor" data-actor-id="{{derived.compagnie.id}}">Ouvrir la compagnie</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.skills.cssClass}}" data-tab="skills">
|
||||
<section class="sheet-card ledger-card skills-ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.competences"}}</h2>
|
||||
<button type="button" data-action="createItem" data-type="competence">+ {{localize "TYPES.Item.competence"}}</button>
|
||||
</div>
|
||||
<div class="skills-columns">
|
||||
{{#each skillColumns as |column|}}
|
||||
<div class="skills-column">
|
||||
{{#each column as |group|}}
|
||||
<div class="group-block skills-group">
|
||||
<div class="group-header">
|
||||
<h3>{{group.label}}</h3>
|
||||
<label class="profile-badge">
|
||||
<span>{{localize "LESOUBLIES.labels.profil"}}</span>
|
||||
<input name="system.profils.{{group.id}}" type="number" value="{{group.profileValue}}" {{#if @root.isPlayMode}}disabled{{/if}} />
|
||||
</label>
|
||||
</div>
|
||||
<div class="item-list skills-item-list">
|
||||
{{#each group.items as |entry|}}
|
||||
<article class="item-card skill-card">
|
||||
<div class="skill-card-main">
|
||||
<strong>{{entry.item.name}}</strong>
|
||||
<span class="skill-summary">Base {{entry.item.system.base}} · {{group.label}} {{group.profileValue}} · {{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</span>
|
||||
</div>
|
||||
<div class="item-controls skill-controls">
|
||||
<button type="button" data-action="rollSkill" data-item-id="{{entry.item.id}}">{{localize "LESOUBLIES.ui.roll"}}</button>
|
||||
<button type="button" data-action="editItem" data-item-id="{{entry.item.id}}">Edit</button>
|
||||
<button type="button" data-action="deleteItem" data-item-id="{{entry.item.id}}">Delete</button>
|
||||
</div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.actions.cssClass}}" data-tab="actions">
|
||||
<section class="sheet-card ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.combat"}}</h2>
|
||||
<div class="embed-buttons">
|
||||
<button type="button" data-action="openCombatPreset" data-preset="encourager">Encourager</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="intimider">Intimider</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="evaluer">Évaluer</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="maitriser">Maîtriser</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="seDeplacer">Se déplacer</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#if equippedWeapons.length}}
|
||||
{{#each equippedWeapons as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.arme"}} - {{item.system.damage}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="useWeapon" data-item-id="{{item.id}}">Attaque</button><button type="button" data-action="resolveWeaponDamage" data-item-id="{{item.id}}">Dégâts</button><button type="button" data-action="toggleEquipped" data-item-id="{{item.id}}">Retirer</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<p class="help-text">Aucune arme équipée.</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="sheet-grid sheet-grid-2">
|
||||
<section class="sheet-card ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.magie"}}</h2>
|
||||
<button type="button" data-action="createItem" data-type="sortilege">+ {{localize "TYPES.Item.sortilege"}}</button>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#each spells as |item|}}
|
||||
<article class="item-card">
|
||||
<div>
|
||||
<strong>{{item.name}}</strong>
|
||||
<div>{{item.system.tradition}} / {{item.system.polarity}} / coût {{item.system.cost}}</div>
|
||||
</div>
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="useSpell" data-item-id="{{item.id}}">Activer</button>
|
||||
<button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button>
|
||||
<button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button>
|
||||
</div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sheet-card ledger-card reserve-card">
|
||||
<h2>{{localize "LESOUBLIES.labels.threadReserves"}}</h2>
|
||||
<div class="reserve-grid">
|
||||
<div class="reserve-panel">
|
||||
<h3>{{localize "LESOUBLIES.labels.personalReserve"}}</h3>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadSonges"}}</label>
|
||||
<input name="system.reserves.songesThreads" type="number" value="{{system.reserves.songesThreads}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadCauchemar"}}</label>
|
||||
<input name="system.reserves.cauchemarThreads" type="number" value="{{system.reserves.cauchemarThreads}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.emptyGlobes"}}</label>
|
||||
<input name="system.reserves.emptyGlobes" type="number" value="{{system.reserves.emptyGlobes}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="reserve-panel reserve-panel--company">
|
||||
<h3>{{localize "LESOUBLIES.labels.companyReserve"}}</h3>
|
||||
{{#if derived.compagnie}}
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadSonges"}}</label>
|
||||
<span>{{derived.companyReserves.songesThreads}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadCauchemar"}}</label>
|
||||
<span>{{derived.companyReserves.cauchemarThreads}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.emptyGlobes"}}</label>
|
||||
<span>{{derived.companyReserves.emptyGlobes}}</span>
|
||||
</div>
|
||||
|
||||
<div class="transfer-list">
|
||||
<div class="transfer-row" data-transfer-row>
|
||||
<strong>{{localize "LESOUBLIES.labels.threadSonges"}}</strong>
|
||||
<input type="number" min="1" value="1" data-transfer-amount />
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="transferThread" data-direction="toCompany" data-resource-key="songesThreads">{{localize "LESOUBLIES.labels.toCompany"}}</button>
|
||||
<button type="button" data-action="transferThread" data-direction="toActor" data-resource-key="songesThreads">{{localize "LESOUBLIES.labels.toActor"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="transfer-row" data-transfer-row>
|
||||
<strong>{{localize "LESOUBLIES.labels.threadCauchemar"}}</strong>
|
||||
<input type="number" min="1" value="1" data-transfer-amount />
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="transferThread" data-direction="toCompany" data-resource-key="cauchemarThreads">{{localize "LESOUBLIES.labels.toCompany"}}</button>
|
||||
<button type="button" data-action="transferThread" data-direction="toActor" data-resource-key="cauchemarThreads">{{localize "LESOUBLIES.labels.toActor"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="transfer-row" data-transfer-row>
|
||||
<strong>{{localize "LESOUBLIES.labels.emptyGlobes"}}</strong>
|
||||
<input type="number" min="1" value="1" data-transfer-amount />
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="transferThread" data-direction="toCompany" data-resource-key="emptyGlobes">{{localize "LESOUBLIES.labels.toCompany"}}</button>
|
||||
<button type="button" data-action="transferThread" data-direction="toActor" data-resource-key="emptyGlobes">{{localize "LESOUBLIES.labels.toActor"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="help-text">Liez une compagnie pour gérer une réserve commune de fils et de globes.</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-text">Les dépenses en fils rendent automatiquement autant de globes vides à la réserve utilisée.</p>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.equipment.cssClass}}" data-tab="equipment">
|
||||
<section class="sheet-card ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.equipement"}}</h2>
|
||||
<div class="embed-buttons">
|
||||
<button type="button" data-action="createItem" data-type="arme">+ {{localize "TYPES.Item.arme"}}</button>
|
||||
<button type="button" data-action="createItem" data-type="armure">+ {{localize "TYPES.Item.armure"}}</button>
|
||||
<button type="button" data-action="createItem" data-type="equipement">+ {{localize "TYPES.Item.equipement"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#each weapons as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.arme"}} - {{item.system.damage}}{{#if item.system.equipped}} - Équipée{{/if}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="toggleEquipped" data-item-id="{{item.id}}">{{#if item.system.equipped}}Retirer{{else}}Équiper{{/if}}</button><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
{{#each armors as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.armure"}} - Prot {{item.system.protection}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
{{#each equipment as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.equipement"}} - {{item.system.category}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.notes.cssClass}}" data-tab="notes">
|
||||
<section class="sheet-card creation-card identity-card identity-card--compact">
|
||||
<h2>{{localize "LESOUBLIES.labels.identite"}}</h2>
|
||||
<div class="identity-grid">
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.age"}}</label>
|
||||
<input name="system.biodata.age" type="number" value="{{system.biodata.age}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.sexe"}}</label>
|
||||
<input name="system.biodata.sexe" type="text" value="{{system.biodata.sexe}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.motsCles"}}</label>
|
||||
<input name="system.biodata.motscles" type="text" value="{{system.biodata.motscles}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.capitaine"}}</label>
|
||||
<input name="system.flagsNarratifs.isCaptain" type="checkbox" {{checked system.flagsNarratifs.isCaptain}} {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="sheet-card notes-card">
|
||||
<h2>{{localize "LESOUBLIES.ui.notes"}}</h2>
|
||||
<label>{{localize "LESOUBLIES.labels.description"}}</label>
|
||||
{{formInput systemFields.biodata.fields.description enriched=enriched.biodata.description value=system.biodata.description name="system.biodata.description" toggled=true}}
|
||||
<label>{{localize "LESOUBLIES.labels.notes"}}</label>
|
||||
{{formInput systemFields.biodata.fields.notes enriched=enriched.biodata.notes value=system.biodata.notes name="system.biodata.notes" toggled=true}}
|
||||
<label>{{localize "LESOUBLIES.labels.gmnotes"}}</label>
|
||||
{{formInput systemFields.biodata.fields.gmnotes enriched=enriched.biodata.gmnotes value=system.biodata.gmnotes name="system.biodata.gmnotes" toggled=true}}
|
||||
<label>{{localize "LESOUBLIES.labels.liensNarratifs"}}</label>
|
||||
{{formInput systemFields.visions enriched=enriched.visions value=system.visions name="system.visions" toggled=true}}
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
@@ -0,0 +1,363 @@
|
||||
<section class="{{cssClass}} les-oublies-sheet personnage-sheet" autocomplete="off">
|
||||
<header class="sheet-header hero-banner">
|
||||
<img class="profile-img" data-edit="img" data-action="editImage" src="{{actor.img}}" title="{{actor.name}}" />
|
||||
<div class="header-fields hero-copy">
|
||||
<button class="mode-button mode-button--icon" type="button" data-action="toggleSheet" title="{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}" aria-label="{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}">
|
||||
<i class="fa-solid {{#if isEditMode}}fa-eye{{else}}fa-pen-to-square{{/if}}"></i>
|
||||
</button>
|
||||
<h1 class="sheet-title"><input name="name" type="text" value="{{actor.name}}" placeholder="Nom" {{#if isPlayMode}}disabled{{/if}} /></h1>
|
||||
<div class="sheet-actions">
|
||||
<button type="button" data-action="openInitiative">{{localize "LESOUBLIES.rolls.initiative"}}</button>
|
||||
<button type="button" data-action="openThreadHarvest">Récolte de fils</button>
|
||||
</div>
|
||||
<div class="creation-slots creation-slots--header" data-creation-drop-zone>
|
||||
{{#each creationSlots as |slot|}}
|
||||
<article class="creation-slot creation-slot--compact {{#if slot.item}}is-filled{{else}}is-empty{{/if}}" data-drop-creation-type="{{slot.type}}">
|
||||
<div class="creation-slot-header">
|
||||
<div>
|
||||
<p class="creation-slot-kicker">{{slot.label}}</p>
|
||||
{{#if slot.item}}
|
||||
<strong class="creation-slot-name">{{slot.item.name}}</strong>
|
||||
{{else}}
|
||||
<strong class="creation-slot-name">Glisser ici</strong>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if slot.item}}
|
||||
<div class="item-controls item-controls--compact">
|
||||
<button type="button" data-action="editItem" data-item-id="{{slot.item.id}}">Mod.</button>
|
||||
{{#unless @root.isPlayMode}}
|
||||
<button type="button" data-action="removeCreationItem" data-type="{{slot.type}}">X</button>
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav class="sheet-tabs" aria-label="Navigation de la fiche">
|
||||
{{#each tabs as |tab|}}
|
||||
<button type="button" class="sheet-tab-button {{tab.cssClass}}" data-action="switchTab" data-tab="{{tab.id}}">
|
||||
<i class="{{tab.icon}}"></i>
|
||||
<span>{{tab.label}}</span>
|
||||
</button>
|
||||
{{/each}}
|
||||
</nav>
|
||||
|
||||
<section class="sheet-tab {{tabs.overview.cssClass}}" data-tab="overview">
|
||||
<div class="sheet-grid sheet-grid-2">
|
||||
<section class="sheet-card summary-card">
|
||||
<h2>{{localize "LESOUBLIES.ui.derivedOverview"}}</h2>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.taille"}}</label>
|
||||
<select name="system.size.value" {{#if isPlayMode}}disabled{{/if}}>
|
||||
{{#each choiceSets.personnageSizeOptions as |option|}}
|
||||
<option value="{{option.value}}" {{#if (eq option.value @root.system.size.value)}}selected{{/if}}>{{option.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
<span>{{derived.sizeLabel}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.ui.vie"}}</label>
|
||||
<input name="system.hp.value" type="number" value="{{system.hp.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
<span>/ {{derived.hpMax}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.ui.songes"}}</label>
|
||||
<input name="system.songes.value" type="number" value="{{system.songes.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
<span>{{system.songes.points}} / {{system.songes.max}} pts</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.detteSonges"}}</label>
|
||||
<input name="system.songes.debt" type="number" value="{{system.songes.debt}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.creditSonges"}}</label>
|
||||
<input name="system.songes.xpCredit" type="number" value="{{system.songes.xpCredit}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.ui.cauchemar"}}</label>
|
||||
<input name="system.cauchemar.value" type="number" value="{{system.cauchemar.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
<span>{{system.cauchemar.points}} / {{system.cauchemar.max}} pts</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.detteCauchemar"}}</label>
|
||||
<input name="system.cauchemar.debt" type="number" value="{{system.cauchemar.debt}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.creditCauchemar"}}</label>
|
||||
<input name="system.cauchemar.xpCredit" type="number" value="{{system.cauchemar.xpCredit}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.xp"}}</label>
|
||||
<input name="system.experience.value" type="number" value="{{system.experience.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.ecorces"}}</label>
|
||||
<input name="system.money.ecorces" type="number" value="{{system.money.ecorces}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.ombreDuTourment"}}</label>
|
||||
<input name="system.flagsNarratifs.ombreDuTourment" type="checkbox" {{checked system.flagsNarratifs.ombreDuTourment}} {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sheet-card creation-card">
|
||||
<h2>{{localize "LESOUBLIES.labels.compagnie"}}</h2>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.compagnie"}}</label>
|
||||
<select name="system.references.compagnieId" {{#if isPlayMode}}disabled{{/if}}>
|
||||
<option value="">—</option>
|
||||
{{#each choiceSets.companyOptions as |option|}}
|
||||
<option value="{{option.value}}" {{#if (eq option.value @root.system.references.compagnieId)}}selected{{/if}}>{{option.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<p class="help-text"><strong>{{localize "LESOUBLIES.labels.compagnie"}} :</strong> {{#if derived.compagnie}}{{derived.compagnie.name}}{{else}}—{{/if}}</p>
|
||||
{{#if activeCompanyPower}}
|
||||
<p class="help-text"><strong>{{localize "LESOUBLIES.labels.pouvoirCompagnieActif"}} :</strong> {{activeCompanyPower.name}} — {{activeCompanyPower.system.activationCondition}}</p>
|
||||
{{/if}}
|
||||
{{#if derived.compagnie}}
|
||||
<div class="embed-buttons">
|
||||
<button type="button" data-action="openLinkedActor" data-actor-id="{{derived.compagnie.id}}">Ouvrir la compagnie</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.skills.cssClass}}" data-tab="skills">
|
||||
<section class="sheet-card ledger-card skills-ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.competences"}}</h2>
|
||||
<button type="button" data-action="createItem" data-type="competence">+ {{localize "TYPES.Item.competence"}}</button>
|
||||
</div>
|
||||
<div class="skills-columns">
|
||||
{{#each skillColumns as |column|}}
|
||||
<div class="skills-column">
|
||||
{{#each column as |group|}}
|
||||
<div class="group-block skills-group">
|
||||
<div class="group-header">
|
||||
<h3>{{group.label}}</h3>
|
||||
<label class="profile-badge">
|
||||
<span>{{localize "LESOUBLIES.labels.profil"}}</span>
|
||||
<input name="system.profils.{{group.id}}" type="number" value="{{group.profileValue}}" {{#if @root.isPlayMode}}disabled{{/if}} />
|
||||
</label>
|
||||
</div>
|
||||
<div class="item-list skills-item-list">
|
||||
{{#each group.items as |entry|}}
|
||||
<article class="item-card skill-card">
|
||||
<div class="skill-card-main">
|
||||
<strong>{{entry.item.name}}</strong>
|
||||
<span class="skill-summary">Base {{entry.item.system.base}} · {{group.label}} {{group.profileValue}} · {{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</span>
|
||||
{{#if entry.domains.length}}
|
||||
<span class="skill-summary">Domaines : {{join entry.domains ", "}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="item-controls skill-controls">
|
||||
<button type="button" data-action="rollSkill" data-item-id="{{entry.item.id}}">{{localize "LESOUBLIES.ui.roll"}}</button>
|
||||
<button type="button" data-action="editItem" data-item-id="{{entry.item.id}}">Edit</button>
|
||||
<button type="button" data-action="deleteItem" data-item-id="{{entry.item.id}}">Delete</button>
|
||||
</div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.actions.cssClass}}" data-tab="actions">
|
||||
<section class="sheet-card ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.combat"}}</h2>
|
||||
<div class="embed-buttons">
|
||||
<button type="button" data-action="openCombatPreset" data-preset="encourager">Encourager</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="intimider">Intimider</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="evaluer">Évaluer</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="maitriser">Maîtriser</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="seDeplacer">Se déplacer</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#if equippedWeapons.length}}
|
||||
{{#each equippedWeapons as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.arme"}} - {{item.system.damage}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="useWeapon" data-item-id="{{item.id}}">Attaque</button><button type="button" data-action="resolveWeaponDamage" data-item-id="{{item.id}}">Dégâts</button><button type="button" data-action="toggleEquipped" data-item-id="{{item.id}}">Retirer</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<p class="help-text">Aucune arme équipée.</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="sheet-grid sheet-grid-2">
|
||||
<section class="sheet-card ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.magie"}}</h2>
|
||||
<button type="button" data-action="createItem" data-type="sortilege">+ {{localize "TYPES.Item.sortilege"}}</button>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#each spells as |item|}}
|
||||
<article class="item-card">
|
||||
<div>
|
||||
<strong>{{item.name}}</strong>
|
||||
<div>{{item.system.tradition}} / {{item.system.polarity}} / coût {{item.system.cost}}</div>
|
||||
</div>
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="useSpell" data-item-id="{{item.id}}">Activer</button>
|
||||
<button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button>
|
||||
<button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button>
|
||||
</div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sheet-card ledger-card reserve-card">
|
||||
<h2>{{localize "LESOUBLIES.labels.threadReserves"}}</h2>
|
||||
<div class="reserve-grid">
|
||||
<div class="reserve-panel">
|
||||
<h3>{{localize "LESOUBLIES.labels.personalReserve"}}</h3>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadSonges"}}</label>
|
||||
<input name="system.reserves.songesThreads" type="number" value="{{system.reserves.songesThreads}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadCauchemar"}}</label>
|
||||
<input name="system.reserves.cauchemarThreads" type="number" value="{{system.reserves.cauchemarThreads}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.emptyGlobes"}}</label>
|
||||
<input name="system.reserves.emptyGlobes" type="number" value="{{system.reserves.emptyGlobes}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="reserve-panel reserve-panel--company">
|
||||
<h3>{{localize "LESOUBLIES.labels.companyReserve"}}</h3>
|
||||
{{#if derived.compagnie}}
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadSonges"}}</label>
|
||||
<span>{{derived.companyReserves.songesThreads}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadCauchemar"}}</label>
|
||||
<span>{{derived.companyReserves.cauchemarThreads}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.emptyGlobes"}}</label>
|
||||
<span>{{derived.companyReserves.emptyGlobes}}</span>
|
||||
</div>
|
||||
|
||||
<div class="transfer-list">
|
||||
<div class="transfer-row" data-transfer-row>
|
||||
<strong>{{localize "LESOUBLIES.labels.threadSonges"}}</strong>
|
||||
<input type="number" min="1" value="1" data-transfer-amount />
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="transferThread" data-direction="toCompany" data-resource-key="songesThreads">{{localize "LESOUBLIES.labels.toCompany"}}</button>
|
||||
<button type="button" data-action="transferThread" data-direction="toActor" data-resource-key="songesThreads">{{localize "LESOUBLIES.labels.toActor"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="transfer-row" data-transfer-row>
|
||||
<strong>{{localize "LESOUBLIES.labels.threadCauchemar"}}</strong>
|
||||
<input type="number" min="1" value="1" data-transfer-amount />
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="transferThread" data-direction="toCompany" data-resource-key="cauchemarThreads">{{localize "LESOUBLIES.labels.toCompany"}}</button>
|
||||
<button type="button" data-action="transferThread" data-direction="toActor" data-resource-key="cauchemarThreads">{{localize "LESOUBLIES.labels.toActor"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="transfer-row" data-transfer-row>
|
||||
<strong>{{localize "LESOUBLIES.labels.emptyGlobes"}}</strong>
|
||||
<input type="number" min="1" value="1" data-transfer-amount />
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="transferThread" data-direction="toCompany" data-resource-key="emptyGlobes">{{localize "LESOUBLIES.labels.toCompany"}}</button>
|
||||
<button type="button" data-action="transferThread" data-direction="toActor" data-resource-key="emptyGlobes">{{localize "LESOUBLIES.labels.toActor"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="help-text">Liez une compagnie pour gérer une réserve commune de fils et de globes.</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-text">Les dépenses en fils rendent automatiquement autant de globes vides à la réserve utilisée.</p>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.equipment.cssClass}}" data-tab="equipment">
|
||||
<section class="sheet-card ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.equipement"}}</h2>
|
||||
<div class="embed-buttons">
|
||||
<button type="button" data-action="createItem" data-type="arme">+ {{localize "TYPES.Item.arme"}}</button>
|
||||
<button type="button" data-action="createItem" data-type="armure">+ {{localize "TYPES.Item.armure"}}</button>
|
||||
<button type="button" data-action="createItem" data-type="equipement">+ {{localize "TYPES.Item.equipement"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#each weapons as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.arme"}} - {{item.system.damage}}{{#if item.system.equipped}} - Équipée{{/if}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="toggleEquipped" data-item-id="{{item.id}}">{{#if item.system.equipped}}Retirer{{else}}Équiper{{/if}}</button><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
{{#each armors as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.armure"}} - Prot {{item.system.protection}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
{{#each equipment as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.equipement"}} - {{item.system.category}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.notes.cssClass}}" data-tab="notes">
|
||||
<section class="sheet-card creation-card identity-card identity-card--compact">
|
||||
<h2>{{localize "LESOUBLIES.labels.identite"}}</h2>
|
||||
<div class="identity-grid">
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.age"}}</label>
|
||||
<input name="system.biodata.age" type="number" value="{{system.biodata.age}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.sexe"}}</label>
|
||||
<input name="system.biodata.sexe" type="text" value="{{system.biodata.sexe}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.motsCles"}}</label>
|
||||
<input name="system.biodata.motscles" type="text" value="{{system.biodata.motscles}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.capitaine"}}</label>
|
||||
<input name="system.flagsNarratifs.isCaptain" type="checkbox" {{checked system.flagsNarratifs.isCaptain}} {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="sheet-card notes-card">
|
||||
<h2>{{localize "LESOUBLIES.ui.notes"}}</h2>
|
||||
<label>{{localize "LESOUBLIES.labels.description"}}</label>
|
||||
{{formInput systemFields.biodata.fields.description enriched=enriched.biodata.description value=system.biodata.description name="system.biodata.description" toggled=true}}
|
||||
<label>{{localize "LESOUBLIES.labels.notes"}}</label>
|
||||
{{formInput systemFields.biodata.fields.notes enriched=enriched.biodata.notes value=system.biodata.notes name="system.biodata.notes" toggled=true}}
|
||||
<label>{{localize "LESOUBLIES.labels.gmnotes"}}</label>
|
||||
{{formInput systemFields.biodata.fields.gmnotes enriched=enriched.biodata.gmnotes value=system.biodata.gmnotes name="system.biodata.gmnotes" toggled=true}}
|
||||
<label>{{localize "LESOUBLIES.labels.liensNarratifs"}}</label>
|
||||
{{formInput systemFields.visions enriched=enriched.visions value=system.visions name="system.visions" toggled=true}}
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
@@ -0,0 +1,365 @@
|
||||
<section class="{{cssClass}} les-oublies-sheet personnage-sheet" autocomplete="off">
|
||||
<header class="sheet-header hero-banner">
|
||||
<img class="profile-img" data-edit="img" data-action="editImage" src="{{actor.img}}" title="{{actor.name}}" />
|
||||
<div class="header-fields hero-copy">
|
||||
<button class="mode-button mode-button--icon" type="button" data-action="toggleSheet" title="{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}" aria-label="{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}">
|
||||
<i class="fa-solid {{#if isEditMode}}fa-eye{{else}}fa-pen-to-square{{/if}}"></i>
|
||||
</button>
|
||||
<h1 class="sheet-title"><input name="name" type="text" value="{{actor.name}}" placeholder="Nom" {{#if isPlayMode}}disabled{{/if}} /></h1>
|
||||
<div class="sheet-actions">
|
||||
<button type="button" data-action="openInitiative">{{localize "LESOUBLIES.rolls.initiative"}}</button>
|
||||
</div>
|
||||
<div class="creation-slots creation-slots--header" data-creation-drop-zone>
|
||||
{{#each creationSlots as |slot|}}
|
||||
<article class="creation-slot creation-slot--compact {{#if slot.item}}is-filled{{else}}is-empty{{/if}}" data-drop-creation-type="{{slot.type}}">
|
||||
<div class="creation-slot-header">
|
||||
<div>
|
||||
<p class="creation-slot-kicker">{{slot.label}}</p>
|
||||
{{#if slot.item}}
|
||||
<strong class="creation-slot-name">{{slot.item.name}}</strong>
|
||||
{{else}}
|
||||
<strong class="creation-slot-name">Glisser ici</strong>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{#if slot.item}}
|
||||
<div class="item-controls item-controls--compact">
|
||||
<button type="button" data-action="editItem" data-item-id="{{slot.item.id}}">Mod.</button>
|
||||
{{#unless @root.isPlayMode}}
|
||||
<button type="button" data-action="removeCreationItem" data-type="{{slot.type}}">X</button>
|
||||
{{/unless}}
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<nav class="sheet-tabs" aria-label="Navigation de la fiche">
|
||||
{{#each tabs as |tab|}}
|
||||
<button type="button" class="sheet-tab-button {{tab.cssClass}}" data-action="switchTab" data-tab="{{tab.id}}">
|
||||
<i class="{{tab.icon}}"></i>
|
||||
<span>{{tab.label}}</span>
|
||||
</button>
|
||||
{{/each}}
|
||||
</nav>
|
||||
|
||||
<section class="sheet-tab {{tabs.overview.cssClass}}" data-tab="overview">
|
||||
<div class="sheet-grid sheet-grid-2">
|
||||
<section class="sheet-card summary-card">
|
||||
<h2>{{localize "LESOUBLIES.ui.derivedOverview"}}</h2>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.taille"}}</label>
|
||||
<select name="system.size.value" {{#if isPlayMode}}disabled{{/if}}>
|
||||
{{#each choiceSets.personnageSizeOptions as |option|}}
|
||||
<option value="{{option.value}}" {{#if (eq option.value @root.system.size.value)}}selected{{/if}}>{{option.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
<span>{{derived.sizeLabel}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.ui.vie"}}</label>
|
||||
<input name="system.hp.value" type="number" value="{{system.hp.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
<span>/ {{derived.hpMax}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.ui.songes"}}</label>
|
||||
<input name="system.songes.value" type="number" value="{{system.songes.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
<span>{{system.songes.points}} / {{system.songes.max}} pts</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.detteSonges"}}</label>
|
||||
<input name="system.songes.debt" type="number" value="{{system.songes.debt}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.creditSonges"}}</label>
|
||||
<input name="system.songes.xpCredit" type="number" value="{{system.songes.xpCredit}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.ui.cauchemar"}}</label>
|
||||
<input name="system.cauchemar.value" type="number" value="{{system.cauchemar.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
<span>{{system.cauchemar.points}} / {{system.cauchemar.max}} pts</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.detteCauchemar"}}</label>
|
||||
<input name="system.cauchemar.debt" type="number" value="{{system.cauchemar.debt}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.creditCauchemar"}}</label>
|
||||
<input name="system.cauchemar.xpCredit" type="number" value="{{system.cauchemar.xpCredit}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.xp"}}</label>
|
||||
<input name="system.experience.value" type="number" value="{{system.experience.value}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.ecorces"}}</label>
|
||||
<input name="system.money.ecorces" type="number" value="{{system.money.ecorces}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.ombreDuTourment"}}</label>
|
||||
<input name="system.flagsNarratifs.ombreDuTourment" type="checkbox" {{checked system.flagsNarratifs.ombreDuTourment}} {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sheet-card creation-card">
|
||||
<h2>{{localize "LESOUBLIES.labels.compagnie"}}</h2>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.compagnie"}}</label>
|
||||
<select name="system.references.compagnieId" {{#if isPlayMode}}disabled{{/if}}>
|
||||
<option value="">—</option>
|
||||
{{#each choiceSets.companyOptions as |option|}}
|
||||
<option value="{{option.value}}" {{#if (eq option.value @root.system.references.compagnieId)}}selected{{/if}}>{{option.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<p class="help-text"><strong>{{localize "LESOUBLIES.labels.compagnie"}} :</strong> {{#if derived.compagnie}}{{derived.compagnie.name}}{{else}}—{{/if}}</p>
|
||||
{{#if activeCompanyPower}}
|
||||
<p class="help-text"><strong>{{localize "LESOUBLIES.labels.pouvoirCompagnieActif"}} :</strong> {{activeCompanyPower.name}} — {{activeCompanyPower.system.activationCondition}}</p>
|
||||
{{/if}}
|
||||
{{#if derived.compagnie}}
|
||||
<div class="embed-buttons">
|
||||
<button type="button" data-action="openLinkedActor" data-actor-id="{{derived.compagnie.id}}">Ouvrir la compagnie</button>
|
||||
</div>
|
||||
{{/if}}
|
||||
</section>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.skills.cssClass}}" data-tab="skills">
|
||||
<section class="sheet-card ledger-card skills-ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.competences"}}</h2>
|
||||
<button type="button" data-action="createItem" data-type="competence">+ {{localize "TYPES.Item.competence"}}</button>
|
||||
</div>
|
||||
<div class="skills-columns">
|
||||
{{#each skillColumns as |column|}}
|
||||
<div class="skills-column">
|
||||
{{#each column as |group|}}
|
||||
<div class="group-block skills-group">
|
||||
<div class="group-header">
|
||||
<h3>{{group.label}}</h3>
|
||||
<label class="profile-badge">
|
||||
<span>{{localize "LESOUBLIES.labels.profil"}}</span>
|
||||
<input name="system.profils.{{group.id}}" type="number" value="{{group.profileValue}}" {{#if @root.isPlayMode}}disabled{{/if}} />
|
||||
</label>
|
||||
</div>
|
||||
<div class="item-list skills-item-list">
|
||||
{{#each group.items as |entry|}}
|
||||
<article class="item-card skill-card">
|
||||
<div class="skill-card-main">
|
||||
<strong>{{entry.item.name}}</strong>
|
||||
<span class="skill-summary">Base {{entry.item.system.base}} · {{group.label}} {{group.profileValue}} · {{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</span>
|
||||
{{#if entry.domains.length}}
|
||||
<span class="skill-summary">Domaines : {{join entry.domains ", "}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="item-controls skill-controls">
|
||||
<button type="button" data-action="rollSkill" data-item-id="{{entry.item.id}}">{{localize "LESOUBLIES.ui.roll"}}</button>
|
||||
<button type="button" data-action="editItem" data-item-id="{{entry.item.id}}">Edit</button>
|
||||
<button type="button" data-action="deleteItem" data-item-id="{{entry.item.id}}">Delete</button>
|
||||
</div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.actions.cssClass}}" data-tab="actions">
|
||||
<section class="sheet-card ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.combat"}}</h2>
|
||||
<div class="embed-buttons">
|
||||
<button type="button" data-action="openCombatPreset" data-preset="encourager">Encourager</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="intimider">Intimider</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="evaluer">Évaluer</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="maitriser">Maîtriser</button>
|
||||
<button type="button" data-action="openCombatPreset" data-preset="seDeplacer">Se déplacer</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#if equippedWeapons.length}}
|
||||
{{#each equippedWeapons as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.arme"}} - {{item.system.damage}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="useWeapon" data-item-id="{{item.id}}">Attaque</button><button type="button" data-action="resolveWeaponDamage" data-item-id="{{item.id}}">Dégâts</button><button type="button" data-action="toggleEquipped" data-item-id="{{item.id}}">Retirer</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
{{else}}
|
||||
<p class="help-text">Aucune arme équipée.</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div class="sheet-grid sheet-grid-2">
|
||||
<section class="sheet-card ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.magie"}}</h2>
|
||||
<button type="button" data-action="createItem" data-type="sortilege">+ {{localize "TYPES.Item.sortilege"}}</button>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#each spells as |item|}}
|
||||
<article class="item-card">
|
||||
<div>
|
||||
<strong>{{item.name}}</strong>
|
||||
<div>{{item.system.tradition}} / {{item.system.polarity}} / coût {{item.system.cost}}</div>
|
||||
</div>
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="useSpell" data-item-id="{{item.id}}">Activer</button>
|
||||
<button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button>
|
||||
<button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button>
|
||||
</div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sheet-card ledger-card reserve-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.labels.threadReserves"}}</h2>
|
||||
<button type="button" data-action="openThreadHarvest">Récolte de fils</button>
|
||||
</div>
|
||||
<div class="reserve-grid">
|
||||
<div class="reserve-panel">
|
||||
<h3>{{localize "LESOUBLIES.labels.personalReserve"}}</h3>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadSonges"}}</label>
|
||||
<input name="system.reserves.songesThreads" type="number" value="{{system.reserves.songesThreads}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadCauchemar"}}</label>
|
||||
<input name="system.reserves.cauchemarThreads" type="number" value="{{system.reserves.cauchemarThreads}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.emptyGlobes"}}</label>
|
||||
<input name="system.reserves.emptyGlobes" type="number" value="{{system.reserves.emptyGlobes}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="reserve-panel reserve-panel--company">
|
||||
<h3>{{localize "LESOUBLIES.labels.companyReserve"}}</h3>
|
||||
{{#if derived.compagnie}}
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadSonges"}}</label>
|
||||
<span>{{derived.companyReserves.songesThreads}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.threadCauchemar"}}</label>
|
||||
<span>{{derived.companyReserves.cauchemarThreads}}</span>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.emptyGlobes"}}</label>
|
||||
<span>{{derived.companyReserves.emptyGlobes}}</span>
|
||||
</div>
|
||||
|
||||
<div class="transfer-list">
|
||||
<div class="transfer-row" data-transfer-row>
|
||||
<strong>{{localize "LESOUBLIES.labels.threadSonges"}}</strong>
|
||||
<input type="number" min="1" value="1" data-transfer-amount />
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="transferThread" data-direction="toCompany" data-resource-key="songesThreads">{{localize "LESOUBLIES.labels.toCompany"}}</button>
|
||||
<button type="button" data-action="transferThread" data-direction="toActor" data-resource-key="songesThreads">{{localize "LESOUBLIES.labels.toActor"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="transfer-row" data-transfer-row>
|
||||
<strong>{{localize "LESOUBLIES.labels.threadCauchemar"}}</strong>
|
||||
<input type="number" min="1" value="1" data-transfer-amount />
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="transferThread" data-direction="toCompany" data-resource-key="cauchemarThreads">{{localize "LESOUBLIES.labels.toCompany"}}</button>
|
||||
<button type="button" data-action="transferThread" data-direction="toActor" data-resource-key="cauchemarThreads">{{localize "LESOUBLIES.labels.toActor"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="transfer-row" data-transfer-row>
|
||||
<strong>{{localize "LESOUBLIES.labels.emptyGlobes"}}</strong>
|
||||
<input type="number" min="1" value="1" data-transfer-amount />
|
||||
<div class="item-controls">
|
||||
<button type="button" data-action="transferThread" data-direction="toCompany" data-resource-key="emptyGlobes">{{localize "LESOUBLIES.labels.toCompany"}}</button>
|
||||
<button type="button" data-action="transferThread" data-direction="toActor" data-resource-key="emptyGlobes">{{localize "LESOUBLIES.labels.toActor"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{else}}
|
||||
<p class="help-text">Liez une compagnie pour gérer une réserve commune de fils et de globes.</p>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
<p class="help-text">Les dépenses en fils rendent automatiquement autant de globes vides à la réserve utilisée.</p>
|
||||
</section>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.equipment.cssClass}}" data-tab="equipment">
|
||||
<section class="sheet-card ledger-card">
|
||||
<div class="section-title-row">
|
||||
<h2>{{localize "LESOUBLIES.ui.equipement"}}</h2>
|
||||
<div class="embed-buttons">
|
||||
<button type="button" data-action="createItem" data-type="arme">+ {{localize "TYPES.Item.arme"}}</button>
|
||||
<button type="button" data-action="createItem" data-type="armure">+ {{localize "TYPES.Item.armure"}}</button>
|
||||
<button type="button" data-action="createItem" data-type="equipement">+ {{localize "TYPES.Item.equipement"}}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="item-list">
|
||||
{{#each weapons as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.arme"}} - {{item.system.damage}}{{#if item.system.equipped}} - Équipée{{/if}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="toggleEquipped" data-item-id="{{item.id}}">{{#if item.system.equipped}}Retirer{{else}}Équiper{{/if}}</button><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
{{#each armors as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.armure"}} - Prot {{item.system.protection}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
{{#each equipment as |item|}}
|
||||
<article class="item-card">
|
||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.equipement"}} - {{item.system.category}}</div></div>
|
||||
<div class="item-controls"><button type="button" data-action="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||
</article>
|
||||
{{/each}}
|
||||
</div>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
<section class="sheet-tab {{tabs.notes.cssClass}}" data-tab="notes">
|
||||
<section class="sheet-card creation-card identity-card identity-card--compact">
|
||||
<h2>{{localize "LESOUBLIES.labels.identite"}}</h2>
|
||||
<div class="identity-grid">
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.age"}}</label>
|
||||
<input name="system.biodata.age" type="number" value="{{system.biodata.age}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.sexe"}}</label>
|
||||
<input name="system.biodata.sexe" type="text" value="{{system.biodata.sexe}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.motsCles"}}</label>
|
||||
<input name="system.biodata.motscles" type="text" value="{{system.biodata.motscles}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.labels.capitaine"}}</label>
|
||||
<input name="system.flagsNarratifs.isCaptain" type="checkbox" {{checked system.flagsNarratifs.isCaptain}} {{#if isPlayMode}}disabled{{/if}} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<section class="sheet-card notes-card">
|
||||
<h2>{{localize "LESOUBLIES.ui.notes"}}</h2>
|
||||
<label>{{localize "LESOUBLIES.labels.description"}}</label>
|
||||
{{formInput systemFields.biodata.fields.description enriched=enriched.biodata.description value=system.biodata.description name="system.biodata.description" toggled=true}}
|
||||
<label>{{localize "LESOUBLIES.labels.notes"}}</label>
|
||||
{{formInput systemFields.biodata.fields.notes enriched=enriched.biodata.notes value=system.biodata.notes name="system.biodata.notes" toggled=true}}
|
||||
<label>{{localize "LESOUBLIES.labels.gmnotes"}}</label>
|
||||
{{formInput systemFields.biodata.fields.gmnotes enriched=enriched.biodata.gmnotes value=system.biodata.gmnotes name="system.biodata.gmnotes" toggled=true}}
|
||||
<label>{{localize "LESOUBLIES.labels.liensNarratifs"}}</label>
|
||||
{{formInput systemFields.visions enriched=enriched.visions value=system.visions name="system.visions" toggled=true}}
|
||||
</section>
|
||||
</section>
|
||||
</section>
|
||||
@@ -97,6 +97,11 @@
|
||||
<strong>{{action.harvest.threadCount}} fil{{#unless (eq action.harvest.threadCount 1)}}s{{/unless}} de {{action.harvest.threadType}}</strong>
|
||||
<em>{{action.harvest.sleeperLabel}}</em>
|
||||
</div>
|
||||
<div class="chat-callout">
|
||||
<span>Stockage</span>
|
||||
<strong>{{action.harvest.destinationLabel}}</strong>
|
||||
<em>{{#if action.harvest.stored}}Réserve créditée{{else}}Aucun fil stocké{{/if}}</em>
|
||||
</div>
|
||||
<div class="chat-callout">
|
||||
<span>Dégâts subis</span>
|
||||
<strong>{{action.harvest.damageTaken}}</strong>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<div class="chat-callout">
|
||||
<span>Ressource</span>
|
||||
<strong>{{activation.costLabel}}</strong>
|
||||
<em>{{activation.paymentSourceLabel}}</em>
|
||||
</div>
|
||||
<div class="chat-callout">
|
||||
<span>Métier</span>
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<div class="les-oublies-roll-dialog">
|
||||
<div class="sheet-grid sheet-grid-2">
|
||||
<section class="sheet-card">
|
||||
<h2>{{spell.name}}</h2>
|
||||
<div class="field-row"><label>Tradition</label><input type="text" value="{{spell.system.tradition}}" disabled /></div>
|
||||
<div class="field-row"><label>Compétence</label><input type="text" value="{{skillLabel spell.system.skillKey}}" disabled /></div>
|
||||
<div class="field-row"><label>Polarité</label><input type="text" value="{{spell.system.polarity}}" disabled /></div>
|
||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.preparation"}}</label><input type="text" value="{{spell.system.preparation}}" disabled /></div>
|
||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.duree"}}</label><input type="text" value="{{spell.system.duration}}" disabled /></div>
|
||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.portee"}}</label><input type="text" value="{{spell.system.range}}" disabled /></div>
|
||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.aire"}}</label><input type="text" value="{{spell.system.area}}" disabled /></div>
|
||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.cumul"}}</label><input type="text" value="{{spell.system.stacking}}" disabled /></div>
|
||||
<p class="help-text">{{#if isMetierMatch}}Le métier de l'acteur couvre ce sortilège : le coût de base s'applique.{{else}}Le métier de l'acteur ne couvre pas ce sortilège : le coût est doublé conformément aux règles.{{/if}}</p>
|
||||
</section>
|
||||
|
||||
<section class="sheet-card">
|
||||
<h2>Activation</h2>
|
||||
<div class="field-row">
|
||||
<label>Coût réglé</label>
|
||||
<input name="actualCost" type="number" value="{{values.actualCost}}" />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>Type de ressource</label>
|
||||
<select name="paymentMode">
|
||||
<option value="points" {{#if (eq values.paymentMode "points")}}selected{{/if}}>Points</option>
|
||||
<option value="fils" {{#if (eq values.paymentMode "fils")}}selected{{/if}}>Fils</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-row" data-payment-source hidden>
|
||||
<label>Réserve de fils</label>
|
||||
<select name="paymentSource">
|
||||
{{#each threadReserves.options as |option|}}
|
||||
<option value="{{option.value}}" {{#if (eq option.value @root.values.paymentSource)}}selected{{/if}}>{{option.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>Coût effectif</label>
|
||||
<input type="text" value="{{effectiveCostLabel}}" data-effective-cost disabled />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>Cible / scène</label>
|
||||
<input name="targetLabel" type="text" value="{{values.targetLabel}}" />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>Notes</label>
|
||||
<input name="notes" type="text" value="{{values.notes}}" />
|
||||
</div>
|
||||
<p class="help-text">{{localize "LESOUBLIES.rolls.resourceState"}} : Songes {{resources.songesPoints}} / {{resources.songesValue}} · Cauchemar {{resources.cauchemarPoints}} / {{resources.cauchemarValue}}</p>
|
||||
<p class="help-text">Réserve perso : Songes {{threadReserves.actor.songesThreads}} · Cauchemar {{threadReserves.actor.cauchemarThreads}} · Globes vides {{threadReserves.actor.emptyGlobes}}</p>
|
||||
{{#if threadReserves.hasCompany}}
|
||||
<p class="help-text">{{threadReserves.company.label}} : Songes {{threadReserves.company.songesThreads}} · Cauchemar {{threadReserves.company.cauchemarThreads}} · Globes vides {{threadReserves.company.emptyGlobes}}</p>
|
||||
{{/if}}
|
||||
<p class="help-text" data-payment-source-hint>La dépense se fait dans les points de Songes ou de Cauchemar du personnage.</p>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,54 @@
|
||||
<div class="les-oublies-roll-dialog">
|
||||
<section class="sheet-card">
|
||||
<h2>Récolte de fils</h2>
|
||||
<div class="field-row">
|
||||
<label>Type de fil</label>
|
||||
<select name="threadType">
|
||||
<option value="songes" {{#if (eq values.threadType "songes")}}selected{{/if}}>Songes</option>
|
||||
<option value="cauchemar" {{#if (eq values.threadType "cauchemar")}}selected{{/if}}>Cauchemar</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>Nombre de fils</label>
|
||||
<input name="threadCount" type="number" min="1" value="{{values.threadCount}}" />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>Réserve de destination</label>
|
||||
<select name="destinationSource">
|
||||
{{#each threadReserves.options as |option|}}
|
||||
<option value="{{option.value}}" {{#if (eq option.value @root.values.destinationSource)}}selected{{/if}}>{{option.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.rolls.rollMode"}}</label>
|
||||
<select name="rollMode">
|
||||
{{#each rollModes as |mode|}}
|
||||
<option value="{{mode.value}}" {{#if (eq mode.value @root.values.rollMode)}}selected{{/if}}>{{mode.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>{{localize "LESOUBLIES.rolls.extraDie"}}</label>
|
||||
<select name="extraDie">
|
||||
{{#each extraDieModes as |mode|}}
|
||||
<option value="{{mode.value}}" {{#if (eq mode.value @root.values.extraDie)}}selected{{/if}}>{{mode.label}}</option>
|
||||
{{/each}}
|
||||
</select>
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>Dormeur</label>
|
||||
<input name="sleeperLabel" type="text" value="{{values.sleeperLabel}}" />
|
||||
</div>
|
||||
<div class="field-row">
|
||||
<label>Notes</label>
|
||||
<input name="notes" type="text" value="{{values.notes}}" />
|
||||
</div>
|
||||
<p class="help-text">Difficulté : -3 par fil supplémentaire. Dégâts subis : 1 par fil souhaité. En cas d'échec, plus aucune récolte possible sur ce dormeur cette nuit.</p>
|
||||
<p class="help-text">{{localize "LESOUBLIES.rolls.resourceState"}} : Songes {{resources.songesPoints}} / {{resources.songesValue}} · Cauchemar {{resources.cauchemarPoints}} / {{resources.cauchemarValue}}</p>
|
||||
<p class="help-text">Réserve perso : Songes {{threadReserves.actor.songesThreads}} · Cauchemar {{threadReserves.actor.cauchemarThreads}} · Globes vides {{threadReserves.actor.emptyGlobes}}</p>
|
||||
{{#if threadReserves.hasCompany}}
|
||||
<p class="help-text">{{threadReserves.company.label}} : Songes {{threadReserves.company.songesThreads}} · Cauchemar {{threadReserves.company.cauchemarThreads}} · Globes vides {{threadReserves.company.emptyGlobes}}</p>
|
||||
{{/if}}
|
||||
</section>
|
||||
</div>
|
||||
@@ -0,0 +1,25 @@
|
||||
<section class="{{cssClass}} les-oublies-sheet item-sheet" autocomplete="off">
|
||||
<header class="sheet-header hero-banner">
|
||||
<img class="profile-img" data-edit="img" data-action="editImage" src="{{item.img}}" title="{{item.name}}" />
|
||||
<div class="header-fields hero-copy">
|
||||
<p class="sheet-kicker">Savoir-faire</p>
|
||||
<h1 class="sheet-title"><input name="name" type="text" value="{{item.name}}" placeholder="Nom" {{#if isPlayMode}}disabled{{/if}} /></h1>
|
||||
<button class="mode-button" type="button" data-action="toggleSheet">{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}</button>
|
||||
</div>
|
||||
</header>
|
||||
<section class="sheet-card summary-card">
|
||||
<div class="field-row"><label>Key</label><select name="system.key" {{#if isPlayMode}}disabled{{/if}}>{{#each choiceSets.skillOptions as |option|}}<option value="{{option.value}}" {{#if (eq option.value @root.system.key)}}selected{{/if}}>{{option.label}}</option>{{/each}}</select></div>
|
||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.profil"}}</label><select name="system.profileKey" {{#if isPlayMode}}disabled{{/if}}>{{#each choiceSets.profileOptions as |option|}}<option value="{{option.value}}" {{#if (eq option.value @root.system.profileKey)}}selected{{/if}}>{{option.label}}</option>{{/each}}</select></div>
|
||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.base"}}</label><input name="system.base" type="number" value="{{system.base}}" {{#if isPlayMode}}disabled{{/if}} /></div>
|
||||
<div class="field-row"><label>Fermée</label><input name="system.closed" type="checkbox" {{checked system.closed}} {{#if isPlayMode}}disabled{{/if}} /></div>
|
||||
<div class="field-row"><label>À domaines</label><input name="system.domainSkill" type="checkbox" {{checked system.domainSkill}} {{#if isPlayMode}}disabled{{/if}} /></div>
|
||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.domaines"}}</label><input type="text" value="{{join system.domains ", "}}" disabled /></div>
|
||||
<div class="field-row"><label>Domaines fixes</label><input type="text" value="{{join system.fixedDomains ", "}}" disabled /></div>
|
||||
</section>
|
||||
<section class="sheet-card notes-card">
|
||||
<h2>{{localize "LESOUBLIES.labels.description"}}</h2>
|
||||
{{formInput systemFields.description enriched=enriched.description value=system.description name="system.description" toggled=true}}
|
||||
<h2>{{localize "LESOUBLIES.labels.notes"}}</h2>
|
||||
{{formInput systemFields.notes enriched=enriched.notes value=system.notes name="system.notes" toggled=true}}
|
||||
</section>
|
||||
</section>
|
||||
Reference in New Issue
Block a user