feat: Health and Resolve rollable saves
Click the Health or Resolve label to roll a save using the current value as the dice pool (plain d6, no stress, no dialog). Zero successes adds +1 Stress. Chat card uses standard yze-die styling.
This commit is contained in:
@@ -257,6 +257,15 @@
|
||||
letter-spacing: 0.8px;
|
||||
}
|
||||
|
||||
.zero-engine .vital-save-label {
|
||||
cursor: pointer;
|
||||
transition: opacity 0.15s;
|
||||
}
|
||||
.zero-engine .vital-save-label:hover {
|
||||
opacity: 0.75;
|
||||
text-decoration: underline dotted;
|
||||
}
|
||||
|
||||
.zero-engine .vital-values {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
{{!-- VITALS ROW: Health, Resolve, Stress, Ebb --}}
|
||||
<div class="header-vitals-row">
|
||||
<div class="vital-box health-box">
|
||||
<label>Health</label>
|
||||
<label class="vital-save-label" data-save-type="health" title="Click to roll Health Save (no successes = +1 Stress)">Health</label>
|
||||
<div class="vital-values">
|
||||
<input type="number" name="system.derivedStats.health.value" value="{{system.derivedStats.health.value}}" />
|
||||
<span class="vital-separator">/</span>
|
||||
@@ -117,7 +117,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="vital-box resolve-box">
|
||||
<label>Resolve</label>
|
||||
<label class="vital-save-label" data-save-type="resolve" title="Click to roll Resolve Save (no successes = +1 Stress)">Resolve</label>
|
||||
<div class="vital-values">
|
||||
<input type="number" name="system.derivedStats.resolve.value" value="{{system.derivedStats.resolve.value}}" />
|
||||
<span class="vital-separator">/</span>
|
||||
|
||||
@@ -455,6 +455,9 @@ class ZeroEngineActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
html.find('.manual-panic-button').click(this._onManualPanic.bind(this));
|
||||
html.find('.manual-armor-button').click(this._onManualArmorCheck.bind(this));
|
||||
|
||||
// Health / Resolve save rolls — click the vital label name
|
||||
html.find('.vital-save-label').click(this._onVitalSave.bind(this));
|
||||
|
||||
// Delete injury buttons
|
||||
html.find('.delete-injury-btn').click(this._onDeleteInjury.bind(this));
|
||||
|
||||
@@ -1214,6 +1217,64 @@ class ZeroEngineActorSheet extends foundry.appv1.sheets.ActorSheet {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Health or Resolve save roll — clicking the vital label name.
|
||||
* Rolls current value in plain d6 (no stress dice, no dialog).
|
||||
* A failure (zero successes) adds +1 Stress.
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
async _onVitalSave(event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
|
||||
const saveType = event.currentTarget.dataset.saveType; // "health" or "resolve"
|
||||
const label = saveType === "health" ? "Health Save" : "Resolve Save";
|
||||
const current = Number(this.actor.system.derivedStats?.[saveType]?.value) || 0;
|
||||
|
||||
if (current <= 0) {
|
||||
ui.notifications.warn(`${this.actor.name} has no ${saveType} remaining — cannot make a ${label}.`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Roll current value in d6 — no stress dice, no dialog
|
||||
const roll = new Roll(`${current}d6`);
|
||||
await roll.evaluate();
|
||||
|
||||
if (game.dice3d) await game.dice3d.showForRoll(roll, game.user, true);
|
||||
|
||||
const results = roll.dice[0]?.results || [];
|
||||
const successes = results.filter(r => r.result === 6).length;
|
||||
const failed = successes === 0;
|
||||
|
||||
// Build dice display using existing yze-die classes
|
||||
const diceHtml = results.map(r => {
|
||||
let cls = 'yze-die';
|
||||
if (r.result === 6) cls += ' yze-success';
|
||||
return `<div class="${cls}">${r.result}</div>`;
|
||||
}).join('');
|
||||
|
||||
let resultLine;
|
||||
if (failed) {
|
||||
const curStress = this._getStressValue(this.actor);
|
||||
const newStress = Math.min(10, curStress + 1);
|
||||
await this.actor.update(this._buildStressUpdate(this.actor, newStress));
|
||||
resultLine = `<div class="yze-summary" style="color:#ff4444"><strong>FAILED</strong> — no successes. +1 Stress (now ${newStress}).</div>`;
|
||||
} else {
|
||||
resultLine = `<div class="yze-summary" style="color:#44cc66"><strong>SUCCESS</strong> — ${successes} success${successes !== 1 ? 'es' : ''}!</div>`;
|
||||
}
|
||||
|
||||
await ChatMessage.create({
|
||||
speaker: ChatMessage.getSpeaker({ actor: this.actor }),
|
||||
flavor: `<strong>${this.actor.name} — ${label}</strong><br><small>${current}d6 (current ${saveType === 'health' ? 'Health' : 'Resolve'})</small>`,
|
||||
content: `<div class="yze-roll-result"><div class="yze-dice-display">${diceHtml}</div>${resultLine}</div>`,
|
||||
style: CONST.CHAT_MESSAGE_STYLES?.ROLL,
|
||||
type: CONST.CHAT_MESSAGE_TYPES?.ROLL,
|
||||
roll: roll,
|
||||
rollMode: game.settings.get('core', 'rollMode')
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle Manual Panic button click
|
||||
* @param {Event} event
|
||||
|
||||
Reference in New Issue
Block a user