Skip to content

Commit bc23b42

Browse files
authored
Merge pull request #36 from paulcheeba/v13.4.0.1
V13.4.0.1
2 parents 8d57dde + b99c685 commit bc23b42

27 files changed

+3729
-235
lines changed

README.md

Lines changed: 51 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
# About Time Next
88

99
**About Time Next** is a timekeeping and event scheduling utility for Foundry VTT v13+. It is a spiritual successor to about-time by Tim Posney and is built on top of the original code in an attempt to keep legacy functions.
10-
It works with **Simple Calendar** (*see installation note 3*) or falls back to Foundrys core time system.
10+
It supports **D&D 5e v5.2+ native calendar**, **Seasons & Stars**, **Simple Calendar**, or falls back to Foundry's core time system.
1111

1212
---
1313

@@ -21,18 +21,41 @@ It works with **Simple Calendar** (*see installation note 3*) or falls back to F
2121
```
2222

2323
2. Enable the module in your world.
24-
3. (Optional) Install **Simple Calendar** for advanced date formatting.
25-
*Note - When SC is available for FVTT v13 I will reconfirm the original functionality. If there are only minor hook changes, about-time-v13 MAY already be compatible with the v13 SC, it's unlikely though...*
24+
3. (Optional) Configure calendar system in settings: Auto-detect (default), D&D 5e Calendar, Simple Calendar, Seasons & Stars, or None.
2625

2726
> Compatibility: Designed for FVTT v13 (min 13, max 13.x).
28-
> With SC enabled, About-Time uses SC’s format/interval helpers where available.
29-
> Works with smalltime and Season and Stars (using foundry's core time system, not Seasons and Stars') but also has it's own Time Management app built in (which can be disabled in settings).
27+
> **Calendar Support:** D&D 5e v5.2+ native calendar, Seasons & Stars, Simple Calendar, and core time fallback.
28+
> Settings dropdown dynamically shows only available calendar systems. Detection display shows all systems with status.
29+
30+
---
31+
32+
## Calendar Integration
33+
34+
About Time Next uses a **calendar adapter system** to integrate with multiple calendar systems. The module automatically detects available calendars and provides formatted time displays.
35+
36+
**Supported Calendars:**
37+
- **D&D 5e Calendar (v5.2+)**: Native Foundry v13 calendar system with Harptos, Greyhawk, Gregorian, and Khorvaire calendars.
38+
- **Seasons & Stars**: Full integration with formatted date/time display.
39+
- **Simple Calendar**: Legacy compatibility layer retained for reference. Full support depends on a FVTT v13 update of the Simple Calendar module. SC integration may soon be removed if confirmed abandoned.
40+
41+
**Auto-Detection (Default):**
42+
When set to "Auto-detect", the module checks in priority order:
43+
1. Seasons & Stars (if module active with API)
44+
2. Simple Calendar (if module active with API)
45+
3. D&D 5e Calendar (if system v5.2+ with calendar configured)
46+
4. Falls back to "None" (Foundry core time)
47+
5. Additional calendars to be added in future updates.
48+
49+
**Calendar Integration Settings:**
50+
- Dropdown shows **only detected** calendars (plus "Auto-detect" and "None")
51+
- Detection info panel shows **all calendars** with ✓/✗ status
52+
- If your selected calendar becomes unavailable, module falls back automatically
3053

3154
---
3255

3356
## Quick Start
3457

35-
- **Event Manager (applicationV2):** Open from the **Journal/Notes** toolbar sub-button **“Event Manager”** (GM-only).
58+
- **Event Manager (applicationV2):** Open from the **Journal/Notes** toolbar sub-button **“Event Manager”** (Timekeeper-only; GMs always allowed).
3659
Use it to create one-shots or repeating events, stop items by name/UID, view the queue, or flush all.
3760

3861
- **Mini Time Manager (optional):** Enable in **Configure Settings → About-Time** to show a compact panel with **Play/Pause**, current time, and tiny toggles for realtime behavior (GM sees controls; players see time).
@@ -48,13 +71,14 @@ It works with **Simple Calendar** (*see installation note 3*) or falls back to F
4871

4972
### Event Manager (ApplicationV2)
5073

51-
<img width="923" height="437" alt="image" src="https://github.com/user-attachments/assets/6e72b4b3-477a-417e-bb5b-789698696a46" />
74+
<img width="929" height="463" alt="image" src="https://github.com/user-attachments/assets/67abca89-4e33-447b-baf6-1ca11ef4bd3f" />
5275

5376
Opened via the **Journal/Notes** toolbar sub-button (GM-only).
5477

5578
- **Create Event**: One-shot or repeating (DD:HH:MM:SS).
5679
- **Stop by Name**: Stops all events matching a given “friendly” name.
5780
- **Stop by UID**: Stops a specific event by unique ID.
81+
- **Pause/Resume**: Temporarily freeze an event’s countdown and resume later.
5882
- **Send Queue to Chat**: Posts a GM-whisper summary with name, UID, next fire time.
5983
- **Stop all Events**: Flush the queue.
6084
- **Stop all + 1h reminder**: Flush and schedule a “Resume in 1h” reminder.
@@ -64,7 +88,7 @@ The Event Manager auto-updates countdowns and refreshes itself if an event fires
6488
### Mini Time Manager (optional, client setting)
6589
Enable **“Enable AT Time Manager”** to show a compact panel:
6690

67-
<img width="299" height="168" alt="image" src="https://github.com/user-attachments/assets/45bca378-3ae8-4cf2-8504-f79a46755352" />
91+
<img width="300" height="151" alt="image" src="https://github.com/user-attachments/assets/8e631dd5-a7b5-4037-9bc5-28e7bebf7c7e" />
6892

6993
- **Play/Pause world time** (GM)
7094
- Live **clock display** (SC-formatted if SC is present)
@@ -94,12 +118,18 @@ Examples: `1h30m`, `2d 4h`, `45m10s`, or `5400` (seconds).
94118
Show the current queue (GM-whisper; includes UID, args, and next fire time).
95119

96120
- `/at clear`
97-
Clear the entire queue.
121+
Clear the entire queue. Prompts for confirm/cancel and updates the same chat card.
98122

99123
- `/at stop <uid>`
100-
Stop a specific event by UID.
124+
Stop a specific event by UID. Prompts for confirm/cancel and updates the same chat card.
101125
> Tip: In EM V2 you can copy a row’s UID, then run **`/at stop UID**.
102126
127+
- `/at pause <uid>`
128+
Pause a specific event by UID (freezes remaining time).
129+
130+
- `/at resume <uid>`
131+
Resume a paused event by UID.
132+
103133
- `/at in <duration> <message>`
104134
Schedule a one-time reminder.
105135
Returns a UID so you can stop it later.
@@ -134,19 +164,21 @@ Actions (top buttons):
134164
- **Send Queue to Chat** (GM-whisper)
135165
- **Stop all Events** / **Stop all + 1h reminder**
136166

