Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adv-Rumors additional conversation options #1182

Merged
merged 12 commits into from
Jul 2, 2024
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +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`: 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
Expand Down
5 changes: 4 additions & 1 deletion docs/advtools.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
100 changes: 96 additions & 4 deletions internal/advtools/convo.lua
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -22,8 +22,8 @@ end
-- Adds a keyword to the dialog choice
local function addKeyword(choice, keyword)
local keyword_ptr = df.new('string')
keyword_ptr.value = keyword
choice.key_word:insert('#', keyword_ptr)
keyword_ptr.value = dfhack.toSearchNormalized(keyword)
choice.keywords:insert('#', keyword_ptr)
end

-- Adds multiple keywords to the dialog choice
Expand All @@ -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
Expand All @@ -61,8 +61,95 @@ 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.title.text:insert("#", text)

if keywords ~= nil then
addKeywords(choice, keywords)
end
return choice
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 race = ""
local creature = df.creature_raw.find(histfig.race)
if creature then
local caste = creature.caste[histfig.caste]
race = caste.caste_name[0]
end

addWhereaboutsChoice(race, histfig.name, histfig.id, profile._type == df.relationship_profile_hf_historicalst)
end

local function addIdentityWhereaboutsChoice(identity)
local identity_name = identity.name
local race = ""
local creature = df.creature_raw.find(identity.race)
if creature then
local caste = creature.caste[identity.caste]
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]
race = caste.caste_name[0]
end
end
addWhereaboutsChoice(race, identity_name, identity.impersonated_hf)
end

-- Condense the rumor system choices
local function rumorUpdate()
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.
-- 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

local visual = relationships.hf_visual
local historical = relationships.hf_historical
local identity = relationships.hf_identity

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 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 ipairs(historical) do
addHistFigWhereaboutsChoice(profile)
end
end

-- generate extra keywords for all options
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if this is being run unconditionally down here, why are you adding keywords in new_choice? can the call to add_keywords be removed from new_choice?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is because new_choice might have its own "vanilla"-style added keywords which is just a few, while this section ensures more searchability

for i, choice in ipairs(adventure.conversation.conv_choice_info) do
generateKeywordsForChoice(choice)
end
Expand All @@ -78,6 +165,11 @@ AdvRumorsOverlay.ATTRS{
frame={w=0, h=0},
}

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