Okay, let's get some data!
Firstly: how emotions work. While the thought text is
white on the emotions page, they are experiencing that emotion and it is actively changing their stress level.
As soon as the thought text goes grey,
it immediately stops affecting their stress. (Edit) This may not be true. I hypothesized below that the unmet needs may be affecting stress drain, but it might actually be some sort of gradual accumulation from stale (grey text) thoughts. I genuinely don't know. Damn this is complicated.
Data Format
Stress: [STRESS_LEVEL]; [EMOTION];[CAUSE];[Strength];[Severity];[unk2]I have no idea what unk2 is, but it seems important.
Stress:-8;
Stress:-4;
Stress:0;
Stress:0;
Stress:48; BOREDOM;NeedsUnfulfilled;100;-1;1 BOREDOM;NeedsUnfulfilled;100;-1;1
Stress:96; BOREDOM;NeedsUnfulfilled;100;-1;1 BOREDOM;NeedsUnfulfilled;100;-1;1
Stress:144; BOREDOM;NeedsUnfulfilled;100;-1;1 BOREDOM;NeedsUnfulfilled;100;-1;1
Stress:134;
Stress:124;
Stress:114;
Stress:104;
Stress:94;
Stress:84;
Stress:74;
Stress:64;
Stress:54;
Stress:44;
Stress:34;
Stress:24;
Stress:14;
Stress:4;
Stress:0;
Stress:0;
Stress:0;
Stress:0;
Stress drifts back towards zero over time. You can see this happening in the data above. However, to my surprise, this drift
doesn't seem to be determined by [ANXIETY PROPENSITY], which is what the wiki states. It's highly variable (I've seen drifts as high as 12 and as low as 2), but my most anxious citizen (goblin hammerwoman, ANXIETY = 73) loses stress
even faster than my least anxious (axedwarfette, ANXIETY = 5) when no thoughts are present.
This requires additional science, by I have a hypothesis that it's affected by the Focus/Needs system. Dwarves who are distracted will drain stress more slowly than dwarves who are focused. As evidence for this, I observed this dwarves stress drain drop from 4 to 2 after a bunch of NeedsUnfulfilled thoughts were applied:
Stress:487;
Stress:483;
Stress:479;
Stress:475;
Stress:471;
Stress:467;
Stress:463;
Stress:459;
Stress:455;
Stress:451;
Stress:447;
Stress:547; BOREDOM;NeedsUnfulfilled;100;-1;1 LONELINESS;NeedsUnfulfilled;1;-1;1 UNEASINESS;NeedsUnfulfilled;1;109;1 BOREDOM;NeedsUnfulfilled;100;-1;1 LONELINESS;NeedsUnfulfilled;1;-1;1 BOREDOM;NeedsUnfulfilled;100;-1;1 UNEASINESS;NeedsUnfulfilled;1;-1;1
Stress:647; BOREDOM;NeedsUnfulfilled;100;-1;1 LONELINESS;NeedsUnfulfilled;1;-1;1 UNEASINESS;NeedsUnfulfilled;1;109;1 BOREDOM;NeedsUnfulfilled;100;-1;1 LONELINESS;NeedsUnfulfilled;1;-1;1 BOREDOM;NeedsUnfulfilled;100;-1;1 UNEASINESS;NeedsUnfulfilled;1;-1;1
Stress:747; BOREDOM;NeedsUnfulfilled;100;-1;1 LONELINESS;NeedsUnfulfilled;1;-1;1 UNEASINESS;NeedsUnfulfilled;1;109;1 BOREDOM;NeedsUnfulfilled;100;-1;1 LONELINESS;NeedsUnfulfilled;1;-1;1 BOREDOM;NeedsUnfulfilled;100;-1;1 UNEASINESS;NeedsUnfulfilled;1;-1;1
Stress:745;
Stress:743;
Stress:741;
Stress:739;
Stress:737;
Stress:735;
Stress:733;
Stress:731;
Stress:729;
Stress:727;
Stress:725;
[DFHack]#
Generally speaking, the two things that matter most for stress are
Strength, which determines how rapidly the thought causes stress change, and
how long it lasts. As far as I can tell, most thoughts do not persist for very long (around 600 ticks), but they can be maintained by syndrome effects (inebriation consistently lasts longer) and combined with new thoughts of the same type.
Thoughts seem to negate stress drain for as long as they last, and they round up to the nearest 1, so even the lowest strength thought possible will affect stress level if no other thought is happening at the time.
Stress:-4701;
Stress:-4699;
Stress:-4697;
Stress:-4697; SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4699; SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4703; SATISFACTION;SatisfiedAtWork;3;0;50 PLEASURE;AdmireOwnBuilding;1;30;20 PLEASURE;AdmireBuilding;1;100;10
Stress:-4708; PLEASURE;AdmireOwnBuilding;1;30;20 PLEASURE;AdmireBuilding;1;100;10
Stress:-4713; PLEASURE;AdmireOwnBuilding;1;30;20 PLEASURE;AdmireBuilding;1;100;10 SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4717; SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4720; SATISFACTION;SatisfiedAtWork;3;0;50 SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4723; SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4725; SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4730; CONTENTMENT;WearItem;1;2;40 CONTENTMENT;WearItem;1;1;20
Stress:-4736; CONTENTMENT;WearItem;1;2;40 CONTENTMENT;WearItem;1;1;20 PLEASURE;WearItem;6;5;100
Stress:-4744; CONTENTMENT;WearItem;1;2;40 CONTENTMENT;WearItem;1;1;20 PLEASURE;WearItem;6;5;100 SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4749; PLEASURE;WearItem;6;5;100 SATISFACTION;SatisfiedAtWork;3;0;50 CONTENTMENT;WearItem;1;1;20
Stress:-4753; SATISFACTION;SatisfiedAtWork;3;0;50 CONTENTMENT;WearItem;1;1;20
Stress:-4755; CONTENTMENT;WearItem;1;1;20
Stress:-4755;
Stress:-4753;
Stress:-4751; EUPHORIA;Syndrome;87;59;87
Stress:-4749; EUPHORIA;Syndrome;100;59;100
Stress:-4747; EUPHORIA;Syndrome;100;59;100
Stress:-4747; SATISFACTION;SatisfiedAtWork;3;0;50 EUPHORIA;Syndrome;100;59;100
Stress:-4749; SATISFACTION;SatisfiedAtWork;3;0;50 EUPHORIA;Syndrome;100;59;100
Stress:-4751; SATISFACTION;SatisfiedAtWork;3;0;50 EUPHORIA;Syndrome;100;59;100
Stress:-4751; EUPHORIA;Syndrome;100;59;100
Stress:-4749; EUPHORIA;Syndrome;100;59;100
Stress:-4747; EUPHORIA;Syndrome;100;59;100
Stress:-4745; EUPHORIA;Syndrome;100;59;100
Stress:-4743; EUPHORIA;Syndrome;100;59;100 SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4745; EUPHORIA;Syndrome;100;59;100 SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4747; EUPHORIA;Syndrome;100;59;100 SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4751; SATISFACTION;SatisfiedAtWork;3;0;50 SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4753; SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4746; SATISFACTION;SatisfiedAtWork;3;0;50 SELF_PITY;NeedsUnfulfilled;10;-1;1 LONELINESS;NeedsUnfulfilled;1;-1;1 DEJECTION;NeedsUnfulfilled;2;-1;1 SELF_PITY;NeedsUnfulfilled;10;-1;1 LONELINESS;NeedsUnfulfilled;1;-1;1 SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4738; SELF_PITY;NeedsUnfulfilled;10;-1;1 LONELINESS;NeedsUnfulfilled;1;-1;1 DEJECTION;NeedsUnfulfilled;2;-1;1 SELF_PITY;NeedsUnfulfilled;10;-1;1 LONELINESS;NeedsUnfulfilled;1;-1;1 SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4730; SELF_PITY;NeedsUnfulfilled;10;-1;1 LONELINESS;NeedsUnfulfilled;1;-1;1 DEJECTION;NeedsUnfulfilled;2;-1;1 SELF_PITY;NeedsUnfulfilled;10;-1;1 LONELINESS;NeedsUnfulfilled;1;-1;1 SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4730;
Stress:-4730; SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4734; SATISFACTION;SatisfiedAtWork;3;0;50 PLEASURE;AdmireBuilding;1;80;10
Stress:-4738; SATISFACTION;SatisfiedAtWork;3;0;50 PLEASURE;AdmireBuilding;1;80;10
Stress:-4743; PLEASURE;AdmireBuilding;1;80;10 SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4745; SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4747; SATISFACTION;SatisfiedAtWork;6;0;100
Stress:-4749; SATISFACTION;SatisfiedAtWork;6;0;100
Stress:-4751; SATISFACTION;SatisfiedAtWork;6;0;100
Stress:-4756; SATISFACTION;ImproveSkill;6;0;100 SATISFACTION;SatisfiedAtWork;3;0;50
Stress:-4762; SATISFACTION;ImproveSkill;6;0;100 SATISFACTION;SatisfiedAtWork;3;0;50 SATISFACTION;SatisfiedAtWork;3;0;50
The thought combination system means that new thoughts of the same type can both extend the duration
and increase the strength of prior thoughts, if they're applied quickly enough. This results in an exponential stress change that lasts as long as the thought is continually applied. This is most apparent in the case of skill demonstrations, and may explain why militiadwarves tend to be very happy critters.
Note the strength of "TeachSkill" and "LearnSkill" starting at 3 and scaling up to 45 as the demonstration continues, after which the thought lasts for another few ticks.
Stress:-3044;
Stress:-3042;
Stress:-3040;
Stress:-3040; SATISFACTION;TeachSkill;3;0;100
Stress:-3042; SATISFACTION;TeachSkill;6;0;100
Stress:-3044; SATISFACTION;TeachSkill;9;0;100
Stress:-3046; SATISFACTION;TeachSkill;12;0;100
Stress:-3052; BLISS;DiningQuality;4;5;70 SATISFACTION;TeachSkill;15;0;100
Stress:-3063; BLISS;DiningQuality;4;5;70 SATISFACTION;TeachSkill;18;0;100
Stress:-3075; BLISS;DiningQuality;4;5;70 SATISFACTION;TeachSkill;21;0;100
Stress:-3079; SATISFACTION;TeachSkill;24;0;100
Stress:-3085; SATISFACTION;TeachSkill;27;0;100
Stress:-3091; SATISFACTION;TeachSkill;27;0;100
Stress:-3097; SATISFACTION;TeachSkill;30;0;100
Stress:-3105; SATISFACTION;TeachSkill;33;0;100
Stress:-3113; SATISFACTION;TeachSkill;36;0;100
Stress:-3121; SATISFACTION;TeachSkill;39;0;100
Stress:-3130; SATISFACTION;TeachSkill;42;0;100
Stress:-3138; BOREDOM;NeedsUnfulfilled;1;-1;1 UNEASINESS;NeedsUnfulfilled;0;109;1 SATISFACTION;TeachSkill;45;0;100
Stress:-3146; UNEASINESS;NeedsUnfulfilled;0;109;1 BOREDOM;NeedsUnfulfilled;1;-1;1 SATISFACTION;TeachSkill;45;0;100 INTEREST;AdmireBuilding;12;80;100
Stress:-3156; UNEASINESS;NeedsUnfulfilled;0;109;1 BOREDOM;NeedsUnfulfilled;1;-1;1 SATISFACTION;TeachSkill;45;0;100 INTEREST;AdmireBuilding;12;80;100
Stress:-3164; INTEREST;AdmireBuilding;12;80;100 INTEREST;LearnSkill;3;0;100
Stress:-3167; INTEREST;LearnSkill;6;0;100
Stress:-3169; INTEREST;LearnSkill;9;0;100
Stress:-3171; INTEREST;LearnSkill;12;0;100
Stress:-3173; INTEREST;LearnSkill;15;0;100
Stress:-3176; INTEREST;LearnSkill;18;0;100
Stress:-3180; INTEREST;LearnSkill;21;0;100
Stress:-3184; INTEREST;LearnSkill;24;0;100
Stress:-3190; INTEREST;LearnSkill;27;0;100
Stress:-3196; INTEREST;LearnSkill;30;0;100
Stress:-3202; INTEREST;LearnSkill;30;0;100
Stress:-3210; INTEREST;LearnSkill;33;0;100
Stress:-3218; INTEREST;LearnSkill;36;0;100
Stress:-3226; INTEREST;LearnSkill;39;0;100
Stress:-3235; INTEREST;LearnSkill;42;0;100
Stress:-3245; INTEREST;LearnSkill;45;0;100
Stress:-3255; INTEREST;LearnSkill;45;0;100
Stress:-3265; INTEREST;LearnSkill;45;0;100
Stress:-3269;
Stress:-3267; CONTENTMENT;GoodMeal;1;2;20
Stress:-3269; CONTENTMENT;GoodMeal;1;2;20
Stress:-3271; CONTENTMENT;GoodMeal;1;2;20
Stress:-3273; CONTENTMENT;GoodMeal;1;2;20
Stress:-3283; INTEREST;LearnSkill;90;0;100
Stress:-3305; INTEREST;LearnSkill;90;0;100
Stress:-3327; INTEREST;LearnSkill;90;0;100
Stress:-3327; SATISFACTION;Argument;3;0;50
Stress:-3329; SATISFACTION;Argument;3;0;50
Stress:-3331; SATISFACTION;Argument;3;0;50
Stress:-3331;
Stress:-3329;
Honeslty, I still don't have any answers about how to exploit all this information. Keeping dwarves happy is complicated. Fun to science, though.
Here's the script. It's a cheap-n-nasty bastardization of the list-memories script that was posted earlier.
-- Prints out all the memories of the selected unit, along with some metadata.
local help = [====[
Select a unit in dwarf fortress, then run this script.
It will print out three blocks of information:
Short term memories, long term memories, and memories which have been
reflected upon.
The number in brackets after the thought is metadata used to store extra
details about the type of memory. It tracks things like who was talked to,
which book was read, etc.
The strength variable probably determines which memories get overwritten.
The severity variable seems to store metadata such as the value of a room
or the quality of an tem of clothing.
Memories in the "reflected memories" category don't seem to cause new
thoughts, but any personality changes which resulted from those memories
are displayed.
The date format is "YYY-MM-DD HH:TT", where TT runs from 0 to 50.
There are 50 ticks per hour so this seemed more elegant.
Options:
-help show this help screen
-all include overwritten and uninitialized memory slots in the output
]====]
utils = require('utils')
local validArgs = utils.invert({'help', 'all'})
local args = utils.processArgs({...}, validArgs)
if args.help then
print(help)
return
end
local color_A = 10
local color_B = 11
local color_uninit = 8
local color_overwritten = 13
function get_thought_type(agr)
return df.unit_thought_type[agr]
end
function get_emotion_type(agr)
return df.emotion_type[agr]
end
function get_facet_type(agr)
return df.personality_facet_type[agr]
end
function get_value_type(agr)
return df.value_type[agr]
end
function sort_emo(emo1, emo2)
return (emo1.year < emo2.year) or ((emo1.year == emo2.year) and (emo1.year_tick < emo2.year_tick))
end
function sort_reflection(ref1, ref2)
return sort_emo(ref1.memory, ref2.memory)
end
function pairs_sorted(t, f)
local a = {}
for key,value in pairs(t) do table.insert(a, value) end
table.sort(a, f)
return pairs(a)
end
function get_date_string(emo)
local year = emo.year
local tick = emo.year_tick
if year == -1 then return "None" end
if tick == -1 then
return string.format("Before year %d", year)
end
local month = math.floor(tick / 33600) + 1
local day = math.floor((tick % 33600) / 1200) + 1
local hour = math.floor((tick % 1200) / 50)
local minute = math.floor((tick % 50))
return string.format("%d-%02d-%02d %02d:%02d", year, month, day, hour, minute)
end
function print_emotion(emo)
local datestr = get_date_string(emo)
local feeling = get_emotion_type(emo.type)
local event = get_thought_type(emo.thought)
local subthought = emo.subthought
if feeling == "ANYTHING" then
return ""
else
return string.format("%s;%s;%s;%s;%s", feeling, event, emo.strength, emo.severity, emo.unk2)
end
end
function display_emotions(emotions, stressLevel)
local outputString = string.format("Stress:%d;", stressLevel)
for ii, emo in pairs_sorted(emotions, sort_emo) do
local color = -1
if ii%2 == 0 then
color = color_A
else
color = color_B
end
if emo.thought == -1 then color = color_overwritten end
if emo.year == -1 then color = color_uninit end
dfhack.color(color)
if emo.unk2 > 0 then
outputString = string.format("%s %s", outputString, print_emotion(emo))
end
end
print(outputString)
dfhack.color(-1)
end
sel = dfhack.gui.getSelectedUnit()
if not sel then qerror("No unit selected.") end
if not sel.status.current_soul.personality.memories then
qerror("The selected unit doesn't have a memory struct.")
end
emotions = sel.status.current_soul.personality.emotions
mem_short = sel.status.current_soul.personality.memories.shortterm
mem_long = sel.status.current_soul.personality.memories.longterm
mem_reflected = sel.status.current_soul.personality.memories.reflected_on
dfhack.color(-1)
display_emotions(emotions, sel.status.current_soul.personality.stress_level)
Follow a dwarf and run it with the following to get an output over time:
[DFHack]# repeat -time 200 -timeUnits ticks -command [ list-memories ]