Files
Lena feb4500c6c small update
boss prototype, auto planter, visual reworks, bug fixes
2026-08-29 10:45:34 +02:00

163 lines
7.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Flora — Turn-Based Battle Game
A turn-based battle game in Python. Normal battles are 4v4; the Tower mode
starts small and ramps up.
## Run it
```
pip install -r requirements.txt
python main.py
```
You land on the **main menu**:
- **Seeds** — seed pack opening; the main way to get/enhance plants.
- **Plants** — the plants you own, with their **level/stage**; open a plant to see its
stats and **Water** (+1 level) or **Evolve** it
(at milestone levels, consuming duplicates).
- **Battle** — pick a difficulty stage (1–5, gated by enemy rarity), then the
enemy team is rolled so you know the matchup, and you pick your 4 allies and
fight. Higher stages grant more packs on a win; any loss grants a lesser pack.
- **Tower** — a 20-stage gauntlet. Enemies start with 1 common plant and get
stronger (more enemies, higher rarity, higher level) each stage; your team is
fresh every fight. After each win you **choose one of three roguelike
blessings** (shields, stat boosts, enemy debuffs, heal-over-time…) that last
for the rest of the run — the core of the tower's roguelike loop.
Stages 1–5 pay 1 water each, stages 6–20 pay scaling
**Tower packs** (high-rarity odds), which you can open or redeem for 20 water.
- **Collection** — plants you've discovered (they're added when you battle them);
undiscovered plants show as blacked-out silhouettes. Saved in `data/collection.json`.
- **Soil** — retrieve a **seed** from any owned plant (once per cooldown, from
its detail page), plant it, then grow a copy in stages. Each stage fills over
time; **fertilizing** (1 fertilizer per stage) advances it. Higher rarities
have more stages; harvesting grants a duplicate of that plant. You start with
**1 plot**; extra plots unlock for escalating fertilizer (10, then 20, 30…,
up to 5 total). Soil unlocks once you own **8 distinct plants**.
## Rarities
Every plant has a **rarity** tag (common / rare / epic / legendary) —
purely cosmetic, only used to weight seed-pack drops. A **victory** grants
seed packs equal to the difficulty stage (1–5) **plus fertilizer equal to the
floor** (1–5); a **defeat** grants 1
**lesser pack** (worse rarity odds, no type weighting). Type packs roll the
rarity first (matching the general pack) and then pick a plant of that rarity
from the type when possible; rarer plants are rarer pulls.
## Watering, fertilizer & Evolution
Two resources:
- **Water** — the scarce, valuable currency. **Watering** gives an instant +1
level by spending 1 water, and 5 water can be converted into a seed pack.
Water comes mainly from Tower rewards (stage 1–5 wins pay 1 water, Tower packs
redeem for 10).
- **Fertilizer** — the common currency earned from **battle wins**. It's used to
fertilize growing Soil plots (each fertilizer advances a plot one stage).
- **XP** is earned from battles (participation + win bonus); allies auto-level up.
Higher difficulty stages pay more XP (scales with the stage number), and Tower
wins pay XP too. The lowest-level plant on your team earns bonus XP based on
the level gap (catch-up).
- **Evolution** unlocks at milestone levels (5 → stage 2, 10 → stage 3) and
consumes duplicates. Stages multiply base stats before the level curve.
- Enemies in battle are scaled to roughly your team's level.
- Stat growth: attack/defense +6%, health +8%, speed +4% per level (see `engine/growth.py`).
## Roguelike blessings (Tower)
After every Tower win you're offered **3 random blessings** and keep one (or
skip). Blessings stack for the rest of the run and apply at the **start of each
battle**. They come in three rarity tiers:
- **Common** — small shields/stat boosts and start-of-battle buffs (e.g. "team
starts with a shield for 10% of max health").
- **Rare** — bigger boosts, heal-over-time, stronger healing, enemy debuffs
(Speed/Attack Down).
- **Epic** — strong shields, "+15% attack", "+20% max health", enemies start
Vulnerable.
- **Legendary** — rare picks with big payoff: block the first damage taken,
a 40% shield, a one-time revive, or a large HP/attack combo.
Blessings are offered from a **rarity-weighted** pool, so legendary relics show
up rarely.
Blessings are defined declaratively in `engine/relics.py` (`RELIC_POOL`); each
relic is a `Relic` with an `apply(battle)` function that runs once per battle in
`Battle.start()`. They're tracked per-run (not saved). An **"All blessings"
overview** (`ui/relics_overview.py`) shows the whole pool grouped by rarity with
the ones you've collected highlighted in gold; click any card for a closer look.
It opens from the blessing-choice screen and by clicking the "Blessings:" line
on the Tower battle screen.
## Plant types & type advantages
Five types with a rock-paper-scissors cycle:
**Radiant > Nocturnal > Ice > Garden > Wildflowers > Radiant**
- Hitting a type you're strong against deals **+30%** damage.
- Hitting a type that's strong against you deals **−30%**.
- Applies only to damage — heals and shields are unaffected.
## Stats & damage
- **Health** — the damage pool.
- **Attack / Defense** — damage = skill power + attack − defense (min 1).
- **Speed** — an **initiative timeline**: each plant acts based on `100 / speed`
interval, so faster plants act *more often* and interleave with slower ones
(e.g. a 110-speed enemy goes 110 → 75 → 110 → 50…). The blue bar under each
unit's health shows how close it is to its next turn. Speed buffs/debuffs
change the interval, and "reduce turn progress" effects literally push a
plant's next turn back.
- **Crit** — base 10%, doubles damage.
## Debuffs
- **Wilt** — damage over 3 turns (total = % of the triggering hit's damage);
reapplying resets it to 3 turns.
- **Shield** — temporary HP that absorbs damage; cannot be healed.
- **Damage-over-time** (Dark Corrosion, Chill) — deals its listed damage **every
turn** while active; Dark Corrosion stacks.
- **Sleep** — skips turns until the target has taken damage twice.
- **Vulnerable X** — +50% damage for the next X hits.
- **Intoxicate / Oblivion** — an Intoxicated plant's attacks splash half their
damage onto one of its own allies; an Oblivious plant may only use its weakest
skill (both last their stated duration, e.g. 1-2 turns).
- Plus speed/crit/attack/defense down, Madness, Tether, and more.
## The plant pool (27)
All defined declaratively in `engine/plants.py` so new plants are easy to add:
- **Radiant:** Zinnia, Sunflower, Daisy, Marigold, Daffodil
- **Garden:** Rose, Peony, Magnolia, Hydrangea, Sweet Pea, Chrysanthemum
- **Wildflower:** Lily, Hibiscus, Poppy, Tulip, Lotus, Dandelion
- **Nocturnal:** Nightshade, Moonflower, Orchid, Lavender, Venus Flytrap
- **Ice:** Snowdrop, Primrose, Winter Jasmine, Hellebore, Camelia
Each has a role (Attacker / Support / Tank), a unique passive, three skills
with cooldowns, and base stats. Tanks protect their team from single-target
attacks (AOE still hits everyone).
## Architecture
```
engine/ Pure-Python battle logic (types, skills, effects, plants, battle).
No pygame — reusable for a web UI or Flet later.
ui/ pygame frontend: team picker + battle screen.
tests/ unittest coverage of the engine.
```
Adding a plant later = add one entry to `POOL` in `engine/plants.py`.
## Tests
```
python -m unittest discover -s tests
```
## Roadmap ideas
- Balance pass (sim currently favors the player's chosen teams)
- More team strategies, saving team compositions
- Web UI via Flask, or a real mobile app via Flet