From 28779f45bba67a9d5cc7f88332e819a65e8ca845 Mon Sep 17 00:00:00 2001 From: Alex Noir Date: Fri, 14 Jun 2024 16:51:20 +0300 Subject: [PATCH 1/9] Update adv-rumors to be able to "ask whereabouts of" for all your histfig relationships --- adv-rumors.lua | 95 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 2 deletions(-) diff --git a/adv-rumors.lua b/adv-rumors.lua index 4e334a8724..f2494940c4 100644 --- a/adv-rumors.lua +++ b/adv-rumors.lua @@ -17,6 +17,23 @@ ignore_words = utils.invert{ local adventure = df.global.game.main_interface.adventure -- CORE FUNCTIONS +-- Helper function to create new dialog choices, returns the created choice +local function new_choice(choice_type, title, keywords) + local choice = df.adventure_conversation_choice_infost:new() + choice.cc = df.talk_choice:new() + choice.cc.type = choice_type + local text = df.new("string") + text.value = title + choice.print_string.text:insert("#", text) + + if keywords ~= nil then + for i, key in ipairs(keywords) do + addKeyword(choice, key) + end + end + return choice +end + -- Gets the keywords already present on the dialog choice local function getKeywords(choice) local keywords = {} @@ -68,8 +85,76 @@ local function generateKeywordsForChoice(choice) addKeywords(choice, new_keywords) end +local function addHistFigWhereaboutsChoice(profile) + local histfig = df.historical_figure.find(profile.histfig_id) + local name = "" + local creature = df.creature_raw.find(histfig.race) + if creature then + local caste = creature.caste[histfig.caste] + name = caste.caste_name[0] + end + local title = "Ask for the whereabouts of the " .. name .. " " .. dfhack.TranslateName(histfig.name) + if profile._type == df.relationship_profile_hf_historicalst then + title = title .. " (Heard of)" + end + local choice = new_choice(df.talk_choice_type.AskWhereabouts, title) + -- insert before the last choice, which is usually "back" + adventure.conversation.conv_choice_info:insert(#adventure.conversation.conv_choice_info-1, choice) + choice.cc.invocation_target_hfid = histfig.id +end + +local function addIdentityWhereaboutsChoice(identity) + local identity_name = identity.name + local name = "" + local creature = df.creature_raw.find(identity.race) + if creature then + local caste = creature.caste[identity.caste] + name = caste.caste_name[0] + else + -- no race given for the identity, assume it's the histfig + local histfig = df.historical_figure.find(identity.histfig_id) + creature = df.creature_raw.find(histfig.race) + if creature then + local caste = creature.caste[histfig.caste] + name = caste.caste_name[0] + end + end + local title = "Ask for the whereabouts of the " .. name .. " " .. dfhack.TranslateName(identity_name) + local choice = new_choice(df.talk_choice_type.AskWhereabouts, title) + -- insert before the last choice, which is usually "back" + adventure.conversation.conv_choice_info:insert(#adventure.conversation.conv_choice_info-1, choice) + choice.cc.invocation_target_hfid = identity.impersonated_hf +end + -- Condense the rumor system choices local function rumorUpdate() + local conversation_state = adventure.conversation.conv_act.event[0].state + -- add new conversation options depending on state + if conversation_state == df.conversation_state_type.AskDirections then + local adventurer_figure = df.historical_figure.find(dfhack.world.getAdventurer().hist_figure_id) + local relationships = adventurer_figure.info.relationships + + local visual = relationships.hf_visual + local historical = relationships.hf_historical + local identity = relationships.hf_identity + + for _, profile in pairs(visual) do + addHistFigWhereaboutsChoice(profile) + end + + -- This option will likely always fail unless the false identity is impersonating someone + -- but giving away the false identity's true historical figure feels cheap. + for _, profile in pairs(identity) do + addIdentityWhereaboutsChoice(df.identity.find(profile.identity_id)) + end + + -- Historical entities go last so as to not give away fake identities + for _, profile in pairs(historical) do + addHistFigWhereaboutsChoice(profile) + end + end + + -- generate extra keywords for i, choice in ipairs(adventure.conversation.conv_choice_info) do generateKeywordsForChoice(choice) end @@ -85,8 +170,14 @@ AdvRumorsOverlay.ATTRS{ viewscreens='dungeonmode/Conversation', } -OVERLAY_WIDGETS = {conversation=AdvRumorsOverlay} - +local last_first_entry = nil function AdvRumorsOverlay:render() + -- Only update if the first entry pointer changed, this reliably indicates the list changed + if #adventure.conversation.conv_choice_info <= 0 or last_first_entry == adventure.conversation.conv_choice_info[0] then return end + + -- Remember the last first entry. This entry changes even if we quit out and return on the same menu! + last_first_entry = adventure.conversation.conv_choice_info[0] rumorUpdate() end + +OVERLAY_WIDGETS = {conversation=AdvRumorsOverlay} \ No newline at end of file From 177a3bb62c884dd6596569961e64cfeed5eb9068 Mon Sep 17 00:00:00 2001 From: Alex Noir Date: Sun, 16 Jun 2024 02:31:55 +0300 Subject: [PATCH 2/9] Fix duplicates Add keywords for both versions of names --- adv-rumors.lua | 62 ++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 22 deletions(-) diff --git a/adv-rumors.lua b/adv-rumors.lua index f2494940c4..05b66d6740 100644 --- a/adv-rumors.lua +++ b/adv-rumors.lua @@ -17,23 +17,6 @@ ignore_words = utils.invert{ local adventure = df.global.game.main_interface.adventure -- CORE FUNCTIONS --- Helper function to create new dialog choices, returns the created choice -local function new_choice(choice_type, title, keywords) - local choice = df.adventure_conversation_choice_infost:new() - choice.cc = df.talk_choice:new() - choice.cc.type = choice_type - local text = df.new("string") - text.value = title - choice.print_string.text:insert("#", text) - - if keywords ~= nil then - for i, key in ipairs(keywords) do - addKeyword(choice, key) - end - end - return choice -end - -- Gets the keywords already present on the dialog choice local function getKeywords(choice) local keywords = {} @@ -85,7 +68,31 @@ local function generateKeywordsForChoice(choice) addKeywords(choice, new_keywords) end +-- Helper function to create new dialog choices, returns the created choice +local function new_choice(choice_type, title, keywords) + local choice = df.adventure_conversation_choice_infost:new() + choice.cc = df.talk_choice:new() + choice.cc.type = choice_type + local text = df.new("string") + text.value = title + choice.print_string.text:insert("#", text) + + if keywords ~= nil then + addKeywords(choice, keywords) + end + return choice +end + local function addHistFigWhereaboutsChoice(profile) + for i, c in pairs(adventure.conversation.conv_choice_info) do + if c.cc.type == df.talk_choice_type.AskWhereabouts and + c.cc.invocation_target_hfid ~= -1 and + c.cc.invocation_target_hfid == profile.histfig_id then + -- Don't add repeat entries + return + end + end + local histfig = df.historical_figure.find(profile.histfig_id) local name = "" local creature = df.creature_raw.find(histfig.race) @@ -93,17 +100,25 @@ local function addHistFigWhereaboutsChoice(profile) local caste = creature.caste[histfig.caste] name = caste.caste_name[0] end - local title = "Ask for the whereabouts of the " .. name .. " " .. dfhack.TranslateName(histfig.name) + local title = "Ask for the whereabouts of the " .. name .. " " .. dfhack.TranslateName(histfig.name, true) if profile._type == df.relationship_profile_hf_historicalst then title = title .. " (Heard of)" end - local choice = new_choice(df.talk_choice_type.AskWhereabouts, title) + local choice = new_choice(df.talk_choice_type.AskWhereabouts, title, dfhack.TranslateName(histfig.name):split()) -- insert before the last choice, which is usually "back" adventure.conversation.conv_choice_info:insert(#adventure.conversation.conv_choice_info-1, choice) choice.cc.invocation_target_hfid = histfig.id end local function addIdentityWhereaboutsChoice(identity) + for i, c in pairs(adventure.conversation.conv_choice_info) do + if c.cc.type == df.talk_choice_type.AskWhereabouts and + c.cc.invocation_target_hfid ~= -1 and + c.cc.invocation_target_hfid == identity.impersonated_hf then + -- Don't add repeat entries + return + end + end local identity_name = identity.name local name = "" local creature = df.creature_raw.find(identity.race) @@ -119,10 +134,10 @@ local function addIdentityWhereaboutsChoice(identity) name = caste.caste_name[0] end end - local title = "Ask for the whereabouts of the " .. name .. " " .. dfhack.TranslateName(identity_name) + local title = "Ask for the whereabouts of the " .. name .. " " .. dfhack.TranslateName(identity_name, true) local choice = new_choice(df.talk_choice_type.AskWhereabouts, title) -- insert before the last choice, which is usually "back" - adventure.conversation.conv_choice_info:insert(#adventure.conversation.conv_choice_info-1, choice) + adventure.conversation.conv_choice_info:insert(#adventure.conversation.conv_choice_info-1, choice, dfhack.TranslateName(identity_name):split()) choice.cc.invocation_target_hfid = identity.impersonated_hf end @@ -130,6 +145,9 @@ end local function rumorUpdate() local conversation_state = adventure.conversation.conv_act.event[0].state -- add new conversation options depending on state + + -- If we're asking about directions, add ability to ask about all our relationships - visual, historical and identities. + -- In vanilla, we're only allowed to ask for directions to people we learned in anything that's added to df.global.adventure.rumor if conversation_state == df.conversation_state_type.AskDirections then local adventurer_figure = df.historical_figure.find(dfhack.world.getAdventurer().hist_figure_id) local relationships = adventurer_figure.info.relationships @@ -154,7 +172,7 @@ local function rumorUpdate() end end - -- generate extra keywords + -- generate extra keywords for all options for i, choice in ipairs(adventure.conversation.conv_choice_info) do generateKeywordsForChoice(choice) end From de730387d43f8835faae7153dd624c357a72341d Mon Sep 17 00:00:00 2001 From: Alex Noir Date: Sat, 22 Jun 2024 17:03:09 +0300 Subject: [PATCH 3/9] Fix addKeyword not doing toSearchNormalized Fix OVERLAY_WIDGETS global being present in the internal script --- internal/advtools/convo.lua | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/internal/advtools/convo.lua b/internal/advtools/convo.lua index b391290167..5446b67d32 100644 --- a/internal/advtools/convo.lua +++ b/internal/advtools/convo.lua @@ -22,7 +22,7 @@ end -- Adds a keyword to the dialog choice local function addKeyword(choice, keyword) local keyword_ptr = df.new('string') - keyword_ptr.value = keyword + keyword_ptr.value = dfhack.toSearchNormalized(keyword) choice.key_word:insert('#', keyword_ptr) end @@ -190,5 +190,3 @@ function AdvRumorsOverlay:render() last_first_entry = adventure.conversation.conv_choice_info[0] rumorUpdate() end - -OVERLAY_WIDGETS = {conversation=AdvRumorsOverlay} \ No newline at end of file From 168a278f1d90566a8c9f55455ae4c3eeb36509b6 Mon Sep 17 00:00:00 2001 From: Alex Noir Date: Sat, 22 Jun 2024 17:05:38 +0300 Subject: [PATCH 4/9] changelog and docs --- changelog.txt | 1 + docs/advtools.rst | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 80cb86fad8..8c1c1803a4 100644 --- a/changelog.txt +++ b/changelog.txt @@ -40,6 +40,7 @@ Template for new versions: - `buildingplan`: dimension tooltip is now displayed for constructions and buildings that are designated over an area - `gui/notify`: new notification type: injured citizens; click to zoom to injured units; also displays warning if your hospital is not functional (or if you have no hospital) - `prioritize`: new info panel on under-construction buildings showing if the construction job has been taken and by whom. click to zoom to builder; toggle high priority status for job if it's not yet taken and you need it to be built ASAP +- `advtools convo`: add a new conversation option to "ask whereabouts of" for all your relationships (before, you could only ask whereabouts of people involved in rumors only) ## Fixes - `item`: don't match uncollected spider webs when you search for "silk" diff --git a/docs/advtools.rst b/docs/advtools.rst index 6c904f36c4..3be128d4de 100644 --- a/docs/advtools.rst +++ b/docs/advtools.rst @@ -35,4 +35,7 @@ framework. They can be repositioned via `gui/overlay` or toggled via When enabled, this overlay will automatically add additional searchable keywords to conversation topics. In particular, topics that relate to slain -enemies will gain the ``slay`` and ``kill`` keywords. +enemies will gain the ``slay`` and ``kill`` keywords. It will also add additional +conversation options for asking whereabouts of your relationships - in vanilla, +you can only ask whereabouts of historical figures involved in rumors you personally +witnessed or heard about. From ddc518bedf478471d85ef1ae0111caf158794a37 Mon Sep 17 00:00:00 2001 From: Alex Noir Date: Sat, 22 Jun 2024 17:11:05 +0300 Subject: [PATCH 5/9] fix invalid changelog --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index af4e62fe9d..c52783f2b3 100644 --- a/changelog.txt +++ b/changelog.txt @@ -41,7 +41,7 @@ Template for new versions: - `gui/notify`: new notification type: injured citizens; click to zoom to injured units; also displays a warning if your hospital is not functional (or if you have no hospital) - `prioritize`: new info panel on under-construction buildings showing if the construction job has been taken and by whom. click to zoom to builder; toggle high priority status for job if it's not yet taken and you need it to be built ASAP - `gui/pathable`: new "Depot" mode that shows whether wagons can path to your trade depot -- `advtools convo`: add a new conversation option to "ask whereabouts of" for all your relationships (before, you could only ask whereabouts of people involved in rumors only) +- `advtools`: convo - add a new conversation option to "ask whereabouts of" for all your relationships (before, you could only ask whereabouts of people involved in rumors only) ## Fixes - `item`: don't match uncollected spider webs when you search for "silk" From f31c34407dc5cc4bfe62034c685c41c4b1e471f5 Mon Sep 17 00:00:00 2001 From: Alex Noir Date: Sun, 30 Jun 2024 01:49:05 +0300 Subject: [PATCH 6/9] Adjust to new var names --- internal/advtools/convo.lua | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/advtools/convo.lua b/internal/advtools/convo.lua index 1bd62193ae..9c478c175c 100644 --- a/internal/advtools/convo.lua +++ b/internal/advtools/convo.lua @@ -13,7 +13,7 @@ local adventure = df.global.game.main_interface.adventure -- Gets the keywords already present on the dialog choice local function getKeywords(choice) local keywords = {} - for _, keyword in ipairs(choice.key_word) do + for _, keyword in ipairs(choice.keywords) do table.insert(keywords, keyword.value:lower()) end return keywords @@ -23,7 +23,7 @@ end local function addKeyword(choice, keyword) local keyword_ptr = df.new('string') keyword_ptr.value = dfhack.toSearchNormalized(keyword) - choice.key_word:insert('#', keyword_ptr) + choice.keywords:insert('#', keyword_ptr) end -- Adds multiple keywords to the dialog choice @@ -45,7 +45,7 @@ local function generateKeywordsForChoice(choice) end -- generate keywords from useful words in the text - for _, data in ipairs(choice.print_string.text) do + for _, data in ipairs(choice.title.text) do for word in dfhack.toSearchNormalized(data.value):gmatch('%w+') do -- collect additional keywords based on the special words if word == 'slew' or word == 'slain' then @@ -68,7 +68,7 @@ local function new_choice(choice_type, title, keywords) choice.cc.type = choice_type local text = df.new("string") text.value = title - choice.print_string.text:insert("#", text) + choice.title.text:insert("#", text) if keywords ~= nil then addKeywords(choice, keywords) @@ -136,7 +136,7 @@ end -- Condense the rumor system choices local function rumorUpdate() - local conversation_state = adventure.conversation.conv_act.event[0].state + local conversation_state = adventure.conversation.conv_act.events[0].menu -- add new conversation options depending on state -- If we're asking about directions, add ability to ask about all our relationships - visual, historical and identities. From dcd3114472f5cb222f3214e15b0d6f9b97127153 Mon Sep 17 00:00:00 2001 From: Crystalwarrior Date: Sun, 30 Jun 2024 17:31:42 +0300 Subject: [PATCH 7/9] Apply suggestions from code review Co-authored-by: Myk --- internal/advtools/convo.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/advtools/convo.lua b/internal/advtools/convo.lua index 9c478c175c..eff7250aaa 100644 --- a/internal/advtools/convo.lua +++ b/internal/advtools/convo.lua @@ -77,7 +77,7 @@ local function new_choice(choice_type, title, keywords) end local function addHistFigWhereaboutsChoice(profile) - for i, c in pairs(adventure.conversation.conv_choice_info) do + for i, c in ipairs(adventure.conversation.conv_choice_info) do if c.cc.type == df.talk_choice_type.AskWhereabouts and c.cc.invocation_target_hfid ~= -1 and c.cc.invocation_target_hfid == profile.histfig_id then @@ -104,7 +104,7 @@ local function addHistFigWhereaboutsChoice(profile) end local function addIdentityWhereaboutsChoice(identity) - for i, c in pairs(adventure.conversation.conv_choice_info) do + for _, c in ipairs(adventure.conversation.conv_choice_info) do if c.cc.type == df.talk_choice_type.AskWhereabouts and c.cc.invocation_target_hfid ~= -1 and c.cc.invocation_target_hfid == identity.impersonated_hf then From 6c06b28f1150fe7e083b53374f2ad2bc86150da9 Mon Sep 17 00:00:00 2001 From: Alex Noir Date: Sun, 30 Jun 2024 18:02:50 +0300 Subject: [PATCH 8/9] Refactor code --- internal/advtools/convo.lua | 59 +++++++++++++------------------------ 1 file changed, 21 insertions(+), 38 deletions(-) diff --git a/internal/advtools/convo.lua b/internal/advtools/convo.lua index eff7250aaa..210d94854b 100644 --- a/internal/advtools/convo.lua +++ b/internal/advtools/convo.lua @@ -76,62 +76,46 @@ local function new_choice(choice_type, title, keywords) return choice end -local function addHistFigWhereaboutsChoice(profile) - for i, c in ipairs(adventure.conversation.conv_choice_info) do - if c.cc.type == df.talk_choice_type.AskWhereabouts and - c.cc.invocation_target_hfid ~= -1 and - c.cc.invocation_target_hfid == profile.histfig_id then - -- Don't add repeat entries - return - end +local function addWhereaboutsChoice(race, name, target_id, heard_of) + local title = "Ask for the whereabouts of the " .. race .. " " .. dfhack.TranslateName(name, true) + if heard_of then + title = title .. " (Heard of)" end + local choice = new_choice(df.talk_choice_type.AskWhereabouts, title, dfhack.TranslateName(name):split()) + -- insert before the last choice, which is usually "back" + adventure.conversation.conv_choice_info:insert(#adventure.conversation.conv_choice_info-1, choice) + choice.cc.invocation_target_hfid = target_id +end +local function addHistFigWhereaboutsChoice(profile) local histfig = df.historical_figure.find(profile.histfig_id) - local name = "" + local race = "" local creature = df.creature_raw.find(histfig.race) if creature then local caste = creature.caste[histfig.caste] - name = caste.caste_name[0] + race = caste.caste_name[0] end - local title = "Ask for the whereabouts of the " .. name .. " " .. dfhack.TranslateName(histfig.name, true) - if profile._type == df.relationship_profile_hf_historicalst then - title = title .. " (Heard of)" - end - local choice = new_choice(df.talk_choice_type.AskWhereabouts, title, dfhack.TranslateName(histfig.name):split()) - -- insert before the last choice, which is usually "back" - adventure.conversation.conv_choice_info:insert(#adventure.conversation.conv_choice_info-1, choice) - choice.cc.invocation_target_hfid = histfig.id + + addWhereaboutsChoice(race, histfig.name, histfig.id, profile._type == df.relationship_profile_hf_historicalst) end local function addIdentityWhereaboutsChoice(identity) - for _, c in ipairs(adventure.conversation.conv_choice_info) do - if c.cc.type == df.talk_choice_type.AskWhereabouts and - c.cc.invocation_target_hfid ~= -1 and - c.cc.invocation_target_hfid == identity.impersonated_hf then - -- Don't add repeat entries - return - end - end local identity_name = identity.name - local name = "" + local race = "" local creature = df.creature_raw.find(identity.race) if creature then local caste = creature.caste[identity.caste] - name = caste.caste_name[0] + race = caste.caste_name[0] else -- no race given for the identity, assume it's the histfig local histfig = df.historical_figure.find(identity.histfig_id) creature = df.creature_raw.find(histfig.race) if creature then local caste = creature.caste[histfig.caste] - name = caste.caste_name[0] + race = caste.caste_name[0] end end - local title = "Ask for the whereabouts of the " .. name .. " " .. dfhack.TranslateName(identity_name, true) - local choice = new_choice(df.talk_choice_type.AskWhereabouts, title) - -- insert before the last choice, which is usually "back" - adventure.conversation.conv_choice_info:insert(#adventure.conversation.conv_choice_info-1, choice, dfhack.TranslateName(identity_name):split()) - choice.cc.invocation_target_hfid = identity.impersonated_hf + addWhereaboutsChoice(race, identity_name, identity.impersonated_hf) end -- Condense the rumor system choices @@ -149,18 +133,18 @@ local function rumorUpdate() local historical = relationships.hf_historical local identity = relationships.hf_identity - for _, profile in pairs(visual) do + for _, profile in ipairs(visual) do addHistFigWhereaboutsChoice(profile) end -- This option will likely always fail unless the false identity is impersonating someone -- but giving away the false identity's true historical figure feels cheap. - for _, profile in pairs(identity) do + for _, profile in ipairs(identity) do addIdentityWhereaboutsChoice(df.identity.find(profile.identity_id)) end -- Historical entities go last so as to not give away fake identities - for _, profile in pairs(historical) do + for _, profile in ipairs(historical) do addHistFigWhereaboutsChoice(profile) end end @@ -185,7 +169,6 @@ local last_first_entry = nil function AdvRumorsOverlay:render() -- Only update if the first entry pointer changed, this reliably indicates the list changed if #adventure.conversation.conv_choice_info <= 0 or last_first_entry == adventure.conversation.conv_choice_info[0] then return end - -- Remember the last first entry. This entry changes even if we quit out and return on the same menu! last_first_entry = adventure.conversation.conv_choice_info[0] rumorUpdate() From 052c38b041ac86dd854eb0f07e46078aa6a9463e Mon Sep 17 00:00:00 2001 From: Myk Date: Mon, 1 Jul 2024 18:12:15 -0700 Subject: [PATCH 9/9] Update changelog.txt --- changelog.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 4922ebef91..a760edab2c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -44,7 +44,7 @@ Template for new versions: - `gui/notify`: new notification type: injured citizens; click to zoom to injured units; also displays a warning if your hospital is not functional (or if you have no hospital) - `prioritize`: new info panel on under-construction buildings showing if the construction job has been taken and by whom. click to zoom to builder; toggle high priority status for job if it's not yet taken and you need it to be built ASAP - `gui/pathable`: new "Depot" mode that shows whether wagons can path to your trade depot -- `advtools`: convo - add a new conversation option to "ask whereabouts of" for all your relationships (before, you could only ask whereabouts of people involved in rumors only) +- `advtools`: automatically add a conversation option to "ask whereabouts of" for all your relationships (before, you could only ask whereabouts of people involved in rumors) - `gui/design`: all-new visually-driven UI for much improved usability ## Fixes