Skip to content

feat: bird roosting behavior on trees#82

Merged
biosynthart merged 2 commits into
hellolifeforms:mainfrom
biosynthart:feature/songbird-reproduction-and-rendering
Jun 9, 2026
Merged

feat: bird roosting behavior on trees#82
biosynthart merged 2 commits into
hellolifeforms:mainfrom
biosynthart:feature/songbird-reproduction-and-rendering

Conversation

@biosynthart

Copy link
Copy Markdown
Member

Summary

Adds data-driven roosting behavior for birds. Species with roost_affinity seek preferred tree species when RESTING or IDLE, and gain an energy recovery bonus while perched within a tree's canopy.

Design

Fully driven by trait data — no engine special-casing by entity type:

  • roost_affinity: list[str] on TraitVector/DerivedParams — species IDs of preferred roost trees (e.g. ["oak", "meadow_oak"])
  • Birds with this trait seek the nearest matching living tree when in RESTING or IDLE state
  • They approach to just inside the tree's canopy radius and stop
  • While within canopy + buffer distance, energy recovery is boosted by 50%

Behavior

  1. IDLE bird with roost_affinity → seeks nearest preferred tree, perches within canopy
  2. RESTING bird with roost_affinity → same tree-seeking behavior
  3. Bird at tree (within canopy + buffer) → gets 1.5× energy recovery while resting/idling
  4. No matching trees nearby → falls through to default wander behavior

Files Changed

File Change
ecosim/traits.py New roost_affinity field on TraitVector + DerivedParams, flows through derive_all() and trait_vector_from_dict()
ecosim/constants.py ROOST_ENERGY_BONUS_FACTOR = 0.5, ROOST_PROXIMITY_BUFFER = 1.0
ecosim/actors/movement_actors.py _resolve_roosting_target() + _find_nearest_roost_tree() — tree-seeking target resolution
ecosim/movement_system.py Allow RESTING/IDLE birds with roost_affinity to move (movement gate exception)
ecosim/actors/flow_actors.py Energy recovery bonus when within canopy of a preferred roost tree
examples/species_definitions.json Songbird gets "roost_affinity": ["oak", "meadow_oak"]
examples/demo_world.json Songbird gets "roost_affinity": ["meadow_oak"]

Testing

All 165 existing tests pass. New trait flows cleanly through TraitVector → derive_all() → DerivedParams pipeline.

- Add songbird rendering to visualizer (teardrop body, animated wings,
  dovetail tail, expanding song rings when IDLE/REPRODUCING)
- Introduce male/female sex for ANIMAL/BIRD/INSECT entities:
  - Only females produce offspring (clutch_size applies per female)
  - Mate must be opposite sex within sensory range
  - Offspring get random sex at birth
  - Auto-assign random sex on init if not provided in world def
- Replace hardcoded FLEE_TRIGGER_DISTANCE with entity's sensory_range,
  so prey flee proportionally to what they can detect
- Add songbird omnivore fallback: foraging songbirds hunt butterflies
  when flowers are scarce or all on cooldown
- Increase demo butterfly count from 2 to 4 (2♀ + 2♂)
- Fix stale comment about reproductive drive being permanently zero
- Update SpawnEntity effect and both spawn handlers to carry sex field
- Add tests: male cannot spawn, same-sex mate rejected
- Add roost_affinity trait (list of preferred tree species) to TraitVector/DerivedParams
- Birds with roost_affinity seek nearest matching tree when RESTING or IDLE
- Movement gate allows resting birds to move toward trees (like pollinators for flowers)
- Energy recovery boosted by 50% when within canopy of a preferred roost tree
- All behavior driven by data — no engine special-casing by entity type

Files changed:
  traits.py          — new roost_affinity field, flows through derive_all()
  constants.py       — ROOST_ENERGY_BONUS_FACTOR, ROOST_PROXIMITY_BUFFER
  movement_actors.py — _resolve_roosting_target(), _find_nearest_roost_tree()
  movement_system.py — allow RESTING/IDLE birds with roost_affinity to move
  flow_actors.py     — energy recovery bonus near preferred roost trees
  species_definitions.json, demo_world.json — wire up songbird → oak affinity
@biosynthart biosynthart merged commit 91c0e85 into hellolifeforms:main Jun 9, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant