Files
Flora/ui/tower.py
T

204 lines
9.2 KiB
Python

import pygame
from engine.plants import RARITY_COLORS, plant_rarity
from ui.scaling import make_window, request_quit, to_logical
WIN_W, WIN_H = 1040, 720
BG = (24, 30, 24)
TEXT = (230, 235, 230)
MUTED = (150, 155, 150)
HINT = (255, 220, 120)
BTN = (60, 90, 60)
BTN_HOVER = (85, 125, 85)
DANGER = (150, 70, 70)
DANGER_HOVER = (180, 90, 90)
class ConfirmScreen:
"""A simple yes/no popup (e.g. "really leave the tower?")."""
def __init__(self, title, message, yes_label="Leave", no_label="Stay"):
pygame.init()
self.window, self.scale = make_window(WIN_W, WIN_H)
self.screen = pygame.Surface((WIN_W, WIN_H))
pygame.display.set_caption("Plants — Tower")
self.clock = pygame.time.Clock()
self.font = pygame.font.SysFont("segoeui", 30)
self.bold = pygame.font.SysFont("segoeui", 20, bold=True)
self.small = pygame.font.SysFont("segoeui", 16)
self.tiny = pygame.font.SysFont("segoeui", 13)
self.title = title
self.message = message
self.yes_label = yes_label
self.no_label = no_label
self.yes_rect = pygame.Rect(WIN_W // 2 + 16, WIN_H - 96, 180, 44)
self.no_rect = pygame.Rect(WIN_W // 2 - 196, WIN_H - 96, 180, 44)
def run(self):
running = True
result = False
while running:
self.clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
request_quit()
running = False
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
pos = to_logical(event.pos, self.scale)
if self.yes_rect.collidepoint(pos):
result = True
running = False
elif self.no_rect.collidepoint(pos):
result = False
running = False
self._draw()
pygame.transform.smoothscale(self.screen, self.window.get_size(), self.window)
pygame.display.flip()
return result
def _draw(self):
self.screen.fill(BG)
title = self.font.render(self.title, True, HINT)
self.screen.blit(title, title.get_rect(center=(WIN_W // 2, 100)))
for i, line in enumerate(self.message.split("\n")):
t = self.small.render(line, True, TEXT)
self.screen.blit(t, t.get_rect(center=(WIN_W // 2, 150 + i * 26)))
self._button(self.no_rect, self.no_label, BTN, BTN_HOVER)
self._button(self.yes_rect, self.yes_label, DANGER, DANGER_HOVER)
def _button(self, rect, label, base, hover):
mouse = pygame.mouse.get_pos()
bg = hover if rect.collidepoint(mouse) else base
pygame.draw.rect(self.screen, bg, rect, border_radius=8)
pygame.draw.rect(self.screen, (150, 190, 150), rect, 2, border_radius=8)
t = self.bold.render(label, True, TEXT)
self.screen.blit(t, t.get_rect(center=rect.center))
class TowerScreen:
def __init__(self, stage, total_stages, reward_text, totals_text, mode="battle",
enemies=()):
pygame.init()
self.window, self.scale = make_window(WIN_W, WIN_H)
self.screen = pygame.Surface((WIN_W, WIN_H))
pygame.display.set_caption("Plants — Tower")
self.clock = pygame.time.Clock()
self.font = pygame.font.SysFont("segoeui", 36)
self.bold = pygame.font.SysFont("segoeui", 20, bold=True)
self.small = pygame.font.SysFont("segoeui", 16)
self.tiny = pygame.font.SysFont("segoeui", 13)
self.stage = stage
self.total = total_stages
self.reward_text = reward_text
self.totals_text = totals_text
self.mode = mode # battle | lost | cleared | summary
self.enemies = list(enemies)
self.left_rect = pygame.Rect(WIN_W // 2 - 320, WIN_H - 90, 200, 44)
self.mid_rect = pygame.Rect(WIN_W // 2 - 100, WIN_H - 90, 200, 44)
self.right_rect = pygame.Rect(WIN_W // 2 + 120, WIN_H - 90, 200, 44)
def run(self):
running = True
result = "exit"
while running:
self.clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
request_quit()
running = False
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
pos = to_logical(event.pos, self.scale)
if self.mode == "battle":
if self.left_rect.collidepoint(pos):
result = "exit"
running = False
elif self.mid_rect.collidepoint(pos):
result = "adjust"
running = False
elif self.right_rect.collidepoint(pos):
result = "next"
running = False
elif self.mode == "lost":
if self.left_rect.collidepoint(pos):
result = "retry"
running = False
elif self.mid_rect.collidepoint(pos):
result = "change"
running = False
elif self.right_rect.collidepoint(pos):
result = "giveup"
running = False
else:
result = "exit"
running = False
self._draw()
pygame.transform.smoothscale(self.screen, self.window.get_size(), self.window)
pygame.display.flip()
return result
def _draw(self):
self.screen.fill(BG)
if self.mode == "battle":
self._draw_battle()
elif self.mode == "lost":
self._draw_lost()
else:
self._draw_summary()
def _button(self, rect, label, base, hover):
mouse = pygame.mouse.get_pos()
bg = hover if rect.collidepoint(mouse) else base
pygame.draw.rect(self.screen, bg, rect, border_radius=8)
pygame.draw.rect(self.screen, (150, 190, 150), rect, 2, border_radius=8)
t = self.bold.render(label, True, TEXT)
self.screen.blit(t, t.get_rect(center=rect.center))
def _draw_battle(self):
title = self.font.render("Tower", True, HINT)
self.screen.blit(title, title.get_rect(center=(WIN_W // 2, 70)))
st = self.bold.render(f"Stage {self.stage} defeated!", True, TEXT)
self.screen.blit(st, st.get_rect(center=(WIN_W // 2, 150)))
info = self.small.render(f"Next: Stage {self.stage + 1} / {self.total}", True, MUTED)
self.screen.blit(info, info.get_rect(center=(WIN_W // 2, 190)))
rw = self.small.render(f"Stage reward: {self.reward_text}", True, TEXT)
self.screen.blit(rw, rw.get_rect(center=(WIN_W // 2, 240)))
tt = self.small.render(f"Total so far: {self.totals_text}", True, MUTED)
self.screen.blit(tt, tt.get_rect(center=(WIN_W // 2, 270)))
self._button(self.left_rect, "Exit tower", BTN, BTN_HOVER)
self._button(self.mid_rect, "Adjust team", BTN, BTN_HOVER)
self._button(self.right_rect, "Next stage", BTN, BTN_HOVER)
def _draw_lost(self):
title = self.font.render("Tower ended", True, HINT)
self.screen.blit(title, title.get_rect(center=(WIN_W // 2, 70)))
sub = self.bold.render(f"Defeated at stage {self.stage}", True, TEXT)
self.screen.blit(sub, sub.get_rect(center=(WIN_W // 2, 130)))
rw = self.small.render(f"Rewards earned: {self.totals_text}", True, TEXT)
self.screen.blit(rw, rw.get_rect(center=(WIN_W // 2, 180)))
if self.enemies:
eh = self.bold.render("Enemy team this stage:", True, HINT)
self.screen.blit(eh, eh.get_rect(midtop=(WIN_W // 2, 224)))
total_w = sum(self.small.size(n)[0] for n in self.enemies) + 14 * (len(self.enemies) - 1)
x = (WIN_W - total_w) // 2
for name in self.enemies:
rar = plant_rarity(name)
surf = self.small.render(name, True, RARITY_COLORS.get(rar, TEXT))
self.screen.blit(surf, (x, 254))
x += surf.get_width() + 14
self._button(self.left_rect, "Retry", BTN, BTN_HOVER)
self._button(self.mid_rect, "Change team", BTN, BTN_HOVER)
self._button(self.right_rect, "Give up", DANGER, DANGER_HOVER)
def _draw_summary(self):
if self.mode == "cleared":
title = self.font.render("Tower cleared!", True, HINT)
sub = self.bold.render(f"Cleared all {self.total} stages!", True, TEXT)
else:
title = self.font.render("Tower ended", True, HINT)
sub = self.bold.render(f"Reached stage {self.stage}", True, TEXT)
self.screen.blit(title, title.get_rect(center=(WIN_W // 2, 90)))
self.screen.blit(sub, sub.get_rect(center=(WIN_W // 2, 170)))
rw = self.small.render(f"Rewards earned: {self.totals_text}", True, TEXT)
self.screen.blit(rw, rw.get_rect(center=(WIN_W // 2, 230)))
hint = self.tiny.render("Click anywhere to return to the menu", True, MUTED)
self.screen.blit(hint, hint.get_rect(center=(WIN_W // 2, 280)))