204 lines
9.2 KiB
Python
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("Flora — 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("Flora — 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))) |