# population.ron

> Where zombies live, respawn and migration toward noise.

<!-- Generated by `zombye-server --docs`. Do not edit: change the game and generate again. -->

**Where zombies live, respawn and migration toward noise.** Read by the game's rules: a change here changes how the game plays, and a world remembers the content it was made with.

File: `assets/data/population.ron`

## About this file

Zombie population: where they live, whether emptied places fill up again, and how loud events draw the far horde in. Schema: zombye_sim::population::PopulationDef (validated on load; every field is optional and defaults to the values below, which are the same as the built-in ones). All numbers are our own.


## Fields

The file is one `PopulationDef`.

The population data file (`assets/data/population.ron`). Every field has a default (the built-in values below), so a file only needs what it changes. Our own numbers.

| Field | Type | What it is |
|---|---|---|
| `density` | `ZoneDensity` | Zombies per km² of open ground (tiles not blocked by walls, trees or furniture) in each zone. The town generator decides the zones: indoors is any room; outdoors in town, the town core is the civic and commercial blocks along the main street (core_fraction of their length along the street, round the middle), the rest is streets (roads, parking lots and sidewalks) and yards; outside town, roads are forest roads and the rest is forest edge (within forest_edge_width metres of town) or deep forest. On the default 480 m map this comes to about 2,600 zombies; a bigger map adds forest, so mostly a sparse scattering. |
| `rooms` | `BTreeMap<String, f32>` | Multipliers on `density.indoors` by room type (`kitchen`, `bedroom`, ...); others 1. |
| `core_fraction` | `f32` | The town core is the civic and commercial blocks along the main street (the generator lays it out): this fraction of its length along the street, round its middle (1 = all of it). |
| `forest_edge_width` | `f32` | Forest within this many metres of the town is forest edge; beyond is deep forest. |
| `scale` | `f32` | Multiplies every density (a sandbox "population" setting). A zombie count given to the world (`--zombies N`) overrides the total instead, keeping the proportions. |
| `fast_share` | `f32` | Share of fast zombies, and walking speeds (m/s, uniform in the range) of fast and slow ones. |
| `fast_speed` | `(f32, f32)` |  |
| `slow_speed` | `(f32, f32)` |  |
| `groups` | `GroupDef` | They stand about in groups, not spread out evenly: each group's first is placed by density, the rest within `radius` metres of it (in the same building, or outdoors, and in sight of it). Group sizes are uniform in the range, in town and in the forest; `loners` of the groups are a single zombie. Wandering zombies drift back toward the ones round them now and then, so groups keep loosely together and stragglers wander off (ZombieTuning's herd_* numbers). |
| `respawn` | `RespawnDef` | Topping up emptied regions (64 m squares) far from everyone. Off by default. Every interval_secs, a region at least min_distance from every player, that nobody has been within seen_distance of for unseen_secs, and that holds fewer than top_up_below of its share, gets back up to its share (at most max_per_region at a time, max_per_check in all). Never in or right by the house the player wakes up in. |
| `migration` | `MigrationDef` | Migration toward noise. A sound at least min_radius loud (metres; breaking a door is 26, a shot will be more) leaves an attractor where it lures to. Its pull spreads outward at spread_speed m/s to reach_mult × the sound's radius (at most max_reach; from indoors only indoor_mult of that), fades out over life_secs (lasting_secs for the lasting kind: MCP make_noise with `lasting`, later alarms), and falls off toward the edge of its reach. Far (virtual) zombies wandering in a region that feels it set off for it a few at a time: each region update (every 5 s) with a chance of join_chance × the pull. They head for a point within gather_radius of it at investigating pace, so a big noise brings the horde in over minutes. A loud sound within merge_radius of an attractor strengthens that one instead; at most max_attractors at once (the weakest gives way). |
| `outfits` | `Vec<crate::corpses::Outfit>` | What zombies wear (`crate::corpses`): each zombie one of these, picked by weight from a hash of the seed and its id, and what a dead one's body gives when searched. Empty: they wear nothing. |

### `ZoneDensity`

Zombies per km² of open ground (tiles not blocked by walls, trees or furniture), per zone.

