|
| 1 | +# Bunnyland Fortunesim |
| 2 | + |
| 3 | +Out-of-tree [Bunnyland](https://github.com/thalismind/bunnyland-server) plugin about **luck, |
| 4 | +charms, and omens** — an expansion-pack-sized themed bundle that gently nudges outcomes and |
| 5 | +rewards ritual behavior. It pairs wickedly with a haunting pack (bad omens near the dead) and a |
| 6 | +fishing pack (a lucky charm for the big catch). |
| 7 | + |
| 8 | +> **Luck is a stat. Superstition is a strategy.** |
| 9 | +
|
| 10 | +The bundle ships five cooperating mechanics: |
| 11 | + |
| 12 | +- **Luck stat** — an open `LuckComponent` on characters. Its materialised `value` (base + |
| 13 | + charms + active rituals) is maintained every tick by `LuckConsequence`, so any pack that opts |
| 14 | + in can read one field to bias its own probabilistic outcomes. Luck shifts the *weighting*; it |
| 15 | + never rolls dice. |
| 16 | +- **Charms & talismans** — carried `CharmComponent` items (a rabbit's foot, a four-leaf clover) |
| 17 | + that raise luck while held; cursed trinkets lower it. |
| 18 | +- **Omens** — `OmenConsequence` reads the world and casts a room foreboding or auspicious, |
| 19 | + surfacing a deterministic omen line ("A crow watches you from the rafters.") into prompts. |
| 20 | +- **Fortune-telling** — a `read-fortune` verb over a held tarot / tea-leaves tool that assembles |
| 21 | + a deterministic reading from the seeker, their luck, and the current room omen. |
| 22 | +- **Superstitions** — a `ward-luck` verb (knock on wood, toss salt, cross fingers) that buys a |
| 23 | + temporary luck boost — fun busy-work with a real payoff. |
| 24 | + |
| 25 | +**Determinism:** every luck-biased outcome and fortune reading is derived from a `hashlib` |
| 26 | +digest of stable ids plus the world `epoch`, reduced over sorted tables. There is no `random` |
| 27 | +and no wall-clock time anywhere in the package, so the same world state always yields the same |
| 28 | +result regardless of `PYTHONHASHSEED`. |
| 29 | + |
| 30 | +This repo intentionally keeps all of the fortune work outside the main `bunnyland-server` repo. |
| 31 | + |
| 32 | +## Layout |
| 33 | + |
| 34 | +- `server/` — Python Bunnyland plugin package with the luck/charm/omen components, the luck and |
| 35 | + omen consequences, the two verbs, prompt fragments, a worldgen enrichment hook, spawn |
| 36 | + factories, and tests. |
| 37 | + |
| 38 | +## Server Plugin |
| 39 | + |
| 40 | +The plugin exposes `bunnyland_fortunesim.bunnyland_plugins()` and contributes: |
| 41 | + |
| 42 | +- `LuckComponent`, `CharmComponent`, `OmenComponent`, `FortuneToolComponent`. |
| 43 | +- `LuckConsequence` — materialises each character's total luck from held charms and active |
| 44 | + rituals every tick, emitting `LuckChangedEvent` on band crossings. |
| 45 | +- `OmenConsequence` — adds, updates, and clears dynamic room omens driven by loose charms, |
| 46 | + leaving sticky worldgen omens alone; emits `OmenSightedEvent` / `OmenClearedEvent`. |
| 47 | +- `luck_fragments`, `charm_fragments`, `omen_fragments` — render luck band, held charms, and |
| 48 | + room omens into both human and AI prompts. |
| 49 | +- `FortuneWorldgenHook` — turns generated charm/trinket objects into `CharmComponent`s and casts |
| 50 | + ominous or auspicious generated rooms with a sticky `OmenComponent`. |
| 51 | +- `read-fortune` and `ward-luck` — verbs for the seeker (human or AI), emitting `FortuneReadEvent` |
| 52 | + and `WardLuckEvent`. |
| 53 | +- `spawn_charm`, `spawn_talisman`, `spawn_cursed_trinket`, `spawn_fortune_tool` — spawn factories. |
| 54 | +- Good and bad fortune colour a character's mood by reusing the core affect system |
| 55 | + (`remember_fortune` attaches a decaying `AffectDelta` thought). |
| 56 | + |
| 57 | +## Running |
| 58 | + |
| 59 | +This package builds no containers. It is loaded into the stock server via `--module`: |
| 60 | + |
| 61 | +```bash |
| 62 | +bunnyland serve --module bunnyland_fortunesim |
| 63 | +``` |
| 64 | + |
| 65 | +`default_enabled=True`, so no `--plugin` flag is required once the module is imported. The |
| 66 | +`bunnyland_fortunesim` package must be importable by the server (installed into the server's |
| 67 | +environment, or on `PYTHONPATH`). |
| 68 | + |
| 69 | +## Development |
| 70 | + |
| 71 | +Run server tests against a sibling `bunnyland-server` checkout (no install required — |
| 72 | +`server/tests/conftest.py` puts both packages on `sys.path`). From `server/`: |
| 73 | + |
| 74 | +```bash |
| 75 | +uv run --project ../../bunnyland-server -m pytest |
| 76 | +uv run --project ../../bunnyland-server ruff check src tests |
| 77 | +``` |
| 78 | + |
| 79 | +See [`server/README.md`](server/README.md) for more detail. |
| 80 | + |
| 81 | +## Contributing & Conduct |
| 82 | + |
| 83 | +This plugin follows the Bunnyland project's |
| 84 | +[contribution guidelines](CONTRIBUTING.md) and [code of conduct](CODE_OF_CONDUCT.md), |
| 85 | +which point back to the `bunnyland-server` repository. |
| 86 | + |
| 87 | +## License |
| 88 | + |
| 89 | +Licensed under the GNU Affero General Public License v3.0. See [LICENSE](LICENSE). |
0 commit comments