aether-garden / ui /featured.py
kavyabhand's picture
Deploy Aether Garden application
74688c8 verified
Raw
History Blame Contribute Delete
4.43 kB
"""Featured characters and living world showcase."""
from __future__ import annotations
from ui import assets
from world.entities import get_all_entities
from world.locations import get_location_by_id
from ui.avatars import render_avatar
def _location_slug(entity: dict) -> str | None:
loc = get_location_by_id(entity["location_id"])
return loc["slug"] if loc else None
def render_featured_characters(limit: int = 6) -> str:
entities = get_all_entities(limit=50)
if not entities:
return ""
# Prioritize characters/creatures with memory and legendary/active status
def score(e: dict) -> int:
s = 0
if e["type"] in ("character", "creature"):
s += 3
if e.get("memory_summary"):
s += 2
if e["status"] == "legendary":
s += 4
if e.get("tags"):
s += 1
s += min(e["days_in_realm"], 10)
return s
featured = sorted(entities, key=score, reverse=True)[:limit]
cards = []
for entity in featured:
loc = get_location_by_id(entity["location_id"])
loc_name = loc["short_description"][:60] if loc else ""
loc_short = loc["name"].replace("The ", "") if loc else "Unknown"
slug = loc["slug"] if loc else None
avatar = render_avatar(entity, size=72, location_slug=slug)
status_class = f"featured-{entity['status']}"
tag = entity["tags"][0] if entity.get("tags") else entity["type"]
img = assets.location_image_url(slug)
bg_style = f"background-image: url('{img}');" if img else ""
cards.append(f"""
<div class="featured-card {status_class}" data-entity-id="{entity['id']}" style="{bg_style}">
<div class="featured-card-scrim"></div>
<div class="featured-portrait">{avatar}</div>
<div class="featured-info">
<span class="featured-type">{tag}</span>
<h3 class="featured-name">{entity['name']}</h3>
<p class="featured-location">{loc_short}</p>
<p class="featured-appearance">{entity['appearance'][:140]}…</p>
<blockquote class="featured-greeting">"{entity['greeting'][:90]}{'…' if len(entity['greeting']) > 90 else ''}"</blockquote>
{f'<p class="featured-memory">{entity["memory_summary"][:100]}…</p>' if entity.get("memory_summary") else ''}
</div>
</div>
""")
return f"""
<div class="featured-section">
<div class="section-header">
<h2 class="section-title">Souls of the Garden</h2>
<p class="section-desc">Real inhabitants β€” each with their own wants, fears, and memories</p>
</div>
<div class="featured-grid">{"".join(cards)}</div>
</div>
"""
def render_world_vignette() -> str:
from world.book_of_ages import get_entries
from world.events import get_active_world_event
event = get_active_world_event()
if event:
effect = (event.get("entity_effect") or "").strip()
mystery = (event.get("mystery_hook") or "").strip()
chronicle = (event.get("book_of_ages_entry") or "").strip()
parts = []
if effect:
parts.append(f"<p class=\"vignette-text\"><b>On the souls:</b> {effect}</p>")
if mystery:
parts.append(f"<p class=\"vignette-text vignette-mystery\"><b>Whispered omen:</b> <em>{mystery}</em></p>")
if not parts and chronicle:
parts.append(f"<p class=\"vignette-text\">{chronicle}</p>")
body = "".join(parts) if parts else (
"<p class=\"vignette-text\">The hour shifts β€” watch the map and chronicle for what stirs.</p>"
)
return f"""
<div class="world-vignette">
<p class="vignette-label">Ripples through the Garden</p>
{body}
</div>
"""
entries = get_entries(limit=1, entry_type="interaction")
if entries:
return f"""
<div class="world-vignette">
<p class="vignette-label">Recently, in the Garden</p>
<p class="vignette-text">{entries[0]['content']}</p>
</div>
"""
return """
<div class="world-vignette">
<p class="vignette-label">You stand at the threshold</p>
<p class="vignette-text">The lanterns are lit. Someone left footprints in the moss.
The world has been waiting. Add something β€” and it will remember you.</p>
</div>
"""