Bay 12 Games Forum

Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 2 [3]

Author Topic: Has Toady revealed any planned changes to cooking / food preferences ?  (Read 4550 times)

PatrikLundell

  • Bay Watcher
    • View Profile

Yes, fortunately, we're all good at different things (or it would get rather boring quickly).

Details for workshops is a fairly recent addition, and it wasn't added consistently (as you see). It certainly would be nice to have the item selection exposed in the UI, and that could fall into the UI improvement bucket. My guess is that it's not at the top of Toady's UI improvement list, but I wouldn't cry if that guess was incorrect (and you'd have to somehow communicate to the player why the list of items for the first slot would be shorter than the other lists [the first item has to be a solid]).

The "mix food" option has nothing to do with the kitchen, but is a stockpile option to control whether different kinds of food can be stored in the same container or not (the more kinds there are the greater the risk of two simultaneous attempts to get at the contents, with job cancellation for one as a result. That's often seen with seed bags if you have seeds for more than one field in the same bag, even if the seeds are of the same type. It also affects stockpile linking, as containers aren't hauled to the target stockpile if there is at least one item in it that isn't allowed at the target). In this case it's your interpretation of the option that's off (given that we all have to guess as to what things mean, it's not meant as an accusation).

@vjek: I've certainly seen thoughts about eating a truly decadent dish with 0.47.04, and others have said there's a satisfaction multiplier applied if and only if a favorite is included. Similarly, I've seen positive thoughts about drinks, but I haven't performed any check to try to see how much satisfaction any of the messages are connected to.
Logged

KevinM

  • Bay Watcher
    • View Profile

@vjek: I've certainly seen thoughts about eating a truly decadent dish with 0.47.04, and others have said there's a satisfaction multiplier applied if and only if a favorite is included. Similarly, I've seen positive thoughts about drinks, but I haven't performed any check to try to see how much satisfaction any of the messages are connected to.

I've seen the same.  I often see that the raw ingredient (which my dwarves will go for when their favorite isn't in a cooked meal), is taken and gives a small positive thought for having a "decent meal" with a cooked meal higher, but I'll have to screenshot and track better for the meal quality for differences.   I'm not sure if the "only one thing" or the preference change could cause different behaviors.
Logged

KevinM

  • Bay Watcher
    • View Profile

Back to the ingredient thing, the raw ingredient is good enough to avoid the lack of a decent meal.   So I buy up a lot of raw ingredients (meat and fish) from the caravans.  What annoys me is that my dwarves take advantage to raid the raw fish that I'm buying to go eat it raw for a content thought instead of a delighted thought.  There's probably more depending on that personality thing too.

Here's one of my raw celery eaters (I don't put this into roasts due to the seed issue)
Spoiler (click to show/hide)
My Nautilus eater who is eating a roast with a non-quality minced nautilus which also received content
Spoiler (click to show/hide)
My Rye Beer eater with a roast with a masterfully minced rye beer who received a delighted thought
Spoiler (click to show/hide)

Lets see if I get the spoilers and images correct on this.

My big frustration about food is the ability to get the ingredients which then causes the lack of positive or even mediocre thoughts.  If the baseline was just that they "didnt' feel anything" for a food that didn't contain one of their favorite ingredients, that would be nice rather than getting negative thoughts like this Reindeer and Pineapple wine eater.
Spoiler (click to show/hide)

Edit:  That one isn't so bad, I have a chance of getting reindeer from traders.  I checked my most meal needy dwarf in Dwarf Therapist.  His only food like is gutter Cruor.  There's no way I'm going to be able to get silver barb for that dwarf.  He's currently "frustrated" at the lack of decent meals.
« Last Edit: June 14, 2020, 01:08:44 am by KevinM »
Logged

PatrikLundell

  • Bay Watcher
    • View Profile

I cobbled together a DFHack script for selecting the ingredients for meals. Given that it has to be run when the job is selected (in the kitchen) and the manual entry of items, I'd expect that it wouldn't be used regularly, but if you just HAVE to make a specific batch you can do it.

