Class Hierarchy
How the 20 housing tier classes are organised, what the base class owns, and what lives in runtime_data_t.
Hierarchy
building_impl (src/building/building_impl.h)
└─ building_house (src/building/building_house.h)
├─ building_house_crude_hut tier 1
├─ building_house_sturdy_hut tier 2
├─ building_house_meager_shanty tier 3
├─ building_house_common_shanty tier 4
├─ building_house_rough_cottage tier 5
├─ building_house_ordinary_cottage tier 6
├─ building_house_modest_homestead tier 7
├─ building_house_spacious_homestead tier 8
├─ building_house_modest_apartment tier 9
├─ building_house_spacious_apartment tier 10
├─ building_house_common_residence tier 11 ← labor stops here
├─ building_house_spacious_residence tier 12
├─ building_house_elegant_residence tier 13
├─ building_house_fancy_residence tier 14
├─ building_house_common_manor tier 15 ← 3×3 footprint
├─ building_house_spacious_manor tier 16
├─ building_house_elegant_manor tier 17
├─ building_house_stately_manor tier 18
├─ building_house_modest_estate tier 19 ← 4×4 footprint
└─ building_house_palatial_estate tier 20
Base Class — building_house
The base class owns the shared interface and helpers used by all tier classes. It does not implement evolution itself — that is delegated to each tier via the virtual evolve() method.
| Method | Description |
|---|---|
virtual evolve(house_demands*) | Called monthly. Checks merge eligibility, runs requirements check, applies tier change. Each of the 20 tier classes overrides this. |
check_requirements(house_demands*) | Returns e_house_progress (EVOLVE / NONE / DECAY). Compares current service state against model thresholds. |
has_required_goods_and_services(int for_upgrade, house_demands*) | Validates water, food, entertainment, education, religion, health, and all goods (pottery / beer / linen / jewelry). Sets demand flags for any unmet requirement. |
check_evolve_desirability() | Reads desirability from the grid, compares to model.evolve_desirability and model.devolve_desirability. |
merge() / merge_impl() | Attempts to merge a 1×1 plot into a 2×2 block with three adjacent matching tiles. Returns true if merge succeeded. |
split(int new_type) | Undoes a merge, placing four 1×1 plots in place of one large footprint. |
decay_services() | Called monthly. Decrements all service counters so that coverage must be renewed each month. |
consume_food_weekly() / consume_goods_weekly() | Deducts food and goods from runtime_data.foods[] and runtime_data.inventory[]. |
dcast_house() | Convenience downcast shorthand (see Downcasting). |
runtime_data_t
Each house instance carries a 186-byte runtime_data_t buffer (enforced by static_assert). All fields are declared in building_house.h.
Population & food
| Field | Type | Meaning |
|---|---|---|
population | u16 | Current occupants. |
highest_population | u16 | Peak population recorded (used for prosperity score). |
days_without_food | u8 | Counter incremented each week food is absent. Triggers devolution after model.days_without_food_devolve_threshold. |
foods[8] | u8[] | Stock of each food type delivered by the bazaar. |
inventory[8] | u8[] | Stock of manufactured goods (pottery, beer, linen, jewelry). |
hsize | u8 | Tile width: 1, 2, 3, or 4. |
is_merged | bool | True when four 1×1 plots have merged into one block. |
Service flags (set by walkers each month)
| Field | Source figure |
|---|---|
bazaar_access | Bazaar buyer |
fancy_bazaar_access | Bazaar buyer (high-tier route) |
school | Scribal School teacher |
library | Library librarian |
academy | Academy teacher |
physician | Physician |
dentist | Dentist |
apothecary | Apothecary |
mortuary | Mortuary embalmer |
magistrate | Courthouse magistrate |
shrine_access | Shrine proximity |
booth_juggler | Juggler booth entertainer |
bandstand_juggler / bandstand_musician | Bandstand walkers |
pavillion_musician / pavillion_dancer | Pavilion walkers |
senet_player | Senet house player |
bullfighter | Bull pen fighter |
Aggregated service scores (computed monthly)
| Field | Range | Computed from |
|---|---|---|
entertainment | 0–100 | Weighted sum of juggler / musician / dancer / senet coverage; see Service Coverage. |
education | 0–3 | school=1, school+library=2, school+library+academy=3. |
health | 0–2 | +1 apothecary, +1 physician. |
num_gods | 0–5 | Count of distinct gods with temple walker coverage. Shrine counts as 1 if no temple present. |
water_supply | 0–2 | 0=none, 1=well, 2=water supply building. |
Tax & economy
| Field | Meaning |
|---|---|
tax_collector_id | ID of the tax collector figure last visiting this house. |
tax_income_or_storage | Accumulated tax since last collection. |
tax_coverage | Boolean — whether a tax collector reached this house this year. |
Devolution & stability
| Field | Meaning |
|---|---|
devolve_delay | Countdown before a triggered devolution is actually applied. Prevents single-tick fluctuations from instantly downgrading a house. |
unreachable_ticks | Incremented each tick that no road-walker can reach the house. Triggers devolution at model.unreachable_ticks_devolve_threshold. |
no_space_to_expand | Set when merge or size-upgrade is blocked by adjacent obstacles. |
house_happiness | General satisfaction score used for crime and prosperity calculations. |
criminal_active | Flag set when a criminal has spawned from this house. |
Tier Classes
Each of the 20 tier classes follows the same pattern:
// building_house.h
struct building_house_ordinary_cottage : building_house {
BUILDING_METAINFO(BUILDING_HOUSE_ORDINARY_COTTAGE,
building_house_ordinary_cottage,
building_house)
virtual void evolve(house_demands* demands) override;
// inherits all other methods from building_house
};
The BUILDING_METAINFO macro handles factory registration, type-safe casting, and static param lookup. Beyond evolve(), most tier classes add no new methods — all variation is driven by the model thresholds loaded from config.
Downcasting
Use dcast<T>() or the convenience shorthand. Never use static_cast.
building* b = ...;
// check and downcast to any housing tier
building_house* h = b->dcast_house(); // nullptr if not a house
// downcast to a specific tier
auto* hut = b->dcast<building_house_crude_hut>(); // nullptr if wrong tier
// safe pattern in an update loop
if (auto* house = b->dcast_house()) {
// safe to call any building_house method
house->decay_services();
}