Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions gui/spectate.lua
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ function Spectate:init()

create_row({t=27}, 'Job', 'J', 'job', colFollow, colHover),
create_row({t=28}, 'Activity', 'A', 'activity', colFollow, colHover),
create_row({t=27}, 'Research', 'R', 'research', colFollow, colHover),
create_row({t=29}, 'Name', 'N', 'name', colFollow, colHover),
create_row({t=30}, 'Stress', 'S', 'stress', colFollow, colHover),
create_stress_list({t=31}, colFollow, colHover),
Expand Down
126 changes: 126 additions & 0 deletions internal/research-info/info.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
-- Main module for research-info
--@ module = true

---@param unit_id df.unit.id
function getHistoricalFigure(unit_id)
for _, historical_figure in ipairs(df.global.world.history.figures) do
if historical_figure.unit_id == unit_id then
return historical_figure
end
end
print("No historical figure found for unit ID: " .. unit_id)
return nil
end

function getKnowledgeGoalCategoryInfo(category_id)
-- alt: df.scholar_knowledgest
local topic_categories = {
[-1] = "None", -- None
[0] = "Philosophy", -- PHILOSOPHY_FLAG
[1] = "Philosophy Adv", -- PHILOSOPHY_FLAG2
[2] = "Mathematics", -- MATHEMATICS_FLAG
[3] = "Mathematics Adv", -- MATHEMATICS_FLAG2
[4] = "History", -- HISTORY_FLAG
[5] = "Astronomy", -- ASTRONOMY_FLAG
[6] = "Naturalist", -- NATURALIST_FLAG
[7] = "Chemistry", -- CHEMISTRY_FLAG
[8] = "Geography", -- GEOGRAPHY_FLAG
[9] = "Medicine 1", -- MEDICINE_FLAG
[10] = "Medicine 2", -- MEDICINE_FLAG2
[11] = "Medicine 3", -- MEDICINE_FLAG3
[12] = "Engineering", -- ENGINEERING_FLAG
[13] = "Engineering Adv" -- ENGINEERING_FLAG2
}
return topic_categories[category_id] or string.format("Unknown Category: %s", category_id)
end

function getGoalInfo(goal, category)
local goal_info = ''
if not goal then
return goal_info
end

local goal_info = ""
for i = 0, 31 do
if goal[i] then
local global_flag_index = category * 32 + i -- wizards move
goal_info = string.format("%s", df.dfhack_knowledge_scholar_flag[global_flag_index]) or string.format("Unknown Flag: %s", i)
end
end
return goal_info

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't understand what you're doing here. Please explain, so that we can see whether there is a better way.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

This func returns name of researchable topic

it takes data from https://github.com/DFHack/df-structures/blob/e4993ceef7907351fd2ac6f9bd3a9e5ff24699db/df.history_figure.xml#L308 and match value with name from https://github.com/DFHack/df-structures/blob/e4993ceef7907351fd2ac6f9bd3a9e5ff24699db/df.dfhack.xml#L221 there is a trouble in relations between these structures and these is doesnt match directrly. So, i use some magic.

end

local function getTopicInfo(topic)
if not topic then
return "No topic information available."
end

local topic_info = ""

for key, value in pairs(topic) do
if type(value) == "boolean" and value then
-- Если значение булевое и равно true, выводим тему как изученную
topic_info = topic_info .. string.format("\n\t\t%s", key)
end
end

if topic_info == "" then
return "No learned topics."
end

return topic_info
end

---@param historical_figure df.historical_figure
function getHistoricKnowledge(historical_figure)
if not historical_figure then
print("Historical figure not found.")
return nil, "Historical figure not found."
end

local known_info = historical_figure.info.known_info

if not known_info then
return nil, "No known_info found."
end

local knowledge = known_info.knowledge

if not knowledge then
return nil, "No knowledge found."
end

return knowledge
end

---@param unit_id df.unit.id
function getUnitKnowledge(unit_id)
return getHistoricKnowledge(getHistoricalFigure(unit_id))
end

---@param historical_figure df.historical_figure
function getResearchData(historical_figure)
local knowledge = getHistoricKnowledge(historical_figure)
local data = {

name = dfhack.translation.translateName(historical_figure.name), --dfhack.translation.TranslateName(historical_figure.name),
knowledge_goal_category = getKnowledgeGoalCategoryInfo(knowledge.knowledge_goal_category),
--knowledge_goal = getGoalInfo(knowledge.knowledge_goal),
knowledge_goal = getGoalInfo(knowledge.knowledge_goal, knowledge.knowledge_goal_category),
research_points = knowledge.research_points,
research_percentage = string.format("%.2f", (knowledge.research_points / 100000) * 100),
times_pondered = knowledge.times_pondered,
research_topics = {}
}