137-
> With **Simple Calendar** installed, About-Time uses SC's formatting/conversion where appropriate. Without SC, it falls back to core Foundry world time.
167+
> Time formatting uses the active calendar adapter (D&D 5e, Seasons & Stars, or Simple Calendar when available). Falls back to Foundry core time if no calendar system is configured.
138168
139169
### Event Notification Cards
140170
When events trigger, they display standardized notification cards with detailed information:
141171

142-
<img width="293" height="365" alt="image" src="https://github.com/user-attachments/assets/0bbc2efb-e1a4-408c-9b54-1865c1e4d457" />
172+
<img width="294" height="451" alt="image" src="https://github.com/user-attachments/assets/d651e84e-f414-47e0-8d83-f0cf2ec37358" />
143173

144174

145175
```
146176
[about-time-next]
147177
Event Name: <name or NA>
148178
Message: <message or NA>
179+
Started On: <timestamp (when available)>
149180
Duration: DD:HH:MM:SS (or NA)
181+
Next Occurrence: <timestamp or —>
150182
Repeating: Yes/No
151183
Macro: <macro name or NA>
152184
Event UID: <unique identifier>
@@ -157,7 +189,7 @@ Event UID: <unique identifier>
157189
- **Macro Integration**: Events with macros show the event card *and* executes the macro
158190
- **Sound Support**: `[about-time-next]` prefix ensures notification sounds trigger correctly
159191

160-
_Note: `/at` chat commands currently use legacy format. Standardization planned for future release._
192+
_Note: `/at in` and `/at every` reminders currently use legacy output formatting. Standardization planned for a future release._
161193

162194
---
163195

@@ -219,6 +251,8 @@ game.abouttime.notifyIn({ seconds: 30 }, "myCustomEvent", "arg1", "arg2");
219251
## Settings (high-level)
220252

221253
- **Enable AT Time Manager (client)** — Shows the mini panel for this user.
254+
- **Minimum role required to be a timekeeper (world)** — Delegates event queue management to non-GM users (GMs always allowed).
255+
- **Time Format (world)** — Choose 12-hour (AM/PM) or 24-hour time display for consistent formatting across the module.
222256
- **Realtime Rate / Tick Hz (world)** — Controls the realtime runner (GM-only; safe ranges enforced).
223257
- **Link Pause / Auto-Pause Combat (client)** — How the mini panel reacts to world/game state.
224258

@@ -241,22 +275,22 @@ Event notifications play automatically when scheduled events fire, helping GMs t
241275
- M4A (.m4a) - AAC audio, good quality
242276
Best practice: MP3 is the safest choice for maximum browser compatibility across all platforms (which is why we used it for the notification sounds in v13.2.0.0+).
243277

244-
> Where SC is present, date/time formatting in the mini panel and EM uses SC helpers.
278+
> Date/time formatting uses the active calendar adapter (D&D 5e, Seasons & Stars, Simple Calendar when available), otherwise it falls back to Foundry core time.
245279
246280
---
247281

248282
## Notes & Limitations
249283

250284
- The module **does not** override combat round/initiative time.
251-
- Complex SC calendars (non-365-day years, custom months) are supported via SC’s own conversions, while raw seconds math remains conservative in fallback mode.
252-
- Only GMs can create, manage, and view scheduled events.
285+
- Complex calendar rules are supported through the active calendar system when present; core-time fallback uses raw seconds math.
286+
- Event queue management is **Timekeeper-only** (configurable role threshold; GMs always allowed).
253287
- Realtime runner is **single-owner (GM)**; if another GM starts it, ownership is handed off gracefully.
254288

255289
---
256290

257291
## Credits
258292

259-
Originally created by **Tim Posney**, updated and maintained for FVTT v13+ by **paulcheeba** with community input and ChatGPT-assisted refactoring.
293+
About Time was originally created and maintained by the great **Tim Posney**, About time Next is updated and maintained for FVTT v13+ by **paulcheeba** with community input and AI-assisted refactoring.
260294

261295
**Event notification sound effects** by [Notification_Message](https://pixabay.com/users/notification_message-47259947/) from [Pixabay](https://pixabay.com/sound-effects/).
262296

about-time.js

Lines changed: 118 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// about-time.js — Entry point
2-
// v13.2.0.0 — Added event notification sound system
2+
// v13.4.0.0 — D&D 5e Calendar integration (native calendar support for D&D 5e v5.2+)
33

44
import { registerSettings, MODULE_ID } from './module/settings.js';
55
import { preloadTemplates } from './module/preloadTemplates.js';
@@ -8,6 +8,12 @@ import { PseudoClock } from './module/PseudoClock.js';
88
import { DTMod } from './module/calendar/DTMod.js';
99
import { DTCalc } from './module/calendar/DTCalc.js';
1010

11+
// Calendar Adapter System (v13.3.1.0 - Phase 1)
12+
import { CalendarAdapter } from './module/calendar/CalendarAdapter.js';
13+
import './module/calendar/Dnd5eAdapter.js'; // Self-registers (v13.3.5.0)
14+
import './module/calendar/SimpleCalendarAdapter.js'; // Self-registers
15+
import './module/calendar/SandSAdapter.js'; // Self-registers
16+
1117
// New (modular, non-destructive)
1218
import { registerMiniSettings } from './module/ATMiniSettings.js';
1319
import { showMiniPanel, hideMiniPanel, toggleMiniPanel } from './module/ATMiniPanel.js';
@@ -45,10 +51,26 @@ try { import('./module/ATToolbar.js'); } catch (e) { /* optional */ }
4551
export function DTNow() { return game.time.worldTime; }
4652

4753
Hooks.once('init', () => {
48-
console.log(`${MODULE_ID} | Initializing`);
4954
registerSettings();
5055
registerMiniSettings(); // <- new mini settings
5156

57+
// Always-on basic status line.
58+
try {
59+
const version = game.modules.get(MODULE_ID)?.version ?? "unknown";
60+
console.info(`${MODULE_ID} | Loaded v${version}`);
61+
} catch {
62+
// ignore
63+
}
64+
65+
const debug = (() => {
66+
try { return !!game.settings.get(MODULE_ID, "debug"); } catch { return false; }
67+
})();
68+
69+
// Expose CalendarAdapter to global namespace for macros and testing
70+
if (!window.AboutTimeNext) window.AboutTimeNext = {};
71+
window.AboutTimeNext.CalendarAdapter = CalendarAdapter;
72+
if (debug) console.log(`${MODULE_ID} | CalendarAdapter available at window.AboutTimeNext.CalendarAdapter`);
73+
5274
// Optionally preload (only real template path is loaded)
5375
preloadTemplates().catch(() => { /* ignore */ });
5476
});
@@ -82,6 +104,8 @@ Hooks.once('setup', () => {
82104

83105
// queue admin
84106
clearTimeout: ElapsedTime.gclearTimeout,
107+
pauseEvent: ElapsedTime.pauseEvent,
108+
resumeEvent: ElapsedTime.resumeEvent,
85109
getTimeString: ElapsedTime.currentTimeString,
86110
getTime: ElapsedTime.currentTimeString,
87111
queue: ElapsedTime.showQueue,
@@ -117,7 +141,10 @@ Hooks.once('setup', () => {
117141
// New: Mini Time Panel controls
118142
showMiniPanel,
119143
hideMiniPanel,
120-
toggleMiniPanel
144+
toggleMiniPanel,
145+
146+
// Calendar Adapter System (v13.3.1.0)
147+
CalendarAdapter
121148
};
122149

123150
// Legacy/global shims
@@ -139,16 +166,101 @@ Hooks.once('setup', () => {
139166
globalThis.Gametime = new Proxy(operations, warnProxy);
140167
});
141168

142-
Hooks.once('ready', () => {
143-
if (!game.modules.get("foundryvtt-simple-calendar")?.active) {
144-
console.warn(`${MODULE_ID} | Simple Calendar not active (optional).`);
169+
Hooks.once('ready', async () => {
170+
// ============================================================================
171+
// CALENDAR SETTINGS MIGRATION (v13.3.2.0 - Phase 2)
172+
// ============================================================================
173+
// Migrate from old use-simple-calendar boolean to new calendar-system string
174+
if (game.user.isGM) {
175+
try {
176+
const currentSystem = game.settings.get(MODULE_ID, "calendar-system");
177+
const legacySetting = game.settings.get(MODULE_ID, "use-simple-calendar");
178+
179+
const debug = (() => {
180+
try { return !!game.settings.get(MODULE_ID, "debug"); } catch { return false; }
181+
})();
182+
183+
if (debug) {
184+
console.log(`${MODULE_ID} | [Migration] Current calendar-system: "${currentSystem}"`);
185+
console.log(`${MODULE_ID} | [Migration] Legacy use-simple-calendar: ${legacySetting}`);
186+
}
187+
188+
// Only migrate if still on default "auto" setting (first time setup or upgrade)
189+
if (currentSystem === "auto") {
190+
const detected = CalendarAdapter.detectAvailableAsObject();
191+
if (debug) console.log(`${MODULE_ID} | [Migration] Detected calendars:`, detected);
192+
193+
let newSystem = "auto"; // Keep auto as default
194+
195+
// If user had explicitly disabled SC, respect that
196+
if (legacySetting === false) {
197+
newSystem = "none";
198+
if (debug) console.log(`${MODULE_ID} | [Migration] User had disabled SC → setting to "none"`);
199+
}
200+
// If user had SC enabled and it's still available, use it explicitly
201+
else if (legacySetting === true && detected.simpleCalendar) {
202+
newSystem = "simple-calendar";
203+
if (debug) console.log(`${MODULE_ID} | [Migration] SC was enabled and is available → setting to "simple-calendar"`);
204+
}
205+
// If SC was enabled but no longer available, check for S&S
206+
else if (legacySetting === true && !detected.simpleCalendar && detected.seasonsStars) {
207+
newSystem = "seasons-and-stars";
208+
if (debug) console.log(`${MODULE_ID} | [Migration] SC unavailable but S&S detected → setting to "seasons-and-stars"`);
209+
}
210+
211+
// Save migrated setting
212+
if (newSystem !== "auto") {
213+
game.settings.set(MODULE_ID, "calendar-system", newSystem);
214+
if (debug) console.log(`${MODULE_ID} | [Migration] ✓ Migrated calendar-system to: "${newSystem}"`);
215+
216+
// Show one-time notice to GM
217+
ui.notifications.info(
218+
`About Time Next: Calendar settings migrated. Now using: ${newSystem.replace('-', ' ').replace(/\b\w/g, l => l.toUpperCase())}`,
219+
{ permanent: false }
220+
);
221+
} else {
222+
if (debug) console.log(`${MODULE_ID} | [Migration] Keeping auto-detect mode`);
223+
}
224+
} else {
225+
const debug = (() => {
226+
try { return !!game.settings.get(MODULE_ID, "debug"); } catch { return false; }
227+
})();
228+
if (debug) console.log(`${MODULE_ID} | [Migration] Already configured, skipping migration`);
229+
}
230+
} catch (err) {
231+
console.error(`${MODULE_ID} | [Migration] Failed:`, err);
232+
}
233+
}
234+
235+
// ============================================================================
236+
// INITIALIZATION
237+
// ============================================================================
238+
239+
try {
240+
if (game.settings.get(MODULE_ID, "debug")) {
241+
if (!game.modules.get("foundryvtt-simple-calendar")?.active) {
242+
console.warn(`${MODULE_ID} | Simple Calendar not active (optional).`);
243+
}
244+
}
245+
} catch {
246+
// ignore
145247
}
146248
PseudoClock.init();
147249
ElapsedTime.init();
148250

149251
// Initialize event notification sound system (v13.2.0.0)
150252
ATNotificationSound.init();
151253

254+
// Check for calendar changes (v13.4.0.0)
255+
// This detects when modules are enabled/disabled and prompts GM to switch calendars
256+
if (game.user.isGM) {
257+
try {
258+
await CalendarAdapter.checkForCalendarChanges();
259+
} catch (e) {
260+
console.warn(`${MODULE_ID} | Calendar change check failed (non-fatal)`, e);
261+
}
262+
}
263+
152264
// Auto-open the mini panel per user setting
153265
try {
154266
if (game.settings.get(MODULE_ID, "enableMiniPanel")) {

0 commit comments

Comments
 (0)