Lukeetah commited on
Commit
e927a21
·
verified ·
1 Parent(s): 16504f4

Upload 12 files

Browse files
.gitattributes CHANGED
@@ -2,6 +2,8 @@ packages.txt text eol=lf
2
  requirements.txt text eol=lf
3
  *.md text eol=lf
4
  bg_obelisco_1764982469642.png filter=lfs diff=lfs merge=lfs -text
 
5
  item_dolar_1764982497080.png filter=lfs diff=lfs merge=lfs -text
6
  item_mate_1764982483347.png filter=lfs diff=lfs merge=lfs -text
 
7
  vida_logo_1764982455490.png filter=lfs diff=lfs merge=lfs -text
 
2
  requirements.txt text eol=lf
3
  *.md text eol=lf
4
  bg_obelisco_1764982469642.png filter=lfs diff=lfs merge=lfs -text
5
+ icon_wine_1764982832885.png filter=lfs diff=lfs merge=lfs -text
6
  item_dolar_1764982497080.png filter=lfs diff=lfs merge=lfs -text
7
  item_mate_1764982483347.png filter=lfs diff=lfs merge=lfs -text
8
+ map_argentina_cyber_1764982818748.png filter=lfs diff=lfs merge=lfs -text
9
  vida_logo_1764982455490.png filter=lfs diff=lfs merge=lfs -text
app.py CHANGED
@@ -24,6 +24,27 @@ IMAGE_PATH = os.path.dirname(os.path.abspath(__file__))
24
  GAME_DATA_FILE = "vida_game_data.json"
25
  USER_SAVES_FILE = "vida_user_saves.json"
26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  class VidaGameEngine:
28
  def __init__(self):
29
  self.groq_client = Groq(api_key=GROQ_API_KEY) if GROQ_API_KEY else None
@@ -44,7 +65,6 @@ class VidaGameEngine:
44
  json.dump(self.users, f, ensure_ascii=False, indent=2)
45
 
46
  def update_news(self):
47
- # Noticias satíricas por defecto (Fallback)
48
  self.news_cache = [
49
  "El Presidente declara feriado nacional porque ganó Boca",
50
  "La inflación bajó 0.1% y el gobierno celebra con asado de polenta",
@@ -59,7 +79,6 @@ class VidaGameEngine:
59
  if res.status_code == 200:
60
  articles = res.json().get('articles', [])
61
  if articles:
62
- # Mezclar noticias reales para más realismo trágico
63
  self.news_cache = [a['title'] for a in articles]
64
  except: pass
65
 
@@ -67,10 +86,10 @@ class VidaGameEngine:
67
  user_id = hashlib.md5(name.encode()).hexdigest()[:8]
68
 
69
  base_stats = {
70
- "Estudiante": {"salary": 150000, "sanity": 100, "savings": 20000, "trait": "Joven e Inocente"},
71
- "Docente": {"salary": 450000, "sanity": 80, "savings": 40000, "trait": "Paciencia Infinita"},
72
- "Freelancer IT": {"salary": 1500000, "sanity": 60, "savings": 5000, "trait": "Cueva Lover"}, # Cobra un montón pero quema todo
73
- "Jubilado": {"salary": 200000, "sanity": 50, "savings": 100000, "trait": "Superviviente"}
74
  }
75
 
76
  stats = base_stats.get(profession, base_stats["Estudiante"])
@@ -82,7 +101,8 @@ class VidaGameEngine:
82
  "money": stats["savings"],
83
  "salary": stats["salary"],
84
  "sanity": stats["sanity"],
85
- "inventory": {"Mate": 0, "Dolar": 0},
 
86
  "status": "ALIVE"
87
  }
88
  self.save_users()
@@ -91,25 +111,34 @@ class VidaGameEngine:
91
  def get_user(self, user_id):
92
  return self.users.get(user_id)
93
 
 
 
 
 
 
 
 
 
 
 
 
94
  def generate_daily_event(self, user_id):
95
  user = self.get_user(user_id)
96
  if not user or user["status"] != "ALIVE":
97
  return None
