From 8504e4469f72450e11d64a25ae75445e9bc7da11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Tue, 11 Feb 2025 21:56:36 +0100 Subject: [PATCH 1/9] Prepare journal for various context (text and cursor) sources --- gui/journal.lua | 42 ++++++-------------- internal/journal/journal_context.lua | 57 ++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 30 deletions(-) create mode 100644 internal/journal/journal_context.lua diff --git a/gui/journal.lua b/gui/journal.lua index 20ce638f2f..de0c1daf09 100644 --- a/gui/journal.lua +++ b/gui/journal.lua @@ -7,6 +7,7 @@ local utils = require 'utils' local json = require 'json' local shifter = reqscript('internal/journal/shifter') local table_of_contents = reqscript('internal/journal/table_of_contents') +local journal_context = reqscript('internal/journal/journal_context') local RESIZE_MIN = {w=54, h=20} local TOC_RESIZE_MIN = {w=24} @@ -291,7 +292,11 @@ JournalScreen.ATTRS { } function JournalScreen:init() - local context = self:loadContext() + self.journal_context = journal_context.journal_context_factory( + self.save_prefix, + self.save_on_change + ) + local context = self.journal_context:load() self:addviews{ JournalWindow{ @@ -304,40 +309,17 @@ function JournalScreen:init() init_cursor=context.cursor[1], show_tutorial=context.show_tutorial or false, - on_text_change=self:callback('saveContext'), - on_cursor_change=self:callback('saveContext') + on_text_change=self:callback('onTextChange'), + on_cursor_change=self:callback('onTextChange') }, } end -function JournalScreen:loadContext() - local site_data = self.save_on_change and dfhack.persistent.getSiteData( - self.save_prefix .. JOURNAL_PERSIST_KEY - ) or {} - - if not site_data.text then - site_data.text={''} - site_data.show_tutorial = true - end - site_data.cursor = site_data.cursor or {#site_data.text[1] + 1} - - return site_data -end - -function JournalScreen:onTextChange(text) - self:saveContext(text) -end +function JournalScreen:onTextChange() + local text = self.subviews.journal_editor:getText() + local cursor = self.subviews.journal_editor:getCursor() -function JournalScreen:saveContext() - if self.save_on_change and dfhack.isWorldLoaded() then - local text = self.subviews.journal_editor:getText() - local cursor = self.subviews.journal_editor:getCursor() - - dfhack.persistent.saveSiteData( - self.save_prefix .. JOURNAL_PERSIST_KEY, - {text={text}, cursor={cursor}} - ) - end + self.journal_context:save(text, cursor) end function JournalScreen:onDismiss() diff --git a/internal/journal/journal_context.lua b/internal/journal/journal_context.lua new file mode 100644 index 0000000000..beea28b981 --- /dev/null +++ b/internal/journal/journal_context.lua @@ -0,0 +1,57 @@ +--@ module = true + +local widgets = require 'gui.widgets' + +local JOURNAL_PERSIST_KEY = 'journal' + +function journal_context_factory(save_prefix, save_on_change) + if not save_on_change then + return DummyJournalContext{} + elseif dfhack.world.isFortressMode() then + return FortJournalContext{save_prefix} + else + qerror('unsupported game mode') + end +end + +FortJournalContext = defclass(FortJournalContext) +FortJournalContext.ATTRS{ + save_prefix='' +} + +function get_fort_context_key(prefix) + return prefix .. JOURNAL_PERSIST_KEY +end + +function FortJournalContext:save(text, cursor) + if dfhack.isWorldLoaded() then + dfhack.persistent.saveSiteData( + get_fort_context_key(self.save_prefix), + {text={text}, cursor={cursor}} + ) + end +end + +function FortJournalContext:load() + if dfhack.isWorldLoaded() then + local site_data = dfhack.persistent.getSiteData( + get_fort_context_key(self.save_prefix) + ) or {} + + if not site_data.text then + site_data.text={''} + site_data.show_tutorial = true + end + site_data.cursor = site_data.cursor or {#site_data.text[1] + 1} + return site_data + end +end + +DummyJournalContext = defclass(DummyJournalContext) + +function DummyJournalContext:save(text, cursor) +end + +function DummyJournalContext:load() + return {text={''}, cursor={1}, show_tutorial=true} +end From b836ca298bfb1e05d9e9b9abd3cdb38c71ebcaad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Sun, 16 Feb 2025 09:22:52 +0100 Subject: [PATCH 2/9] Add journal context for adventurer game mode --- gui/journal.lua | 5 ++- internal/journal/journal_context.lua | 64 +++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/gui/journal.lua b/gui/journal.lua index de0c1daf09..277e8ba2f3 100644 --- a/gui/journal.lua +++ b/gui/journal.lua @@ -327,8 +327,9 @@ function JournalScreen:onDismiss() end function main(options) - if not dfhack.isMapLoaded() or not dfhack.world.isFortressMode() then - qerror('journal requires a fortress map to be loaded') + if not dfhack.isMapLoaded() or (not dfhack.world.isFortressMode() + and not dfhack.world.isAdventureMode()) then + qerror('journal requires a fortress/adventure map to be loaded') end local save_layout = options and options.save_layout diff --git a/internal/journal/journal_context.lua b/internal/journal/journal_context.lua index beea28b981..61a3a86594 100644 --- a/internal/journal/journal_context.lua +++ b/internal/journal/journal_context.lua @@ -4,16 +4,24 @@ local widgets = require 'gui.widgets' local JOURNAL_PERSIST_KEY = 'journal' -function journal_context_factory(save_prefix, save_on_change) +function journal_context_factory(save_on_change, save_prefix) if not save_on_change then return DummyJournalContext{} elseif dfhack.world.isFortressMode() then return FortJournalContext{save_prefix} + elseif dfhack.world.isAdventureMode() then + return AdventurerJournalContext{ + save_prefix, + adventurer_id=dfhack.world.getAdventurer().id + } else qerror('unsupported game mode') end end + +-- Fortress Context -- + FortJournalContext = defclass(FortJournalContext) FortJournalContext.ATTRS{ save_prefix='' @@ -47,6 +55,19 @@ function FortJournalContext:load() end end +-- Dummy Context, no storage -- + +DummyJournalContext = defclass(DummyJournalContext) + +function DummyJournalContext:save(text, cursor) +end + +function DummyJournalContext:load() + return {text={''}, cursor={1}, show_tutorial=true} +end + +-- Dummy Context, no storage -- + DummyJournalContext = defclass(DummyJournalContext) function DummyJournalContext:save(text, cursor) @@ -55,3 +76,44 @@ end function DummyJournalContext:load() return {text={''}, cursor={1}, show_tutorial=true} end + +-- Adventure Context -- + +AdventurerJournalContext = defclass(AdventurerJournalContext) +AdventurerJournalContext.ATTRS{ + save_prefix='', + adventurer_id='' +} + +function get_adventurer_context_key(prefix, adventurer_id) + return string.format( + '%s%s:adventurer:%s', + prefix, + JOURNAL_PERSIST_KEY, + adventurer_id + ) +end + +function AdventurerJournalContext:save(text, cursor) + if dfhack.isWorldLoaded() then + dfhack.persistent.saveSiteData( + get_adventurer_context_key(self.save_prefix, self.adventurer_id), + {text={text}, cursor={cursor}} + ) + end +end + +function AdventurerJournalContext:load() + if dfhack.isWorldLoaded() then + local site_data = dfhack.persistent.getSiteData( + get_adventurer_context_key(self.save_prefix, self.adventurer_id) + ) or {} + + if not site_data.text then + site_data.text={''} + site_data.show_tutorial = true + end + site_data.cursor = site_data.cursor or {#site_data.text[1] + 1} + return site_data + end +end From a643f6b865f4cbe4935ace9ec868a501a76dd8b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Wed, 26 Feb 2025 07:39:09 +0100 Subject: [PATCH 3/9] Refactor journal contexts --- internal/journal/contexts/adventure.lua | 38 ++++++++ internal/journal/contexts/dummy.lua | 13 +++ internal/journal/contexts/fortress.lua | 34 +++++++ internal/journal/journal_context.lua | 116 +++--------------------- 4 files changed, 98 insertions(+), 103 deletions(-) create mode 100644 internal/journal/contexts/adventure.lua create mode 100644 internal/journal/contexts/dummy.lua create mode 100644 internal/journal/contexts/fortress.lua diff --git a/internal/journal/contexts/adventure.lua b/internal/journal/contexts/adventure.lua new file mode 100644 index 0000000000..8ae6d9e2fc --- /dev/null +++ b/internal/journal/contexts/adventure.lua @@ -0,0 +1,38 @@ +--@ module = true + +AdventurerJournalContext = defclass(AdventurerJournalContext) +AdventurerJournalContext.ATTRS{ + save_prefix='', +} + +function get_adventurer_context_key(prefix, adventurer_id) + return string.format( + '%sjournal:adventurer:%s', + prefix, + adventurer_id + ) +end + +function AdventurerJournalContext:save(text, cursor) + if dfhack.isWorldLoaded() then + dfhack.persistent.saveSiteData( + get_adventurer_context_key(self.save_prefix, self.adventurer_id), + {text={text}, cursor={cursor}} + ) + end +end + +function AdventurerJournalContext:load() + if dfhack.isWorldLoaded() then + local site_data = dfhack.persistent.getSiteData( + get_adventurer_context_key(self.save_prefix, self.adventurer_id) + ) or {} + + if not site_data.text then + site_data.text={''} + site_data.show_tutorial = true + end + site_data.cursor = site_data.cursor or {#site_data.text[1] + 1} + return site_data + end +end diff --git a/internal/journal/contexts/dummy.lua b/internal/journal/contexts/dummy.lua new file mode 100644 index 0000000000..50178bab1e --- /dev/null +++ b/internal/journal/contexts/dummy.lua @@ -0,0 +1,13 @@ +--@ module = true + +-- Dummy Context, no storage -- + +DummyJournalContext = defclass(DummyJournalContext) + +function DummyJournalContext:save(text, cursor) +end + +function DummyJournalContext:load() + return {text={''}, cursor={1}, show_tutorial=true} +end + diff --git a/internal/journal/contexts/fortress.lua b/internal/journal/contexts/fortress.lua new file mode 100644 index 0000000000..db1a64c434 --- /dev/null +++ b/internal/journal/contexts/fortress.lua @@ -0,0 +1,34 @@ +--@ module = true + +FortressJournalContext = defclass(FortressJournalContext) +FortressJournalContext.ATTRS{ + save_prefix='' +} + +function get_fort_context_key(prefix) + return prefix .. 'journal' +end + +function FortressJournalContext:save(text, cursor) + if dfhack.isWorldLoaded() then + dfhack.persistent.saveSiteData( + get_fort_context_key(self.save_prefix), + {text={text}, cursor={cursor}} + ) + end +end + +function FortressJournalContext:load() + if dfhack.isWorldLoaded() then + local site_data = dfhack.persistent.getSiteData( + get_fort_context_key(self.save_prefix) + ) or {} + + if not site_data.text then + site_data.text={''} + site_data.show_tutorial = true + end + site_data.cursor = site_data.cursor or {#site_data.text[1] + 1} + return site_data + end +end diff --git a/internal/journal/journal_context.lua b/internal/journal/journal_context.lua index 61a3a86594..e85dc70ec0 100644 --- a/internal/journal/journal_context.lua +++ b/internal/journal/journal_context.lua @@ -1,119 +1,29 @@ --@ module = true local widgets = require 'gui.widgets' - -local JOURNAL_PERSIST_KEY = 'journal' +local utils = require('utils') +local DummyJournalContext = reqscript('internal/journal/contexts/dummy') +local FortressJournalContext = reqscript('internal/journal/contexts/fortress') +local AdventurerJournalContext = reqscript('internal/journal/contexts/adventure') function journal_context_factory(save_on_change, save_prefix) if not save_on_change then return DummyJournalContext{} elseif dfhack.world.isFortressMode() then - return FortJournalContext{save_prefix} + return FortressJournalContext{save_prefix} elseif dfhack.world.isAdventureMode() then + local interactions = df.global.adventure.interactions + if #interactions.party_core_members == 0 then + qerror('Can not identify party core member') + end + + local adventurer_id = interactions.party_core_members[0] + return AdventurerJournalContext{ save_prefix, - adventurer_id=dfhack.world.getAdventurer().id + adventurer_id=adventurer_id } else qerror('unsupported game mode') end end - - --- Fortress Context -- - -FortJournalContext = defclass(FortJournalContext) -FortJournalContext.ATTRS{ - save_prefix='' -} - -function get_fort_context_key(prefix) - return prefix .. JOURNAL_PERSIST_KEY -end - -function FortJournalContext:save(text, cursor) - if dfhack.isWorldLoaded() then - dfhack.persistent.saveSiteData( - get_fort_context_key(self.save_prefix), - {text={text}, cursor={cursor}} - ) - end -end - -function FortJournalContext:load() - if dfhack.isWorldLoaded() then - local site_data = dfhack.persistent.getSiteData( - get_fort_context_key(self.save_prefix) - ) or {} - - if not site_data.text then - site_data.text={''} - site_data.show_tutorial = true - end - site_data.cursor = site_data.cursor or {#site_data.text[1] + 1} - return site_data - end -end - --- Dummy Context, no storage -- - -DummyJournalContext = defclass(DummyJournalContext) - -function DummyJournalContext:save(text, cursor) -end - -function DummyJournalContext:load() - return {text={''}, cursor={1}, show_tutorial=true} -end - --- Dummy Context, no storage -- - -DummyJournalContext = defclass(DummyJournalContext) - -function DummyJournalContext:save(text, cursor) -end - -function DummyJournalContext:load() - return {text={''}, cursor={1}, show_tutorial=true} -end - --- Adventure Context -- - -AdventurerJournalContext = defclass(AdventurerJournalContext) -AdventurerJournalContext.ATTRS{ - save_prefix='', - adventurer_id='' -} - -function get_adventurer_context_key(prefix, adventurer_id) - return string.format( - '%s%s:adventurer:%s', - prefix, - JOURNAL_PERSIST_KEY, - adventurer_id - ) -end - -function AdventurerJournalContext:save(text, cursor) - if dfhack.isWorldLoaded() then - dfhack.persistent.saveSiteData( - get_adventurer_context_key(self.save_prefix, self.adventurer_id), - {text={text}, cursor={cursor}} - ) - end -end - -function AdventurerJournalContext:load() - if dfhack.isWorldLoaded() then - local site_data = dfhack.persistent.getSiteData( - get_adventurer_context_key(self.save_prefix, self.adventurer_id) - ) or {} - - if not site_data.text then - site_data.text={''} - site_data.show_tutorial = true - end - site_data.cursor = site_data.cursor or {#site_data.text[1] + 1} - return site_data - end -end From ee5308b4156ac1527932cf5888868da0ab9caa45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Wed, 26 Feb 2025 08:04:37 +0100 Subject: [PATCH 4/9] Make journal welcome text contextual (different for fort/adv) --- gui/journal.lua | 43 ++++++++----------------- internal/journal/contexts/adventure.lua | 35 ++++++++++++++++++-- internal/journal/contexts/dummy.lua | 21 ++++++++++-- internal/journal/contexts/fortress.lua | 34 +++++++++++++++++-- internal/journal/journal_context.lua | 9 +++--- 5 files changed, 101 insertions(+), 41 deletions(-) diff --git a/gui/journal.lua b/gui/journal.lua index 277e8ba2f3..30e12f7c67 100644 --- a/gui/journal.lua +++ b/gui/journal.lua @@ -12,29 +12,6 @@ local journal_context = reqscript('internal/journal/journal_context') local RESIZE_MIN = {w=54, h=20} local TOC_RESIZE_MIN = {w=24} -local JOURNAL_PERSIST_KEY = 'journal' - -local JOURNAL_WELCOME_COPY = [=[ -Welcome to gui/journal, the chronicler's tool for Dwarf Fortress! - -Here, you can carve out notes, sketch your grand designs, or record the history of your fortress. -The text you write here is saved together with your fort. - -For guidance on navigation and hotkeys, tap the ? button in the upper right corner. -Happy digging! -]=] - -local TOC_WELCOME_COPY = [=[ -Start a line with # symbols and a space to create a header. For example: - -# My section heading - -or - -## My section subheading - -Those headers will appear here, and you can click on them to jump to them in the text.]=] - journal_config = journal_config or json.open('dfhack-config/journal.json') JournalWindow = defclass(JournalWindow, widgets.Window) @@ -48,6 +25,9 @@ JournalWindow.ATTRS { save_layout=true, show_tutorial=false, + toc_welcome_copy=DEFAULT_NIL, + journal_welcome_copy=DEFAULT_NIL, + on_text_change=DEFAULT_NIL, on_cursor_change=DEFAULT_NIL, on_layout_change=DEFAULT_NIL @@ -77,7 +57,7 @@ function JournalWindow:init() widgets.WrappedLabel{ view_id='table_of_contents_tutorial', frame={l=0,t=0,r=0,b=3}, - text_to_wrap=TOC_WELCOME_COPY, + text_to_wrap=self.toc_welcome_copy or '', visible=false } } @@ -144,7 +124,7 @@ function JournalWindow:init() widgets.WrappedLabel{ view_id='journal_tutorial', frame={l=0,t=1,r=0,b=0}, - text_to_wrap=JOURNAL_WELCOME_COPY + text_to_wrap=self.journal_welcome_copy or '' } } end @@ -296,7 +276,7 @@ function JournalScreen:init() self.save_prefix, self.save_on_change ) - local context = self.journal_context:load() + local content = self.journal_context:load_content() self:addviews{ JournalWindow{ @@ -305,9 +285,12 @@ function JournalScreen:init() save_layout=self.save_layout, - init_text=context.text[1], - init_cursor=context.cursor[1], - show_tutorial=context.show_tutorial or false, + init_text=content.text[1], + init_cursor=content.cursor[1], + show_tutorial=content.show_tutorial or false, + + toc_welcome_copy=self.journal_context:tocWelcomeCopy(), + journal_welcome_copy=self.journal_context:welcomeCopy(), on_text_change=self:callback('onTextChange'), on_cursor_change=self:callback('onTextChange') @@ -319,7 +302,7 @@ function JournalScreen:onTextChange() local text = self.subviews.journal_editor:getText() local cursor = self.subviews.journal_editor:getCursor() - self.journal_context:save(text, cursor) + self.journal_context:save_content(text, cursor) end function JournalScreen:onDismiss() diff --git a/internal/journal/contexts/adventure.lua b/internal/journal/contexts/adventure.lua index 8ae6d9e2fc..5d8faffe34 100644 --- a/internal/journal/contexts/adventure.lua +++ b/internal/journal/contexts/adventure.lua @@ -1,8 +1,31 @@ --@ module = true +local JOURNAL_WELCOME_COPY = [=[ +Welcome to gui/journal, the adventurer's notebook for Dwarf Fortress! + +Here, you can jot down your travels, keep track of important places, or note anything worth remembering. +The text you write here is saved together with your adventurer. + +For guidance on navigation and hotkeys, tap the ? button in the upper right corner. +Safe travels! +]=] + +local TOC_WELCOME_COPY = [=[ +Start a line with # symbols and a space to create a header. For example: + +# My section heading + +or + +## My section subheading + +Those headers will appear here, and you can click on them to jump to them in the text.]=] + + AdventurerJournalContext = defclass(AdventurerJournalContext) AdventurerJournalContext.ATTRS{ save_prefix='', + adventurer_id=DEFAULT_NIL } function get_adventurer_context_key(prefix, adventurer_id) @@ -13,7 +36,7 @@ function get_adventurer_context_key(prefix, adventurer_id) ) end -function AdventurerJournalContext:save(text, cursor) +function AdventurerJournalContext:save_content(text, cursor) if dfhack.isWorldLoaded() then dfhack.persistent.saveSiteData( get_adventurer_context_key(self.save_prefix, self.adventurer_id), @@ -22,7 +45,7 @@ function AdventurerJournalContext:save(text, cursor) end end -function AdventurerJournalContext:load() +function AdventurerJournalContext:load_content() if dfhack.isWorldLoaded() then local site_data = dfhack.persistent.getSiteData( get_adventurer_context_key(self.save_prefix, self.adventurer_id) @@ -36,3 +59,11 @@ function AdventurerJournalContext:load() return site_data end end + +function AdventurerJournalContext:welcomeCopy() + return JOURNAL_WELCOME_COPY +end + +function AdventurerJournalContext:tocWelcomeCopy() + return TOC_WELCOME_COPY +end diff --git a/internal/journal/contexts/dummy.lua b/internal/journal/contexts/dummy.lua index 50178bab1e..aa3f55d338 100644 --- a/internal/journal/contexts/dummy.lua +++ b/internal/journal/contexts/dummy.lua @@ -1,13 +1,30 @@ --@ module = true +local JOURNAL_WELCOME_COPY = [=[ +Welcome to gui/journal. This is dummy context and it should be available only +in automatic tests. +]=] + +local TOC_WELCOME_COPY = [=[ +This is Table of Contenst test welcome copy +]=] + + -- Dummy Context, no storage -- DummyJournalContext = defclass(DummyJournalContext) -function DummyJournalContext:save(text, cursor) +function DummyJournalContext:save_content(text, cursor) end -function DummyJournalContext:load() +function DummyJournalContext:load_content() return {text={''}, cursor={1}, show_tutorial=true} end +function DummyJournalContext:welcomeCopy() + return JOURNAL_WELCOME_COPY +end + +function DummyJournalContext:tocWelcomeCopy() + return TOC_WELCOME_COPY +end diff --git a/internal/journal/contexts/fortress.lua b/internal/journal/contexts/fortress.lua index db1a64c434..c8e8f2a8a0 100644 --- a/internal/journal/contexts/fortress.lua +++ b/internal/journal/contexts/fortress.lua @@ -1,5 +1,27 @@ --@ module = true +local JOURNAL_WELCOME_COPY = [=[ +Welcome to gui/journal, the chronicler's tool for Dwarf Fortress! + +Here, you can carve out notes, sketch your grand designs, or record the history of your fortress. +The text you write here is saved together with your fort. + +For guidance on navigation and hotkeys, tap the ? button in the upper right corner. +Happy digging! +]=] + +local TOC_WELCOME_COPY = [=[ +Start a line with # symbols and a space to create a header. For example: + +# My section heading + +or + +## My section subheading + +Those headers will appear here, and you can click on them to jump to them in the text.]=] + + FortressJournalContext = defclass(FortressJournalContext) FortressJournalContext.ATTRS{ save_prefix='' @@ -9,7 +31,7 @@ function get_fort_context_key(prefix) return prefix .. 'journal' end -function FortressJournalContext:save(text, cursor) +function FortressJournalContext:save_content(text, cursor) if dfhack.isWorldLoaded() then dfhack.persistent.saveSiteData( get_fort_context_key(self.save_prefix), @@ -18,7 +40,7 @@ function FortressJournalContext:save(text, cursor) end end -function FortressJournalContext:load() +function FortressJournalContext:load_content() if dfhack.isWorldLoaded() then local site_data = dfhack.persistent.getSiteData( get_fort_context_key(self.save_prefix) @@ -32,3 +54,11 @@ function FortressJournalContext:load() return site_data end end + +function FortressJournalContext:welcomeCopy() + return JOURNAL_WELCOME_COPY +end + +function FortressJournalContext:tocWelcomeCopy() + return TOC_WELCOME_COPY +end diff --git a/internal/journal/journal_context.lua b/internal/journal/journal_context.lua index e85dc70ec0..a9b7485aaf 100644 --- a/internal/journal/journal_context.lua +++ b/internal/journal/journal_context.lua @@ -2,9 +2,9 @@ local widgets = require 'gui.widgets' local utils = require('utils') -local DummyJournalContext = reqscript('internal/journal/contexts/dummy') -local FortressJournalContext = reqscript('internal/journal/contexts/fortress') -local AdventurerJournalContext = reqscript('internal/journal/contexts/adventure') +local DummyJournalContext = reqscript('internal/journal/contexts/dummy').DummyJournalContext +local FortressJournalContext = reqscript('internal/journal/contexts/fortress').FortressJournalContext +local AdventurerJournalContext = reqscript('internal/journal/contexts/adventure').AdventurerJournalContext function journal_context_factory(save_on_change, save_prefix) if not save_on_change then @@ -13,12 +13,11 @@ function journal_context_factory(save_on_change, save_prefix) return FortressJournalContext{save_prefix} elseif dfhack.world.isAdventureMode() then local interactions = df.global.adventure.interactions - if #interactions.party_core_members == 0 then + if #interactions.party_core_members == 0 or interactions.party_core_members[0] == nil then qerror('Can not identify party core member') end local adventurer_id = interactions.party_core_members[0] - return AdventurerJournalContext{ save_prefix, adventurer_id=adventurer_id From 4c047c1d23fd9e0ba1eeb676db5765dc8b9dad26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Wed, 26 Feb 2025 08:20:20 +0100 Subject: [PATCH 5/9] Adjust journal help to adventurer support --- docs/gui/journal.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/gui/journal.rst b/docs/gui/journal.rst index 0063ff63ad..d773e2f863 100644 --- a/docs/gui/journal.rst +++ b/docs/gui/journal.rst @@ -6,11 +6,11 @@ gui/journal :tags: fort interface The `gui/journal` interface makes it easy to take notes and document -important details for the fortresses. +important details for your fortresses and adventurers. With this multi-line text editor, -you can keep track of your fortress's background story, goals, notable events, -and both short-term and long-term plans. +you can keep track of your fortress's/adventurer's background story, goals, +notable events, and both short-term and long-term plans. This is particularly useful when you need to take a longer break from the game. Having detailed notes makes it much easier to resume your game after From bafc23dc0017d0d738a3b5d03dad2167c752afe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Wed, 26 Feb 2025 18:17:40 +0100 Subject: [PATCH 6/9] Make gui/journal contexts testable --- gui/journal.lua | 14 +++++--- internal/journal/contexts/adventure.lua | 22 +++++++++---- internal/journal/contexts/dummy.lua | 17 +++------- internal/journal/contexts/fortress.lua | 8 +++++ internal/journal/journal_context.lua | 27 +++++++++++++--- test/gui/journal.lua | 43 +++++++++++++++++++------ 6 files changed, 92 insertions(+), 39 deletions(-) diff --git a/gui/journal.lua b/gui/journal.lua index 30e12f7c67..5010933392 100644 --- a/gui/journal.lua +++ b/gui/journal.lua @@ -14,6 +14,8 @@ local TOC_RESIZE_MIN = {w=24} journal_config = journal_config or json.open('dfhack-config/journal.json') +JOURNAL_CONTEXT_MODE = journal_context.JOURNAL_CONTEXT_MODE + JournalWindow = defclass(JournalWindow, widgets.Window) JournalWindow.ATTRS { frame_title='DF Journal', @@ -266,15 +268,15 @@ end JournalScreen = defclass(JournalScreen, gui.ZScreen) JournalScreen.ATTRS { focus_path='journal', - save_on_change=true, + context_mode=DEFAULT_NIL, save_layout=true, save_prefix='' } function JournalScreen:init() self.journal_context = journal_context.journal_context_factory( - self.save_prefix, - self.save_on_change + self.context_mode, + self.save_prefix ) local content = self.journal_context:load_content() @@ -316,12 +318,14 @@ function main(options) end local save_layout = options and options.save_layout - local save_on_change = options and options.save_on_change + local overrided_context_mode = options and options.context_mode + local context_mode = overrided_context_mode == nil and + journal_context.detect_journal_context_mode() or overrided_context_mode view = view and view:raise() or JournalScreen{ save_prefix=options and options.save_prefix or '', save_layout=save_layout == nil and true or save_layout, - save_on_change=save_on_change == nil and true or save_on_change, + context_mode=context_mode, }:show() end diff --git a/internal/journal/contexts/adventure.lua b/internal/journal/contexts/adventure.lua index 5d8faffe34..9957cbb615 100644 --- a/internal/journal/contexts/adventure.lua +++ b/internal/journal/contexts/adventure.lua @@ -38,7 +38,7 @@ end function AdventurerJournalContext:save_content(text, cursor) if dfhack.isWorldLoaded() then - dfhack.persistent.saveSiteData( + dfhack.persistent.saveWorldData( get_adventurer_context_key(self.save_prefix, self.adventurer_id), {text={text}, cursor={cursor}} ) @@ -47,16 +47,24 @@ end function AdventurerJournalContext:load_content() if dfhack.isWorldLoaded() then - local site_data = dfhack.persistent.getSiteData( + local world_data = dfhack.persistent.getWorldData( get_adventurer_context_key(self.save_prefix, self.adventurer_id) ) or {} - if not site_data.text then - site_data.text={''} - site_data.show_tutorial = true + if not world_data.text then + world_data.text={''} + world_data.show_tutorial = true end - site_data.cursor = site_data.cursor or {#site_data.text[1] + 1} - return site_data + world_data.cursor = world_data.cursor or {#world_data.text[1] + 1} + return world_data + end +end + +function AdventurerJournalContext:delete_content() + if dfhack.isWorldLoaded() then + dfhack.persistent.deleteWorldData( + get_adventurer_context_key(self.save_prefix, self.adventurer_id) + ) end end diff --git a/internal/journal/contexts/dummy.lua b/internal/journal/contexts/dummy.lua index aa3f55d338..1993bb770b 100644 --- a/internal/journal/contexts/dummy.lua +++ b/internal/journal/contexts/dummy.lua @@ -1,15 +1,5 @@ --@ module = true -local JOURNAL_WELCOME_COPY = [=[ -Welcome to gui/journal. This is dummy context and it should be available only -in automatic tests. -]=] - -local TOC_WELCOME_COPY = [=[ -This is Table of Contenst test welcome copy -]=] - - -- Dummy Context, no storage -- DummyJournalContext = defclass(DummyJournalContext) @@ -21,10 +11,13 @@ function DummyJournalContext:load_content() return {text={''}, cursor={1}, show_tutorial=true} end +function DummyJournalContext:delete_content() +end + function DummyJournalContext:welcomeCopy() - return JOURNAL_WELCOME_COPY + return '' end function DummyJournalContext:tocWelcomeCopy() - return TOC_WELCOME_COPY + return '' end diff --git a/internal/journal/contexts/fortress.lua b/internal/journal/contexts/fortress.lua index c8e8f2a8a0..46a28f568c 100644 --- a/internal/journal/contexts/fortress.lua +++ b/internal/journal/contexts/fortress.lua @@ -55,6 +55,14 @@ function FortressJournalContext:load_content() end end +function FortressJournalContext:delete_content() + if dfhack.isWorldLoaded() then + dfhack.persistent.deleteSiteData( + get_fort_context_key(self.save_prefix) + ) + end +end + function FortressJournalContext:welcomeCopy() return JOURNAL_WELCOME_COPY end diff --git a/internal/journal/journal_context.lua b/internal/journal/journal_context.lua index a9b7485aaf..989e10f06c 100644 --- a/internal/journal/journal_context.lua +++ b/internal/journal/journal_context.lua @@ -6,22 +6,39 @@ local DummyJournalContext = reqscript('internal/journal/contexts/dummy').DummyJo local FortressJournalContext = reqscript('internal/journal/contexts/fortress').FortressJournalContext local AdventurerJournalContext = reqscript('internal/journal/contexts/adventure').AdventurerJournalContext -function journal_context_factory(save_on_change, save_prefix) - if not save_on_change then - return DummyJournalContext{} - elseif dfhack.world.isFortressMode() then - return FortressJournalContext{save_prefix} +JOURNAL_CONTEXT_MODE = { + FORTRESS='fortress', + ADVENTURE='adventure', + DUMMY='dummy' +} + +function detect_journal_context_mode() + if dfhack.world.isFortressMode() then + return JOURNAL_CONTEXT_MODE.FORTRESS elseif dfhack.world.isAdventureMode() then + return JOURNAL_CONTEXT_MODE.ADVENTURE + else + qerror('unsupported game mode') + end +end + +function journal_context_factory(journal_context_mode, save_prefix) + if journal_context_mode == JOURNAL_CONTEXT_MODE.FORTRESS then + return FortressJournalContext{save_prefix} + elseif journal_context_mode == JOURNAL_CONTEXT_MODE.ADVENTURE then local interactions = df.global.adventure.interactions if #interactions.party_core_members == 0 or interactions.party_core_members[0] == nil then qerror('Can not identify party core member') end local adventurer_id = interactions.party_core_members[0] + return AdventurerJournalContext{ save_prefix, adventurer_id=adventurer_id } + elseif journal_context_mode == JOURNAL_CONTEXT_MODE.DUMMY then + return DummyJournalContext{} else qerror('unsupported game mode') end diff --git a/test/gui/journal.lua b/test/gui/journal.lua index 19975a7379..2ce3288886 100644 --- a/test/gui/journal.lua +++ b/test/gui/journal.lua @@ -1,5 +1,6 @@ local gui = require('gui') local gui_journal = reqscript('gui/journal') +local journal_context = reqscript('internal/journal/journal_context') config = { target = 'gui/journal', @@ -75,8 +76,8 @@ local function arrange_empty_journal(options) options = options or {} gui_journal.main({ - save_prefix='test:', - save_on_change=options.save_on_change or false, + save_prefix=options.save_prefix or 'test:', + context_mode=options.context_mode or gui_journal.JOURNAL_CONTEXT_MODE.DUMMY, save_layout=options.allow_layout_restore or false, }) @@ -98,9 +99,9 @@ local function arrange_empty_journal(options) local text_area = journal_window.subviews.journal_editor.text_area text_area.enable_cursor_blink = false - if not options.save_on_change then - text_area:setText('') - end + -- if not options.save_on_change then + -- text_area:setText('') + -- end if not options.allow_layout_restore then local toc_panel = journal_window.subviews.table_of_contents_panel @@ -202,7 +203,10 @@ function test.restore_layout() end function test.restore_text_between_sessions() - local journal, text_area = arrange_empty_journal({w=80,save_on_change=true}) + local journal, text_area = arrange_empty_journal({ + w=80, + context_mode=gui_journal.JOURNAL_CONTEXT_MODE.FORTRESS + }) simulate_input_keys('CUSTOM_CTRL_A') simulate_input_keys('CUSTOM_DELETE') @@ -224,7 +228,10 @@ function test.restore_text_between_sessions() journal:dismiss() - journal, text_area = arrange_empty_journal({w=80, save_on_change=true}) + journal, text_area = arrange_empty_journal({ + w=80, + context_mode=gui_journal.JOURNAL_CONTEXT_MODE.FORTRESS + }) expect.eq(read_rendered_text(text_area), table.concat({ '60: Lorem ipsum dolor sit amet, consectetur adipiscing elit.', @@ -600,11 +607,27 @@ function test.table_of_contents_keyboard_navigation() journal:dismiss() end -function test.show_tutorials_on_first_use() - local journal, text_area, journal_window = arrange_empty_journal({w=65}) +function test.show_fortress_tutorials_on_first_use() + local save_prefix = 'test:' + local context = journal_context.journal_context_factory( + gui_journal.JOURNAL_CONTEXT_MODE.FORTRESS, + save_prefix + ) + -- reset saved data + context:delete_content() + + local journal, text_area, journal_window = arrange_empty_journal({ + w=125, + context_mode=gui_journal.JOURNAL_CONTEXT_MODE.FORTRESS, + save_prefix=save_prefix + }) + simulate_input_keys('CUSTOM_CTRL_O') - expect.str_find('Welcome to gui/journal', read_rendered_text(text_area)); + expect.str_find( + "Welcome to gui/journal, the chronicler's tool for Dwarf Fortress!", + read_rendered_text(text_area) + ); simulate_input_text(' ') From 68c2ebbcb5a158f0121b5b238aba6494a5b52236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Wed, 26 Feb 2025 18:32:40 +0100 Subject: [PATCH 7/9] Add adventure mode journal info to changelog --- changelog.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/changelog.txt b/changelog.txt index b4e7bddd2d..69947583bc 100644 --- a/changelog.txt +++ b/changelog.txt @@ -34,6 +34,7 @@ Template for new versions: ## New Features - `advtools`: new ``advtools.fastcombat`` overlay (enabled by default) allows you to skip combat animations and the announcement "More" button by mashing the movement keys +- `gui/journal`: now working in adventure mode ## Fixes - `position`: support for adv mode look cursor From 1feabe8769bc4475af2dfdeae071a61680f9ea67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Wiktor=20Obr=C4=99bski?= Date: Wed, 26 Feb 2025 19:22:08 +0100 Subject: [PATCH 8/9] Remove redundant comment --- test/gui/journal.lua | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/gui/journal.lua b/test/gui/journal.lua index 2ce3288886..8571937157 100644 --- a/test/gui/journal.lua +++ b/test/gui/journal.lua @@ -99,9 +99,6 @@ local function arrange_empty_journal(options) local text_area = journal_window.subviews.journal_editor.text_area text_area.enable_cursor_blink = false - -- if not options.save_on_change then - -- text_area:setText('') - -- end if not options.allow_layout_restore then local toc_panel = journal_window.subviews.table_of_contents_panel From 1552b528739c0a78b28005eea9cd7e586ff8c812 Mon Sep 17 00:00:00 2001 From: Myk Date: Fri, 7 Mar 2025 15:36:53 -0800 Subject: [PATCH 9/9] add adventure tag --- docs/gui/journal.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/gui/journal.rst b/docs/gui/journal.rst index d773e2f863..5240002c5c 100644 --- a/docs/gui/journal.rst +++ b/docs/gui/journal.rst @@ -3,7 +3,7 @@ gui/journal .. dfhack-tool:: :summary: Fort journal with a multi-line text editor. - :tags: fort interface + :tags: adventure fort interface The `gui/journal` interface makes it easy to take notes and document important details for your fortresses and adventurers.