kaiz / app.py
triett's picture
Update app.py
202dc27 verified
import gradio as gr
import random
import time
# ---------------- Cấu hình dữ liệu ----------------
MONSTERS = [
{"id":"slime","name":"Slime","base_hp":30,"xp":10,"gold":5, "arise":0.7},
{"id":"goblin","name":"Goblin","base_hp":45,"xp":18,"gold":12, "arise":0.5},
{"id":"elf","name":"Elf","base_hp":60,"xp":28,"gold":20, "arise":0.35},
{"id":"dragon","name":"Dragon","base_hp":160,"xp":220,"gold":150, "arise":0.05},
{"id":"king","name":"King","base_hp":220,"xp":330,"gold":240, "arise":0.08},
{"id":"beru","name":"Beru","base_hp":80,"xp":70,"gold":60, "arise":0.25},
{"id":"sjw","name":"Shadow Walker","base_hp":120,"xp":120,"gold":90, "arise":0.12},
]
SEEDS = [
{"id":"basic","name":"Hạt Thường","cost":10,"grow_time":3,"mut_rate":0.08},
{"id":"spark","name":"Hạt Sét","cost":30,"grow_time":4,"mut_rate":0.18},
{"id":"glow","name":"Hạt Lấp Lánh","cost":60,"grow_time":5,"mut_rate":0.32},
]
CARDS_POOL = [
{"name":"Flame Edge","desc":"Tăng dam +6","apply": lambda s: s.update({"attack": s["attack"]+6})},
{"name":"Swift Step","desc":"Tăng tốc độ, +1 atk","apply": lambda s: s.update({"attack": s["attack"]+1})},
{"name":"Nature's Guard","desc":"Khi HP<30% = +25% shield","apply": lambda s: s.update({"guard": True})},
{"name":"Mana Bloom","desc":"Tăng mana regen","apply": lambda s: s.update({"mana_regen": s.get("mana_regen",0.0)+0.5})},
]
# ---------------- Hàm phụ trợ ----------------
def choose_monster_for_floor(floor):
pool = []
for m in MONSTERS:
weight = 1.0
if m["id"] in ("slime","goblin"):
weight = max(1.0, 6 - floor//2)
else:
weight = 1.0 + floor/6
pool.append((m, weight))
total = sum(w for _,w in pool)
r = random.random()*total
upto = 0
for m,w in pool:
if upto + w >= r:
return dict(m)
upto += w
return dict(MONSTERS[0])
def fmt_status(state):
p = state["player"]
return f"Cấp {p['level']} · HP {p['hp']}/{p['hp_max']} · XP {p['xp']}/{p['xp_needed']} · Vàng {p['gold']} · Pet: {p['pet']['name'] if p['pet'] else 'Không'}"
def add_log(state, text):
state["log"].append(f"[{time.strftime('%H:%M:%S')}] {text}")
if len(state["log"]) > 200:
state["log"].pop(0)
def default_state():
return {
"player": {
"level":1, "xp":0, "hp_max":100, "hp":100, "attack":10, "gold":50,
"hp_regen":0.0, "mana":50, "mana_max":50,
"xp_needed":100, "skills":[], "pet": None
},
"dungeon": {"in_dungeon": False, "dungeon_name": None, "floor": 0, "monster": None},
"farm": {"plots": []},
"shop": {"seeds": SEEDS},
"log": [],
"inventory": [],
"pending_cards": []
}
# ---------------- Game logic ----------------
def start_dungeon(state, dungeon_name):
state["dungeon"]["in_dungeon"] = True
state["dungeon"]["dungeon_name"] = dungeon_name
state["dungeon"]["floor"] = 1
m = choose_monster_for_floor(1)
m["hp"] = m["base_hp"] + state["player"]["level"]*3
state["dungeon"]["monster"] = m
add_log(state, f"Vào phó bản {dungeon_name} - Tầng 1. Thử thách: {m['name']}")
return fmt_status(state), "\n".join(state["log"][-10:])
def attack(state):
if not state["dungeon"]["in_dungeon"]:
add_log(state, "Bạn chưa vào phó bản.")
return fmt_status(state), "\n".join(state["log"][-10:])
m = state["dungeon"]["monster"]
p = state["player"]
pet_bonus = p["pet"]["attack"]//2 if p["pet"] else 0
dmg = random.randint(max(1,p["attack"]-3), p["attack"]+3) + pet_bonus
m["hp"] -= dmg
add_log(state, f"Tấn công {m['name']} gây {dmg} sát thương. (Pet +{pet_bonus})")
if m["hp"] <= 0:
xp = m["xp"] + state["dungeon"]["floor"]*2
gold = m["gold"] + state["dungeon"]["floor"]
p["xp"] += xp
p["gold"] += gold
add_log(state, f"{m['name']} bị hạ! +{xp} XP, +{gold} vàng.")
if state["dungeon"]["floor"] == 10 and random.random() < m.get("arise", 0.0):
pet = {"name": f"Pet {m['name']}", "attack": max(3, m["base_hp"]//10), "tier":"common"}
p["pet"] = pet
add_log(state, f"✨ {m['name']} đã arise! Trở thành pet: {pet['name']}")
if state["dungeon"]["floor"] >= 10:
add_log(state, f"Hoàn thành phó bản {state['dungeon']['dungeon_name']}! Về thị trấn.")
state["dungeon"] = {"in_dungeon": False, "dungeon_name": None, "floor": 0, "monster": None}
p["hp"] = min(p["hp_max"], p["hp"] + 20)
else:
state["dungeon"]["floor"] += 1
m2 = choose_monster_for_floor(state["dungeon"]["floor"])
m2["hp"] = m2["base_hp"] + p["level"]*3 + state["dungeon"]["floor"]*2
state["dungeon"]["monster"] = m2
add_log(state, f"Tầng {state['dungeon']['floor']}: Quái {m2['name']}")
while p["xp"] >= p["xp_needed"]:
p["xp"] -= p["xp_needed"]
p["level"] += 1
p["hp_max"] += 15
p["attack"] += 2
p["hp"] = p["hp_max"]
p["xp_needed"] = int(p["xp_needed"] * 1.4)
add_log(state, f"⭐ Lên cấp {p['level']}! Chọn 1 thẻ bài.")
return fmt_status(state), "\n".join(state["log"][-12:])
else:
mdmg = random.randint(max(1, m["xp"]//6), max(1, m["xp"]//4)) + int(state["dungeon"]["floor"]/2)
p["hp"] -= mdmg
add_log(state, f"{m['name']} phản công gây {mdmg} sát thương!")
if p["hp"] <= 0:
add_log(state, "⚠️ Bạn đã tử vong! Mất 10% vàng.")
p["hp"] = int(p["hp_max"]*0.6)
p["gold"] = max(0, int(p["gold"]*0.9))
state["dungeon"] = {"in_dungeon": False, "dungeon_name": None, "floor": 0, "monster": None}
return fmt_status(state), "\n".join(state["log"][-12:])
def choose_card_flow(state):
pick = random.sample(CARDS_POOL, 3)
state["pending_cards"] = pick
add_log(state, "