@@ -13,6 +13,27 @@ function distance(p1, p2)
1313 return math.max (math.abs (p1 .x - p2 .x ), math.abs (p1 .y - p2 .y )) + math.abs (p1 .z - p2 .z )
1414end
1515
16+ --- find best item in an item vector (according to some metric)
17+ --- @generic T : df.item
18+ --- @param item_vector T[]
19+ --- @param metric fun ( item : T ): number
20+ --- @param is_good ? fun ( item : T ): boolean
21+ --- @return T ?
22+ function findBest (item_vector , metric , is_good )
23+ local best = nil
24+ local mbest = - 1
25+ for _ ,item in ipairs (item_vector ) do
26+ if not item .flags .in_job and (not is_good or is_good (item )) then
27+ mitem = metric (item )
28+ if not best or mitem > mbest then
29+ best = item
30+ mbest = mitem
31+ end
32+ end
33+ end
34+ return best
35+ end
36+
1637--- find closest accessible item in an item vector
1738--- @generic T : df.item
1839--- @param pos df.coord
@@ -46,19 +67,28 @@ local function get_closest_drink(pos)
4667 return findClosest (pos , df .global .world .items .other .DRINK , is_good )
4768end
4869
49- --- find some prepared meal
70+ --- find highest-value accessible meal
5071--- @return df.item_foodst ?
51- local function get_closest_meal (pos )
72+ local function get_best_meal (pos )
73+
5274 --- @param meal df.item_foodst
5375 local function is_good (meal )
54- if meal .flags .rotten then
76+ local accessible = dfhack .maps .canWalkBetween (pos ,xyz2pos (dfhack .items .getPosition (meal )))
77+ if meal .flags .rotten or not accessible then
5578 return false
5679 else
80+ -- check that meal is either on the ground or in food storage (and not in a backpack)
5781 local container = dfhack .items .getContainer (meal )
5882 return not container or container :isFoodStorage ()
5983 end
6084 end
61- return findClosest (pos , df .global .world .items .other .FOOD , is_good )
85+
86+ --- @param meal df.item_foodst
87+ local function portion_value (meal )
88+ return dfhack .items .getValue (meal ) / meal .stack_size
89+ end
90+
91+ return findBest (df .global .world .items .other .FOOD , portion_value , is_good )
6292end
6393
6494--- create a Drink job for the given unit
86116--- create Eat job for the given unit
87117--- @param unit df.unit
88118local function goEat (unit )
89- local meal = get_closest_meal (unit .pos )
119+ local meal = get_best_meal (unit .pos )
90120 if not meal then
91121 -- print('no accessible meals found')
92122 return
@@ -181,12 +211,15 @@ local function main_loop()
181211 -- print('immortal-cravings watching:')
182212 watched = {}
183213 for _ , unit in ipairs (dfhack .units .getCitizens ()) do
184- if not is_active_caste_flag (unit , ' NO_DRINK' ) and not is_active_caste_flag (unit , ' NO_EAT' ) then
214+ if
215+ not (is_active_caste_flag (unit , ' NO_DRINK' ) or is_active_caste_flag (unit , ' NO_EAT' )) or
216+ unit .counters2 .stomach_content > 0
217+ then
185218 goto next_unit
186219 end
187220 for _ , need in ipairs (unit .status .current_soul .personality .needs ) do
188- if need .id == DrinkAlcohol and need .focus_level < threshold or
189- need .id == EatGoodMeal and need .focus_level < threshold
221+ if need .id == DrinkAlcohol and need .focus_level < threshold or
222+ need .id == EatGoodMeal and need .focus_level < threshold
190223 then
191224 table.insert (watched , unit .id )
192225 -- print(' '..dfhack.df2console(dfhack.units.getReadableName(unit)))
0 commit comments