98
 
99
- # Asegurar noticias
100
  if not self.news_cache: self.update_news()
101
  news_item = random.choice(self.news_cache)
 
102
 
103
- # Prompt Satírico
104
- system_prompt = """
105
- Eres el narrador de un juego satírico sobre Argentina.
106
- Genera un evento corto, absurdo pero plausible basado en la noticia.
107
- HUMOR NEGRO Y SARCASMO OBLIGATORIO.
108
- Dame 3 opciones:
109
- 1. La civica/correcta (pierde cordura, poco dinero).
110
- 2. La "viveza criolla" (gana dinero, pierde moral/cordura).
111
- 3. La absurda/desesperada (alto riesgo).
112
- JSON output: {text: str, options: [{text: str, cost_money: int, cost_sanity: int}]}
113
  """
114
  user_context = f"Rol: {user['profession']}, Plata: ${user['money']}, Cordura: {user['sanity']}%. Noticia: {news_item}"
115
 
@@ -128,11 +157,11 @@ class VidaGameEngine:
128
  raise Exception("No AI")
129
  except:
130
  event_data = {
131
- "text": f"Cadena Nacional: {news_item}. El caos reina. ¿Qué hacés?",
132
  "options": [
133
- {"text": "Aplaudo desde el balcón", "cost_money": 0, "cost_sanity": -15},
134
- {"text": "Compro dólares en la cueva", "cost_money": -50000, "cost_sanity": 10},
135
- {"text": "Me hago el muerto", "cost_money": -100, "cost_sanity": -5}
136
  ]
137
  }
138
 
@@ -142,68 +171,60 @@ class VidaGameEngine:
142
  user = self.get_user(user_id)
143
  selected_option = event_data["options"][option_idx]
144
 
145
- # Efectos
146
  user["money"] += selected_option.get("cost_money", 0)
147
  user["sanity"] += selected_option.get("cost_sanity", 0)
148
  user["days_survived"] += 1
149
 
150
- # Inflación y Cobro (cada 10 turnos para más ritmo)
151
- msg_extra = ""
152
- if user["days_survived"] % 10 == 0:
153
- inflation = random.uniform(0.10, 0.25)
154
- user["salary"] = int(user["salary"] * (1 + inflation * 0.4))
155
- renta = int(user["salary"] * 0.5)
156
- user["money"] -= renta
157
- user["money"] += user["salary"]
158
- msg_extra = f"\n\n¡COBRASTE! Pero el alquiler subió {int(inflation*100)}%. Pagaste ${renta}."
159
-
160
  # Game Over Checks
161
  game_over = False
162
  death_reason = ""
163
 
164
- if user["money"] < -50000: # Permitir un poco de deuda
165
  user["status"] = "BANKRUPT"
166
- death_reason = "Te embargaron hasta el perro. Game Over."
167
  game_over = True
168
  elif user["sanity"] <= 0:
169
- # Chance de salvación si tenés Mate
170
- if user["inventory"]["Mate"] > 0:
171
- user["inventory"]["Mate"] -= 1
172
- user["sanity"] = 20
173
- msg_extra += "\n\n¡Casi te volvés loco, pero un buen MATE te salvó!"
174
- else:
175
- user["status"] = "BURNED_OUT"
176
- death_reason = "Brote psicótico. Terminaste corriendo desnudo por la 9 de Julio."
177
- game_over = True
178
 
179
  self.save_users()
180
- return user, f"{selected_option['text']}. {msg_extra}", game_over, death_reason
181
 
182
- def buy_item(self, user_id, item):
183
  user = self.get_user(user_id)
184
- prices = {"Mate": 5000, "Dolar": 1200} # Dolar es 1 unidad (simbólico)
185
 
186
- if item not in prices: return "No existe eso che."
187
- price = prices[item]
 
188
 
