Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 2 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ Template for new versions:

## Fixes

- `fix/stuck-worship`: fix lookup of units current prayer target(s).

## Misc Improvements

## Removed
Expand Down
58 changes: 38 additions & 20 deletions fix/stuck-worship.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
--@module = true

local argparse = require('argparse')

local verbose, quiet = false, false
Expand All @@ -14,12 +16,17 @@ local function for_pray_need(needs, fn)
end
end

---Rearrange prayer needs
---@param needs _unit_personality_needs
---@param prayer_targets table<integer, boolean> analysis suggests that there is exactly one prayer target
---@return boolean?
local function shuffle_prayer_needs(needs, prayer_targets)
local idx_of_prayer_target, max_focus_level
local idx_of_min_focus_level, min_focus_level

-- determine most satisfied need inside the prayer group and most
-- unsatisfied need outside the prayer group
for_pray_need(needs, function(idx, need)
-- only shuffle if the need for one of the current prayer targets
-- is already met
if prayer_targets[need.deity_id] and need.focus_level > -1000 and
(not max_focus_level or need.focus_level > max_focus_level)
then
Expand All @@ -37,7 +44,7 @@ local function shuffle_prayer_needs(needs, prayer_targets)
end)

-- if a need inside the prayer group is met and a need outside of the
-- prayer group is not met, transfer the credit outside of the prayer group
-- prayer group is not met, swap the respective focus levels
if idx_of_prayer_target and idx_of_min_focus_level then
needs[idx_of_min_focus_level].focus_level = needs[idx_of_prayer_target].focus_level
needs[idx_of_prayer_target].focus_level = min_focus_level
Expand All @@ -46,9 +53,10 @@ local function shuffle_prayer_needs(needs, prayer_targets)

if not idx_of_prayer_target then return end

-- otherwise, if the only unmet needs are inside the prayer group,
-- set the credit inside the prayer group to the level of the met need
-- we found earlier
-- If there is a satisfied prayer need inside the prayer group, set the
-- focus level of all unsatisfied prayer needs inside the group to the
-- maximum focus level found earlier (dead code if prayer groups are
-- singletons)
local modified = false
for_pray_need(needs, function(_, need)
if prayer_targets[need.deity_id] and need.focus_level <= -1000 then
Expand All @@ -59,34 +67,44 @@ local function shuffle_prayer_needs(needs, prayer_targets)
return modified
end

local function get_prayer_targets(unit)
---get current prayer target(s) of a unit (as set of histfig_id)
---@param unit df.unit
---@return table<integer, boolean>?
function get_prayer_targets(unit)
local deity_set = {}
local return_set = false

for _, sa in ipairs(unit.social_activities) do
local ae = df.activity_entry.find(sa)
if not ae or ae.type ~= df.activity_entry_type.Prayer then
goto next_activity
end
for _, ev in ipairs(ae.events) do
if not df.activity_event_worshipst:is_instance(ev) then
goto next_event
end
for _, hfid in ipairs(ev.participants.histfigs) do
local hf = df.historical_figure.find(hfid)
if not hf then goto next_hf end
local deity_set = {}
for _, hf_link in ipairs(hf.histfig_links) do
if df.histfig_hf_link_deityst:is_instance(hf_link) then
deity_set[hf_link.target_hf] = true
if df.activity_event_prayerst:is_instance(ev) then
for _, participant_id in ipairs(ev.participants.units) do
if participant_id == unit.id then
deity_set[ev.histfig_id] = true
--I want to know whether units can actually have multiple prayer targets or not
if return_set then
dfhack.color(COLOR_YELLOW)
print(("%s has multiple prayer targets, please report"):format(
dfhack.translation.translateName(unit.name)
))
dfhack.color(nil)
end
return_set = true
end
end
if next(deity_set) then return deity_set end
::next_hf::

end
::next_event::
end
::next_activity::
end
return return_set and deity_set or nil
end

if dfhack_flags.module then return end

local count = 0
for _,unit in ipairs(dfhack.units.getCitizens(false, true)) do
local prayer_targets = get_prayer_targets(unit)
Expand Down
Loading