Skip to content

Farming #62

@dmccoystephenson

Description

@dmccoystephenson

Summary

Allow the player to plant seeds in the world, tend growing crops, and harvest food from fully grown plants.

Background

Currently the only way for the player to obtain food is to gather it from pre-spawned world entities (apples from oak trees, bananas from jungle trees). Farming gives the player a renewable food source they can cultivate. The implementation should follow existing entity and interaction patterns: seeds and crops are placeable DrawableEntity subclasses, growth is driven by TickCounter, and harvesting reuses the existing left-click gather action in WorldScreen. Note: if PR #344 is merged before this, any new logging should use getLogger from src/gameLogging/logger.py.

Requirements

New Entities

  • src/entity/wheatSeed.pyWheatSeed, solid=False, not a food item, placeholder asset assets/images/wheatSeed.png
  • src/entity/youngCrop.pyYoungCrop, solid=False, stores tickPlanted, placeholder asset assets/images/youngCrop.png
  • src/entity/matureCrop.pyMatureCrop, solid=False, stores tickPlanted, placeholder asset assets/images/matureCrop.png
  • src/entity/wheat.pyWheat(Food), solid=False, energy 10–20, placeholder asset assets/images/wheat.png

Growth Config

  • Add cropGrowthTicks integer to config.yml (default 1800 — 1 minute per stage at 30 tps) and load it in Config (src/config/config.py)
  • Growth proceeds in two stages: YoungCropMatureCrop after cropGrowthTicks ticks, then MatureCrop → harvestable (signals readiness; harvesting converts it to Wheat in the player's inventory)

Growth Logic

  • Add a tickCrops(tick, config) method to Room (src/world/room.py), following the same pattern as tickExcrement()
  • Each tick, iterate all locations; for any YoungCrop or MatureCrop whose tick - tickPlanted >= cropGrowthTicks, replace it with the next stage entity
  • Call tickCrops from the world screen tick loop in WorldScreen alongside tickExcrement

Planting

  • WheatSeed must be added to the crafting registry (src/crafting/recipeRegistry.py) — e.g. 1× Grass → 3× WheatSeed — so the player has a reliable way to obtain seeds
  • Planting uses the existing right-click place action (executePlaceAction() in worldScreen.py): when the selected hotbar item is a WheatSeed and the target location contains Grass but no solid entity, remove the Grass, consume the seed from inventory, and place a YoungCrop with tickPlanted = tickCounter.getTick()
  • If the target location does not contain Grass, set a status message via status.set("Must plant on grass") and consume no items

Harvesting

  • When the player left-clicks (executeGatherAction()) on a MatureCrop, remove it from the room, add a Wheat entity to the player's inventory via placeIntoFirstAvailableInventorySlot, and set status "Harvested Wheat"
  • YoungCrop cannot be harvested — clicking it sets status "Crop is not ready"
  • Add WheatSeed, YoungCrop, MatureCrop, and Wheat to canBePickedUp() in worldScreen.py (seeds and young crops can be picked back up to replant or cancel; mature crops are harvested only)

Persistence

  • Add all four new entity types to the entity registries in roomJsonReaderWriter.py and inventoryJsonReaderWriter.py, following the existing registry pattern
  • YoungCrop and MatureCrop must persist tickPlanted so growth state survives save/load, following the same pattern as Excrement.tickCreated
  • Update schemas/room.json if any new required fields are added to entity JSON

README

  • Add farming controls to the Controls table in README.md (right-click to plant seed, left-click to harvest mature crop)

Acceptance Criteria

  • WheatSeed can be crafted from Grass and placed on grass tiles via right-click
  • Planted seeds progress through YoungCropMatureCrop over two cropGrowthTicks intervals
  • Left-clicking a MatureCrop adds Wheat (food) to the player's inventory
  • Left-clicking a YoungCrop shows "Crop is not ready" and does nothing
  • Planting on a non-grass location shows "Must plant on grass" and consumes no items
  • Crop growth state (stage and tickPlanted) is preserved across save/load cycles
  • All four entity types are handled in both roomJsonReaderWriter.py and inventoryJsonReaderWriter.py
  • All existing tests pass; new tests cover growth stage transitions, planting validation, harvest behaviour, and save/load round-trip for YoungCrop and MatureCrop

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions