diff --git a/changelog.txt b/changelog.txt index 9ca3d5e44..d0c587b7f 100644 --- a/changelog.txt +++ b/changelog.txt @@ -32,6 +32,8 @@ Template for new versions: ## Fixes +- `fix/stuck-worship`: fix lookup of units current prayer target(s). + ## Misc Improvements ## Removed diff --git a/fix/stuck-worship.lua b/fix/stuck-worship.lua index d21df8271..fbd1d768a 100644 --- a/fix/stuck-worship.lua +++ b/fix/stuck-worship.lua @@ -1,3 +1,5 @@ +--@module = true + local argparse = require('argparse') local verbose, quiet = false, false @@ -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 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 @@ -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 @@ -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 @@ -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? +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)