40 — Property plots & player farming
Status: Design (roadmap). Not implemented.
Related: 37 — Economic map zones, 38 — Biomes & cultivate, 23 — Harvest, 13 — Workers, 20 — Buildings, 08 — Banks.
1. Summary
Players buy plots of land only inside property zones. A plot is a fraction of a zone’s footprint — not the whole crown parcel, and not arbitrary wilderness. Ownership unlocks cultivate / farm, later build and bank hooks, and a share of tax collected on that land when it overlaps a tax zone.
First playable vertical: farming. Cultivate owned cells → plant seeds → crops grow through gfx stages → harvest like a resource node (produce + chance of more seeds) → replant quickly.
Whole-zone crown buy/sell already exists as a thin slice (37 §5); this plan supersedes that UX with fractional plots while keeping zone YAML as the crown catalog of where land can be claimed.
2. Design principles
| Principle | Meaning |
|---|---|
| Property zones only | No purchase outside a property_zone. Wild / road / biome land stays crown or public |
| Fractional claims | Buy a sub-rect (cell grid) inside a zone; pay proportional purchase + upkeep |
| Tax-aware pricing | Period cost scales with zone upkeep and local tax pressure |
| Own → act | Farm / build / tax share require ownership of the cells you act on |
| Harvest parity | Mature crops are harvestable like resource nodes (23) |
| Growth presentation | Crop sprites use optional stage modes (grow_10 … grow_100) |
| Layer multipliers | Growth speed = base × fertility × biome × weather (37, 38) |
3. What can be bought
World cell (x,y)
└─ inside property_zone Z? → claimable (if free / seller)
└─ else → not for sale
- Not every tile in Flatland — only cells covered by a property overlay.
- One property zone may host many plots owned by different players (and leftover crown remainder).
- Plots must stay axis-aligned cell rects on the plant/claim grid (same meter grid as movement).
- Reject claims that overlap another plot, leave slivers under a min size, or exceed zone
max_area_m2for a single claim (settings).
3.1 Plot record (runtime)
PropertyPlot {
plot_id,
segment_id,
property_zone_id, // crown terms come from zone YAML
owner_character_id,
rect: { x0, y0, x1, y1 }, // inclusive cell bounds or half-open — pick one in impl
purchased_at_tick / day,
upkeep_arrears_days,
}
Persist with world / character economy state (worker checkpoint + control-plane as for 37 ownership). Whole-zone property_ownership map becomes derived or migrated to plot set.
4. Purchase price & period cost
Zone YAML still defines crown terms (37):
| Zone field | Role |
|---|---|
crown_price_copper |
Base price for entire zone area |
upkeep_copper_per_day |
Base daily upkeep for entire zone |
upkeep_grace_days |
Grace before reclaim |
owner_tax_discount_bps |
Discount when paying tax on owned land |
For a plot of area A inside zone of area Z:
area_frac = A / Z
purchase = ceil(crown_price_copper * area_frac * tax_premium)
upkeep_day = max(1, ceil(upkeep_copper_per_day * area_frac * tax_premium))
4.1 Tax premium (period cost ↔ tax rate)
If the plot overlaps a tax zone, apply a premium so busy / high-tax land costs more to hold:
tax_premium = 1 + (rate_bps / 10000) * tax_premium_weight
# tax_premium_weight from server-settings (e.g. 0.5 → 5% tax ⇒ +2.5% price/upkeep)
Use the highest overlapping tax zone’s rate_bps (same z_order rule as tax sampling). Flat copper tax does not enter the premium (keep it simple).
Optional later: flat_copper adds a small daily surcharge per plot.
4.2 Buy / sell / reclaim
| Action | Behavior |
|---|---|
| Buy from crown | Player stands in/near free cells inside zone; selects rect or brush size; pays purchase; plot recorded |
| Sell to crown | Owner sells plot back at property_sellback_bps of that plot’s purchase basis (or current crown pro-rata — settings) |
| Player → player | Deferred (trade deed item) — not required for v1 |
| Upkeep | Each game day: charge upkeep_day; soft then grace → reclaim plot (crops may wither — settings) |
| Reclaim | Plot returns to crown free pool; cultivated/crop state cleared or frozen for loot window |
4.3 Tax share (owner benefit)
When a harvest (or later activity) pays tax inside a tax zone and the taxed cell lies on an owned plot:
owner_share = floor(tax_collected * owner_tax_share_bps / 10000)
crown_keep = tax_collected - owner_share
Credit owner_share to the plot owner’s copper (ledger: Taxes / Rent). Discount (37 §4.2) still applies to the harvester’s bill when they own the land.
5. Ownership unlocks (phased)
| Unlock | Phase | Notes |
|---|---|---|
| Cultivate + farm | v1 (this plan) | Fun first loop |
| Tax share | v1 | Soft copper sink redistributed |
| Build / place schematics | later (20) | Must be on owned cells |
| Banks / housing storage | after banks (08) | Key chests to plot |
| Worker farm jobs | with 13 | Cultivate / plant / harvest routes |
6. Farming vertical (v1)
6.1 Flow
Own plot cells
→ Cultivate (timed; workers optional) → tilled cells
→ Acquire seeds (loot / vendor / prior harvest)
→ Plant seed type + quantity into free tilled slots
→ Grow over time (sprite stages)
→ At 100%: Harvest (same channel as resource nodes)
→ Yield: crop item (e.g. potatoes) + chance of extra seeds
→ Replant quickly
6.2 Cultivate
- Only on owned plot cells.
- Prefer cells inside a growth zone (37 / 38 cultivate gate):
require_growth_zone+allowed_kinds/allowed_biomes. - Timed channel (player and/or worker). Writes tilled / farm terrain delta (reuse cultivate transitions from 38).
- Cultivated cells stay owned; losing the plot clears them.
6.3 Plant grid & capacity
Planting uses a coarse grid over cultivated land (settings), e.g. 1 seed slot per 1×1 m or per 2×2 m cell:
max_slots = floor(cultivated_area_m2 / plant_slot_m2)
used_slots = count(active crop instances on plot)
free_slots = max_slots - used_slots
Player UX:
- Choose seed type (inventory template with
seed_for: potato/crop_tags). - Enter quantity (cap =
min(stack, free_slots)). - Confirm → seeds consume; crop instances spawn on free slots (nearest empty tilled cells / auto-fill).
6.4 Crop instance
CropInstance {
id,
plot_id,
cell: (x, y),
crop_id, // catalog: potato, carrot, …
planted_at_tick,
growth_progress: 0.0..1.0,
sprite_mode, // grow_10 | grow_20 | grow_60 | grow_100
}
6.5 Growth rate
base_ticks_to_mature = crop.def.grow_ticks
fertility = growth_zone_at(cell).fertility or 1.0
biome_mult = biome catalog grow_mult (default 1.0)
weather_mult = regional weather (default 1.0 until weather ships)
progress_per_tick = 1.0 / (base_ticks_to_mature / fertility / biome_mult * weather_mult)
Clamp fertility via existing economy_zones settings. Weather stub stays 1.0 until weather lands — same pattern as 37.
6.6 Sprite growth modes
Presentation / resource catalog for each crop tile id exposes optional modes:
| Mode | Progress band |
|---|---|
grow_10 |
0% – <20% |
grow_20 |
20% – <60% |
grow_60 |
60% – <100% |
grow_100 |
100% (harvestable) |
Gfx already selects sprite_mode on resource nodes; crops reuse that path. Missing modes fall back to nearest lower stage or default tile.
6.7 Harvest
At grow_100, crop is a harvestable resource (23):
- Same interact / channel / cancel-on-move rules.
- Yield table on crop def, e.g. potatoes
quantity_min/max+seed_drop_chance/seed_quantity. - After harvest: cell returns to tilled empty (ready to replant); no long wild respawn unless configured.
6.8 Seeds & crop catalog (content)
# illustrative
items:
- id: potato_seed
tags: [seed, potato]
seed_for: potato_crop
- id: potato
tags: [food, vegetable, potato]
crops:
- id: potato_crop
seed_item: potato_seed
grow_ticks: 18000 # ~10 min at 30 Hz — tune in content
crop_tags: [potato, vegetable]
harvest:
item: potato
quantity_min: 2
quantity_max: 5
seed_item: potato_seed
seed_chance_bps: 6000 # 60%
seed_quantity_min: 1
seed_quantity_max: 2
presentation_tile: crop.potato
Vendors / world loot can sell or drop seeds; first loop may seed Ada / farm NPC with a small seed stock.
6.9 Workers
Optional v1.5: hire worker job cultivate / plant / harvest_crops on employer plots (13). Not required to ship solo farming.
7. Client / UX sketch
| Surface | Behavior |
|---|---|
| Gfx map | Owned plot outline; tilled tint; crop sprites by grow_* mode |
| Buy plot | Enter claim mode on free property cells → drag rect → cost preview (purchase + daily upkeep) → confirm |
| Farm | Cultivate intent on owned cells; plant panel: seed type + quantity |
| CLI / agent | flatland plot buy …, plot list, farm cultivate, farm plant <seed> --qty N, harvest via existing interact |
Dashboard (04 §4.8) may list plots / upkeep later.
8. Settings knobs
property_plots:
plant_slot_m2: 1.0
min_plot_area_m2: 4.0
tax_premium_weight: 0.5
owner_tax_share_bps: 2500 # 25% of tax collected on owned cells
sellback_bps: 5000
claim_must_be_in_growth_to_farm: true
farming:
default_weather_mult: 1.0
wither_on_reclaim: true
9. Implementation phasing
| Phase | Scope |
|---|---|
| P0 | Plot claim/buy/sell/upkeep/reclaim inside property zones; fractional pricing + tax premium; map outline |
| P1 | Cultivate owned cells (growth-zone gate); tilled state |
| P2 | Seeds, plant slots, crop growth + grow_* sprites, harvest yields |
| P3 | Tax share to owners; seed vendor; worker farm jobs |
| P4 | Build-on-plot gates; bank/housing hooks |
Ordering vs other Tier 4 work: after banks (4.13) preferred for clean copper/upkeep; can start P0 in parallel with ability (4.14). Biomes/weather improve P2 multipliers but are not blockers (stubs = 1.0).
10. Exit criteria (farming vertical)
- Player buys a partial plot inside a property zone; cannot buy outside zones
- Daily upkeep scales with plot area (+ tax premium when taxed)
- Cultivate → plant N seeds capped by cultivated area → see
grow_10…grow_100 - Harvest mature crop grants produce + occasional seeds; replant works
- Growth faster in higher fertility growth zones (biome/weather mults when present)
11. Non-goals (this plan)
- Buying land outside property zones
- Stock-market land speculation / auctions
- Full greenhouse / multi-story farms
- Particle “growth VFX” beyond sprite modes
- Replacing wild resource nodes (carrots on roads stay 23 / growth-zone respawn)
12. Open questions
| # | Question | Lean |
|---|---|---|
| F1 | Cell grid: 1 m vs 2 m plant slots? | 1 m for starter; settings |
| F2 | Can you cultivate owned land outside a growth zone? | No for v1 (claim_must_be_in_growth_to_farm) |
| F3 | Whole-zone buy API — keep as shortcut for “claim entire free zone”? | Yes, as “select all free cells” |
| F4 | Tax share when harvester is the owner? | Share still posts; net ≈ discount + share (tune bps) |