Untitled
unknown
plain_text
a year ago
20 kB
11
Indexable
import random
import tkinter as tk
from tkinter import simpledialog, font
try:
from PIL import Image, ImageTk
PIL_OK = True
except Exception:
PIL_OK = False
# ==============================
# INTERFACE (Tkinter)
# ==============================
class GameUI:
def __init__(self):
self.root = tk.Tk()
self.root.title("RPG Livro-Jogo — Ruínas de Nhar")
self.root.geometry("1000x650")
self.root.minsize(860, 580)
# --- Fundo com arte ---
self.canvas = tk.Canvas(self.root, highlightthickness=0)
self.canvas.pack(fill="both", expand=True)
self.bg_img = None
if PIL_OK:
try:
from PIL import Image
img = Image.open("background.jpg")
self._orig_bg = img
except Exception:
self._orig_bg = None
else:
self._orig_bg = None
self.root.bind("<Configure>", self._on_resize)
# --- Fonte custom / fallback ---
self.font_size = 16
try:
self.custom_font = font.Font(file="medieval.ttf", size=self.font_size)
except Exception:
self.custom_font = font.Font(family="Georgia", size=self.font_size)
# --- Área de texto (com scrollbar) ---
self.text_frame = tk.Frame(self.root, bg="#00000000")
self.text_win = self.canvas.create_window(
0, 0, anchor="nw", window=self.text_frame
)
self.text = tk.Text(
self.text_frame,
wrap="word",
bg="#151515",
fg="#f7f1e3",
insertbackground="white",
font=self.custom_font,
relief="flat",
padx=14,
pady=14,
)
self.scroll = tk.Scrollbar(self.text_frame, command=self.text.yview)
self.text.configure(yscrollcommand=self.scroll.set)
self.text.grid(row=0, column=0, sticky="nsew")
self.scroll.grid(row=0, column=1, sticky="ns")
self.text_frame.grid_rowconfigure(0, weight=1)
self.text_frame.grid_columnconfigure(0, weight=1)
# --- Barra de botões ---
self.buttons_frame = tk.Frame(self.root, bg="#1f1f1f")
self.buttons_win = self.canvas.create_window(
0, 0, anchor="nw", window=self.buttons_frame
)
self.status = tk.StringVar(value="")
self.choice = tk.StringVar(value="")
self.continue_btn = tk.Button(
self.buttons_frame,
text="▶ Continuar",
font=self.custom_font,
bg="#333333",
fg="white",
relief="flat",
padx=12,
pady=6,
command=lambda: self.status.set("go"),
)
self.continue_btn.pack(side="right", padx=6, pady=6)
# --- Menu ---
menubar = tk.Menu(self.root)
game_menu = tk.Menu(menubar, tearoff=0)
game_menu.add_command(label="Novo Jogo", command=self._menu_novo_jogo)
game_menu.add_separator()
game_menu.add_command(label="Sair", command=self.root.quit)
menubar.add_cascade(label="Jogo", menu=game_menu)
view_menu = tk.Menu(menubar, tearoff=0)
view_menu.add_command(label="A+", command=self._font_up)
view_menu.add_command(label="A−", command=self._font_down)
menubar.add_cascade(label="Visual", menu=view_menu)
self.root.config(menu=menubar)
# ---------- util UI ----------
def _on_resize(self, event=None):
w = self.root.winfo_width()
h = self.root.winfo_height()
# fundo
if self._orig_bg and PIL_OK:
try:
from PIL import ImageTk
img = self._orig_bg.resize((w, h))
self.bg_img = ImageTk.PhotoImage(img)
self.canvas.delete("bg")
self.canvas.create_image(0, 0, image=self.bg_img, anchor="nw", tags="bg")
except Exception:
self.canvas.delete("bg")
self.canvas.create_rectangle(0, 0, w, h, fill="black", outline="", tags="bg")
else:
self.canvas.delete("bg")
self.canvas.create_rectangle(0, 0, w, h, fill="black", outline="", tags="bg")
# posicionar caixas
margin = 18
text_h = int(h * 0.72)
btn_h = h - text_h - (margin * 3)
self.canvas.coords(self.text_win, margin, margin)
self.canvas.itemconfig(self.text_win, width=w - margin * 2, height=text_h)
self.canvas.coords(self.buttons_win, margin, margin * 2 + text_h)
self.canvas.itemconfig(self.buttons_win, width=w - margin * 2, height=btn_h)
def _font_up(self):
self.font_size = min(self.font_size + 2, 26)
self.custom_font.configure(size=self.font_size)
def _font_down(self):
self.font_size = max(self.font_size - 2, 12)
self.custom_font.configure(size=self.font_size)
def _menu_novo_jogo(self):
self.text.delete("1.0", "end")
self.status.set("reset")
start_new_game()
def write(self, s: str):
if s:
if not s.endswith("\n"):
s += "\n"
self.text.insert("end", s)
self.text.see("end")
self.root.update_idletasks()
def pause(self, msg="\n[▶ Pressione Continuar]"):
self.write(msg)
self.status.set("")
self.root.wait_variable(self.status)
self.write("")
def choose(self, options: dict, prompt: str = "Escolha: ") -> str:
# limpa botões anteriores (menos o continuar)
for w in list(self.buttons_frame.children.values()):
if w is not self.continue_btn:
w.destroy()
self.write("\n" + prompt)
for k, v in options.items():
self.write(f"{k}) {v}")
self.choice.set("")
for k, v in options.items():
b = tk.Button(
self.buttons_frame,
text=f"{k}) {v}",
font=self.custom_font,
bg="#444444",
fg="white",
relief="flat",
padx=10, pady=6,
command=lambda key=k: self.choice.set(key),
)
b.pack(side="left", padx=4, pady=6)
self.continue_btn.pack_forget()
self.root.wait_variable(self.choice)
self.continue_btn.pack(side="right", padx=6, pady=6)
return self.choice.get()
# instancia UI e redireciona prints
ui = GameUI()
import builtins
def _gui_print(*args, **kwargs):
ui.write(" ".join(str(a) for a in args))
builtins.print = _gui_print
def escolher(opcoes: dict, prompt: str = "Escolha: "):
return ui.choose(opcoes, prompt)
def pausar(msg="\n[▶ Pressione Continuar]"):
ui.pause(msg)
# ==============================
# SISTEMA / REGRAS
# ==============================
class Personagem:
def __init__(self, nome, classe, vida, forca, magia):
self.nome = nome
self.classe = classe
self.vida_max = vida
self.vida = vida
self.forca = forca
self.magia = magia
self.nivel = 1
self.xp = 0
self.itens = {"Poção de Cura": 2}
# eixos narrativos
self.honra = 0
self.compaixao = 0
self.trevas = 0
self.reliquias = set()
# combate
def atacar_fisico(self, alvo):
dano = random.randint(1 + self.nivel, self.forca + self.nivel)
alvo.vida -= dano
print(f"{self.nome} ataca {alvo.nome} e causa {dano} de dano!")
def atacar_magia(self, alvo):
base = random.randint(1 + self.nivel, self.magia + 3 + self.nivel)
crit = 2 if random.random() < 0.15 else 1
dano = base * crit
alvo.vida -= dano
print(f"{self.nome} lança magia em {alvo.nome} e causa {dano}!{' (Crítico!)' if crit==2 else ''}")
def usar_item(self, nome_item):
if self.itens.get(nome_item, 0) <= 0:
print("Você não tem esse item.")
return False
if nome_item == "Poção de Cura":
cura = random.randint(10, 18) + self.nivel
self.vida = min(self.vida + cura, self.vida_max)
self.itens[nome_item] -= 1
print(f"{self.nome} usa Poção de Cura e recupera {cura} de vida. ({self.itens[nome_item]} restantes)")
return True
print("Nada acontece...")
return False
def ganhar_xp(self, qtd):
self.xp += qtd
while self.xp >= self.nivel * 20:
self.xp -= self.nivel * 20
self.nivel += 1
self.vida_max += 6
self.forca += 2
self.magia += 1
self.vida = self.vida_max
print(f"\n✨ {self.nome} subiu para o Nível {self.nivel}! Atributos melhorados e vida restaurada.\n")
def vivo(self):
return self.vida > 0
class Inimigo:
def __init__(self, nome, vida, forca, xp):
self.nome = nome
self.vida = vida
self.forca = forca
self.xp = xp
def atacar(self, alvo):
dano = random.randint(1, self.forca)
alvo.vida -= dano
print(f"{self.nome} ataca {alvo.nome} e causa {dano} de dano!")
def vivo(self):
return self.vida > 0
def batalha(jogador: Personagem, inimigo: Inimigo) -> bool:
print(f"\n⚔️ BATALHA: {jogador.nome} (HP {jogador.vida}/{jogador.vida_max}) vs {inimigo.nome} (HP {inimigo.vida})\n")
while jogador.vivo() and inimigo.vivo():
print(f"Seu HP: {jogador.vida}/{jogador.vida_max} | Inimigo: {inimigo.vida}")
acao = escolher({
"1": "Atacar (Físico)",
"2": "Usar Magia",
"3": "Usar Poção de Cura",
"4": "Tentar Fugir"
}, "Ação: ")
if acao == "1":
jogador.atacar_fisico(inimigo)
elif acao == "2":
jogador.atacar_magia(inimigo)
elif acao == "3":
jogador.usar_item("Poção de Cura")
elif acao == "4":
if random.random() < 0.35 + (jogador.nivel * 0.03):
print("Você escapa às pressas!")
return False
else:
print("A fuga falhou!")
if inimigo.vivo():
inimigo.atacar(jogador)
print("-")
if jogador.vivo():
print(f"\n Vitória sobre {inimigo.nome}!")
jogador.ganhar_xp(inimigo.xp)
return True
else:
print("\n Você foi derrotado...")
return False
# ==============================
# MUNDO / HISTÓRIA
# ==============================
class Mundo:
def __init__(self):
self.salvou_camponesa = False
self.fez_pacto = False
self.pegou_reliquia_fogo = False
self.pegou_reliquia_luz = False
self.derrotou_dragao = False
# --- Cenas ---
def cena_intro(jog: Personagem, mundo: Mundo):
print("""
=== PRÓLOGO ===
Você desperta entre as ruínas da Vila de Arvendel. Uma névoa fria envolve as casas queimadas.
Dizem que o Lich Supremo abriu fendas de trevas na Floresta Sombria.
Seu caminho começa na encruzilhada: à esquerda, a Floresta; à direita, a Estrada Velha.
""")
op = escolher({"1": "Seguir pela Floresta Sombria", "2": "Tomar a Estrada Velha"}, "Seu caminho: ")
if op == "1":
jog.honra += 1
return cena_floresta
else:
return cena_estrada
def cena_floresta(jog: Personagem, mundo: Mundo):
print("""
A copa fecha o céu. Sussurros entre as árvores. Um Goblin salta do mato.
""")
goblin = Inimigo("Goblin Emboscador", 16, 5, 10)
venceu = batalha(jog, goblin)
if not venceu:
print("Você recua, ferido, para a Estrada Velha.")
return cena_estrada
print("Ao vasculhar a clareira, você encontra uma pequena RELÍQUIA ardente.")
op = escolher({"1": "Pegar a Relíquia do Fogo", "2": "Deixar onde está"}, "Decisão: ")
if op == "1":
mundo.pegou_reliquia_fogo = True
jog.reliquias.add("Fogo")
print("A relíquia aquece sua mão. Você sente poder fluir.")
else:
print("Você respeita o santuário natural e segue em frente.")
jog.compaixao += 1
return cena_cabana
def cena_estrada(jog: Personagem, mundo: Mundo):
print("""
A Estrada Velha serpenteia por campos secos. Uma carroça tombada bloqueia o caminho.
Você ouve um pedido de socorro vindo do matagal.
""")
op = escolher({"1": "Ajudar quem pede socorro", "2": "Ignorar e prosseguir"}, "Sua ação: ")
if op == "1":
print("Você resgata uma camponesa presa sob galhos. Ela lhe dá uma Poção de Cura.")
jog.itens["Poção de Cura"] = jog.itens.get("Poção de Cura", 0) + 1
jog.compaixao += 1
mundo.salvou_camponesa = True
else:
print("Você endurece o coração e segue em frente.")
jog.trevas += 1
return cena_cruzamento_estrada
def cena_cabana(jog: Personagem, mundo: Mundo):
print("""
Você encontra uma cabana coberta de musgo. Uma bruxa anciana oferece um pacto:
"Entrarei em sua sombra e lhe darei poder. Em troca, um pedaço de sua alma."
""")
op = escolher({"1": "Aceitar o pacto (poder imediato)", "2": "Recusar (manter sua alma)"}, "Decisão: ")
if op == "1":
mundo.fez_pacto = True
jog.trevas += 2
jog.forca += 2
jog.magia += 2
print("A sombra sussurra segredos proibidos. Você sente-se mais forte... e mais frio.")
else:
jog.honra += 1
print("Você recusa com firmeza. A bruxa ri e some na neblina.")
return cena_colina
def cena_cruzamento_estrada(jog: Personagem, mundo: Mundo):
print("""
Mais adiante, um bando de salteadores aparece. O líder exige tributo.
"Nada pessoal, viajante. Deixe ouro e vá." Você sente que lutar fará fama... ou feridas.
""")
op = escolher({"1": "Enfrentar os salteadores", "2": "Pagar e evitar conflito"}, "Escolha: ")
if op == "1":
b1 = Inimigo("Salteador", 14, 5, 8)
b2 = Inimigo("Chefe Salteador", 22, 7, 14)
if not batalha(jog, b1):
return cena_derrota
if not batalha(jog, b2):
return cena_derrota
jog.honra += 1
print("Os camponeses escondidos te aplaudem. Alguém deixa uma RELÍQUIA de Luz aos seus pés.")
mundo.pegou_reliquia_luz = True
jog.reliquias.add("Luz")
else:
print("Você paga algumas moedas e passa. Vive para lutar outro dia.")
jog.compaixao += 1
return cena_colina
def cena_colina(jog: Personagem, mundo: Mundo):
print("""
No alto da colina, o vento uiva. O céu escurece e um Dragão desce em espiral.
"Prove seu valor, mortal!" ruge a criatura.
""")
op = escolher({"1": "Enfrentar o Dragão", "2": "Tentar se esconder"}, "Decisão: ")
if op == "2":
print("Você rola para trás de uma rocha. O Dragão sopra fogo, mas você escapa. A vergonha pesa.")
jog.trevas += 1
return cena_ruinas
bonus_vida = 6 if "Luz" in jog.reliquias else 0
bonus_dano = 2 if "Fogo" in jog.reliquias else 0
dragao = Inimigo("Dragão Ancião", 40 + bonus_vida, 10 + bonus_dano, 30)
venceu = batalha(jog, dragao)
if venceu:
mundo.derrotou_dragao = True
jog.honra += 1
print("As escamas do Dragão brilham. Entre elas, um amuleto radiante pulsa energia.")
op = escolher({"1": "Tomar o amuleto", "2": "Deixar como oferenda"}, "Sua decisão: ")
if op == "1":
jog.reliquias.add("Amuleto do Vento")
print("O vento agora sussurra ao seu favor.")
else:
jog.compaixao += 1
print("Você respeita o espírito da criatura.")
else:
print("Você cai do penhasco e sobrevive por pouco. O Dragão alça voo, orgulhoso.")
return cena_ruinas
def cena_ruinas(jog: Personagem, mundo: Mundo):
print("""
As Ruínas de Nhar abrem-se como uma boca de pedra. O frio aumenta. A presença do Lich é palpável.
Uma porta selada pede duas luzes: Fogo e Luz. Talvez relíquias ajudem...
""")
if mundo.pegou_reliquia_fogo and mundo.pegou_reliquia_luz:
print("As relíquias queimam e iluminam os sigilos. A porta se abre sem resistência.")
facil = True
else:
print("Sem as duas relíquias, você força a entrada, despertando guardiões.")
facil = False
guardiao = Inimigo("Guardião Ósseo", 26, 8, 18)
if not batalha(jog, guardiao):
return cena_derrota
vida_boss = 58 if facil else 66
forca_boss = 11 if facil else 13
if mundo.fez_pacto:
print("O Lich reconhece a sombra em você e ri: 'Metade do trabalho já fizeste'.")
forca_boss += 2
if mundo.derrotou_dragao:
print("O eco do rugido do Dragão fortalece seu espírito.")
jog.forca += 1
jog.magia += 1
lich = Inimigo("Lich Supremo", vida_boss, forca_boss, 50)
venceu = batalha(jog, lich)
if not venceu:
return cena_final_tragico
score_luz = jog.honra + jog.compaixao + (1 if "Luz" in jog.reliquias else 0)
score_trevas = jog.trevas + (2 if mundo.fez_pacto else 0)
if score_trevas >= score_luz + 2:
return cena_final_sombrio
if score_luz >= score_trevas + 2 and mundo.salvou_camponesa and mundo.derrotou_dragao:
return cena_final_luminoso
return cena_final_neutro
# --- finais / derrota ---
def cena_final_tragico(jog: Personagem, mundo: Mundo):
print("""
=== FINAL TRÁGICO ===
Você cai diante do Lich. As Ruínas ecoam um riso gélido. A noite se aprofunda sobre o reino.
Talvez em outra vida, um herói reúna luz suficiente.
""")
return None
def cena_final_luminoso(jog: Personagem, mundo: Mundo):
print("""
=== FINAL LUMINOSO ===
Com honra e compaixão, você desfaz os selos das trevas. A alma do Lich se dissipa como cinza ao vento.
A camponesa resgatada acende uma vela por você; o reino canta seu nome. A aurora permanece.
""")
return None
def cena_final_neutro(jog: Personagem, mundo: Mundo):
print("""
=== FINAL DO CREPÚSCULO ===
O Lich cai, mas cicatrizes ficam. Nem luz plena, nem sombra total. O povo sobrevive, e você parte em silêncio,
levando no peito um amuleto que sussurra histórias não contadas.
""")
return None
def cena_final_sombrio(jog: Personagem, mundo: Mundo):
print("""
=== FINAL SOMBRIO ===
Você triunfa... mas a sombra do pacto consome suas cores. O trono fica vazio, e um novo sussurro toma as ruínas.
Seu nome será lembrado — não como herói, mas como aviso.
""")
return None
def cena_derrota(jog: Personagem, mundo: Mundo):
print("""
Seus passos cessam antes do destino. A história, inacabada, retorna à poeira.
""")
return None
# ==============================
# LOOP E INICIALIZAÇÃO
# ==============================
def criar_personagem() -> Personagem:
print("=== Bem-vindo ao RPG Livro-Jogo ===")
nome = simpledialog.askstring("Nome", "Nome do herói:") or "Herói"
print("\nEscolha sua classe:")
escolha = escolher({
"1": "Guerreiro (Vida 30, Força 8, Magia 2)",
"2": "Mago (Vida 22, Força 3, Magia 10)",
"3": "Arqueiro (Vida 26, Força 6, Magia 4)"
}, "Classe: ")
if escolha == "1":
return Personagem(nome, "Guerreiro", 30, 8, 2)
if escolha == "
Editor is loading...
Leave a Comment