|
|
@@ -1,328 +1,257 @@
|
|
|
-import pygame
|
|
|
-import os
|
|
|
-import sys
|
|
|
-
|
|
|
-# ================= ИНИЦИАЛИЗАЦИЯ =================
|
|
|
-pygame.init()
|
|
|
-WIDTH, HEIGHT = 1024, 768
|
|
|
-screen = pygame.display.set_mode((WIDTH, HEIGHT))
|
|
|
-pygame.display.set_caption("Симулятор: Административный персонал")
|
|
|
-clock = pygame.time.Clock()
|
|
|
-FONT = pygame.font.SysFont("Arial", 20)
|
|
|
-BIG_FONT = pygame.font.SysFont("Arial", 26)
|
|
|
-ASSET_DIR = r"C:\VVV"
|
|
|
-
|
|
|
-# Цвета
|
|
|
-WHITE = (255, 255, 255)
|
|
|
-BLACK = (0, 0, 0)
|
|
|
-GRAY = (210, 210, 210)
|
|
|
-DARK_GRAY = (100, 100, 100)
|
|
|
-BLUE = (40, 100, 180)
|
|
|
-GREEN = (40, 150, 40)
|
|
|
-RED = (180, 40, 40)
|
|
|
-ORANGE = (230, 160, 40)
|
|
|
-
|
|
|
-# ================= УТИЛИТЫ =================
|
|
|
-def load_asset(filename, fallback_color=GRAY, w=100, h=80):
|
|
|
- path = os.path.join(ASSET_DIR, filename)
|
|
|
- if os.path.exists(path):
|
|
|
+import tkinter as tk
|
|
|
+from tkinter import messagebox
|
|
|
+from PIL import Image, ImageTk
|
|
|
+
|
|
|
+class AdminGameGUI:
|
|
|
+ def __init__(self, root):
|
|
|
+ self.root = root
|
|
|
+ self.root.title("Административный персонал - Игра")
|
|
|
+ self.root.geometry("700x600")
|
|
|
+
|
|
|
+ # Ресурсы
|
|
|
+ self.reputation = 100
|
|
|
+ self.budget = 100
|
|
|
+ self.stress = 0
|
|
|
+
|
|
|
+ # Верхняя панель (ресурсы)
|
|
|
+ self.top_frame = tk.Frame(root)
|
|
|
+ self.top_frame.pack(pady=10)
|
|
|
+
|
|
|
+ self.reputation_label = tk.Label(self.top_frame, font=('Arial', 12))
|
|
|
+ self.reputation_label.pack()
|
|
|
+
|
|
|
+ self.budget_label = tk.Label(self.top_frame, font=('Arial', 12))
|
|
|
+ self.budget_label.pack()
|
|
|
+
|
|
|
+ self.stress_label = tk.Label(self.top_frame, font=('Arial', 12))
|
|
|
+ self.stress_label.pack()
|
|
|
+
|
|
|
+ # Картинка сцены
|
|
|
+ self.image_label = tk.Label(root)
|
|
|
+ self.image_label.pack(pady=10)
|
|
|
+
|
|
|
+ # Текст сцены
|
|
|
+ self.text_label = tk.Label(root, font=('Arial', 12), wraplength=600, justify="center")
|
|
|
+ self.text_label.pack(pady=10)
|
|
|
+
|
|
|
+ # Кнопки
|
|
|
+ self.button_frame = tk.Frame(root)
|
|
|
+ self.button_frame.pack(pady=20)
|
|
|
+
|
|
|
+ self.update_labels()
|
|
|
+ self.scene_1()
|
|
|
+
|
|
|
+ # ================= UI =================
|
|
|
+
|
|
|
+ def update_labels(self):
|
|
|
+ self.reputation_label.config(text=f"Репутация: {self.reputation}")
|
|
|
+ self.budget_label.config(text=f"Бюджет: {self.budget}")
|
|
|
+ self.stress_label.config(text=f"Стресс: {self.stress}")
|
|
|
+
|
|
|
+ def show_text(self, text):
|
|
|
+ self.text_label.config(text=text)
|
|
|
+
|
|
|
+ def create_buttons(self, choices):
|
|
|
+ self.clear_buttons()
|
|
|
+ for text, command in choices:
|
|
|
+ btn = tk.Button(self.button_frame, text=text, width=50, command=command)
|
|
|
+ btn.pack(pady=5)
|
|
|
+
|
|
|
+ def clear_buttons(self):
|
|
|
+ for widget in self.button_frame.winfo_children():
|
|
|
+ widget.destroy()
|
|
|
+
|
|
|
+ def load_image(self, path):
|
|
|
+ """
|
|
|
+ 🔴 ВАЖНО: ВСТАВКА КАРТИНОК ЗДЕСЬ
|
|
|
+ Просто замени путь:
|
|
|
+ "images/scene1.jpg"
|
|
|
+ на свой файл
|
|
|
+ """
|
|
|
try:
|
|
|
- img = pygame.image.load(path).convert_alpha()
|
|
|
- return img
|
|
|
+ img = Image.open(path)
|
|
|
+ img = img.resize((400, 250))
|
|
|
+ self.tk_img = ImageTk.PhotoImage(img)
|
|
|
+ self.image_label.config(image=self.tk_img)
|
|
|
except:
|
|
|
- pass
|
|
|
- surf = pygame.Surface((w, h), pygame.SRCALPHA)
|
|
|
- surf.fill(fallback_color)
|
|
|
- txt = FONT.render(filename, True, BLACK)
|
|
|
- surf.blit(txt, (5, h//2-10))
|
|
|
- return surf
|
|
|
-
|
|
|
-def draw_text(text, x, y, font=FONT, color=BLACK, center=False):
|
|
|
- surf = font.render(text, True, color)
|
|
|
- rect = surf.get_rect(center=(x, y)) if center else surf.get_rect(topleft=(x, y))
|
|
|
- screen.blit(surf, rect)
|
|
|
-
|
|
|
-class Button:
|
|
|
- def __init__(self, x, y, w, h, text, callback, color=BLUE, hover_color=(60, 120, 200)):
|
|
|
- self.rect = pygame.Rect(x, y, w, h)
|
|
|
- self.text = text
|
|
|
- self.callback = callback
|
|
|
- self.color = color
|
|
|
- self.hover_color = hover_color
|
|
|
- self.hovered = False
|
|
|
- self.selected = False
|
|
|
-
|
|
|
- def draw(self):
|
|
|
- c = self.hover_color if self.hovered else self.color
|
|
|
- if self.selected: c = GREEN
|
|
|
- pygame.draw.rect(screen, c, self.rect, border_radius=6)
|
|
|
- pygame.draw.rect(screen, BLACK, self.rect, 2, border_radius=6)
|
|
|
- draw_text(self.text, self.rect.centerx, self.rect.centery, color=WHITE, font=FONT)
|
|
|
-
|
|
|
- def handle(self, event):
|
|
|
- if event.type == pygame.MOUSEMOTION:
|
|
|
- self.hovered = self.rect.collidepoint(event.pos)
|
|
|
- elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
|
|
|
- if self.hovered:
|
|
|
- if self.callback: self.callback()
|
|
|
- return True
|
|
|
+ self.image_label.config(image="", text="(Нет изображения)")
|
|
|
+
|
|
|
+ def check_game_over(self):
|
|
|
+ if self.reputation <= 0:
|
|
|
+ self.end_game("Репутация упала до нуля. Компания закрылась.")
|
|
|
+ return True
|
|
|
+ if self.budget <= 0:
|
|
|
+ self.end_game("Бюджет исчерпан. Компания обанкротилась.")
|
|
|
+ return True
|
|
|
+ if self.stress >= 100:
|
|
|
+ self.end_game("Вы перегорели и уволились.")
|
|
|
+ return True
|
|
|
return False
|
|
|
|
|
|
-# ================= ИГРОВОЙ КЛАСС =================
|
|
|
-class Game:
|
|
|
- def __init__(self):
|
|
|
- self.scene = 0
|
|
|
- self.running = True
|
|
|
- self.message = ""
|
|
|
- self.msg_timer = 0
|
|
|
- self.buttons = []
|
|
|
- self.state = {}
|
|
|
- self.setup_scene()
|
|
|
-
|
|
|
- def show_msg(self, text, duration=2500):
|
|
|
- self.message = text
|
|
|
- self.msg_timer = duration
|
|
|
-
|
|
|
- def progress(self):
|
|
|
- self.scene += 1
|
|
|
- self.buttons = []
|
|
|
- self.state = {}
|
|
|
- self.message = ""
|
|
|
- if self.scene >= 5:
|
|
|
- self.show_msg("🎉 Поздравляем! Вы успешно прошли все этапы обучения!", 99999)
|
|
|
+ # ================= СЦЕНЫ =================
|
|
|
+
|
|
|
+ def scene_1(self):
|
|
|
+ self.update_labels()
|
|
|
+ self.load_image("D:/grouppe2025-26 - 36/goev/xxxxx/images/scene1.jpg") # 👉 КАРТИНКА СЦЕНЫ 1
|
|
|
+
|
|
|
+ self.show_text("Утро администратора. Что сделать первым?")
|
|
|
+
|
|
|
+ self.create_buttons([
|
|
|
+ ("Планировать встречи", self.s1_plan),
|
|
|
+ ("Финансовая отчетность", self.s1_finance),
|
|
|
+ ("Ответить на звонки", self.s1_calls),
|
|
|
+ ])
|
|
|
+
|
|
|
+ def s1_plan(self):
|
|
|
+ self.reputation += 10
|
|
|
+ self.stress += 5
|
|
|
+ if not self.check_game_over():
|
|
|
+ self.scene_2()
|
|
|
+
|
|
|
+ def s1_finance(self):
|
|
|
+ self.budget += 5
|
|
|
+ self.stress += 10
|
|
|
+ if not self.check_game_over():
|
|
|
+ self.scene_2()
|
|
|
+
|
|
|
+ def s1_calls(self):
|
|
|
+ self.reputation += 5
|
|
|
+ self.stress += 15
|
|
|
+ if not self.check_game_over():
|
|
|
+ self.scene_2()
|
|
|
+
|
|
|
+ # ---------
|
|
|
+
|
|
|
+ def scene_2(self):
|
|
|
+ self.update_labels()
|
|
|
+ self.load_image("D:/grouppe2025-26 - 36/goev/xxxxx/images/scene2.jpg") # 👉 КАРТИНКА СЦЕНЫ 2
|
|
|
+
|
|
|
+ self.show_text("Отдел просит дорогое оборудование. Что делать?")
|
|
|
+
|
|
|
+ self.create_buttons([
|
|
|
+ ("Договориться о дешевом варианте", self.s2_soft),
|
|
|
+ ("Одобрить и перераспределить бюджет", self.s2_spend),
|
|
|
+ ("Жестко отказать", self.s2_refuse),
|
|
|
+ ])
|
|
|
+
|
|
|
+ def s2_soft(self):
|
|
|
+ self.budget -= 10
|
|
|
+ self.reputation += 10
|
|
|
+ if not self.check_game_over():
|
|
|
+ self.scene_3()
|
|
|
+
|
|
|
+ def s2_spend(self):
|
|
|
+ self.budget -= 25
|
|
|
+ self.stress += 10
|
|
|
+ if not self.check_game_over():
|
|
|
+ self.scene_3()
|
|
|
+
|
|
|
+ def s2_refuse(self):
|
|
|
+ self.reputation -= 10
|
|
|
+ self.stress += 5
|
|
|
+ if not self.check_game_over():
|
|
|
+ self.scene_3()
|
|
|
+
|
|
|
+ # ---------
|
|
|
+
|
|
|
+ def scene_3(self):
|
|
|
+ self.update_labels()
|
|
|
+ self.load_image("D:/grouppe2025-26 - 36/goev/xxxxx/images/scene3.png") # 👉 КАРТИНКА СЦЕНЫ 3
|
|
|
+
|
|
|
+ self.show_text("Клиент жалуется. Как реагировать?")
|
|
|
+
|
|
|
+ self.create_buttons([
|
|
|
+ ("Проявить эмпатию", self.s3_empathy),
|
|
|
+ ("Дать четкий ответ", self.s3_clear),
|
|
|
+ ("Формальный отказ", self.s3_refuse),
|
|
|
+ ])
|
|
|
+
|
|
|
+ def s3_empathy(self):
|
|
|
+ self.reputation += 15
|
|
|
+ self.stress += 5
|
|
|
+ if not self.check_game_over():
|
|
|
+ self.scene_4()
|
|
|
+
|
|
|
+ def s3_clear(self):
|
|
|
+ self.reputation += 5
|
|
|
+ self.stress += 10
|
|
|
+ if not self.check_game_over():
|
|
|
+ self.scene_4()
|
|
|
+
|
|
|
+ def s3_refuse(self):
|
|
|
+ self.reputation -= 15
|
|
|
+ self.stress += 5
|
|
|
+ if not self.check_game_over():
|
|
|
+ self.scene_4()
|
|
|
+
|
|
|
+ # ---------
|
|
|
+
|
|
|
+ def scene_4(self):
|
|
|
+ self.update_labels()
|
|
|
+ self.load_image("D:/grouppe2025-26 - 36/goev/xxxxx/images/scene4.jpg") # 👉 КАРТИНКА СЦЕНЫ 4
|
|
|
+
|
|
|
+ self.show_text("Как улучшить процессы?")
|
|
|
+
|
|
|
+ self.create_buttons([
|
|
|
+ ("Внедрить CRM", self.s4_crm),
|
|
|
+ ("Нанять сотрудника", self.s4_hire),
|
|
|
+ ("Ничего не делать", self.s4_skip),
|
|
|
+ ])
|
|
|
+
|
|
|
+ def s4_crm(self):
|
|
|
+ self.budget -= 30
|
|
|
+ self.stress -= 15
|
|
|
+ if not self.check_game_over():
|
|
|
+ self.scene_5()
|
|
|
+
|
|
|
+ def s4_hire(self):
|
|
|
+ self.budget -= 50
|
|
|
+ self.stress += 20
|
|
|
+ if not self.check_game_over():
|
|
|
+ self.scene_5()
|
|
|
+
|
|
|
+ def s4_skip(self):
|
|
|
+ self.stress += 15
|
|
|
+ if not self.check_game_over():
|
|
|
+ self.scene_5()
|
|
|
+
|
|
|
+ # ---------
|
|
|
+
|
|
|
+ def scene_5(self):
|
|
|
+ self.update_labels()
|
|
|
+ self.load_image("D:/grouppe2025-26 - 36/goev/xxxxx/images/scene5.jpg") # 👉 КАРТИНКА СЦЕНЫ 5
|
|
|
+
|
|
|
+ result = "Итог:\n"
|
|
|
+
|
|
|
+ if self.reputation > 70:
|
|
|
+ result += "Отличная работа с клиентами\n"
|
|
|
else:
|
|
|
- self.setup_scene()
|
|
|
-
|
|
|
- def reset_scene(self):
|
|
|
- self.show_msg("❌ Задача не выполнена. Перезапуск сцены...", 2000)
|
|
|
- self.buttons = []
|
|
|
- self.state = {}
|
|
|
- self.setup_scene()
|
|
|
-
|
|
|
- def setup_scene(self):
|
|
|
- self.buttons = []
|
|
|
- if self.scene == 0: self.init_scene1()
|
|
|
- elif self.scene == 1: self.init_scene2()
|
|
|
- elif self.scene == 2: self.init_scene3()
|
|
|
- elif self.scene == 3: self.init_scene4()
|
|
|
- elif self.scene == 4: self.init_scene5()
|
|
|
-
|
|
|
- # ---------- СЦЕНА 1: Звонок ----------
|
|
|
- def init_scene1(self):
|
|
|
- self.state = {"phone_clicked": False, "answered": False}
|
|
|
- self.phone_img = load_asset("phone.png", ORANGE, 120, 120)
|
|
|
- self.buttons.append(Button(400, 220, 220, 80, "📞 Принять звонок", self.click_phone, GRAY))
|
|
|
- self.buttons.append(Button(80, 400, 280, 60, "Конечно, расскажите подробнее", lambda: self.check_call(0)))
|
|
|
- self.buttons.append(Button(380, 400, 280, 60, "Это не в нашей компетенции", lambda: self.check_call(1)))
|
|
|
- self.buttons.append(Button(680, 400, 280, 60, "Не можем помочь сейчас", lambda: self.check_call(2)))
|
|
|
-
|
|
|
- def click_phone(self): self.state["phone_clicked"] = True
|
|
|
- def check_call(self, idx):
|
|
|
- if not self.state["phone_clicked"]: return
|
|
|
- if idx == 0: self.progress()
|
|
|
- else: self.reset_scene()
|
|
|
-
|
|
|
- # ---------- СЦЕНА 2: Рабочий процесс ----------
|
|
|
- def init_scene2(self):
|
|
|
- self.state = {"cal_clicked": False, "selected_doc": None, "docs_sorted": 0, "meetings_ok": 0}
|
|
|
- self.docs = [
|
|
|
- {"id": 0, "name": "Отчет_Q1", "cat": "Отчеты", "sorted": False},
|
|
|
- {"id": 1, "name": "Договор_А", "cat": "Договоры", "sorted": False},
|
|
|
- {"id": 2, "name": "Запрос_Клиента", "cat": "Запросы", "sorted": False}
|
|
|
- ]
|
|
|
- self.meetings = [{"id": 0, "time": "10:00", "handled": False}, {"id": 1, "time": "15:00", "handled": False}]
|
|
|
- self.buttons.append(Button(350, 100, 300, 60, "📅 Календарь", self.click_cal, GRAY))
|
|
|
-
|
|
|
- def click_cal(self):
|
|
|
- self.state["cal_clicked"] = True
|
|
|
- for i, d in enumerate(self.docs):
|
|
|
- cb = Button(150 + i*250, 250, 180, 50, d["name"], lambda i=i: self.select_doc(i), DARK_GRAY)
|
|
|
- cb.is_doc = True; cb.doc_id = i
|
|
|
- self.buttons.append(cb)
|
|
|
- for i, name in enumerate(["Отчеты", "Договоры", "Запросы"]):
|
|
|
- self.buttons.append(Button(100 + i*300, 450, 180, 50, f"📁 {name}", lambda c=name: self.sort_doc(c)))
|
|
|
- for i, m in enumerate(self.meetings):
|
|
|
- self.buttons.append(Button(200, 580, 180, 40, f"Встреча {m['time']}", lambda i=i: self.handle_meeting(i)))
|
|
|
-
|
|
|
- def select_doc(self, idx):
|
|
|
- if self.docs[idx]["sorted"]: return
|
|
|
- self.state["selected_doc"] = idx
|
|
|
- self.show_msg(f"Выбран: {self.docs[idx]['name']}. Кликните на папку.")
|
|
|
- def sort_doc(self, cat):
|
|
|
- sel = self.state["selected_doc"]
|
|
|
- if sel is None: return
|
|
|
- if self.docs[sel]["cat"] == cat:
|
|
|
- self.docs[sel]["sorted"] = True
|
|
|
- self.state["docs_sorted"] += 1
|
|
|
- self.state["selected_doc"] = None
|
|
|
- self.show_msg("✅ Документ разложен верно!")
|
|
|
- else:
|
|
|
- self.show_msg("❌ Неверная категория!")
|
|
|
- self.check_scene2_win()
|
|
|
- def handle_meeting(self, idx):
|
|
|
- if not self.meetings[idx]["handled"]:
|
|
|
- self.meetings[idx]["handled"] = True
|
|
|
- self.state["meetings_ok"] += 1
|
|
|
- self.show_msg("✅ Запрос на встречу обработан.")
|
|
|
- self.check_scene2_win()
|
|
|
- def check_scene2_win(self):
|
|
|
- if self.state["docs_sorted"] == 3 and self.state["meetings_ok"] == 2:
|
|
|
- self.progress()
|
|
|
-
|
|
|
- # ---------- СЦЕНА 3: Жалоба по Email ----------
|
|
|
- def init_scene3(self):
|
|
|
- self.state = {"mail_open": False, "template": -1}
|
|
|
- self.templates = [
|
|
|
- {"text": "Приносим извинения за неудобства. Решим проблему в течение 24ч.", "correct": True},
|
|
|
- {"text": "Жалоба принята. Гарантий не даем.", "correct": False},
|
|
|
- {"text": "Мы не можем повлиять на ситуацию.", "correct": False}
|
|
|
- ]
|
|
|
- self.buttons.append(Button(400, 150, 220, 60, "📧 Открыть почту", self.open_mail, GRAY))
|
|
|
- for i, t in enumerate(self.templates):
|
|
|
- btn = Button(100, 350 + i*70, 824, 60, t["text"], lambda i=i: self.pick_template(i))
|
|
|
- btn.is_template = True; btn.tpl_idx = i
|
|
|
- self.buttons.append(btn)
|
|
|
- self.buttons.append(Button(400, 600, 200, 50, "📤 Отправить", self.send_mail, GREEN))
|
|
|
- self.email_text = "Здравствуйте! Получил заказ с браком. Требую замены или возврата."
|
|
|
-
|
|
|
- def open_mail(self): self.state["mail_open"] = True
|
|
|
- def pick_template(self, idx):
|
|
|
- self.state["template"] = idx
|
|
|
- for b in self.buttons:
|
|
|
- if hasattr(b, 'is_template'):
|
|
|
- b.selected = (b.tpl_idx == idx)
|
|
|
- def send_mail(self):
|
|
|
- if not self.state["mail_open"]: return
|
|
|
- if self.state["template"] != -1 and self.templates[self.state["template"]]["correct"]:
|
|
|
- self.progress()
|
|
|
+ result += "Нужно улучшить коммуникацию\n"
|
|
|
+
|
|
|
+ if self.budget > 50:
|
|
|
+ result += "Хорошее управление бюджетом\n"
|
|
|
else:
|
|
|
- self.show_msg("❌ Клиент недоволен ответом. Попробуйте другой шаблон.")
|
|
|
-
|
|
|
- # ---------- СЦЕНА 4: Продажа по телефону ----------
|
|
|
- def init_scene4(self):
|
|
|
- self.state = {"call_started": False, "chosen": -1}
|
|
|
- self.need = "Консультация + Скидка на первый заказ"
|
|
|
- self.offers = [
|
|
|
- {"text": "Базовая консультация без бонусов.", "match": False},
|
|
|
- {"text": "Персональная консультация + 10% скидка на первую покупку.", "match": True},
|
|
|
- {"text": "Отправим каталог на email. Консультации нет.", "match": False}
|
|
|
- ]
|
|
|
- self.buttons.append(Button(400, 150, 220, 60, "📞 Принять звонок", self.start_call, GRAY))
|
|
|
- for i, o in enumerate(self.offers):
|
|
|
- btn = Button(100, 350 + i*80, 824, 60, o["text"], lambda i=i: self.pick_offer(i))
|
|
|
- btn.is_offer = True; btn.offer_idx = i
|
|
|
- self.buttons.append(btn)
|
|
|
- self.client_query = "Добрый день! Интересует ваш продукт. Хотелось бы получить консультацию и узнать про скидки."
|
|
|
-
|
|
|
- def start_call(self): self.state["call_started"] = True
|
|
|
- def pick_offer(self, idx):
|
|
|
- self.state["chosen"] = idx
|
|
|
- for b in self.buttons:
|
|
|
- if hasattr(b, 'is_offer'):
|
|
|
- b.selected = (b.offer_idx == idx)
|
|
|
- if self.offers[idx]["match"]:
|
|
|
- self.show_msg("✅ Отличная продажа! Клиент согласился.")
|
|
|
- self.progress()
|
|
|
+ result += "Слабый финансовый контроль\n"
|
|
|
+
|
|
|
+ if self.stress < 50:
|
|
|
+ result += "Вы стрессоустойчивы\n"
|
|
|
else:
|
|
|
- self.show_msg("❌ Предложение не подошло. Клиент отказался. Перезапуск...")
|
|
|
- self.reset_scene()
|
|
|
-
|
|
|
- # ---------- СЦЕНА 5: CRM-система ----------
|
|
|
- def init_scene5(self):
|
|
|
- self.state = {"tasks_done": 0, "db_updated": False}
|
|
|
- self.tasks = [
|
|
|
- {"id": 0, "desc": "Добавить контакт Иванова И.И.", "done": False},
|
|
|
- {"id": 1, "desc": "Обновить статус заказа #482", "done": False},
|
|
|
- {"id": 2, "desc": "Назначить встречу с ООО 'Вектор'", "done": False}
|
|
|
- ]
|
|
|
- for i, t in enumerate(self.tasks):
|
|
|
- btn = Button(150, 200 + i*90, 450, 60, f"☐ {t['desc']}", lambda i=i: self.complete_task(i), DARK_GRAY)
|
|
|
- btn.is_task = True
|
|
|
- btn.task_id = i
|
|
|
- self.buttons.append(btn)
|
|
|
- self.buttons.append(Button(700, 350, 200, 60, "💾 Обновить БД", self.update_db, BLUE))
|
|
|
-
|
|
|
- def complete_task(self, idx):
|
|
|
- if self.tasks[idx]["done"]: return
|
|
|
- self.tasks[idx]["done"] = True
|
|
|
- self.state["tasks_done"] += 1
|
|
|
- # Безопасное обновление кнопки без синтаксических ошибок
|
|
|
- for b in self.buttons:
|
|
|
- if hasattr(b, 'task_id') and b.task_id == idx:
|
|
|
- b.text = f"✅ {self.tasks[idx]['desc']}"
|
|
|
- b.color = GREEN
|
|
|
- self.show_msg("✅ Задача выполнена. Не забудьте обновить базу данных.")
|
|
|
- if self.state["tasks_done"] == 3 and self.state["db_updated"]:
|
|
|
- self.progress()
|
|
|
-
|
|
|
- def update_db(self):
|
|
|
- self.state["db_updated"] = True
|
|
|
- self.show_msg("✅ База данных обновлена.")
|
|
|
- if self.state["tasks_done"] == 3:
|
|
|
- self.progress()
|
|
|
-
|
|
|
- # ================= ГЛАВНЫЙ ЦИКЛ =================
|
|
|
- def run(self):
|
|
|
- while self.running:
|
|
|
- dt = clock.tick(60)
|
|
|
- for event in pygame.event.get():
|
|
|
- if event.type == pygame.QUIT:
|
|
|
- self.running = False
|
|
|
- for btn in self.buttons:
|
|
|
- btn.handle(event)
|
|
|
-
|
|
|
- if self.msg_timer > 0:
|
|
|
- self.msg_timer -= dt
|
|
|
- if self.msg_timer <= 0: self.message = ""
|
|
|
-
|
|
|
- screen.fill(WHITE)
|
|
|
- draw_text(f"СЦЕНА {self.scene + 1} из 5", 20, 20, BIG_FONT, BLUE)
|
|
|
-
|
|
|
- if self.scene < 5:
|
|
|
- if self.scene == 0:
|
|
|
- screen.blit(self.phone_img, (450, 80))
|
|
|
- if self.state.get("phone_clicked"):
|
|
|
- draw_text("Клиент: Здравствуйте, у меня возникла проблема с заказом, можете помочь?", 100, 350, BIG_FONT)
|
|
|
- else:
|
|
|
- draw_text("Кликните на телефон, чтобы принять звонок.", 300, 150, FONT, DARK_GRAY)
|
|
|
-
|
|
|
- elif self.scene == 1:
|
|
|
- if self.state.get("cal_clicked"):
|
|
|
- draw_text("Расписание открыто. Кликайте на документы -> папки. Подтвердите встречи.", 100, 180, FONT, GREEN)
|
|
|
- else:
|
|
|
- draw_text("Откройте календарь для начала работы.", 350, 200, FONT, DARK_GRAY)
|
|
|
-
|
|
|
- elif self.scene == 2:
|
|
|
- if self.state.get("mail_open"):
|
|
|
- draw_text(f"📩 ЖАЛОБА: {self.email_text}", 50, 250, BIG_FONT, RED)
|
|
|
- draw_text("Выберите шаблон ответа и нажмите 'Отправить'.", 100, 320, FONT, DARK_GRAY)
|
|
|
- else:
|
|
|
- draw_text("Нажмите на иконку почты, чтобы проверить входящие.", 250, 250, FONT, DARK_GRAY)
|
|
|
-
|
|
|
- elif self.scene == 3:
|
|
|
- if self.state.get("call_started"):
|
|
|
- draw_text(f"🗣 Клиент: {self.client_query}", 50, 250, BIG_FONT)
|
|
|
- draw_text(f"🎯 Потребность: {self.need}", 50, 300, FONT, ORANGE)
|
|
|
- else:
|
|
|
- draw_text("Примите звонок, чтобы начать диалог.", 350, 250, FONT, DARK_GRAY)
|
|
|
-
|
|
|
- elif self.scene == 4:
|
|
|
- draw_text("🖥 CRM-СИСТЕМА", 400, 100, BIG_FONT, BLUE)
|
|
|
- draw_text("Выполните задачи и обновите данные в базе.", 250, 150, FONT, DARK_GRAY)
|
|
|
- if self.state["db_updated"]:
|
|
|
- draw_text("✅ Базы обновлены", 700, 450, FONT, GREEN)
|
|
|
-
|
|
|
- if self.message:
|
|
|
- pygame.draw.rect(screen, (50, 50, 50, 230), (50, HEIGHT//2 - 40, WIDTH - 100, 80), border_radius=8)
|
|
|
- draw_text(self.message, WIDTH//2, HEIGHT//2, BIG_FONT, WHITE, True)
|
|
|
-
|
|
|
- for btn in self.buttons:
|
|
|
- btn.draw()
|
|
|
-
|
|
|
- pygame.display.flip()
|
|
|
- pygame.quit()
|
|
|
- sys.exit()
|
|
|
-
|
|
|
-if __name__ == "__main__":
|
|
|
- game = Game()
|
|
|
- game.run()
|
|
|
+ result += "Высокий уровень стресса\n"
|
|
|
+
|
|
|
+ self.show_text(result)
|
|
|
+ self.clear_buttons()
|
|
|
+
|
|
|
+ tk.Button(self.button_frame, text="Выход", command=self.root.quit).pack(pady=10)
|
|
|
+
|
|
|
+ # ---------
|
|
|
+
|
|
|
+ def end_game(self, text):
|
|
|
+ self.show_text(text)
|
|
|
+ self.clear_buttons()
|
|
|
+ tk.Button(self.button_frame, text="Выход", command=self.root.quit).pack()
|
|
|
+
|
|
|
+
|
|
|
+# Запуск
|
|
|
+root = tk.Tk()
|
|
|
+game = AdminGameGUI(root)
|
|
|
+root.mainloop()
|