Turn the single boat into a fleet with dedicated roles - #139
Merged
Conversation
One boat that could only fish becomes any number of boats, each dedicated to fishing, hauling, piracy or transport. - Add src/business/boats.py: the fleet, the four roles, and crew drawn from ONE shared roster. Wages are owed on every hand hired whether or not they have a berth, so an idle boat is a real cost, and only crew on a fishing boat bring in a catch - Add src/business/voyages.py: the active job boards. Transport always pays and never touches the hull; hauling pays better but heavy seas can batter it; piracy pays far better and can cost a villager hired by name plus a hull too damaged to sail until it's paid to be fixed. Raids show their real odds before the player commits - player.hasBoat/boatTier become read-only properties derived from the fleet, so the flag and the tier can no longer disagree - Migrate pre-roles saves into a single fishing boat carrying the whole crew; nobody loses a boat or a hand by loading an old file - Hauling boats carry half again as much on an export run - Rebuild the docks fleet menu: buy, crew, re-dedicate, repair, upgrade, rename and sell per boat, plus "Send Out a Boat" - Move production/crew/selling out of business.py, which is now just the tier catalogue, so boats.py can depend on it without a cycle Fixed while testing: the save loader built the fleet before reading businessName, so a migrated boat lost the name it should have inherited. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
One boat that could only fish becomes any number of boats, each dedicated to a role. Two new modules carry it:
src/business/boats.py— the fleet, the four roles, and crew assignment.src/business/voyages.py— the job boards for the three active roles.Crew come from one shared roster. A new hire goes aboard the first boat with a free berth and can be moved between boats afterwards. Wages are owed on every hand hired whether or not they have a berth, so an idle boat is a real cost — and when payroll can't be met, the idle hands quit first. Only crew on a fishing boat bring in a catch, so where people stand is now a decision with a number attached.
Voyages cost a day, same as an export run. Pay scales with hull tier and crew size.
Piracy is the deep one, and shows its real odds before the player commits — a full-crewed Fishing Fleet is ~90% against the Saltmarsh skiffs but 47% (with a 16% disaster risk) against the escorted Thornhaven bullion run. Four outcomes: a rich take, an ordinary take (plus fish seized off their hold, straight into yours), driven off with a scratched hull, or a disaster that takes a villager the player hired by name off the boat and off the roster for good. Damage is lasting — past halfway a boat can't sail until the yard is paid.
Compatibility
player.hasBoatandplayer.boatTierare now read-only properties derived from the fleet, so the flag and the tier can't disagree any more (they previously could). Every read site is unchanged; write sites went throughboats.addBoat.A save written before roles existed has no
boatskey, so it's migrated into a single fishing boat carrying the whole crew — the exact meaning that save had. Nobody loses a boat or a hand by loading an old file, andhasBoat/boatTierare still written out so an older build can read a modern save. There are live save slots on the production box, so this path has its own tests.business.pyis now just the tier catalogue; production, crew and selling moved toboats.py, which letsboats.pydepend on it without an import cycle.tests/business/test_business.pywas split accordingly, with the fleet half becomingtests/business/test_boats.py.Test plan
python3 -m compileall -q src testsSDL_VIDEODRIVER=dummy SDL_AUDIODRIVER=dummy python3 -m pytest --verbose -vv --cov=src --cov-report=term-missing --cov-report=xml:cov.xml— 594 passed, 97% total.voyages.py100%,player.py100%,playerJsonReaderWriter.py100%,boats.py96%,docks.py93% (remaining gaps are pre-existingfish()branches).black+autoflakeover the changed files only.showOptions/showInteractiveDialogue/currentPrompt— no new primitive, so console, pygame and web all get it.fleetChooser), so adding an option no longer breaks a dozen unrelated tests.Balance note
A raid on the top target beats a hauling contract on the same hull by a wide margin, which is the point — but it's gated behind a tier-3 boat, a real crew, and a 16% chance of losing one of them plus a repair bill. Happy to tune the loot bands or the disaster share if it plays too hot.