Code: [Select]
local dialogs = require 'gui.dialogs'
local gui = require 'gui'
local utils = require 'utils'
local widgets = require 'gui.widgets'

--============================================================

function Chef ()
  local job = dfhack.gui.getSelectedJob (true)
  local df_selects = "<DF Selects>"
  local Main_Page = {}
  local persist_screen
  local list = {}
  local display_list = {}

  local keybindings = {
    first = {key = "CUSTOM_A",
             desc = "Select first (solid) ingredient"},
    second = {key = "CUSTOM_B",
              desc = "Select second ingredient"},
    third = {key = "CUSTOM_C",
             desc = "Select third ingredient"},
    fourth = {key = "CUSTOM_D",
              desc = "Select fourth ingredient"}}

  if df.global.ui.main.mode ~= df.ui_sidebar_mode.QueryBuilding then
    qerror ("This script must be run when a kitchen job screen ('q'uery) is open and a meal preparation task has been created")
   
  elseif not job or
         job.job_type ~= df.job_type.PrepareMeal then
    qerror ("This script must be run when a kitchen job screen ('q'uery) is open and a meal preparation task has been created")
  end
 
  --==============================================================

  Ui = defclass (nil, gui.FramedScreen)
 
  Ui.ATTRS = {
    frame_style = gui.GREY_LINE_FRAME,
    frame_title = "The Chef",
    transparent = false
  }

  --==============================================================

  function description_string_of (item_type, mat_type, mat_index)
    if item_type == -1 then
      return df_selects
    end
   
    if df.item_type.attrs [item_type].is_caste_mat then  --  caste mat things don't have a material
      if item_type == df.item_type.EGG then
        return df.global.world.raws.creatures.all [mat_index].name [0] .. " eggs"
           
      else  --  All of those are animals
        return df.global.world.raws.creatures.all [mat_index].name [0]
      end
     
    else
      local mat_info = dfhack.matinfo.decode (mat_type, mat_index)
      local description
       
      if mat_info.mode == 'plant' then
        description = mat_info.plant.name
       
      else
        description = mat_info.creature.name [0]
      end
         
      if item_type == df.item_type.DRINK or
         item_type == df.item_type.LIQUID_MISC then
        return description .. " " .. mat_info.material.state_name [1]  --  Liquid
         
      else
        return description .. " " .. mat_info.material.state_name [0]  --  Solid
      end
    end
  end
 
  --==============================================================

  function populate_lists (list, display_list, solids_only)
    for i = #list, 1, -1 do
      table.remove (list, i)
      table.remove (display_list, i)
    end
   
    for i, item in ipairs (df.global.world.items.other.ANY_COOKABLE) do
      local item_type = item.getType (item)
      local mat_info
      local mat_type
      local mat_index
     
      if (item_type == df.item_type.MEAT or
          item_type == df.item_type.FISH or
          item_type == df.item_type.FISH_RAW or
          item_type == df.item_type.SEEDS or
          item_type == df.item_type.PLANT or
          item_type == df.item_type.PLANT_GROWTH or
          item_type == df.item_type.DRINK or
          item_type == df.item_type.POWDER_MISC or
          item_type == df.item_type.CHEESE or
          item_type == df.item_type.LIQUID_MISC or
          item_type == df.item_type.GLOB or
          item_type == df.item_type.EGG) and
         (not solids_only or
          (item_type ~= df.item_type.DRINK and
           item_type ~= df.item_type.LIQUID_MISC)) and
         not item.flags.in_job and
         not item.flags.removed and
         not item.flags.in_inventory and
         not item.flags.rotten and
         not item.flags.encased and
         not item.flags.trader and
         not item.flags.garbage_collect and
         not item.flags.forbid and
         not item.flags.dump and
         not item.flags.on_fire then
        if df.item_type.attrs [item_type].is_caste_mat then  --  caste mat things don't have a material
          mat_type = -1
          mat_index = item.race
         
        else
          mat_type = item.mat_type
          mat_index = item.mat_index
          mat_info = dfhack.matinfo.decode (mat_type, mat_index)         
        end
       
        if not mat_info or
           mat_info.material.flags.EDIBLE_COOKED then
          local found = false
         
          for k, element in ipairs (list) do
            if element [1] == item_type and
               element [2] == mat_type and
               element [3] == mat_index then
              found = true
              break
            end
          end
         
          if not found then
            table.insert (list, {item_type, mat_type, mat_index, description_string_of (item_type, mat_type, mat_index)})
          end
        end
      end     
    end
   
    local temp
   
    for i, dummy in ipairs (list) do
      for k = i + 1, #list do
        if list [k] [4] < list [i] [4] then
          temp = list [i]
          list [i] = list [k]
          list [k] = temp         
        end
      end
    end
   
    table.insert (list, 1, {-1, -1, -1, df_selects})
   
    for i, element in ipairs (list) do
      table.insert (display_list, element [4])
    end
  end
 
  --==============================================================

  function Ui:init ()
    self.stack = {}
    self.item_count = 0
    self.keys = {}
    local description
   
