diff --git a/IDEAS.md b/IDEAS.md new file mode 100644 index 0000000..6054d71 --- /dev/null +++ b/IDEAS.md @@ -0,0 +1,132 @@ +yes ai made this, no, i dont care. + +# Ideas & Future Vision + +Parking lot for things I want to build but aren't building yet. Nothing here is a +commitment to a timeline — it's here so it's out of my head and safe. + +Rule for this file: an idea only graduates to "actually build it" once the things +it depends on already exist. Don't build up the dependency chain. Build down it. + +--- + +## The Big One: Emergent Quest Engine + +The dream. A quest system where quests aren't hand-written — they're generated by +chaining several smaller generators together, each feeding the next. The goal is +quests that feel *authored* because the pieces reference each other and reference +the player's actual cat/state. + +### The chain +1. Generate an **item** + what it does (effect). +2. Generate a **character** who needs that item *because of what it does*. +3. Generate a **location** the character (or the cat?) travels to. +4. Generate an **encounter / fight**, scaled to a generated skill level, maybe + flavored by a custom name. +5. Resolve it → bring the item back → gain **xp, money**, maybe **food/items found + on the way**. + +### Why it could feel special (not generic radiant-quest slop) +- Quests reference the *specific cat*: its traits ("your chonky cat..."), its name, + its current stats. Two players get different quests because their cats differ — + not because of raw RNG. +- The chain links cause to effect: the character needs the item *because* of what + the item does. The reward ties back to the chain. That's the "wait, this feels + written" magic. + +### The trap to avoid +"Unique" and "meaningful" pull opposite directions. Pure randomization gives you +infinite *technically unique* quests that all *feel identical* (Skyrim radiant +quests: "go to random place, kill random thing, fetch random item" forever). + +The fix — same lesson as the name generator: **variety lives in the TEMPLATES, +uniqueness lives in the SLOTS.** Ten hand-written quest templates with rich, +state-aware slots beats one template randomized harder. Constrain to get quality. + +### The hard part most people underestimate +- **Completion checking.** A quest is only meaningful if the game can tell when + it's *done*. Every template's win condition must be something the game actually + tracks. "Feed 3 times" needs a feed counter. "Happiness > 50" needs the happiness + stat. So quests are GATED on the systems they reference already existing. +- **Procedural MECHANICS are way harder than procedural CONTENT.** A generated + *name* is just text — any string works. A generated *item effect* has to actually + DO something the game can execute. That means generated items pick from a FIXED + vocabulary of effects the game already knows how to run ("restore N hunger", + "add N happiness", "worth N money") — generated *parameters*, fixed *effect types*. + Do NOT try to generate brand-new mechanics; generate combinations of existing ones. + +### Quests must persist +An active/in-progress quest has to survive save/load. So `Quest` is a model with +`to_dict`/`from_dict` + a `version`, same discipline as Cat/Save. Active quests +live on the Save. + +--- + +## Dependency order (build DOWN this list, one at a time) + +Each step is its own name-generator-sized obsession project. Each one is gated on +the steps above it. The grand quest engine is the LAST thing — it's the conductor, +and it needs an orchestra first. + +0. **Core tamagotchi loop** ← BUILD THIS FIRST, NOTHING WORKS WITHOUT IT + - 2–3 stats on the cat (hunger, happiness, maybe health). Start with ONE. + - Decay over time (stats drop while away — uses elapsed-time logic). + - Actions that restore them (feed → hunger, pet/play → happiness). First real + `rules.py` verbs. Pure + testable. + - A reason actions aren't free → food item → money → a way to earn money. + - **Prove the core loop is fun before building anything on top of it.** If the + cat-care loop isn't satisfying, no quest engine saves it. + +1. **Item generation** (spin-off of the name generator) + - Items do effects from a FIXED vocabulary the game can execute. + - Generate the parameters/flavor, not new mechanics. + - Gated on: stats existing (effects need something to affect). + +2. **Character / NPC generation** + - Reuse the name generator for NPC names. + - Each NPC has a need (tied to an item effect). + - Gated on: item generation. + +3. **Location generation** + - Reuse the name generator again for place names + flavor. + +4. **Combat system** + - Its own whole system. Skill/level scaling, resolution. + - Gated on: stats, maybe items (gear?). + +5. **Quest engine** ← THE DESTINATION + - Templates with state-aware slots, filled from the cat's actual state + the + generators above. + - Orchestrates items + characters + locations + combat into a chain. + - Completion conditions that check real, existing systems. + - Rewards that pay out real money/xp/items. + - Gated on: literally everything above. + +--- + +## Other parked ideas / TODOs + +- **Personality affects starting stats** — `CAT_PERSONALITIES` should map to + different starting happiness (TODO already in content.py). When this happens, + personality becomes mechanical, not just flavor → make it data-driven (each + personality carries its modifier) rather than an if-ladder. +- **Save overwrite handling** — two cats named the same silently overwrite. Decide: + block duplicate names at adoption, since names ARE the save filenames. +- **Saves → proper user-data dir** — currently `untitled/saves/` inside the package. + Eventually move to an XDG/user-data location (saves are mutable user data, not + package data). +- **Delete save** flow (main-menu only, with confirm, never the active save). +- **Web version** — pty/xterm.js bridge. Dead last, after the game is actually a game. +- **Name generator polish** — order-3 vs order-2 experiment; soft length cap is in. +- **A studio splash / fake boot sequence** easter egg (CatDOS-style). + +--- + +## Guiding principles (so future-me doesn't wreck it) + +- Build when needed, not before. Park visions here; build the next small thing. +- Variety in templates, uniqueness in slots. Constrain generators to get quality. +- Generate parameters from a fixed vocabulary, never generate raw mechanics. +- Keep the layers: model (data) ← rules/generation (logic) ← screens (I/O). +- Pure logic stays testable. If you can't test it without a terminal, it leaked. +- Prove each loop is fun before stacking the next system on it. \ No newline at end of file diff --git a/untitled/migration.py b/untitled/migration.py index 90c7b2d..c31b5c3 100644 --- a/untitled/migration.py +++ b/untitled/migration.py @@ -1,4 +1,5 @@ -_MIGRATIONS = {} + +_MIGRATIONS = {} # TODO: ADD HUNGER AND LAST PLAYED MIGRATION def migrate(data): diff --git a/untitled/model.py b/untitled/model.py index 0725b51..c75f999 100644 --- a/untitled/model.py +++ b/untitled/model.py @@ -1,14 +1,24 @@ +import time + + class Cat: - def __init__(self, name, traits): + def __init__(self, name, traits, hunger=100, last_updated=None): self.name = name self.traits = traits + self.hunger = hunger + self.last_updated = last_updated if last_updated is not None else time.time() def to_dict(self): - return {"name": self.name, "traits": self.traits} + return { + "name": self.name, + "traits": self.traits, + "hunger": self.hunger, + "last_updated": self.last_updated, + } @staticmethod def from_dict(data): - return Cat(data["name"], data["traits"]) + return Cat(data["name"], data["traits"], data["hunger"], data["last_updated"]) class Save: