Skip to content

Commit

Permalink
new tool: immortal-cravings
Browse files Browse the repository at this point in the history
  • Loading branch information
chdoc authored and master-spike committed Nov 13, 2024
1 parent cb03157 commit 42a8ac3
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 36 deletions.
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Template for new versions:
- `idle-crafting`: allow dwarves to independently satisfy their need to craft objects
- `gui/family-affairs`: (reinstated) inspect or meddle with pregnancies, marriages, or lover relationships
- `notes`: attach notes to locations on a fort map
- `immortal-cravings`: allow immortals to satisfy their cravings for food and drink

## New Features
- `caravan`: DFHack dialogs for trade screens (both ``Bring goods to depot`` and the ``Trade`` barter screen) can now filter by item origins (foreign vs. fort-made) and can filter bins by whether they have a mix of ethically acceptable and unacceptable items in them
Expand Down
5 changes: 2 additions & 3 deletions docs/immortal-cravings.rst
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,5 @@ occupied.
Usage
-----

::

enable immortal-cravings
``enable immortal-cravings``
``disable immortal-cravings``
59 changes: 26 additions & 33 deletions immortal-cravings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ local function findClosest(pos, item_vector, is_good)
local dclosest = -1
for _,item in ipairs(item_vector) do
if not item.flags.in_job and (not is_good or is_good(item)) then
local pitem = xyz2pos(dfhack.items.getPosition(item))
local x, y, z = dfhack.items.getPosition(item)
local pitem = xyz2pos(x, y, z)
local ditem = distance(pos, pitem)
if dfhack.maps.canWalkBetween(pos, pitem) and (not closest or ditem < dclosest) then
closest = item
Expand All @@ -37,11 +38,11 @@ end

---find a drink
---@param pos df.coord
---@return df.item_drinkst?
---@return df.item_drinkst|nil
local function get_closest_drink(pos)
local is_good = function (drink)
local container = dfhack.items.getContainer(drink)
return container and container:isFoodStorage()
return container and df.item_barrelst:is_instance(container)
end
return findClosest(pos, df.global.world.items.other.DRINK, is_good)
end
Expand All @@ -51,12 +52,7 @@ end
local function get_closest_meal(pos)
---@param meal df.item_foodst
local function is_good(meal)
if meal.flags.rotten then
return false
else
local container = dfhack.items.getContainer(meal)
return not container or container:isFoodStorage()
end
return meal.flags.rotten == false
end
return findClosest(pos, df.global.world.items.other.FOOD, is_good)
end
Expand Down Expand Up @@ -127,13 +123,13 @@ local function load_state()
enabled = persisted_data.enabled or false
end

DrinkAlcohol = df.need_type.DrinkAlcohol
EatGoodMeal = df.need_type.EatGoodMeal
DrinkAlcohol = df.need_type['DrinkAlcohol']
EatGoodMeal = df.need_type['EatGoodMeal']

---@type integer[]
watched = watched or {}
watched = {}

local threshold = -9000
threshold = -9000

---unit loop: check for idle watched units and create eat/drink jobs for them
local function unit_loop()
Expand All @@ -142,25 +138,23 @@ local function unit_loop()
local kept = {}
for _, unit_id in ipairs(watched) do
local unit = df.unit.find(unit_id)
if
not unit or not dfhack.units.isActive(unit) or
unit.flags1.caged or unit.flags1.chained
then
goto next_unit
end
if not idle.unitIsAvailable(unit) then
table.insert(kept, unit.id)
else
-- unit is available for jobs; satisfy one of its needs
for _, need in ipairs(unit.status.current_soul.personality.needs) do
if need.id == DrinkAlcohol and need.focus_level < threshold then
goDrink(unit)
break
elseif need.id == EatGoodMeal and need.focus_level < threshold then
goEat(unit)
break
if unit and not (unit.flags1.caged or unit.flags1.chained) then
if not idle.unitIsAvailable(unit) then
table.insert(kept, unit.id)
else
--
for _, need in ipairs(unit.status.current_soul.personality.needs) do
if need.id == DrinkAlcohol and need.focus_level < threshold then
goDrink(unit)
goto next_unit
elseif need.id == EatGoodMeal and need.focus_level < threshold then
goEat(unit)
goto next_unit
end
end
end
else
-- print('immortal-cravings: unit gone or caged')
end
::next_unit::
end
Expand All @@ -173,7 +167,7 @@ end

---main loop: look for citizens with personality needs for food/drink but w/o physiological need
local function main_loop()
-- print('immortal-cravings watching:')
print('immortal-cravings watching:')
watched = {}
for _, unit in ipairs(dfhack.units.getCitizens()) do
if unit.curse.add_tags1.NO_DRINK or unit.curse.add_tags1.NO_EAT then
Expand All @@ -182,7 +176,7 @@ local function main_loop()
need.id == EatGoodMeal and need.focus_level < threshold
then
table.insert(watched, unit.id)
-- print(' '..dfhack.df2console(dfhack.TranslateName(dfhack.units.getVisibleName(unit))))
print(' '..dfhack.df2console(dfhack.TranslateName(dfhack.units.getVisibleName(unit))))
goto next_unit
end
end
Expand Down Expand Up @@ -214,7 +208,6 @@ end
dfhack.onStateChange[GLOBAL_KEY] = function(sc)
if sc == SC_MAP_UNLOADED then
enabled = false
-- repeat-util will cancel the loops on unload
return
end

Expand Down

0 comments on commit 42a8ac3

Please sign in to comment.