{
"id": "pet.trezy.gameConfig",
"defs": {
"main": {
"key": "literal:self",
"type": "record",
"record": {
"type": "object",
"required": [
"stageMoneyCap",
"activePetCap",
"starterGrantCap",
"hungerDecayRate",
"happinessDecayRate",
"interactionCooldown"
],
"properties": {
"activePetCap": {
"type": "integer",
"minimum": 0,
"description": "How many pets can be on the stage at once. Only active pets earn, so this is the ceiling on income rather than a display limit. Replaces the literal 3 in createPet's active-slot CASE and the MAX_PETS constant deleted in Task 4."
},
"stageMoneyCap": {
"type": "integer",
"minimum": 0,
"description": "A SANITY BOUND, NOT A GAME MECHANIC — and it used to be the other way round, which is why this says so. It caps what can accrue between one settle and the next: while it is met, active pets stop producing entirely. It no longer shapes play, because DECAY already does that job better: care quality falls to zero within about a day and a half, so a pet earns roughly one care cycle however long somebody stays away, and a player who never returns is bounded without any ceiling being involved. Set it well clear of what honest play can reach — a full stage of well-kept pets makes a few hundred coins from one session — so that it can only ever fire on a bug in the curve. A cap tight enough to bind in normal play punishes the ONE THING the design asks for, which is that checking in once a day is enough: with money banking itself, the only way a player could dodge a tight cap is to open the game more often. Raising it is safe at any time; lowering it below what a player has already accrued is not."
},
"hungerDecayRate": {
"type": "integer",
"minimum": 1,
"description": "Seconds for one feeding to fall from full to nothing — a duration, not a per-second rate, despite the name. THE SAME NUMBER DECIDES WHAT A PET LOOKS LIKE AND WHAT IT EARNED: collectCoins and getWallet price a stretch of care from this curve, while getStats and getLeaderboard draw the bar from it. It lives here because it was a literal in all four of those files and they drifted: a rebalance to a once-a-day return schedule landed on the two that pay and missed the two that display, so the game paid as though a day away was fine and simultaneously showed the pet with nothing left. Readers must FAULT when it is absent or unusable rather than falling back to a default, because a silent default is exactly how that drift became invisible."
},
"starterGrantCap": {
"type": "integer",
"minimum": 0,
"description": "The most the server will grant a player for their very first pet. A new player has no income until they have a pet and no pet until they can pay for one, so createPet grants the price of the pet they choose and buys it on their behalf — but only up to this much, or a hand-rolled call would make an epic the free starter. A species dearer than this falls through to the ordinary affordability check and refuses cannot-afford. NOT the lowest tier's price: at 50 the grantable pool would be the two purchasable commons, which is smaller than the three onboarding offers and excludes both slimes. Raising it is safe; lowering it only affects players who have not had their grant yet, because a grant is once per DID and recorded in trezy_pet_grants."
},
"happinessDecayRate": {
"type": "integer",
"minimum": 1,
"description": "Seconds for one petting to fall from full to nothing. Same rules and the same four readers as hungerDecayRate; kept separate because the two halves of care need not fade at the same speed, even where they currently do."
},
"interactionCooldown": {
"type": "integer",
"minimum": 1,
"description": "Seconds after feeding or petting before the SAME action is allowed on the SAME pet again. Two scripts need it and they must agree: createInteraction ENFORCES it, and getStats REPORTS how much of it is left so the buttons can show a countdown rather than discovering the rule by being refused. It was a literal `30 * 60` in createInteraction and a second copy as COOLDOWN_MS in the web client, which is the same three-way drift hazard the decay rates had — with a worse failure, because a client that thinks the wait is shorter than the server does invites the player to click a button that then refuses them. Readers must FAULT when it is absent rather than defaulting, for the same reason as the decay rates."
}
}
},
"description": "The game's tunable numbers — caps, and the curves that decay a pet's care — published in the game's own repo (did:plc:ollch4g7tes2reb5eceiwuol) at rkey `self`. Only records from that DID are ever read — record.index:pet.trezy.gameConfig refuses the rest, and a forged config is worth more to an attacker than a forged tier because it raises every cap at once. These are records rather than constants because an upgrade system is coming: players will unlock higher caps as records in their OWN repo, so every cap resolves as base-from-here plus that player's unlocks, and the upgrade system adds records instead of restructuring readers."
}
},
"$type": "com.atproto.lexicon.schema",
"lexicon": 1
}