small update

boss prototype, auto planter, visual reworks, bug fixes
This commit is contained in:
2026-08-29 10:45:34 +02:00
parent 6840b715de
commit feb4500c6c
31 changed files with 1293 additions and 213 deletions
+38 -13
View File
@@ -3,18 +3,19 @@ from __future__ import annotations
import random
# Rune kinds (gems). Each rune is an item equipped into a plant's slots.
RUNE_COLORS = ("sapphire", "ruby", "amethyst", "jade", "brown")
RUNE_COLORS = ("sapphire", "ruby", "amethyst", "jade", "brown", "pearl")
RUNE_NAMES = {
"sapphire": "Sapphire Rune",
"ruby": "Ruby Rune",
"amethyst": "Amethyst Rune",
"jade": "Jade Rune",
"brown": "Brown Rune",
"pearl": "Pearl Rune",
}
# Tier classification: sapphire/ruby/amethyst/jade are Tier 1, brown is Tier 2.
# Tier classification: sapphire/ruby/amethyst/jade are Tier 1, brown & pearl Tier 2.
TIER1_COLORS = ("sapphire", "ruby", "amethyst", "jade")
TIER2_COLORS = ("brown",)
TIER2_COLORS = ("brown", "pearl")
RUNE_TIERS = {c: 1 for c in TIER1_COLORS}
RUNE_TIERS.update({c: 2 for c in TIER2_COLORS})
@@ -25,6 +26,7 @@ RUNE_ICON_FILES = {
"jade": "jade_rune",
"amethyst": "amethyst_rune",
"brown": "rune_brown",
"pearl": "pearl_rune",
}
# Old color names kept in earlier saves, mapped to the current gem names.
@@ -43,31 +45,39 @@ def canonical_color(color: str) -> str:
# Primitive effects: each rune rolls its own stat and stacks additively with
# other equipped runes of the same effect. Brown is rarer and rolls lower, but
# turns part of the damage this plant deals into a Wilt.
# turns part of the damage this plant deals into a Wilt. Pearl rolls a chunk of
# critical hit chance.
RUNE_EFFECTS = {
"ruby": "damage", # +damage dealt
"sapphire": "shield", # +shielding
"jade": "healing", # +healing received
"amethyst": "damage_taken", # -damage taken
"brown": "wilt", # damage dealt also Wils the target
"pearl": "crit", # +critical hit chance
}
PCT_MIN = 25
PCT_MAX = 35
BROWN_PCT_MIN = 5
BROWN_PCT_MAX = 15
PEARL_PCT_MIN = 20
PEARL_PCT_MAX = 40
# a plant can't stack more than this many runes of the same type
MAX_RUNES_PER_TYPE = 2
# runes sacrificed to reroll one rune to a higher stat
RUNE_SACRIFICE_COST = 3
# coin costs to buy a random rune of a tier in the runes shop
T1_RUNE_COST = 100
T2_RUNE_COST = 150
# brown drops less often than the other runes (relative weights)
RUNE_WEIGHTS = {"sapphire": 1.0, "ruby": 1.0, "amethyst": 1.0, "jade": 1.0, "brown": 0.75}
# brown & pearl drop less often than the other runes (relative weights)
RUNE_WEIGHTS = {"sapphire": 1.0, "ruby": 1.0, "amethyst": 1.0, "jade": 1.0,
"brown": 0.75, "pearl": 0.75}
_EFFECT_TEXTS = {
"ruby": "+{pct}% damage dealt",
"sapphire": "+{pct}% shielding",
"jade": "+{pct}% healing",
"amethyst": "-{pct}% damage taken",
"brown": "deals {pct}% of damage as Wilt",
"pearl": "+{pct}% critical chance",
}
RUNE_SUMMARIES = {
"ruby": "Increases damage dealt",
@@ -75,6 +85,7 @@ RUNE_SUMMARIES = {
"jade": "Increases healing received",
"amethyst": "Reduces damage taken",
"brown": "Deals a portion of damage as Wilt",
"pearl": "Increases critical hit chance",
}
MAX_RUNE_SLOTS = 3
@@ -91,12 +102,23 @@ def random_color() -> str:
def roll_pct(color: str = None) -> int:
"""Roll a rune's stat percentage. Brown rolls 5-15; the rest 25-35."""
"""Roll a rune's stat percentage. Brown rolls 5-15, pearl 20-40, the rest 25-35."""
if color == "brown":
return random.randint(BROWN_PCT_MIN, BROWN_PCT_MAX)
if color == "pearl":
return random.randint(PEARL_PCT_MIN, PEARL_PCT_MAX)
return random.randint(PCT_MIN, PCT_MAX)
def max_pct(color: str) -> int:
"""The highest stat a rune of `color` can roll (brown/pearl have their own caps)."""
if color == "brown":
return BROWN_PCT_MAX
if color == "pearl":
return PEARL_PCT_MAX
return PCT_MAX
def name(color: str) -> str:
return RUNE_NAMES.get(color, "Rune")
@@ -106,11 +128,11 @@ def tier(color: str) -> int:
def roll_ratio(rune) -> float:
"""How close a rune's roll is to its own maximum (0..1). Brown's 5-15 range
is compared to its 15 cap, so a maxed brown ranks equally with a maxed
yellow even though 15 < 35."""
max_pct = BROWN_PCT_MAX if rune.get("color") == "brown" else PCT_MAX
return rune.get("pct", 0) / max_pct
"""How close a rune's roll is to its own maximum (0..1). Each color is
compared to its own cap, so a maxed brown or pearl ranks equally with a
maxed ruby even though 15 < 35."""
cap = max_pct(rune.get("color"))
return rune.get("pct", 0) / cap
def effect_text(color: str, pct: int) -> str:
@@ -124,6 +146,7 @@ _CARD_TEXTS = {
"jade": "+{pct}% heal",
"amethyst": "-{pct}% taken",
"brown": "Wilt {pct}%",
"pearl": "+{pct}% crit",
}
@@ -149,9 +172,11 @@ def summary(color: str) -> str:
def roll_range(color: str) -> str:
"""The stat range a rune of `color` rolls between (brown is lower)."""
"""The stat range a rune of `color` rolls between (brown/pearl are lower)."""
if color == "brown":
return f"{BROWN_PCT_MIN}–{BROWN_PCT_MAX}%"
if color == "pearl":
return f"{PEARL_PCT_MIN}–{PEARL_PCT_MAX}%"
return f"{PCT_MIN}–{PCT_MAX}%"