189
- if user["money"] >= price:
190
- user["money"] -= price
191
- user["inventory"][item] = user["inventory"].get(item, 0) + 1
192
- self.save_users()
193
- return f"Compraste {item}!"
194
- return "No tenés plata. Andá a laburar."
195
-
196
- def use_item(self, user_id, item):
197
- user = self.get_user(user_id)
198
- if user["inventory"].get(item, 0) > 0:
199
- if item == "Mate":
 
 
 
 
 
 
 
 
 
 
200
  user["inventory"][item] -= 1
201
- user["sanity"] = min(100, user["sanity"] + 15)
202
  self.save_users()
203
- return "Tomaste unos mates. Recuperaste Cordura."
204
- elif item == "Dolar":
205
- return "Los dólares no se usan, se guardan bajo el colchón."
206
- return "No tenés eso."
207
 
208
  # --- ASSETS ---
209
  def get_img(name):
@@ -213,146 +234,133 @@ def get_img(name):
213
  # --- UI LOGIC ---
214
  game = VidaGameEngine()
215
 
216
- def ui_refresh_hud(user):
217
- if not user: return 0, 0, 0, 0, 0
218
- return (
219
- user['money'],
220
- user['sanity'],
221
- user['days_survived'],
222
- user['inventory'].get('Mate', 0),
223
- user['inventory'].get('Dolar', 0)
224
- )
225
-
226
- with gr.Blocks(theme=gr.themes.Monochrome(primary_hue="cyan", radius_size=gr.themes.sizes.radius_none)) as demo:
227
  state_uid = gr.State()
228
  state_event = gr.State()
229
 
230
  # HEADER
231
  with gr.Row():
232
  logo_img = get_img("vida_logo.png")
233
- if logo_img: gr.Image(logo_img, show_label=False, show_download_button=False, container=False, height=100)
234
- gr.Markdown("# 🇦🇷 VIDA 2.0: Cyber-Gaucho Edition")
235
 
236
  # CREATION
237
  with gr.Group(visible=True) as screen_creation:
238
- gr.Markdown("### Elegí tu destino")
239
  with gr.Row():
240
- name_input = gr.Textbox(label="Apodo")
241
- prof_input = gr.Radio(["Estudiante", "Docente", "Freelancer IT", "Jubilado"], label="Clase Social", value="Estudiante")
242
- start_btn = gr.Button("Nacer en Crisis", variant="primary")
243
 
244
- # GAME HUD
245
  with gr.Group(visible=False) as screen_game:
 
246
  with gr.Row(variant="panel"):
247
  with gr.Column(scale=1):
248
- gr.Image(get_img("item_dolar.png"), height=50, container=False, show_label=False)
249
- stat_money = gr.Number(label="Pesos", value=0)
250
  with gr.Column(scale=1):
251
- stat_sanity = gr.Number(label="Cordura", value=100)
252
  with gr.Column(scale=1):
253
- stat_days = gr.Number(label="Días", value=0)
254
  with gr.Column(scale=1):
255
- gr.Image(get_img("item_mate.png"), height=50, container=False, show_label=False)
256
- inv_mate = gr.Number(label="Mates", value=0)
257
- btn_drink_mate = gr.Button("Tomar Mate", size="sm")
258
 
259
- # EVENTO CENTRAL
260
  with gr.Row():
 
 
 
 
 
 
 
 
 
 
261
  with gr.Column(scale=2):
262
- bg_img = get_img("bg_obelisco.png")
263
- if bg_img: gr.Image(bg_img, show_label=False, container=False)
264
- with gr.Column(scale=3):
265
  event_display = gr.Markdown("...")
266
- btn_opt1 = gr.Button("Opción 1")
267
- btn_opt2 = gr.Button("Opción 2")
268
- btn_opt3 = gr.Button("Opción 3")
269
-
270
- # SHOP
271
- gr.Markdown("---")
272
- with gr.Row():
273
- gr.Markdown("### 🏪 El Kiosco")
274
- btn_buy_mate = gr.Button("Comprar Mate ($5000)")
275
- btn_buy_dolar = gr.Button("Comprar Dolar ($1200)")
276
- shop_log = gr.Markdown("")
 
 
 
 
277
 
