triett commited on
Commit
202dc27
·
verified ·
1 Parent(s): 3a8c237

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +27 -219
app.py CHANGED
@@ -1,9 +1,8 @@
1
- # app.py
2
  import gradio as gr
3
  import random
4
  import time
5
 
6
- # ---------------- Config / Data ----------------
7
  MONSTERS = [
8
  {"id":"slime","name":"Slime","base_hp":30,"xp":10,"gold":5, "arise":0.7},
9
  {"id":"goblin","name":"Goblin","base_hp":45,"xp":18,"gold":12, "arise":0.5},
@@ -27,13 +26,11 @@ CARDS_POOL = [
27
  {"name":"Mana Bloom","desc":"Tăng mana regen","apply": lambda s: s.update({"mana_regen": s.get("mana_regen",0.0)+0.5})},
28
  ]
29
 
30
- # ---------------- Helpers ----------------
31
  def choose_monster_for_floor(floor):
32
- """Scale monster by floor: higher floor -> rarer monsters"""
33
  pool = []
34
  for m in MONSTERS:
35
  weight = 1.0
36
- # basic scaling: dragons/kings rarer but appear at high floors
37
  if m["id"] in ("slime","goblin"):
38
  weight = max(1.0, 6 - floor//2)
39
  else:
@@ -50,35 +47,29 @@ def choose_monster_for_floor(floor):
50
 
51
  def fmt_status(state):
52
  p = state["player"]
53
- s = 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'}"
54
- return s
55
 
56
  def add_log(state, text):
57
  state["log"].append(f"[{time.strftime('%H:%M:%S')}] {text}")
58
- if len(state["log"])>200: state["log"].pop(0)
 
59
 
60
- # ---------------- Initialize state ----------------
61
  def default_state():
62
  return {
63
- "player":{
64
  "level":1, "xp":0, "hp_max":100, "hp":100, "attack":10, "gold":50,
65
  "hp_regen":0.0, "mana":50, "mana_max":50,
66
  "xp_needed":100, "skills":[], "pet": None
67
  },
68
- "dungeon": {
69
- "in_dungeon": False,
70
- "dungeon_name": None,
71
- "floor": 0,
72
- "monster": None,
73
- },
74
- "farm": {
75
- "plots": [], # each: {"seed_id":..., "ready_at":time_offset, "mutated":False, "quality":...}
76
- },
77
  "shop": {"seeds": SEEDS},
78
  "log": [],
 
 
79
  }
80
 
81
- # ---------------- Game actions ----------------
82
  def start_dungeon(state, dungeon_name):
83
  state["dungeon"]["in_dungeon"] = True
84
  state["dungeon"]["dungeon_name"] = dungeon_name
@@ -91,48 +82,34 @@ def start_dungeon(state, dungeon_name):
91
 
92
  def attack(state):
93
  if not state["dungeon"]["in_dungeon"]:
94
- add_log(state, "Bạn chưa vào phó bản. Vui lòng chọn 'Chọn phó bản'.")
95
  return fmt_status(state), "\n".join(state["log"][-10:])
96
  m = state["dungeon"]["monster"]
97
  p = state["player"]
98
- # pet assists
99
- pet_bonus = 0
100
- if p["pet"]:
101
- pet_bonus = p["pet"]["attack"]//2
102
  dmg = random.randint(max(1,p["attack"]-3), p["attack"]+3) + pet_bonus
103
  m["hp"] -= dmg
104
- add_log(state, f"Bạn tấn công {m['name']} gây {dmg} sát thương. (Pet +{pet_bonus})")
105
  if m["hp"] <= 0:
106
  xp = m["xp"] + state["dungeon"]["floor"]*2
107
  gold = m["gold"] + state["dungeon"]["floor"]
108
  p["xp"] += xp
109
  p["gold"] += gold
110
- add_log(state, f"{m['name']} bị hạ! +{xp} XP, +{gold} gold.")
111
- # chance to arise as pet (on boss floors)
112
- if state["dungeon"]["floor"] == 10:
113
- ar = m.get("arise", 0.0)
114
- if random.random() < ar:
115
- pet = {"name": f"Pet {m['name']}", "attack": max(3, m["base_hp"]//10), "tier":"common"}
116
- p["pet"] = pet
117
- add_log(state, f"✨ {m['name']} đã arise! Trở thành pet của bạn: {pet['name']}")
118
- # next floor
119
  if state["dungeon"]["floor"] >= 10:
120
- # finished dungeon
121
  add_log(state, f"Hoàn thành phó bản {state['dungeon']['dungeon_name']}! Về thị trấn.")
122
- state["dungeon"]["in_dungeon"] = False
123
- state["dungeon"]["monster"] = None
124
- state["dungeon"]["floor"] = 0
125
- # back to town: minor heal
126
  p["hp"] = min(p["hp_max"], p["hp"] + 20)
127
  else:
128
- # go to next floor
129
  state["dungeon"]["floor"] += 1
130
  m2 = choose_monster_for_floor(state["dungeon"]["floor"])
131
- m2["hp"] = m2["base_hp"] + state["player"]["level"]*3 + state["dungeon"]["floor"]*2
132
  state["dungeon"]["monster"] = m2
133
- add_log(state, f"Bước sang tầng {state['dungeon']['floor']}. Quái: {m2['name']}")
134
- # check level up
135
- level_up_msgs = ""
136
  while p["xp"] >= p["xp_needed"]:
137
  p["xp"] -= p["xp_needed"]
138
  p["level"] += 1
@@ -140,189 +117,20 @@ def attack(state):
140
  p["attack"] += 2
141
  p["hp"] = p["hp_max"]
142
  p["xp_needed"] = int(p["xp_needed"] * 1.4)
143
- add_log(state, f"⭐ Bạn đã lên cấp {p['level']}! Chọn 1 thẻ bài.")
144
- level_up_msgs += "LEVEL_UP\n"
145
  return fmt_status(state), "\n".join(state["log"][-12:])
146
  else:
147
- # monster attacks back
148
- mdmg = random.randint(max(1, m["xp"]//6), max(1, m["xp"]//4))
149
- # small scale with floor
150
- mdmg = int(mdmg + state["dungeon"]["floor"]/2)
151
  p["hp"] -= mdmg
152
  add_log(state, f"{m['name']} phản công gây {mdmg} sát thương!")
153
  if p["hp"] <= 0:
154
- add_log(state, "⚠️ Bạn đã tử vong! Quay về thị trấn và mất 10% vàng.")
155
  p["hp"] = int(p["hp_max"]*0.6)
156
  p["gold"] = max(0, int(p["gold"]*0.9))
157
- state["dungeon"]["in_dungeon"] = False
158
- state["dungeon"]["monster"] = None
159
- state["dungeon"]["floor"] = 0
160
  return fmt_status(state), "\n".join(state["log"][-12:])
161
 
162
  def choose_card_flow(state):
163
- # produce 3 random cards (copies)
164
  pick = random.sample(CARDS_POOL, 3)
165
  state["pending_cards"] = pick
166
- add_log(state, "Hiện 3 thẻ bài ngẫu nhiên - chọn 1 thẻ để áp dụng.")
167
- return [f"{c['name']}: {c['desc']}" for c in pick], "\n".join(state["log"][-8:])
168
-
169
- def apply_card(state, idx):
170
- pick = state.get("pending_cards")
171
- if not pick or idx<0 or idx>=len(pick):
172
- return "Không có thẻ để chọn.", "\n".join(state["log"][-6:])
173
- card = pick[idx]
174
- # apply card effect by calling its lambda (we store callable in pool)
175
- # Note: CARDS_POOL entries have apply: lambda s: s.update(...)
176
- # Here pick's item is same object
177
- try:
178
- card["apply"](state["player"])
179
- state["player"]["skills"].append(card["name"])
180
- except Exception as e:
181
- add_log(state, f"Lỗi khi áp dụng thẻ: {e}")
182
- add_log(state, f"Bạn chọn thẻ: {card['name']}. Hiệu ứng đã áp dụng.")
183
- state["pending_cards"] = []
184
- return fmt_status(state), "\n".join(state["log"][-8:])
185
-
186
- # ---------------- Farming ----------------
187
- def plant_seed(state, seed_id):
188
- seeds = state["shop"]["seeds"]
189
- s = next((x for x in seeds if x["id"]==seed_id), None)
190
- if not s:
191
- return "Hạt giống không hợp lệ.", "\n".join(state["log"][-8:])
192
- player = state["player"]
193
- if player["gold"] < s["cost"]:
194
- return "Không đủ vàng để mua hạt.", "\n".join(state["log"][-8:])
195
- player["gold"] -= s["cost"]
196
- # simulate grow_time by storing a counter (we'll use integer tick simulation)
197
- plot = {"seed_id": seed_id, "seed_name": s["name"], "grow_time": s["grow_time"], "remaining": s["grow_time"], "mutated": False, "quality":1}
198
- state["farm"]["plots"].append(plot)
199
- add_log(state, f"Mua và trồng {s['name']}. Thời gian chờ: {s['grow_time']} tick.")
200
- return f"Trồng {s['name']} thành công.", "\n".join(state["log"][-8:])
201
-
202
- def tick_grow(state):
203
- # called when user 'waits' or acts: reduce remaining for each plot
204
- for p in state["farm"]["plots"]:
205
- if p["remaining"]>0:
206
- p["remaining"] -= 1
207
- if p["remaining"]<=0:
208
- # finish, determine mutation by seed base mut_rate
209
- seed = next((x for x in SEEDS if x["name"]==p["seed_name"] or x["id"]==p["seed_id"]), None)
210
- base = seed["mut_rate"] if seed else 0.05
211
- if random.random() < base:
212
- p["mutated"] = True
213
- p["quality"] = random.randint(2,4)
214
- add_log(state, f"🌱 Cây {p['seed_name']} biến dị! Chất lượng {p['quality']}.")
215
- else:
216
- p["mutated"] = False
217
- p["quality"] = 1
218
- add_log(state, f"🌿 Cây {p['seed_name']} thu hoạch bình thường.")
219
- return "Đã tiến hành 1 tick thời gian.", "\n".join(state["log"][-8:])
220
-
221
- def harvest_plot(state, idx):
222
- if idx<0 or idx>=len(state["farm"]["plots"]):
223
- return "Không có ô trồng này.", "\n".join(state["log"][-8:])
224
- plot = state["farm"]["plots"].pop(idx)
225
- reward_xp = 5 * plot["quality"]
226
- # mutated gives special item (mutation fruit)
227
- if plot["mutated"]:
228
- item = {"type":"mutation","power":plot["quality"], "name":f"Mutation {plot['seed_name']}"}
229
- state.setdefault("inventory", []).append(item)
230
- add_log(state, f"Thu hoạch: {plot['seed_name']} (Mutation!). Đã nhận 1 Mutation.")
231
- else:
232
- state["player"]["gold"] += 8*plot["quality"]
233
- add_log(state, f"Thu hoạch: {plot['seed_name']}. Nhận {8*plot['quality']} vàng.")
234
- state["player"]["xp"] += reward_xp
235
- add_log(state, f"Nhận thêm +{reward_xp} XP từ thu hoạch.")
236
- return fmt_status(state), "\n".join(state["log"][-10:])
237
-
238
- def feed_mutation(state, inv_idx):
239
- inv = state.get("inventory", [])
240
- if inv_idx<0 or inv_idx>=len(inv):
241
- return "Không có item này.", "\n".join(state["log"][-8:])
242
- item = inv.pop(inv_idx)
243
- if item["type"]!="mutation":
244
- return "Chỉ có Mutation mới cho ăn.", "\n".join(state["log"][-8:])
245
- # feeding: add XP scaled by power and chance to learn skill
246
- gain_xp = item["power"] * 25
247
- state["player"]["xp"] += gain_xp
248
- learned = False
249
- if random.random() < 0.25 * item["power"]:
250
- new_skill = f"MutSkill_{random.randint(100,999)}"
251
- state["player"]["skills"].append(new_skill)
252
- learned = True
253
- add_log(state, f"🎉 Nhân vật học được kỹ năng mới từ mutation: {new_skill}!")
254
- add_log(state, f"Bạn cho nhân vật ăn {item['name']} -> +{gain_xp} XP. {'(Learned skill!)' if learned else ''}")
255
- return fmt_status(state), "\n".join(state["log"][-8:])
256
-
257
- # ---------------- Shop ----------------
258
- def buy_seed(state, seed_id):
259
- s = next((x for x in SEEDS if x["id"]==seed_id), None)
260
- if not s:
261
- return "Hạt không hợp lệ.", "\n".join(state["log"][-6:])
262
- if state["player"]["gold"] < s["cost"]:
263
- return "Không đủ vàng.", "\n".join(state["log"][-6:])
264
- state["player"]["gold"] -= s["cost"]
265
- state.setdefault("seed_bag", []).append(s)
266
- add_log(state, f"Mua {s['name']} x1.")
267
- return f"Mua {s['name']} thành công.", "\n".join(state["log"][-6:])
268
-
269
- # ---------------- UI / Gradio ----------------
270
- with gr.Blocks(title="Adias: Arise & Mutation (Demo)") as demo:
271
- gr.Markdown("## 🏞️ Adias — Arise & Mutation (Mini demo)")
272
- # state
273
- state = gr.State(default_state())
274
-
275
- col1 = gr.Column(scale=2)
276
- col2 = gr.Column(scale=1)
277
-
278
- with gr.Row():
279
- with col1:
280
- gr.Markdown("### 🔹 Thị Trấn (Menu)")
281
- dungeon_select = gr.Dropdown([ "Slime Cave","Goblin Den","Elf Forest","Dragon Lair","King's Trial" ], label="Chọn phó bản")
282
- start_btn = gr.Button("🗡️ Vào phó bản")
283
- attack_btn = gr.Button("⚔️ Tấn công (Trong dungeon)")
284
- tick_btn = gr.Button("⏳ Thời gian trôi 1 tick (farm)")
285
- harvest_btn = gr.Button("🌾 Thu hoạch ô đầu")
286
- cards_btn = gr.Button("🃏 Lấy 3 thẻ bài (nếu có lvl up)")
287
- buy_seed_btn = gr.Button("🛒 Mua Hạt Thường (10 gold)")
288
- buy_spark_btn = gr.Button("🛒 Mua Hạt Sét (30 gold)")
289
- buy_glow_btn = gr.Button("🛒 Mua Hạt Lấp Lánh (60 gold)")
290
- feed_btn = gr.Button("🍎 Cho ăn Mutation (ô 0 trong inventory)")
291
-
292
- status_box = gr.Textbox(label="Trạng thái", lines=1, interactive=False)
293
- log_box = gr.Textbox(label="Log", lines=12, interactive=False)
294
- inv_box = gr.Textbox(label="Inventory (index: item)", lines=3, interactive=False)
295
-
296
- with col2:
297
- gr.Markdown("### 🧾 Hồ sơ nhân vật")
298
- panel = gr.HTML("<div id='panel'></div>")
299
- stats_box = gr.Textbox(label="Thông tin nhân vật", lines=8, interactive=False)
300
-
301
- # callbacks
302
- def refresh_ui(state):
303
- st = fmt_status(state)
304
- status = st
305
- logs = "\n".join(state["log"][-12:])
306
- inv = state.get("inventory", [])
307
- inv_text = "\n".join([f"{i}. {it['name']} (power {it.get('power')})" for i,it in enumerate(inv)]) if inv else "Rỗng"
308
- stats = f"Cấp: {state['player']['level']}\nHP: {state['player']['hp']}/{state['player']['hp_max']}\nATK: {state['player']['attack']}\nGold: {state['player']['gold']}\nSkills: {', '.join(state['player']['skills']) if state['player']['skills'] else 'None'}\nPet: {state['player']['pet']['name'] if state['player']['pet'] else 'Không'}"
309
- return status, logs, inv_text, stats
310
-
311
- start_btn.click(lambda s, d: start_dungeon(s, d), inputs=[state, dungeon_select], outputs=[status_box, log_box])
312
- attack_btn.click(lambda s: attack(s), inputs=[state], outputs=[status_box, log_box])
313
- tick_btn.click(lambda s: tick_grow(s), inputs=[state], outputs=[status_box, log_box])
314
- harvest_btn.click(lambda s: harvest_plot(s, 0), inputs=[state], outputs=[status_box, log_box])
315
- cards_btn.click(lambda s: choose_card_flow(s), inputs=[state], outputs=[gr.Dropdown.update(choices=[]), log_box]) # placeholder
316
- buy_seed_btn.click(lambda s: buy_seed(s, "basic"), inputs=[state], outputs=[log_box, status_box])
317
- buy_spark_btn.click(lambda s: buy_seed(s, "spark"), inputs=[state], outputs=[log_box, status_box])
318
- buy_glow_btn.click(lambda s: buy_seed(s, "glow"), inputs=[state], outputs=[log_box, status_box])
319
- feed_btn.click(lambda s: feed_mutation(s, 0), inputs=[state], outputs=[status_box, log_box])
320
-
321
- # small refresh button to show state
322
- refresh = gr.Button("🔄 Refresh UI")
323
- refresh.click(lambda s: refresh_ui(s), inputs=[state], outputs=[status_box, log_box, inv_box, stats_box])
324
-
325
- # initial fill
326
- demo.load(lambda s: refresh_ui(s), inputs=[state], outputs=[status_box, log_box, inv_box, stats_box])
327
-
328
- demo.launch()
 
 
1
  import gradio as gr
2
  import random
3
  import time
4
 
5
+ # ---------------- Cấu hình dữ liệu ----------------
6
  MONSTERS = [
7
  {"id":"slime","name":"Slime","base_hp":30,"xp":10,"gold":5, "arise":0.7},
8
  {"id":"goblin","name":"Goblin","base_hp":45,"xp":18,"gold":12, "arise":0.5},
 
26
  {"name":"Mana Bloom","desc":"Tăng mana regen","apply": lambda s: s.update({"mana_regen": s.get("mana_regen",0.0)+0.5})},
27
  ]
28
 
29
+ # ---------------- Hàm phụ trợ ----------------
30
  def choose_monster_for_floor(floor):
 
31
  pool = []
32
  for m in MONSTERS:
33
  weight = 1.0
 
34
  if m["id"] in ("slime","goblin"):
35
  weight = max(1.0, 6 - floor//2)
36
  else:
 
47
 
48
  def fmt_status(state):
49
  p = state["player"]
50
+ 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'}"
 
51
 
52
  def add_log(state, text):
53
  state["log"].append(f"[{time.strftime('%H:%M:%S')}] {text}")
54
+ if len(state["log"]) > 200:
55
+ state["log"].pop(0)
56
 
 
57
  def default_state():
58
  return {
59
+ "player": {
60
  "level":1, "xp":0, "hp_max":100, "hp":100, "attack":10, "gold":50,
61
  "hp_regen":0.0, "mana":50, "mana_max":50,
62
  "xp_needed":100, "skills":[], "pet": None
63
  },
64
+ "dungeon": {"in_dungeon": False, "dungeon_name": None, "floor": 0, "monster": None},
65
+ "farm": {"plots": []},
 
 
 
 
 
 
 
66
  "shop": {"seeds": SEEDS},
67
  "log": [],
68
+ "inventory": [],
69
+ "pending_cards": []
70
  }
71
 
72
+ # ---------------- Game logic ----------------
73
  def start_dungeon(state, dungeon_name):
74
  state["dungeon"]["in_dungeon"] = True
75
  state["dungeon"]["dungeon_name"] = dungeon_name
 
82
 
83
  def attack(state):
84
  if not state["dungeon"]["in_dungeon"]:
85
+ add_log(state, "Bạn chưa vào phó bản.")
86
  return fmt_status(state), "\n".join(state["log"][-10:])
87
  m = state["dungeon"]["monster"]
88
  p = state["player"]
89
+ pet_bonus = p["pet"]["attack"]//2 if p["pet"] else 0
 
 
 
90
  dmg = random.randint(max(1,p["attack"]-3), p["attack"]+3) + pet_bonus
91
  m["hp"] -= dmg
92
+ add_log(state, f"Tấn công {m['name']} gây {dmg} sát thương. (Pet +{pet_bonus})")
93
  if m["hp"] <= 0:
94
  xp = m["xp"] + state["dungeon"]["floor"]*2
95
  gold = m["gold"] + state["dungeon"]["floor"]
96
  p["xp"] += xp
97
  p["gold"] += gold
98
+ add_log(state, f"{m['name']} bị hạ! +{xp} XP, +{gold} vàng.")
99
+ if state["dungeon"]["floor"] == 10 and random.random() < m.get("arise", 0.0):
100
+ pet = {"name": f"Pet {m['name']}", "attack": max(3, m["base_hp"]//10), "tier":"common"}
101
+ p["pet"] = pet
102
+ add_log(state, f"✨ {m['name']} đã arise! Trở thành pet: {pet['name']}")
 
 
 
 
103
  if state["dungeon"]["floor"] >= 10:
 
104
  add_log(state, f"Hoàn thành phó bản {state['dungeon']['dungeon_name']}! Về thị trấn.")
105
+ state["dungeon"] = {"in_dungeon": False, "dungeon_name": None, "floor": 0, "monster": None}
 
 
 
106
  p["hp"] = min(p["hp_max"], p["hp"] + 20)
107
  else:
 
108
  state["dungeon"]["floor"] += 1
109
  m2 = choose_monster_for_floor(state["dungeon"]["floor"])
110
+ m2["hp"] = m2["base_hp"] + p["level"]*3 + state["dungeon"]["floor"]*2
111
  state["dungeon"]["monster"] = m2
112
+ add_log(state, f"Tầng {state['dungeon']['floor']}: Quái {m2['name']}")
 
 
113
  while p["xp"] >= p["xp_needed"]:
114
  p["xp"] -= p["xp_needed"]
115
  p["level"] += 1
 
117
  p["attack"] += 2
118
  p["hp"] = p["hp_max"]
119
  p["xp_needed"] = int(p["xp_needed"] * 1.4)
120
+ add_log(state, f"⭐ Lên cấp {p['level']}! Chọn 1 thẻ bài.")
 
121
  return fmt_status(state), "\n".join(state["log"][-12:])
122
  else:
123
+ mdmg = random.randint(max(1, m["xp"]//6), max(1, m["xp"]//4)) + int(state["dungeon"]["floor"]/2)
 
 
 
124
  p["hp"] -= mdmg
125
  add_log(state, f"{m['name']} phản công gây {mdmg} sát thương!")
126
  if p["hp"] <= 0:
127
+ add_log(state, "⚠️ Bạn đã tử vong! Mất 10% vàng.")
128
  p["hp"] = int(p["hp_max"]*0.6)
129
  p["gold"] = max(0, int(p["gold"]*0.9))
130
+ state["dungeon"] = {"in_dungeon": False, "dungeon_name": None, "floor": 0, "monster": None}
 
 
131
  return fmt_status(state), "\n".join(state["log"][-12:])
132
 
133
  def choose_card_flow(state):
 
134
  pick = random.sample(CARDS_POOL, 3)
135
  state["pending_cards"] = pick
136
+ add_log(state, "