This commit is contained in:
2026-11-05 09:57:11 -05:00
parent d34388bf2c
commit 89e392cc2e
81 changed files with 12410 additions and 1135 deletions
+188 -53
View File
@@ -13,14 +13,16 @@ Sunny, moderately grassy sites support wildflowers; dense grass competes with
flowers. Moist shaded sites support ferns. Trees reduce local light and retain
moisture; prolonged shade kills sun-loving ground cover. Rivers and biome humidity
also influence moisture. Established sparse meadow can recruit a tree seedling;
seedlings become young trees, then mature seed-bearing trees and finally deadwood.
seedlings become young trees, then mature seed-bearing trees. Lifespan endpoints
never automatically kill calendar plants or turn them into deadwood.
Living plants disperse to one adjacent suitable gap per eligible attempt. Mature
trees shed litter and disperse seedlings. Competition and occupation reject seeds;
seedlings never replace flowers, crops, another tree, or even existing meadow grass.
Wildlife can consume active natural grass, ferns, clover, sedge and nettles and
leave dung. Dormant winter plants cannot supply food or breeding habitat. Grazing opens gaps
but imposes a five-minute recolonization cooldown. Dung, litter and deadwood
leave dung. Dormant winter plants cannot supply browse. Grazing debits one partial
canopy ration without removing the perennial; the shared per-root browse receipt
rests seven real days. No stubble rendering is installed by this change. Dung, litter and deadwood
decompose; moist, shaded organic patches seed fungi. Decomposition releases finite
nutrients into the supporting soil (capped at eight). Fertile soil recruits ground
cover sooner and successful establishment consumes one nutrient. Fungi are
@@ -47,7 +49,7 @@ identity, respects external protection, and uses `swap_node` to retain owner/pla
markers, natural flags, age, metadata inventories and timers. It does not convert
other timber, rewrite surrounding nodes, or regenerate existing terrain.
### Active-time scales (minimums, not wall-clock promises)
### Calendar biology versus bounded loaded work
| Process | Observed active time |
| --- | --- |
@@ -55,17 +57,22 @@ other timber, rewrite surrounding nodes, or regenerate existing terrain.
| Grass/flower/fern dispersal eligibility | 15 minutes; attempt every third evaluation |
| Severe niche stress to litter/deadwood | 10 minutes |
| Old meadow recruits a seedling | 2 hours; 4 in dense unfertilized grass, only suitable spatial niches |
| Seedling to young tree | 6 hours |
| Young to mature tree | 24 additional hours |
| Mature tree death | 72 additional hours |
| Mature seed dispersal | After 30 minutes; every tenth evaluation |
| Wildflower / grass and fern senescence | 4 / 6 hours |
| Dung / litter / fungi / deadwood decay | 10 / 30 / 40 / 120 minutes |
| Named seedling to young tree | Absolute juvenile-age endpoint from its lifecycle profile (default 5 real years) |
| Named young to mature tree | Absolute species maturity endpoint, not an additional stage-local duration |
| Generic unidentified tree | Explicit fallback: young after 1 real year, mature after 10; lifespan unknown |
| Living calendar plant death | Never inferred from lifespan endpoints or unknown age |
| Mature tree seed opportunity | At most one present eligible attempt per mean real year; no missed-event replay |
| Named understory seed opportunity | Requires known maturity and seed season; at most one attempt per 30 days |
| Dung / generic fungi decay | Existing game policies: 10 / 40 loaded minutes |
| Litter / deadwood decay | Conservative game fallbacks: 90 calendar days / one mean real year |
New tree generations therefore take sessions, not seconds. Each stage resets its
own age. Cold weather below 3°C suppresses establishment and living reproduction/
stage transitions. Decomposition and stress remain possible. This is a practical
niche model, not a botanical or hydrological solver. Young/mature identities are
New tree generations take actual calendar years, not compressed sessions. One
day is 86,400 seconds, a mean year 365.2425 days. Every named plant uses
[the lifecycle policy](lifecycles.md), including explicitly unverified group
fallbacks; sourced fields are not proof that all timing fields were researched.
Stage swaps preserve one root age. Cold below 3°C/dormancy suppresses visible
stage transitions and seeding, **not calendar aging**. No exact historical
growing-season integration or mortality model is claimed. Young/mature identities are
ordinary full-cube log roots; **a mature tree needs an actual multi-node block trunk
and leaf canopy**, not one bare root cube. The read-only `diversity.tree_plan`
interface below shares the same geometry used by mapgen. Applying it, validating
@@ -76,17 +83,54 @@ clearance assumption: mature profiles reach 9×10×9 and must be preflighted in
Unknown/player plants, water, unloaded nodes, claims and markers must block growth;
the plan's omitted air cells are never permission to clear or replace anything.
Existing mapgen log/leaves trees contribute shade but are not aged or destroyed.
Player-planted saplings, crops and berry bushes retain their existing time contract.
Player-planted generic saplings now require one real year before their bounded
young block-tree establishment, using an explicitly unidentified family fallback,
not an assumed birch. Generic trees have a ten-year maturity policy and no
automatic death. Player provenance is retained on every newly written timber cell.
Existing mature player/mapgen timber is not retroactively made killable.
Generic game grain has an explicit **120 warm-day approximate parameter**, not a
species/cultivar research claim. Stages require 24/72/120 equivalent warm days;
temperature below 3°C contributes zero, 3–10°C half, warmer one. At most 366
midpoint samples cover the entire planting-to-now interval, with no silent
30-day age cutoff. Long gaps coarsen quadrature, not discard age. This is bounded
climate estimation, not exact historic degree-day integration; stage high-water
prevents display regression. Invalid/future planting clocks and rollback pause,
never reset birthdays. Berry regrowth and food-patch harvest cooldowns remain
game resource policies, not organism lifespans. Legacy unidentified berry bushes
retain their initial standing crop, but picking locks them for one mean real year;
bare bushes then return only in an eligible Summer. This is a conservative annual
game policy, not researched species phenology. Rejected inventory transfer
restores original readiness; partial transfer spends the batch. Node swaps
preserve natural/ownership metadata. Seasonal greens/mushrooms retain their daily
game harvest policy, with reservation before inventory callbacks.
#### Calendar root persistence and migration (version 1)
See [the full metadata contract](botany.md#root-persistence-and-migration).
`succ_birth_at` is the UTC recruitment/adoption epoch, `succ_initial_age_seconds`
is a separate documented initial-stage assumption, and
`succ_last_observed_at` is a durable clock high-water mark.
`succ_lifecycle_version=1`, exact `succ_lifecycle_profile`, position-derived
`succ_lifecycle_seed`, `succ_lifecycle_origin` and policy label persist on roots.
New recruits use `natural_seed` and zero initial age. Existing natural legacy
plants migrate once at NOW with `legacy_established`, preserving `succ_age`
unchanged; it remains old active seconds, never millennia or a birthday.
Generated known botanical stands/soil-supported block log roots adopt
`worldgen_established` without resetting mature canopies into seeds or claiming
historically observed ages. Initial stage ages come from known profile endpoints;
unknown maturity is zero, not invented history. No negative/pre-epoch birthdays.
Malformed metadata, unsupported versions and clock rollback fail closed. No
offline mortality, forced terrain loads, whole-world scans or queued seed replay.
## Species diversity and understory
Shared tree identities are exactly **oak, birch, pine, willow, alder, beech, aspen,
rowan, hazel, spruce**, matching the ten trees in [botany.md](botany.md). Each has
rowan, hazel, spruce, crab_apple, wild_cherry, field_maple**, matching the thirteen trees in [botany.md](botany.md). Each has
canonical `hearth:<species>_seedling`, `hearth:<species>_young`, and
`hearth:<species>_mature` nodes. The six-hour/24-hour/72-hour stage durations above
remain unchanged. Growth and seed dispersal preserve the parent's species, and
death records `succ_species` on generic deadwood (retained through its litter
transition). Each young/mature root drops **one** of its species logs, never three
`hearth:<species>_mature` nodes. Growth and seed dispersal preserve the parent's
species and calendar anchor; old accelerated stage/death durations are removed.
Each young/mature root drops **one** of its species logs, never three
logs from one cube. Additional generated trunk cubes are separately harvestable.
Roots are hidden from creative inventory, use species log top/end and bark side
textures, `drawtype="normal"`, `tree=1`, `choppy=2`, and default cube collision.
@@ -101,7 +145,9 @@ Recruitment is deterministic, not an all-oak fallback:
- Oak favors stable forest floor with an existing canopy.
- Beech has a broad domed crown and avoids saturation; aspen is tall and columnar;
rowan has an open crown; hazel is low coppice; spruce has a narrow evergreen spire.
All ten have distinct mature block silhouettes and deterministic recruitment.
Crab apple has a broad round crown, wild cherry has horizontal branch tiers,
and field maple has a broad lobed crown. All thirteen have distinct mature block
silhouettes, species bark/end-grain/leaves/planks and deterministic recruitment.
- Willow favors moist alluvium/floodplain; alder favors peat and wet woodland.
Riparian recruitment requires moisture ≥0.65. Species soil support is delegated
to `hearth.biomes.supports_species(species, surface)` when present; its decision
@@ -138,8 +184,9 @@ nutrient metadata to eight without rewriting it.
Natural blooming clover, wildflowers, spring bluebells and autumn heather increase
the read-only `habitat(pos).pollination` count. This exposes a bounded habitat input
for berry-regrowth consumers; this module does **not** change berry timers or grant
extra berries. `edible` is a separate active-natural-forage count. Pine and spruce
for consumers; habitat reads never change berry timers or grant extra berries.
Transactional nectar debit below is separate from this observation.
`edible` is a separate active-natural-forage count. Pine and spruce
are evergreen in the catalogue and seasonal node policy; deciduous trees
retain only 15% canopy influence.
@@ -150,9 +197,13 @@ protection and placement/unknown metadata. Hand placement marks `player_placed=1
It never adopts species/generic logs, leaves, planks, crops or berry bushes. There
is no general adoption of arbitrary flora, generic litter or fungi, and no new
scanning scheduler. Adopted deadwood needs loaded natural ecological soil and
decays to litter after **two observed active hours**, releasing three nutrients
decays to litter after **one mean calendar year**, releasing three nutrients
(soil cap eight); subsequent litter decay releases one more, once. Adoption is
idempotent and grants no age or absence catch-up. As with
idempotent and grants no invented age. Organic decay uses durable
`succ_decay_at`, `succ_decay_initial`, `succ_decay_seen_at` high-water and bounded
`succ_decay_bonus`; elapsed absence changes present eligibility, never queues
missed decomposition or payouts. Litter returns only its unconsumed mineral
budget, not another full unit after earthworm feeding. As with
legacy unmarked soil, provenance cannot distinguish third-party placements that
deliberately omit every marker; those integrations must mark or claim their flora.
@@ -176,10 +227,12 @@ calendar through the existing solar model. Explicit test climates can preview it
| Spring greens patch | Pickable | Dormant | Dormant | Dormant |
| Autumn mushroom patch | Dormant | Dormant | Pickable | Dormant |
Frost and seasonal dormancy pause living age, stress and reproduction; they do not
kill perennials at first frost. Spring resumes the same ecological age. Deadwood,
Frost and seasonal dormancy pause visible growth, loaded stress and reproduction,
not calendar age; they do not kill perennials at first frost. Spring observes the
same root anchor plus the full elapsed calendar interval. Deadwood,
litter, dung and decomposer fungi continue returning nutrients in winter; mature
trees can continue shedding litter. First-night berry availability stays year-round.
trees can continue shedding litter. Initial legacy berry crops remain available;
spent crops no longer refill every real day.
Spring greens recruit and spread into moist (≥0.55), light ≥9 gaps in Spring.
Autumn mushrooms recruit and spread into moist (≥0.6), shaded (light ≤10) gaps in
@@ -231,14 +284,21 @@ revision IDs, biological rates, or undisclosed effect generation from tags.
### Implemented mechanics, not just catalogue descriptions
Calendar-v1 update: nitrogen eligibility below is now **90 calendar days**, not
the historical 900 loaded seconds, retaining the finite two-unit support cap.
New red clover, birdsfoot trefoil, gorse and broom share it. Their tags are not
independently reviewed species-rate measurements. Separately owned read-only
effect descriptions may still describe old acceleration; runtime policy here
and field-level lifecycle confidence labels take precedence.
| Species / relationship | Exact game effect | Evidence and limits |
| --- | --- | --- |
| Common alder (*Alnus glutinosa*), white clover (*Trifolium repens*) | After 900 warm active seconds, add at most one nutrient per eligible evaluation, never above local fertility four. **Two units total per supporting soil node**, recorded in `succ_fixed_nitrogen`, shared across species, recolonization and restart; soil's universal cap remains eight. Alder seedling, young and mature roots resolve through the same species ID; generated logs/leaves do not earn another contribution. | [Alder, Ecology](https://en.wikipedia.org/wiki/Alnus_glutinosa#Ecology) describes *Frankia* nodules and fertility; [white clover, Forage](https://en.wikipedia.org/wiki/Trifolium_repens#Forage) describes symbiotic fixation. The finite lifetime cap is game balance, not an annual nitrogen flux or physiological exhaustion claim. |
| Dog lichen (*Peltigera canina*) | Uses the same existing finite nitrogen budget, never a fertilizer item or independent annual allowance. The pre-existing lungwort-lichen nitrogen tag retains that shared policy; its species-effect evidence is not independently reviewed here. | [Dog lichen, Description](https://en.wikipedia.org/wiki/Peltigera_canina#Description) identifies *Nostoc*; [Peltigera, Description](https://en.wikipedia.org/wiki/Peltigera#Description) explains nitrogen fixation. Explicit species identity plus genus-level mechanism, not a measured species rate. |
| Blunt-leaved bog-moss (*Sphagnum palustre*) | A natural, active mat on loaded, permitted peat/alluvium at the sample's ground level adds **0.10 moisture** and subtracts **0.20 pH** from the local **land/bank habitat estimate**, capped at **two mats** (+0.20 / -0.40); moisture clamps to 0..1, pH to 3.5..8.5. This changes actual recruitment/stress niche tests. | [S. palustre](https://en.wikipedia.org/wiki/Sphagnum_palustre) describes water absorption; [Sphagnum](https://en.wikipedia.org/wiki/Sphagnum) explains water retention and acidification by cation exchange. Acidification evidence is genus-level. Coefficients are game approximations, not measured pH changes per plant. No permanent chemistry, peat creation, terrain conversion or global hydrology. |
| Common duckweed (*Lemna minor*) | Each natural active mat immediately above conserved source water at the sample's stand level reduces nearby **submerged freshwater** habitat light by **1.5**, capped at four mats / six light units. It never brightens a dark site, and never lowers light below two. Surface plants and terrestrial sites are not shaded by this rule. | [L. minor, Cultivation](https://en.wikipedia.org/wiki/Lemna_minor#Cultivation) describes floating carpets; [Lemnoideae, Duckweed in natural environments](https://en.wikipedia.org/wiki/Lemnoideae#Duckweed_in_natural_environments) describes shade. This is a local group-level shading approximation, not an algae, oxygen, contaminant-removal or nutrient-purification simulation. |
| Host-associated fungi, including fly agaric (*Amanita muscaria*) | An active compatible nearby fungus permits a tree seedling's young-stage transition at **16,200 rather than 21,600 active seconds**. Only a successful transition consumes **at most one existing soil nutrient**. Multiple fungi select the maximum allowance, not a sum; zero nutrients means no early growth. | [Fly agaric, Distribution and ecology](https://en.wikipedia.org/wiki/Amanita_muscaria#Distribution_and_ecology) describes ectomycorrhizal associations. Game host lists are narrower than the article. The existing growth debit is not nutrient creation, a full carbon-for-mineral ledger, or simulated water transfer. |
| Saprotrophic wood fungi, including birch polypore (*Fomitopsis betulina*) | On suitable natural deadwood/litter only, advance its existing decay age by at most **60 seconds per eligible evaluation**, capped at 7,200 / 1,800. The ordinary substrate transition consumes deadwood to litter to air, paying **three then one** soil nutrients once, subject to cap eight. Removing the support removes its natural fungal occupant. The fungus itself has no extra nutrient payout. Soil-growing saprotrophs receive no special nutrient effect. | [Birch polypore, Distribution, habitat and ecology](https://en.wikipedia.org/wiki/Fomitopsis_betulina) describes birch-specific brown rot. Existing host suitability remains authoritative. Natural parasitism on weakened living birches is **not simulated**. No attacks on living/player trees. |
| Host-associated fungi, including fly agaric (*Amanita muscaria*) | A compatible natural fungus can transfer/debit **at most one existing soil nutrient** when a tree independently reaches its calendar juvenile threshold. Multiple fungi select a maximum allowance, not a sum. There is **no time reduction**; the former 16,200/21,600-second boost is removed. | [Fly agaric ecology](https://en.wikipedia.org/wiki/Amanita_muscaria#Distribution_and_ecology) describes associations, not a measured growth acceleration. This is not nutrient creation or a full carbon/water ledger. |
| Saprotrophic wood fungi, including birch polypore (*Fomitopsis betulina*) | On suitable natural deadwood/litter only, advance its calendar decay bonus by at most **60 seconds per eligible evaluation**, capped at the one-year / 90-day substrate lifetime. The ordinary transition consumes deadwood to litter to air, paying **three then the unconsumed portion of one** soil nutrient once, subject to cap eight. Removing the support removes its natural fungal occupant. The fungus itself has no extra payout. Soil-growing saprotrophs receive no special nutrient effect. | [Birch polypore, Distribution, habitat and ecology](https://en.wikipedia.org/wiki/Fomitopsis_betulina) describes birch-specific brown rot. Host suitability remains authoritative. Natural parasitism on weakened living birches is **not simulated**. No attacks on living/player trees. |
The sampler collects `species_counts` (including canonical alder roots, moss and
duckweed) within its existing **5x5x5** stencil. Mat feedback uses only the
@@ -287,7 +347,8 @@ Lua tests, not a claim of full-engine or multiplayer validation.
Wildlife calls scan at most nine candidate sites and mutate at most one.
- Only `get_node_or_nil` reads are used. Missing/ignore nodes fail closed. There
is no emerge, force-load, mapgen edit, ABM, per-node timer or offline replay.
- Ages accrue from consecutive observations, not from absolute planting dates.
- Legacy active counters accrue from consecutive observations. Calendar plant
ages and organic decay use durable absolute anchors, not these counters.
First observation after restart, load, cache eviction, disconnect, clock rewind,
or a gap longer than 1,200 seconds only establishes a baseline. The load callback
invalidates observations when vegetation or its natural support reloads. A stalled
@@ -297,9 +358,10 @@ Lua tests, not a claim of full-engine or multiplayer validation.
next-attempt timestamp, natural-origin flag and attempt serial live in node
metadata; soil stores only its nutrient count. There is no global save schema.
Durable attempt timestamps/serials prevent repeated evaluation or rerolling
a blocked seed by reconnecting/restarting. Restarting pauses growth; it cannot
accelerate it. Ages are sampled approximations between visits, not per-tick
accounting; very busy/many-player worlds may deliberately progress more slowly.
a blocked seed by reconnecting/restarting. Restarting cannot accelerate or
reset birthdays, organic clocks or resource receipts. Calendar eligibility
survives absence; only bounded present work occurs on return. Legacy active
processes remain sampled approximations, not per-tick accounting.
- Source, destination and natural supports must all be unclaimed, externally
unprotected and free of placement metadata. All normal content placement marks
`player_placed=1`, including hand-placed soil/turf and soil left by crop harvest.
@@ -316,9 +378,52 @@ Lua tests, not a claim of full-engine or multiplayer validation.
`hearth.succession` is installed by the content registrar:
- `forage(pos) -> boolean`: consume exactly one nearby active natural
`meadow_grass`, `fern`, `clover`, `sedge` or `nettle` on safe natural support.
Does not eat dormant flora, flowers, crops or player plants.
- `forage(pos) -> boolean`: debit one partial canopy ration from one nearby
active natural browse plant on safe support. The plant remains rooted;
`succ_browse_ready_at = now + 7 days` is shared across animals and restarts.
Seven days is an unverified conservative game fallback, not measured biomass
recovery. No dormant flora, nonbrowse flowers, crops or player plants are eaten.
- `pollinate(pos) -> boolean`: exact source, not a new scan. Require botanical
active flowering (`B.pollinator`), known calendar maturity, natural root and
permitted loaded source/support. Atomically reserve
`succ_nectar_ready_at = now + 3600` before any effects. Competing bees share
this receipt. One non-additive boolean `succ_pollinated_until = now + 86400`
is written only when the old credit has expired; repeated visits do not stack
yield or extend the existing credit. One hour replenishment and one day credit
are game approximations, not measured species rates.
- `frugivore(pos, species_id?) -> boolean`: verify exact identity if supplied,
known mature shrub and actual botanical fruiting season. Consume one feeding
unit from the existing batch by spending the **whole two-fruit patch**; discard
the remainder rather than duplicate it. Reserve the human harvest field
`botany_ready_at = now + one mean year`; no items or animal-only fruit account.
- `granivore(pos, species_id?) -> boolean, optional_cache_id`: only mature
oak/hazel rooted trees (including adopted soil-level block roots), in Autumn
and their botanical seeding window. `succ_nuts_year` (UTC calendar year) and
`succ_nuts_remaining` persist a maximum two-nut current crop per root/year.
One nut funds a meal. If a second exists it is **separately debited** and the
second return is the plain species ID expected by wildlife. One remaining
nut returns `true, nil`; no old-year crop replay, reconnect refill or immature
root production. Two nuts is a coarse budget, not a measured yield.
- `disperse_seed(pos, species_id) -> boolean`: plain IDs alone confer no
authority. One in-memory handoff slot records the immediately preceding paid
granivore cache nut, with its source/species/UTC second. Any cache attempt
consumes the slot **before** destination checks; other mutating wildlife
hooks or another granivore call supersede it. Restart loses it, never refunds
nuts. Source identity/protection is rechecked; destination must be nearby
(within two horizontal nodes, same root height), loaded, permitted air on
viable natural support, with valid cooldown metadata. Existing establishment
preflight/niche rules apply. Success creates exactly one calendar-zero
same-species seedling and a one-day destination receipt. This matches the
synchronous squirrel caller; no opaque token or saved animal seed is required.
It is an internal trusted-call contract, not authentication against hostile
mods that can call hooks between them.
- `detritivore(pos) -> boolean`: exact natural litter source; consume 0.1 of
its normalized one-unit `succ_litter_remaining` mass and transfer exactly
0.1 existing mineral budget to permitted soil. At most ten meals per patch,
shared across restart. Keep the patch until the last unit; final removal
preflights any dependent fungus. Full soil refuses without spending material.
Ordinary decay returns only the remainder. No extra fertilizer aura, items
or renewal timer. Normalized units are game accounting, not measured digestion.
- `deposit(pos) -> boolean`: place exactly one dung nutrient patch in nearby
**air** over safe natural support. Never replaces existing plants or water.
Nutrients arrive through active decomposition, not immediately on deposit.
@@ -334,6 +439,31 @@ Callers supply animal ground-cover height (the air/plant cell above soil), not t
supporting soil or the animal's eye height. Calls return false when no safe target
exists. Habitat has no writes, timers or protection-violation reports.
### Integration handoff: botanical fruit effect remains separately owned
Current [botany.lua](../mods/hearth/botany.lua) human harvest still has a fixed
two-berry output and a one-day refill. This owned change does **not** pretend
that `succ_pollinated_until` already increases botanical fruit yield. The botany
owner must apply at most **one extra berry to an existing eligible fruit batch**
when its unexpired boolean credit is present, spend that credit with the shared
harvest transaction, and never give fruit merely for a pollen visit. It must also
replace daily human botanical refill with the next annual fruiting-season policy
and coordinate the same `botany_ready_at` lock used here. Animal fruit consumption
already uses a conservative one-year lock, but a human-first harvest still uses
the separately owned old daily policy until that integration lands. Flowering
may precede fruiting by months: the requested one-day credit is explicitly a
limited game approximation, not an annual pollination/fruit-set simulation.
Runtime signatures were checked against [wildlife.lua](../mods/hearth/wildlife.lua)
and [fauna.md](fauna.md): it consumes literal `true`, calls fruit/nut hooks with
the plain species ID, compares the optional cache return to that ID, and calls
dispersal synchronously only for oak/hazel squirrels. The older fauna contract's
one-day fruit deadline is superseded here by the conservative annual animal
receipt; its owner should align that documentation. No wildlife edits were made.
All resource failures leave node/resource metadata unchanged; paid cache authority
is the intentional exception, lost even on failed caching. No secrets, network
requests, serialization evaluation or cryptographic authorization were introduced.
## Assets and verification
### Exact registered node / art integration contract
@@ -368,9 +498,13 @@ explicit mesh tiles directly; it does not require `override_item` in engine mock
### Main-agent wiring and exact diversity interface
The blockshape change owns only diversity, content, biomes, their three focused
tests and this document. Succession, ecology, seasons, botany and generated assets
remain other owners' responsibility. Exact integrated order:
The calendar expansion owns only the six requested flora/ecology modules, their
six focused tests and the two botany/ecosystem documents. Bootstrap, lifecycle
policy, content, schema and generated assets remain other owners' responsibility.
Exact integrated order (main owns wiring):
0. Assign `hearth.lifecycle = dofile(modpath .. "/lifecycle.lua")` (plain namespace,
not a factory) **before** botany/content.
1. Create/install `hearth.seasons = dofile(modpath .. "/seasons.lua")(hearth, api)`.
2. Create/install `hearth.botany = dofile(modpath .. "/botany.lua")(hearth, api)`.
@@ -378,17 +512,18 @@ remain other owners' responsibility. Exact integrated order:
`hearth.diversity = dofile(modpath .. "/diversity.lua")(hearth, api)`.
This factory immediately extends `seasons.add_variants` with species policy.
4. Instantiate succession using its factory and assign `hearth.succession`.
5. After normal content, register/install biomes (ten species' logs/leaves/planks).
5. After normal content, register/install biomes (thirteen species' logs/leaves/planks).
6. Call `hearth.diversity.register_nodes(register_node)` with the bare-name wrapper:
30 species stage nodes, eight existing understory nodes and the bootstrap LBM.
7. Call `hearth.botany.register_nodes(register_node)`: exactly 62 new non-tree taxa,
with all explicit tiles and inventory/wield images preserved. The ten trees
39 species stage nodes, eight existing understory nodes and the bootstrap LBM.
7. Call `hearth.botany.register_nodes(register_node)`: exactly 79 new non-tree taxa,
with all explicit tiles and inventory/wield images preserved. The thirteen trees
and eight existing understory nodes are not registered twice.
8. Call `seasons.register()` after every canonical node, then instantiate wildlife.
The returned diversity table exposes:
- `species_order`, `plants`: ordered ten/eight canonical short names.
- `species_order`, `plants`: ordered thirteen/eight canonical short names (the
latter are legacy registrar-owned understory, not the whole botanical catalogue).
- `grounds`, `rocks`: exact short-name membership sets; `is_ground(node_or_name)`,
`is_rock(node_or_name)` and `supports_ground(kind, support)` are boolean policies.
- `tree_info(kind_or_node) -> species, stage`: two Lua return values, or nil;
@@ -409,7 +544,7 @@ The returned diversity table exposes:
### Geometry handoff to ecological growth
`diversity.tree_plan(species, stage?) -> plan | nil` is read-only. Species is one
of the ten IDs or `"generic"` for legacy trees; stage is `"young"` or `"mature"`
of the thirteen IDs or `"generic"` for legacy trees; stage is `"young"` or `"mature"`
(default mature). Invalid IDs/stages or missing biome integration return nil.
`plan` is a fresh dense array of `{x, y, z, name, param2}` records: integer offsets
@@ -445,7 +580,7 @@ No original 12-month climate calculation or preview-clock semantics changed.
### Exact species/understory art contract
For **all ten** species in `species_order`:
For **all thirteen** species in `species_order`:
- Seedlings use `hearth_botany_<species>.png` on a plantlike sprite. Young/mature
roots and species timber use `hearth_<species>_log_top.png` on both ends and
@@ -470,10 +605,10 @@ heather, bluebell, sedge and bulrush additionally use
has `_summer` and `_autumn` node variants using its same dormant texture.
Moss and lichen have no dormant art. No art is generated or modified here.
With all biome leaves installed, diversity adds **142 nodes**: 38 canonical nodes,
72 deciduous stage variants, 24 deciduous full-block leaf variants and eight
With all biome leaves installed, diversity adds **187 nodes**: 47 canonical nodes,
99 deciduous stage variants, 33 deciduous full-block leaf variants and eight
understory variants. Pine and spruce add no seasonal variants. Botany independently
adds 62 nodes. Species provenance on generic deadwood remains metadata.
adds 79 nodes. Species provenance on generic deadwood remains metadata.
The standalone succession fixture tests growth, niches, shade, competition,
seedlings, seeds, nutrient feedback, dung/fungi/decay, grazing, source/destination/
@@ -484,10 +619,10 @@ all four seasons, northern/southern calendars, seasonal foliage/restoration,
metadata/age conservation, forage cooldowns/restart, niches/occupation, protected
and unloaded no-write cases, target-volume clearance and the 96-swap bound.
The blockshape-focused standalone suites are diversity, biomes and content;
botany has its separate catalogue suite. They check exact ten-species ordering,
botany has its separate catalogue suite. They check exact thirteen-species ordering,
distinct mature schematics, bounded young canopies, shared rooted geometry,
metadata-safe deadwood migration, axe-only harvesting, all 78 unique recipes,
62 additional botany nodes and preserved aquatic icons/placement guards.
metadata-safe deadwood migration, axe-only harvesting, unique material recipes,
79 additional botany nodes and preserved aquatic icons/placement guards.
Engine visuals,
multiplayer ecology balance and long-session woodland density still require
in-engine playtesting; unit fixtures are not a performance benchmark.