278
- # GAME OVER
279
- with gr.Group(visible=False) as screen_death:
280
- death_msg = gr.Markdown("# 💀 TE MORISTE")
281
- restart_btn = gr.Button("Reencarnar sin aprender nada")
 
 
 
 
282
 
283
- # --- HANDLERS ---
284
  def on_start(n, p):
285
  if not n: return (None,)*15
286
  uid, u = game.create_character(n, p)
287
  evt = game.generate_daily_event(uid)
288
-
289
- m, s, d, i_m, i_d = ui_refresh_hud(u)
290
  opts = evt['options']
291
-
292
  return (
293
- uid, evt,
294
- gr.update(visible=False), gr.update(visible=True), gr.update(visible=False),
295
- m, s, d, i_m, i_d,
296
- f"### 📅 Día 1\n\n**{evt['text']}**",
297
- gr.update(value=f"{opts[0]['text']}"),
298
- gr.update(value=f"{opts[1]['text']}"),
299
- gr.update(value=f"{opts[2]['text']}")
300
  )
301
 
302
  start_btn.click(on_start, [name_input, prof_input],
303
- [state_uid, state_event, screen_creation, screen_game, screen_death,
304
- stat_money, stat_sanity, stat_days, inv_mate, gr.Dummy(), # Dolar hidden in state
305
  event_display, btn_opt1, btn_opt2, btn_opt3])
306
 
307
  def on_option(uid, evt, idx):
308
- user, log, dead, reason = game.process_turn(uid, idx, evt)
 
309
 
310
- if dead:
311
- return (
312
- evt,
313
- gr.update(visible=False), gr.update(visible=True),
314
- f"# 💀 {reason}\n\nSobreviviste {user['days_survived']} días.",
315
- 0,0,0,0,0,
316
- "", gr.update(), gr.update(), gr.update()
317
- )
318
-
319
  new_evt = game.generate_daily_event(uid)
320
- m, s, d, i_m, i_d = ui_refresh_hud(user)
321
  opts = new_evt['options']
 
322
 
323
  return (
324
  new_evt,
325
- gr.update(visible=True), gr.update(visible=False),
326
- "", # death msg
327
- m, s, d, i_m, i_d,
328
- f"### 📅 Día {d+1}\n\nConsequence: {log}\n\n---\n\n**{new_evt['text']}**",
329
- gr.update(value=f"{opts[0]['text']}"),
330
- gr.update(value=f"{opts[1]['text']}"),
331
- gr.update(value=f"{opts[2]['text']}")
332
  )
333
 
334
- btn_opt1.click(lambda u, e: on_option(u, e, 0), [state_uid, state_event], [state_event, screen_game, screen_death, death_msg, stat_money, stat_sanity, stat_days, inv_mate, gr.Dummy(), event_display, btn_opt1, btn_opt2, btn_opt3])
335
- btn_opt2.click(lambda u, e: on_option(u, e, 1), [state_uid, state_event], [state_event, screen_game, screen_death, death_msg, stat_money, stat_sanity, stat_days, inv_mate, gr.Dummy(), event_display, btn_opt1, btn_opt2, btn_opt3])
336
- btn_opt3.click(lambda u, e: on_option(u, e, 2), [state_uid, state_event], [state_event, screen_game, screen_death, death_msg, stat_money, stat_sanity, stat_days, inv_mate, gr.Dummy(), event_display, btn_opt1, btn_opt2, btn_opt3])
337
 
338
- def on_buy(uid, item):
339
- res = game.buy_item(uid, item)
340
- u = game.get_user(uid)
341
- m, s, d, i_m, i_d = ui_refresh_hud(u)
342
- return res, m, s, d, i_m, i_d
343
-
344
- btn_buy_mate.click(lambda u: on_buy(u, "Mate"), state_uid, [shop_log, stat_money, stat_sanity, stat_days, inv_mate, gr.Dummy()])
345
- btn_buy_dolar.click(lambda u: on_buy(u, "Dolar"), state_uid, [shop_log, stat_money, stat_sanity, stat_days, inv_mate, gr.Dummy()])
346
-
347
- def on_drink(uid):
348
- res = game.use_item(uid, "Mate")
349
- u = game.get_user(uid)
350
- m, s, d, i_m, i_d = ui_refresh_hud(u)
351
- return m, s, inv_mate, res
352
 
