Needs & Mood

Overview

Every elf has five basic needs and a mood stack that together determine their morale -- the single number (0-100) that governs behavior, work speed, and departure risk. Needs decay at different rates; mood modifiers stack additively; and morale tiers have hysteresis bands to prevent flickering when an elf hovers near a boundary.


How It Works

Needs

Needs live on a 0-100 scale. Each need decays automatically every tick (or every Nth tick). When a need drops below a threshold, the elf's behavior tree redirects them toward satisfying it before doing productive work.

NeedInitial ValueDecay RateDecay Frequency
Rest100-1Every tick
Sustenance100-1Every 4th tick
Beauty60-1Every 2nd tick
Stimulation60-1Every 2nd tick
Company50variesEvery 2nd tick (personality)

(Source: src/sim/components.rs, Needs::full(); src/sim/systems.rs, rest_decay_system(), sustenance_decay_system(), beauty_decay_system(), stimulation_decay_system(), company_system())

Need Status Labels

The game displays a named tier for each need value:

Value RangeLabelCompact Char
80-100Fulfilled+
50-79Fine~
20-49Wanting-
0-19Critical!

(Source: src/sim/components.rs, need_label(), need_char())

Company (the 5th Need)

Company is unique: its behavior depends on the elf's Social aesthetic axis (0.0 = Personal, 1.0 = Social).

Social AxisBehaviorRecovery
> 0.7 (Social elf)Decays -1 per cycle toward 0+2 when >= 2 elves within 3 tiles
< 0.3 (Personal elf)Rises toward 100 (wants solitude)-2 when alone; +1 when >= 3 within 5 tiles
0.3-0.7 (Middle)Gentle pull toward 50+1 if below 50; -1 if above 50

The proximity check uses Manhattan distance. Company ticks every 2nd tick, same as Beauty and Stimulation.

(Source: src/sim/systems.rs, company_system())

Mood Stack

Mood is a collection of active MoodModifiers. Each modifier has:

  • description -- human-readable label (e.g. "Ate a meal")
  • value -- signed integer bonus/penalty (i8)
  • ticks_remaining -- countdown to expiry

Every tick, the mood system decrements ticks_remaining by 1 and removes expired modifiers. Modifiers stack additively.

Morale is computed as:

morale = clamp(base + sum(modifier.value), 0, 100)

where base = 50 (constant).

(Source: src/sim/components.rs, Mood::compute_morale(), Mood::net_mood())

Common Mood Modifiers

SourceValueDuration (ticks)
Ate a meal+550
Slept in dwelling+3100
Slept on ground-350
Caught in rain (outdoors)-150
Snow-covered landscape+250
Awed by ancient grove+2200
Grieving (mourning)-5mourning duration
Spring optimism (seasonal)+21 day (100 ticks)
Autumn melancholy (seasonal)-11 day (100 ticks)
Winter stillness (seasonal)-11 day (100 ticks)
Favorite spot+115 ticks
Personal time+250 ticks

(Source: src/sim/systems.rs, eating_system(), resting_system(), weather_mood_system(), seasonal_mood_system(), favorite_places_system(), personal_time_system(); src/sim/components.rs, Mourning)

Replace vs Push Semantics

  • mood.push() -- always adds a new modifier (stacks with existing same-name entries).
  • mood.replace() -- if a modifier with the same description exists, refreshes its value and duration; otherwise inserts. Weather modifiers use replace to avoid stacking.

(Source: src/sim/components.rs, Mood::push(), Mood::replace())


Values & Formulas

Morale Tiers

TierMorale RangeEffect
Inspired80-100Work speed +2; gravitates toward creative work
Normal50-79Standard behavior
Stressed20-49Work speed -1
Breaking0-19Refuses all non-critical work; idles

Work Speed Modifier = match morale_state: Inspired => +2, Stressed => -1, else => 0

(Source: src/sim/systems.rs, work_speed_modifier(); src/sim/components.rs, morale_state())

Hysteresis Bands

To prevent rapid tier-flickering, transitions require crossing a threshold 3 points beyond the nominal boundary:

Current TierTransition UpTransition Down
Breaking> 23 -> Stressed--
Stressed> 53 -> Normal< 17 -> Breaking
Normal> 83 -> Inspired< 47 -> Stressed
Inspired--< 77 -> Normal

If no previous tier exists (e.g. first evaluation), the nominal thresholds (80, 50, 20) are used directly.

(Source: src/sim/components.rs, morale_state_with_hysteresis())


Interactions

  • Roles -- morale determines which tasks an elf will accept; Breaking-tier elves refuse all non-critical work.
  • Buildings -- Dwellings speed rest recovery (+5/tick vs +2 outdoors); buildings within Manhattan distance 2 count as "shelter" for weather mood modifiers.
  • Skills -- work speed modifier from morale applies to gathering and building progress rates.
  • Terrain -- terrain beauty values passively restore the Beauty need.
  • Resources -- eating consumes 1 Food and restores +30 Sustenance (capped at 100).

Tips

  • Rest decays fastest (every tick). Prioritize building Dwellings early to keep rest recovery efficient (+5/tick indoors vs +2 outdoors).
  • Sustenance decays slowest (every 4th tick). In a pinch, elves can survive a long time on foraging alone.
  • Beauty and Stimulation both decay every 2nd tick starting from 60 (not 100). Build a Garden and Workshop early to prevent mid-game mood dips.
  • Company is personality-driven. Social elves (Social > 0.7) need companions nearby; personal elves (Social < 0.3) want solitude. Keep an eye on the aesthetic axes of your colony members.
  • Hysteresis means momentum matters. An elf who climbs to Inspired will stay there until morale drops below 77. Plan mood boosts in clusters rather than spreading them thin.
  • Weather modifiers use replace semantics, so you will never see "Caught in rain" stacked five times. But one-time events (first ancient grove visit) do stack with ongoing weather effects.