| Field | Type | What it is |
|---|---|---|
| `town_core` | `f32` |  |
| `street` | `f32` |  |
| `yard` | `f32` |  |
| `indoors` | `f32` |  |
| `forest_road` | `f32` |  |
| `forest_edge` | `f32` |  |
| `deep_forest` | `f32` |  |

### `GroupDef`

Zombies are placed in groups, not one by one: each group's first is placed by density, the rest round it within `radius` (same building, in sight of the first).

| Field | Type | What it is |
|---|---|---|
| `size` | `(u32, u32)` | Zombies in a group in town (uniform, inclusive), and in the forest. |
| `forest_size` | `(u32, u32)` |  |
| `radius` | `f32` | How far from the group's first the rest stand (metres). |
| `loners` | `f32` | Share of groups that are a single zombie. |

### `RespawnDef`

Topping up emptied regions far from everyone. Off by default.

| Field | Type | What it is |
|---|---|---|
| `enabled` | `bool` |  |
| `interval_secs` | `f32` | Seconds between checks. |
| `min_distance` | `f32` | Only regions whose nearest point is at least this far from every player (metres). |
| `seen_distance` | `f32` | A player within this distance of a region (its nearest point) has "seen" it... |
| `unseen_secs` | `f32` | ...and it isn't topped up until this many seconds after that. |
| `top_up_below` | `f32` | A region is topped up (back to its target) once it holds fewer than this fraction of it. |
| `max_per_region` | `u32` | At most this many new zombies per region per check, and in all per check. |
| `max_per_check` | `u32` |  |

### `MigrationDef`

Loud events drawing the far horde in over minutes.

