diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4b88d6d..c92b0b8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,15 @@
All notable changes to Grim Arithmetic are documented here.
+## v0.7.2-rc1 - Player-safe options and calmer tooltips
+
+Release candidate. Three usability fixes on top of v0.7.1; no changes to the underlying mortality math.
+
+### Usability
+- The Grim Arithmetic settings section is now GM-only — regular players no longer see any module options (KHT-118). The GM-facing options carry clearer descriptions of what each one does.
+- Hover help across all three windows now waits a beat (750ms) before appearing, so tooltips no longer flicker continuously while scanning down a list of values (KHT-120).
+- The risk-rating tooltip now spells out the full ladder — Low, Guarded, Dangerous, Severe, Grim, with the chance-of-being-downed band for each — instead of just "Low → Grim" (KHT-121).
+
## v0.7.1 - Localization, tooltips, and tactics clarity
Builds on v0.7.0's ApplicationV2 migration with internationalization groundwork, on-hover help across every window, clearer tactics options, and a real CI/release pipeline. No changes to the underlying mortality math.
diff --git a/lang/en.json b/lang/en.json
index ea28ed3..f002c07 100644
--- a/lang/en.json
+++ b/lang/en.json
@@ -3,7 +3,7 @@
"Settings": {
"DefaultStrikes": {
"Name": "Default enemy Strike count",
- "Hint": "Default number of Strikes used for immediate-threat estimates.",
+ "Hint": "How many Strikes each enemy is assumed to make per round when estimating immediate knock-out threat on the Encounter Danger Board.",
"Choices": {
"1": "1 Strike",
"2": "2 Strikes",
@@ -12,11 +12,11 @@
},
"DebugLogging": {
"Name": "Debug logging",
- "Hint": "Log Grim Arithmetic debug information to the browser console."
+ "Hint": "Write Grim Arithmetic diagnostic messages to the browser console (F12). Leave off unless troubleshooting."
},
"EnableMonteCarlo": {
"Name": "Enable Monte Carlo encounter simulation",
- "Hint": "Disable on low-end machines if simulation runs are too slow. The Encounter Danger Board still works either way."
+ "Hint": "Turn on the Encounter Forecast's full-fight simulation. Disable on low-end machines if runs are too slow — the Encounter Danger Board still works either way."
}
},
"Window": {
@@ -28,7 +28,8 @@
"Detail": "Detail",
"Vs": "vs",
"DownTooltip": "Chance this PC is knocked out in one round by this attack.",
- "RiskPillTooltip": "Risk rating from chance of being downed: Low → Grim.",
+ "RiskPillTooltip": "Risk of being downed this round, lowest to highest: Low, Guarded, Dangerous, Severe, Grim.",
+ "RiskPillTooltipHtml": "Risk of being downed this round: Low — below 5% Guarded — 5–15% Dangerous — 15–35% Severe — 35–60% Grim — 60% or more",
"CiTooltip": "95% confidence interval — the range the true value likely falls in given sampling variance."
},
"DangerBoard": {
diff --git a/module.json b/module.json
index 3a2e5b9..73c5d4a 100644
--- a/module.json
+++ b/module.json
@@ -2,7 +2,7 @@
"id": "grim-arithmetic",
"title": "Grim Arithmetic",
"description": "GM-facing PF2e mortality and encounter-risk analysis for Foundry VTT.",
- "version": "0.7.1",
+ "version": "0.7.2-rc1",
"authors": [
{
"name": "Kyle Travis",
@@ -36,5 +36,5 @@
],
"url": "https://github.com/kyletravis/grim-arithmetic",
"manifest": "https://github.com/kyletravis/grim-arithmetic/releases/latest/download/module.json",
- "download": "https://github.com/kyletravis/grim-arithmetic/releases/download/v0.7.1/grim-arithmetic-v0.7.1.zip"
+ "download": "https://github.com/kyletravis/grim-arithmetic/releases/download/v0.7.2-rc1/grim-arithmetic-v0.7.2-rc1.zip"
}
diff --git a/package.json b/package.json
index 796d8e1..b78ec9c 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "grim-arithmetic",
- "version": "0.7.1",
+ "version": "0.7.2-rc1",
"description": "Foundry VTT module for GM-facing PF2e mortality and encounter-risk analysis.",
"type": "module",
"private": true,
diff --git a/src/main.ts b/src/main.ts
index 8a05ca0..29c777f 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -1,9 +1,10 @@
import { MODULE_ID, MODULE_TITLE } from './constants';
import { logDebugCapture } from './debug-capture';
-import { registerSettings } from './settings';
+import { registerSettings, applyPlayerSettingsVisibility, type SettingsRegistry } from './settings';
import { DangerBoardPanel } from './ui/danger-board-panel';
import { ForecastPanel } from './ui/forecast-panel';
import { PairDetailPanel } from './ui/pair-detail-panel';
+import { applyTooltipDelay } from './ui/tooltip-delay';
import { registerTokenControls } from './ui/token-controls';
Hooks.once('init', () => {
@@ -22,6 +23,13 @@ function registerHandlebarsHelpers(): void {
}
Hooks.once('ready', () => {
+ applyTooltipDelay(750);
+ // Runs before the GM guard below: players must reach this to have their settings hidden.
+ applyPlayerSettingsVisibility(
+ (game.settings as { settings?: SettingsRegistry } | undefined)?.settings,
+ game.user?.isGM === true
+ );
+
if (!game.user?.isGM) return;
const grimArithmeticModule = game.modules.get(MODULE_ID);
diff --git a/src/settings.ts b/src/settings.ts
index 5ab258e..74629a0 100644
--- a/src/settings.ts
+++ b/src/settings.ts
@@ -36,6 +36,34 @@ export function registerSettings(): void {
});
}
+const GRIM_SETTING_KEYS = ['defaultStrikes', 'debugLogging', ENABLE_MONTE_CARLO_SETTING] as const;
+
+export interface SettingsRegistry {
+ get(key: string): { config?: boolean } | undefined;
+}
+
+/**
+ * Hide every Grim Arithmetic setting from non-GM players (KHT-118).
+ *
+ * Settings must be registered during `init`, but `game.user` is not populated
+ * until later — so registration can't know who the GM is. We register with
+ * `config: true` and, once `game.user.isGM` is known (the `ready` hook), flip
+ * the `config` flag to false for non-GMs. Foundry's settings menu reads each
+ * registration's `config` flag at render time and omits a module's heading
+ * when it has no visible settings, so this removes the entire Grim Arithmetic
+ * section for players — heading included. No-op for the GM.
+ */
+export function applyPlayerSettingsVisibility(
+ registry: SettingsRegistry | undefined | null,
+ isGM: boolean
+): void {
+ if (isGM || !registry) return;
+ for (const key of GRIM_SETTING_KEYS) {
+ const registration = registry.get(`${MODULE_ID}.${key}`);
+ if (registration) registration.config = false;
+ }
+}
+
/**
* True when the Monte Carlo simulation feature is enabled for this client.
*
diff --git a/src/ui/tooltip-delay.ts b/src/ui/tooltip-delay.ts
new file mode 100644
index 0000000..4b88cc9
--- /dev/null
+++ b/src/ui/tooltip-delay.ts
@@ -0,0 +1,20 @@
+/**
+ * Lengthen the delay before Foundry's native `data-tooltip` help appears,
+ * so tooltips don't fire continuously while scanning down a list of values
+ * (KHT-120). Foundry reads `TOOLTIP_ACTIVATION_MS` off the tooltip manager
+ * class at hover time, so overriding it affects all subsequent hovers.
+ *
+ * `game.tooltip.constructor` is the live class regardless of v13+ namespace
+ * relocation. No-ops safely when the manager is unavailable (pre-ready, or
+ * the test environment where `game` is undefined).
+ */
+export function applyTooltipDelay(ms: number): void {
+ if (typeof game === 'undefined') return;
+ try {
+ const manager = (game as { tooltip?: { constructor?: { TOOLTIP_ACTIVATION_MS?: number } } }).tooltip;
+ const managerClass = manager?.constructor;
+ if (managerClass) managerClass.TOOLTIP_ACTIVATION_MS = ms;
+ } catch {
+ /* tooltip manager unavailable; leave the default delay in place */
+ }
+}
diff --git a/templates/danger-board-panel.hbs b/templates/danger-board-panel.hbs
index 319f66e..3dc09cb 100644
--- a/templates/danger-board-panel.hbs
+++ b/templates/danger-board-panel.hbs
@@ -35,7 +35,7 @@
{{enemyName}} {{attackName}}{{downPercent}}%
- {{riskLabel}}
+ {{riskLabel}}