353
- btn_drink_mate.click(on_drink, state_uid, [stat_money, stat_sanity, inv_mate, shop_log])
354
-
355
- restart_btn.click(lambda: (gr.update(visible=True), gr.update(visible=False)), None, [screen_creation, screen_death])
 
 
 
 
 
 
356
 
357
  if __name__ == "__main__":
358
  demo.launch(server_name="0.0.0.0", server_port=7860)
 
24
  GAME_DATA_FILE = "vida_game_data.json"
25
  USER_SAVES_FILE = "vida_user_saves.json"
26
 
27
+ class Province:
28
+ def __init__(self, name, description, risk, trade_good, buy_price, sell_price, traits):
29
+ self.name = name
30
+ self.description = description
31
+ self.risk = risk # 0-100
32
+ self.trade_good = trade_good
33
+ self.buy_price = buy_price
34
+ self.sell_price = sell_price
35
+ self.traits = traits
36
+
37
+ PROVINCES = {
38
+ "CABA": Province("CABA", "La Ciudad de la Furia. Oportunidades y caos.",
39
+ risk=80, trade_good="Dolar", buy_price=1200, sell_price=1100, traits=["Political Hub", "Stress"]),
40
+ "Mendoza": Province("Mendoza", "Tierra del Sol y del Buen Vino.",
41
+ risk=30, trade_good="Vino", buy_price=2000, sell_price=5000, traits=["Relax", "Tourism"]),
42
+ "Cordoba": Province("Córdoba", "La República del Fernet. Humor y sierras.",
43
+ risk=40, trade_good="Fernet", buy_price=3000, sell_price=6000, traits=["Humor", "Mountains"]),
44
+ "Jujuy": Province("Jujuy", "El Norte Profundo. Litio y Pachamama.",
45
+ risk=50, trade_good="Litio", buy_price=100, sell_price=10000, traits=["Mining", "Culture"])
46
+ }
47
+
48
  class VidaGameEngine:
49
  def __init__(self):
50
  self.groq_client = Groq(api_key=GROQ_API_KEY) if GROQ_API_KEY else None
 
65
  json.dump(self.users, f, ensure_ascii=False, indent=2)
66
 
67
  def update_news(self):
 
68
  self.news_cache = [
69
  "El Presidente declara feriado nacional porque ganó Boca",
70
  "La inflación bajó 0.1% y el gobierno celebra con asado de polenta",
 
79
  if res.status_code == 200:
80
  articles = res.json().get('articles', [])
81
  if articles:
 
82
  self.news_cache = [a['title'] for a in articles]
83
  except: pass
84
 
 
86
  user_id = hashlib.md5(name.encode()).hexdigest()[:8]
87
 
88
  base_stats = {
89
+ "Estudiante": {"salary": 150000, "sanity": 100, "savings": 20000},
90
+ "Docente": {"salary": 450000, "sanity": 80, "savings": 40000},
91
+ "Freelancer IT": {"salary": 1500000, "sanity": 60, "savings": 5000},
92
+ "Jubilado": {"salary": 200000, "sanity": 50, "savings": 100000}
93
  }
94
 
95
  stats = base_stats.get(profession, base_stats["Estudiante"])
 
101
  "money": stats["savings"],
102
  "salary": stats["salary"],
103
  "sanity": stats["sanity"],
104
+ "inventory": {"Mate": 0, "Dolar": 0, "Vino": 0, "Fernet": 0, "Litio": 0},
105
+ "current_province": "CABA",
106
  "status": "ALIVE"
107
  }
108
  self.save_users()
 
111
  def get_user(self, user_id):
112
  return self.users.get(user_id)
113
 
