ui.screens
ui/screens.py
Interfaz visual del juego.
Incluye:
- Mapa interactivo de cámaras.
- Visualización de habitaciones y linterna.
- Pantallas de Game Over, historia, introducción e instrucciones.
- Selección de dificultad.
1""" 2ui/screens.py 3 4Interfaz visual del juego. 5 6Incluye: 7- Mapa interactivo de cámaras. 8- Visualización de habitaciones y linterna. 9- Pantallas de Game Over, historia, introducción e instrucciones. 10- Selección de dificultad. 11""" 12 13 14import os 15import time 16import msvcrt 17import warnings 18from threading import Thread 19 20from colorama import Fore, init, Style 21 22from utils.utils import limpiar_pantalla, reproducir_sonido, cargar_plantilla_archivo 23from core.energy import barra_energia 24import core.config as estado 25from core.animatronics import animatronics 26from core.movement import mover_animatronico, detener_todos_los_canales 27 28init(autoreset=True) 29 30# Ignorar warnings de Pygame 31os.environ['PYGAME_HIDE_SUPPORT_PROMPT'] = "hide" 32warnings.filterwarnings("ignore", category=UserWarning) 33 34import pygame 35pygame.init() 36 37 38# -------------------------- MAPA Y CÁMARAS -------------------------- # 39def mostrar_mapa(camara_seleccionada): 40 """ 41 Muestra en pantalla el mapa de cámaras interactivo, resaltando la cámara seleccionada. 42 43 Args: 44 camara_seleccionada (int): Número de cámara actualmente seleccionada. 45 """ 46 limpiar_pantalla() 47 def cam_texto(numero): 48 texto = f"CAM 0{numero}" 49 return Fore.RED + texto + Style.RESET_ALL if camara_seleccionada == numero else texto 50 51 print("\r" + barra_energia(), end="", flush=True) 52 print(Fore.LIGHTYELLOW_EX + f"\nHora: {estado.horas[estado.hora_actual]}\n") 53 print(Fore.LIGHTWHITE_EX + f""" 54 ╔══════════╗ 55 ╔══════╣ {cam_texto(2)} ╠════════════╗ 56 ║ ╚══════════╝ ║ 57 ╔═╩══════╗ ╔═════╩══╗ 58 ╔══════╣ ║ ╔════════════╗ ║ ║ 59 ╔══╩═════╗║ {cam_texto(6)} ╠══╣ {cam_texto(1)} ╠═╣ {cam_texto(3)} ╠══╗ 60 ║ ║║ ║ ╚════════╦═══╝ ║ ║ ║ 61 ║ {cam_texto(7)} ║╚══╦═════╝ ║ ╚═╦═══╦══╝ ║ 62 ║ ║ ║ ╔════════╗ ║ ║ ║ ║ 63 ╚══╦═════╝ ╚═════╣ {cam_texto(5)} ╠══╩═══════╝ ║ ║ 64 ║ ╚════════╝ ╠═════╝ 65 ║ ╔═════════════════╗ ║ 66 ╚═══════════╣ {cam_texto(4)} ╠═════════╝ 67 ╚════╦══════╦═════╝ 68 ╔══╝ ╚══╗ 69 ║ ╔════╗ ║ 70 ╚═══╣ CG ╠═══╝ 71 ╚════╝ 72 """) 73 print("Presiona 'Q' para salir") 74 75 76def mapa_interactivo(): 77 """ 78 Muestra el mapa interactivo de cámaras y permite navegación. 79 Controla refresco de pantalla, batería y sincronización con stop_event. 80 """ 81 camaras_disponibles = [1, 2, 3, 4, 5, 6, 7] 82 indice = 0 83 camara_seleccionada = camaras_disponibles[indice] 84 ultimo_refresco = time.time() 85 86 mostrar_mapa(camara_seleccionada) 87 88 while not estado.stop_event.is_set(): 89 # Refresco automático 90 if time.time() - ultimo_refresco >= estado.config["tiempo_avanzar_hora"]: 91 mostrar_mapa(camara_seleccionada) 92 ultimo_refresco = time.time() 93 94 # Entrada de usuario 95 if msvcrt.kbhit(): 96 if estado.stop_event.is_set(): 97 break 98 tecla = msvcrt.getch() 99 100 if tecla == b'\xe0': 101 flecha = msvcrt.getch() 102 if flecha in [b'H', b'M']: # Arriba/derecha 103 indice = (indice + 1) % len(camaras_disponibles) 104 elif flecha in [b'P', b'K']: # Abajo/izquierda 105 indice = (indice - 1) % len(camaras_disponibles) 106 camara_seleccionada = camaras_disponibles[indice] 107 mostrar_mapa(camara_seleccionada) 108 109 elif tecla == b'\r': # Enter 110 if estado.energia_actual <= 0: 111 print(Fore.RED + "\n¡Sin batería! No podés usar cámaras.") 112 estado.energia_actual = 0 113 time.sleep(1.5) 114 else: 115 mostrar_habitacion(camara_seleccionada) 116 mostrar_mapa(camara_seleccionada) 117 118 elif tecla in [b'q', b'Q']: 119 estado.stop_event.set() 120 print("Saliendo del juego...") 121 time.sleep(2) 122 detener_todos_los_canales() 123 limpiar_pantalla() 124 break 125 126 127def mostrar_habitacion(numero: int): 128 """ 129 Muestra la cámara seleccionada y permite interacción con linterna. 130 131 Args: 132 numero (int): Número de la cámara. 133 """ 134 if estado.energia_actual <= 0: 135 print(Fore.RED + "¡Sin batería! No podés usar cámaras.") 136 time.sleep(2) 137 return 138 139 estado.energia_actual -= estado.config["energia_uso_camara"] 140 estado.energia_actual = max(0, estado.energia_actual) 141 142 reproducir_sonido(estado.config["sonido_camara"], canal=estado.canal_interface) 143 limpiar_pantalla() 144 print(Fore.CYAN + f"[ Cámara {numero:02d} - {estado.habitaciones[numero]} ]\n") 145 146 anim_presentes = [n for n, a in animatronics.items() if a.posicion == numero] 147 plantilla = cargar_plantilla_archivo(numero, anim_presentes) 148 for linea in plantilla: 149 print(Fore.WHITE + linea.rstrip("\n")) 150 151 spawn_owners = [n for n, a in animatronics.items() if a.spawn == numero] 152 anim_own = any(owner in anim_presentes for owner in spawn_owners) 153 todos_son_duenios = all(anim in spawn_owners for anim in anim_presentes) 154 155 if not todos_son_duenios and anim_own: 156 print(Fore.YELLOW + "\n¡Animatrónico detectado! Presiona 'F' para usar la linterna.") 157 if input("\n> ").strip().upper() == 'F': 158 usar_linterna(anim_presentes, spawn_owners[0]) 159 elif todos_son_duenios and anim_presentes: 160 print(Fore.RED + "\n¡Linterna Desactivada!") 161 input("\nPresiona Enter para volver.") 162 elif not anim_own and anim_presentes: 163 print(Fore.YELLOW + "\n¡Animatrónico detectado! Presiona 'F' para usar la linterna.") 164 if input("\n> ").strip().upper() == 'F': 165 usar_linterna(anim_presentes, None) 166 else: 167 if estado.energia_actual <= 0: 168 print(Fore.RED + "\nSin batería. No podés usar cámaras.") 169 time.sleep(2) 170 else: 171 print(Fore.CYAN + "\nPresiona Enter para volver.") 172 input() 173 174 175def usar_linterna(anim_presentes: list, spawn_owner=None): 176 """ 177 Simula el uso de la linterna para retroceder animatrónicos no dueños del spawn. 178 179 Args: 180 anim_presentes (list): Animatrónicos presentes. 181 spawn_owner (str, optional): Animatrónico dueño del spawn. 182 """ 183 if estado.energia_actual <= 0: 184 print(Fore.RED + "¡Sin batería! La linterna no funciona.") 185 time.sleep(1) 186 return 187 188 estado.energia_actual -= estado.config["energia_uso_linterna"] 189 estado.energia_actual = max(0, estado.energia_actual) 190 191 print(Fore.GREEN + "¡Usaste la linterna!") 192 for nombre in anim_presentes: 193 if nombre != spawn_owner: 194 animatronics[nombre].regresar_spawn() 195 print(Fore.GREEN + f"{animatronics[nombre].cara} {nombre} regresó a su posición inicial.") 196 time.sleep(1) 197 198 199# -------------------------- GAME OVER -------------------------- # 200def pantalla_game_over(nombre: str): 201 """ 202 Muestra la pantalla de Game Over, reproduciendo sonidos y ASCII art. 203 204 Args: 205 nombre (str): Animatrónico responsable del Game Over. 206 """ 207 anim = animatronics[nombre] 208 detener_todos_los_canales() 209 210 reproducir_sonido(estado.config["sonido_powerdown"]) 211 while pygame.mixer.music.get_busy(): 212 time.sleep(0.1) 213 214 reproducir_sonido(anim.cancion_muerte) 215 while pygame.mixer.music.get_busy(): 216 time.sleep(0.1) 217 218 reproducir_sonido(estado.config["sonido_jumpscare"]) 219 time.sleep(1.5) 220 221 estado.stop_event.set() 222 estado.juego_activo = False 223 limpiar_pantalla() 224 ancho = 80 225 226 mensaje = [ 227 Fore.RED + Style.BRIGHT + f"¡{nombre.upper()} ENTRÓ A LA OFICINA!".center(ancho), 228 "", 229 Fore.MAGENTA + Style.BRIGHT + " ██████╗ █████╗ ███╗ ███╗ ███████╗ ██████╗ ██╗ ██╗ ███████╗ ██████╗ ", 230 Fore.MAGENTA + Style.BRIGHT + " ██╔════╝ ██╔══██╗ ████╗ ████║ ██╔════╝ ██╔═══██╗ ██║ ██║ ██╔════╝ ██╔══██╗", 231 Fore.MAGENTA + Style.BRIGHT + " ██║ ███╗ ███████║ ██╔████╔██║ █████╗ ██║ ██║ ██║ ██║ █████╗ ██████╔╝", 232 Fore.MAGENTA + Style.BRIGHT + " ██║ ██║ ██╔══██║ ██║╚██╔╝██║ ██╔══╝ ██║ ██║ ███╗ ███║ ██╔══╝ ██╔══██╗", 233 Fore.MAGENTA + Style.BRIGHT + " ╚██████╔╝ ██║ ██║ ██║ ╚═╝ ██║ ███████╗ ╚██████╔╝ ╚═████╔═╝ ███████╗ ██║ ██║", 234 Fore.MAGENTA + Style.BRIGHT + " ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═══╝ ╚══════╝ ╚═╝ ╚═╝" 235 ] 236 237 for linea in mensaje: 238 print(linea) 239 time.sleep(0.3) 240 241 time.sleep(2) 242 print(Fore.YELLOW + "Volviendo al menú principal...".center(ancho)) 243 time.sleep(1) 244 from ui.menu import menu_principal 245 menu_principal() 246 247 248# ------------------------------ INTRO ------------------------------ # 249def intro(): 250 """Reproduce la introducción de audio y luego inicia el movimiento de los animatrónicos.""" 251 reproducir_sonido(estado.config["intro"]) 252 while pygame.mixer.music.get_busy(): 253 time.sleep(0.1) 254 255 for nombre in animatronics: 256 Thread(target=mover_animatronico, args=(nombre,), daemon=True).start() 257 258 259# -------------------------- INSTRUCCIONES -------------------------- # 260def mostrar_instrucciones(): 261 """Muestra las instrucciones del juego en consola.""" 262 limpiar_pantalla() 263 print("\n════════════════════════════════════════") 264 print(Style.BRIGHT + Fore.MAGENTA + "📜 INSTRUCCIONES 📜".center(38)) 265 print("════════════════════════════════════════\n") 266 267 print(Style.BRIGHT + Fore.WHITE + "- Usa las flechas " + Fore.CYAN + "↑ ↓ ← →" + Fore.WHITE + " para moverte por el mapa.\n") 268 print(Fore.WHITE + "- Tu objetivo es " + Fore.RED + "sobrevivir la noche" + Fore.WHITE + " vigilando las cámaras.\n") 269 print(Fore.WHITE + "- Observa los movimientos de los animatrónicos.\n") 270 print(Fore.WHITE + "- Usa la " + Fore.LIGHTYELLOW_EX + "linterna" + Fore.WHITE + " para espantarlos.\n") 271 print(Fore.WHITE + "- Si un animatrónico entra en la oficina... " + Fore.RED + Style.BRIGHT + "GAME OVER!\n") 272 input(Fore.GREEN + "\nPresiona Enter para volver al menú.") 273 274 275# -------------------------- DIFICULTAD -------------------------- # 276def seleccionar_dificultad(): 277 """ 278 Muestra un menú interactivo para seleccionar la dificultad del juego. 279 280 Permite elegir entre NORMAL, DIFÍCIL, PESADILLA o VOLVER al menú principal. 281 Cada dificultad modifica: 282 - Velocidad de avance de las horas. 283 - Consumo de energía por linterna. 284 - Consumo de energía por uso de cámara. 285 286 Controles: 287 - Flechas arriba/abajo: navegan entre las opciones. 288 - Enter: confirma la selección. 289 290 Variables globales: 291 estado.config (dict): Diccionario con los parámetros de configuración. 292 """ 293 opciones = ["NORMAL", "DIFÍCIL", "PESADILLA", "VOLVER"] 294 colores = [Fore.GREEN, Fore.YELLOW, Fore.MAGENTA, Fore.WHITE] 295 ancho_pantalla = 60 296 seleccion = 0 297 298 while True: 299 limpiar_pantalla() 300 301 # Título del menú 302 print(Style.BRIGHT + Fore.WHITE + """ 303 304 ███╗ ███╗ ██████╗ ██████╗ ██████╗ ███████╗ 305 ████╗ ████║ ██╔═══██╗ ██╔══██╗ ██╔═══██╗ ██╔════╝ 306 ██╔████╔██║ ██║ ██║ ██║ ██║ ██║ ██║ ███████╗ 307 ██║╚██╔╝██║ ██║ ██║ ██║ ██║ ██║ ██║ ╚════██║ 308 ██║ ╚═╝ ██║ ╚██████╔╝ ██████╔╝ ╚██████╔╝ ███████║ 309 ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ 310 """) 311 312 # Mostrar opciones con la selección actual 313 for i, opcion in enumerate(opciones): 314 flecha = ">> " if i == seleccion else " " 315 linea = flecha + opcion 316 print("\n" + colores[i] + linea.center(ancho_pantalla)) 317 318 # Lectura de teclas 319 tecla = msvcrt.getch() 320 321 if tecla == b'\xe0': # Flechas 322 flecha = msvcrt.getch() 323 if flecha == b'H': # Arriba 324 seleccion = (seleccion - 1) % len(opciones) 325 elif flecha == b'P': # Abajo 326 seleccion = (seleccion + 1) % len(opciones) 327 elif tecla == b'\r': # Enter 328 if seleccion == 0: # NORMAL 329 estado.config.update({ 330 "tiempo_avanzar_hora": 60, 331 "energia_uso_linterna": 5, 332 "energia_uso_camara": 2, 333 "dificultad": "NORMAL" 334 }) 335 elif seleccion == 1: # DIFÍCIL 336 estado.config.update({ 337 "tiempo_avanzar_hora": 120, 338 "energia_uso_linterna": 3, 339 "energia_uso_camara": 1.5, 340 "dificultad": "DIFICIL" 341 }) 342 elif seleccion == 2: # PESADILLA 343 estado.config.update({ 344 "tiempo_avanzar_hora": 225, 345 "energia_uso_linterna": 2, 346 "energia_uso_camara": 1, 347 "dificultad": "PESADILLA" 348 }) 349 elif seleccion == 3: # VOLVER 350 from ui.menu import menu_principal 351 menu_principal() 352 return 353 time.sleep(1) 354 return
40def mostrar_mapa(camara_seleccionada): 41 """ 42 Muestra en pantalla el mapa de cámaras interactivo, resaltando la cámara seleccionada. 43 44 Args: 45 camara_seleccionada (int): Número de cámara actualmente seleccionada. 46 """ 47 limpiar_pantalla() 48 def cam_texto(numero): 49 texto = f"CAM 0{numero}" 50 return Fore.RED + texto + Style.RESET_ALL if camara_seleccionada == numero else texto 51 52 print("\r" + barra_energia(), end="", flush=True) 53 print(Fore.LIGHTYELLOW_EX + f"\nHora: {estado.horas[estado.hora_actual]}\n") 54 print(Fore.LIGHTWHITE_EX + f""" 55 ╔══════════╗ 56 ╔══════╣ {cam_texto(2)} ╠════════════╗ 57 ║ ╚══════════╝ ║ 58 ╔═╩══════╗ ╔═════╩══╗ 59 ╔══════╣ ║ ╔════════════╗ ║ ║ 60 ╔══╩═════╗║ {cam_texto(6)} ╠══╣ {cam_texto(1)} ╠═╣ {cam_texto(3)} ╠══╗ 61 ║ ║║ ║ ╚════════╦═══╝ ║ ║ ║ 62 ║ {cam_texto(7)} ║╚══╦═════╝ ║ ╚═╦═══╦══╝ ║ 63 ║ ║ ║ ╔════════╗ ║ ║ ║ ║ 64 ╚══╦═════╝ ╚═════╣ {cam_texto(5)} ╠══╩═══════╝ ║ ║ 65 ║ ╚════════╝ ╠═════╝ 66 ║ ╔═════════════════╗ ║ 67 ╚═══════════╣ {cam_texto(4)} ╠═════════╝ 68 ╚════╦══════╦═════╝ 69 ╔══╝ ╚══╗ 70 ║ ╔════╗ ║ 71 ╚═══╣ CG ╠═══╝ 72 ╚════╝ 73 """) 74 print("Presiona 'Q' para salir")
Muestra en pantalla el mapa de cámaras interactivo, resaltando la cámara seleccionada.
Args: camara_seleccionada (int): Número de cámara actualmente seleccionada.
77def mapa_interactivo(): 78 """ 79 Muestra el mapa interactivo de cámaras y permite navegación. 80 Controla refresco de pantalla, batería y sincronización con stop_event. 81 """ 82 camaras_disponibles = [1, 2, 3, 4, 5, 6, 7] 83 indice = 0 84 camara_seleccionada = camaras_disponibles[indice] 85 ultimo_refresco = time.time() 86 87 mostrar_mapa(camara_seleccionada) 88 89 while not estado.stop_event.is_set(): 90 # Refresco automático 91 if time.time() - ultimo_refresco >= estado.config["tiempo_avanzar_hora"]: 92 mostrar_mapa(camara_seleccionada) 93 ultimo_refresco = time.time() 94 95 # Entrada de usuario 96 if msvcrt.kbhit(): 97 if estado.stop_event.is_set(): 98 break 99 tecla = msvcrt.getch() 100 101 if tecla == b'\xe0': 102 flecha = msvcrt.getch() 103 if flecha in [b'H', b'M']: # Arriba/derecha 104 indice = (indice + 1) % len(camaras_disponibles) 105 elif flecha in [b'P', b'K']: # Abajo/izquierda 106 indice = (indice - 1) % len(camaras_disponibles) 107 camara_seleccionada = camaras_disponibles[indice] 108 mostrar_mapa(camara_seleccionada) 109 110 elif tecla == b'\r': # Enter 111 if estado.energia_actual <= 0: 112 print(Fore.RED + "\n¡Sin batería! No podés usar cámaras.") 113 estado.energia_actual = 0 114 time.sleep(1.5) 115 else: 116 mostrar_habitacion(camara_seleccionada) 117 mostrar_mapa(camara_seleccionada) 118 119 elif tecla in [b'q', b'Q']: 120 estado.stop_event.set() 121 print("Saliendo del juego...") 122 time.sleep(2) 123 detener_todos_los_canales() 124 limpiar_pantalla() 125 break
Muestra el mapa interactivo de cámaras y permite navegación. Controla refresco de pantalla, batería y sincronización con stop_event.
128def mostrar_habitacion(numero: int): 129 """ 130 Muestra la cámara seleccionada y permite interacción con linterna. 131 132 Args: 133 numero (int): Número de la cámara. 134 """ 135 if estado.energia_actual <= 0: 136 print(Fore.RED + "¡Sin batería! No podés usar cámaras.") 137 time.sleep(2) 138 return 139 140 estado.energia_actual -= estado.config["energia_uso_camara"] 141 estado.energia_actual = max(0, estado.energia_actual) 142 143 reproducir_sonido(estado.config["sonido_camara"], canal=estado.canal_interface) 144 limpiar_pantalla() 145 print(Fore.CYAN + f"[ Cámara {numero:02d} - {estado.habitaciones[numero]} ]\n") 146 147 anim_presentes = [n for n, a in animatronics.items() if a.posicion == numero] 148 plantilla = cargar_plantilla_archivo(numero, anim_presentes) 149 for linea in plantilla: 150 print(Fore.WHITE + linea.rstrip("\n")) 151 152 spawn_owners = [n for n, a in animatronics.items() if a.spawn == numero] 153 anim_own = any(owner in anim_presentes for owner in spawn_owners) 154 todos_son_duenios = all(anim in spawn_owners for anim in anim_presentes) 155 156 if not todos_son_duenios and anim_own: 157 print(Fore.YELLOW + "\n¡Animatrónico detectado! Presiona 'F' para usar la linterna.") 158 if input("\n> ").strip().upper() == 'F': 159 usar_linterna(anim_presentes, spawn_owners[0]) 160 elif todos_son_duenios and anim_presentes: 161 print(Fore.RED + "\n¡Linterna Desactivada!") 162 input("\nPresiona Enter para volver.") 163 elif not anim_own and anim_presentes: 164 print(Fore.YELLOW + "\n¡Animatrónico detectado! Presiona 'F' para usar la linterna.") 165 if input("\n> ").strip().upper() == 'F': 166 usar_linterna(anim_presentes, None) 167 else: 168 if estado.energia_actual <= 0: 169 print(Fore.RED + "\nSin batería. No podés usar cámaras.") 170 time.sleep(2) 171 else: 172 print(Fore.CYAN + "\nPresiona Enter para volver.") 173 input()
Muestra la cámara seleccionada y permite interacción con linterna.
Args: numero (int): Número de la cámara.
176def usar_linterna(anim_presentes: list, spawn_owner=None): 177 """ 178 Simula el uso de la linterna para retroceder animatrónicos no dueños del spawn. 179 180 Args: 181 anim_presentes (list): Animatrónicos presentes. 182 spawn_owner (str, optional): Animatrónico dueño del spawn. 183 """ 184 if estado.energia_actual <= 0: 185 print(Fore.RED + "¡Sin batería! La linterna no funciona.") 186 time.sleep(1) 187 return 188 189 estado.energia_actual -= estado.config["energia_uso_linterna"] 190 estado.energia_actual = max(0, estado.energia_actual) 191 192 print(Fore.GREEN + "¡Usaste la linterna!") 193 for nombre in anim_presentes: 194 if nombre != spawn_owner: 195 animatronics[nombre].regresar_spawn() 196 print(Fore.GREEN + f"{animatronics[nombre].cara} {nombre} regresó a su posición inicial.") 197 time.sleep(1)
Simula el uso de la linterna para retroceder animatrónicos no dueños del spawn.
Args: anim_presentes (list): Animatrónicos presentes. spawn_owner (str, optional): Animatrónico dueño del spawn.
201def pantalla_game_over(nombre: str): 202 """ 203 Muestra la pantalla de Game Over, reproduciendo sonidos y ASCII art. 204 205 Args: 206 nombre (str): Animatrónico responsable del Game Over. 207 """ 208 anim = animatronics[nombre] 209 detener_todos_los_canales() 210 211 reproducir_sonido(estado.config["sonido_powerdown"]) 212 while pygame.mixer.music.get_busy(): 213 time.sleep(0.1) 214 215 reproducir_sonido(anim.cancion_muerte) 216 while pygame.mixer.music.get_busy(): 217 time.sleep(0.1) 218 219 reproducir_sonido(estado.config["sonido_jumpscare"]) 220 time.sleep(1.5) 221 222 estado.stop_event.set() 223 estado.juego_activo = False 224 limpiar_pantalla() 225 ancho = 80 226 227 mensaje = [ 228 Fore.RED + Style.BRIGHT + f"¡{nombre.upper()} ENTRÓ A LA OFICINA!".center(ancho), 229 "", 230 Fore.MAGENTA + Style.BRIGHT + " ██████╗ █████╗ ███╗ ███╗ ███████╗ ██████╗ ██╗ ██╗ ███████╗ ██████╗ ", 231 Fore.MAGENTA + Style.BRIGHT + " ██╔════╝ ██╔══██╗ ████╗ ████║ ██╔════╝ ██╔═══██╗ ██║ ██║ ██╔════╝ ██╔══██╗", 232 Fore.MAGENTA + Style.BRIGHT + " ██║ ███╗ ███████║ ██╔████╔██║ █████╗ ██║ ██║ ██║ ██║ █████╗ ██████╔╝", 233 Fore.MAGENTA + Style.BRIGHT + " ██║ ██║ ██╔══██║ ██║╚██╔╝██║ ██╔══╝ ██║ ██║ ███╗ ███║ ██╔══╝ ██╔══██╗", 234 Fore.MAGENTA + Style.BRIGHT + " ╚██████╔╝ ██║ ██║ ██║ ╚═╝ ██║ ███████╗ ╚██████╔╝ ╚═████╔═╝ ███████╗ ██║ ██║", 235 Fore.MAGENTA + Style.BRIGHT + " ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═══╝ ╚══════╝ ╚═╝ ╚═╝" 236 ] 237 238 for linea in mensaje: 239 print(linea) 240 time.sleep(0.3) 241 242 time.sleep(2) 243 print(Fore.YELLOW + "Volviendo al menú principal...".center(ancho)) 244 time.sleep(1) 245 from ui.menu import menu_principal 246 menu_principal()
Muestra la pantalla de Game Over, reproduciendo sonidos y ASCII art.
Args: nombre (str): Animatrónico responsable del Game Over.
250def intro(): 251 """Reproduce la introducción de audio y luego inicia el movimiento de los animatrónicos.""" 252 reproducir_sonido(estado.config["intro"]) 253 while pygame.mixer.music.get_busy(): 254 time.sleep(0.1) 255 256 for nombre in animatronics: 257 Thread(target=mover_animatronico, args=(nombre,), daemon=True).start()
Reproduce la introducción de audio y luego inicia el movimiento de los animatrónicos.
261def mostrar_instrucciones(): 262 """Muestra las instrucciones del juego en consola.""" 263 limpiar_pantalla() 264 print("\n════════════════════════════════════════") 265 print(Style.BRIGHT + Fore.MAGENTA + "📜 INSTRUCCIONES 📜".center(38)) 266 print("════════════════════════════════════════\n") 267 268 print(Style.BRIGHT + Fore.WHITE + "- Usa las flechas " + Fore.CYAN + "↑ ↓ ← →" + Fore.WHITE + " para moverte por el mapa.\n") 269 print(Fore.WHITE + "- Tu objetivo es " + Fore.RED + "sobrevivir la noche" + Fore.WHITE + " vigilando las cámaras.\n") 270 print(Fore.WHITE + "- Observa los movimientos de los animatrónicos.\n") 271 print(Fore.WHITE + "- Usa la " + Fore.LIGHTYELLOW_EX + "linterna" + Fore.WHITE + " para espantarlos.\n") 272 print(Fore.WHITE + "- Si un animatrónico entra en la oficina... " + Fore.RED + Style.BRIGHT + "GAME OVER!\n") 273 input(Fore.GREEN + "\nPresiona Enter para volver al menú.")
Muestra las instrucciones del juego en consola.
277def seleccionar_dificultad(): 278 """ 279 Muestra un menú interactivo para seleccionar la dificultad del juego. 280 281 Permite elegir entre NORMAL, DIFÍCIL, PESADILLA o VOLVER al menú principal. 282 Cada dificultad modifica: 283 - Velocidad de avance de las horas. 284 - Consumo de energía por linterna. 285 - Consumo de energía por uso de cámara. 286 287 Controles: 288 - Flechas arriba/abajo: navegan entre las opciones. 289 - Enter: confirma la selección. 290 291 Variables globales: 292 estado.config (dict): Diccionario con los parámetros de configuración. 293 """ 294 opciones = ["NORMAL", "DIFÍCIL", "PESADILLA", "VOLVER"] 295 colores = [Fore.GREEN, Fore.YELLOW, Fore.MAGENTA, Fore.WHITE] 296 ancho_pantalla = 60 297 seleccion = 0 298 299 while True: 300 limpiar_pantalla() 301 302 # Título del menú 303 print(Style.BRIGHT + Fore.WHITE + """ 304 305 ███╗ ███╗ ██████╗ ██████╗ ██████╗ ███████╗ 306 ████╗ ████║ ██╔═══██╗ ██╔══██╗ ██╔═══██╗ ██╔════╝ 307 ██╔████╔██║ ██║ ██║ ██║ ██║ ██║ ██║ ███████╗ 308 ██║╚██╔╝██║ ██║ ██║ ██║ ██║ ██║ ██║ ╚════██║ 309 ██║ ╚═╝ ██║ ╚██████╔╝ ██████╔╝ ╚██████╔╝ ███████║ 310 ╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═════╝ ╚══════╝ 311 """) 312 313 # Mostrar opciones con la selección actual 314 for i, opcion in enumerate(opciones): 315 flecha = ">> " if i == seleccion else " " 316 linea = flecha + opcion 317 print("\n" + colores[i] + linea.center(ancho_pantalla)) 318 319 # Lectura de teclas 320 tecla = msvcrt.getch() 321 322 if tecla == b'\xe0': # Flechas 323 flecha = msvcrt.getch() 324 if flecha == b'H': # Arriba 325 seleccion = (seleccion - 1) % len(opciones) 326 elif flecha == b'P': # Abajo 327 seleccion = (seleccion + 1) % len(opciones) 328 elif tecla == b'\r': # Enter 329 if seleccion == 0: # NORMAL 330 estado.config.update({ 331 "tiempo_avanzar_hora": 60, 332 "energia_uso_linterna": 5, 333 "energia_uso_camara": 2, 334 "dificultad": "NORMAL" 335 }) 336 elif seleccion == 1: # DIFÍCIL 337 estado.config.update({ 338 "tiempo_avanzar_hora": 120, 339 "energia_uso_linterna": 3, 340 "energia_uso_camara": 1.5, 341 "dificultad": "DIFICIL" 342 }) 343 elif seleccion == 2: # PESADILLA 344 estado.config.update({ 345 "tiempo_avanzar_hora": 225, 346 "energia_uso_linterna": 2, 347 "energia_uso_camara": 1, 348 "dificultad": "PESADILLA" 349 }) 350 elif seleccion == 3: # VOLVER 351 from ui.menu import menu_principal 352 menu_principal() 353 return 354 time.sleep(1) 355 return
Muestra un menú interactivo para seleccionar la dificultad del juego.
Permite elegir entre NORMAL, DIFÍCIL, PESADILLA o VOLVER al menú principal. Cada dificultad modifica: - Velocidad de avance de las horas. - Consumo de energía por linterna. - Consumo de energía por uso de cámara.
Controles: - Flechas arriba/abajo: navegan entre las opciones. - Enter: confirma la selección.
Variables globales: estado.config (dict): Diccionario con los parámetros de configuración.