--    local screen_width, screen_height = dfhack.screen.getWindowSize ()

    Main_Page.First_Ingredient_Label =
      widgets.Label {text = {{text = "",
                                     key = keybindings.first.key,
                                     key_sep = '()'},
                             {text = " Solid Ingredient:",
                              pen = COLOR_LIGHTBLUE}},
                     frame = {l = 0, t = 2, y_align = 0}}
                     
    Main_Page.Second_Ingredient_Label =
      widgets.Label {text = {{text = "",
                                     key = keybindings.second.key,
                                     key_sep = '()'},
                             {text = " Second Ingredient:",
                              pen = COLOR_LIGHTBLUE}},
                     frame = {l = 0, t = 3, y_align = 0}}
                     
           
    Main_Page.Third_Ingredient_Label =
      widgets.Label {text = {{text = "",
                                     key = keybindings.third.key,
                                     key_sep = '()'},
                             {text = " Third Ingredient:",
                              pen = COLOR_LIGHTBLUE}},
                     frame = {l = 0, t = 4, y_align = 0},
                     visible = job.mat_type > 2}                     
   
    Main_Page.Fourth_Ingredient_Label =
      widgets.Label {text = {{text = "",
                                     key = keybindings.fourth.key,
                                     key_sep = '()'},
                             {text = " Fourth Ingredient:",
                              pen = COLOR_LIGHTBLUE}},
                     frame = {l = 0, t = 5, y_align = 0},
                     visible = job.mat_type > 3}
   
    Main_Page.Name_Label =
      widgets.Label {text = "(Provides the name of the meal)",
                     frame = {l = 60, t = 3 - 2 + job.mat_type, y_align = 0},
                     text_pen = COLOR_WHITE}
   
    description = description_string_of (job.job_items [0].item_type,
                                         job.job_items [0].mat_type,
                                         job.job_items [0].mat_index)

    Main_Page.First_Item =
      widgets.Label {text = description,
                     frame = {l = 24, t = 2, y_align = 0},
                     text_pen = COLOR_YELLOW}
   
    description = description_string_of (job.job_items [1].item_type,
                                         job.job_items [1].mat_type,
                                         job.job_items [1].mat_index)

    Main_Page.Second_Item =
      widgets.Label {text = description,
                     frame = {l = 24, t = 3, y_align = 0},
                     text_pen = COLOR_YELLOW}
   
    if job.mat_type <= 2 then
      description = df_selects
     
    else
      description = description_string_of (job.job_items [2].item_type,
                                           job.job_items [2].mat_type,
                                           job.job_items [2].mat_index)
    end
   
    Main_Page.Third_Item =
      widgets.Label {text = description,
                     frame = {l = 24, t = 4, y_align = 0},
                     text_pen = COLOR_YELLOW,
                     visible = job.mat_type > 2}
   
    if job.mat_type <= 3 then
      description = df_selects
     
    else
      description = description_string_of (job.job_items [3].item_type,
                                           job.job_items [3].mat_type,
                                           job.job_items [3].mat_index)
    end
   
    Main_Page.Fourth_Item =
      widgets.Label {text = description,
                     frame = {l = 24, t = 5, y_align = 0},
                     text_pen = COLOR_YELLOW,
                     visible = job.mat_type > 3}
           
    local mainPage = widgets.Panel {
      subviews = {Main_Page.First_Ingredient_Label,
                  Main_Page.Second_Ingredient_Label,
                  Main_Page.Third_Ingredient_Label,
                  Main_Page.Fourth_Ingredient_Label,
                  Main_Page.Name_Label,
                  Main_Page.First_Item,
                  Main_Page.Second_Item,
                  Main_Page.Third_Item,
                  Main_Page.Fourth_Item}}
               
    local pages = widgets.Pages
      {subviews = {mainPage},view_id = "pages",
                   }

    pages:setSelected (1)
     
    self:addviews {pages}
  end

  --==============================================================

  function Ui:on_select_first_ingredient (index, choice)
    job.job_items [0].item_type = list [index] [1]
    job.job_items [0].mat_type = list [index] [2]
    job.job_items [0].mat_index = list [index] [3]
   
    Main_Page.First_Item:setText (list [index] [4])
  end
 
  --==============================================================

  function Ui:on_select_second_ingredient (index, choice)
    dfhack.println (index, choice, #choice)
    job.job_items [1].item_type = list [index] [1]
    job.job_items [1].mat_type = list [index] [2]
    job.job_items [1].mat_index = list [index] [3]
   
    Main_Page.Second_Item:setText (list [index] [4])
  end
 
  --==============================================================

  function Ui:on_select_third_ingredient (index, choice)
    job.job_items [2].item_type = list [index] [1]
    job.job_items [2].mat_type = list [index] [2]
    job.job_items [2].mat_index = list [index] [3]
   
    Main_Page.Third_Item:setText (list [index] [4])
  end
 
  --==============================================================

  function Ui:on_select_fourth_ingredient (index, choice)
    job.job_items [3].item_type = list [index] [1]
    job.job_items [3].mat_type = list [index] [2]
    job.job_items [3].mat_index = list [index] [3]
   
    Main_Page.Fourth_Item:setText (list [index] [4])
  end
 
  --==============================================================

  function Ui:onInput (keys)
    if keys.LEAVESCREEN_ALL then
        self:dismiss ()
    end
   
    if keys.LEAVESCREEN then
        self:dismiss ()
    end

    if keys [keybindings.first.key] then
      populate_lists (list, display_list, true)
     
      dialogs.showListPrompt("Enter first ingredient selection",
                             "text",
                             nil,
                             display_list,
                             self:callback ("on_select_first_ingredient"))  --  Don't think an "on_cancel" is needed       
   
    elseif keys [keybindings.second.key] then
      populate_lists (list, display_list, false)
   
      dialogs.showListPrompt("Enter second ingredient selection",
                             "text",
                             nil,
                             display_list,
                             self:callback ("on_select_second_ingredient"))  --  Don't think an "on_cancel" is needed       
   
    elseif keys [keybindings.third.key] and
           job.mat_type > 2 then
      populate_lists (list, display_list, false)     
   
      dialogs.showListPrompt("Enter third ingredient selection",
                             "text",
                             nil,
                             display_list,
                             self:callback ("on_select_third_ingredient"))  --  Don't think an "on_cancel" is needed       
   
    elseif keys [keybindings.fourth.key] and
           job.mat_type > 3 then
      populate_lists (list, display_list, false)
       
      dialogs.showListPrompt("Enter fourth ingredient selection",
                             "text",
                             nil,
                             display_list,
                             self:callback ("on_select_fourth_ingredient"))  --  Don't think an "on_cancel" is needed         
    end

    self.super.onInput (self, keys)
  end

  --============================================================

  function Show_Viewer ()
    local screen = Ui {}
    persist_screen = screen
    screen:show ()
  end

  --============================================================

  Show_Viewer () 
end

Chef ()
Logged

hanni79

  • Bay Watcher
    • View Profile

Wow, nice, thank you very much !

But, well, I don't have any clue what to do with this  :'(

I would guess I have to save it somewhere into the DFHack folder and then call it via the DFHack console while playing ?
Logged

Jimmy

  • Bay Watcher
    • View Profile

Damn I'm old. I remember when all you needed to keep a fortress happy was stacks of dwarven syrup roasts, floodgates to refresh your farms each spring, and avoiding digging too far to the right.
Logged

PatrikLundell

  • Bay Watcher
    • View Profile

Wow, nice, thank you very much !

But, well, I don't have any clue what to do with this  :'(

I would guess I have to save it somewhere into the DFHack folder and then call it via the DFHack console while playing ?
Sorry.
Copy the contents in the code part, paste it into a text file you've created with new (text) file named chef.lua in the hack\scripts folder, save the file, and type "chef" into the dfhack console (without the .lua suffix) when you've opened the kitchen and created a new meal (I always use lavish meals, but the others should work as well). Once the script runs, it should bring up an overlay on top of DF with 2-4 commands available, "a", "b", "c", and "d" for selection of the various meal components.  These commands bring up a selection window with all the possible ingredients (and it's a long list, typically), sorted alphabetically. Scroll up/down with the arrow keys and select with <ENTER>. Once done, leave with <ESC>.
Logged

KevinM

  • Bay Watcher
    • View Profile

Just one thing, that
Quote
Especially when thinking about the stress problems it is paramaount in my view to at least get cooking right. I have dozens of dwarves with "Feeling dejected because of lack of decent meal" thought (x349739).

part is purely due to not having the ingredients.  I think the script will help with the liquid ingredients, and if I use DFhack I may borrow it for that purpose, but if you don't have the other favorite ingredients that a dwarf may want, then you're still going to get those negative thoughts.

I know how you feel about the food thing.  My main focus in any game is the food and recipes and just enjoying that part. I could care less about the invasions and fighting, I just like making the food variety with as little pain as possible.
Logged

PatrikLundell

  • Bay Watcher
    • View Profile

Here's an improved version of the script with string matching selection for the items, which saves on scrolling.

Spoiler (click to show/hide)
Logged

Bumber

  • Bay Watcher
  • REMOVE KOBOLD
    • View Profile

Doesn't gui/workshop-job (alt-a) mostly do the same thing?
Logged
Reading his name would trigger it. Thinking of him would trigger it. No other circumstances would trigger it- it was strictly related to the concept of Bill Clinton entering the conscious mind.

THE xTROLL FUR SOCKx RUSE WAS A........... DISTACTION        the carp HAVE the wagon

A wizard has turned you into a wagon. This was inevitable (Y/y)?

hanni79

  • Bay Watcher
    • View Profile

Here's an improved version of the script with string matching selection for the items, which saves on scrolling.

Hmm, something went wrong I think, it just gives me the following options and isn't able to "see" all my ingredients :
Spoiler (click to show/hide)

Thanks a lot for your effort anyway !
As Bumber pointed out, "gui/workshop-job (alt-a)" seems to indeed do basically what your script does, I never knew ! :o

I kind of feel bad that you wrote that whole script just because I wasn't aware of what Bumber said, I'm sorry -.-
Logged

PatrikLundell

  • Bay Watcher
    • View Profile

@bumber: yes, mostly. There are a number of ingredients it can't handle, though, like eggs, if I remember correctly from trying it a number of years ago.

Anyway, I think the reason most of the items are missing is that I've mistakenly thought the "in_inventory" flag meant someone was carrying the item around, but it's also set for all the items stored in containers... and I basically don't use containers (using quantum stockpiles instead). Here's the updated version, but you're free to use whatever you feel is most convenient.

Spoiler (click to show/hide)
Logged
Pages: 1 2 [3]