114
+ def travel(self, user_id, destination):
115
+ user = self.get_user(user_id)
116
+ if user["money"] < 20000:
117
+ return "No tenés plata para el pasaje ($20.000).", False
118
+
119
+ user["money"] -= 20000
120
+ user["current_province"] = destination
121
+ user["days_survived"] += 1 # Viajar toma 1 día
122
+ self.save_users()
123
+ return f"Viajaste a {destination}.", True
124
+
125
  def generate_daily_event(self, user_id):
126
  user = self.get_user(user_id)
127
  if not user or user["status"] != "ALIVE":
128
  return None
129
 
 
130
  if not self.news_cache: self.update_news()
131
  news_item = random.choice(self.news_cache)
132
+ province = PROVINCES.get(user["current_province"], PROVINCES["CABA"])
133
 
134
+ # Prompt Regional
135
+ system_prompt = f"""
136
+ Eres el narrador de un juego de rol profundo en Argentina.
137
+ Provincia actual: {province.name} ({province.description}).
138
+ Genera un evento narrativo complejo basado en la noticia y la región.
139
+ Usa modismos locales (ej: si es CABA porteño, si es Cordoba cordobés).
140
+ Dame 3 opciones con consecuencias morales y económicas.
141
+ JSON output: {{text: str, options: [{{text: str, cost_money: int, cost_sanity: int}}]}}
 
 
142
  """
143
  user_context = f"Rol: {user['profession']}, Plata: ${user['money']}, Cordura: {user['sanity']}%. Noticia: {news_item}"
144
 
 
157
  raise Exception("No AI")
158
  except:
159
  event_data = {
160
+ "text": f"Estás en {province.name}. {news_item}. ¿Qué hacés?",
161
  "options": [
162
+ {"text": "Seguir sobreviviendo", "cost_money": -1000, "cost_sanity": -5},
163
+ {"text": "Buscar oportunidades", "cost_money": -5000, "cost_sanity": 5},
164
+ {"text": "Dormir", "cost_money": 0, "cost_sanity": 10}
165
  ]
166
  }
167
 
 
171
  user = self.get_user(user_id)
172
  selected_option = event_data["options"][option_idx]
173
 
 
174
  user["money"] += selected_option.get("cost_money", 0)
175
  user["sanity"] += selected_option.get("cost_sanity", 0)
176
  user["days_survived"] += 1
177
 
 
 
 
 
 
 
 
 
 
 
178
  # Game Over Checks
179
  game_over = False
180
  death_reason = ""
181
 
182
+ if user["money"] < -50000:
183
  user["status"] = "BANKRUPT"
184
+ death_reason = "Quiebra total. Terminaste vendiendo pañuelitos en el subte."
185
  game_over = True
186
  elif user["sanity"] <= 0:
187
+ user["status"] = "BURNED_OUT"
188
+ death_reason = "La locura te consumió."
189
+ game_over = True
 
 
 
 
 
 
190
 
191
  self.save_users()
192
+ return user, f"{selected_option['text']}", game_over, death_reason
193
 
194
+ def trade_item(self, user_id, action, item):
195
  user = self.get_user(user_id)
196
+ province = PROVINCES.get(user["current_province"], PROVINCES["CABA"])
197
 
198
+ # Precios dinámicos según provincia
199
+ buy_price = 5000 # Base
200
+ sell_price = 1000 # Base
201
 
202
+ # Regional goods
203
+ if item == province.trade_good:
204
+ buy_price = province.buy_price # Barato aquí
205
+ else:
206
+ buy_price = province.buy_price * 2 # Caro aquí (importado)
207
+
208
+ # Venta
209
+ if item == province.trade_good:
210
+ sell_price = province.sell_price / 2 # Vender lo local paga poco
211
+ else:
212
+ sell_price = province.sell_price # Vender lo de afuera paga mucho
213
+
214
+ if action == "buy":
215
+ if user["money"] >= buy_price:
216
+ user["money"] -= buy_price
217
+ user["inventory"][item] = user["inventory"].get(item, 0) + 1
218
+ self.save_users()
219
+ return f"Compraste {item} por ${buy_price}"
220
+ return "No tenés plata."
221
+ elif action == "sell":
222
+ if user["inventory"].get(item, 0) > 0:
223
  user["inventory"][item] -= 1