for i, topic in pairs(knowledge) do
if type(topic) == "userdata" and i ~= "knowledge_goal" then
local topic_info = getTopicInfo(topic)
if topic_info ~= "\tNo topic information available." and topic_info ~= "No learned topics." then
table.insert(data.research_topics, {name = i, info = topic_info})
end
end
end

return {data}
end
43 changes: 43 additions & 0 deletions internal/research-info/overlay.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
-- Spectate-Overlay module for research-info
--@ module = true

local researchInfo = reqscript("internal/research-info/info")

local function formatKnowledgeString(str)
if not str or type(str) ~= "string" or str == "" then
return str or ""
end

local parts = {}
for part in str:gmatch("[^_]+") do
-- Первую букву делаем заглавной, остальные - строчными

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

If you add comments, please add them in English.

local formatted = part:sub(1,1):upper() .. part:sub(2):lower()
table.insert(parts, formatted)
end

return table.concat(parts, " ")
end

function GetUnitResearchInfo(unit_id)
local info = ''

historical_figure = researchInfo.getHistoricalFigure(unit_id)
local knowledge = researchInfo.getHistoricKnowledge(historical_figure)
local data = {
knowledge_goal_category = researchInfo.getKnowledgeGoalCategoryInfo(knowledge.knowledge_goal_category),
knowledge_goal = formatKnowledgeString(researchInfo.getGoalInfo(knowledge.knowledge_goal, knowledge.knowledge_goal_category)),
research_points = knowledge.research_points, --TOTAL: 100'000
research_percentage = string.format("%.2f", (knowledge.research_points / 100000) * 100),
times_pondered = knowledge.times_pondered
}

if((data.knowledge_goal ~= 'nil') and ((data.times_pondered > 0) or (knowledge.research_points > 0))) then
info = data.knowledge_goal..string.format(' %s%%', data.research_percentage)..string.format(' [%d] ', data.times_pondered)
end

return info
end

function GetUnitKnowledge(unit_id)
return researchInfo.getUnitKnowledge(unit_id)
end
69 changes: 69 additions & 0 deletions research-info.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
local researchInfo = reqscript("internal/research-info/info")

local function sortResearchDataByPercAndPondered(data_list)
table.sort(data_list, function(a, b)
if tonumber(a.research_percentage) == tonumber(b.research_percentage) then
return a.times_pondered > b.times_pondered
end
return tonumber(a.research_percentage) > tonumber(b.research_percentage)
end)

return data_list
end

local function printResearchData(data)
if not data then
print("No data to display.")
return
end

if data.research_points == 0 and data.knowledge_goal == "" and data.times_pondered == 0 then
return
end

print("==================")
print("Dwarf: " .. data.name)
print("\tKnowledge Goal Category: " .. data.knowledge_goal_category)
print("\tKnowledge Goal: " .. data.knowledge_goal)
print("\tResearch Points: " .. data.research_points .. "/100000")
print("\tResearch Percentage: " .. data.research_percentage .. "%")
print("\tTimes Pondered: " .. data.times_pondered)

if #data.research_topics > 0 then
print("Knowledge:")
for _, topic in ipairs(data.research_topics) do
print("\t" .. topic.name .. ": " .. topic.info)
end
end
end

--
local unit = dfhack.units.getCitizens()
local selected_unit = dfhack.gui.getSelectedUnit()

if unit then
Comment on lines +41 to +44

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

dfhack.units.getCitizens returns a table, and even the empty table (which this will never return in an active fort) is a "truthy" value in lua. So this condition can never evaluate to false.

local research_data_list = {}
for i, unit in pairs(dfhack.units.getCitizens()) do

if selected_unit and selected_unit.id ~= unit.id then
goto continue
end

local historical_figure = researchInfo.getHistoricalFigure(unit.id)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
local historical_figure = researchInfo.getHistoricalFigure(unit.id)
local historical_figure = df.historical_figure.find(unit.hist_figure_id)

There are two observations here: units have a historical figure id field, and the idiomatic way to turn a numeric field into the corresponding structure is to use df.<structure_name>.find(id). This makes functions like your getHistoricalFigure basically useless. Please revisit your code and see whether this same pattern can be applied elsewhere.

if historical_figure then
local research_data, error_msg = researchInfo.getResearchData(historical_figure)
if research_data then
for _, data in ipairs(research_data) do
table.insert(research_data_list, data)
end
end
end
::continue::
end

research_data_list = sortResearchDataByPercAndPondered(research_data_list)

for _, data in ipairs(research_data_list) do
printResearchData(data)
end
end