v1.7.5: add healthHeal field — instant HP restore on drug activation

- New healthHeal field: heals current HP immediately on activation, clamped at max
- healthMod unchanged: still modifies derived max HP persistently (wears off with drug)
- _activateDrug: apply healthHeal heal and notify with before/after/max values
- _formatDrugStateSummary: show Heals Xhp for healthHeal, Max Health +X for healthMod
- updateDrugModel: healthHeal added to numericPaths for validation
- KickStart: healthMod 0, healthHeal 2
- KickStart Plus: healthMod 0, healthHeal 3
- KickStart Solo: healthMod 0, healthHeal 2
This commit is contained in:
2026-06-10 22:19:18 +01:00
parent e6e8986e25
commit 1b16e0e0cc
8 changed files with 45 additions and 20 deletions
Binary file not shown.
Binary file not shown.
+1 -1
View File
@@ -1 +1 @@
MANIFEST-000012 MANIFEST-000014
+13 -9
View File
@@ -1,9 +1,13 @@
2026/06/10-19:00:40.626229 ef3d6afdefa0 Recovering log #11 2026/06/10-21:19:08.220245 eb1634f9efa0 Recovering log #13
2026/06/10-19:00:40.632846 ef3d6afdefa0 Delete type=0 #7 2026/06/10-21:19:08.220734 eb1634f9efa0 Level-0 table #15: started
2026/06/10-19:00:40.633093 ef3d6afdefa0 Delete type=0 #4 2026/06/10-21:19:08.222419 eb1634f9efa0 Level-0 table #15: 2401 bytes OK
2026/06/10-19:00:40.633425 ef3d6afdefa0 Delete type=0 #11 2026/06/10-21:19:08.224826 eb1634f9efa0 Delete type=0 #13
2026/06/10-19:00:40.633539 ef3d6afdefa0 Delete type=3 #8 2026/06/10-21:19:08.225002 eb1634f9efa0 Delete type=0 #7
2026/06/10-19:00:40.633698 ef3d6afdefa0 Delete type=3 #6 2026/06/10-21:19:08.225252 eb1634f9efa0 Delete type=0 #4
2026/06/10-19:00:40.633835 ef3d6afdefa0 Delete type=3 #10 2026/06/10-21:19:08.225418 eb1634f9efa0 Delete type=0 #11
2026/06/10-19:00:40.633940 ef3d6afdefa0 Delete type=3 #2 2026/06/10-21:19:08.225568 eb1634f9efa0 Delete type=3 #12
2026/06/10-19:00:40.634055 ef3d6afdefa0 Delete type=0 #9 2026/06/10-21:19:08.225685 eb1634f9efa0 Delete type=3 #8
2026/06/10-21:19:08.225823 eb1634f9efa0 Delete type=3 #6
2026/06/10-21:19:08.225963 eb1634f9efa0 Delete type=3 #10
2026/06/10-21:19:08.226081 eb1634f9efa0 Delete type=3 #2
2026/06/10-21:19:08.226189 eb1634f9efa0 Delete type=0 #9
+9 -7
View File
@@ -1,7 +1,9 @@
2026/06/10-18:57:57.727392 f90bb1f9efa0 Recovering log #9 2026/06/10-19:00:40.626229 ef3d6afdefa0 Recovering log #11
2026/06/10-18:57:57.730975 f90bb1f9efa0 Delete type=0 #7 2026/06/10-19:00:40.632846 ef3d6afdefa0 Delete type=0 #7
2026/06/10-18:57:57.731180 f90bb1f9efa0 Delete type=0 #4 2026/06/10-19:00:40.633093 ef3d6afdefa0 Delete type=0 #4
2026/06/10-18:57:57.731359 f90bb1f9efa0 Delete type=3 #8 2026/06/10-19:00:40.633425 ef3d6afdefa0 Delete type=0 #11
2026/06/10-18:57:57.731591 f90bb1f9efa0 Delete type=3 #6 2026/06/10-19:00:40.633539 ef3d6afdefa0 Delete type=3 #8
2026/06/10-18:57:57.731898 f90bb1f9efa0 Delete type=3 #2 2026/06/10-19:00:40.633698 ef3d6afdefa0 Delete type=3 #6
2026/06/10-18:57:57.732147 f90bb1f9efa0 Delete type=0 #9 2026/06/10-19:00:40.633835 ef3d6afdefa0 Delete type=3 #10
2026/06/10-19:00:40.633940 ef3d6afdefa0 Delete type=3 #2
2026/06/10-19:00:40.634055 ef3d6afdefa0 Delete type=0 #9
Binary file not shown.
+1 -1
View File
@@ -2,7 +2,7 @@
"id": "zero-engine", "id": "zero-engine",
"title": "Zero Engine (SLA Industries)", "title": "Zero Engine (SLA Industries)",
"description": "A basic game system for SLA Industries using the Zero Engine rules.", "description": "A basic game system for SLA Industries using the Zero Engine rules.",
"version": "1.7.4", "version": "1.7.5",
"compatibility": { "compatibility": {
"minimum": 13, "minimum": 13,
"verified": "14.359" "verified": "14.359"
+21 -2
View File
@@ -870,8 +870,11 @@ class ZeroEngineActorSheet extends foundry.appv1.sheets.ActorSheet {
const panicReduction = Number(isWithdrawal ? s.wdPanicReduction : s.panicReduction) || 0; const panicReduction = Number(isWithdrawal ? s.wdPanicReduction : s.panicReduction) || 0;
const injuryIgnore = Number(isWithdrawal ? s.wdInjuryPenaltyIgnore : s.injuryPenaltyIgnore) || 0; const injuryIgnore = Number(isWithdrawal ? s.wdInjuryPenaltyIgnore : s.injuryPenaltyIgnore) || 0;
const healthHeal = (!isWithdrawal) ? (Number(s.healthHeal) || 0) : 0;
const parts = []; const parts = [];
if (health !== 0) parts.push(`Health ${health > 0 ? "+" : ""}${health}`); if (healthHeal > 0) parts.push(`Heals ${healthHeal} HP`);
if (health !== 0) parts.push(`Max Health ${health > 0 ? "+" : ""}${health}`);
if (resolve !== 0) parts.push(`Resolve ${resolve > 0 ? "+" : ""}${resolve}`); if (resolve !== 0) parts.push(`Resolve ${resolve > 0 ? "+" : ""}${resolve}`);
if (stat !== 0) parts.push(`Physical ${stat > 0 ? "+" : ""}${stat}`); if (stat !== 0) parts.push(`Physical ${stat > 0 ? "+" : ""}${stat}`);
if (skillAll !== 0) parts.push(`All Skills ${skillAll > 0 ? "+" : ""}${skillAll}`); if (skillAll !== 0) parts.push(`All Skills ${skillAll > 0 ? "+" : ""}${skillAll}`);
@@ -958,6 +961,22 @@ class ZeroEngineActorSheet extends foundry.appv1.sheets.ActorSheet {
} }
} }
// ── Instant HP heal (healthHeal): restore current HP, clamped at max ────────
const healthHeal = Math.max(0, Number(item.system?.healthHeal) || 0);
if (healthHeal > 0 && this.actor) {
const rawHp = this.actor.system?.derivedStats?.health;
const currentHp = Number((typeof rawHp === "object" ? rawHp?.value : rawHp) ?? 0);
const hpMax = Number(this.actor.system?.derivedStats?.health?.max ?? 0);
if (hpMax > 0) {
const newHp = Math.min(hpMax, currentHp + healthHeal);
const actual = newHp - currentHp;
if (actual > 0) {
await this.actor.update({ "system.derivedStats.health.value": newHp });
ui.notifications.info(`${item.name}: healed ${actual} HP (${currentHp} → ${newHp} / ${hpMax})`);
}
}
}
await this._notifyDrugState(item, "is ACTIVE", String(item.system?.activeDuration || "")); await this._notifyDrugState(item, "is ACTIVE", String(item.system?.activeDuration || ""));
} }
@@ -3960,7 +3979,7 @@ Hooks.once('ready', function() {
if (data.withdrawalDuration === undefined || data.withdrawalDuration === null) updates["system.withdrawalDuration"] = ""; if (data.withdrawalDuration === undefined || data.withdrawalDuration === null) updates["system.withdrawalDuration"] = "";
const numericPaths = [ const numericPaths = [
"healthMod", "resolveMod", "statPhysicalMod", "skillAllMod", "panicReduction", "healthMod", "healthHeal", "resolveMod", "statPhysicalMod", "skillAllMod", "panicReduction",
"injuryPenaltyIgnore", "stressRecoveryBonus", "postUseStaminaDamage", "injuryPenaltyIgnore", "stressRecoveryBonus", "postUseStaminaDamage",
"wdHealthMod", "wdResolveMod", "wdStatPhysicalMod", "wdSkillAllMod", "wdPanicReduction", "wdHealthMod", "wdResolveMod", "wdStatPhysicalMod", "wdSkillAllMod", "wdPanicReduction",
"wdInjuryPenaltyIgnore", "wdStressRecoveryBonus", "wdPostUseStaminaDamage" "wdInjuryPenaltyIgnore", "wdStressRecoveryBonus", "wdPostUseStaminaDamage"