224
+ user["money"] += sell_price
225
  self.save_users()
226
+ return f"Vendiste {item} por ${sell_price}"
227
+ return "No tenés ese item."
 
 
228
 
229
  # --- ASSETS ---
230
  def get_img(name):
 
234
  # --- UI LOGIC ---
235
  game = VidaGameEngine()
236
 
237
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="cyan")) as demo:
 
 
 
 
 
 
 
 
 
 
238
  state_uid = gr.State()
239
  state_event = gr.State()
240
 
241
  # HEADER
242
  with gr.Row():
243
  logo_img = get_img("vida_logo.png")
244
+ if logo_img: gr.Image(logo_img, show_label=False, show_download_button=False, container=False, height=120)
245
+ gr.Markdown("# 🇦🇷 VIDA 3.0: Argentina Federal")
246
 
247
  # CREATION
248
  with gr.Group(visible=True) as screen_creation:
 
249
  with gr.Row():
250
+ name_input = gr.Textbox(label="Nombre")
251
+ prof_input = gr.Radio(["Estudiante", "Docente", "Freelancer IT", "Jubilado"], label="Rol", value="Estudiante")
252
+ start_btn = gr.Button("Iniciar Travesía", variant="primary")
253
 
254
+ # MAIN GAME
255
  with gr.Group(visible=False) as screen_game:
256
+ # HUD
257
  with gr.Row(variant="panel"):
258
  with gr.Column(scale=1):
259
+ cur_prov_disp = gr.Markdown("### 📍 Provincia: ...")
 
260
  with gr.Column(scale=1):
261
+ inv_money = gr.Number(label="Efectivo", value=0)
262
  with gr.Column(scale=1):
263
+ inv_sanity = gr.Number(label="Cordura", value=100)
264
  with gr.Column(scale=1):
265
+ inv_days = gr.Number(label="Días", value=0)
 
 
266
 
267
+ # CENTRAL AREA
268
  with gr.Row():
269
+ # MAP / TRAVEL
270
+ with gr.Column(scale=1):
271
+ map_img = get_img("map_argentina_cyber.png")
272
+ if map_img: gr.Image(map_img, show_label=False, container=False)
273
+ gr.Markdown("### ✈️ Viajar ($20.000)")
274
+ dest_dropdown = gr.Dropdown(list(PROVINCES.keys()), label="Destino")
275
+ btn_travel = gr.Button("Viajar")
276
+ travel_log = gr.Markdown("")
277
+
278
+ # EVENTS
279
  with gr.Column(scale=2):
 
 
 
280
  event_display = gr.Markdown("...")
281
+ btn_opt1 = gr.Button("...")
282
+ btn_opt2 = gr.Button("...")
283
+ btn_opt3 = gr.Button("...")
284
+
285
+ # MARKET
286
+ with gr.Column(scale=1):
287
+ gr.Markdown("### 📦 Mercado Regional")
288
+ gr.Image(get_img("icon_wine.png"), height=50, show_label=False, container=False)
289
+ with gr.Row():
290
+ btn_buy_wine = gr.Button("Comprar Vino")
291
+ btn_sell_wine = gr.Button("Vender Vino")
292
+ gr.Markdown("---")
293
+ inv_wine_disp = gr.Number(label="Vinos", value=0)
294
+ inv_lith_disp = gr.Number(label="Litio", value=0)
295
+ market_log = gr.Markdown("")
296
 
297
+ # HANDLERS
298
+ def refresh_ui(uid):
299
+ u = game.get_user(uid)
300
+ return (
301
+ f"### 📍 Provincia: {u['current_province']}",
302
+ u['money'], u['sanity'], u['days_survived'],
303
+ u['inventory'].get('Vino', 0), u['inventory'].get('Litio', 0)
304
+ )
305
 
 
306
  def on_start(n, p):
307
  if not n: return (None,)*15
308
  uid, u = game.create_character(n, p)
309
  evt = game.generate_daily_event(uid)
 
 
310
  opts = evt['options']
