snapquest / game_data.py
ashish-doing's picture
v5: pure HTML/JS game UI with global JS bridge, base64 photo upload, fixes gr.HTML script execution bug
7af7501
Raw
History Blame Contribute Delete
7.5 kB
"""game_data.py — shared data for SnapQuest: classes, loot, helpers."""
from __future__ import annotations
import random
CHARACTER_CLASSES = ["Swordsman", "Archer", "Healer", "Rogue", "Mage"]
CLASS_DATA = {
"Swordsman": {
"icon": "⚔️", "tagline": "The Iron Vanguard",
"desc": "Charges first, fears last. Built for face-to-face combat in tight dungeon corridors.",
"stats": {"HP": 130, "ATK": 18, "DEF": 14, "SPD": 10},
"perks": ["Shield Bash — stun enemy 1 turn", "Rallying Cry — +20 HP when below 30%", "Armor Expertise — DEF items give +50% bonus"],
"playstyle": "Aggressive. Frontline. Walk up and hit hard.",
"color": "#e8ffe8", "accent": "#4ade80",
},
"Archer": {
"icon": "🏹", "tagline": "The Silent Wind",
"desc": "Keeps distance. Every object in the room is a potential vantage point or obstacle.",
"stats": {"HP": 100, "ATK": 22, "DEF": 8, "SPD": 18},
"perks": ["Piercing Shot — ignores 50% of enemy DEF", "Eagle Eye — first strike each room always crits", "Quiver Master — ranged attacks never miss"],
"playstyle": "Stay back. Strike first. Control the flow.",
"color": "#fef9c3", "accent": "#facc15",
},
"Healer": {
"icon": "💚", "tagline": "The Warden of Light",
"desc": "Survives what others cannot. Turns the dungeon's own energy against it.",
"stats": {"HP": 115, "ATK": 10, "DEF": 16, "SPD": 12},
"perks": ["Mend — restore 25 HP per turn (passive)", "Holy Shield — 3-turn damage immunity, 1/room", "Life Tap — defeat enemy → gain 20 HP"],
"playstyle": "Outlast. Heal. Endure. Win by attrition.",
"color": "#dcfce7", "accent": "#86efac",
},
"Rogue": {
"icon": "🗡️", "tagline": "The Shadow Knife",
"desc": "Sees what others walk past. Strikes from angles the enemy never expected.",
"stats": {"HP": 95, "ATK": 20, "DEF": 10, "SPD": 22},
"perks": ["Backstab — first action each room deals 3× damage", "Vanish — 30% chance to dodge any attack", "Loot Sense — always finds one extra item per room"],
"playstyle": "Strike fast. Dodge. Never fight fair.",
"color": "#ede9fe", "accent": "#c084fc",
},
"Mage": {
"icon": "🔮", "tagline": "The Arcane Eye",
"desc": "Every object hums with power. Ordinary rooms are arcane batteries waiting to be drained.",
"stats": {"HP": 90, "ATK": 28, "DEF": 6, "SPD": 14},
"perks": ["Arcane Burst — 40% chance to deal double damage", "Object Reading — detect all hidden items on room entry", "Mana Shield — DEF scales with INT (ATK stat)"],
"playstyle": "Glass cannon. High risk, highest reward.",
"color": "#dbeafe", "accent": "#60a5fa",
},
}
LOOT_TIERS = {
"common": {"color": "#9ca3af", "glow": "none", "label": "COMMON"},
"uncommon": {"color": "#4ade80", "glow": "0 0 8px rgba(74,222,128,0.5)", "label": "UNCOMMON"},
"rare": {"color": "#60a5fa", "glow": "0 0 12px rgba(96,165,250,0.6)", "label": "RARE"},
"epic": {"color": "#c084fc", "glow": "0 0 16px rgba(192,132,252,0.7)","label": "EPIC"},
"legendary": {"color": "#fbbf24", "glow": "0 0 24px rgba(251,191,36,0.8)", "label": "LEGENDARY"},
}
LOOT_TABLE = [
{"name": "Rusty Dagger", "tier": "common", "type": "weapon", "stat": "+3 ATK", "icon": "🗡️"},
{"name": "Torn Cloak", "tier": "common", "type": "armor", "stat": "+2 DEF", "icon": "🧥"},
{"name": "Stale Bread", "tier": "common", "type": "consumable", "stat": "+10 HP", "icon": "🍞"},
{"name": "Copper Coin", "tier": "common", "type": "misc", "stat": "+5 Gold", "icon": "🪙"},
{"name": "Pebble Shard", "tier": "common", "type": "misc", "stat": "+1 ATK", "icon": "🪨"},
{"name": "Healing Herbs", "tier": "uncommon", "type": "consumable", "stat": "+30 HP", "icon": "🌿"},
{"name": "Iron Shield", "tier": "uncommon", "type": "armor", "stat": "+8 DEF", "icon": "🛡️"},
{"name": "Shadow Cloak", "tier": "uncommon", "type": "armor", "stat": "+5 DEF, +EVD", "icon": "🌑"},
{"name": "Throwing Stars", "tier": "uncommon", "type": "weapon", "stat": "+6 ATK", "icon": "⭐"},
{"name": "Smoke Bomb", "tier": "uncommon", "type": "consumable", "stat": "Stun enemy", "icon": "💨"},
{"name": "Lockpick Set", "tier": "uncommon", "type": "tool", "stat": "Open locks", "icon": "🔑"},
{"name": "Enchanted Rope", "tier": "rare", "type": "tool", "stat": "Escape trap", "icon": "🪢"},
{"name": "Arcane Scroll", "tier": "rare", "type": "consumable", "stat": "+50 HP + 25 DMG", "icon": "📜"},
{"name": "Rune Stone", "tier": "rare", "type": "misc", "stat": "+15 ATK (3 turns)", "icon": "🔮"},
{"name": "Bone Dagger", "tier": "rare", "type": "weapon", "stat": "+12 ATK, lifesteal", "icon": "🦴"},
{"name": "Ember Flask", "tier": "rare", "type": "consumable", "stat": "Burn enemy (3 turns)", "icon": "🔥"},
{"name": "Silver Sigil Ring", "tier": "rare", "type": "armor", "stat": "+10 DEF, magic resist", "icon": "💍"},
{"name": "Thornwood Staff", "tier": "epic", "type": "weapon", "stat": "+20 ATK, AOE", "icon": "🪄"},
{"name": "Crystal Prism", "tier": "epic", "type": "misc", "stat": "Reveal hidden paths", "icon": "💎"},
{"name": "Void Dagger", "tier": "epic", "type": "weapon", "stat": "+18 ATK, ignore DEF", "icon": "🌀"},
{"name": "Phantom Mantle", "tier": "epic", "type": "armor", "stat": "+15 DEF, 20% dodge", "icon": "👻"},
{"name": "Blood Vial", "tier": "epic", "type": "consumable", "stat": "Full HP restore", "icon": "🩸"},
{"name": "Orb of Zot", "tier": "legendary", "type": "misc", "stat": "+50 ATK, reveal boss weakness", "icon": "🌐"},
{"name": "Wraithblade", "tier": "legendary", "type": "weapon", "stat": "+35 ATK, drain soul", "icon": "⚔️"},
{"name": "Dragonscale Armor", "tier": "legendary", "type": "armor", "stat": "+30 DEF, fire immunity", "icon": "🐉"},
{"name": "Eternal Lantern", "tier": "legendary", "type": "misc", "stat": "Never lose HP to traps", "icon": "🏮"},
]
_TIER_WEIGHTS = {"common": 45, "uncommon": 28, "rare": 16, "epic": 8, "legendary": 3}
def roll_loot(n: int = 2) -> list[dict]:
"""Roll n loot items with weighted tier probability."""
pool_by_tier: dict[str, list[dict]] = {}
for item in LOOT_TABLE:
pool_by_tier.setdefault(item["tier"], []).append(item)
tiers = list(_TIER_WEIGHTS.keys())
weights = list(_TIER_WEIGHTS.values())
result = []
for _ in range(n):
tier = random.choices(tiers, weights=weights, k=1)[0]
result.append(random.choice(pool_by_tier[tier]))
return result