| Field | Type | What it is |
|---|---|---|
| `enabled` | `bool` |  |
| `min_radius` | `f32` | Sounds at least this loud (radius, metres) leave an attractor. |
| `reach_mult` | `f32` | An attractor pulls from this many times the sound's radius... |
| `max_reach` | `f32` | ...but never more than this (metres). |
| `indoor_mult` | `f32` | A sound made indoors (or heard from a room) pulls from only this fraction of that. |
| `life_secs` | `f32` | Seconds an attractor lasts (its pull fades to nothing over this time), and how long the lasting kind (MCP `make_noise` with `lasting`; later alarms, a helicopter) does. |
| `lasting_secs` | `f32` |  |
| `spread_speed` | `f32` | Metres per second the pull spreads outward from the attractor. |
| `join_chance` | `f32` | Chance per region update (every few seconds) that a wandering virtual zombie feeling the full pull sets off; scaled by the pull it feels (0..1). |
| `gather_radius` | `f32` | Migrants head for a point within this distance of the attractor (so they don't all pile onto one tile). |
| `merge_radius` | `f32` | A loud sound this close to an existing attractor strengthens that one instead. |
| `max_attractors` | `u32` | Attractors kept at once (the weakest gives way). |

### `Outfit`

One outfit a zombie may wear: item ids (clothing, as `items.ron` has them), and how likely it is against the others.

| Field | Type | What it is |
|---|---|---|
| `wears` | `Vec<String>` |  |
| `weight` | `f32` |  |

## The file

<details>
<summary>The whole file as shipped</summary>

```ron
// Zombie population: where they live, whether emptied places fill up again, and how loud events
// draw the far horde in. Schema: zombye_sim::population::PopulationDef (validated on load; every
// field is optional and defaults to the values below, which are the same as the built-in ones).
// All numbers are our own.
(
    // Zombies per km² of open ground (tiles not blocked by walls, trees or furniture) in each zone.
    // The town generator decides the zones: indoors is any room; outdoors in town, the town core is
    // the civic and commercial blocks along the main street (core_fraction of their length along the
    // street, round the middle), the rest is streets (roads, parking lots and sidewalks) and yards; outside town, roads
    // are forest roads and the rest is forest edge (within forest_edge_width metres of town) or deep
    // forest. On the default 480 m map this comes to about 2,600 zombies; a bigger map adds forest, so
    // mostly a sparse scattering.
    density: (
        town_core: 40000.0,
        street: 32000.0,
        yard: 19000.0,
        indoors: 10000.0,
        forest_road: 7000.0,
        forest_edge: 2600.0,
        deep_forest: 650.0,
    ),
    // Multipliers on `indoors` by room type (others 1): kitchens and living rooms fill up, the small
    // rooms less so.
    rooms: {
        "kitchen": 1.3,
        "living": 1.3,
        "dining": 1.1,
        "hall": 1.0,
        "bedroom": 0.8,
        "bathroom": 0.6,
        "laundry": 0.7,
    },
    core_fraction: 1.0,
    forest_edge_width: 60.0,
    // Multiplies every density (a sandbox "population" setting). `--zombies N` sets the total
    // instead, keeping the proportions.
    scale: 1.0,
    // One in ten is fast. Speeds in m/s, uniform in the range.
    fast_share: 0.1,
    fast_speed: (2.0, 3.0),
    slow_speed: (0.6, 1.1),
    // They stand about in groups, not spread out evenly: each group's first is placed by density,
    // the rest within `radius` metres of it (in the same building, or outdoors, and in sight of it).
    // Group sizes are uniform in the range, in town and in the forest; `loners` of the groups are
    // a single zombie. Wandering zombies drift back toward the ones round them now and then, so
    // groups keep loosely together and stragglers wander off (ZombieTuning's herd_* numbers).
    groups: (
        size: (2, 6),
        forest_size: (1, 3),
        radius: 8.0,
        loners: 0.35,
    ),

    // Topping up emptied regions (64 m squares) far from everyone. Off by default. Every
    // interval_secs, a region at least min_distance from every player, that nobody has been within
    // seen_distance of for unseen_secs, and that holds fewer than top_up_below of its share, gets
    // back up to its share (at most max_per_region at a time, max_per_check in all). Never in or
    // right by the house the player wakes up in.
    respawn: (
        enabled: false,
        interval_secs: 120.0,
        min_distance: 250.0,
        seen_distance: 100.0,
        unseen_secs: 1800.0,
        top_up_below: 0.75,
        max_per_region: 6,
        max_per_check: 60,
    ),

    // Migration toward noise. A sound at least min_radius loud (metres; breaking a door is 26, a
    // shot will be more) leaves an attractor where it lures to. Its pull spreads outward at
    // spread_speed m/s to reach_mult × the sound's radius (at most max_reach; from indoors only
    // indoor_mult of that), fades out over life_secs (lasting_secs for the lasting kind: MCP
    // make_noise with `lasting`, later alarms), and falls off toward the edge of its reach. Far
    // (virtual) zombies wandering in a region that feels it set off for it a few at a time: each
    // region update (every 5 s) with a chance of join_chance × the pull. They head for a point
    // within gather_radius of it at investigating pace, so a big noise brings the horde in over
    // minutes. A loud sound within merge_radius of an attractor strengthens that one instead; at
    // most max_attractors at once (the weakest gives way).
    migration: (
        enabled: true,
        min_radius: 25.0,
        reach_mult: 4.0,
        max_reach: 700.0,
        indoor_mult: 0.6,
        life_secs: 600.0,
        lasting_secs: 1800.0,
        spread_speed: 3.0,
        join_chance: 0.5,
        gather_radius: 12.0,
        merge_radius: 24.0,
        max_attractors: 16,
    ),

    // What zombies wear: each zombie one of these (by weight, from a hash of the seed and its id).
    // Item ids from items.ron; what a dead one wears is on its body to take (searched with E). The
    // client draws the baked crowd variant nearest to it (zombie_NN_<item ids>.zvat).
    outfits: [
        (wears: ["t_shirt", "jeans", "trainers"], weight: 3.0),
        (wears: ["hoodie", "jeans", "trainers", "baseball_cap"], weight: 2.0),
        (wears: ["leather_jacket", "jeans", "work_boots"], weight: 1.0),
        (wears: ["jumper", "jeans", "work_boots", "woolly_hat"], weight: 1.5),
        (wears: ["t_shirt", "jeans", "work_boots"], weight: 2.0),
        (wears: ["jeans", "trainers"], weight: 1.0),
    ],
)
```

</details>