Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 454f8de412 | |||
| ee6fecbcef | |||
| 919b1888bd | |||
| 8f9d357c0c | |||
| 0b93f15225 | |||
| 552731bc3b | |||
| 0187daa1e5 | |||
| a008543f61 | |||
| 3534bdf181 |
@@ -6,6 +6,5 @@ styles/*.css
|
|||||||
# Node Modules
|
# Node Modules
|
||||||
node_modules/
|
node_modules/
|
||||||
.github/*
|
.github/*
|
||||||
!.github/copilot-instructions.md
|
|
||||||
.history/
|
.history/
|
||||||
_regles/
|
_regles/
|
||||||
|
|||||||
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 90 KiB |
|
After Width: | Height: | Size: 143 KiB |
|
After Width: | Height: | Size: 314 KiB |
|
After Width: | Height: | Size: 137 KiB |
|
After Width: | Height: | Size: 105 KiB |
|
After Width: | Height: | Size: 109 KiB |
|
After Width: | Height: | Size: 611 KiB |
|
After Width: | Height: | Size: 560 KiB |
|
After Width: | Height: | Size: 560 KiB |
|
After Width: | Height: | Size: 214 KiB |
@@ -87,6 +87,43 @@
|
|||||||
--lo-control-height: 1.95rem;
|
--lo-control-height: 1.95rem;
|
||||||
--lo-number-width: 4.75rem;
|
--lo-number-width: 4.75rem;
|
||||||
}
|
}
|
||||||
|
body.system-fvtt-les-oublies #pause {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
body.system-fvtt-les-oublies #pause.paused {
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
body.system-fvtt-les-oublies #pause > figcaption {
|
||||||
|
color: #d9d4ca;
|
||||||
|
text-shadow: 0 0 10px rgba(255, 255, 255, 0.22);
|
||||||
|
}
|
||||||
|
body.system-fvtt-les-oublies #pause > img {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
body.system-fvtt-les-oublies #pause::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
background: url("../assets/ui/pause_oublie.webp") center / contain no-repeat;
|
||||||
|
animation: lo-pause-logo 4.2s ease-in-out infinite;
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.35));
|
||||||
|
}
|
||||||
|
@keyframes lo-pause-logo {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: scale(0.98) translateY(0);
|
||||||
|
filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.3));
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: scale(1.03) translateY(-6px);
|
||||||
|
filter: drop-shadow(0 16px 26px rgba(0, 0, 0, 0.45));
|
||||||
|
}
|
||||||
|
}
|
||||||
.fvtt-les-oublies.sheet {
|
.fvtt-les-oublies.sheet {
|
||||||
color: var(--lo-ink);
|
color: var(--lo-ink);
|
||||||
font-family: "Cormorant Garamond", Georgia, serif;
|
font-family: "Cormorant Garamond", Georgia, serif;
|
||||||
@@ -233,6 +270,9 @@
|
|||||||
.fvtt-les-oublies .sheet-grid-2 {
|
.fvtt-les-oublies .sheet-grid-2 {
|
||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
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 {
|
.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);
|
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);
|
border: 1px solid rgba(133, 99, 74, 0.5);
|
||||||
@@ -362,6 +402,46 @@
|
|||||||
.fvtt-les-oublies .group-block + .group-block {
|
.fvtt-les-oublies .group-block + .group-block {
|
||||||
margin-top: var(--lo-space-lg);
|
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 {
|
.fvtt-les-oublies .group-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -723,8 +803,10 @@
|
|||||||
}
|
}
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
.fvtt-les-oublies .sheet-grid-2,
|
.fvtt-les-oublies .sheet-grid-2,
|
||||||
|
.fvtt-les-oublies .sheet-grid-3,
|
||||||
.fvtt-les-oublies .profile-grid,
|
.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;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
.fvtt-les-oublies .hero-banner {
|
.fvtt-les-oublies .hero-banner {
|
||||||
|
|||||||
@@ -115,6 +115,18 @@
|
|||||||
"tie": "Égalité : la fiction tranche."
|
"tie": "Égalité : la fiction tranche."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"welcome": {
|
||||||
|
"title": "Bienvenue dans Les Oubliés",
|
||||||
|
"eyebrow": "Système",
|
||||||
|
"intro": "Bienvenue dans le système FoundryVTT des Oubliés.",
|
||||||
|
"developerLabel": "Développement du système :",
|
||||||
|
"publisherLabel": "Jeu édité par",
|
||||||
|
"helpLabel": "Aide intégrée :",
|
||||||
|
"helpLinkLabel": "Ouvrir l’aide du système",
|
||||||
|
"helpUnavailable": "le compendium d’aide n’est pas disponible pour le moment.",
|
||||||
|
"openHelp": "Ouvrir l’aide",
|
||||||
|
"close": "Fermer"
|
||||||
|
},
|
||||||
"labels": {
|
"labels": {
|
||||||
"race": "Race",
|
"race": "Race",
|
||||||
"tribu": "Tribu",
|
"tribu": "Tribu",
|
||||||
@@ -169,6 +181,14 @@
|
|||||||
"creditCauchemar": "Crédits Cauchemar",
|
"creditCauchemar": "Crédits Cauchemar",
|
||||||
"pointsSonges": "Points de Songes",
|
"pointsSonges": "Points de Songes",
|
||||||
"pointsCauchemar": "Points de Cauchemar",
|
"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",
|
"degats": "Dégâts",
|
||||||
"sortilegesSonges": "Sortilèges de Songes",
|
"sortilegesSonges": "Sortilèges de Songes",
|
||||||
"sortilegesCauchemar": "Sortilèges de Cauchemar",
|
"sortilegesCauchemar": "Sortilèges de Cauchemar",
|
||||||
|
|||||||
@@ -34,6 +34,50 @@
|
|||||||
--lo-number-width: 4.75rem;
|
--lo-number-width: 4.75rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body.system-fvtt-les-oublies #pause {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.system-fvtt-les-oublies #pause.paused {
|
||||||
|
gap: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.system-fvtt-les-oublies #pause > figcaption {
|
||||||
|
color: #d9d4ca;
|
||||||
|
text-shadow: 0 0 10px rgba(255, 255, 255, 0.22);
|
||||||
|
}
|
||||||
|
|
||||||
|
body.system-fvtt-les-oublies #pause > img {
|
||||||
|
opacity: 0;
|
||||||
|
width: 0;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.system-fvtt-les-oublies #pause::before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
background: url("../assets/ui/pause_oublie.webp") center/contain no-repeat;
|
||||||
|
animation: lo-pause-logo 4.2s ease-in-out infinite;
|
||||||
|
transform-origin: 50% 50%;
|
||||||
|
filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.35));
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes lo-pause-logo {
|
||||||
|
0%,
|
||||||
|
100% {
|
||||||
|
transform: scale(0.98) translateY(0);
|
||||||
|
filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.3));
|
||||||
|
}
|
||||||
|
|
||||||
|
50% {
|
||||||
|
transform: scale(1.03) translateY(-6px);
|
||||||
|
filter: drop-shadow(0 16px 26px rgba(0, 0, 0, 0.45));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.fvtt-les-oublies.sheet {
|
.fvtt-les-oublies.sheet {
|
||||||
color: var(--lo-ink);
|
color: var(--lo-ink);
|
||||||
font-family: "Cormorant Garamond", Georgia, serif;
|
font-family: "Cormorant Garamond", Georgia, serif;
|
||||||
@@ -214,6 +258,10 @@
|
|||||||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sheet-grid-3 {
|
||||||
|
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||||||
|
}
|
||||||
|
|
||||||
.sheet-card {
|
.sheet-card {
|
||||||
background:
|
background:
|
||||||
linear-gradient(180deg, var(--lo-panel), var(--lo-panel-heavy)),
|
linear-gradient(180deg, var(--lo-panel), var(--lo-panel-heavy)),
|
||||||
@@ -379,6 +427,54 @@
|
|||||||
margin-top: var(--lo-space-lg);
|
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 {
|
.group-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -833,8 +929,10 @@
|
|||||||
|
|
||||||
@media (max-width: 900px) {
|
@media (max-width: 900px) {
|
||||||
.sheet-grid-2,
|
.sheet-grid-2,
|
||||||
|
.sheet-grid-3,
|
||||||
.profile-grid,
|
.profile-grid,
|
||||||
.creation-slots {
|
.creation-slots,
|
||||||
|
.reserve-card .reserve-grid {
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ export default class LesOubliesActorSheet extends HandlebarsApplicationMixin(fou
|
|||||||
openCombatPreset: LesOubliesActorSheet.#onOpenCombatPreset,
|
openCombatPreset: LesOubliesActorSheet.#onOpenCombatPreset,
|
||||||
openThreadHarvest: LesOubliesActorSheet.#onOpenThreadHarvest,
|
openThreadHarvest: LesOubliesActorSheet.#onOpenThreadHarvest,
|
||||||
openLinkedActor: LesOubliesActorSheet.#onOpenLinkedActor,
|
openLinkedActor: LesOubliesActorSheet.#onOpenLinkedActor,
|
||||||
|
transferThread: LesOubliesActorSheet.#onTransferThread,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,10 +77,27 @@ export default class LesOubliesActorSheet extends HandlebarsApplicationMixin(fou
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_prepareWeaponEntries(items = []) {
|
||||||
|
return items.map((item) => ({
|
||||||
|
...item.toObject(),
|
||||||
|
id: item.id,
|
||||||
|
displayDamage: LesOubliesUtility.formatWeaponDamage(this.document, item),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
_onRender(context, options) {
|
_onRender(context, options) {
|
||||||
super._onRender(context, options)
|
super._onRender(context, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_onDragStart(event) {
|
||||||
|
const itemElement = event.currentTarget?.closest?.("[data-item-id]") ?? event.target?.closest?.("[data-item-id]")
|
||||||
|
const itemId = itemElement?.dataset?.itemId
|
||||||
|
const item = itemId ? this.document.items.get(itemId) : null
|
||||||
|
if (!item || !event.dataTransfer) return
|
||||||
|
|
||||||
|
event.dataTransfer.setData("text/plain", JSON.stringify(item.toDragData()))
|
||||||
|
}
|
||||||
|
|
||||||
_canDragStart() {
|
_canDragStart() {
|
||||||
return this.isEditable
|
return this.isEditable
|
||||||
}
|
}
|
||||||
@@ -217,4 +235,26 @@ export default class LesOubliesActorSheet extends HandlebarsApplicationMixin(fou
|
|||||||
const actor = game.actors.get(actorId)
|
const actor = game.actors.get(actorId)
|
||||||
if (actor) actor.sheet.render(true)
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -105,6 +105,9 @@ export default class LesOubliesItemSheet extends HandlebarsApplicationMixin(foun
|
|||||||
choiceSets,
|
choiceSets,
|
||||||
enriched,
|
enriched,
|
||||||
enrichedDescription: foundry.utils.getProperty(enriched, "description") ?? "",
|
enrichedDescription: foundry.utils.getProperty(enriched, "description") ?? "",
|
||||||
|
weaponDamagePreview: this.document.type === "arme"
|
||||||
|
? LesOubliesUtility.formatWeaponDamage(this.document.parent instanceof Actor ? this.document.parent : null, this.document)
|
||||||
|
: "",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export default class LesOubliesCompagnieSheet extends LesOubliesActorSheet {
|
|||||||
|
|
||||||
static PARTS = {
|
static PARTS = {
|
||||||
sheet: {
|
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 {
|
export default class LesOubliesCompetenceSheet extends LesOubliesItemSheet {
|
||||||
static PARTS = {
|
static PARTS = {
|
||||||
sheet: {
|
sheet: {
|
||||||
template: "systems/fvtt-les-oublies/templates/item-competence-sheet.hbs",
|
template: "systems/fvtt-les-oublies/templates/item-competence-sheet-v2.hbs",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export default class LesOubliesCreatureSheet extends LesOubliesActorSheet {
|
|||||||
context.derived = this.document.getDerivedOverview()
|
context.derived = this.document.getDerivedOverview()
|
||||||
context.skillGroups = this.document.getGroupedCompetences()
|
context.skillGroups = this.document.getGroupedCompetences()
|
||||||
context.spells = this.document.getEmbeddedItems("sortilege")
|
context.spells = this.document.getEmbeddedItems("sortilege")
|
||||||
context.weapons = this.document.getEmbeddedItems("arme")
|
context.weapons = this._prepareWeaponEntries(this.document.getEmbeddedItems("arme"))
|
||||||
context.armors = this.document.getEmbeddedItems("armure")
|
context.armors = this.document.getEmbeddedItems("armure")
|
||||||
context.equipment = this.document.getEmbeddedItems("equipement")
|
context.equipment = this.document.getEmbeddedItems("equipement")
|
||||||
return context
|
return context
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export default class LesOubliesPersonnageSheet extends LesOubliesActorSheet {
|
|||||||
|
|
||||||
static PARTS = {
|
static PARTS = {
|
||||||
sheet: {
|
sheet: {
|
||||||
template: "systems/fvtt-les-oublies/templates/actor-personnage-sheet-v14.hbs",
|
template: "systems/fvtt-les-oublies/templates/actor-personnage-sheet-v18.hbs",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +64,7 @@ export default class LesOubliesPersonnageSheet extends LesOubliesActorSheet {
|
|||||||
context.skillGroups.slice(splitIndex),
|
context.skillGroups.slice(splitIndex),
|
||||||
]
|
]
|
||||||
context.spells = this.document.getEmbeddedItems("sortilege")
|
context.spells = this.document.getEmbeddedItems("sortilege")
|
||||||
context.weapons = this.document.getEmbeddedItems("arme")
|
context.weapons = this._prepareWeaponEntries(this.document.getEmbeddedItems("arme"))
|
||||||
context.equippedWeapons = context.weapons.filter((item) => item.system.equipped)
|
context.equippedWeapons = context.weapons.filter((item) => item.system.equipped)
|
||||||
context.armors = this.document.getEmbeddedItems("armure")
|
context.armors = this.document.getEmbeddedItems("armure")
|
||||||
context.equipment = this.document.getEmbeddedItems("equipement")
|
context.equipment = this.document.getEmbeddedItems("equipement")
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { LesOubliesRolls } from "./les-oublies-rolls.js"
|
|||||||
|
|
||||||
export class LesOubliesActor extends Actor {
|
export class LesOubliesActor extends Actor {
|
||||||
static CREATION_ITEM_TYPES = new Set(["race", "tribu", "metier"])
|
static CREATION_ITEM_TYPES = new Set(["race", "tribu", "metier"])
|
||||||
|
static THREAD_RESOURCE_KEYS = new Set(["songesThreads", "cauchemarThreads", "emptyGlobes"])
|
||||||
|
|
||||||
prepareDerivedData() {
|
prepareDerivedData() {
|
||||||
super.prepareDerivedData()
|
super.prepareDerivedData()
|
||||||
@@ -22,14 +23,27 @@ export class LesOubliesActor extends Actor {
|
|||||||
system.cauchemar.max = totals.cauchemarPoints
|
system.cauchemar.max = totals.cauchemarPoints
|
||||||
system.songes.points = Math.clamp(Number(system.songes.points ?? totals.songesPoints), 0, totals.songesPoints)
|
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.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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.type !== "creature") return
|
if (this.type !== "creature") return
|
||||||
|
|
||||||
const system = this.system
|
const system = this.system
|
||||||
const hpValue = Math.max(Number(system.hp?.value ?? 0), 0)
|
const sizeValue = Math.clamp(Number(system.size?.value ?? 1), 1, 8)
|
||||||
const hpMax = Math.max(Number(system.hp?.max ?? hpValue), hpValue, 0)
|
const hpMax = Math.max(sizeValue * 4, 0)
|
||||||
|
const hpValue = Math.max(Number(system.hp?.value ?? hpMax), 0)
|
||||||
system.hp.max = hpMax
|
system.hp.max = hpMax
|
||||||
system.hp.value = Math.min(hpValue, hpMax)
|
system.hp.value = Math.min(hpValue, hpMax)
|
||||||
const songesPoints = Math.max(Number(system.songes?.points ?? 0), 0)
|
const songesPoints = Math.max(Number(system.songes?.points ?? 0), 0)
|
||||||
@@ -62,6 +76,7 @@ export class LesOubliesActor extends Actor {
|
|||||||
async assignCreationItem(sourceItem) {
|
async assignCreationItem(sourceItem) {
|
||||||
if (!sourceItem || !LesOubliesActor.CREATION_ITEM_TYPES.has(sourceItem.type)) return null
|
if (!sourceItem || !LesOubliesActor.CREATION_ITEM_TYPES.has(sourceItem.type)) return null
|
||||||
|
|
||||||
|
const previousItem = this.getCreationItem(sourceItem.type)
|
||||||
const itemData = sourceItem.toObject()
|
const itemData = sourceItem.toObject()
|
||||||
delete itemData._id
|
delete itemData._id
|
||||||
|
|
||||||
@@ -77,12 +92,19 @@ export class LesOubliesActor extends Actor {
|
|||||||
[`system.references.${sourceItem.type}Id`]: createdItem.id,
|
[`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
|
return createdItem
|
||||||
}
|
}
|
||||||
|
|
||||||
async clearCreationItem(type) {
|
async clearCreationItem(type) {
|
||||||
if (!LesOubliesActor.CREATION_ITEM_TYPES.has(type)) return
|
if (!LesOubliesActor.CREATION_ITEM_TYPES.has(type)) return
|
||||||
|
|
||||||
|
const previousItem = this.getCreationItem(type)
|
||||||
|
|
||||||
const existingIds = this.getEmbeddedItems(type).map((item) => item.id)
|
const existingIds = this.getEmbeddedItems(type).map((item) => item.id)
|
||||||
if (existingIds.length) {
|
if (existingIds.length) {
|
||||||
await this.deleteEmbeddedDocuments("Item", existingIds, { renderSheet: false })
|
await this.deleteEmbeddedDocuments("Item", existingIds, { renderSheet: false })
|
||||||
@@ -91,6 +113,11 @@ export class LesOubliesActor extends Actor {
|
|||||||
await this.update({
|
await this.update({
|
||||||
[`system.references.${type}Id`]: "",
|
[`system.references.${type}Id`]: "",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if (type === "race") {
|
||||||
|
await this.syncRaceProfiles({ currentRace: null })
|
||||||
|
await this.syncRaceDomains({ currentRace: null, previousRace: previousItem })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
getCompagnie() {
|
getCompagnie() {
|
||||||
@@ -98,10 +125,94 @@ export class LesOubliesActor extends Actor {
|
|||||||
return compagnieId ? game.actors.get(compagnieId) ?? null : null
|
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) {
|
getCompetenceByKey(skillKey) {
|
||||||
return this.getEmbeddedItems("competence").find((item) => item.system.key === skillKey) ?? null
|
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) {
|
getSkillScoreByKey(skillKey) {
|
||||||
const competence = this.getCompetenceByKey(skillKey)
|
const competence = this.getCompetenceByKey(skillKey)
|
||||||
return competence ? this.computeSkillValue(competence) : 0
|
return competence ? this.computeSkillValue(competence) : 0
|
||||||
@@ -119,6 +230,8 @@ export class LesOubliesActor extends Actor {
|
|||||||
item,
|
item,
|
||||||
finalValue: this.computeSkillValue(item),
|
finalValue: this.computeSkillValue(item),
|
||||||
profileLabel: LESOUBLIES_CONFIG.profileLabels[item.system.profileKey] ?? item.system.profileKey,
|
profileLabel: LESOUBLIES_CONFIG.profileLabels[item.system.profileKey] ?? item.system.profileKey,
|
||||||
|
domains: LesOubliesUtility.uniqueStrings(item.system.domains ?? []),
|
||||||
|
fixedDomains: LesOubliesUtility.uniqueStrings(item.system.fixedDomains ?? []),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,6 +259,8 @@ export class LesOubliesActor extends Actor {
|
|||||||
cauchemarMax: this.system.cauchemar?.max ?? this.system.cauchemar?.points ?? 0,
|
cauchemarMax: this.system.cauchemar?.max ?? this.system.cauchemar?.points ?? 0,
|
||||||
songesPoints: this.system.songes?.points ?? 0,
|
songesPoints: this.system.songes?.points ?? 0,
|
||||||
cauchemarPoints: this.system.cauchemar?.points ?? 0,
|
cauchemarPoints: this.system.cauchemar?.points ?? 0,
|
||||||
|
reserves: this.getThreadReserves(),
|
||||||
|
companyReserves: this.getThreadReserves("company"),
|
||||||
race: this.getCreationItem("race"),
|
race: this.getCreationItem("race"),
|
||||||
tribu: this.getCreationItem("tribu"),
|
tribu: this.getCreationItem("tribu"),
|
||||||
metier: this.getCreationItem("metier"),
|
metier: this.getCreationItem("metier"),
|
||||||
|
|||||||
@@ -60,12 +60,14 @@ export const SIZE_LABELS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const WEAPON_CATEGORY_LABELS = {
|
export const WEAPON_CATEGORY_LABELS = {
|
||||||
|
corpsacorps: "Corps à corps",
|
||||||
melee: "Mêlée",
|
melee: "Mêlée",
|
||||||
tir: "Tir",
|
tir: "Tir",
|
||||||
jet: "Jet",
|
jet: "Jet",
|
||||||
}
|
}
|
||||||
|
|
||||||
export const WEAPON_ORIGIN_LABELS = {
|
export const WEAPON_ORIGIN_LABELS = {
|
||||||
|
animaux: "Animaux",
|
||||||
geant: "Géant",
|
geant: "Géant",
|
||||||
petitPeuple: "Petit Peuple",
|
petitPeuple: "Petit Peuple",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,10 @@ import { LesOubliesRolls } from "./les-oublies-rolls.js"
|
|||||||
import * as models from "./models/index.mjs"
|
import * as models from "./models/index.mjs"
|
||||||
import * as sheets from "./applications/sheets/_module.mjs"
|
import * as sheets from "./applications/sheets/_module.mjs"
|
||||||
|
|
||||||
|
const DEFAULT_PERSONNAGE_TOKEN_TEXTURE = "systems/fvtt-les-oublies/assets/tokens/border_token_oublies.webp"
|
||||||
|
const UBERWALD_URL = "https://www.uberwald.me"
|
||||||
|
const XII_SINGES_URL = "https://www.les12singes.com/84-les-oublies"
|
||||||
|
|
||||||
function ensureSystemStyles() {
|
function ensureSystemStyles() {
|
||||||
const href = `systems/${game.system.id}/css/les-oublies.css`
|
const href = `systems/${game.system.id}/css/les-oublies.css`
|
||||||
const existingLink = document.querySelector(`link[href$="${href}"]`)
|
const existingLink = document.querySelector(`link[href$="${href}"]`)
|
||||||
@@ -19,6 +23,60 @@ function ensureSystemStyles() {
|
|||||||
document.head.append(link)
|
document.head.append(link)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function usesFoundryDefaultTokenTexture(actor, data) {
|
||||||
|
const tokenTexture = foundry.utils.getProperty(data, "prototypeToken.texture.src")
|
||||||
|
?? foundry.utils.getProperty(actor, "prototypeToken.texture.src")
|
||||||
|
?? ""
|
||||||
|
return !tokenTexture || tokenTexture === CONST.DEFAULT_TOKEN || tokenTexture === "icons/svg/mystery-man.svg"
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getHelpJournalEntry() {
|
||||||
|
const pack = game.packs.get(`${game.system.id}.aide-systeme`)
|
||||||
|
if (!pack) return null
|
||||||
|
|
||||||
|
const documents = await pack.getDocuments()
|
||||||
|
return documents[0] ?? null
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildWelcomeMessageContent(helpJournal) {
|
||||||
|
const helpContent = helpJournal
|
||||||
|
? await foundry.applications.ux.TextEditor.implementation.enrichHTML(
|
||||||
|
`@UUID[${helpJournal.uuid}]{${game.i18n.localize("LESOUBLIES.welcome.helpLinkLabel")}}`,
|
||||||
|
{ async: true },
|
||||||
|
)
|
||||||
|
: game.i18n.localize("LESOUBLIES.welcome.helpUnavailable")
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="les-oublies-chat-card les-oublies-welcome-chat">
|
||||||
|
<div class="chat-card-header">
|
||||||
|
<div>
|
||||||
|
<p class="chat-card-eyebrow">${game.i18n.localize("LESOUBLIES.welcome.eyebrow")}</p>
|
||||||
|
<h3>${game.i18n.localize("LESOUBLIES.welcome.title")}</h3>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="chat-card-body">
|
||||||
|
<p>${game.i18n.localize("LESOUBLIES.welcome.intro")}</p>
|
||||||
|
<p>${game.i18n.localize("LESOUBLIES.welcome.developerLabel")} <a href="${UBERWALD_URL}" target="_blank" rel="noopener noreferrer">Uberwald</a>.</p>
|
||||||
|
<p>${game.i18n.localize("LESOUBLIES.welcome.publisherLabel")} <a href="${XII_SINGES_URL}" target="_blank" rel="noopener noreferrer">Les XII Singes</a>.</p>
|
||||||
|
<p><strong>${game.i18n.localize("LESOUBLIES.welcome.helpLabel")}</strong> ${helpContent}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`
|
||||||
|
}
|
||||||
|
|
||||||
|
async function showWelcomeMessage() {
|
||||||
|
const helpJournal = await getHelpJournalEntry()
|
||||||
|
const content = await buildWelcomeMessageContent(helpJournal)
|
||||||
|
|
||||||
|
await ChatMessage.create({
|
||||||
|
speaker: {
|
||||||
|
alias: game.system.title,
|
||||||
|
},
|
||||||
|
content,
|
||||||
|
whisper: [game.user.id],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
Hooks.once("init", function () {
|
Hooks.once("init", function () {
|
||||||
console.info("Les Oubliés | Initialisation du système")
|
console.info("Les Oubliés | Initialisation du système")
|
||||||
ensureSystemStyles()
|
ensureSystemStyles()
|
||||||
@@ -67,3 +125,20 @@ Hooks.once("init", function () {
|
|||||||
|
|
||||||
LesOubliesUtility.registerHandlebarsHelpers()
|
LesOubliesUtility.registerHandlebarsHelpers()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Hooks.once("ready", function () {
|
||||||
|
showWelcomeMessage()
|
||||||
|
})
|
||||||
|
|
||||||
|
Hooks.on("preCreateActor", function (actor, data) {
|
||||||
|
if (actor.type !== "personnage") return
|
||||||
|
if (!usesFoundryDefaultTokenTexture(actor, data)) return
|
||||||
|
|
||||||
|
actor.updateSource({
|
||||||
|
prototypeToken: {
|
||||||
|
texture: {
|
||||||
|
src: DEFAULT_PERSONNAGE_TOKEN_TEXTURE,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|||||||
@@ -289,10 +289,13 @@ export class LesOubliesRolls {
|
|||||||
|
|
||||||
const result = await this.resolveTest(actor, data)
|
const result = await this.resolveTest(actor, data)
|
||||||
if (!result) return null
|
if (!result) return null
|
||||||
|
const initiativeScore = Math.min(Math.max(Math.ceil(result.final / 2), 0), 12)
|
||||||
|
await this.#syncInitiativeToCombat(actor, initiativeScore)
|
||||||
|
|
||||||
return this.#createChatMessage(actor, {
|
return this.#createChatMessage(actor, {
|
||||||
...result,
|
...result,
|
||||||
mode: "initiative",
|
mode: "initiative",
|
||||||
initiativeScore: Math.min(Math.max(Math.ceil(result.final / 2), 0), 12),
|
initiativeScore,
|
||||||
successLabel: null,
|
successLabel: null,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -439,7 +442,12 @@ export class LesOubliesRolls {
|
|||||||
|
|
||||||
const data = await this.#promptSpellOptions(actor, spell)
|
const data = await this.#promptSpellOptions(actor, spell)
|
||||||
if (!data) return null
|
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 skill = actor.getCompetenceByKey?.(spell.system.skillKey) ?? null
|
||||||
const skillBase = Number(skill?.system?.base ?? 0)
|
const skillBase = Number(skill?.system?.base ?? 0)
|
||||||
if (skillBase < 1) {
|
if (skillBase < 1) {
|
||||||
@@ -450,7 +458,6 @@ export class LesOubliesRolls {
|
|||||||
const métierMatch = this.#actorMatchesSpellGrant(actor, spell)
|
const métierMatch = this.#actorMatchesSpellGrant(actor, spell)
|
||||||
const surcharge = !métierMatch
|
const surcharge = !métierMatch
|
||||||
const effectiveCost = Number(data.actualCost ?? 0) * (surcharge ? 2 : 1)
|
const effectiveCost = Number(data.actualCost ?? 0) * (surcharge ? 2 : 1)
|
||||||
const paymentMode = String(data.paymentMode || "points")
|
|
||||||
if (paymentMode === "points") {
|
if (paymentMode === "points") {
|
||||||
const resource = spell.system.polarity || "songes"
|
const resource = spell.system.polarity || "songes"
|
||||||
const available = Number(actor.system?.[resource]?.points ?? 0)
|
const available = Number(actor.system?.[resource]?.points ?? 0)
|
||||||
@@ -468,9 +475,43 @@ export class LesOubliesRolls {
|
|||||||
[`system.${resource}.points`]: Math.max(available - effectiveCost, 0),
|
[`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
|
||||||
}
|
}
|
||||||
|
|
||||||
return { métierMatch, surcharge, effectiveCost, paymentMode }
|
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,
|
||||||
|
paymentSource,
|
||||||
|
paymentSourceLabel: paymentMode === "fils"
|
||||||
|
? this.#getThreadReserveLabel(actor, paymentSource)
|
||||||
|
: actor.name,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
if (!activation) return null
|
if (!activation) return null
|
||||||
|
|
||||||
@@ -487,6 +528,7 @@ export class LesOubliesRolls {
|
|||||||
costLabel: activation.paymentMode === "points"
|
costLabel: activation.paymentMode === "points"
|
||||||
? `${activation.effectiveCost} point${activation.effectiveCost > 1 ? "s" : ""} de ${spell.system.polarity === "cauchemar" ? "Cauchemar" : "Songes"}`
|
? `${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"}`,
|
: `${activation.effectiveCost} fil${activation.effectiveCost > 1 ? "s" : ""} de ${spell.system.polarity === "cauchemar" ? "Cauchemar" : "Songes"}`,
|
||||||
|
paymentSourceLabel: activation.paymentSourceLabel,
|
||||||
métierMatch: activation.métierMatch,
|
métierMatch: activation.métierMatch,
|
||||||
surcharge: activation.surcharge,
|
surcharge: activation.surcharge,
|
||||||
notes: data.notes?.trim() || "",
|
notes: data.notes?.trim() || "",
|
||||||
@@ -578,6 +620,17 @@ export class LesOubliesRolls {
|
|||||||
if (!data) return null
|
if (!data) return null
|
||||||
|
|
||||||
const threadCount = Math.max(Number(data.threadCount ?? 1), 1)
|
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 damageTaken = threadCount
|
||||||
const difficulty = -3 * (threadCount - 1)
|
const difficulty = -3 * (threadCount - 1)
|
||||||
const result = await this.resolveTest(actor, {
|
const result = await this.resolveTest(actor, {
|
||||||
@@ -599,8 +652,11 @@ export class LesOubliesRolls {
|
|||||||
if (!result) return null
|
if (!result) return null
|
||||||
|
|
||||||
await this.#applyDamageToActor(actor, damageTaken)
|
await this.#applyDamageToActor(actor, damageTaken)
|
||||||
const durationRoll = await (new Roll("1d12")).evaluate()
|
if (result.success) {
|
||||||
const effectRoll = await (new Roll("1d12")).evaluate()
|
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)
|
const effectIndex = Number(effectRoll.total ?? 1)
|
||||||
result.metadata.action.harvest = {
|
result.metadata.action.harvest = {
|
||||||
threadType: data.threadType,
|
threadType: data.threadType,
|
||||||
@@ -611,6 +667,8 @@ export class LesOubliesRolls {
|
|||||||
sideEffectRoll: effectIndex,
|
sideEffectRoll: effectIndex,
|
||||||
sideEffectText: HARVEST_SIDE_EFFECTS[effectIndex],
|
sideEffectText: HARVEST_SIDE_EFFECTS[effectIndex],
|
||||||
sleeperLabel: data.sleeperLabel?.trim() || "Dormeur non précisé",
|
sleeperLabel: data.sleeperLabel?.trim() || "Dormeur non précisé",
|
||||||
|
destinationLabel: destinationReserve.label,
|
||||||
|
stored: result.success,
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.#createChatMessage(actor, result)
|
return this.#createChatMessage(actor, result)
|
||||||
@@ -661,14 +719,7 @@ export class LesOubliesRolls {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pool = this.#buildPool(options.rollMode, options.extraDie)
|
const pool = this.#buildPool(options.rollMode, options.extraDie)
|
||||||
const dice = []
|
const dice = await this.#rollExplodingPool(pool)
|
||||||
for (let index = 0; index < pool.length; index += 1) {
|
|
||||||
const spec = pool[index]
|
|
||||||
dice.push(await this.#rollExplodingDie({
|
|
||||||
...spec,
|
|
||||||
index,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
|
|
||||||
const selectedIndex = this.#needsSelection(dice)
|
const selectedIndex = this.#needsSelection(dice)
|
||||||
? await this.#promptDieSelection(actor, options.label, dice)
|
? await this.#promptDieSelection(actor, options.label, dice)
|
||||||
@@ -737,6 +788,23 @@ export class LesOubliesRolls {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static async #syncInitiativeToCombat(actor, initiativeScore) {
|
||||||
|
if (!game.combat || !actor?.id) return false
|
||||||
|
|
||||||
|
const combatants = game.combat.combatants.filter((combatant) => combatant.actorId === actor.id)
|
||||||
|
if (!combatants.length) {
|
||||||
|
ui.notifications.warn(`${actor.name} n'est pas présent dans le combat actif.`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
await game.combat.updateEmbeddedDocuments("Combatant", combatants.map((combatant) => ({
|
||||||
|
_id: combatant.id,
|
||||||
|
initiative: initiativeScore,
|
||||||
|
})))
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
static async #createConfrontationMessage(actor, data, actionData = null) {
|
static async #createConfrontationMessage(actor, data, actionData = null) {
|
||||||
const attacker = await this.resolveTest(actor, {
|
const attacker = await this.resolveTest(actor, {
|
||||||
label: data.attackerLabel,
|
label: data.attackerLabel,
|
||||||
@@ -1129,17 +1197,20 @@ export class LesOubliesRolls {
|
|||||||
const polarityLabel = spell.system.polarity === "cauchemar"
|
const polarityLabel = spell.system.polarity === "cauchemar"
|
||||||
? game.i18n.localize("LESOUBLIES.ui.cauchemar")
|
? game.i18n.localize("LESOUBLIES.ui.cauchemar")
|
||||||
: game.i18n.localize("LESOUBLIES.ui.songes")
|
: game.i18n.localize("LESOUBLIES.ui.songes")
|
||||||
|
const threadReserves = this.#getThreadDialogState(actor)
|
||||||
const content = await foundry.applications.handlebars.renderTemplate(
|
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,
|
actor,
|
||||||
spell,
|
spell,
|
||||||
resources: this.#getDialogResources(actor),
|
resources: this.#getDialogResources(actor),
|
||||||
|
threadReserves,
|
||||||
isMetierMatch,
|
isMetierMatch,
|
||||||
effectiveCostLabel: `${effectiveCost} point${effectiveCost > 1 ? "s" : ""} de ${polarityLabel}`,
|
effectiveCostLabel: `${effectiveCost} point${effectiveCost > 1 ? "s" : ""} de ${polarityLabel}`,
|
||||||
values: {
|
values: {
|
||||||
actualCost: Number(spell.system.cost ?? 0),
|
actualCost: Number(spell.system.cost ?? 0),
|
||||||
paymentMode: "points",
|
paymentMode: "points",
|
||||||
|
paymentSource: "actor",
|
||||||
targetLabel: "",
|
targetLabel: "",
|
||||||
notes: "",
|
notes: "",
|
||||||
},
|
},
|
||||||
@@ -1151,6 +1222,9 @@ export class LesOubliesRolls {
|
|||||||
title: `Activer ${spell.name}`,
|
title: `Activer ${spell.name}`,
|
||||||
},
|
},
|
||||||
content,
|
content,
|
||||||
|
render: (_event, dialog) => {
|
||||||
|
this.#bindSpellPaymentSelection(dialog, { actor, spell, effectiveCost })
|
||||||
|
},
|
||||||
buttons: [
|
buttons: [
|
||||||
{
|
{
|
||||||
action: "activate",
|
action: "activate",
|
||||||
@@ -1161,8 +1235,9 @@ export class LesOubliesRolls {
|
|||||||
if (!form) return null
|
if (!form) return null
|
||||||
const data = this.#formToObject(form)
|
const data = this.#formToObject(form)
|
||||||
return {
|
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"),
|
paymentMode: String(data.paymentMode || "points"),
|
||||||
|
paymentSource: String(data.paymentSource || "actor"),
|
||||||
targetLabel: String(data.targetLabel || ""),
|
targetLabel: String(data.targetLabel || ""),
|
||||||
notes: String(data.notes || ""),
|
notes: String(data.notes || ""),
|
||||||
}
|
}
|
||||||
@@ -1338,16 +1413,19 @@ export class LesOubliesRolls {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static async #promptThreadHarvestOptions(actor) {
|
static async #promptThreadHarvestOptions(actor) {
|
||||||
|
const threadReserves = this.#getThreadDialogState(actor)
|
||||||
const content = await foundry.applications.handlebars.renderTemplate(
|
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,
|
actor,
|
||||||
rollModes: this.getRollModes(),
|
rollModes: this.getRollModes(),
|
||||||
extraDieModes: this.getExtraDieModes(),
|
extraDieModes: this.getExtraDieModes(),
|
||||||
resources: this.#getDialogResources(actor),
|
resources: this.#getDialogResources(actor),
|
||||||
|
threadReserves,
|
||||||
values: {
|
values: {
|
||||||
threadType: "songes",
|
threadType: "songes",
|
||||||
threadCount: 1,
|
threadCount: 1,
|
||||||
|
destinationSource: "actor",
|
||||||
rollMode: this.getDefaultRollMode(actor),
|
rollMode: this.getDefaultRollMode(actor),
|
||||||
extraDie: "",
|
extraDie: "",
|
||||||
sleeperLabel: "",
|
sleeperLabel: "",
|
||||||
@@ -1373,6 +1451,7 @@ export class LesOubliesRolls {
|
|||||||
return {
|
return {
|
||||||
threadType: String(data.threadType || "songes"),
|
threadType: String(data.threadType || "songes"),
|
||||||
threadCount: Number(data.threadCount ?? 1),
|
threadCount: Number(data.threadCount ?? 1),
|
||||||
|
destinationSource: String(data.destinationSource || "actor"),
|
||||||
rollMode: String(data.rollMode || this.getDefaultRollMode(actor)),
|
rollMode: String(data.rollMode || this.getDefaultRollMode(actor)),
|
||||||
extraDie: String(data.extraDie || ""),
|
extraDie: String(data.extraDie || ""),
|
||||||
sleeperLabel: String(data.sleeperLabel || ""),
|
sleeperLabel: String(data.sleeperLabel || ""),
|
||||||
@@ -1441,31 +1520,111 @@ export class LesOubliesRolls {
|
|||||||
return dice
|
return dice
|
||||||
}
|
}
|
||||||
|
|
||||||
static async #rollExplodingDie({ type, index, source = "base" }) {
|
static async #rollExplodingPool(pool) {
|
||||||
const faces = []
|
const dice = pool.map(({ type, source = "base" }, index) => ({
|
||||||
let total = 0
|
|
||||||
let lastFace = 12
|
|
||||||
|
|
||||||
while (lastFace === 12) {
|
|
||||||
const roll = await (new Roll("1d12")).evaluate()
|
|
||||||
lastFace = Number(roll.total ?? 0)
|
|
||||||
faces.push(lastFace)
|
|
||||||
total += lastFace
|
|
||||||
}
|
|
||||||
|
|
||||||
const typeLabel = game.i18n.localize(`LESOUBLIES.rolls.dice.${type}`)
|
|
||||||
return {
|
|
||||||
index,
|
index,
|
||||||
type,
|
type,
|
||||||
typeLabel,
|
typeLabel: game.i18n.localize(`LESOUBLIES.rolls.dice.${type}`),
|
||||||
source,
|
source,
|
||||||
sourceLabel: source === "extra" ? game.i18n.localize("LESOUBLIES.rolls.extraDie") : null,
|
sourceLabel: source === "extra" ? game.i18n.localize("LESOUBLIES.rolls.extraDie") : null,
|
||||||
faces,
|
faces: [],
|
||||||
firstFace: faces[0] ?? 0,
|
rolls: [],
|
||||||
total,
|
total: 0,
|
||||||
exploded: faces.length > 1,
|
}))
|
||||||
breakdown: faces.join(" + "),
|
|
||||||
|
let pendingDice = [...dice]
|
||||||
|
while (pendingDice.length) {
|
||||||
|
const roll = await this.#evaluateDisplayedRoll(
|
||||||
|
Array.from({ length: pendingDice.length }, () => "1d12").join(" + "),
|
||||||
|
(pendingRoll) => this.#applyDieAppearances(pendingRoll, pendingDice),
|
||||||
|
)
|
||||||
|
|
||||||
|
const dieTerms = roll.terms.filter((term) => Number(term.faces ?? 0) === 12)
|
||||||
|
const nextPendingDice = []
|
||||||
|
|
||||||
|
pendingDice.forEach((die, index) => {
|
||||||
|
const face = Number(dieTerms[index]?.results?.[0]?.result ?? 0)
|
||||||
|
die.rolls.push(roll)
|
||||||
|
die.faces.push(face)
|
||||||
|
die.total += face
|
||||||
|
if (face === 12) nextPendingDice.push(die)
|
||||||
|
})
|
||||||
|
|
||||||
|
pendingDice = nextPendingDice
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return dice.map((die) => ({
|
||||||
|
...die,
|
||||||
|
firstFace: die.faces[0] ?? 0,
|
||||||
|
exploded: die.faces.length > 1,
|
||||||
|
breakdown: die.faces.join(" + "),
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
static #applyDieAppearances(roll, dice) {
|
||||||
|
const dieTerms = roll.terms.filter((term) => Number(term.faces ?? 0) === 12)
|
||||||
|
dieTerms.forEach((term, index) => {
|
||||||
|
term.options ??= {}
|
||||||
|
term.options.appearance = this.#getDieAppearance(dice[index]?.type)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static #getDieAppearance(type) {
|
||||||
|
switch (type) {
|
||||||
|
case "songes":
|
||||||
|
return {
|
||||||
|
foreground: "#111111",
|
||||||
|
background: "#f3efe4",
|
||||||
|
outline: "#b8aa87",
|
||||||
|
}
|
||||||
|
case "cauchemar":
|
||||||
|
return {
|
||||||
|
foreground: "#f4f0e8",
|
||||||
|
background: "#111111",
|
||||||
|
outline: "#5d5d5d",
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return {
|
||||||
|
foreground: "#201813",
|
||||||
|
background: "#ddd0b0",
|
||||||
|
outline: "#8d5c3b",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static async #evaluateDisplayedRoll(formula, configureRoll = null) {
|
||||||
|
const roll = typeof formula === "string" ? new Roll(formula) : formula
|
||||||
|
if (configureRoll) configureRoll(roll)
|
||||||
|
await roll.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) {
|
static #needsSelection(dice) {
|
||||||
@@ -1571,9 +1730,106 @@ export class LesOubliesRolls {
|
|||||||
songesPoints: Number(context.system.songes?.points ?? 0),
|
songesPoints: Number(context.system.songes?.points ?? 0),
|
||||||
cauchemarValue: Number(context.system.cauchemar?.value ?? 0),
|
cauchemarValue: Number(context.system.cauchemar?.value ?? 0),
|
||||||
cauchemarPoints: Number(context.system.cauchemar?.points ?? 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) {
|
static #createSpentResource(extraDie) {
|
||||||
if (!extraDie) return null
|
if (!extraDie) return null
|
||||||
return {
|
return {
|
||||||
@@ -1860,16 +2116,7 @@ export class LesOubliesRolls {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static #getWeaponBaseDamage(actor, weapon) {
|
static #getWeaponBaseDamage(actor, weapon) {
|
||||||
const damageText = String(weapon?.system?.damage || "")
|
return LesOubliesUtility.getWeaponBaseDamage(actor, weapon)
|
||||||
const parsed = this.#extractFirstInteger(damageText)
|
|
||||||
if (parsed !== null) return parsed
|
|
||||||
|
|
||||||
const explicitValue = Number(weapon?.system?.sizeValue ?? 0)
|
|
||||||
if (explicitValue > 0) return explicitValue
|
|
||||||
|
|
||||||
const actorSize = Number(actor?.system?.size?.value ?? 0)
|
|
||||||
const sizeModifier = Number(weapon?.system?.sizeModifier ?? 0)
|
|
||||||
return Math.max(actorSize + sizeModifier, 0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static #extractFirstInteger(text) {
|
static #extractFirstInteger(text) {
|
||||||
|
|||||||
@@ -97,6 +97,38 @@ export class LesOubliesUtility {
|
|||||||
return [...documents].sort((left, right) => left.name.localeCompare(right.name, "fr"))
|
return [...documents].sort((left, right) => left.name.localeCompare(right.name, "fr"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static getWeaponBaseDamage(actor, weapon) {
|
||||||
|
const sizeMode = String(weapon?.system?.sizeMode || "").toLowerCase()
|
||||||
|
if (sizeMode === "variable") {
|
||||||
|
const actorSize = Number(actor?.system?.size?.value ?? 0)
|
||||||
|
const sizeModifier = Number(weapon?.system?.sizeModifier ?? 0)
|
||||||
|
return Math.max(actorSize + sizeModifier, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
const explicitValue = Number(weapon?.system?.sizeValue ?? 0)
|
||||||
|
if (explicitValue > 0) return explicitValue
|
||||||
|
|
||||||
|
const damageText = String(weapon?.system?.damage || "")
|
||||||
|
const match = damageText.match(/-?\d+/)
|
||||||
|
return match ? Number(match[0]) : 0
|
||||||
|
}
|
||||||
|
|
||||||
|
static formatWeaponDamage(actor, weapon) {
|
||||||
|
const baseLabel = String(weapon?.system?.damage || "").trim()
|
||||||
|
const baseDamage = this.getWeaponBaseDamage(actor, weapon)
|
||||||
|
const sizeMode = String(weapon?.system?.sizeMode || "").toLowerCase()
|
||||||
|
if (sizeMode === "variable" || /taille/i.test(baseLabel)) {
|
||||||
|
return baseLabel ? `${baseLabel} (${baseDamage})` : String(baseDamage)
|
||||||
|
}
|
||||||
|
return baseLabel || String(baseDamage)
|
||||||
|
}
|
||||||
|
|
||||||
|
static uniqueStrings(values = []) {
|
||||||
|
return [...new Set((Array.isArray(values) ? values : [])
|
||||||
|
.map((value) => String(value ?? "").trim())
|
||||||
|
.filter(Boolean))]
|
||||||
|
}
|
||||||
|
|
||||||
static async prepareEnrichedHtml(documentName, type, systemData) {
|
static async prepareEnrichedHtml(documentName, type, systemData) {
|
||||||
const htmlFields = game.system.documentTypes?.[documentName]?.[type]?.htmlFields ?? []
|
const htmlFields = game.system.documentTypes?.[documentName]?.[type]?.htmlFields ?? []
|
||||||
const enriched = {}
|
const enriched = {}
|
||||||
|
|||||||
@@ -21,6 +21,11 @@ export default class CompagnieDataModel extends foundry.abstract.TypeDataModel {
|
|||||||
label: new fields.StringField({ initial: "" }),
|
label: new fields.StringField({ initial: "" }),
|
||||||
details: new fields.StringField({ initial: "" }),
|
details: new fields.StringField({ initial: "" }),
|
||||||
}), { 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({
|
money: new fields.SchemaField({
|
||||||
ecorces: new fields.NumberField({ initial: 0, integer: true, min: 0 }),
|
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({
|
flagsNarratifs: new fields.SchemaField({
|
||||||
ombreDuTourment: new fields.BooleanField({ initial: false }),
|
ombreDuTourment: new fields.BooleanField({ initial: false }),
|
||||||
isCaptain: new fields.BooleanField({ initial: false }),
|
isCaptain: new fields.BooleanField({ initial: false }),
|
||||||
|
|||||||
@@ -5,8 +5,9 @@
|
|||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node scripts/build-compendiums.mjs && gulp build",
|
"build": "node scripts/split-compendium-content.mjs && gulp build",
|
||||||
"build:packs": "node scripts/build-compendiums.mjs",
|
"build:packs": "node scripts/split-compendium-content.mjs",
|
||||||
|
"split:compendiums": "node scripts/split-compendium-content.mjs",
|
||||||
"watch": "gulp watch"
|
"watch": "gulp watch"
|
||||||
},
|
},
|
||||||
"author": "Copilot",
|
"author": "Copilot",
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Aide du système",
|
||||||
|
"type": "JournalEntry",
|
||||||
|
"ownership": {
|
||||||
|
"default": 2
|
||||||
|
},
|
||||||
|
"flags": {
|
||||||
|
"core": {}
|
||||||
|
},
|
||||||
|
"pages": [
|
||||||
|
{
|
||||||
|
"name": "Bienvenue",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Les Oubliés dans Foundry</h1><p>Cette aide de jeu présente le fonctionnement concret du système <strong>fvtt-les-oublies</strong> dans Foundry VTT. Elle est pensée pour une prise en main rapide autour de la fiche, des jets, du combat, de la magie et des compendiums fournis.</p><h2>Ce que fait le système</h2><ul><li>gère les acteurs <strong>Personnage</strong>, <strong>Compagnie</strong> et <strong>Créature</strong> ;</li><li>calcule les valeurs dérivées utiles, dont les points de vie liés à la taille ;</li><li>propose des dialogues dédiés pour les tests, confrontations, initiatives et dégâts ;</li><li>fournit des compendiums techniques pour les races, tribus, métiers, compétences, armes, armures, équipements, pouvoirs de compagnie et sortilèges.</li></ul><h2>Par où commencer ?</h2><ol><li>Créez un <strong>Personnage</strong>.</li><li>Assignez-lui une <strong>Race</strong>, une <strong>Tribu</strong> et un <strong>Métier</strong> par glisser-déposer.</li><li>Complétez ou ajustez ses compétences et son équipement.</li><li>Utilisez les boutons de la fiche pour lancer les jets utiles en jeu.</li></ol><p>Les pages suivantes détaillent chaque zone importante avec des captures d'écran prises dans le système lui-même.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Portrait et identité",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Lire la fiche personnage</h1><p>L'onglet <strong>Portrait</strong> concentre l'identité du personnage et les éléments de création qui structurent le reste de la fiche.</p><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-sheet-portrait.png\" alt=\"Fiche personnage des Oubliés, onglet Portrait.\" /><figcaption>La fiche personnage affiche immédiatement les références de race, de tribu et de métier.</figcaption></figure><h2>À retenir</h2><ul><li>La zone <strong>Race / Tribu / Métier</strong> accepte le glisser-déposer depuis les compendiums et remplace proprement la référence existante.</li><li>Un nouveau personnage reçoit automatiquement le token système <code>border_token_oublies.webp</code> tant qu'aucun token personnalisé n'a déjà été défini.</li><li>Les informations d'identité, les notes et les ressources principales restent modifiables directement sur la fiche.</li></ul><p>Le portrait sert surtout de synthèse et de point d'entrée avant de passer aux compétences et aux actions de jeu.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Compétences et profils",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Compétences et profils</h1><p>L'onglet <strong>Compétences</strong> présente les compétences regroupées par profil. Le système rappelle en permanence la logique <strong>Base + Profil = Valeur finale</strong>.</p><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-sheet-competences.png\" alt=\"Fiche personnage des Oubliés, onglet Compétences.\" /><figcaption>Chaque groupe affiche sa valeur de profil et les compétences qui en dépendent.</figcaption></figure><h2>Fonctionnement</h2><ul><li>Les compétences du personnage proviennent en pratique de la création, des compendiums ou d'ajouts manuels.</li><li>Les compétences fermées restent identifiables et peuvent demander une activation fictionnelle ou un apprentissage préalable.</li><li>Les domaines utiles (<em>Arts</em>, <em>Artisanat</em>, <em>Érudition</em>, <em>Langues</em>) peuvent être saisis sur les items concernés.</li></ul><p>Quand vous préparez un jet, c'est généralement la <strong>valeur finale</strong> affichée ici qu'il faut reporter dans le dialogue de résolution.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jets de test, confrontation et initiative",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Les jets principaux</h1><p>Le système embarque trois dialogues génériques : <strong>test</strong>, <strong>confrontation</strong> et <strong>initiative</strong>. Ils respectent le principe Songes / Cauchemar avec choix du dé retenu quand plusieurs dés sont en concurrence.</p><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-dialog-test.png\" alt=\"Dialogue de jet de test dans le système Les Oubliés.\" /><figcaption>Le jet de test permet de choisir la difficulté, le mode de jet et un éventuel dé supplémentaire.</figcaption></figure><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-dialog-confrontation.png\" alt=\"Dialogue de confrontation dans le système Les Oubliés.\" /><figcaption>La confrontation gère les deux camps, avec saisie manuelle ou sélection d'un adversaire cible.</figcaption></figure><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-dialog-initiative.png\" alt=\"Dialogue d'initiative dans le système Les Oubliés.\" /><figcaption>L'initiative s'appuie sur Rapidité puis applique l'arrondi supérieur avec plafond à 12.</figcaption></figure><h2>Comportements utiles</h2><ul><li>Le système gère les modes <strong>1d12</strong>, <strong>2d12</strong> Songes / Cauchemar et les variantes avec dé supplémentaire.</li><li>Le <strong>12 explosif</strong> et le <strong>1 naturel</strong> sont pris en compte dans la résolution.</li><li>La confrontation peut récupérer une cible sélectionnée sur la scène, mais reste utilisable en saisie libre si aucune cible n'est active.</li></ul><p>Après le lancer, le chat produit une carte de résultat dédiée avec le détail utile à la table.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Combat, dégâts et protections",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Combattre dans le système</h1><p>L'onglet <strong>Combat & Magie</strong> regroupe les actions de combat, les armes équipées et les aides à la résolution associées.</p><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-sheet-combat-magie.png\" alt=\"Fiche personnage des Oubliés, onglet Combat et magie.\" /><figcaption>Les actions de combat, les réserves de fils et la magie partagent le même onglet pour limiter les allers-retours.</figcaption></figure><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-dialog-degats.png\" alt=\"Dialogue de résolution des dégâts dans le système Les Oubliés.\" /><figcaption>Le helper de dégâts applique la base de l'arme, les modificateurs et la protection ciblée.</figcaption></figure><h2>Points importants</h2><ul><li>Le bouton <strong>Attaque</strong> ouvre une action contextualisée depuis l'arme portée.</li><li>Le bouton <strong>Dégâts</strong> ouvre un helper plutôt qu'un jet classique, conformément aux règles du jeu.</li><li>Les armes à taille variable tiennent compte de la <strong>taille réelle du porteur</strong> pour calculer les dégâts de base.</li><li>La protection de la cible peut être appliquée directement dans la résolution finale.</li></ul><p>Les cartes de chat qui en résultent sont compactes et conçues pour un usage fréquent en partie.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Magie, fils et globes",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Magie et réserves</h1><p>La moitié basse de l'onglet <strong>Combat & Magie</strong> gère les fils, les globes et les sortilèges du personnage.</p><figure><img src=\"systems/fvtt-les-oublies/assets/ui/help-sheet-combat-magie.png\" alt=\"Réserves de fils, globes et sortilèges dans la fiche personnage des Oubliés.\" /><figcaption>Les réserves personnelle et de compagnie sont directement manipulables depuis la fiche.</figcaption></figure><h2>Ce que permet la fiche</h2><ul><li>déplacer des <strong>fils de Songes</strong>, des <strong>fils de Cauchemar</strong> et des <strong>globes vides</strong> entre la réserve personnelle et la compagnie ;</li><li>lancer la <strong>récolte de fils</strong> depuis le bouton dédié ;</li><li>activer un <strong>sortilège</strong> depuis sa ligne sans passer par un jet générique quand les règles ne le demandent pas.</li></ul><p>Les dépenses de fils rendent automatiquement autant de globes vides à la réserve utilisée. Le système met ainsi l'accent sur la circulation des ressources plutôt que sur des sous-feuilles séparées.</p>"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Compendiums et glisser-déposer",
|
||||||
|
"type": "text",
|
||||||
|
"title": {
|
||||||
|
"show": true,
|
||||||
|
"level": 1
|
||||||
|
},
|
||||||
|
"text": {
|
||||||
|
"format": 1,
|
||||||
|
"content": "<h1>Utiliser les compendiums</h1><p>Les compendiums fournis par le système servent de base technique pour créer et enrichir les acteurs.</p><h2>Usages recommandés</h2><ul><li>glisser une <strong>race</strong>, une <strong>tribu</strong> ou un <strong>métier</strong> sur un personnage pour configurer rapidement sa création ;</li><li>ajouter des <strong>armes</strong>, <strong>armures</strong>, <strong>équipements</strong> et <strong>sortilèges</strong> depuis les packs dédiés ;</li><li>faire glisser un item embarqué depuis la fiche vers la sidebar des objets quand vous souhaitez l'extraire comme document autonome.</li></ul><h2>À savoir</h2><ul><li>Les compendiums du système sont volontairement <strong>techniques</strong> : les champs descriptifs riches ont été vidés pour rester dans le périmètre du système.</li><li>Les versions complètes des contenus sont destinées au module frère <strong>fvtt-les-oublies-base</strong>.</li></ul><p>Pour une table de jeu, le plus simple est donc d'utiliser ces compendiums comme bibliothèque de construction rapide, puis d'affiner directement sur la fiche si nécessaire.</p>"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
@@ -1,38 +1,762 @@
|
|||||||
[
|
[
|
||||||
{ "name": "Aiguille à coudre", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Objet de géant détourné en arme fine et redoutablement pointue.</p>", "notes": "", "category": "melee", "origin": "geant", "sizeMode": "fixe", "sizeValue": 2, "sizeModifier": 0, "damage": "2", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 90, "equipped": false } },
|
{
|
||||||
{ "name": "Aiguille à tricoter", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Longue arme de géant reconvertie en lance massive. Le tableau lui accorde <em>Charge</em> et exige <em>Force 1</em>.</p>", "notes": "", "category": "melee", "origin": "geant", "sizeMode": "fixe", "sizeValue": 5, "sizeModifier": 0, "damage": "5", "range": "", "properties": ["Charge", "Force 1"], "restrictedRace": "", "quantity": 1, "price": 630, "equipped": false } },
|
"name": "Aiguille à coudre",
|
||||||
{ "name": "Clef de géant", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Arme très prisée dans le milieu des mercenaires. Ces instruments d'acier de géant sont réputés d'une redoutable efficacité.</p>", "notes": "", "category": "melee", "origin": "geant", "sizeMode": "plage", "sizeValue": 3, "sizeModifier": 0, "damage": "3 à 5", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 450, "equipped": false } },
|
"type": "arme",
|
||||||
{ "name": "Couteau de géant", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Grand couteau des géants utilisé comme arme longue du Petit Peuple.</p>", "notes": "", "category": "melee", "origin": "geant", "sizeMode": "fixe", "sizeValue": 5, "sizeModifier": 0, "damage": "5", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 630, "equipped": false } },
|
"img": "icons/svg/sword.svg",
|
||||||
{ "name": "Clou", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Simple clou de géant, efficace comme pointe ou pieu improvisé.</p>", "notes": "", "category": "melee", "origin": "geant", "sizeMode": "plage", "sizeValue": 2, "sizeModifier": 0, "damage": "2 à 5", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 12, "equipped": false } },
|
"system": {
|
||||||
{ "name": "Épingle à nourrice", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Broche de géant détournée en arme perçante. On en fait aussi parfois des grappins.</p>", "notes": "", "category": "melee", "origin": "geant", "sizeMode": "fixe", "sizeValue": 2, "sizeModifier": 0, "damage": "2", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 360, "equipped": false } },
|
"description": "",
|
||||||
{ "name": "Fourchette", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Couvert de géant converti en arme d'estoc ou de hampe selon sa prise.</p>", "notes": "", "category": "melee", "origin": "geant", "sizeMode": "plage", "sizeValue": 4, "sizeModifier": 0, "damage": "4 à 5", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 630, "equipped": false } },
|
"notes": "",
|
||||||
{ "name": "Grifdrachat", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Pointe de métal recourbée en forme de griffe de drachat. Extrêmement pointue, elle peut se glisser dans la plupart des interstices des armures.</p>", "notes": "", "category": "melee", "origin": "geant", "sizeMode": "fixe", "sizeValue": 3, "sizeModifier": 0, "damage": "3", "range": "", "properties": ["Blessure précise"], "restrictedRace": "", "quantity": 1, "price": 540, "equipped": false } },
|
"category": "melee",
|
||||||
{ "name": "Hameçon des Marches", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Les vivitins utilisent volontiers ces gros hameçons de géants comme armes, tenus à la main ou montés au bout d'une hampe.</p>", "notes": "", "category": "melee", "origin": "geant", "sizeMode": "fixe", "sizeValue": 2, "sizeModifier": 0, "damage": "2", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 21, "equipped": false } },
|
"origin": "geant",
|
||||||
{ "name": "Marteau de tailleur", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Outil de géant lourd et massif, réemployé comme arme contondante. Le livre ne donne pas de tarif explicite pour cette entrée.</p>", "notes": "", "category": "melee", "origin": "geant", "sizeMode": "plage", "sizeValue": 4, "sizeModifier": 0, "damage": "4 à 5", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 0, "equipped": false } },
|
"sizeMode": "fixe",
|
||||||
{ "name": "Paire de ciseaux", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Grande paire de ciseaux de géant. Le tableau lui accorde <em>Attaque multiple</em> mais impose <em>Force 3</em>.</p>", "notes": "", "category": "melee", "origin": "geant", "sizeMode": "plage", "sizeValue": 4, "sizeModifier": 0, "damage": "4 à 5", "range": "", "properties": ["Attaque multiple", "Force 3"], "restrictedRace": "", "quantity": 1, "price": 540, "equipped": false } },
|
"sizeValue": 2,
|
||||||
|
"sizeModifier": 0,
|
||||||
{ "name": "Akinakas", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Arme prisee par l'élite des gardes de Crinios. Les belgfolks fixent à leur lance les piques prélevées sur des veuves des mers ; l'akinakas est réputé traverser les alliages.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 0, "damage": "Taille +0", "range": "", "properties": ["Blessure précise"], "restrictedRace": "", "quantity": 1, "price": 900, "equipped": false } },
|
"damage": "2",
|
||||||
{ "name": "Arc", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Arme de tir du Petit Peuple. Encocher une nouvelle flèche est une action libre.</p>", "notes": "", "category": "tir", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 0, "damage": "Taille +0", "range": "75", "properties": ["Encocher une nouvelle flèche est une action libre"], "restrictedRace": "", "quantity": 1, "price": 360, "equipped": false } },
|
"range": "",
|
||||||
{ "name": "Arbalète", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Arme de tir du Petit Peuple. Encocher un nouveau carreau est une action unique. Le livre ne donne pas de tarif explicite dans les tableaux de prix.</p>", "notes": "", "category": "tir", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 1, "damage": "Taille +1", "range": "100", "properties": ["Encocher un nouveau carreau est une action unique"], "restrictedRace": "", "quantity": 1, "price": 0, "equipped": false } },
|
"properties": [],
|
||||||
{ "name": "Bâton de marche", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Bâton robuste qui peut aussi servir d'arme d'appoint. Le tableau lui accorde la prime <em>Blessure non létale</em>.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 1, "damage": "Taille +1", "range": "", "properties": ["Blessure non létale"], "restrictedRace": "", "quantity": 1, "price": 10, "equipped": false } },
|
"restrictedRace": "",
|
||||||
{ "name": "Coup de poing", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Ensemble de bagues reliées par une barre métallique. Arme de bagarreur qui laisse des marques durables.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": -1, "damage": "Taille -1", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 24, "equipped": false } },
|
"quantity": 1,
|
||||||
{ "name": "Dague de Songiam", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Dague kobolde si fine et discrète qu'on peut la dissimuler sans éveiller les soupçons. On la surnomme la dague du dernier souffle.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": -1, "damage": "Taille -1", "range": "", "properties": ["Discrétion +3 (en cas de fouille)", "Blessure précise"], "restrictedRace": "", "quantity": 1, "price": 270, "equipped": false } },
|
"price": 90,
|
||||||
{ "name": "Dandegéant", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Masse d'arme à deux mains utilisée notamment par les Huvons, avec une dent de géant à son extrémité.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "fixe", "sizeValue": 4, "sizeModifier": 0, "damage": "4", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 720, "equipped": false } },
|
"equipped": false
|
||||||
{ "name": "Épée", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Épée standard du Petit Peuple, listée sans particularité spéciale dans le tableau.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 0, "damage": "Taille +0", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 360, "equipped": false } },
|
}
|
||||||
{ "name": "Espadon huvon", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Grande épée forgée par et pour les Korrigans des Huvons. Aussi longue qu'une aiguille à tricoter, elle réclame <em>Force 1</em>.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "fixe", "sizeValue": 4, "sizeModifier": 0, "damage": "4", "range": "", "properties": ["Force 1"], "restrictedRace": "Korrigan", "quantity": 1, "price": 900, "equipped": false } },
|
},
|
||||||
{ "name": "Fronde", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Arme de tir simple du Petit Peuple.</p>", "notes": "", "category": "tir", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": -1, "damage": "Taille -1", "range": "50", "properties": [], "restrictedRace": "", "quantity": 1, "price": 5, "equipped": false } },
|
{
|
||||||
{ "name": "Glaive", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Arme de taille du Petit Peuple, listée sans propriété particulière.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 0, "damage": "Taille +0", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 180, "equipped": false } },
|
"name": "Aiguille à tricoter",
|
||||||
{ "name": "Hache", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Hache standard du Petit Peuple.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 0, "damage": "Taille +0", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 270, "equipped": false } },
|
"type": "arme",
|
||||||
{ "name": "Hachette", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Petite hache pouvant être lancée. Le tableau lui donne une portée de <em>Taille x 10</em>.</p>", "notes": "", "category": "jet", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": -1, "damage": "Taille -1", "range": "Taille x 10", "properties": [], "restrictedRace": "", "quantity": 1, "price": 180, "equipped": false } },
|
"img": "icons/svg/sword.svg",
|
||||||
{ "name": "Hymalamort", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Gourdin hérissé de clous, sans doute l'arme issue de matériaux de géants la plus répandue. Brutale, elle demande de la force pour être arrachée du corps de l'adversaire.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 0, "damage": "Taille +0", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 24, "equipped": false } },
|
"system": {
|
||||||
{ "name": "Lame coup de poing", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Variante du coup de poing dotée d'une large lame dans le prolongement de la main, souvent vue dans les arènes de Ciméria.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 0, "damage": "Taille +0", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 180, "equipped": false } },
|
"description": "",
|
||||||
{ "name": "Lame d’Ichtys", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Lame recourbée, symbole des Vivitins, remise aux prêtres d'Ichtys lors de leur intronisation. Les marins l'apprécient particulièrement.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 0, "damage": "Taille +0", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 360, "equipped": false } },
|
"notes": "",
|
||||||
{ "name": "Lance plume", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Lance ornée d'une plume taillée et incrustée. Si elle suit immédiatement un engagement, elle bénéficie gratuitement de la prime <em>Blessure grave</em> via <em>Charge</em>.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 1, "damage": "Taille +1", "range": "", "properties": ["Charge"], "restrictedRace": "", "quantity": 1, "price": 270, "equipped": false } },
|
"category": "melee",
|
||||||
{ "name": "Mains nues", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Entrée canonique du tableau des armes pour les attaques à mains nues.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": -1, "damage": "Taille -1", "range": "", "properties": ["Blessure légère"], "restrictedRace": "", "quantity": 1, "price": 0, "equipped": false } },
|
"origin": "geant",
|
||||||
{ "name": "Masse", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Masse standard du Petit Peuple. Le tableau de prix la nomme <em>Masse en os</em>.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 0, "damage": "Taille +0", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 12, "equipped": false } },
|
"sizeMode": "fixe",
|
||||||
{ "name": "Masse d’arme", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Masse d'arme du Petit Peuple, distincte de la simple masse.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 0, "damage": "Taille +0", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 360, "equipped": false } },
|
"sizeValue": 5,
|
||||||
{ "name": "Poignard", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Arme courte qui peut aussi être jetée. Le tableau lui donne une portée de <em>Taille x 5</em>.</p>", "notes": "", "category": "jet", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": -1, "damage": "Taille -1", "range": "Taille x 5", "properties": [], "restrictedRace": "", "quantity": 1, "price": 90, "equipped": false } },
|
"sizeModifier": 0,
|
||||||
{ "name": "Piolet", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Version martiale du piolet listée dans le tableau des armes. À distinguer du piolet de voyage vendu dans le matériel de voyage.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 0, "damage": "Taille +0", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 270, "equipped": false } },
|
"damage": "5",
|
||||||
{ "name": "Sabre sixt", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Arme de prédilection de la noblesse des Sixts, souvent ornée de pierres précieuses et chargée de prestige.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": 0, "damage": "Taille +0", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 450, "equipped": false } },
|
"range": "",
|
||||||
{ "name": "Serpe", "type": "arme", "img": "icons/svg/sword.svg", "system": { "description": "<p>Petite lame courbe du Petit Peuple.</p>", "notes": "", "category": "melee", "origin": "petitPeuple", "sizeMode": "variable", "sizeValue": 0, "sizeModifier": -1, "damage": "Taille -1", "range": "", "properties": [], "restrictedRace": "", "quantity": 1, "price": 135, "equipped": false } }
|
"properties": [
|
||||||
|
"Charge",
|
||||||
|
"Force 1"
|
||||||
|
],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 630,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Clef de géant",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "geant",
|
||||||
|
"sizeMode": "plage",
|
||||||
|
"sizeValue": 3,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "3 à 5",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 450,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Couteau de géant",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "geant",
|
||||||
|
"sizeMode": "fixe",
|
||||||
|
"sizeValue": 5,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "5",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 630,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Clou",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "geant",
|
||||||
|
"sizeMode": "plage",
|
||||||
|
"sizeValue": 2,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "2 à 5",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 12,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Épingle à nourrice",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "geant",
|
||||||
|
"sizeMode": "fixe",
|
||||||
|
"sizeValue": 2,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "2",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 360,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fourchette",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "geant",
|
||||||
|
"sizeMode": "plage",
|
||||||
|
"sizeValue": 4,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "4 à 5",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 630,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Grifdrachat",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "geant",
|
||||||
|
"sizeMode": "fixe",
|
||||||
|
"sizeValue": 3,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "3",
|
||||||
|
"range": "",
|
||||||
|
"properties": [
|
||||||
|
"Blessure précise"
|
||||||
|
],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 540,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Hameçon des Marches",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "geant",
|
||||||
|
"sizeMode": "fixe",
|
||||||
|
"sizeValue": 2,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "2",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 21,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Marteau de tailleur",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "geant",
|
||||||
|
"sizeMode": "plage",
|
||||||
|
"sizeValue": 4,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "4 à 5",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 0,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Paire de ciseaux",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "geant",
|
||||||
|
"sizeMode": "plage",
|
||||||
|
"sizeValue": 4,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "4 à 5",
|
||||||
|
"range": "",
|
||||||
|
"properties": [
|
||||||
|
"Attaque multiple",
|
||||||
|
"Force 3"
|
||||||
|
],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 540,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Akinakas",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "Taille +0",
|
||||||
|
"range": "",
|
||||||
|
"properties": [
|
||||||
|
"Blessure précise"
|
||||||
|
],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 900,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Arc",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "tir",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "Taille +0",
|
||||||
|
"range": "75",
|
||||||
|
"properties": [
|
||||||
|
"Encocher une nouvelle flèche est une action libre"
|
||||||
|
],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 360,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Arbalète",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "tir",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 1,
|
||||||
|
"damage": "Taille +1",
|
||||||
|
"range": "100",
|
||||||
|
"properties": [
|
||||||
|
"Encocher un nouveau carreau est une action unique"
|
||||||
|
],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 0,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bâton de marche",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 1,
|
||||||
|
"damage": "Taille +1",
|
||||||
|
"range": "",
|
||||||
|
"properties": [
|
||||||
|
"Blessure non létale"
|
||||||
|
],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 10,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Coup de poing",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": -1,
|
||||||
|
"damage": "Taille -1",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 24,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dague de Songiam",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": -1,
|
||||||
|
"damage": "Taille -1",
|
||||||
|
"range": "",
|
||||||
|
"properties": [
|
||||||
|
"Discrétion +3 (en cas de fouille)",
|
||||||
|
"Blessure précise"
|
||||||
|
],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 270,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dandegéant",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "fixe",
|
||||||
|
"sizeValue": 4,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "4",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 720,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Épée",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "Taille +0",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 360,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Espadon huvon",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "fixe",
|
||||||
|
"sizeValue": 4,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "4",
|
||||||
|
"range": "",
|
||||||
|
"properties": [
|
||||||
|
"Force 1"
|
||||||
|
],
|
||||||
|
"restrictedRace": "Korrigan",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 900,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Fronde",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "tir",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": -1,
|
||||||
|
"damage": "Taille -1",
|
||||||
|
"range": "50",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 5,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Glaive",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "Taille +0",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 180,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Hache",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "Taille +0",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 270,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Hachette",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "jet",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": -1,
|
||||||
|
"damage": "Taille -1",
|
||||||
|
"range": "Taille x 10",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 180,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Hymalamort",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "Taille +0",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 24,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lame coup de poing",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "Taille +0",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 180,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lame d’Ichtys",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "Taille +0",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 360,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lance plume",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 1,
|
||||||
|
"damage": "Taille +1",
|
||||||
|
"range": "",
|
||||||
|
"properties": [
|
||||||
|
"Charge"
|
||||||
|
],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 270,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mains nues",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": -1,
|
||||||
|
"damage": "Taille -1",
|
||||||
|
"range": "",
|
||||||
|
"properties": [
|
||||||
|
"Blessure légère"
|
||||||
|
],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 0,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Masse",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "Taille +0",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 12,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Masse d’arme",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "Taille +0",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 360,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Poignard",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "jet",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": -1,
|
||||||
|
"damage": "Taille -1",
|
||||||
|
"range": "Taille x 5",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 90,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Piolet",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "Taille +0",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 270,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sabre sixt",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": 0,
|
||||||
|
"damage": "Taille +0",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 450,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Serpe",
|
||||||
|
"type": "arme",
|
||||||
|
"img": "icons/svg/sword.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"notes": "",
|
||||||
|
"category": "melee",
|
||||||
|
"origin": "petitPeuple",
|
||||||
|
"sizeMode": "variable",
|
||||||
|
"sizeValue": 0,
|
||||||
|
"sizeModifier": -1,
|
||||||
|
"damage": "Taille -1",
|
||||||
|
"range": "",
|
||||||
|
"properties": [],
|
||||||
|
"restrictedRace": "",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 135,
|
||||||
|
"equipped": false
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,5 +1,50 @@
|
|||||||
[
|
[
|
||||||
{ "name": "Protégé", "type": "armure", "img": "icons/svg/shield.svg", "system": { "description": "<p>État d'équipement léger : bouclier simple, quelques pièces de défense ou protection souple.</p>", "state": "protégé", "protection": 1, "physicalPenalty": 1, "initiativePenalty": 1, "quantity": 1, "price": 0, "equipped": false } },
|
{
|
||||||
{ "name": "Harnaché", "type": "armure", "img": "icons/svg/shield.svg", "system": { "description": "<p>État d'équipement intermédiaire combinant plusieurs pièces d'armure.</p>", "state": "harnaché", "protection": 2, "physicalPenalty": 2, "initiativePenalty": 2, "quantity": 1, "price": 0, "equipped": false } },
|
"name": "Protégé",
|
||||||
{ "name": "Bardé", "type": "armure", "img": "icons/svg/shield.svg", "system": { "description": "<p>État d'équipement lourd et très encombrant, correspondant au niveau maximal du livre de base.</p>", "state": "bardé", "protection": 3, "physicalPenalty": 3, "initiativePenalty": 3, "quantity": 1, "price": 0, "equipped": false } }
|
"type": "armure",
|
||||||
|
"img": "icons/svg/shield.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"state": "protégé",
|
||||||
|
"protection": 1,
|
||||||
|
"physicalPenalty": 1,
|
||||||
|
"initiativePenalty": 1,
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 0,
|
||||||
|
"equipped": false,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Harnaché",
|
||||||
|
"type": "armure",
|
||||||
|
"img": "icons/svg/shield.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"state": "harnaché",
|
||||||
|
"protection": 2,
|
||||||
|
"physicalPenalty": 2,
|
||||||
|
"initiativePenalty": 2,
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 0,
|
||||||
|
"equipped": false,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bardé",
|
||||||
|
"type": "armure",
|
||||||
|
"img": "icons/svg/shield.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"state": "bardé",
|
||||||
|
"protection": 3,
|
||||||
|
"physicalPenalty": 3,
|
||||||
|
"initiativePenalty": 3,
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 0,
|
||||||
|
"equipped": false,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
"type": "armure",
|
"type": "armure",
|
||||||
"img": "icons/svg/shield.svg",
|
"img": "icons/svg/shield.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>État d'armure légère du livre de base. Il correspond à un personnage équipé de quelques pièces défensives seulement : rondache, casque, bouton de géant, cuir léger ou pièces disparates.</p>",
|
"description": "",
|
||||||
"notes": "<p>Le chapitre 5 donne surtout une table de prix par pièce. Cette entrée sert de profil prêt à jouer fidèle à la règle : protection 1, malus physique 1, malus d'initiative 1.</p>",
|
"notes": "",
|
||||||
"state": "protege",
|
"state": "protege",
|
||||||
"protection": 1,
|
"protection": 1,
|
||||||
"physicalPenalty": 1,
|
"physicalPenalty": 1,
|
||||||
@@ -20,8 +20,8 @@
|
|||||||
"type": "armure",
|
"type": "armure",
|
||||||
"img": "icons/svg/shield.svg",
|
"img": "icons/svg/shield.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>État d'armure intermédiaire du livre de base. Il représente un personnage réellement équipé : cuirasse, jambières, pavois ou ensemble cohérent de pièces de protection.</p>",
|
"description": "",
|
||||||
"notes": "<p>Le livre ne fixe pas de mécanique détaillée par pièce ; il donne un état global. Cette entrée correspond au profil standard de protection 2.</p>",
|
"notes": "",
|
||||||
"state": "harnache",
|
"state": "harnache",
|
||||||
"protection": 2,
|
"protection": 2,
|
||||||
"physicalPenalty": 2,
|
"physicalPenalty": 2,
|
||||||
@@ -36,8 +36,8 @@
|
|||||||
"type": "armure",
|
"type": "armure",
|
||||||
"img": "icons/svg/shield.svg",
|
"img": "icons/svg/shield.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>État d'armure lourde du livre de base. Il correspond à un personnage abondamment protégé, jusqu'à l'armure complète.</p>",
|
"description": "",
|
||||||
"notes": "<p>Profil abstrait mais canonique : protection 3, malus physique 3, malus d'initiative 3. À utiliser pour refléter les personnages les plus couverts sans surdétailler chaque pièce.</p>",
|
"notes": "",
|
||||||
"state": "barde",
|
"state": "barde",
|
||||||
"protection": 3,
|
"protection": 3,
|
||||||
"physicalPenalty": 3,
|
"physicalPenalty": 3,
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Mesure l'affinité du personnage avec les domaines artistiques. Un test permet de créer une œuvre, en reconnaître les techniques, en estimer l'intérêt ou mobiliser l'histoire de l'art.</p>",
|
"description": "",
|
||||||
"notes": "<p>Compétence à domaines : le nombre de domaines maîtrisés est égal à la base.</p>",
|
"notes": "",
|
||||||
"key": "arts",
|
"key": "arts",
|
||||||
"profileKey": "artiste",
|
"profileKey": "artiste",
|
||||||
"base": 0,
|
"base": 0,
|
||||||
@@ -13,7 +13,19 @@
|
|||||||
"domainSkill": true,
|
"domainSkill": true,
|
||||||
"domains": [],
|
"domains": [],
|
||||||
"fixedDomains": [],
|
"fixedDomains": [],
|
||||||
"exampleDomains": ["Architecture", "Calligraphie", "Chant", "Danse", "Dessin", "Littérature", "Musique", "Peinture", "Poésie", "Sculpture", "Théâtre"]
|
"exampleDomains": [
|
||||||
|
"Architecture",
|
||||||
|
"Calligraphie",
|
||||||
|
"Chant",
|
||||||
|
"Danse",
|
||||||
|
"Dessin",
|
||||||
|
"Littérature",
|
||||||
|
"Musique",
|
||||||
|
"Peinture",
|
||||||
|
"Poésie",
|
||||||
|
"Sculpture",
|
||||||
|
"Théâtre"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -21,7 +33,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Permet de saisir les intentions de quelqu'un, ce qu'il ressent, s'il ment, ou encore l'état émotionnel d'un animal.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "empathie",
|
"key": "empathie",
|
||||||
"profileKey": "artiste",
|
"profileKey": "artiste",
|
||||||
@@ -38,7 +50,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Régit le charme, les négociations, le marchandage, le mensonge et la persuasion par l'éloquence.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "seduction",
|
"key": "seduction",
|
||||||
"profileKey": "artiste",
|
"profileKey": "artiste",
|
||||||
@@ -55,7 +67,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Regroupe les actions physiques qui exigent coordination, agilité, équilibre et souffle, comme nager, courir ou sauter.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "athletisme",
|
"key": "athletisme",
|
||||||
"profileKey": "athlete",
|
"profileKey": "athlete",
|
||||||
@@ -72,7 +84,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Gouverne les réflexes, les courses de vitesse pure et toutes les actions où la célérité est essentielle. Elle sert aussi à déterminer l'initiative.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "rapidite",
|
"key": "rapidite",
|
||||||
"profileKey": "athlete",
|
"profileKey": "athlete",
|
||||||
@@ -89,7 +101,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Mesure la capacité à affirmer sa personnalité, garder son sang-froid et résister à la peur.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "volonte",
|
"key": "volonte",
|
||||||
"profileKey": "athlete",
|
"profileKey": "athlete",
|
||||||
@@ -106,7 +118,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Permet d'être à l'écoute de son environnement : entendre, repérer un danger avant qu'il ne surgisse, suivre quelqu'un sans le perdre ou déceler des signes faibles.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "sens",
|
"key": "sens",
|
||||||
"profileKey": "chasseur",
|
"profileKey": "chasseur",
|
||||||
@@ -123,7 +135,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Englobe la vie autonome en milieu sauvage : orientation, raccourcis, escalade, exploration de ruines, navigation aux étoiles, chasse, lecture de carte et pistage.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "survie",
|
"key": "survie",
|
||||||
"profileKey": "chasseur",
|
"profileKey": "chasseur",
|
||||||
@@ -140,7 +152,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Régit l'usage des armes à distance.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "tir",
|
"key": "tir",
|
||||||
"profileKey": "chasseur",
|
"profileKey": "chasseur",
|
||||||
@@ -157,8 +169,8 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Mesure l'habileté du personnage avec ses mains et des outils simples, pour fabriquer, réparer ou juger la qualité d'un objet.</p>",
|
"description": "",
|
||||||
"notes": "<p>Compétence à domaines : le nombre de domaines maîtrisés est égal à la base.</p>",
|
"notes": "",
|
||||||
"key": "artisanat",
|
"key": "artisanat",
|
||||||
"profileKey": "faiseur",
|
"profileKey": "faiseur",
|
||||||
"base": 0,
|
"base": 0,
|
||||||
@@ -166,7 +178,16 @@
|
|||||||
"domainSkill": true,
|
"domainSkill": true,
|
||||||
"domains": [],
|
"domains": [],
|
||||||
"fixedDomains": [],
|
"fixedDomains": [],
|
||||||
"exampleDomains": ["Enluminure", "Forge", "Mécanique", "Menuiserie", "Peinture", "Restauration d’œuvres d’art", "Serrurerie", "Taille de pierre"]
|
"exampleDomains": [
|
||||||
|
"Enluminure",
|
||||||
|
"Forge",
|
||||||
|
"Mécanique",
|
||||||
|
"Menuiserie",
|
||||||
|
"Peinture",
|
||||||
|
"Restauration d’œuvres d’art",
|
||||||
|
"Serrurerie",
|
||||||
|
"Taille de pierre"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -174,7 +195,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Regroupe les facultés de logique et de raisonnement. On l'utilise pour résoudre un problème, décrypter un message, jouer aux échecs ou démêler une énigme.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "intellect",
|
"key": "intellect",
|
||||||
"profileKey": "faiseur",
|
"profileKey": "faiseur",
|
||||||
@@ -191,7 +212,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Regroupe les premiers soins, les soins journaliers, le diagnostic des maladies, la prescription de remèdes et la chirurgie.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "soins",
|
"key": "soins",
|
||||||
"profileKey": "faiseur",
|
"profileKey": "faiseur",
|
||||||
@@ -208,7 +229,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Mesure l'aptitude à donner des ordres, inspirer loyauté ou peur, faire parler quelqu'un par intimidation ou soutenir un allié face à la peur.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "commandement",
|
"key": "commandement",
|
||||||
"profileKey": "forceNature",
|
"profileKey": "forceNature",
|
||||||
@@ -225,7 +246,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Permet de résister à la fatigue, de maintenir un effort prolongé et de rester éveillé de longues périodes.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "endurance",
|
"key": "endurance",
|
||||||
"profileKey": "forceNature",
|
"profileKey": "forceNature",
|
||||||
@@ -242,7 +263,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Régit les manifestations brutes de puissance physique : briser des liens, enfoncer une porte, soulever une charge ou tordre des barreaux.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "force",
|
"key": "force",
|
||||||
"profileKey": "forceNature",
|
"profileKey": "forceNature",
|
||||||
@@ -259,7 +280,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Mesure la faculté d'utiliser mains, pieds, tête, coudes et prises pour blesser, immobiliser ou faire tomber un adversaire.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "corpsacorps",
|
"key": "corpsacorps",
|
||||||
"profileKey": "guerrier",
|
"profileKey": "guerrier",
|
||||||
@@ -276,7 +297,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Mesure l'aptitude martiale avec une arme en main, qu'il s'agisse d'une lame, d'une arme d'hast ou d'une arme contondante.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "melee",
|
"key": "melee",
|
||||||
"profileKey": "guerrier",
|
"profileKey": "guerrier",
|
||||||
@@ -293,7 +314,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Détermine la capacité à débourrer, dresser et conduire des montures. Un personnage ne peut guider que des montures dont la taille ne dépasse la sienne que de 1 point.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "montures",
|
"key": "montures",
|
||||||
"profileKey": "guerrier",
|
"profileKey": "guerrier",
|
||||||
@@ -310,8 +331,8 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Équivalent d'Érudition pour les sortilèges des doux rêveurs et des sœurs de l'effroi.</p>",
|
"description": "",
|
||||||
"notes": "<p>Compétence fermée : avec une base de 0, tout test impliquant cette compétence est automatiquement raté.</p>",
|
"notes": "",
|
||||||
"key": "chimerisme",
|
"key": "chimerisme",
|
||||||
"profileKey": "mystique",
|
"profileKey": "mystique",
|
||||||
"base": 0,
|
"base": 0,
|
||||||
@@ -327,8 +348,8 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Équivalent d'Érudition pour les sortilèges des mages des Songes et des mages noirs.</p>",
|
"description": "",
|
||||||
"notes": "<p>Compétence fermée : avec une base de 0, tout test impliquant cette compétence est automatiquement raté.</p>",
|
"notes": "",
|
||||||
"key": "magie",
|
"key": "magie",
|
||||||
"profileKey": "mystique",
|
"profileKey": "mystique",
|
||||||
"base": 0,
|
"base": 0,
|
||||||
@@ -344,8 +365,8 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Équivalent d'Érudition pour les sortilèges des rêvirines et des sangfous, ainsi que pour la récolte de fils de Songes ou de Cauchemar et l'affrontement du Néphertine.</p>",
|
"description": "",
|
||||||
"notes": "<p>Compétence fermée : avec une base de 0, tout test impliquant cette compétence est automatiquement raté.</p>",
|
"notes": "",
|
||||||
"key": "onirologie",
|
"key": "onirologie",
|
||||||
"profileKey": "mystique",
|
"profileKey": "mystique",
|
||||||
"base": 0,
|
"base": 0,
|
||||||
@@ -361,7 +382,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Permet de se cacher, de dissimuler un objet ou de se déplacer sans se faire repérer, souvent en opposition à Sens.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "discretion",
|
"key": "discretion",
|
||||||
"profileKey": "ombre",
|
"profileKey": "ombre",
|
||||||
@@ -378,7 +399,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Met un personnage à l'abri des tirs ou des coups, aide à se libérer de liens et couvre cascades, acrobaties et voltige périlleuse.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "esquive",
|
"key": "esquive",
|
||||||
"profileKey": "ombre",
|
"profileKey": "ombre",
|
||||||
@@ -395,7 +416,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Art de faire prendre les apparences pour la réalité : déguisement, faux documents, pickpocket et tours de passe-passe.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "subterfuge",
|
"key": "subterfuge",
|
||||||
"profileKey": "ombre",
|
"profileKey": "ombre",
|
||||||
@@ -412,8 +433,8 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Regroupe les connaissances intellectuelles, leurs théories, leurs pratiques et leur histoire. Le domaine Lettres couvre la lecture, l'écriture et la recherche documentaire.</p>",
|
"description": "",
|
||||||
"notes": "<p>Compétence fermée et à domaines : le nombre de domaines maîtrisés est égal à la base.</p>",
|
"notes": "",
|
||||||
"key": "erudition",
|
"key": "erudition",
|
||||||
"profileKey": "savant",
|
"profileKey": "savant",
|
||||||
"base": 0,
|
"base": 0,
|
||||||
@@ -421,7 +442,17 @@
|
|||||||
"domainSkill": true,
|
"domainSkill": true,
|
||||||
"domains": [],
|
"domains": [],
|
||||||
"fixedDomains": [],
|
"fixedDomains": [],
|
||||||
"exampleDomains": ["Catholicisme", "Culte de Dame Nature", "Géographie", "Histoire", "Judaïsme", "Légendes", "Lettres", "Protestantisme", "Terra Incognita"]
|
"exampleDomains": [
|
||||||
|
"Catholicisme",
|
||||||
|
"Culte de Dame Nature",
|
||||||
|
"Géographie",
|
||||||
|
"Histoire",
|
||||||
|
"Judaïsme",
|
||||||
|
"Légendes",
|
||||||
|
"Lettres",
|
||||||
|
"Protestantisme",
|
||||||
|
"Terra Incognita"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -429,8 +460,8 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Rassemble les facultés de parler, traduire et contextualiser une ou plusieurs langues. Elle limite aussi les autres compétences dès qu'elles s'appliquent à un texte ou discours dans une langue connue.</p>",
|
"description": "",
|
||||||
"notes": "<p>Compétence fermée et à domaines : chaque langue est un domaine distinct, et le personnage est illettré par défaut hors domaine Lettres/formation appropriée.</p>",
|
"notes": "",
|
||||||
"key": "langues",
|
"key": "langues",
|
||||||
"profileKey": "savant",
|
"profileKey": "savant",
|
||||||
"base": 0,
|
"base": 0,
|
||||||
@@ -438,7 +469,15 @@
|
|||||||
"domainSkill": true,
|
"domainSkill": true,
|
||||||
"domains": [],
|
"domains": [],
|
||||||
"fixedDomains": [],
|
"fixedDomains": [],
|
||||||
"exampleDomains": ["Chimérique", "Jargon des likias", "Latin", "Lutin", "Oc", "Vieux lutin", "Velu nuton"]
|
"exampleDomains": [
|
||||||
|
"Chimérique",
|
||||||
|
"Jargon des likias",
|
||||||
|
"Latin",
|
||||||
|
"Lutin",
|
||||||
|
"Oc",
|
||||||
|
"Vieux lutin",
|
||||||
|
"Velu nuton"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -446,7 +485,7 @@
|
|||||||
"type": "competence",
|
"type": "competence",
|
||||||
"img": "icons/svg/book.svg",
|
"img": "icons/svg/book.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Science de la définition d'objectifs et des moyens pour les atteindre. Elle sert à planifier une action complexe et à comprendre les buts d'une organisation ou d'un adversaire.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"key": "strategie",
|
"key": "strategie",
|
||||||
"profileKey": "savant",
|
"profileKey": "savant",
|
||||||
|
|||||||
@@ -1,12 +1,172 @@
|
|||||||
[
|
[
|
||||||
{ "name": "Bougie de géant", "type": "equipement", "img": "icons/svg/chest.svg", "system": { "description": "<p>Source de lumière simple à planter sur une pique.</p>", "category": "voyage", "quantity": 1, "price": 180, "bonus": "", "usage": "Éclairage", "lifespan": "", "equipped": false, "consumable": true } },
|
{
|
||||||
{ "name": "Dé à coudre en acier", "type": "equipement", "img": "icons/svg/chest.svg", "system": { "description": "<p>Brasero miniature portable utilisé sans laisser de trace de campement.</p>", "category": "voyage", "quantity": 1, "price": 15, "bonus": "", "usage": "Campement", "lifespan": "", "equipped": false, "consumable": false } },
|
"name": "Bougie de géant",
|
||||||
{ "name": "Lampe à fée des nuits", "type": "equipement", "img": "icons/svg/chest.svg", "system": { "description": "<p>Lampe froide alimentée par une ou plusieurs fées des nuits captives.</p>", "category": "voyage", "quantity": 1, "price": 360, "bonus": "", "usage": "Éclairage", "lifespan": "Quelques mois", "equipped": false, "consumable": true } },
|
"type": "equipement",
|
||||||
{ "name": "Corde", "type": "equipement", "img": "icons/svg/chest.svg", "system": { "description": "<p>Segment de corde de 50 à 70 cm prélevé sur les cordages des géants.</p>", "category": "voyage", "quantity": 1, "price": 3, "bonus": "", "usage": "Escalade", "lifespan": "", "equipped": false, "consumable": false } },
|
"img": "icons/svg/chest.svg",
|
||||||
{ "name": "Grappin", "type": "equipement", "img": "icons/svg/chest.svg", "system": { "description": "<p>Souvent façonné dans un hameçon ou une broche de géant. Peut aussi servir d'arme de corps à corps.</p>", "category": "voyage", "quantity": 1, "price": 6, "bonus": "", "usage": "Escalade", "lifespan": "", "equipped": false, "consumable": false } },
|
"system": {
|
||||||
{ "name": "Nécessaire d'entretien d'armes", "type": "equipement", "img": "icons/svg/chest.svg", "system": { "description": "<p>Sert à l'affûtage et à la prévention de la corrosion des armes.</p>", "category": "outil", "quantity": 1, "price": 0, "bonus": "", "usage": "Maintenance", "lifespan": "", "equipped": false, "consumable": false } },
|
"description": "",
|
||||||
{ "name": "Nécessaire à écriture / dessins", "type": "equipement", "img": "icons/svg/chest.svg", "system": { "description": "<p>Encre, plume et supports de fortune pour écrire, dessiner ou cartographier.</p>", "category": "outil", "quantity": 1, "price": 0, "bonus": "", "usage": "Écriture", "lifespan": "", "equipped": false, "consumable": false } },
|
"category": "voyage",
|
||||||
{ "name": "Piolet", "type": "equipement", "img": "icons/svg/chest.svg", "system": { "description": "<p>Outil d'ascension accordant un bonus de +3 aux escalades adaptées.</p>", "category": "voyage", "quantity": 1, "price": 60, "bonus": "+3 escalade", "usage": "Ascension", "lifespan": "", "equipped": false, "consumable": false } },
|
"quantity": 1,
|
||||||
{ "name": "Rikilin", "type": "equipement", "img": "icons/svg/chest.svg", "system": { "description": "<p>Chaussures de marche munies de crampons métalliques pour l'escalade.</p>", "category": "voyage", "quantity": 1, "price": 0, "bonus": "+3 escalade", "usage": "Ascension", "lifespan": "", "equipped": false, "consumable": false } },
|
"price": 180,
|
||||||
{ "name": "Trousse de premiers soins", "type": "equipement", "img": "icons/svg/chest.svg", "system": { "description": "<p>Bandages, plantes désinfectantes et fioles de soins pour les premiers secours.</p>", "category": "voyage", "quantity": 1, "price": 0, "bonus": "", "usage": "Soins", "lifespan": "", "equipped": false, "consumable": true } }
|
"bonus": "",
|
||||||
|
"usage": "Éclairage",
|
||||||
|
"lifespan": "",
|
||||||
|
"equipped": false,
|
||||||
|
"consumable": true,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Dé à coudre en acier",
|
||||||
|
"type": "equipement",
|
||||||
|
"img": "icons/svg/chest.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"category": "voyage",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 15,
|
||||||
|
"bonus": "",
|
||||||
|
"usage": "Campement",
|
||||||
|
"lifespan": "",
|
||||||
|
"equipped": false,
|
||||||
|
"consumable": false,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lampe à fée des nuits",
|
||||||
|
"type": "equipement",
|
||||||
|
"img": "icons/svg/chest.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"category": "voyage",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 360,
|
||||||
|
"bonus": "",
|
||||||
|
"usage": "Éclairage",
|
||||||
|
"lifespan": "Quelques mois",
|
||||||
|
"equipped": false,
|
||||||
|
"consumable": true,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Corde",
|
||||||
|
"type": "equipement",
|
||||||
|
"img": "icons/svg/chest.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"category": "voyage",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 3,
|
||||||
|
"bonus": "",
|
||||||
|
"usage": "Escalade",
|
||||||
|
"lifespan": "",
|
||||||
|
"equipped": false,
|
||||||
|
"consumable": false,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Grappin",
|
||||||
|
"type": "equipement",
|
||||||
|
"img": "icons/svg/chest.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"category": "voyage",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 6,
|
||||||
|
"bonus": "",
|
||||||
|
"usage": "Escalade",
|
||||||
|
"lifespan": "",
|
||||||
|
"equipped": false,
|
||||||
|
"consumable": false,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nécessaire d'entretien d'armes",
|
||||||
|
"type": "equipement",
|
||||||
|
"img": "icons/svg/chest.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"category": "outil",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 0,
|
||||||
|
"bonus": "",
|
||||||
|
"usage": "Maintenance",
|
||||||
|
"lifespan": "",
|
||||||
|
"equipped": false,
|
||||||
|
"consumable": false,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nécessaire à écriture / dessins",
|
||||||
|
"type": "equipement",
|
||||||
|
"img": "icons/svg/chest.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"category": "outil",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 0,
|
||||||
|
"bonus": "",
|
||||||
|
"usage": "Écriture",
|
||||||
|
"lifespan": "",
|
||||||
|
"equipped": false,
|
||||||
|
"consumable": false,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Piolet",
|
||||||
|
"type": "equipement",
|
||||||
|
"img": "icons/svg/chest.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"category": "voyage",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 60,
|
||||||
|
"bonus": "+3 escalade",
|
||||||
|
"usage": "Ascension",
|
||||||
|
"lifespan": "",
|
||||||
|
"equipped": false,
|
||||||
|
"consumable": false,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rikilin",
|
||||||
|
"type": "equipement",
|
||||||
|
"img": "icons/svg/chest.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"category": "voyage",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 0,
|
||||||
|
"bonus": "+3 escalade",
|
||||||
|
"usage": "Ascension",
|
||||||
|
"lifespan": "",
|
||||||
|
"equipped": false,
|
||||||
|
"consumable": false,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Trousse de premiers soins",
|
||||||
|
"type": "equipement",
|
||||||
|
"img": "icons/svg/chest.svg",
|
||||||
|
"system": {
|
||||||
|
"description": "",
|
||||||
|
"category": "voyage",
|
||||||
|
"quantity": 1,
|
||||||
|
"price": 0,
|
||||||
|
"bonus": "",
|
||||||
|
"usage": "Soins",
|
||||||
|
"lifespan": "",
|
||||||
|
"equipped": false,
|
||||||
|
"consumable": true,
|
||||||
|
"notes": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Lampe inspirée des lanternes-tempête des géants. Elle diffuse une lumière froide sans chaleur grâce à une ou plusieurs fées des nuits capturées.</p>",
|
"description": "",
|
||||||
"notes": "<p>La lumière décroît à mesure que la créature enfermée dépérit.</p>",
|
"notes": "",
|
||||||
"category": "voyage",
|
"category": "voyage",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 360,
|
"price": 360,
|
||||||
@@ -21,7 +21,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Dé à coudre en acier de géant utilisé comme brasero portatif, pratique pour ne laisser presque aucune trace de campement.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "voyage",
|
"category": "voyage",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Hameçon, épingle à nourrice ou broche de géant affûtée servant à l'escalade et, au besoin, au combat rapproché.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "voyage",
|
"category": "voyage",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -55,7 +55,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Segment de corde de haute qualité prélevé sur les cordages des navires des géants.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "voyage",
|
"category": "voyage",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -72,7 +72,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Petite canne hérissée de piques, utile pour grimper sur les hauteurs du Giganti, dans les Drumes ou sur les poutres des maisons des géants.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "voyage",
|
"category": "voyage",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -89,8 +89,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Chaussures de marche à crampons métalliques conçues pour l'escalade de bois, de poutres ou de surfaces raides.</p>",
|
"description": "",
|
||||||
"notes": "<p>Elles sont lourdes et ne se portent en pratique que pour l'ascension.</p>",
|
"notes": "",
|
||||||
"category": "voyage",
|
"category": "voyage",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 0,
|
"price": 0,
|
||||||
@@ -106,7 +106,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Petite sacoche de secours contenant bandages, toiles d'araignée cicatrisantes, plantes désinfectantes et huiles essentielles contre les parasites.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "soin",
|
"category": "soin",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -123,7 +123,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Kit d'affûtage et de protection contre la corrosion, indispensable pour garder des armes fiables en Terra Incognita.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "survie",
|
"category": "survie",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -140,8 +140,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Encre, plume et supports d'écriture pour prendre des notes, dessiner ou cartographier.</p>",
|
"description": "",
|
||||||
"notes": "<p>Le livre le décrit comme un peu d'encre dans une fiole bien fermée, des parchemins et parfois du papier volé aux géants.</p>",
|
"notes": "",
|
||||||
"category": "ecriture",
|
"category": "ecriture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 0,
|
"price": 0,
|
||||||
@@ -157,8 +157,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Bougie de géant, souvent plantée sur une lance ou une pique pour éclairer les voyages nocturnes.</p>",
|
"description": "",
|
||||||
"notes": "<p>Le livre insiste sur le risque d'incendie.</p>",
|
"notes": "",
|
||||||
"category": "butin",
|
"category": "butin",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 180,
|
"price": 180,
|
||||||
@@ -174,7 +174,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Source de lumière plus modeste que la bougie de géant, mais toujours utile en expédition.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "butin",
|
"category": "butin",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -191,7 +191,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Dérobé aux géants, ce dé à coudre peut être revendu, détourné ou recyclé en brasero.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "butin",
|
"category": "butin",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -208,7 +208,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Bouton de géant récupéré comme bien de valeur, matériau ou future rondache improvisée.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "butin",
|
"category": "butin",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -225,7 +225,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Lot de bons cordages prélevés sur les navires des géants.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "butin",
|
"category": "butin",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -242,7 +242,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Éclats de miroir géant, utiles autant pour l'artisanat que pour certains tours de lumière ou de repérage.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "butin",
|
"category": "butin",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -259,7 +259,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Éclats de verre géant récupérés pour la fabrication, le troc ou certaines improvisations dangereuses.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "butin",
|
"category": "butin",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -276,7 +276,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Morceaux de textile précieux dérobés aux géants, recherchés pour leur finesse et leur rareté.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "butin",
|
"category": "butin",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -293,7 +293,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Coupons de tissu géant particulièrement utiles pour la couture, le troc ou la fabrication d'abris improvisés.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "butin",
|
"category": "butin",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -310,7 +310,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Supports d'écriture volés aux géants, rares et précieux pour qui veut tenir journal, archives ou cartes.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "ecriture",
|
"category": "ecriture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -327,7 +327,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Grande plume de géant pouvant servir à l'écriture, à l'apparat ou à certains bricolages.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "ecriture",
|
"category": "ecriture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -344,7 +344,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Encrier dérobé aux géants, précieux pour l'écriture et la cartographie.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "ecriture",
|
"category": "ecriture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -361,7 +361,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Bijou géant d'une valeur exceptionnelle dans l'économie du Petit Peuple.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "butin",
|
"category": "butin",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -378,7 +378,7 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Parure géante extrêmement recherchée, autant comme richesse portable que comme matériau précieux.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"category": "butin",
|
"category": "butin",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
@@ -395,8 +395,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Monture dressée utilisable par le Petit Peuple selon la table des prix.</p>",
|
"description": "",
|
||||||
"notes": "<p>Pré-créée comme équipement faute de type d'item dédié aux montures.</p>",
|
"notes": "",
|
||||||
"category": "monture",
|
"category": "monture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 5400,
|
"price": 5400,
|
||||||
@@ -412,8 +412,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Monture dressée listée dans la table des prix du chapitre 5.</p>",
|
"description": "",
|
||||||
"notes": "<p>Pré-créée comme équipement faute de type d'item dédié aux montures.</p>",
|
"notes": "",
|
||||||
"category": "monture",
|
"category": "monture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 118000,
|
"price": 118000,
|
||||||
@@ -429,8 +429,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Monture dressée volante de la table des prix.</p>",
|
"description": "",
|
||||||
"notes": "<p>Pré-créée comme équipement faute de type d'item dédié aux montures.</p>",
|
"notes": "",
|
||||||
"category": "monture",
|
"category": "monture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 5400,
|
"price": 5400,
|
||||||
@@ -446,8 +446,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Oiseau dressé mentionné dans la table des montures du livre de base.</p>",
|
"description": "",
|
||||||
"notes": "<p>Pré-créé comme équipement faute de type d'item dédié aux montures.</p>",
|
"notes": "",
|
||||||
"category": "monture",
|
"category": "monture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 6300,
|
"price": 6300,
|
||||||
@@ -463,8 +463,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Amphibien dressé prévu par la table des montures.</p>",
|
"description": "",
|
||||||
"notes": "<p>Pré-créé comme équipement faute de type d'item dédié aux montures.</p>",
|
"notes": "",
|
||||||
"category": "monture",
|
"category": "monture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 4500,
|
"price": 4500,
|
||||||
@@ -480,8 +480,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Monture dressée listée dans le chapitre des prix.</p>",
|
"description": "",
|
||||||
"notes": "<p>Pré-créée comme équipement faute de type d'item dédié aux montures.</p>",
|
"notes": "",
|
||||||
"category": "monture",
|
"category": "monture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 7200,
|
"price": 7200,
|
||||||
@@ -497,8 +497,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Petite monture nerveuse mentionnée dans la table des montures dressées.</p>",
|
"description": "",
|
||||||
"notes": "<p>Pré-créée comme équipement faute de type d'item dédié aux montures.</p>",
|
"notes": "",
|
||||||
"category": "monture",
|
"category": "monture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 6300,
|
"price": 6300,
|
||||||
@@ -514,8 +514,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Monture dressée nocturne du chapitre 5.</p>",
|
"description": "",
|
||||||
"notes": "<p>Pré-créée comme équipement faute de type d'item dédié aux montures.</p>",
|
"notes": "",
|
||||||
"category": "monture",
|
"category": "monture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 3600,
|
"price": 3600,
|
||||||
@@ -531,8 +531,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Monture dressée reptilienne listée dans les prix.</p>",
|
"description": "",
|
||||||
"notes": "<p>Pré-créée comme équipement faute de type d'item dédié aux montures.</p>",
|
"notes": "",
|
||||||
"category": "monture",
|
"category": "monture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 4500,
|
"price": 4500,
|
||||||
@@ -548,8 +548,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Petit oiseau dressé, peu coûteux relativement aux autres montures du tableau.</p>",
|
"description": "",
|
||||||
"notes": "<p>Pré-créé comme équipement faute de type d'item dédié aux montures.</p>",
|
"notes": "",
|
||||||
"category": "monture",
|
"category": "monture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 2700,
|
"price": 2700,
|
||||||
@@ -565,8 +565,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Monture dressée fréquente ou du moins familière dans la table du livre.</p>",
|
"description": "",
|
||||||
"notes": "<p>Pré-créée comme équipement faute de type d'item dédié aux montures.</p>",
|
"notes": "",
|
||||||
"category": "monture",
|
"category": "monture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 5400,
|
"price": 5400,
|
||||||
@@ -582,8 +582,8 @@
|
|||||||
"type": "equipement",
|
"type": "equipement",
|
||||||
"img": "icons/svg/chest.svg",
|
"img": "icons/svg/chest.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Plus petite monture dressée de la table des prix.</p>",
|
"description": "",
|
||||||
"notes": "<p>Pré-créée comme équipement faute de type d'item dédié aux montures.</p>",
|
"notes": "",
|
||||||
"category": "monture",
|
"category": "monture",
|
||||||
"quantity": 1,
|
"quantity": 1,
|
||||||
"price": 900,
|
"price": 900,
|
||||||
|
|||||||
@@ -4,25 +4,91 @@
|
|||||||
"type": "metier",
|
"type": "metier",
|
||||||
"img": "icons/svg/upgrade.svg",
|
"img": "icons/svg/upgrade.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Puissant magicien du Petit Peuple et acteur majeur de sa survie en Terra Incognita.</p>",
|
"description": "",
|
||||||
"specialRules": "<p>Possède 3 sortilèges de magie de Songes et 3 de Cauchemar à la création.</p>",
|
"specialRules": "",
|
||||||
"roleplayNotes": "<p>Le mage des Songes est une figure importante et souvent respectée, dépositaire d'une magie utile à la survie collective.</p>",
|
"roleplayNotes": "",
|
||||||
"skillBonuses": [
|
"skillBonuses": [
|
||||||
{ "key": "magie", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
{
|
||||||
{ "key": "intellect", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"key": "magie",
|
||||||
{ "key": "erudition", "alternativeKeys": [], "base": 1, "domainsGranted": ["Lettres"], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"alternativeKeys": [],
|
||||||
{ "key": "volonte", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" }
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "intellect",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "erudition",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [
|
||||||
|
"Lettres"
|
||||||
|
],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "volonte",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"startingEquipment": [
|
"startingEquipment": [
|
||||||
{ "name": "Sphère de verre contenant 1 fil de Songes", "type": "equipement", "quantity": 3, "details": "", "choiceText": "", "ecorces": 0 },
|
{
|
||||||
{ "name": "Arme", "type": "arme", "quantity": 1, "details": "", "choiceText": "Arme au choix", "ecorces": 0 },
|
"name": "Sphère de verre contenant 1 fil de Songes",
|
||||||
{ "name": "Bourse", "type": "equipement", "quantity": 1, "details": "", "choiceText": "", "ecorces": 180 }
|
"type": "equipement",
|
||||||
|
"quantity": 3,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Arme",
|
||||||
|
"type": "arme",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "Arme au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bourse",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 180
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"spellGrants": [
|
"spellGrants": [
|
||||||
{ "tradition": "magie", "skillKey": "magie", "polarity": "songes", "amount": 3 },
|
{
|
||||||
{ "tradition": "magie", "skillKey": "magie", "polarity": "cauchemar", "amount": 3 }
|
"tradition": "magie",
|
||||||
|
"skillKey": "magie",
|
||||||
|
"polarity": "songes",
|
||||||
|
"amount": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tradition": "magie",
|
||||||
|
"skillKey": "magie",
|
||||||
|
"polarity": "cauchemar",
|
||||||
|
"amount": 3
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"revenues": { "beginner": 30, "intermediate": 90, "expert": 450 }
|
"revenues": {
|
||||||
|
"beginner": 30,
|
||||||
|
"intermediate": 90,
|
||||||
|
"expert": 450
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -30,26 +96,97 @@
|
|||||||
"type": "metier",
|
"type": "metier",
|
||||||
"img": "icons/svg/upgrade.svg",
|
"img": "icons/svg/upgrade.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Guerrier des Songes chargé de récolter les rêves des géants.</p>",
|
"description": "",
|
||||||
"specialRules": "<p>Connaît 1 sortilège d'Onirologie de Songes et 1 de Cauchemar.</p>",
|
"specialRules": "",
|
||||||
"roleplayNotes": "<p>Les rêvirines sont des spécialistes des dormeurs géants et des filaments de Songe, à la fois magiciens et prédateurs de rêves.</p>",
|
"roleplayNotes": "",
|
||||||
"skillBonuses": [
|
"skillBonuses": [
|
||||||
{ "key": "onirologie", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
{
|
||||||
{ "key": "volonte", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"key": "onirologie",
|
||||||
{ "key": "magie", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"alternativeKeys": [],
|
||||||
{ "key": "endurance", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" }
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "volonte",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "magie",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "endurance",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"startingEquipment": [
|
"startingEquipment": [
|
||||||
{ "name": "Sphère de verre contenant 1 fil de Songes", "type": "equipement", "quantity": 1, "details": "", "choiceText": "", "ecorces": 0 },
|
{
|
||||||
{ "name": "Arme", "type": "arme", "quantity": 1, "details": "", "choiceText": "Arme au choix", "ecorces": 0 },
|
"name": "Sphère de verre contenant 1 fil de Songes",
|
||||||
{ "name": "Corde solide et très fine", "type": "equipement", "quantity": 1, "details": "Environ 3 mètres", "choiceText": "", "ecorces": 0 },
|
"type": "equipement",
|
||||||
{ "name": "Bourse", "type": "equipement", "quantity": 1, "details": "", "choiceText": "", "ecorces": 180 }
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Arme",
|
||||||
|
"type": "arme",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "Arme au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Corde solide et très fine",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "Environ 3 mètres",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bourse",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 180
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"spellGrants": [
|
"spellGrants": [
|
||||||
{ "tradition": "onirologie", "skillKey": "onirologie", "polarity": "songes", "amount": 1 },
|
{
|
||||||
{ "tradition": "onirologie", "skillKey": "onirologie", "polarity": "cauchemar", "amount": 1 }
|
"tradition": "onirologie",
|
||||||
|
"skillKey": "onirologie",
|
||||||
|
"polarity": "songes",
|
||||||
|
"amount": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tradition": "onirologie",
|
||||||
|
"skillKey": "onirologie",
|
||||||
|
"polarity": "cauchemar",
|
||||||
|
"amount": 1
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"revenues": { "beginner": 30, "intermediate": 100, "expert": 300 }
|
"revenues": {
|
||||||
|
"beginner": 30,
|
||||||
|
"intermediate": 100,
|
||||||
|
"expert": 300
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -57,23 +194,84 @@
|
|||||||
"type": "metier",
|
"type": "metier",
|
||||||
"img": "icons/svg/upgrade.svg",
|
"img": "icons/svg/upgrade.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Dernier représentant d'un code d'honneur hérité d'Edenia.</p>",
|
"description": "",
|
||||||
"specialRules": "",
|
"specialRules": "",
|
||||||
"roleplayNotes": "<p>Les chevaliers errants vivent selon un idéal ancien, souvent moqué mais encore redoutable au combat.</p>",
|
"roleplayNotes": "",
|
||||||
"skillBonuses": [
|
"skillBonuses": [
|
||||||
{ "key": "melee", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
{
|
||||||
{ "key": "montures", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"key": "melee",
|
||||||
{ "key": "commandement", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"alternativeKeys": [],
|
||||||
{ "key": "volonte", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" }
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "montures",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "commandement",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "volonte",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"startingEquipment": [
|
"startingEquipment": [
|
||||||
{ "name": "Arme", "type": "arme", "quantity": 2, "details": "", "choiceText": "2 armes au choix", "ecorces": 0 },
|
{
|
||||||
{ "name": "Armure", "type": "armure", "quantity": 1, "details": "", "choiceText": "Armure au choix", "ecorces": 0 },
|
"name": "Arme",
|
||||||
{ "name": "Monture", "type": "equipement", "quantity": 1, "details": "", "choiceText": "Monture au choix", "ecorces": 0 },
|
"type": "arme",
|
||||||
{ "name": "Bourse", "type": "equipement", "quantity": 1, "details": "", "choiceText": "", "ecorces": 6 }
|
"quantity": 2,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "2 armes au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Armure",
|
||||||
|
"type": "armure",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "Armure au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Monture",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "Monture au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bourse",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 6
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"spellGrants": [],
|
"spellGrants": [],
|
||||||
"revenues": { "beginner": 3, "intermediate": 12, "expert": 30 }
|
"revenues": {
|
||||||
|
"beginner": 3,
|
||||||
|
"intermediate": 12,
|
||||||
|
"expert": 30
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -81,22 +279,76 @@
|
|||||||
"type": "metier",
|
"type": "metier",
|
||||||
"img": "icons/svg/upgrade.svg",
|
"img": "icons/svg/upgrade.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Combattant de métier, formé à l'obéissance et aux conflits permanents de la Terra.</p>",
|
"description": "",
|
||||||
"specialRules": "",
|
"specialRules": "",
|
||||||
"roleplayNotes": "<p>Les mercenaires servent dans les grinides et vivent dans une logique de guerre, de hiérarchie et de solde.</p>",
|
"roleplayNotes": "",
|
||||||
"skillBonuses": [
|
"skillBonuses": [
|
||||||
{ "key": "melee", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
{
|
||||||
{ "key": "rapidite", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"key": "melee",
|
||||||
{ "key": "athletisme", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"alternativeKeys": [],
|
||||||
{ "key": "soins", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" }
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "rapidite",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "athletisme",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "soins",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"startingEquipment": [
|
"startingEquipment": [
|
||||||
{ "name": "Arme", "type": "arme", "quantity": 2, "details": "", "choiceText": "2 armes au choix", "ecorces": 0 },
|
{
|
||||||
{ "name": "Armure", "type": "armure", "quantity": 1, "details": "", "choiceText": "Armure au choix", "ecorces": 0 },
|
"name": "Arme",
|
||||||
{ "name": "Bourse", "type": "equipement", "quantity": 1, "details": "", "choiceText": "", "ecorces": 18 }
|
"type": "arme",
|
||||||
|
"quantity": 2,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "2 armes au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Armure",
|
||||||
|
"type": "armure",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "Armure au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bourse",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 18
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"spellGrants": [],
|
"spellGrants": [],
|
||||||
"revenues": { "beginner": 9, "intermediate": 30, "expert": 180 }
|
"revenues": {
|
||||||
|
"beginner": 9,
|
||||||
|
"intermediate": 30,
|
||||||
|
"expert": 180
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -104,22 +356,78 @@
|
|||||||
"type": "metier",
|
"type": "metier",
|
||||||
"img": "icons/svg/upgrade.svg",
|
"img": "icons/svg/upgrade.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Voyageur, négociant et éclaireur des routes de la Terra Incognita.</p>",
|
"description": "",
|
||||||
"specialRules": "",
|
"specialRules": "",
|
||||||
"roleplayNotes": "<p>Les explorateurs-marchands parcourent sans cesse les routes dangereuses pour ravitailler le Petit Peuple.</p>",
|
"roleplayNotes": "",
|
||||||
"skillBonuses": [
|
"skillBonuses": [
|
||||||
{ "key": "survie", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
{
|
||||||
{ "key": "seduction", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"key": "survie",
|
||||||
{ "key": "artisanat", "alternativeKeys": ["arts"], "base": 1, "domainsGranted": [], "domainsToChoose": 1, "domainsChoiceText": "domaine au choix dans la compétence retenue" },
|
"alternativeKeys": [],
|
||||||
{ "key": "montures", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" }
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "seduction",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "artisanat",
|
||||||
|
"alternativeKeys": [
|
||||||
|
"arts"
|
||||||
|
],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 1,
|
||||||
|
"domainsChoiceText": "domaine au choix dans la compétence retenue"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "montures",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"startingEquipment": [
|
"startingEquipment": [
|
||||||
{ "name": "Arme", "type": "arme", "quantity": 1, "details": "", "choiceText": "Arme au choix", "ecorces": 0 },
|
{
|
||||||
{ "name": "Bel objet", "type": "equipement", "quantity": 1, "details": "", "choiceText": "Bel objet au choix", "ecorces": 0 },
|
"name": "Arme",
|
||||||
{ "name": "Bourse", "type": "equipement", "quantity": 1, "details": "", "choiceText": "", "ecorces": 72 }
|
"type": "arme",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "Arme au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bel objet",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "Bel objet au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bourse",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 72
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"spellGrants": [],
|
"spellGrants": [],
|
||||||
"revenues": { "beginner": 18, "intermediate": 60, "expert": 360 }
|
"revenues": {
|
||||||
|
"beginner": 18,
|
||||||
|
"intermediate": 60,
|
||||||
|
"expert": 360
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -127,23 +435,90 @@
|
|||||||
"type": "metier",
|
"type": "metier",
|
||||||
"img": "icons/svg/upgrade.svg",
|
"img": "icons/svg/upgrade.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Observateur curieux, collectionneur de cartes et d'usages des géants.</p>",
|
"description": "",
|
||||||
"specialRules": "",
|
"specialRules": "",
|
||||||
"roleplayNotes": "<p>Le cartographe observe les géants, leurs lieux et leurs bibliothèques avec une curiosité méthodique.</p>",
|
"roleplayNotes": "",
|
||||||
"skillBonuses": [
|
"skillBonuses": [
|
||||||
{ "key": "erudition", "alternativeKeys": [], "base": 3, "domainsGranted": ["Géants", "Lettres", "Terra Incognita"], "domainsToChoose": 0, "domainsChoiceText": "" },
|
{
|
||||||
{ "key": "survie", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"key": "erudition",
|
||||||
{ "key": "artisanat", "alternativeKeys": [], "base": 1, "domainsGranted": ["Cartographie"], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"alternativeKeys": [],
|
||||||
{ "key": "endurance", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" }
|
"base": 3,
|
||||||
|
"domainsGranted": [
|
||||||
|
"Géants",
|
||||||
|
"Lettres",
|
||||||
|
"Terra Incognita"
|
||||||
|
],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "survie",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "artisanat",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [
|
||||||
|
"Cartographie"
|
||||||
|
],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "endurance",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"startingEquipment": [
|
"startingEquipment": [
|
||||||
{ "name": "Boîte de cartographe", "type": "equipement", "quantity": 1, "details": "2 plumes, 2 fioles d'encre, 1 fil mesureur et 5 parchemins vierges", "choiceText": "", "ecorces": 0 },
|
{
|
||||||
{ "name": "Arme", "type": "arme", "quantity": 1, "details": "", "choiceText": "Arme au choix", "ecorces": 0 },
|
"name": "Boîte de cartographe",
|
||||||
{ "name": "Objet géant", "type": "equipement", "quantity": 1, "details": "", "choiceText": "Objet géant au choix", "ecorces": 0 },
|
"type": "equipement",
|
||||||
{ "name": "Bourse", "type": "equipement", "quantity": 1, "details": "", "choiceText": "", "ecorces": 18 }
|
"quantity": 1,
|
||||||
|
"details": "2 plumes, 2 fioles d'encre, 1 fil mesureur et 5 parchemins vierges",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Arme",
|
||||||
|
"type": "arme",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "Arme au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Objet géant",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "Objet géant au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bourse",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 18
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"spellGrants": [],
|
"spellGrants": [],
|
||||||
"revenues": { "beginner": 9, "intermediate": 30, "expert": 180 }
|
"revenues": {
|
||||||
|
"beginner": 9,
|
||||||
|
"intermediate": 30,
|
||||||
|
"expert": 180
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -151,25 +526,89 @@
|
|||||||
"type": "metier",
|
"type": "metier",
|
||||||
"img": "icons/svg/upgrade.svg",
|
"img": "icons/svg/upgrade.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Conteur, comédien ou ménestrel qui entretient le mythe d'Edenia.</p>",
|
"description": "",
|
||||||
"specialRules": "<p>Connaît 3 sortilèges de Chimérisme de Songes et 3 de Cauchemar.</p>",
|
"specialRules": "",
|
||||||
"roleplayNotes": "<p>Les doux rêveurs font vivre le récit de l'Exil, de Syllistine et des exploits des compagnies dans l'imaginaire du Petit Peuple.</p>",
|
"roleplayNotes": "",
|
||||||
"skillBonuses": [
|
"skillBonuses": [
|
||||||
{ "key": "chimerisme", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
{
|
||||||
{ "key": "seduction", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"key": "chimerisme",
|
||||||
{ "key": "arts", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 1, "domainsChoiceText": "domaine d'Arts au choix" },
|
"alternativeKeys": [],
|
||||||
{ "key": "magie", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" }
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "seduction",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "arts",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 1,
|
||||||
|
"domainsChoiceText": "domaine d'Arts au choix"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "magie",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"startingEquipment": [
|
"startingEquipment": [
|
||||||
{ "name": "Instrument de musique", "type": "equipement", "quantity": 1, "details": "", "choiceText": "", "ecorces": 0 },
|
{
|
||||||
{ "name": "Arme", "type": "arme", "quantity": 1, "details": "", "choiceText": "Arme au choix", "ecorces": 0 },
|
"name": "Instrument de musique",
|
||||||
{ "name": "Bourse", "type": "equipement", "quantity": 1, "details": "", "choiceText": "", "ecorces": 12 }
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Arme",
|
||||||
|
"type": "arme",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "Arme au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bourse",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 12
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"spellGrants": [
|
"spellGrants": [
|
||||||
{ "tradition": "chimerisme", "skillKey": "chimerisme", "polarity": "songes", "amount": 3 },
|
{
|
||||||
{ "tradition": "chimerisme", "skillKey": "chimerisme", "polarity": "cauchemar", "amount": 3 }
|
"tradition": "chimerisme",
|
||||||
|
"skillKey": "chimerisme",
|
||||||
|
"polarity": "songes",
|
||||||
|
"amount": 3
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"tradition": "chimerisme",
|
||||||
|
"skillKey": "chimerisme",
|
||||||
|
"polarity": "cauchemar",
|
||||||
|
"amount": 3
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"revenues": { "beginner": 6, "intermediate": 30, "expert": 180 }
|
"revenues": {
|
||||||
|
"beginner": 6,
|
||||||
|
"intermediate": 30,
|
||||||
|
"expert": 180
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -177,22 +616,76 @@
|
|||||||
"type": "metier",
|
"type": "metier",
|
||||||
"img": "icons/svg/upgrade.svg",
|
"img": "icons/svg/upgrade.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Récupérateur audacieux des biens des géants.</p>",
|
"description": "",
|
||||||
"specialRules": "",
|
"specialRules": "",
|
||||||
"roleplayNotes": "<p>Les trouvetouts vivent du risque, de l'intrusion et du pillage utile des demeures géantes.</p>",
|
"roleplayNotes": "",
|
||||||
"skillBonuses": [
|
"skillBonuses": [
|
||||||
{ "key": "discretion", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
{
|
||||||
{ "key": "athletisme", "alternativeKeys": [], "base": 3, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"key": "discretion",
|
||||||
{ "key": "force", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" },
|
"alternativeKeys": [],
|
||||||
{ "key": "rapidite", "alternativeKeys": [], "base": 1, "domainsGranted": [], "domainsToChoose": 0, "domainsChoiceText": "" }
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "athletisme",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 3,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "force",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "rapidite",
|
||||||
|
"alternativeKeys": [],
|
||||||
|
"base": 1,
|
||||||
|
"domainsGranted": [],
|
||||||
|
"domainsToChoose": 0,
|
||||||
|
"domainsChoiceText": ""
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"startingEquipment": [
|
"startingEquipment": [
|
||||||
{ "name": "Arme", "type": "arme", "quantity": 1, "details": "", "choiceText": "Arme au choix", "ecorces": 0 },
|
{
|
||||||
{ "name": "Objet de survie", "type": "equipement", "quantity": 1, "details": "", "choiceText": "Objet de survie au choix", "ecorces": 0 },
|
"name": "Arme",
|
||||||
{ "name": "Bourse", "type": "equipement", "quantity": 1, "details": "", "choiceText": "", "ecorces": 60 }
|
"type": "arme",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "Arme au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Objet de survie",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "Objet de survie au choix",
|
||||||
|
"ecorces": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bourse",
|
||||||
|
"type": "equipement",
|
||||||
|
"quantity": 1,
|
||||||
|
"details": "",
|
||||||
|
"choiceText": "",
|
||||||
|
"ecorces": 60
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"spellGrants": [],
|
"spellGrants": [],
|
||||||
"revenues": { "beginner": 30, "intermediate": 90, "expert": 180 }
|
"revenues": {
|
||||||
|
"beginner": 30,
|
||||||
|
"intermediate": 90,
|
||||||
|
"expert": 180
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -4,11 +4,11 @@
|
|||||||
"type": "pouvoircompagnie",
|
"type": "pouvoircompagnie",
|
||||||
"img": "icons/svg/aura.svg",
|
"img": "icons/svg/aura.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Pouvoir de compagnie offensif favorisant les assauts du groupe.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"scope": "compagnie",
|
"scope": "compagnie",
|
||||||
"effectMode": "passif",
|
"effectMode": "passif",
|
||||||
"ruleText": "<p>Les dégâts des attaques au corps à corps et en mêlée augmentent de 1 point.</p>",
|
"ruleText": "",
|
||||||
"limitedUses": "",
|
"limitedUses": "",
|
||||||
"resourceImpact": "",
|
"resourceImpact": "",
|
||||||
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
||||||
@@ -21,11 +21,11 @@
|
|||||||
"type": "pouvoircompagnie",
|
"type": "pouvoircompagnie",
|
||||||
"img": "icons/svg/aura.svg",
|
"img": "icons/svg/aura.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Pouvoir de compagnie axé sur la récupération de Songes.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"scope": "compagnie",
|
"scope": "compagnie",
|
||||||
"effectMode": "passif",
|
"effectMode": "passif",
|
||||||
"ruleText": "<p>À l'aube, les Oubliés de la compagnie récupèrent 2 points de Songes au lieu de 1 seul.</p>",
|
"ruleText": "",
|
||||||
"limitedUses": "",
|
"limitedUses": "",
|
||||||
"resourceImpact": "+1 point de Songes récupéré à l'aube",
|
"resourceImpact": "+1 point de Songes récupéré à l'aube",
|
||||||
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
||||||
@@ -38,11 +38,11 @@
|
|||||||
"type": "pouvoircompagnie",
|
"type": "pouvoircompagnie",
|
||||||
"img": "icons/svg/aura.svg",
|
"img": "icons/svg/aura.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Pouvoir de compagnie qui magnifie les doubles obtenus sur 2d12.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"scope": "compagnie",
|
"scope": "compagnie",
|
||||||
"effectMode": "passif",
|
"effectMode": "passif",
|
||||||
"ruleText": "<p>Lors d'un test réalisé avec 2d12, si les deux dés indiquent le même nombre, le résultat naturel est calculé en additionnant ces deux nombres, sauf sur deux 1 où le pouvoir reste sans effet.</p>",
|
"ruleText": "",
|
||||||
"limitedUses": "",
|
"limitedUses": "",
|
||||||
"resourceImpact": "",
|
"resourceImpact": "",
|
||||||
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
||||||
@@ -55,11 +55,11 @@
|
|||||||
"type": "pouvoircompagnie",
|
"type": "pouvoircompagnie",
|
||||||
"img": "icons/svg/aura.svg",
|
"img": "icons/svg/aura.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Pouvoir de compagnie qui récompense la concentration avant l'action.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"scope": "compagnie",
|
"scope": "compagnie",
|
||||||
"effectMode": "préparation",
|
"effectMode": "préparation",
|
||||||
"ruleText": "<p>Passer cinq secondes, soit un round en combat, à se concentrer avant un test de compétence permet d'augmenter de 1 le résultat final. Ce temps de concentration est une action unique réussie automatiquement.</p>",
|
"ruleText": "",
|
||||||
"limitedUses": "",
|
"limitedUses": "",
|
||||||
"resourceImpact": "",
|
"resourceImpact": "",
|
||||||
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
||||||
@@ -72,11 +72,11 @@
|
|||||||
"type": "pouvoircompagnie",
|
"type": "pouvoircompagnie",
|
||||||
"img": "icons/svg/aura.svg",
|
"img": "icons/svg/aura.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Pouvoir de compagnie défensif accordant une armure naturelle.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"scope": "compagnie",
|
"scope": "compagnie",
|
||||||
"effectMode": "passif",
|
"effectMode": "passif",
|
||||||
"ruleText": "<p>Le pouvoir accorde une armure naturelle de 2 points.</p>",
|
"ruleText": "",
|
||||||
"limitedUses": "",
|
"limitedUses": "",
|
||||||
"resourceImpact": "",
|
"resourceImpact": "",
|
||||||
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
||||||
@@ -89,11 +89,11 @@
|
|||||||
"type": "pouvoircompagnie",
|
"type": "pouvoircompagnie",
|
||||||
"img": "icons/svg/aura.svg",
|
"img": "icons/svg/aura.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Pouvoir de compagnie qui sublime les réussites parfaites.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"scope": "compagnie",
|
"scope": "compagnie",
|
||||||
"effectMode": "passif",
|
"effectMode": "passif",
|
||||||
"ruleText": "<p>Lors d'un test, si le dé indique 12, le dé est relancé conformément aux règles habituelles. Cependant, le chiffre 12 remplace toujours le résultat obtenu au nouveau jet pour déterminer le résultat naturel. Si un nouveau 12 apparaît, le procédé continue jusqu'à obtention d'un autre chiffre.</p>",
|
"ruleText": "",
|
||||||
"limitedUses": "",
|
"limitedUses": "",
|
||||||
"resourceImpact": "",
|
"resourceImpact": "",
|
||||||
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
||||||
@@ -106,11 +106,11 @@
|
|||||||
"type": "pouvoircompagnie",
|
"type": "pouvoircompagnie",
|
||||||
"img": "icons/svg/aura.svg",
|
"img": "icons/svg/aura.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Pouvoir de compagnie qui donne une seconde chance face au pire résultat naturel.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"scope": "compagnie",
|
"scope": "compagnie",
|
||||||
"effectMode": "réaction",
|
"effectMode": "réaction",
|
||||||
"ruleText": "<p>Lors d'un test de compétence, le joueur qui obtient un résultat naturel de 1 peut relancer le dé. S'il obtient à nouveau un 1 naturel, il doit garder ce résultat.</p>",
|
"ruleText": "",
|
||||||
"limitedUses": "",
|
"limitedUses": "",
|
||||||
"resourceImpact": "",
|
"resourceImpact": "",
|
||||||
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
||||||
@@ -123,11 +123,11 @@
|
|||||||
"type": "pouvoircompagnie",
|
"type": "pouvoircompagnie",
|
||||||
"img": "icons/svg/aura.svg",
|
"img": "icons/svg/aura.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Pouvoir de compagnie doté de sa propre réserve de Songes.</p>",
|
"description": "",
|
||||||
"notes": "",
|
"notes": "",
|
||||||
"scope": "compagnie",
|
"scope": "compagnie",
|
||||||
"effectMode": "ressource",
|
"effectMode": "ressource",
|
||||||
"ruleText": "<p>La compagnie possède 1 point de Songes. Un membre peut l'utiliser comme si c'était l'un des siens. Il n'est alors plus utilisable jusqu'à la prochaine aube où il se régénère.</p>",
|
"ruleText": "",
|
||||||
"limitedUses": "1 point par aube",
|
"limitedUses": "1 point par aube",
|
||||||
"resourceImpact": "Réserve commune de 1 point de Songes",
|
"resourceImpact": "Réserve commune de 1 point de Songes",
|
||||||
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
"activationCondition": "À portée de vue du capitaine ; le capitaine doit voir au moins un autre membre pour en bénéficier lui-même.",
|
||||||
|
|||||||
@@ -4,17 +4,49 @@
|
|||||||
"type": "race",
|
"type": "race",
|
||||||
"img": "icons/svg/mystery-man.svg",
|
"img": "icons/svg/mystery-man.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Race trapue, robuste et ingénieuse du Petit Peuple.</p>",
|
"description": "",
|
||||||
"size": 2,
|
"size": 2,
|
||||||
"lifeExpectancy": 60,
|
"lifeExpectancy": 60,
|
||||||
"keywords": ["intelligent", "ingénieux", "curieux", "calculateur", "égoïste", "têtu", "bourru", "nostalgique", "costaud"],
|
"keywords": [
|
||||||
"mainTribes": ["Frinios", "Margouts"],
|
"intelligent",
|
||||||
|
"ingénieux",
|
||||||
|
"curieux",
|
||||||
|
"calculateur",
|
||||||
|
"égoïste",
|
||||||
|
"têtu",
|
||||||
|
"bourru",
|
||||||
|
"nostalgique",
|
||||||
|
"costaud"
|
||||||
|
],
|
||||||
|
"mainTribes": [
|
||||||
|
"Frinios",
|
||||||
|
"Margouts"
|
||||||
|
],
|
||||||
"language": "Belgfolk",
|
"language": "Belgfolk",
|
||||||
"languageDomains": ["Chimérique", "Jargon des likias", "Belgfolk"],
|
"languageDomains": [
|
||||||
|
"Chimérique",
|
||||||
|
"Jargon des likias",
|
||||||
|
"Belgfolk"
|
||||||
|
],
|
||||||
"specialRules": "",
|
"specialRules": "",
|
||||||
"appearance": "<p>Les belgfolks sont massifs, poilus et courts sur patte, avec un long nez, une haute stature pour leur taille et une barbe ou une longue natte soigneusement portée.</p>",
|
"appearance": "",
|
||||||
"roleplayHints": ["Garant d'une époque glorieuse passée", "Inspirations slaves et vikings", "Endurant face aux éléments"],
|
"roleplayHints": [
|
||||||
"profiles": { "artiste": 0, "athlete": 0, "chasseur": 1, "faiseur": 5, "forceNature": 5, "guerrier": 0, "mystique": 0, "ombre": 1, "savant": 3 }
|
"Garant d'une époque glorieuse passée",
|
||||||
|
"Inspirations slaves et vikings",
|
||||||
|
"Endurant face aux éléments"
|
||||||
|
],
|
||||||
|
"profiles": {
|
||||||
|
"artiste": 0,
|
||||||
|
"athlete": 0,
|
||||||
|
"chasseur": 1,
|
||||||
|
"faiseur": 5,
|
||||||
|
"forceNature": 5,
|
||||||
|
"guerrier": 0,
|
||||||
|
"mystique": 0,
|
||||||
|
"ombre": 1,
|
||||||
|
"savant": 3
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -22,17 +54,49 @@
|
|||||||
"type": "race",
|
"type": "race",
|
||||||
"img": "icons/svg/mystery-man.svg",
|
"img": "icons/svg/mystery-man.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Race mystique, longévive et liée aux sortilèges.</p>",
|
"description": "",
|
||||||
"size": 3,
|
"size": 3,
|
||||||
"lifeExpectancy": 100,
|
"lifeExpectancy": 100,
|
||||||
"keywords": ["calme", "silencieux", "paisible", "résigné", "pessimiste", "généreux", "mystique", "solitaire", "enchanteur"],
|
"keywords": [
|
||||||
"mainTribes": ["Siccomores", "Margouts"],
|
"calme",
|
||||||
|
"silencieux",
|
||||||
|
"paisible",
|
||||||
|
"résigné",
|
||||||
|
"pessimiste",
|
||||||
|
"généreux",
|
||||||
|
"mystique",
|
||||||
|
"solitaire",
|
||||||
|
"enchanteur"
|
||||||
|
],
|
||||||
|
"mainTribes": [
|
||||||
|
"Siccomores",
|
||||||
|
"Margouts"
|
||||||
|
],
|
||||||
"language": "Farfadet",
|
"language": "Farfadet",
|
||||||
"languageDomains": ["Chimérique", "Jargon des likias", "Farfadet"],
|
"languageDomains": [
|
||||||
|
"Chimérique",
|
||||||
|
"Jargon des likias",
|
||||||
|
"Farfadet"
|
||||||
|
],
|
||||||
"specialRules": "",
|
"specialRules": "",
|
||||||
"appearance": "<p>Les farfadets sont voûtés, rabougris, aux cheveux noirs, à la peau abîmée et aux longs ongles. Les femmes se distinguent souvent par leurs bijoux et boucles d'oreilles.</p>",
|
"appearance": "",
|
||||||
"roleplayHints": ["Fier d'une race autrefois influente", "Inspirations d'enchanteurs et de vieilles sorcières médiévales", "Présence inquiétante et ancienne"],
|
"roleplayHints": [
|
||||||
"profiles": { "artiste": 1, "athlete": 0, "chasseur": 0, "faiseur": 1, "forceNature": 3, "guerrier": 0, "mystique": 5, "ombre": 0, "savant": 4 }
|
"Fier d'une race autrefois influente",
|
||||||
|
"Inspirations d'enchanteurs et de vieilles sorcières médiévales",
|
||||||
|
"Présence inquiétante et ancienne"
|
||||||
|
],
|
||||||
|
"profiles": {
|
||||||
|
"artiste": 1,
|
||||||
|
"athlete": 0,
|
||||||
|
"chasseur": 0,
|
||||||
|
"faiseur": 1,
|
||||||
|
"forceNature": 3,
|
||||||
|
"guerrier": 0,
|
||||||
|
"mystique": 5,
|
||||||
|
"ombre": 0,
|
||||||
|
"savant": 4
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -40,17 +104,51 @@
|
|||||||
"type": "race",
|
"type": "race",
|
||||||
"img": "icons/svg/mystery-man.svg",
|
"img": "icons/svg/mystery-man.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Race très petite, acrobatique, bruyante et farceuse.</p>",
|
"description": "",
|
||||||
"size": 2,
|
"size": 2,
|
||||||
"lifeExpectancy": 50,
|
"lifeExpectancy": 50,
|
||||||
"keywords": ["agile", "acrobate", "chétif", "comédien", "espiègle", "farceur", "bruyant", "bagarreur", "cavalier", "tireur"],
|
"keywords": [
|
||||||
"mainTribes": ["Pataches", "Banshises", "Margouts"],
|
"agile",
|
||||||
|
"acrobate",
|
||||||
|
"chétif",
|
||||||
|
"comédien",
|
||||||
|
"espiègle",
|
||||||
|
"farceur",
|
||||||
|
"bruyant",
|
||||||
|
"bagarreur",
|
||||||
|
"cavalier",
|
||||||
|
"tireur"
|
||||||
|
],
|
||||||
|
"mainTribes": [
|
||||||
|
"Pataches",
|
||||||
|
"Banshises",
|
||||||
|
"Margouts"
|
||||||
|
],
|
||||||
"language": "Gnome",
|
"language": "Gnome",
|
||||||
"languageDomains": ["Chimérique", "Jargon des likias", "Gnome"],
|
"languageDomains": [
|
||||||
|
"Chimérique",
|
||||||
|
"Jargon des likias",
|
||||||
|
"Gnome"
|
||||||
|
],
|
||||||
"specialRules": "",
|
"specialRules": "",
|
||||||
"appearance": "<p>Les gnomes ont un visage d'enfant, aucune pilosité et une allure malingre. Leur petite taille contraste avec leur énergie débordante.</p>",
|
"appearance": "",
|
||||||
"roleplayHints": ["Déclenche facilement les bagarres", "Grandes variations culturelles", "Inspirations nomades et tsiganes"],
|
"roleplayHints": [
|
||||||
"profiles": { "artiste": 3, "athlete": 5, "chasseur": 3, "faiseur": 0, "forceNature": 0, "guerrier": 1, "mystique": 0, "ombre": 3, "savant": 0 }
|
"Déclenche facilement les bagarres",
|
||||||
|
"Grandes variations culturelles",
|
||||||
|
"Inspirations nomades et tsiganes"
|
||||||
|
],
|
||||||
|
"profiles": {
|
||||||
|
"artiste": 3,
|
||||||
|
"athlete": 5,
|
||||||
|
"chasseur": 3,
|
||||||
|
"faiseur": 0,
|
||||||
|
"forceNature": 0,
|
||||||
|
"guerrier": 1,
|
||||||
|
"mystique": 0,
|
||||||
|
"ombre": 3,
|
||||||
|
"savant": 0
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -58,17 +156,50 @@
|
|||||||
"type": "race",
|
"type": "race",
|
||||||
"img": "icons/svg/mystery-man.svg",
|
"img": "icons/svg/mystery-man.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Race gracile et macabre, proche des morts et de la nuit.</p>",
|
"description": "",
|
||||||
"size": 3,
|
"size": 3,
|
||||||
"lifeExpectancy": 65,
|
"lifeExpectancy": 65,
|
||||||
"keywords": ["calme", "froid", "taciturne", "solitaire", "macabre", "gracieux", "agile", "orgueilleux", "élancé"],
|
"keywords": [
|
||||||
"mainTribes": ["Sixts", "Vivitins", "Margouts"],
|
"calme",
|
||||||
|
"froid",
|
||||||
|
"taciturne",
|
||||||
|
"solitaire",
|
||||||
|
"macabre",
|
||||||
|
"gracieux",
|
||||||
|
"agile",
|
||||||
|
"orgueilleux",
|
||||||
|
"élancé"
|
||||||
|
],
|
||||||
|
"mainTribes": [
|
||||||
|
"Sixts",
|
||||||
|
"Vivitins",
|
||||||
|
"Margouts"
|
||||||
|
],
|
||||||
"language": "Kobold",
|
"language": "Kobold",
|
||||||
"languageDomains": ["Chimérique", "Jargon des likias", "Kobold"],
|
"languageDomains": [
|
||||||
"specialRules": "<p>Les kobolds voient et entendent les esprits des morts qui les entourent.</p>",
|
"Chimérique",
|
||||||
"appearance": "<p>Les kobolds ont la peau pâle, les cheveux argentés et une beauté glaciale. Certains sont d'un bleu sombre presque noir et sont promis à un grand destin magique.</p>",
|
"Jargon des likias",
|
||||||
"roleplayHints": ["Chevaliers noirs et noblesse décadente", "Affinité naturelle avec les morts", "Souvent tenus pour suspects"],
|
"Kobold"
|
||||||
"profiles": { "artiste": 0, "athlete": 5, "chasseur": 0, "faiseur": 0, "forceNature": 0, "guerrier": 3, "mystique": 3, "ombre": 1, "savant": 1 }
|
],
|
||||||
|
"specialRules": "",
|
||||||
|
"appearance": "",
|
||||||
|
"roleplayHints": [
|
||||||
|
"Chevaliers noirs et noblesse décadente",
|
||||||
|
"Affinité naturelle avec les morts",
|
||||||
|
"Souvent tenus pour suspects"
|
||||||
|
],
|
||||||
|
"profiles": {
|
||||||
|
"artiste": 0,
|
||||||
|
"athlete": 5,
|
||||||
|
"chasseur": 0,
|
||||||
|
"faiseur": 0,
|
||||||
|
"forceNature": 0,
|
||||||
|
"guerrier": 3,
|
||||||
|
"mystique": 3,
|
||||||
|
"ombre": 1,
|
||||||
|
"savant": 1
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -76,17 +207,49 @@
|
|||||||
"type": "race",
|
"type": "race",
|
||||||
"img": "icons/svg/mystery-man.svg",
|
"img": "icons/svg/mystery-man.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Race violente, puissante et exubérante, peu sensible au Songe.</p>",
|
"description": "",
|
||||||
"size": 2,
|
"size": 2,
|
||||||
"lifeExpectancy": 45,
|
"lifeExpectancy": 45,
|
||||||
"keywords": ["agressif", "violent", "bruyant", "impulsif", "épicurien", "farceur", "tolérant", "force prodigieuse", "guerrier"],
|
"keywords": [
|
||||||
"mainTribes": ["Huvons", "Margouts"],
|
"agressif",
|
||||||
|
"violent",
|
||||||
|
"bruyant",
|
||||||
|
"impulsif",
|
||||||
|
"épicurien",
|
||||||
|
"farceur",
|
||||||
|
"tolérant",
|
||||||
|
"force prodigieuse",
|
||||||
|
"guerrier"
|
||||||
|
],
|
||||||
|
"mainTribes": [
|
||||||
|
"Huvons",
|
||||||
|
"Margouts"
|
||||||
|
],
|
||||||
"language": "Korrigan",
|
"language": "Korrigan",
|
||||||
"languageDomains": ["Chimérique", "Jargon des likias", "Korrigan"],
|
"languageDomains": [
|
||||||
|
"Chimérique",
|
||||||
|
"Jargon des likias",
|
||||||
|
"Korrigan"
|
||||||
|
],
|
||||||
"specialRules": "",
|
"specialRules": "",
|
||||||
"appearance": "<p>Très trapus, souvent sombres et extrêmement velus, les korrigans ressemblent à des cubes de muscle taillés pour la bagarre.</p>",
|
"appearance": "",
|
||||||
"roleplayHints": ["Guerrier craint", "Adore la compagnie et les conflits", "Inspirations barbares et celtes"],
|
"roleplayHints": [
|
||||||
"profiles": { "artiste": 0, "athlete": 3, "chasseur": 1, "faiseur": 0, "forceNature": 5, "guerrier": 5, "mystique": 0, "ombre": 1, "savant": 0 }
|
"Guerrier craint",
|
||||||
|
"Adore la compagnie et les conflits",
|
||||||
|
"Inspirations barbares et celtes"
|
||||||
|
],
|
||||||
|
"profiles": {
|
||||||
|
"artiste": 0,
|
||||||
|
"athlete": 3,
|
||||||
|
"chasseur": 1,
|
||||||
|
"faiseur": 0,
|
||||||
|
"forceNature": 5,
|
||||||
|
"guerrier": 5,
|
||||||
|
"mystique": 0,
|
||||||
|
"ombre": 1,
|
||||||
|
"savant": 0
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -94,17 +257,49 @@
|
|||||||
"type": "race",
|
"type": "race",
|
||||||
"img": "icons/svg/mystery-man.svg",
|
"img": "icons/svg/mystery-man.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Race noble, charismatique et très polyvalente.</p>",
|
"description": "",
|
||||||
"size": 3,
|
"size": 3,
|
||||||
"lifeExpectancy": 60,
|
"lifeExpectancy": 60,
|
||||||
"keywords": ["agile", "sensuel", "élancé", "orgueilleux", "autoritaire", "arrogant", "charismatique", "polyvalent"],
|
"keywords": [
|
||||||
"mainTribes": ["Krograines", "Karius", "Margouts"],
|
"agile",
|
||||||
|
"sensuel",
|
||||||
|
"élancé",
|
||||||
|
"orgueilleux",
|
||||||
|
"autoritaire",
|
||||||
|
"arrogant",
|
||||||
|
"charismatique",
|
||||||
|
"polyvalent"
|
||||||
|
],
|
||||||
|
"mainTribes": [
|
||||||
|
"Krograines",
|
||||||
|
"Karius",
|
||||||
|
"Margouts"
|
||||||
|
],
|
||||||
"language": "Lutin",
|
"language": "Lutin",
|
||||||
"languageDomains": ["Chimérique", "Jargon des likias", "Lutin"],
|
"languageDomains": [
|
||||||
|
"Chimérique",
|
||||||
|
"Jargon des likias",
|
||||||
|
"Lutin"
|
||||||
|
],
|
||||||
"specialRules": "",
|
"specialRules": "",
|
||||||
"appearance": "<p>Les lutins sont minces, élégants, d'une grande beauté et portent de longues chevelures aux reflets d'or ou de rouille. Leur regard froid impressionne les autres races.</p>",
|
"appearance": "",
|
||||||
"roleplayHints": ["Respecté des autres races", "Gardien des mythes d'Edenia", "Inspirations arthuriennes et féodales"],
|
"roleplayHints": [
|
||||||
"profiles": { "artiste": 4, "athlete": 0, "chasseur": 1, "faiseur": 0, "forceNature": 0, "guerrier": 5, "mystique": 3, "ombre": 1, "savant": 0 }
|
"Respecté des autres races",
|
||||||
|
"Gardien des mythes d'Edenia",
|
||||||
|
"Inspirations arthuriennes et féodales"
|
||||||
|
],
|
||||||
|
"profiles": {
|
||||||
|
"artiste": 4,
|
||||||
|
"athlete": 0,
|
||||||
|
"chasseur": 1,
|
||||||
|
"faiseur": 0,
|
||||||
|
"forceNature": 0,
|
||||||
|
"guerrier": 5,
|
||||||
|
"mystique": 3,
|
||||||
|
"ombre": 1,
|
||||||
|
"savant": 0
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -112,17 +307,47 @@
|
|||||||
"type": "race",
|
"type": "race",
|
||||||
"img": "icons/svg/mystery-man.svg",
|
"img": "icons/svg/mystery-man.svg",
|
||||||
"system": {
|
"system": {
|
||||||
"description": "<p>Les plus grands et les plus robustes du Petit Peuple.</p>",
|
"description": "",
|
||||||
"size": 4,
|
"size": 4,
|
||||||
"lifeExpectancy": 50,
|
"lifeExpectancy": 50,
|
||||||
"keywords": ["force de la nature", "brute", "cavalier", "amoureux de la nature", "conteur", "sauvage", "primitif"],
|
"keywords": [
|
||||||
"mainTribes": ["Ventrus", "Margouts"],
|
"force de la nature",
|
||||||
|
"brute",
|
||||||
|
"cavalier",
|
||||||
|
"amoureux de la nature",
|
||||||
|
"conteur",
|
||||||
|
"sauvage",
|
||||||
|
"primitif"
|
||||||
|
],
|
||||||
|
"mainTribes": [
|
||||||
|
"Ventrus",
|
||||||
|
"Margouts"
|
||||||
|
],
|
||||||
"language": "Velu nuton",
|
"language": "Velu nuton",
|
||||||
"languageDomains": ["Chimérique", "Jargon des likias", "Velu nuton"],
|
"languageDomains": [
|
||||||
|
"Chimérique",
|
||||||
|
"Jargon des likias",
|
||||||
|
"Velu nuton"
|
||||||
|
],
|
||||||
"specialRules": "",
|
"specialRules": "",
|
||||||
"appearance": "<p>Les velus nutons mesurent souvent de 10 à 13 cm, voire davantage. Puissants mais peu agiles, ils sont prisés comme gardes du corps.</p>",
|
"appearance": "",
|
||||||
"roleplayHints": ["Individu craint et sous-estimé", "Ogre poétique et nomade", "Inspirations barbares primitives"],
|
"roleplayHints": [
|
||||||
"profiles": { "artiste": 1, "athlete": 1, "chasseur": 3, "faiseur": 0, "forceNature": 5, "guerrier": 3, "mystique": 0, "ombre": 0, "savant": 0 }
|
"Individu craint et sous-estimé",
|
||||||
|
"Ogre poétique et nomade",
|
||||||
|
"Inspirations barbares primitives"
|
||||||
|
],
|
||||||
|
"profiles": {
|
||||||
|
"artiste": 1,
|
||||||
|
"athlete": 1,
|
||||||
|
"chasseur": 3,
|
||||||
|
"faiseur": 0,
|
||||||
|
"forceNature": 5,
|
||||||
|
"guerrier": 3,
|
||||||
|
"mystique": 0,
|
||||||
|
"ombre": 0,
|
||||||
|
"savant": 0
|
||||||
|
},
|
||||||
|
"notes": ""
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1 @@
|
|||||||
|
MANIFEST-000002
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
2026/05/06-20:00:09.287368 7f612bfff6c0 Delete type=3 #1
|
||||||
@@ -1 +1 @@
|
|||||||
2026/05/03-20:13:00.428719 7f25c15fe6c0 Delete type=3 #1
|
2026/05/06-20:00:09.149296 7f6174dfd6c0 Delete type=3 #1
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2026/05/03-20:13:00.445629 7f2577fff6c0 Delete type=3 #1
|
2026/05/06-20:00:09.165377 7f612bfff6c0 Delete type=3 #1
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2026/05/03-20:13:00.492466 7f25c15fe6c0 Delete type=3 #1
|
2026/05/06-20:00:09.210742 7f6174dfd6c0 Delete type=3 #1
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2026/05/03-20:13:00.461618 7f25c1dff6c0 Delete type=3 #1
|
2026/05/06-20:00:09.180731 7f6175dff6c0 Delete type=3 #1
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2026/05/03-20:13:00.538848 7f25c0dfd6c0 Delete type=3 #1
|
2026/05/06-20:00:09.256606 7f61755fe6c0 Delete type=3 #1
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2026/05/03-20:13:00.476671 7f25c0dfd6c0 Delete type=3 #1
|
2026/05/06-20:00:09.195364 7f61755fe6c0 Delete type=3 #1
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2026/05/03-20:13:00.509155 7f2577fff6c0 Delete type=3 #1
|
2026/05/06-20:00:09.225835 7f612bfff6c0 Delete type=3 #1
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2026/05/03-20:13:00.554628 7f25c15fe6c0 Delete type=3 #1
|
2026/05/06-20:00:09.271737 7f6174dfd6c0 Delete type=3 #1
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2026/05/03-20:13:00.523663 7f25c1dff6c0 Delete type=3 #1
|
2026/05/06-20:00:09.241097 7f6175dff6c0 Delete type=3 #1
|
||||||
|
|||||||
@@ -1,132 +1,17 @@
|
|||||||
import fs from "node:fs"
|
|
||||||
import path from "node:path"
|
import path from "node:path"
|
||||||
import crypto from "node:crypto"
|
import fs from "node:fs"
|
||||||
|
|
||||||
import { Level } from "level"
|
import { buildPacks, SYSTEM_PACK_DEFINITIONS } from "./pack-builder.mjs"
|
||||||
|
|
||||||
const rootDir = path.resolve(import.meta.dirname, "..")
|
const rootDir = path.resolve(import.meta.dirname, "..")
|
||||||
const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, "package.json"), "utf8"))
|
const packageJson = JSON.parse(fs.readFileSync(path.join(rootDir, "package.json"), "utf8"))
|
||||||
const systemJson = JSON.parse(fs.readFileSync(path.join(rootDir, "system.json"), "utf8"))
|
const systemJson = JSON.parse(fs.readFileSync(path.join(rootDir, "system.json"), "utf8"))
|
||||||
|
|
||||||
const PACK_SOURCES = [
|
await buildPacks({
|
||||||
{
|
sourceRoot: path.join(rootDir, "packs-src"),
|
||||||
sourcePath: path.join(rootDir, "packs-src", "armes.json"),
|
outputRoot: path.join(rootDir, "packs"),
|
||||||
outputPath: path.join(rootDir, "packs", "armes"),
|
packDefinitions: SYSTEM_PACK_DEFINITIONS,
|
||||||
type: "Item",
|
documentSystemId: systemJson.id,
|
||||||
},
|
documentSystemVersion: packageJson.version,
|
||||||
{
|
coreVersion: String(systemJson.compatibility?.verified ?? systemJson.compatibility?.minimum ?? ""),
|
||||||
sourcePath: path.join(rootDir, "packs-src", "armures.json"),
|
|
||||||
outputPath: path.join(rootDir, "packs", "armures"),
|
|
||||||
type: "Item",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sourcePath: path.join(rootDir, "packs-src", "equipements.json"),
|
|
||||||
outputPath: path.join(rootDir, "packs", "equipements"),
|
|
||||||
type: "Item",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sourcePath: path.join(rootDir, "packs-src", "pouvoirs-compagnie.json"),
|
|
||||||
outputPath: path.join(rootDir, "packs", "pouvoirs-compagnie"),
|
|
||||||
type: "Item",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sourcePath: path.join(rootDir, "packs-src", "competences.json"),
|
|
||||||
outputPath: path.join(rootDir, "packs", "competences"),
|
|
||||||
type: "Item",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sourcePath: path.join(rootDir, "packs-src", "races.json"),
|
|
||||||
outputPath: path.join(rootDir, "packs", "races"),
|
|
||||||
type: "Item",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sourcePath: path.join(rootDir, "packs-src", "tribus.json"),
|
|
||||||
outputPath: path.join(rootDir, "packs", "tribus"),
|
|
||||||
type: "Item",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sourcePath: path.join(rootDir, "packs-src", "metiers.json"),
|
|
||||||
outputPath: path.join(rootDir, "packs", "metiers"),
|
|
||||||
type: "Item",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
sourcePath: path.join(rootDir, "packs-src", "sortileges.json"),
|
|
||||||
outputPath: path.join(rootDir, "packs", "sortileges"),
|
|
||||||
type: "Item",
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const now = Date.now()
|
|
||||||
const systemId = systemJson.id
|
|
||||||
const systemVersion = packageJson.version
|
|
||||||
const coreVersion = String(systemJson.compatibility?.verified ?? systemJson.compatibility?.minimum ?? "")
|
|
||||||
|
|
||||||
function slugId(input) {
|
|
||||||
const hash = crypto.createHash("sha256").update(input).digest()
|
|
||||||
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
|
||||||
let id = ""
|
|
||||||
for (let index = 0; id.length < 16; index += 1) {
|
|
||||||
id += alphabet[hash[index % hash.length] % alphabet.length]
|
|
||||||
}
|
|
||||||
return id
|
|
||||||
}
|
|
||||||
|
|
||||||
function toPackDocument(entry, index) {
|
|
||||||
const docId = slugId(`${entry.type}:${entry.name}`)
|
|
||||||
return {
|
|
||||||
name: entry.name,
|
|
||||||
type: entry.type,
|
|
||||||
img: entry.img ?? "icons/svg/item-bag.svg",
|
|
||||||
system: entry.system ?? {},
|
|
||||||
effects: Array.isArray(entry.effects) ? entry.effects : [],
|
|
||||||
flags: entry.flags ?? {},
|
|
||||||
_stats: {
|
|
||||||
systemId,
|
|
||||||
systemVersion,
|
|
||||||
coreVersion,
|
|
||||||
createdTime: now,
|
|
||||||
modifiedTime: now,
|
|
||||||
lastModifiedBy: "Copilot",
|
|
||||||
compendiumSource: null,
|
|
||||||
duplicateSource: null,
|
|
||||||
exportSource: null,
|
|
||||||
},
|
|
||||||
_id: docId,
|
|
||||||
folder: null,
|
|
||||||
sort: index * 1000,
|
|
||||||
ownership: {
|
|
||||||
default: 0,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function buildPack({ sourcePath, outputPath, type }) {
|
|
||||||
const source = JSON.parse(fs.readFileSync(sourcePath, "utf8"))
|
|
||||||
if (!Array.isArray(source)) {
|
|
||||||
throw new Error(`Pack source must be an array: ${sourcePath}`)
|
|
||||||
}
|
|
||||||
|
|
||||||
fs.rmSync(outputPath, { recursive: true, force: true })
|
|
||||||
fs.mkdirSync(outputPath, { recursive: true })
|
|
||||||
|
|
||||||
const db = new Level(outputPath, { valueEncoding: "utf8" })
|
|
||||||
|
|
||||||
try {
|
|
||||||
await db.open()
|
|
||||||
const batch = db.batch()
|
|
||||||
source.forEach((entry, index) => {
|
|
||||||
if (!entry.type) {
|
|
||||||
throw new Error(`Missing document type in ${sourcePath}: ${entry.name}`)
|
|
||||||
}
|
|
||||||
const doc = toPackDocument(entry, index)
|
|
||||||
batch.put(`!items!${doc._id}`, JSON.stringify(doc))
|
|
||||||
})
|
})
|
||||||
await batch.write()
|
|
||||||
} finally {
|
|
||||||
await db.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const pack of PACK_SOURCES) {
|
|
||||||
await buildPack(pack)
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,217 @@
|
|||||||
|
import fs from "node:fs"
|
||||||
|
import path from "node:path"
|
||||||
|
import crypto from "node:crypto"
|
||||||
|
|
||||||
|
import { Level } from "level"
|
||||||
|
|
||||||
|
export const CONTENT_PACK_DEFINITIONS = [
|
||||||
|
{ sourceFile: "armes.json", outputFolder: "armes", type: "Item" },
|
||||||
|
{ sourceFile: "armures.json", outputFolder: "armures", type: "Item" },
|
||||||
|
{ sourceFile: "equipements.json", outputFolder: "equipements", type: "Item" },
|
||||||
|
{ sourceFile: "pouvoirs-compagnie.json", outputFolder: "pouvoirs-compagnie", type: "Item" },
|
||||||
|
{ sourceFile: "competences.json", outputFolder: "competences", type: "Item" },
|
||||||
|
{ sourceFile: "races.json", outputFolder: "races", type: "Item" },
|
||||||
|
{ sourceFile: "tribus.json", outputFolder: "tribus", type: "Item" },
|
||||||
|
{ sourceFile: "metiers.json", outputFolder: "metiers", type: "Item" },
|
||||||
|
{ sourceFile: "sortileges.json", outputFolder: "sortileges", type: "Item" },
|
||||||
|
]
|
||||||
|
|
||||||
|
export const SYSTEM_PACK_DEFINITIONS = [
|
||||||
|
...CONTENT_PACK_DEFINITIONS,
|
||||||
|
{ sourceFile: "aide-systeme.json", outputFolder: "aide-systeme", type: "JournalEntry" },
|
||||||
|
]
|
||||||
|
|
||||||
|
function slugId(input) {
|
||||||
|
const hash = crypto.createHash("sha256").update(input).digest()
|
||||||
|
const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
|
||||||
|
let id = ""
|
||||||
|
for (let index = 0; id.length < 16; index += 1) {
|
||||||
|
id += alphabet[hash[index % hash.length] % alphabet.length]
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
function createDocumentStats({
|
||||||
|
documentSystemId,
|
||||||
|
documentSystemVersion,
|
||||||
|
coreVersion,
|
||||||
|
createdTime,
|
||||||
|
lastModifiedBy = "Copilot",
|
||||||
|
} = {}) {
|
||||||
|
return {
|
||||||
|
systemId: documentSystemId,
|
||||||
|
systemVersion: documentSystemVersion,
|
||||||
|
coreVersion,
|
||||||
|
createdTime,
|
||||||
|
modifiedTime: createdTime,
|
||||||
|
lastModifiedBy,
|
||||||
|
compendiumSource: null,
|
||||||
|
duplicateSource: null,
|
||||||
|
exportSource: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toItemPackDocument(entry, index, options = {}) {
|
||||||
|
const docId = slugId(`${entry.type}:${entry.name}`)
|
||||||
|
return {
|
||||||
|
key: `!items!${docId}`,
|
||||||
|
value: {
|
||||||
|
name: entry.name,
|
||||||
|
type: entry.type,
|
||||||
|
img: entry.img ?? "icons/svg/item-bag.svg",
|
||||||
|
system: entry.system ?? {},
|
||||||
|
effects: Array.isArray(entry.effects) ? entry.effects : [],
|
||||||
|
flags: entry.flags ?? {},
|
||||||
|
_stats: createDocumentStats(options),
|
||||||
|
_id: docId,
|
||||||
|
folder: null,
|
||||||
|
sort: index * 1000,
|
||||||
|
ownership: {
|
||||||
|
default: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
embedded: [],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toJournalPageDocument(entry, journalId, page, pageIndex, options = {}) {
|
||||||
|
const pageId = slugId(`JournalEntryPage:${entry.name}:${page.name ?? page.title ?? pageIndex}`)
|
||||||
|
return {
|
||||||
|
_id: pageId,
|
||||||
|
name: page.name ?? `Page ${pageIndex + 1}`,
|
||||||
|
type: page.type ?? "text",
|
||||||
|
title: {
|
||||||
|
show: page.title?.show ?? true,
|
||||||
|
level: page.title?.level ?? 1,
|
||||||
|
},
|
||||||
|
text: {
|
||||||
|
format: page.text?.format ?? 1,
|
||||||
|
content: page.text?.content ?? "",
|
||||||
|
},
|
||||||
|
system: page.system ?? {},
|
||||||
|
image: page.image ?? {},
|
||||||
|
video: page.video ?? { controls: true, volume: 0.5 },
|
||||||
|
src: page.src ?? null,
|
||||||
|
category: page.category ?? null,
|
||||||
|
sort: page.sort ?? pageIndex * 1000,
|
||||||
|
ownership: page.ownership ?? { default: -1 },
|
||||||
|
flags: page.flags ?? {},
|
||||||
|
_stats: createDocumentStats(options),
|
||||||
|
_key: `!journal.pages!${journalId}.${pageId}`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toJournalPackDocument(entry, index, options = {}) {
|
||||||
|
const docId = slugId(`JournalEntry:${entry.name}`)
|
||||||
|
const pages = Array.isArray(entry.pages)
|
||||||
|
? entry.pages.map((page, pageIndex) => toJournalPageDocument(entry, docId, page, pageIndex, options))
|
||||||
|
: []
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: `!journal!${docId}`,
|
||||||
|
value: {
|
||||||
|
name: entry.name,
|
||||||
|
pages: pages.map((page) => page._id),
|
||||||
|
ownership: entry.ownership ?? { default: 0 },
|
||||||
|
flags: entry.flags ?? { core: {} },
|
||||||
|
_stats: createDocumentStats(options),
|
||||||
|
folder: null,
|
||||||
|
sort: entry.sort ?? index * 1000,
|
||||||
|
_id: docId,
|
||||||
|
categories: Array.isArray(entry.categories) ? entry.categories : [],
|
||||||
|
},
|
||||||
|
embedded: pages.map((page) => ({
|
||||||
|
key: page._key,
|
||||||
|
value: {
|
||||||
|
name: page.name,
|
||||||
|
type: page.type,
|
||||||
|
title: page.title,
|
||||||
|
text: page.text,
|
||||||
|
system: page.system,
|
||||||
|
image: page.image,
|
||||||
|
video: page.video,
|
||||||
|
src: page.src,
|
||||||
|
category: page.category,
|
||||||
|
sort: page.sort,
|
||||||
|
ownership: page.ownership,
|
||||||
|
flags: page.flags,
|
||||||
|
_stats: page._stats,
|
||||||
|
_id: page._id,
|
||||||
|
},
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function toPackDocument(entry, index, options = {}) {
|
||||||
|
if (entry.type === "JournalEntry") return toJournalPackDocument(entry, index, options)
|
||||||
|
return toItemPackDocument(entry, index, options)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function buildPack({
|
||||||
|
sourcePath,
|
||||||
|
outputPath,
|
||||||
|
type,
|
||||||
|
documentSystemId,
|
||||||
|
documentSystemVersion,
|
||||||
|
coreVersion,
|
||||||
|
createdTime,
|
||||||
|
lastModifiedBy,
|
||||||
|
}) {
|
||||||
|
const source = JSON.parse(fs.readFileSync(sourcePath, "utf8"))
|
||||||
|
if (!Array.isArray(source)) {
|
||||||
|
throw new Error(`Pack source must be an array: ${sourcePath}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.rmSync(outputPath, { recursive: true, force: true })
|
||||||
|
fs.mkdirSync(outputPath, { recursive: true })
|
||||||
|
|
||||||
|
const db = new Level(outputPath, { valueEncoding: "utf8" })
|
||||||
|
|
||||||
|
try {
|
||||||
|
await db.open()
|
||||||
|
const batch = db.batch()
|
||||||
|
source.forEach((entry, index) => {
|
||||||
|
if (!entry.type) {
|
||||||
|
throw new Error(`Missing document type in ${sourcePath}: ${entry.name}`)
|
||||||
|
}
|
||||||
|
const doc = toPackDocument(entry, index, {
|
||||||
|
documentSystemId,
|
||||||
|
documentSystemVersion,
|
||||||
|
coreVersion,
|
||||||
|
createdTime,
|
||||||
|
lastModifiedBy,
|
||||||
|
})
|
||||||
|
batch.put(doc.key, JSON.stringify(doc.value))
|
||||||
|
for (const embedded of doc.embedded) {
|
||||||
|
batch.put(embedded.key, JSON.stringify(embedded.value))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await batch.write()
|
||||||
|
} finally {
|
||||||
|
await db.close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function buildPacks({
|
||||||
|
sourceRoot,
|
||||||
|
outputRoot,
|
||||||
|
packDefinitions = SYSTEM_PACK_DEFINITIONS,
|
||||||
|
documentSystemId,
|
||||||
|
documentSystemVersion,
|
||||||
|
coreVersion,
|
||||||
|
createdTime = Date.now(),
|
||||||
|
lastModifiedBy = "Copilot",
|
||||||
|
}) {
|
||||||
|
for (const pack of packDefinitions) {
|
||||||
|
await buildPack({
|
||||||
|
sourcePath: path.join(sourceRoot, pack.sourceFile),
|
||||||
|
outputPath: path.join(outputRoot, pack.outputFolder),
|
||||||
|
type: pack.type,
|
||||||
|
documentSystemId,
|
||||||
|
documentSystemVersion,
|
||||||
|
coreVersion,
|
||||||
|
createdTime,
|
||||||
|
lastModifiedBy,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,233 @@
|
|||||||
|
import fs from "node:fs"
|
||||||
|
import path from "node:path"
|
||||||
|
|
||||||
|
import { CONTENT_PACK_DEFINITIONS, SYSTEM_PACK_DEFINITIONS, buildPacks } from "./pack-builder.mjs"
|
||||||
|
|
||||||
|
const systemRoot = path.resolve(import.meta.dirname, "..")
|
||||||
|
const targetRoot = path.resolve(
|
||||||
|
process.env.FVTT_LES_OUBLIES_BASE_ROOT || path.join(systemRoot, "..", "fvtt-les-oublies-base"),
|
||||||
|
)
|
||||||
|
const systemManifestPath = path.join(systemRoot, "system.json")
|
||||||
|
const systemPackagePath = path.join(systemRoot, "package.json")
|
||||||
|
const systemSourceRoot = path.join(systemRoot, "packs-src")
|
||||||
|
const targetSourceRoot = path.join(targetRoot, "packs-src")
|
||||||
|
const targetPacksRoot = path.join(targetRoot, "packs")
|
||||||
|
const moduleRepoUrl = "https://www.uberwald.me/gitea/public/fvtt-les-oublies-base"
|
||||||
|
|
||||||
|
const systemManifest = JSON.parse(fs.readFileSync(systemManifestPath, "utf8"))
|
||||||
|
const systemPackage = JSON.parse(fs.readFileSync(systemPackagePath, "utf8"))
|
||||||
|
const richFieldMap = Object.fromEntries(
|
||||||
|
Object.entries(systemManifest.documentTypes?.Item ?? {}).map(([type, data]) => [type, data.htmlFields ?? []]),
|
||||||
|
)
|
||||||
|
const coreVersion = String(systemManifest.compatibility?.verified ?? systemManifest.compatibility?.minimum ?? "")
|
||||||
|
const basePackDefinitions = CONTENT_PACK_DEFINITIONS.map((pack) => ({
|
||||||
|
...pack,
|
||||||
|
outputFolder: `base-${pack.outputFolder}`,
|
||||||
|
}))
|
||||||
|
const contentPackNames = new Set(CONTENT_PACK_DEFINITIONS.map((pack) => pack.outputFolder))
|
||||||
|
|
||||||
|
function setDeepValue(target, propertyPath, value) {
|
||||||
|
const segments = String(propertyPath || "").split(".").filter(Boolean)
|
||||||
|
if (!segments.length) return
|
||||||
|
let cursor = target
|
||||||
|
while (segments.length > 1) {
|
||||||
|
const segment = segments.shift()
|
||||||
|
if (!(segment in cursor) || typeof cursor[segment] !== "object" || cursor[segment] === null) {
|
||||||
|
cursor[segment] = {}
|
||||||
|
}
|
||||||
|
cursor = cursor[segment]
|
||||||
|
}
|
||||||
|
cursor[segments[0]] = value
|
||||||
|
}
|
||||||
|
|
||||||
|
function sanitizeEntries(entries = []) {
|
||||||
|
let clearedFields = 0
|
||||||
|
const sanitized = entries.map((entry) => {
|
||||||
|
const fields = richFieldMap[entry.type] ?? []
|
||||||
|
if (!fields.length) return entry
|
||||||
|
|
||||||
|
const clone = structuredClone(entry)
|
||||||
|
clone.system ??= {}
|
||||||
|
for (const fieldPath of fields) {
|
||||||
|
setDeepValue(clone.system, fieldPath, "")
|
||||||
|
clearedFields += 1
|
||||||
|
}
|
||||||
|
return clone
|
||||||
|
})
|
||||||
|
|
||||||
|
return { sanitized, clearedFields }
|
||||||
|
}
|
||||||
|
|
||||||
|
function countNonEmptyRichFields(entries = []) {
|
||||||
|
let nonEmpty = 0
|
||||||
|
for (const entry of entries) {
|
||||||
|
for (const fieldPath of richFieldMap[entry.type] ?? []) {
|
||||||
|
const value = fieldPath
|
||||||
|
.split(".")
|
||||||
|
.reduce((cursor, segment) => cursor?.[segment], entry.system ?? {})
|
||||||
|
if ((value ?? "") !== "") nonEmpty += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nonEmpty
|
||||||
|
}
|
||||||
|
|
||||||
|
function parseJsonArray(rawText, filePath) {
|
||||||
|
const parsed = JSON.parse(rawText)
|
||||||
|
if (!Array.isArray(parsed)) {
|
||||||
|
return {
|
||||||
|
parsed,
|
||||||
|
entries: null,
|
||||||
|
isArray: false,
|
||||||
|
error: `${filePath} must contain a JSON array`,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
parsed,
|
||||||
|
entries: parsed,
|
||||||
|
isArray: true,
|
||||||
|
error: null,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureWritableTargetRoot() {
|
||||||
|
const parentDir = path.dirname(targetRoot)
|
||||||
|
fs.mkdirSync(parentDir, { recursive: true })
|
||||||
|
fs.accessSync(parentDir, fs.constants.W_OK)
|
||||||
|
fs.mkdirSync(targetRoot, { recursive: true })
|
||||||
|
fs.accessSync(targetRoot, fs.constants.W_OK)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ensureTargetModuleScaffold() {
|
||||||
|
ensureWritableTargetRoot()
|
||||||
|
fs.mkdirSync(targetSourceRoot, { recursive: true })
|
||||||
|
fs.mkdirSync(targetPacksRoot, { recursive: true })
|
||||||
|
|
||||||
|
const moduleManifestPath = path.join(targetRoot, "module.json")
|
||||||
|
|
||||||
|
const moduleManifest = {
|
||||||
|
id: "fvtt-les-oublies-base",
|
||||||
|
title: "Les Oubliés Base",
|
||||||
|
description: "Module de contenu pour Les Oubliés, conservant les compendiums complets avec leurs textes descriptifs.",
|
||||||
|
manifest: `${moduleRepoUrl}/raw/branch/main/module.json`,
|
||||||
|
download: "#{DOWNLOAD}#",
|
||||||
|
url: moduleRepoUrl,
|
||||||
|
version: systemPackage.version,
|
||||||
|
authors: [
|
||||||
|
{
|
||||||
|
name: "Copilot",
|
||||||
|
flags: {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
compatibility: systemManifest.compatibility,
|
||||||
|
relationships: {
|
||||||
|
requires: [
|
||||||
|
{
|
||||||
|
id: systemManifest.id,
|
||||||
|
type: "system",
|
||||||
|
compatibility: {
|
||||||
|
minimum: systemManifest.compatibility?.minimum ?? undefined,
|
||||||
|
verified: systemManifest.compatibility?.verified ?? undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
systems: [
|
||||||
|
{
|
||||||
|
id: systemManifest.id,
|
||||||
|
type: "system",
|
||||||
|
compatibility: {
|
||||||
|
minimum: systemManifest.compatibility?.minimum ?? undefined,
|
||||||
|
verified: systemManifest.compatibility?.verified ?? undefined,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
packs: (systemManifest.packs ?? []).map((pack) => ({
|
||||||
|
// The base content module only mirrors content packs, not system journals or utility packs.
|
||||||
|
...pack,
|
||||||
|
}))
|
||||||
|
.filter((pack) => contentPackNames.has(pack.name))
|
||||||
|
.map((pack) => ({
|
||||||
|
...pack,
|
||||||
|
name: `base-${pack.name}`,
|
||||||
|
path: `packs/base-${pack.name}`,
|
||||||
|
system: systemManifest.id,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(moduleManifestPath, `${JSON.stringify(moduleManifest, null, 2)}\n`)
|
||||||
|
}
|
||||||
|
|
||||||
|
function pruneStalePackDirectories(outputRoot, expectedDefinitions) {
|
||||||
|
if (!fs.existsSync(outputRoot)) return
|
||||||
|
const expected = new Set(expectedDefinitions.map((definition) => definition.outputFolder))
|
||||||
|
for (const entry of fs.readdirSync(outputRoot, { withFileTypes: true })) {
|
||||||
|
if (!entry.isDirectory()) continue
|
||||||
|
if (expected.has(entry.name)) continue
|
||||||
|
fs.rmSync(path.join(outputRoot, entry.name), { recursive: true, force: true })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function copyAndSanitizeSources() {
|
||||||
|
const summaries = []
|
||||||
|
const sourceFiles = fs.readdirSync(systemSourceRoot)
|
||||||
|
.filter((entry) => entry.endsWith(".json"))
|
||||||
|
.sort((left, right) => left.localeCompare(right, "fr"))
|
||||||
|
|
||||||
|
for (const fileName of sourceFiles) {
|
||||||
|
const systemSourcePath = path.join(systemSourceRoot, fileName)
|
||||||
|
const targetSourcePath = path.join(targetSourceRoot, fileName)
|
||||||
|
const rawText = fs.readFileSync(systemSourcePath, "utf8")
|
||||||
|
const systemJson = parseJsonArray(rawText, systemSourcePath)
|
||||||
|
const targetRawText = fs.existsSync(targetSourcePath) ? fs.readFileSync(targetSourcePath, "utf8") : null
|
||||||
|
const targetJson = targetRawText ? parseJsonArray(targetRawText, targetSourcePath) : null
|
||||||
|
const systemRichCount = systemJson.isArray ? countNonEmptyRichFields(systemJson.entries) : -1
|
||||||
|
const targetRichCount = targetJson?.isArray ? countNonEmptyRichFields(targetJson.entries) : -1
|
||||||
|
const authoritativeRawText = targetRichCount > systemRichCount ? targetRawText : rawText
|
||||||
|
|
||||||
|
fs.writeFileSync(targetSourcePath, authoritativeRawText)
|
||||||
|
|
||||||
|
if (!systemJson.isArray) {
|
||||||
|
summaries.push({ fileName, clearedFields: 0, copiedOnly: true })
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
const { sanitized, clearedFields } = sanitizeEntries(systemJson.entries)
|
||||||
|
fs.writeFileSync(systemSourcePath, `${JSON.stringify(sanitized, null, 2)}\n`)
|
||||||
|
summaries.push({ fileName, clearedFields, copiedOnly: false })
|
||||||
|
}
|
||||||
|
|
||||||
|
return summaries
|
||||||
|
}
|
||||||
|
|
||||||
|
ensureTargetModuleScaffold()
|
||||||
|
const summaries = copyAndSanitizeSources()
|
||||||
|
pruneStalePackDirectories(targetPacksRoot, basePackDefinitions)
|
||||||
|
|
||||||
|
await buildPacks({
|
||||||
|
sourceRoot: systemSourceRoot,
|
||||||
|
outputRoot: path.join(systemRoot, "packs"),
|
||||||
|
packDefinitions: SYSTEM_PACK_DEFINITIONS,
|
||||||
|
documentSystemId: systemManifest.id,
|
||||||
|
documentSystemVersion: systemPackage.version,
|
||||||
|
coreVersion,
|
||||||
|
})
|
||||||
|
|
||||||
|
await buildPacks({
|
||||||
|
sourceRoot: targetSourceRoot,
|
||||||
|
outputRoot: targetPacksRoot,
|
||||||
|
packDefinitions: basePackDefinitions,
|
||||||
|
documentSystemId: systemManifest.id,
|
||||||
|
documentSystemVersion: systemPackage.version,
|
||||||
|
coreVersion,
|
||||||
|
})
|
||||||
|
|
||||||
|
console.info(`Base module root: ${targetRoot}`)
|
||||||
|
|
||||||
|
for (const summary of summaries) {
|
||||||
|
if (summary.copiedOnly) {
|
||||||
|
console.info(`${summary.fileName}: copied as-is`)
|
||||||
|
} else {
|
||||||
|
console.info(`${summary.fileName}: cleared ${summary.clearedFields} rich fields in system source`)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,7 +5,8 @@
|
|||||||
"manifest": "https://www.uberwald.me/gitea/public/fvtt-les-oublies/raw/branch/main/system.json",
|
"manifest": "https://www.uberwald.me/gitea/public/fvtt-les-oublies/raw/branch/main/system.json",
|
||||||
"download": "#{DOWNLOAD}#",
|
"download": "#{DOWNLOAD}#",
|
||||||
"url": "https://www.uberwald.me/gitea/public/fvtt-les-oublies",
|
"url": "https://www.uberwald.me/gitea/public/fvtt-les-oublies",
|
||||||
"version": "0.1.0",
|
"background": "systems/fvtt-les-oublies/assets/ui/banniere_les_oublies.webp",
|
||||||
|
"version": "14.0.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Copilot",
|
"name": "Copilot",
|
||||||
@@ -234,6 +235,18 @@
|
|||||||
"PLAYER": "OBSERVER",
|
"PLAYER": "OBSERVER",
|
||||||
"ASSISTANT": "OWNER"
|
"ASSISTANT": "OWNER"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "JournalEntry",
|
||||||
|
"label": "Aide du système",
|
||||||
|
"name": "aide-systeme",
|
||||||
|
"path": "packs/aide-systeme",
|
||||||
|
"system": "fvtt-les-oublies",
|
||||||
|
"flags": {},
|
||||||
|
"ownership": {
|
||||||
|
"PLAYER": "OBSERVER",
|
||||||
|
"ASSISTANT": "OWNER"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"packFolders": [
|
"packFolders": [
|
||||||
@@ -249,7 +262,8 @@
|
|||||||
"races",
|
"races",
|
||||||
"tribus",
|
"tribus",
|
||||||
"metiers",
|
"metiers",
|
||||||
"sortileges"
|
"sortileges",
|
||||||
|
"aide-systeme"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,114 +0,0 @@
|
|||||||
<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">
|
|
||||||
<h1 class="sheet-title"><input name="name" type="text" value="{{actor.name}}" placeholder="Nom de compagnie" {{#if isPlayMode}}disabled{{/if}} /></h1>
|
|
||||||
<p class="sheet-subtitle">Capitaine, pouvoir partagé et liens forgés dans l'Exil</p>
|
|
||||||
<button class="mode-button" type="button" data-action="toggleSheet">{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}</button>
|
|
||||||
</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>
|
|
||||||
<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>
|
|
||||||
@@ -1,113 +0,0 @@
|
|||||||
<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">
|
|
||||||
<h1 class="sheet-title"><input name="name" type="text" value="{{actor.name}}" placeholder="Nom de compagnie" {{#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>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
<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>
|
|
||||||
@@ -29,6 +29,19 @@
|
|||||||
<label>{{localize "LESOUBLIES.labels.reserveSongesCompagnie"}}</label>
|
<label>{{localize "LESOUBLIES.labels.reserveSongesCompagnie"}}</label>
|
||||||
<input name="system.power.sharedDreamPoints" type="number" value="{{system.power.sharedDreamPoints}}" {{#if isPlayMode}}disabled{{/if}} />
|
<input name="system.power.sharedDreamPoints" type="number" value="{{system.power.sharedDreamPoints}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||||
</div>
|
</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">
|
<div class="field-row">
|
||||||
<label>{{localize "LESOUBLIES.labels.activation"}}</label>
|
<label>{{localize "LESOUBLIES.labels.activation"}}</label>
|
||||||
<input name="system.power.activationCondition" type="text" value="{{system.power.activationCondition}}" {{#if isPlayMode}}disabled{{/if}} />
|
<input name="system.power.activationCondition" type="text" value="{{system.power.activationCondition}}" {{#if isPlayMode}}disabled{{/if}} />
|
||||||
@@ -48,7 +61,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="item-list">
|
<div class="item-list">
|
||||||
{{#each powers as |item|}}
|
{{#each powers as |item|}}
|
||||||
<article class="item-card">
|
<article class="item-card" data-item-id="{{item.id}}" draggable="true">
|
||||||
<div><strong>{{item.name}}</strong><div>{{item.system.activationCondition}}</div></div>
|
<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>
|
<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>
|
</article>
|
||||||
@@ -1,115 +0,0 @@
|
|||||||
<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">
|
|
||||||
<p class="sheet-kicker">Blason de la compagnie</p>
|
|
||||||
<h1 class="sheet-title"><input name="name" type="text" value="{{actor.name}}" placeholder="Nom de compagnie" {{#if isPlayMode}}disabled{{/if}} /></h1>
|
|
||||||
<p class="sheet-subtitle">Capitaine, pouvoir partagé et liens forgés dans l'Exil</p>
|
|
||||||
<button class="mode-button" type="button" data-action="toggleSheet">{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}</button>
|
|
||||||
</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>
|
|
||||||
<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>
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
<section class="{{cssClass}} les-oublies-sheet creature-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">
|
|
||||||
<h1 class="sheet-title"><input name="name" type="text" value="{{actor.name}}" placeholder="Nom" {{#if isPlayMode}}disabled{{/if}} /></h1>
|
|
||||||
<p class="sheet-subtitle">Créatures du Petit Peuple, du Cauchemar et des frontières</p>
|
|
||||||
<div class="sheet-actions">
|
|
||||||
<button type="button" data-action="openRoll">{{localize "LESOUBLIES.rolls.test"}}</button>
|
|
||||||
<button type="button" data-action="openConfrontation">{{localize "LESOUBLIES.rolls.confrontation"}}</button>
|
|
||||||
<button type="button" data-action="openInitiative">{{localize "LESOUBLIES.rolls.initiative"}}</button>
|
|
||||||
<button type="button" data-action="openThreadHarvest">Récolte de fils</button>
|
|
||||||
<button class="mode-button" type="button" data-action="toggleSheet">{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}</button>
|
|
||||||
</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.categorie"}}</label><input name="system.biodata.categorie" type="text" value="{{system.biodata.categorie}}" {{#if isPlayMode}}disabled{{/if}} /></div>
|
|
||||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.taille"}}</label><select name="system.size.value" {{#if isPlayMode}}disabled{{/if}}>{{#each choiceSets.creatureSizeOptions 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.labels.hpAffichage"}}</label><input name="system.hp.display" type="text" value="{{system.hp.display}}" {{#if isPlayMode}}disabled{{/if}} /><span>{{derived.hpDisplay}}</span></div>
|
|
||||||
<div class="field-row"><label>Protection</label><input name="system.protection" type="number" value="{{system.protection}}" {{#if isPlayMode}}disabled{{/if}} /></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}} /></div>
|
|
||||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.pointsSonges"}}</label><input name="system.songes.points" type="number" value="{{system.songes.points}}" {{#if isPlayMode}}disabled{{/if}} /><span>/ {{system.songes.max}}</span></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}} /></div>
|
|
||||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.pointsCauchemar"}}</label><input name="system.cauchemar.points" type="number" value="{{system.cauchemar.points}}" {{#if isPlayMode}}disabled{{/if}} /><span>/ {{system.cauchemar.max}}</span></div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-card ledger-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.degats"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.damage enriched=enriched.statblock.damage value=system.statblock.damage name="system.statblock.damage" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.reglesSpeciales"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.special enriched=enriched.statblock.special value=system.statblock.special name="system.statblock.special" toggled=true}}
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-tab {{tabs.aptitudes.cssClass}}" data-tab="aptitudes">
|
|
||||||
<section class="sheet-card profiles-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.profilsOptionnels"}}</h2>
|
|
||||||
<div class="profile-grid">
|
|
||||||
{{#each system.profils as |value key|}}
|
|
||||||
<div class="profile-cell">
|
|
||||||
<button type="button" data-action="rollProfile" data-profile-key="{{key}}">{{profileLabel key}}</button>
|
|
||||||
<input name="system.profils.{{key}}" type="number" value="{{value}}" {{#if @root.isPlayMode}}disabled{{/if}} />
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-card 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>
|
|
||||||
{{#each skillGroups as |group|}}
|
|
||||||
{{#if (count group.items)}}
|
|
||||||
<div class="group-block">
|
|
||||||
<h3>{{group.label}}</h3>
|
|
||||||
<div class="item-list">
|
|
||||||
{{#each group.items as |entry|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div><strong>{{entry.item.name}}</strong><div>{{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</div></div>
|
|
||||||
<div class="item-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>
|
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-tab {{tabs.combat.cssClass}}" data-tab="combat">
|
|
||||||
<div class="sheet-grid sheet-grid-2">
|
|
||||||
<section class="sheet-card ledger-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.sortilegesSonges"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.spellSonges enriched=enriched.statblock.spellSonges value=system.statblock.spellSonges name="system.statblock.spellSonges" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.sortilegesCauchemar"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.spellCauchemar enriched=enriched.statblock.spellCauchemar value=system.statblock.spellCauchemar name="system.statblock.spellCauchemar" toggled=true}}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
<button type="button" data-action="createItem" data-type="sortilege">+ {{localize "TYPES.Item.sortilege"}}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="item-list">
|
|
||||||
{{#each weapons as |item|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div><strong>{{item.name}}</strong><div>{{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="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>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}}
|
|
||||||
{{#each spells as |item|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div><strong>{{item.name}}</strong><div>{{item.system.tradition}} / {{item.system.polarity}}</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.notes.cssClass}}" data-tab="notes">
|
|
||||||
<section class="sheet-card notes-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.description"}}</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.description enriched=enriched.biodata.description value=system.biodata.description name="system.biodata.description" toggled=true}}
|
|
||||||
<h2>Habitat</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.habitat enriched=enriched.biodata.habitat value=system.biodata.habitat name="system.biodata.habitat" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.notes"}}</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.notes enriched=enriched.biodata.notes value=system.biodata.notes name="system.biodata.notes" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.gmnotes"}}</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.gmnotes enriched=enriched.biodata.gmnotes value=system.biodata.gmnotes name="system.biodata.gmnotes" toggled=true}}
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
@@ -1,159 +0,0 @@
|
|||||||
<section class="{{cssClass}} les-oublies-sheet creature-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">
|
|
||||||
<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="openRoll">{{localize "LESOUBLIES.rolls.test"}}</button>
|
|
||||||
<button type="button" data-action="openConfrontation">{{localize "LESOUBLIES.rolls.confrontation"}}</button>
|
|
||||||
<button type="button" data-action="openInitiative">{{localize "LESOUBLIES.rolls.initiative"}}</button>
|
|
||||||
<button type="button" data-action="openThreadHarvest">Récolte de fils</button>
|
|
||||||
<button class="mode-button" type="button" data-action="toggleSheet">{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}</button>
|
|
||||||
</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.categorie"}}</label><input name="system.biodata.categorie" type="text" value="{{system.biodata.categorie}}" {{#if isPlayMode}}disabled{{/if}} /></div>
|
|
||||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.taille"}}</label><select name="system.size.value" {{#if isPlayMode}}disabled{{/if}}>{{#each choiceSets.creatureSizeOptions 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.labels.hpAffichage"}}</label><input name="system.hp.display" type="text" value="{{system.hp.display}}" {{#if isPlayMode}}disabled{{/if}} /><span>{{derived.hpDisplay}}</span></div>
|
|
||||||
<div class="field-row"><label>Protection</label><input name="system.protection" type="number" value="{{system.protection}}" {{#if isPlayMode}}disabled{{/if}} /></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}} /></div>
|
|
||||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.pointsSonges"}}</label><input name="system.songes.points" type="number" value="{{system.songes.points}}" {{#if isPlayMode}}disabled{{/if}} /><span>/ {{system.songes.max}}</span></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}} /></div>
|
|
||||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.pointsCauchemar"}}</label><input name="system.cauchemar.points" type="number" value="{{system.cauchemar.points}}" {{#if isPlayMode}}disabled{{/if}} /><span>/ {{system.cauchemar.max}}</span></div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-card ledger-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.degats"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.damage enriched=enriched.statblock.damage value=system.statblock.damage name="system.statblock.damage" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.reglesSpeciales"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.special enriched=enriched.statblock.special value=system.statblock.special name="system.statblock.special" toggled=true}}
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-tab {{tabs.aptitudes.cssClass}}" data-tab="aptitudes">
|
|
||||||
<section class="sheet-card profiles-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.profilsOptionnels"}}</h2>
|
|
||||||
<div class="profile-grid">
|
|
||||||
{{#each system.profils as |value key|}}
|
|
||||||
<div class="profile-cell">
|
|
||||||
<button type="button" data-action="rollProfile" data-profile-key="{{key}}">{{profileLabel key}}</button>
|
|
||||||
<input name="system.profils.{{key}}" type="number" value="{{value}}" {{#if @root.isPlayMode}}disabled{{/if}} />
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-card 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>
|
|
||||||
{{#each skillGroups as |group|}}
|
|
||||||
{{#if (count group.items)}}
|
|
||||||
<div class="group-block">
|
|
||||||
<h3>{{group.label}}</h3>
|
|
||||||
<div class="item-list">
|
|
||||||
{{#each group.items as |entry|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div><strong>{{entry.item.name}}</strong><div>{{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</div></div>
|
|
||||||
<div class="item-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>
|
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-tab {{tabs.combat.cssClass}}" data-tab="combat">
|
|
||||||
<div class="sheet-grid sheet-grid-2">
|
|
||||||
<section class="sheet-card ledger-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.sortilegesSonges"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.spellSonges enriched=enriched.statblock.spellSonges value=system.statblock.spellSonges name="system.statblock.spellSonges" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.sortilegesCauchemar"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.spellCauchemar enriched=enriched.statblock.spellCauchemar value=system.statblock.spellCauchemar name="system.statblock.spellCauchemar" toggled=true}}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
<button type="button" data-action="createItem" data-type="sortilege">+ {{localize "TYPES.Item.sortilege"}}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="item-list">
|
|
||||||
{{#each weapons as |item|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div><strong>{{item.name}}</strong><div>{{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="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>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}}
|
|
||||||
{{#each spells as |item|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div><strong>{{item.name}}</strong><div>{{item.system.tradition}} / {{item.system.polarity}}</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.notes.cssClass}}" data-tab="notes">
|
|
||||||
<section class="sheet-card notes-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.description"}}</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.description enriched=enriched.biodata.description value=system.biodata.description name="system.biodata.description" toggled=true}}
|
|
||||||
<h2>Habitat</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.habitat enriched=enriched.biodata.habitat value=system.biodata.habitat name="system.biodata.habitat" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.notes"}}</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.notes enriched=enriched.biodata.notes value=system.biodata.notes name="system.biodata.notes" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.gmnotes"}}</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.gmnotes enriched=enriched.biodata.gmnotes value=system.biodata.gmnotes name="system.biodata.gmnotes" toggled=true}}
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
<section class="{{cssClass}} les-oublies-sheet creature-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="openRoll">{{localize "LESOUBLIES.rolls.test"}}</button>
|
|
||||||
<button type="button" data-action="openConfrontation">{{localize "LESOUBLIES.rolls.confrontation"}}</button>
|
|
||||||
<button type="button" data-action="openInitiative">{{localize "LESOUBLIES.rolls.initiative"}}</button>
|
|
||||||
<button type="button" data-action="openThreadHarvest">Récolte de fils</button>
|
|
||||||
</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.categorie"}}</label><input name="system.biodata.categorie" type="text" value="{{system.biodata.categorie}}" {{#if isPlayMode}}disabled{{/if}} /></div>
|
|
||||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.taille"}}</label><select name="system.size.value" {{#if isPlayMode}}disabled{{/if}}>{{#each choiceSets.creatureSizeOptions 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.labels.hpAffichage"}}</label><input name="system.hp.display" type="text" value="{{system.hp.display}}" {{#if isPlayMode}}disabled{{/if}} /><span>{{derived.hpDisplay}}</span></div>
|
|
||||||
<div class="field-row"><label>Protection</label><input name="system.protection" type="number" value="{{system.protection}}" {{#if isPlayMode}}disabled{{/if}} /></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}} /></div>
|
|
||||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.pointsSonges"}}</label><input name="system.songes.points" type="number" value="{{system.songes.points}}" {{#if isPlayMode}}disabled{{/if}} /><span>/ {{system.songes.max}}</span></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}} /></div>
|
|
||||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.pointsCauchemar"}}</label><input name="system.cauchemar.points" type="number" value="{{system.cauchemar.points}}" {{#if isPlayMode}}disabled{{/if}} /><span>/ {{system.cauchemar.max}}</span></div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-card ledger-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.degats"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.damage enriched=enriched.statblock.damage value=system.statblock.damage name="system.statblock.damage" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.reglesSpeciales"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.special enriched=enriched.statblock.special value=system.statblock.special name="system.statblock.special" toggled=true}}
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-tab {{tabs.aptitudes.cssClass}}" data-tab="aptitudes">
|
|
||||||
<section class="sheet-card profiles-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.profilsOptionnels"}}</h2>
|
|
||||||
<div class="profile-grid">
|
|
||||||
{{#each system.profils as |value key|}}
|
|
||||||
<div class="profile-cell">
|
|
||||||
<button type="button" data-action="rollProfile" data-profile-key="{{key}}">{{profileLabel key}}</button>
|
|
||||||
<input name="system.profils.{{key}}" type="number" value="{{value}}" {{#if @root.isPlayMode}}disabled{{/if}} />
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-card 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>
|
|
||||||
{{#each skillGroups as |group|}}
|
|
||||||
{{#if (count group.items)}}
|
|
||||||
<div class="group-block">
|
|
||||||
<h3>{{group.label}}</h3>
|
|
||||||
<div class="item-list">
|
|
||||||
{{#each group.items as |entry|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div><strong>{{entry.item.name}}</strong><div>{{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</div></div>
|
|
||||||
<div class="item-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>
|
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-tab {{tabs.combat.cssClass}}" data-tab="combat">
|
|
||||||
<div class="sheet-grid sheet-grid-2">
|
|
||||||
<section class="sheet-card ledger-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.sortilegesSonges"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.spellSonges enriched=enriched.statblock.spellSonges value=system.statblock.spellSonges name="system.statblock.spellSonges" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.sortilegesCauchemar"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.spellCauchemar enriched=enriched.statblock.spellCauchemar value=system.statblock.spellCauchemar name="system.statblock.spellCauchemar" toggled=true}}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
<button type="button" data-action="createItem" data-type="sortilege">+ {{localize "TYPES.Item.sortilege"}}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="item-list">
|
|
||||||
{{#each weapons as |item|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div><strong>{{item.name}}</strong><div>{{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="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>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}}
|
|
||||||
{{#each spells as |item|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div><strong>{{item.name}}</strong><div>{{item.system.tradition}} / {{item.system.polarity}}</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.notes.cssClass}}" data-tab="notes">
|
|
||||||
<section class="sheet-card notes-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.description"}}</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.description enriched=enriched.biodata.description value=system.biodata.description name="system.biodata.description" toggled=true}}
|
|
||||||
<h2>Habitat</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.habitat enriched=enriched.biodata.habitat value=system.biodata.habitat name="system.biodata.habitat" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.notes"}}</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.notes enriched=enriched.biodata.notes value=system.biodata.notes name="system.biodata.notes" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.gmnotes"}}</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.gmnotes enriched=enriched.biodata.gmnotes value=system.biodata.gmnotes name="system.biodata.gmnotes" toggled=true}}
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
@@ -70,7 +70,7 @@
|
|||||||
<h3>{{group.label}}</h3>
|
<h3>{{group.label}}</h3>
|
||||||
<div class="item-list">
|
<div class="item-list">
|
||||||
{{#each group.items as |entry|}}
|
{{#each group.items as |entry|}}
|
||||||
<article class="item-card">
|
<article class="item-card" data-item-id="{{entry.item.id}}" draggable="true">
|
||||||
<div><strong>{{entry.item.name}}</strong><div>{{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</div></div>
|
<div><strong>{{entry.item.name}}</strong><div>{{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</div></div>
|
||||||
<div class="item-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>
|
<div class="item-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>
|
</article>
|
||||||
@@ -117,25 +117,25 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="item-list">
|
<div class="item-list">
|
||||||
{{#each weapons as |item|}}
|
{{#each weapons as |item|}}
|
||||||
<article class="item-card">
|
<article class="item-card" data-item-id="{{item.id}}" draggable="true">
|
||||||
<div><strong>{{item.name}}</strong><div>{{item.system.damage}}</div></div>
|
<div><strong>{{item.name}}</strong><div>{{item.displayDamage}}</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="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></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="editItem" data-item-id="{{item.id}}">Edit</button><button type="button" data-action="deleteItem" data-item-id="{{item.id}}">Delete</button></div>
|
||||||
</article>
|
</article>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{#each armors as |item|}}
|
{{#each armors as |item|}}
|
||||||
<article class="item-card">
|
<article class="item-card" data-item-id="{{item.id}}" draggable="true">
|
||||||
<div><strong>{{item.name}}</strong><div>Prot {{item.system.protection}}</div></div>
|
<div><strong>{{item.name}}</strong><div>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>
|
<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>
|
</article>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{#each equipment as |item|}}
|
{{#each equipment as |item|}}
|
||||||
<article class="item-card">
|
<article class="item-card" data-item-id="{{item.id}}" draggable="true">
|
||||||
<div><strong>{{item.name}}</strong><div>{{localize "TYPES.Item.equipement"}} - {{item.system.category}}</div></div>
|
<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>
|
<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>
|
</article>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
{{#each spells as |item|}}
|
{{#each spells as |item|}}
|
||||||
<article class="item-card">
|
<article class="item-card" data-item-id="{{item.id}}" draggable="true">
|
||||||
<div><strong>{{item.name}}</strong><div>{{item.system.tradition}} / {{item.system.polarity}}</div></div>
|
<div><strong>{{item.name}}</strong><div>{{item.system.tradition}} / {{item.system.polarity}}</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>
|
<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>
|
</article>
|
||||||
|
|||||||
@@ -1,161 +0,0 @@
|
|||||||
<section class="{{cssClass}} les-oublies-sheet creature-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">
|
|
||||||
<p class="sheet-kicker">Bestiaire de la Terra</p>
|
|
||||||
<h1 class="sheet-title"><input name="name" type="text" value="{{actor.name}}" placeholder="Nom" {{#if isPlayMode}}disabled{{/if}} /></h1>
|
|
||||||
<p class="sheet-subtitle">Créatures du Petit Peuple, du Cauchemar et des frontières</p>
|
|
||||||
<div class="sheet-actions">
|
|
||||||
<button type="button" data-action="openRoll">{{localize "LESOUBLIES.rolls.test"}}</button>
|
|
||||||
<button type="button" data-action="openConfrontation">{{localize "LESOUBLIES.rolls.confrontation"}}</button>
|
|
||||||
<button type="button" data-action="openInitiative">{{localize "LESOUBLIES.rolls.initiative"}}</button>
|
|
||||||
<button type="button" data-action="openThreadHarvest">Récolte de fils</button>
|
|
||||||
<button class="mode-button" type="button" data-action="toggleSheet">{{#if isEditMode}}{{localize "LESOUBLIES.ui.playMode"}}{{else}}{{localize "LESOUBLIES.ui.editMode"}}{{/if}}</button>
|
|
||||||
</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.categorie"}}</label><input name="system.biodata.categorie" type="text" value="{{system.biodata.categorie}}" {{#if isPlayMode}}disabled{{/if}} /></div>
|
|
||||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.taille"}}</label><select name="system.size.value" {{#if isPlayMode}}disabled{{/if}}>{{#each choiceSets.creatureSizeOptions 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.labels.hpAffichage"}}</label><input name="system.hp.display" type="text" value="{{system.hp.display}}" {{#if isPlayMode}}disabled{{/if}} /><span>{{derived.hpDisplay}}</span></div>
|
|
||||||
<div class="field-row"><label>Protection</label><input name="system.protection" type="number" value="{{system.protection}}" {{#if isPlayMode}}disabled{{/if}} /></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}} /></div>
|
|
||||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.pointsSonges"}}</label><input name="system.songes.points" type="number" value="{{system.songes.points}}" {{#if isPlayMode}}disabled{{/if}} /><span>/ {{system.songes.max}}</span></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}} /></div>
|
|
||||||
<div class="field-row"><label>{{localize "LESOUBLIES.labels.pointsCauchemar"}}</label><input name="system.cauchemar.points" type="number" value="{{system.cauchemar.points}}" {{#if isPlayMode}}disabled{{/if}} /><span>/ {{system.cauchemar.max}}</span></div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-card ledger-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.degats"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.damage enriched=enriched.statblock.damage value=system.statblock.damage name="system.statblock.damage" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.reglesSpeciales"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.special enriched=enriched.statblock.special value=system.statblock.special name="system.statblock.special" toggled=true}}
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-tab {{tabs.aptitudes.cssClass}}" data-tab="aptitudes">
|
|
||||||
<section class="sheet-card profiles-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.profilsOptionnels"}}</h2>
|
|
||||||
<div class="profile-grid">
|
|
||||||
{{#each system.profils as |value key|}}
|
|
||||||
<div class="profile-cell">
|
|
||||||
<button type="button" data-action="rollProfile" data-profile-key="{{key}}">{{profileLabel key}}</button>
|
|
||||||
<input name="system.profils.{{key}}" type="number" value="{{value}}" {{#if @root.isPlayMode}}disabled{{/if}} />
|
|
||||||
</div>
|
|
||||||
{{/each}}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-card 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>
|
|
||||||
{{#each skillGroups as |group|}}
|
|
||||||
{{#if (count group.items)}}
|
|
||||||
<div class="group-block">
|
|
||||||
<h3>{{group.label}}</h3>
|
|
||||||
<div class="item-list">
|
|
||||||
{{#each group.items as |entry|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div><strong>{{entry.item.name}}</strong><div>{{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</div></div>
|
|
||||||
<div class="item-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>
|
|
||||||
{{/if}}
|
|
||||||
{{/each}}
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-tab {{tabs.combat.cssClass}}" data-tab="combat">
|
|
||||||
<div class="sheet-grid sheet-grid-2">
|
|
||||||
<section class="sheet-card ledger-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.sortilegesSonges"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.spellSonges enriched=enriched.statblock.spellSonges value=system.statblock.spellSonges name="system.statblock.spellSonges" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.sortilegesCauchemar"}}</h2>
|
|
||||||
{{formInput systemFields.statblock.fields.spellCauchemar enriched=enriched.statblock.spellCauchemar value=system.statblock.spellCauchemar name="system.statblock.spellCauchemar" toggled=true}}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<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>
|
|
||||||
<button type="button" data-action="createItem" data-type="sortilege">+ {{localize "TYPES.Item.sortilege"}}</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="item-list">
|
|
||||||
{{#each weapons as |item|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div><strong>{{item.name}}</strong><div>{{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="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>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}}
|
|
||||||
{{#each spells as |item|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div><strong>{{item.name}}</strong><div>{{item.system.tradition}} / {{item.system.polarity}}</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.notes.cssClass}}" data-tab="notes">
|
|
||||||
<section class="sheet-card notes-card">
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.description"}}</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.description enriched=enriched.biodata.description value=system.biodata.description name="system.biodata.description" toggled=true}}
|
|
||||||
<h2>Habitat</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.habitat enriched=enriched.biodata.habitat value=system.biodata.habitat name="system.biodata.habitat" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.notes"}}</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.notes enriched=enriched.biodata.notes value=system.biodata.notes name="system.biodata.notes" toggled=true}}
|
|
||||||
<h2>{{localize "LESOUBLIES.labels.gmnotes"}}</h2>
|
|
||||||
{{formInput systemFields.biodata.fields.gmnotes enriched=enriched.biodata.gmnotes value=system.biodata.gmnotes name="system.biodata.gmnotes" toggled=true}}
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
@@ -1,279 +0,0 @@
|
|||||||
<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.ui.creation"}}</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>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section class="sheet-tab {{tabs.skills.cssClass}}" data-tab="skills">
|
|
||||||
<section class="sheet-card 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>
|
|
||||||
{{#each skillGroups as |group|}}
|
|
||||||
<div class="group-block">
|
|
||||||
<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">
|
|
||||||
{{#each group.items as |entry|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div>
|
|
||||||
<strong>{{entry.item.name}}</strong>
|
|
||||||
<div>Base {{entry.item.system.base}} + {{group.label}} {{group.profileValue}} - {{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="item-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}}
|
|
||||||
</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}}
|
|
||||||
{{#if activeCompanyPower}}
|
|
||||||
<label>{{localize "LESOUBLIES.labels.pouvoirCompagnieActif"}}</label>
|
|
||||||
<div class="help-text">{{activeCompanyPower.name}} — {{activeCompanyPower.system.activationCondition}}</div>
|
|
||||||
{{/if}}
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
@@ -1,284 +0,0 @@
|
|||||||
<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 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">
|
|
||||||
<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>
|
|
||||||
{{#each skillGroups as |group|}}
|
|
||||||
<div class="group-block">
|
|
||||||
<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">
|
|
||||||
{{#each group.items as |entry|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div>
|
|
||||||
<strong>{{entry.item.name}}</strong>
|
|
||||||
<div>Base {{entry.item.system.base}} + {{group.label}} {{group.profileValue}} - {{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="item-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}}
|
|
||||||
</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}}
|
|
||||||
{{#if activeCompanyPower}}
|
|
||||||
<label>{{localize "LESOUBLIES.labels.pouvoirCompagnieActif"}}</label>
|
|
||||||
<div class="help-text">{{activeCompanyPower.name}} — {{activeCompanyPower.system.activationCondition}}</div>
|
|
||||||
{{/if}}
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
<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">
|
|
||||||
<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>
|
|
||||||
{{#each skillGroups as |group|}}
|
|
||||||
<div class="group-block">
|
|
||||||
<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">
|
|
||||||
{{#each group.items as |entry|}}
|
|
||||||
<article class="item-card">
|
|
||||||
<div>
|
|
||||||
<strong>{{entry.item.name}}</strong>
|
|
||||||
<div>Base {{entry.item.system.base}} + {{group.label}} {{group.profileValue}} - {{localize "LESOUBLIES.labels.valeurFinale"}} {{entry.finalValue}}</div>
|
|
||||||
</div>
|
|
||||||
<div class="item-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}}
|
|
||||||
</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>
|
|
||||||
@@ -1,283 +0,0 @@
|
|||||||
<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>
|
|
||||||
{{#each skillGroups 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}}
|
|
||||||
</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>
|
|
||||||