feat: Add farming system — planting, crop growth, and harvesting#348
Conversation
…tities with planting, growth, and harvesting Agent-Logs-Url: https://github.com/Preponderous-Software/roam/sessions/5179343d-6ba3-4b52-a04a-410ce8f30a1b Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a farming loop (seed crafting → planting → time-based crop growth → harvesting) to provide a renewable food source, integrated into ticking, persistence, UI actions, and tests.
Changes:
- Introduces WheatSeed / YoungCrop / MatureCrop / Wheat entities plus placeholder sprites.
- Adds crop growth ticking (
Room.tickCrops) and world interactions for planting/harvesting inWorldScreen. - Extends crafting to support multi-item outputs via
Recipe.resultCountand updates persistence + tests.
Reviewed changes
Copilot reviewed 22 out of 26 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/world/test_roomJsonReaderWriter.py | Expands room JSON coverage for wheat/crops + tickPlanted round-trips |
| tests/world/test_cropGrowth.py | New unit tests for Room.tickCrops() growth transitions |
| tests/entity/test_youngCrop.py | New tests for YoungCrop defaults + tickPlanted accessors |
| tests/entity/test_wheatSeed.py | New tests for WheatSeed defaults |
| tests/entity/test_wheat.py | New tests for Wheat defaults + energy range |
| tests/entity/test_matureCrop.py | New tests for MatureCrop defaults + tickPlanted accessors |
| tests/crafting/test_wheatSeedRecipe.py | New test asserting Grass → WheatSeed×3 recipe exists |
| tests/crafting/test_recipe.py | Updates to expect Recipe.craft() returns a list |
| src/world/roomJsonReaderWriter.py | Registers wheat/crops for room (de)serialization + tickPlanted |
| src/world/room.py | Adds tickCrops() to mature crops over time |
| src/screen/worldScreen.py | Adds planting/harvesting behaviors; calls crop ticking in main loop |
| src/screen/inventoryScreen.py | Updates crafting flow to handle list results |
| src/inventory/inventoryJsonReaderWriter.py | Adds wheat/crops to inventory (de)serialization + tickPlanted |
| src/entity/youngCrop.py | New YoungCrop entity (non-solid, tickPlanted) |
| src/entity/wheatSeed.py | New WheatSeed entity (non-solid) |
| src/entity/wheat.py | New Wheat food entity (energy 10–20) |
| src/entity/matureCrop.py | New MatureCrop entity (non-solid, tickPlanted) |
| src/crafting/recipeRegistry.py | Adds Wheat Seed recipe (Grass → WheatSeed×3) |
| src/crafting/recipe.py | Adds resultCount; craft() now returns a list of results |
| src/config/config.py | Adds cropGrowthTicks config option (default 1800) |
| assets/images/youngCrop.png | New sprite placeholder |
| assets/images/wheatSeed.png | New sprite placeholder |
| assets/images/wheat.png | New sprite placeholder |
| assets/images/matureCrop.png | New sprite placeholder |
| README.md | Documents new planting/harvesting controls |
| CHANGELOG.md | Documents feature and adds learning-log notes |
| @@ -738,6 +766,34 @@ def executePlaceAction(self): | |||
| if inventorySlot.isEmpty(): | |||
| self.status.set("Select an item first (1-0)") | |||
There was a problem hiding this comment.
executePlaceAction() deducts interaction energy before verifying that a selected WheatSeed can actually be planted (and before other early-return validations like an empty slot). With the new seed-planting branch, a failed plant attempt (e.g., not on grass) still costs energy. Move the energy deduction to after all validations succeed (or refund on failure) so unsuccessful actions don’t drain energy.
| if not self.inventory.hasAvailableSlotFor(recipe.getResultClass()): | ||
| self.status.set("Inventory full") | ||
| return |
There was a problem hiding this comment.
craftRecipe() only checks hasAvailableSlotFor(recipe.getResultClass()), which is insufficient now that Recipe.craft() can return multiple items via resultCount. This can allow crafting to proceed when there isn’t enough total capacity for all results, leading to partial placement and/or item loss after ingredients are consumed. Consider adding an inventory-capacity check that accounts for recipe.getResultCount() (including stacking space) before calling craft().
|
@copilot You are a coding agent tasked with resolving all open comments and review threads Instructions1. Discover all comments
2. For each comment, do the following:
3. Types of issues to handle:
4. Do NOT:
After making changes
Context
|
…gy/inventory issues in crafting and planting Agent-Logs-Url: https://github.com/Preponderous-Software/roam/sessions/78cbe4e0-050b-43d3-b2b7-68e529faf105 Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
All four review threads addressed in a518d48:
|
|
@copilot Prevent placing crops in locations that already have a crop present |
Agent-Logs-Url: https://github.com/Preponderous-Software/roam/sessions/240f7ae3-2784-4c36-afe8-b43cbb11e673 Co-authored-by: dmccoystephenson <21204351+dmccoystephenson@users.noreply.github.com>
Added in 58100b0. The planting logic in |
Adds a renewable food source via farming. Players craft wheat seeds from grass, plant them on grass tiles, wait for two growth stages driven by
TickCounter, and harvest mature crops for wheat (food).New entities
WheatSeed— craftable, plantable, non-solidYoungCrop/MatureCrop— non-solid, storetickPlantedfor growth trackingWheat(Food)— energy 10–20, harvested from mature cropsGrowth
Room.tickCrops(tick, config)— mirrorstickExcrementpattern. YoungCrop → MatureCrop aftercropGrowthTicksticks (default 1800 ≈ 1 min at 30 tps). MatureCrop waits for player harvest.cropGrowthTicksadded toConfigPlanting & harvesting (
worldScreen.py)executePlaceAction: WheatSeed on grass → remove grass, consume seed, place YoungCrop. Non-grass → "Must plant on grass". Locations that already contain a crop are blocked with "A crop is already growing here".executeGatherAction: MatureCrop → remove, add Wheat to inventory. YoungCrop → "Crop is not ready".Wheatis registered in the Player'sedibleEntityTypesso harvested wheat is consumable.Crafting
RecipegainsresultCountparam;craft()now returns a list:craftRecipe()pre-validates inventory capacity for allresultCountitems (including stacking space) before consuming ingredients, and handles placement failures mid-loop.Persistence
YoungCrop/MatureCropserializetickPlantedin bothroomJsonReaderWriterandinventoryJsonReaderWriter, following theExcrement.tickCreatedpattern_CROP_ENTITY_CONSTRUCTORSregistry added to inventory reader/writer for tick-parameterized constructionTests