Repository navigation
S6a: Contract: salvage and selling - #372
Merged
Merged
Conversation
Adds what S6 needs for salvage to be picked up and sold: `player_state` gains `piles`, what's lying in the world to pick up, and `buyer`, who buys where the player stands and for what; `sell` from the client; a `Pile` can hold `money`, for the metro's cash secrets; and `Player.taken` keeps which of the world's pickups they've taken from. The new fields are left out of dumps while empty. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Review of S6a. Approving. Checked
Design
Optional nits
|
- Player.taken records when each pickup was last taken, by pickup id, so salvage can lie there again after a while. A secret stays taken. - Pile.money is strict: a string like "0" can't pass the "some money" rule and then turn into 0. - Reflow protocol.md's paragraph on saves. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
Re-review at Since
|
jamescrosswell
marked this pull request as ready for review
October 22, 2026 15:47
This was referenced Oct 22, 2026
Merged
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.
The contract S6 (#353) needs for salvage to be picked up and sold. Nothing sends or handles any of it yet; S6 does.
Client → server
sell:{"type": "sell", "item": "copper_wire"}sells one thing the player carries, by itsid, to the buyer where they stand."item": nullsells everything they carry that the buyer buys. The server ignores asellwhere there's no buyer, or for something they don't carry or the buyer doesn't buy.pick_upis unchanged, but now also takes a pile's money, and works on the world's piles as well as the player's own.Server → client
player_stategainsbuyer:{"place": "scrap_stall", "name": "The scrap trader", "prices": {"copper_wire": 6}}, who buys where the player stands, a stall or a keeper at their place, and what it pays for one of each thing they carry that it buys. It's left out where there's none, so the client never has to know where the buyers are or what anything's worth. The prices are the server's, and an NPC only voices them.player_stategainspiles: what's lying in the world to pick up besides what the player left (player.left), on every map, such as the metro's salvage and secrets. Left out while there's none.Schema
Pile.money: cash lying there, which weighs nothing. A pile holds at least one item or some money, so{"at": ..., "items": [], "money": 25}is the stairwell's secret.itemsis still always sent.moneyis strict, so a string such as"0"can't pass the "some money" rule and then become 0.Player.taken: when the player last took from each of the world's pickups, a sim timestamp by pickup id ({"metro_salvage_1": "2026-03-14T10:05:30Z"}), saved with the player. Salvage lies there again a while after it was taken, after a delay S6 sets, and a secret, cash or a ration, stays taken for good. Anything of a pickup that didn't fit goes intoleft, so a half-taken pickup is saved too, andleft's description now covers it.Additive only
money,taken,buyerandpilesare left out of dumps while empty (exclude_if) and aren't required in the exported schemas, so every existing message, theplayers.jsonfixtures and saves dump exactly as before. A save from before them loads with nothing taken.Pile.itemslosesminItems: 1for the cash-only pile, which the validator replaces with "at least one item or some money". Everything valid before is still valid. Inprotocol.tsit's nowItem[]rather than a non-empty tuple; the client still type-checks.sellis only added to the client union.Player.json,protocol.schema.jsonandprotocol.tsare regenerated.Choices
pilesandbuyerinplayer_state, not messages of their own. Only the player picks things up, and taking part of a world pile moves the rest intoleft, so both change in one message.player_statealready goes out on every change.Player.takenrather than the world's piles in the save. The ids come from the maps'pickupslayer (S3), so a pickup S3 moves or adds is picked up from its map, and the save only says which were taken and when.pricesandtakenkeyed byKey, notId. AnId-keyed dict makes json-schema-to-typescript write a stray "referenced byundefined" comment intoprotocol.ts.Closes #371
🤖 Generated with Claude Code