game.py 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. import pygame
  2. import os
  3. import sys
  4. # ================= ИНИЦИАЛИЗАЦИЯ =================
  5. pygame.init()
  6. WIDTH, HEIGHT = 1024, 768
  7. screen = pygame.display.set_mode((WIDTH, HEIGHT))
  8. pygame.display.set_caption("Симулятор: Административный персонал")
  9. clock = pygame.time.Clock()
  10. FONT = pygame.font.SysFont("Arial", 20)
  11. BIG_FONT = pygame.font.SysFont("Arial", 26)
  12. ASSET_DIR = r"C:\VVV"
  13. # Цвета
  14. WHITE = (255, 255, 255)
  15. BLACK = (0, 0, 0)
  16. GRAY = (210, 210, 210)
  17. DARK_GRAY = (100, 100, 100)
  18. BLUE = (40, 100, 180)
  19. GREEN = (40, 150, 40)
  20. RED = (180, 40, 40)
  21. ORANGE = (230, 160, 40)
  22. # ================= УТИЛИТЫ =================
  23. def load_asset(filename, fallback_color=GRAY, w=100, h=80):
  24. path = os.path.join(ASSET_DIR, filename)
  25. if os.path.exists(path):
  26. try:
  27. img = pygame.image.load(path).convert_alpha()
  28. return img
  29. except:
  30. pass
  31. surf = pygame.Surface((w, h), pygame.SRCALPHA)
  32. surf.fill(fallback_color)
  33. txt = FONT.render(filename, True, BLACK)
  34. surf.blit(txt, (5, h//2-10))
  35. return surf
  36. def draw_text(text, x, y, font=FONT, color=BLACK, center=False):
  37. surf = font.render(text, True, color)
  38. rect = surf.get_rect(center=(x, y)) if center else surf.get_rect(topleft=(x, y))
  39. screen.blit(surf, rect)
  40. class Button:
  41. def __init__(self, x, y, w, h, text, callback, color=BLUE, hover_color=(60, 120, 200)):
  42. self.rect = pygame.Rect(x, y, w, h)
  43. self.text = text
  44. self.callback = callback
  45. self.color = color
  46. self.hover_color = hover_color
  47. self.hovered = False
  48. self.selected = False
  49. def draw(self):
  50. c = self.hover_color if self.hovered else self.color
  51. if self.selected: c = GREEN
  52. pygame.draw.rect(screen, c, self.rect, border_radius=6)
  53. pygame.draw.rect(screen, BLACK, self.rect, 2, border_radius=6)
  54. draw_text(self.text, self.rect.centerx, self.rect.centery, color=WHITE, font=FONT)
  55. def handle(self, event):
  56. if event.type == pygame.MOUSEMOTION:
  57. self.hovered = self.rect.collidepoint(event.pos)
  58. elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
  59. if self.hovered:
  60. if self.callback: self.callback()
  61. return True
  62. return False
  63. # ================= ИГРОВОЙ КЛАСС =================
  64. class Game:
  65. def __init__(self):
  66. self.scene = 0
  67. self.running = True
  68. self.message = ""
  69. self.msg_timer = 0
  70. self.buttons = []
  71. self.state = {}
  72. self.setup_scene()
  73. def show_msg(self, text, duration=2500):
  74. self.message = text
  75. self.msg_timer = duration
  76. def progress(self):
  77. self.scene += 1
  78. self.buttons = []
  79. self.state = {}
  80. self.message = ""
  81. if self.scene >= 5:
  82. self.show_msg("🎉 Поздравляем! Вы успешно прошли все этапы обучения!", 99999)
  83. else:
  84. self.setup_scene()
  85. def reset_scene(self):
  86. self.show_msg("❌ Задача не выполнена. Перезапуск сцены...", 2000)
  87. self.buttons = []
  88. self.state = {}
  89. self.setup_scene()
  90. def setup_scene(self):
  91. self.buttons = []
  92. if self.scene == 0: self.init_scene1()
  93. elif self.scene == 1: self.init_scene2()
  94. elif self.scene == 2: self.init_scene3()
  95. elif self.scene == 3: self.init_scene4()
  96. elif self.scene == 4: self.init_scene5()
  97. # ---------- СЦЕНА 1: Звонок ----------
  98. def init_scene1(self):
  99. self.state = {"phone_clicked": False, "answered": False}
  100. self.phone_img = load_asset("phone.png", ORANGE, 120, 120)
  101. self.buttons.append(Button(400, 220, 220, 80, "📞 Принять звонок", self.click_phone, GRAY))
  102. self.buttons.append(Button(80, 400, 280, 60, "Конечно, расскажите подробнее", lambda: self.check_call(0)))
  103. self.buttons.append(Button(380, 400, 280, 60, "Это не в нашей компетенции", lambda: self.check_call(1)))
  104. self.buttons.append(Button(680, 400, 280, 60, "Не можем помочь сейчас", lambda: self.check_call(2)))
  105. def click_phone(self): self.state["phone_clicked"] = True
  106. def check_call(self, idx):
  107. if not self.state["phone_clicked"]: return
  108. if idx == 0: self.progress()
  109. else: self.reset_scene()
  110. # ---------- СЦЕНА 2: Рабочий процесс ----------
  111. def init_scene2(self):
  112. self.state = {"cal_clicked": False, "selected_doc": None, "docs_sorted": 0, "meetings_ok": 0}
  113. self.docs = [
  114. {"id": 0, "name": "Отчет_Q1", "cat": "Отчеты", "sorted": False},
  115. {"id": 1, "name": "Договор_А", "cat": "Договоры", "sorted": False},
  116. {"id": 2, "name": "Запрос_Клиента", "cat": "Запросы", "sorted": False}
  117. ]
  118. self.meetings = [{"id": 0, "time": "10:00", "handled": False}, {"id": 1, "time": "15:00", "handled": False}]
  119. self.buttons.append(Button(350, 100, 300, 60, "📅 Календарь", self.click_cal, GRAY))
  120. def click_cal(self):
  121. self.state["cal_clicked"] = True
  122. for i, d in enumerate(self.docs):
  123. cb = Button(150 + i*250, 250, 180, 50, d["name"], lambda i=i: self.select_doc(i), DARK_GRAY)
  124. cb.is_doc = True; cb.doc_id = i
  125. self.buttons.append(cb)
  126. for i, name in enumerate(["Отчеты", "Договоры", "Запросы"]):
  127. self.buttons.append(Button(100 + i*300, 450, 180, 50, f"📁 {name}", lambda c=name: self.sort_doc(c)))
  128. for i, m in enumerate(self.meetings):
  129. self.buttons.append(Button(200, 580, 180, 40, f"Встреча {m['time']}", lambda i=i: self.handle_meeting(i)))
  130. def select_doc(self, idx):
  131. if self.docs[idx]["sorted"]: return
  132. self.state["selected_doc"] = idx
  133. self.show_msg(f"Выбран: {self.docs[idx]['name']}. Кликните на папку.")
  134. def sort_doc(self, cat):
  135. sel = self.state["selected_doc"]
  136. if sel is None: return
  137. if self.docs[sel]["cat"] == cat:
  138. self.docs[sel]["sorted"] = True
  139. self.state["docs_sorted"] += 1
  140. self.state["selected_doc"] = None
  141. self.show_msg("✅ Документ разложен верно!")
  142. else:
  143. self.show_msg("❌ Неверная категория!")
  144. self.check_scene2_win()
  145. def handle_meeting(self, idx):
  146. if not self.meetings[idx]["handled"]:
  147. self.meetings[idx]["handled"] = True
  148. self.state["meetings_ok"] += 1
  149. self.show_msg("✅ Запрос на встречу обработан.")
  150. self.check_scene2_win()
  151. def check_scene2_win(self):
  152. if self.state["docs_sorted"] == 3 and self.state["meetings_ok"] == 2:
  153. self.progress()
  154. # ---------- СЦЕНА 3: Жалоба по Email ----------
  155. def init_scene3(self):
  156. self.state = {"mail_open": False, "template": -1}
  157. self.templates = [
  158. {"text": "Приносим извинения за неудобства. Решим проблему в течение 24ч.", "correct": True},
  159. {"text": "Жалоба принята. Гарантий не даем.", "correct": False},
  160. {"text": "Мы не можем повлиять на ситуацию.", "correct": False}
  161. ]
  162. self.buttons.append(Button(400, 150, 220, 60, "📧 Открыть почту", self.open_mail, GRAY))
  163. for i, t in enumerate(self.templates):
  164. btn = Button(100, 350 + i*70, 824, 60, t["text"], lambda i=i: self.pick_template(i))
  165. btn.is_template = True; btn.tpl_idx = i
  166. self.buttons.append(btn)
  167. self.buttons.append(Button(400, 600, 200, 50, "📤 Отправить", self.send_mail, GREEN))
  168. self.email_text = "Здравствуйте! Получил заказ с браком. Требую замены или возврата."
  169. def open_mail(self): self.state["mail_open"] = True
  170. def pick_template(self, idx):
  171. self.state["template"] = idx
  172. for b in self.buttons:
  173. if hasattr(b, 'is_template'):
  174. b.selected = (b.tpl_idx == idx)
  175. def send_mail(self):
  176. if not self.state["mail_open"]: return
  177. if self.state["template"] != -1 and self.templates[self.state["template"]]["correct"]:
  178. self.progress()
  179. else:
  180. self.show_msg("❌ Клиент недоволен ответом. Попробуйте другой шаблон.")
  181. # ---------- СЦЕНА 4: Продажа по телефону ----------
  182. def init_scene4(self):
  183. self.state = {"call_started": False, "chosen": -1}
  184. self.need = "Консультация + Скидка на первый заказ"
  185. self.offers = [
  186. {"text": "Базовая консультация без бонусов.", "match": False},
  187. {"text": "Персональная консультация + 10% скидка на первую покупку.", "match": True},
  188. {"text": "Отправим каталог на email. Консультации нет.", "match": False}
  189. ]
  190. self.buttons.append(Button(400, 150, 220, 60, "📞 Принять звонок", self.start_call, GRAY))
  191. for i, o in enumerate(self.offers):
  192. btn = Button(100, 350 + i*80, 824, 60, o["text"], lambda i=i: self.pick_offer(i))
  193. btn.is_offer = True; btn.offer_idx = i
  194. self.buttons.append(btn)
  195. self.client_query = "Добрый день! Интересует ваш продукт. Хотелось бы получить консультацию и узнать про скидки."
  196. def start_call(self): self.state["call_started"] = True
  197. def pick_offer(self, idx):
  198. self.state["chosen"] = idx
  199. for b in self.buttons:
  200. if hasattr(b, 'is_offer'):
  201. b.selected = (b.offer_idx == idx)
  202. if self.offers[idx]["match"]:
  203. self.show_msg("✅ Отличная продажа! Клиент согласился.")
  204. self.progress()
  205. else:
  206. self.show_msg("❌ Предложение не подошло. Клиент отказался. Перезапуск...")
  207. self.reset_scene()
  208. # ---------- СЦЕНА 5: CRM-система ----------
  209. def init_scene5(self):
  210. self.state = {"tasks_done": 0, "db_updated": False}
  211. self.tasks = [
  212. {"id": 0, "desc": "Добавить контакт Иванова И.И.", "done": False},
  213. {"id": 1, "desc": "Обновить статус заказа #482", "done": False},
  214. {"id": 2, "desc": "Назначить встречу с ООО 'Вектор'", "done": False}
  215. ]
  216. for i, t in enumerate(self.tasks):
  217. btn = Button(150, 200 + i*90, 450, 60, f"☐ {t['desc']}", lambda i=i: self.complete_task(i), DARK_GRAY)
  218. btn.is_task = True
  219. btn.task_id = i
  220. self.buttons.append(btn)
  221. self.buttons.append(Button(700, 350, 200, 60, "💾 Обновить БД", self.update_db, BLUE))
  222. def complete_task(self, idx):
  223. if self.tasks[idx]["done"]: return
  224. self.tasks[idx]["done"] = True
  225. self.state["tasks_done"] += 1
  226. # Безопасное обновление кнопки без синтаксических ошибок
  227. for b in self.buttons:
  228. if hasattr(b, 'task_id') and b.task_id == idx:
  229. b.text = f"✅ {self.tasks[idx]['desc']}"
  230. b.color = GREEN
  231. self.show_msg("✅ Задача выполнена. Не забудьте обновить базу данных.")
  232. if self.state["tasks_done"] == 3 and self.state["db_updated"]:
  233. self.progress()
  234. def update_db(self):
  235. self.state["db_updated"] = True
  236. self.show_msg("✅ База данных обновлена.")
  237. if self.state["tasks_done"] == 3:
  238. self.progress()
  239. # ================= ГЛАВНЫЙ ЦИКЛ =================
  240. def run(self):
  241. while self.running:
  242. dt = clock.tick(60)
  243. for event in pygame.event.get():
  244. if event.type == pygame.QUIT:
  245. self.running = False
  246. for btn in self.buttons:
  247. btn.handle(event)
  248. if self.msg_timer > 0:
  249. self.msg_timer -= dt
  250. if self.msg_timer <= 0: self.message = ""
  251. screen.fill(WHITE)
  252. draw_text(f"СЦЕНА {self.scene + 1} из 5", 20, 20, BIG_FONT, BLUE)
  253. if self.scene < 5:
  254. if self.scene == 0:
  255. screen.blit(self.phone_img, (450, 80))
  256. if self.state.get("phone_clicked"):
  257. draw_text("Клиент: Здравствуйте, у меня возникла проблема с заказом, можете помочь?", 100, 350, BIG_FONT)
  258. else:
  259. draw_text("Кликните на телефон, чтобы принять звонок.", 300, 150, FONT, DARK_GRAY)
  260. elif self.scene == 1:
  261. if self.state.get("cal_clicked"):
  262. draw_text("Расписание открыто. Кликайте на документы -> папки. Подтвердите встречи.", 100, 180, FONT, GREEN)
  263. else:
  264. draw_text("Откройте календарь для начала работы.", 350, 200, FONT, DARK_GRAY)
  265. elif self.scene == 2:
  266. if self.state.get("mail_open"):
  267. draw_text(f"📩 ЖАЛОБА: {self.email_text}", 50, 250, BIG_FONT, RED)
  268. draw_text("Выберите шаблон ответа и нажмите 'Отправить'.", 100, 320, FONT, DARK_GRAY)
  269. else:
  270. draw_text("Нажмите на иконку почты, чтобы проверить входящие.", 250, 250, FONT, DARK_GRAY)
  271. elif self.scene == 3:
  272. if self.state.get("call_started"):
  273. draw_text(f"🗣 Клиент: {self.client_query}", 50, 250, BIG_FONT)
  274. draw_text(f"🎯 Потребность: {self.need}", 50, 300, FONT, ORANGE)
  275. else:
  276. draw_text("Примите звонок, чтобы начать диалог.", 350, 250, FONT, DARK_GRAY)
  277. elif self.scene == 4:
  278. draw_text("🖥 CRM-СИСТЕМА", 400, 100, BIG_FONT, BLUE)
  279. draw_text("Выполните задачи и обновите данные в базе.", 250, 150, FONT, DARK_GRAY)
  280. if self.state["db_updated"]:
  281. draw_text("✅ Базы обновлены", 700, 450, FONT, GREEN)
  282. if self.message:
  283. pygame.draw.rect(screen, (50, 50, 50, 230), (50, HEIGHT//2 - 40, WIDTH - 100, 80), border_radius=8)
  284. draw_text(self.message, WIDTH//2, HEIGHT//2, BIG_FONT, WHITE, True)
  285. for btn in self.buttons:
  286. btn.draw()
  287. pygame.display.flip()
  288. pygame.quit()
  289. sys.exit()
  290. if __name__ == "__main__":
  291. game = Game()
  292. game.run()