feat: tirage MJ, hotbarDrop, blessures incapacitantes
1. Tirage MJ dans le dialogue de compétence : - Bouton tirer une carte dans la section difficulté - Pioche dans le deck, affiche la carte tirée - Calcule la difficulté sous tension 2. Drag & drop vers barre de raccourcis : - Acteurs → ouvre la feuille - Compétences → lance le jet de compétence - Sorts → ouvre le dialogue de lancement - Armes → lance le jet d'arme 3. Blessures incapacitantes (règle p.159) : - Champs blessureIncapacitante / malusBlessure - Dialogue proposant la blessure quand Épée diminue - Malus -2 appliqué aux jets de compétence - Bannière dans la feuille (mode jeu) - Bouton guérison
This commit is contained in:
+35
-8
@@ -243,15 +243,42 @@ Hooks.on("createChatMessage", async (message, options, userId) => {
|
||||
})
|
||||
|
||||
|
||||
/**
|
||||
* Create a macro when dropping an entity on the hotbar
|
||||
* Item - open roll dialog
|
||||
* Actor - open actor sheet
|
||||
* Journal - open journal sheet
|
||||
*/
|
||||
Hooks.on("hotbarDrop", (bar, data, slot) => {
|
||||
if (["Actor", "Item", "JournalEntry", "skill", "weapon"].includes(data.type)) {
|
||||
// TODO -> Manage this
|
||||
if (data.type === "Actor") {
|
||||
const actor = fromUuidSync(data.uuid)
|
||||
if (!actor) return false
|
||||
Macro.create({
|
||||
name: actor.name,
|
||||
type: "script",
|
||||
img: actor.img,
|
||||
command: `game.actors.get("${actor.id}")?.sheet?.render(true)`,
|
||||
scope: "global",
|
||||
}).then(macro => bar.assignMacro(macro, slot))
|
||||
return false
|
||||
}
|
||||
if (data.type === "Item") {
|
||||
const item = fromUuidSync(data.uuid)
|
||||
if (!item) return false
|
||||
const actor = item.parent
|
||||
let command = ""
|
||||
if (item.type === "competence") {
|
||||
command = `const a = game.actors.get("${actor?.id}"); const i = a?.items?.get("${item.id}"); if (i) a?.system?.roll?.("competence", i)`
|
||||
} else if (item.type === "sortilege") {
|
||||
command = `const { default: Cast } = await import("${game.system.id}/module/applications/sortilege-casting.mjs"); const a = game.actors.get("${actor?.id}"); const i = a?.items?.get("${item.id}"); if (i) Cast.prompt(i, a)`
|
||||
} else if (item.type === "arme") {
|
||||
command = `const a = game.actors.get("${actor?.id}"); const i = a?.items?.get("${item.id}"); if (i) a?.system?.roll?.("weapon", i)`
|
||||
} else {
|
||||
command = `const a = game.actors.get("${actor?.id}"); a?.items?.get("${item.id}")?.sheet?.render(true)`
|
||||
}
|
||||
if (command) {
|
||||
Macro.create({
|
||||
name: item.name,
|
||||
type: "script",
|
||||
img: item.img,
|
||||
command,
|
||||
scope: "actor",
|
||||
}).then(macro => bar.assignMacro(macro, slot))
|
||||
}
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
+13
-2
@@ -640,7 +640,8 @@
|
||||
"cancel": "Annuler",
|
||||
"roll": "Lancer l'épreuve",
|
||||
"rollCompetence": "Jet de compétence",
|
||||
"skill": "Compétence"
|
||||
"skill": "Compétence",
|
||||
"drawCard": "Tirer une carte"
|
||||
},
|
||||
"Tarot": {
|
||||
"FIELDS": {
|
||||
@@ -843,6 +844,16 @@
|
||||
"Initiative": {
|
||||
"Title": "Initiative",
|
||||
"Value": "Valeur"
|
||||
}
|
||||
},
|
||||
"Wound": {
|
||||
"Title": "Blessure incapacitante",
|
||||
"Question": "Vous allez perdre 1 point de Résistance Épée. Voulez-vous plutôt subir une blessure incapacitante (membre cassé, -2 aux actions physiques) ?",
|
||||
"Take": "Subir la blessure",
|
||||
"Resist": "Perdre le point",
|
||||
"Active": "Blessure incapacitante active",
|
||||
"Remove": "Guérir la blessure",
|
||||
"RemoveConfirm": "La blessure est-elle guérie ? Cela restaurera vos capacités physiques.",
|
||||
"Healed": "Blessure guérie !"
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ export default class HamalronPersonnageSheet extends HamalronActorSheet {
|
||||
createSortilege: HamalronPersonnageSheet.#onCreateSortilege,
|
||||
openRecovery: HamalronPersonnageSheet.#onOpenRecovery,
|
||||
modifyResistance: HamalronPersonnageSheet.#onModifyResistance,
|
||||
removeWound: HamalronPersonnageSheet.#onRemoveWound,
|
||||
discardCard: HamalronPersonnageSheet.#onDiscardCard,
|
||||
rollCompetence: HamalronPersonnageSheet.#onRollCompetence,
|
||||
castSortilege: HamalronPersonnageSheet.#onCastSortilege,
|
||||
@@ -195,9 +196,46 @@ export default class HamalronPersonnageSheet extends HamalronActorSheet {
|
||||
}
|
||||
|
||||
const newValue = Math.max(0, Math.min(resistance.max, resistance.value + delta))
|
||||
|
||||
// Blessure incapacitante pour Épée (règle p.159)
|
||||
if (symbole === "epee" && delta < 0 && newValue < resistance.value && !this.document.system.blessureIncapacitante) {
|
||||
const choice = await foundry.applications.api.DialogV2.wait({
|
||||
window: { title: game.i18n.localize("HAMALRON.Wound.Title") },
|
||||
content: `<p>${game.i18n.localize("HAMALRON.Wound.Question")}</p>`,
|
||||
buttons: [
|
||||
{ action: "wound", label: game.i18n.localize("HAMALRON.Wound.Take"), default: true, callback: () => "wound" },
|
||||
{ action: "resist", label: game.i18n.localize("HAMALRON.Wound.Resist"), callback: () => "resist" },
|
||||
],
|
||||
rejectClose: false,
|
||||
})
|
||||
if (choice === "wound") {
|
||||
await this.document.update({
|
||||
"system.blessureIncapacitante": true,
|
||||
"system.malusBlessure": -2,
|
||||
})
|
||||
ui.notifications.info(game.i18n.localize("HAMALRON.Wound.Active"))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
await this.document.update({ [`system.resistances.${symbole}.value`]: newValue })
|
||||
}
|
||||
|
||||
static async #onRemoveWound(event, target) {
|
||||
const confirmed = await foundry.applications.api.DialogV2.confirm({
|
||||
window: { title: game.i18n.localize("HAMALRON.Wound.Remove") },
|
||||
content: `<p>${game.i18n.localize("HAMALRON.Wound.RemoveConfirm")}</p>`,
|
||||
rejectClose: false,
|
||||
modal: true,
|
||||
})
|
||||
if (!confirmed) return
|
||||
await this.document.update({
|
||||
"system.blessureIncapacitante": false,
|
||||
"system.malusBlessure": 0,
|
||||
})
|
||||
ui.notifications.info(game.i18n.localize("HAMALRON.Wound.Healed"))
|
||||
}
|
||||
|
||||
static async #onDiscardCard(event, target) {
|
||||
const itemId = $(event.target).data("item-id")
|
||||
const item = this.document.items.get(itemId)
|
||||
|
||||
@@ -104,6 +104,9 @@ export default class HamalronTirageTarot extends Roll {
|
||||
// Récupérer le modificateur de compétence depuis NIVEAU_COMPETENCES
|
||||
const niveauData = SYSTEM.NIVEAU_COMPETENCES[options.rollItem.system.niveau]
|
||||
options.competenceModifier = niveauData ? niveauData.modificateur : 0
|
||||
if (actor.system.malusBlessure) {
|
||||
options.competenceModifier += actor.system.malusBlessure
|
||||
}
|
||||
|
||||
// Marquer les cartes de succès
|
||||
if (options.tarotCards && actor.system.cartesSucces) {
|
||||
@@ -266,7 +269,6 @@ export default class HamalronTirageTarot extends Roll {
|
||||
const difficultyData = SYSTEM.DIFFICULTY_CHOICES[difficultyKey]
|
||||
|
||||
if (difficultyData.standard === null) {
|
||||
// Sous tension ou opposé - pas de score cible
|
||||
options.targetScore = null
|
||||
$("#target-score").text("-")
|
||||
} else {
|
||||
@@ -275,6 +277,29 @@ export default class HamalronTirageTarot extends Roll {
|
||||
}
|
||||
})
|
||||
|
||||
// Tirage d'une carte pour la difficulté (épreuve sous tension)
|
||||
$("#draw-difficulty-btn").click(async function () {
|
||||
const deckManager = globalThis.HamalronTarotDeckManager?._instance
|
||||
if (!deckManager || deckManager.deck.length === 0) {
|
||||
ui.notifications.warn(game.i18n.localize("HAMALRON.Notifications.deckEmpty"))
|
||||
return
|
||||
}
|
||||
const drawn = deckManager.drawCards(1)
|
||||
if (drawn.length > 0) {
|
||||
const card = drawn[0]
|
||||
const valData = SYSTEM.TAROT_VALEURS[card.valeur]
|
||||
const val = valData?.value ?? 0
|
||||
options.targetScore = val
|
||||
options.selectedDifficulty = "soustension_oppose"
|
||||
$(".difficulty-select").val("soustension_oppose")
|
||||
$("#target-score").text(String(val))
|
||||
$("#drawn-card-name").text(`${card.name} (${val})`)
|
||||
$("#drawn-card-info").show()
|
||||
deckManager.addToDiscard(card)
|
||||
await deckManager.saveDeckState()
|
||||
}
|
||||
})
|
||||
|
||||
$(".tarot-card-select").click(function () {
|
||||
// Désélectionner toutes les cartes
|
||||
$(".tarot-card-select").removeClass("selected")
|
||||
|
||||
@@ -34,8 +34,10 @@ export default class HamalronPersonnage extends foundry.abstract.TypeDataModel {
|
||||
|
||||
schema.historial = new fields.HTMLField({ required: true, textSearch: true })
|
||||
schema.progression = new fields.NumberField({ ...requiredInteger, initial: 0, min: 0 })
|
||||
schema.rangMagie = new fields.StringField({ required: true, initial: "initie", choices: Object.fromEntries(Object.entries(SYSTEM.RANG_MAGICIEN).map(([key, val]) => [key, val.label])) })
|
||||
schema.rangMagie = new fields.StringField({ required: true, initial: "initie", choices: Object.fromEntries(Object.entries(SYSTEM.RANG_MAGICIEN).map(([key, val]) => [key, val.name])) })
|
||||
schema.resistanceRecovery = new fields.ObjectField({ required: false, initial: {} })
|
||||
schema.blessureIncapacitante = new fields.BooleanField({ required: true, initial: false })
|
||||
schema.malusBlessure = new fields.NumberField({ required: true, integer: true, initial: 0, min: -8, max: 0 })
|
||||
|
||||
schema.biodata = new fields.SchemaField({
|
||||
age: new fields.StringField({ required: true, nullable: false, initial: "" }),
|
||||
|
||||
@@ -191,6 +191,16 @@
|
||||
{{/each}}
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
{{#if (and system.blessureIncapacitante isPlayMode)}}
|
||||
<div class="wound-banner">
|
||||
<i class="fas fa-bandage"></i>
|
||||
{{localize "HAMALRON.Wound.Active"}} ({{system.malusBlessure}})
|
||||
<a class="control" data-action="removeWound" data-tooltip="{{localize 'HAMALRON.Wound.Remove'}}">
|
||||
<i class="fa-solid fa-check"></i>
|
||||
</a>
|
||||
</div>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
@@ -63,13 +63,21 @@
|
||||
|
||||
<fieldSet>
|
||||
<legend>{{localize "HAMALRON.Label.difficulty"}}</legend>
|
||||
<select name="difficulty" class="difficulty-select">
|
||||
<div class="difficulty-row">
|
||||
<select name="difficulty" class="difficulty-select" style="flex:1">
|
||||
{{selectOptions
|
||||
difficultyChoices
|
||||
selected="soustension_oppose"
|
||||
localize=false
|
||||
}}
|
||||
</select>
|
||||
<button type="button" id="draw-difficulty-btn" class="draw-difficulty-btn" title="{{localize 'HAMALRON.Roll.drawCard'}}">
|
||||
<i class="fas fa-cards"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div id="drawn-card-info" class="drawn-card-info" style="display:none">
|
||||
<span id="drawn-card-name"></span>
|
||||
</div>
|
||||
</fieldSet>
|
||||
|
||||
<fieldSet class="dialog-result">
|
||||
|
||||
Reference in New Issue
Block a user