311
+ prov, m, s, d, i_w, i_l = refresh_ui(uid)
312
  return (
313
+ uid, evt,
314
+ gr.update(visible=False), gr.update(visible=True),
315
+ prov, m, s, d, i_w, i_l,
316
+ f"### 📰 Noticias: {evt['text']}",
317
+ gr.update(value=opts[0]['text']),
318
+ gr.update(value=opts[1]['text']),
319
+ gr.update(value=opts[2]['text'])
320
  )
321
 
322
  start_btn.click(on_start, [name_input, prof_input],
323
+ [state_uid, state_event, screen_creation, screen_game,
324
+ cur_prov_disp, inv_money, inv_sanity, inv_days, inv_wine_disp, inv_lith_disp,
325
  event_display, btn_opt1, btn_opt2, btn_opt3])
326
 
327
  def on_option(uid, evt, idx):
328
+ u, log, over, reason = game.process_turn(uid, idx, evt)
329
+ if over: return (evt, f"# 💀 {reason}", gr.update(visible=False), gr.update(visible=False), gr.update(visible=False)) # Lazy game over handling
330
 
 
 
 
 
 
 
 
 
 
331
  new_evt = game.generate_daily_event(uid)
 
332
  opts = new_evt['options']
333
+ prov, m, s, d, i_w, i_l = refresh_ui(uid)
334
 
335
  return (
336
  new_evt,
337
+ f"### 📅 Día {d}\n\nConsequence: {log}\n\n---\n\n**{new_evt['text']}**",
338
+ gr.update(value=opts[0]['text']),
339
+ gr.update(value=opts[1]['text']),
340
+ gr.update(value=opts[2]['text'])
 
 
 
341
  )
342
 
343
+ btn_opt1.click(lambda u, e: on_option(u, e, 0), [state_uid, state_event], [state_event, event_display, btn_opt1, btn_opt2, btn_opt3])
344
+ btn_opt2.click(lambda u, e: on_option(u, e, 1), [state_uid, state_event], [state_event, event_display, btn_opt1, btn_opt2, btn_opt3])
345
+ btn_opt3.click(lambda u, e: on_option(u, e, 2), [state_uid, state_event], [state_event, event_display, btn_opt1, btn_opt2, btn_opt3])
346
 
347
+ def on_travel(uid, dest):
348
+ if not dest: return "Elegí destino."
349
+ log, success = game.travel(uid, dest)
350
+ if success:
351
+ prov, m, s, d, i_w, i_l = refresh_ui(uid)
352
+ return log, prov, m, s, d
353
+ return log, gr.update(), gr.update(), gr.update(), gr.update()
 
 
 
 
 
 
 
354
 
355
+ btn_travel.click(on_travel, [state_uid, dest_dropdown], [travel_log, cur_prov_disp, inv_money, inv_sanity, inv_days])
356
+
357
+ def on_trade(uid, action, item):
358
+ log = game.trade_item(uid, action, item)
359
+ prov, m, s, d, i_w, i_l = refresh_ui(uid)
360
+ return log, m, i_w, i_l
361
+
362
+ btn_buy_wine.click(lambda u: on_trade(u, "buy", "Vino"), state_uid, [market_log, inv_money, inv_wine_disp, inv_lith_disp])
363
+ btn_sell_wine.click(lambda u: on_trade(u, "sell", "Vino"), state_uid, [market_log, inv_money, inv_wine_disp, inv_lith_disp])
364
 
365
  if __name__ == "__main__":
366
  demo.launch(server_name="0.0.0.0", server_port=7860)
icon_wine_1764982832885.png ADDED

Git LFS Details

  • SHA256: 507c193aa28581e55cd49782e5dbed2cf55d625fefc31477e1291382da24d942
  • Pointer size: 131 Bytes
  • Size of remote file: 521 kB
map_argentina_cyber_1764982818748.png ADDED

Git LFS Details

  • SHA256: 49a62be95356fb33e44c3a6988076e6ce9f3455b618d97175e0d736dfdcf30da
  • Pointer size: 131 Bytes
  • Size of remote file: 842 kB