From 353cb75e9953392c5b4c5ef0c88dec678e75a2a5 Mon Sep 17 00:00:00 2001 From: Chris Wegrzyn Date: Fri, 16 Aug 2024 22:28:24 -0400 Subject: [PATCH] Allow resolving clocks --- docs/Commands/Advance a clock.md | 2 +- docs/Commands/Resolve a clock.md | 3 ++ docs/Entities/Clocks.md | 7 ++- src/clocks/commands.ts | 63 +++++++++++++++++++++--- src/commands.ts | 10 +++- src/mechanics/css/dlist-clock-status.css | 4 +- src/mechanics/node-builders/clocks.ts | 12 +++++ 7 files changed, 88 insertions(+), 13 deletions(-) create mode 100644 docs/Commands/Resolve a clock.md diff --git a/docs/Commands/Advance a clock.md b/docs/Commands/Advance a clock.md index cd2a7896..3cd1f65e 100644 --- a/docs/Commands/Advance a clock.md +++ b/docs/Commands/Advance a clock.md @@ -1,6 +1,6 @@ Advances a [[Clocks|Clock]], modifying its frontmatter, and inserts a [[Mechanics Blocks#`clock`|`clock` mechanics node]] into your active journal. Clocks which are already filled, or which are completed, cannot be advanced (and will not show up at all in the picker for the command). -Advancing a Clock to completion will not automatically be marked as closed. In keeping with the spirit of Iron Vault letting the player take care of actual mechanics instead of playing the game for them, this is left up to you to manage as you see fit. +Advancing a Clock to completion will not automatically be marked as resolved. You will be asked if you wish to mark the clock as resolved. If you choose not to resolve it now, you can always resolve it as needed with the [[Resolve a clock]] command. ![[Mechanics Blocks#`clock`#Example|iv-embed]] ![[Doomsday Device|iv-embed]] \ No newline at end of file diff --git a/docs/Commands/Resolve a clock.md b/docs/Commands/Resolve a clock.md new file mode 100644 index 00000000..a8b58630 --- /dev/null +++ b/docs/Commands/Resolve a clock.md @@ -0,0 +1,3 @@ +Resolves a [[Clocks|Clock]]. This will remove it from the list of active clocks shown by, e.g., the [[Advance a clock]] command. + +Note that you may resolve a clock that is not full. This is appropriate for situations where the clock is no longer relevant. \ No newline at end of file diff --git a/docs/Entities/Clocks.md b/docs/Entities/Clocks.md index 6446e3c3..def880a4 100644 --- a/docs/Entities/Clocks.md +++ b/docs/Entities/Clocks.md @@ -1,6 +1,11 @@ +--- +aliases: + - Clock + - clock +--- Starforged introduced a mechanic called "clocks", which Iron Vault has direct support for. There are two main types of clock: Tension Clocks, and Campaign Clocks. Both are represented by a single "Clock" entity in Iron Vault, and it does not distinguish between them. Clocks are managed/advanced manually. -You can create a clock using the [[Create a clock]] command. To advance the clock and record the step in your journal, use the [[Advance a clock]] command. You can also click on the clock itself, but that will *not* update your journal automatically. +You can create a clock using the [[Create a clock]] command. To advance the clock and record the step in your journal, use the [[Advance a clock]] command. You can also click on the clock itself, but that will *not* update your journal automatically. Finally, you can [[Resolve a clock]] which will mark it as "incomplete" and remove it from the active clocks listed in [[Advance a clock]]. #### Example ![[Doomsday Device|iv-embed]] diff --git a/src/clocks/commands.ts b/src/clocks/commands.ts index 1f325d64..bf12549a 100644 --- a/src/clocks/commands.ts +++ b/src/clocks/commands.ts @@ -3,11 +3,13 @@ import IronVaultPlugin from "index"; import { appendNodesToMoveOrMechanicsBlock } from "mechanics/editor"; import { createDetailsNode } from "mechanics/node-builders"; import { + clockResolvedNode, createClockCreationNode, createClockNode, } from "mechanics/node-builders/clocks"; -import { Editor, MarkdownView } from "obsidian"; +import { Editor, MarkdownFileInfo, MarkdownView, Notice } from "obsidian"; import { stripMarkdown } from "utils/strip-markdown"; +import { YesNoPrompt } from "utils/ui/yesno"; import { ClockFileAdapter, clockUpdater } from "../clocks/clock-file"; import { selectClock } from "../clocks/select-clock"; import { BLOCK_TYPE__CLOCK, IronVaultKind } from "../constants"; @@ -38,21 +40,66 @@ export async function advanceClock( "Select number of segments to fill.", ); + let shouldMarkResolved = false; + if (clockInfo.clock.tick(ticks).isFilled) { + shouldMarkResolved = await YesNoPrompt.asSuggest( + plugin.app, + "This clock is now filled. Do you want to mark it as resolved/inactive?", + ); + } + + const newClock = await clockUpdater( + vaultProcess(plugin.app, clockPath), + (clockAdapter) => { + return clockAdapter.updatingClock((clock) => { + let updatedClock = clock.tick(ticks); + if (shouldMarkResolved) { + if (updatedClock.isFilled) { + updatedClock = updatedClock.deactivate(); + } else { + const msg = `Clock '${clockPath}' was no longer filled and was not marked inactive.`; + console.warn(msg); + new Notice(msg, 0); + shouldMarkResolved = false; + } + } + return updatedClock; + }); + }, + ); + + const clockName = stripMarkdown(plugin, clockInfo.name); + appendNodesToMoveOrMechanicsBlock( + editor, + ...[ + createClockNode(clockName, clockPath, clockInfo, newClock.clock), + ...(shouldMarkResolved ? [clockResolvedNode(clockName, clockPath)] : []), + ], + ); +} + +export async function resolveClock( + plugin: IronVaultPlugin, + editor: Editor, + view: MarkdownFileInfo, +) { + const campaignContext = await determineCampaignContext(plugin, view); + const [clockPath] = await selectClock( + campaignContext.clocks, + plugin, + ([, clockInfo]) => clockInfo.clock.active, + ); + const newClock = await clockUpdater( vaultProcess(plugin.app, clockPath), (clockAdapter) => { - return clockAdapter.updatingClock((clock) => clock.tick(ticks)); + return clockAdapter.updatingClock((clock) => clock.deactivate()); }, ); appendNodesToMoveOrMechanicsBlock( editor, - createClockNode( - stripMarkdown(plugin, clockInfo.name), - clockPath, - clockInfo, - newClock.clock, - ), + clockResolvedNode(stripMarkdown(plugin, newClock.name), clockPath), ); } diff --git a/src/commands.ts b/src/commands.ts index 38c09926..1fd21e32 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -6,7 +6,7 @@ import { createNewCharacter, pickActiveCharacter, } from "characters/commands"; -import { advanceClock, createClock } from "clocks/commands"; +import { advanceClock, createClock, resolveClock } from "clocks/commands"; import { openDocsInBrowser, openDocsInTab } from "docs/commands"; import { generateEntityCommand } from "entity/command"; import { createFactionInfluenceGrid } from "factions/commands"; @@ -210,6 +210,14 @@ export class IronVaultCommands { advanceClock(this.plugin, editor, ctx as MarkdownView), }, + { + id: "clock-resolve", + name: "Clock: Resolve a clock", + icon: "alarm-clock-off", + editorCallback: (editor: Editor, ctx: MarkdownView | MarkdownFileInfo) => + resolveClock(this.plugin, editor, ctx), + }, + /* * ENTITIES */ diff --git a/src/mechanics/css/dlist-clock-status.css b/src/mechanics/css/dlist-clock-status.css index da33c8c8..cd5ec25c 100644 --- a/src/mechanics/css/dlist-clock-status.css +++ b/src/mechanics/css/dlist-clock-status.css @@ -8,9 +8,9 @@ content: "Clock added: "; } } - &.clock-name:has(~ .clock-status[data-value="removed"]) { + &.clock-name:has(~ .clock-status[data-value="resolved"]) { &:before { - content: "Clock removed: "; + content: "Clock resolved: "; } } &.clock-status { diff --git a/src/mechanics/node-builders/clocks.ts b/src/mechanics/node-builders/clocks.ts index f217eedb..c190dc1d 100644 --- a/src/mechanics/node-builders/clocks.ts +++ b/src/mechanics/node-builders/clocks.ts @@ -15,6 +15,18 @@ export function createClockCreationNode( }); } +export function clockResolvedNode( + clockName: string, + clockPath: string, +): kdl.Node { + return node("clock", { + properties: { + name: `[[${clockPath}|${clockName}]]`, + status: "resolved", + }, + }); +} + export function createClockNode( clockName: string, clockPath: string,