Загрузка данных
import pygame
import sys
import os
import random
# Инициализация Pygame и звука
pygame.init()
pygame.font.init()
pygame.mixer.init()
# --- АВТООПРЕДЕЛЕНИЕ ПУТЕЙ ДЛЯ .EXE ---
def get_path(relative_path):
if getattr(sys, 'frozen', False):
base_path = os.path.dirname(sys.executable)
else:
base_path = os.path.dirname(os.path.abspath(__file__))
return os.path.join(base_path, relative_path)
# Размеры экрана
WIDTH, HEIGHT = 900, 650
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("КПП: Пограничный досмотр")
# Цвета
BG_COLOR = (40, 44, 52)
DESK_COLOR = (70, 50, 40)
TEXT_COLOR = (255, 255, 255)
BTN_GREEN = (46, 139, 87)
BTN_RED = (178, 34, 34)
BTN_BLUE = (30, 144, 255)
PANEL_BG = (230, 230, 230)
PASSPORT_BG = (240, 230, 210)
# Шрифты
font_main = pygame.font.SysFont("Arial", 15)
font_bold = pygame.font.SysFont("Arial", 17, bold=True)
font_large = pygame.font.SysFont("Arial", 22, bold=True)
# Загрузка звуков
sounds = {}
def load_sounds():
sound_files = {
'allow': 'allow.wav',
'deny': 'deny.wav',
'click': 'click.wav'
}
for name, file in sound_files.items():
path = get_path(os.path.join('sounds', file))
if os.path.exists(path):
try:
sounds[name] = pygame.mixer.Sound(path)
except:
sounds[name] = None
else:
sounds[name] = None
def play_sound(name):
if name in sounds and sounds[name]:
sounds[name].play()
load_sounds()
# Состояние игры
score = 0
lives = 3
current_npc = None
# Состояния окон
inspecting_passport = False
inspecting_phone = False
inspecting_bag = False
# Списки стран
VALID_COUNTRIES = ["Россия", "Китай", "КНДР"]
INVALID_COUNTRIES = ["США", "Великобритания", "Германия", "Япония"]
def load_image_files(folder_path):
path = get_path(folder_path)
if not os.path.exists(path):
os.makedirs(path, exist_ok=True)
return []
valid_exts = ('.png', '.jpg', '.jpeg', '.bmp')
return [os.path.join(path, f) for f in os.listdir(path) if f.lower().endswith(valid_exts)]
def load_and_scale(image_path, size):
try:
img = pygame.image.load(image_path).convert_alpha()
return pygame.transform.scale(img, size)
except Exception:
return create_placeholder(size, "Ошибка")
def create_placeholder(size, text):
surf = pygame.Surface(size)
surf.fill((200, 200, 200))
pygame.draw.rect(surf, (100, 100, 100), surf.get_rect(), 2)
txt_surf = font_main.render(text, True, (50, 50, 50))
rect = txt_surf.get_rect(center=(size[0]//2, size[1]//2))
surf.blit(txt_surf, rect)
return surf
class NPC:
def __init__(self):
# 60% шанс на нелегала
self.is_threat = random.random() < 0.60
# Страна и данные
if self.is_threat and random.random() < 0.5:
self.country = random.choice(INVALID_COUNTRIES)
else:
self.country = random.choice(VALID_COUNTRIES)
self.passport_valid = (self.country in VALID_COUNTRIES)
self.name = random.choice(["Иван", "Ли", "Ким", "Алексей", "Чжан", "Пак"]) + " " + random.choice(["Иванов", "Вэй", "Мин", "Петров", "Сун"])
self.doc_id = str(random.randint(100000, 999999))
# Аватар (friends)
friends_files = load_image_files('friends')
if friends_files:
self.avatar_path = random.choice(friends_files)
self.avatar = load_and_scale(self.avatar_path, (180, 220))
self.pass_avatar = load_and_scale(self.avatar_path, (90, 110))
else:
self.avatar = create_placeholder((180, 220), "Нет фото")
self.pass_avatar = create_placeholder((90, 110), "Нет фото")
# Галерея телефона (phone_photos)
good_photos = load_image_files(os.path.join('phone_photos', 'good'))
bad_photos = load_image_files(os.path.join('phone_photos', 'bad'))
self.phone_gallery = []
# Выбираем несколько хороших фото
if good_photos:
sample_g = random.sample(good_photos, min(len(good_photos), random.randint(2, 4)))
for p in sample_g:
self.phone_gallery.append(('good', load_and_scale(p, (160, 200))))
# Если угроз - подбрасываем bad-фото
if self.is_threat and bad_photos:
bad_p = random.choice(bad_photos)
self.phone_gallery.append(('bad', load_and_scale(bad_p, (160, 200))))
random.shuffle(self.phone_gallery)
self.phone_photo_index = 0
# Предметы в сумке (items)
items_files = load_image_files('items')
self.items = []
if items_files:
sample_count = min(len(items_files), random.randint(2, 4))
selected = random.sample(items_files, sample_count)
for path in selected:
fname = os.path.splitext(os.path.basename(path))[0]
if fname.lower() == "запрещенная рация":
fname = "Рация"
self.items.append((fname, load_and_scale(path, (55, 55))))
def check_verdict(self, player_action):
should_deny = self.is_threat or (not self.passport_valid)
if player_action == 'allow':
return not should_deny
else:
return should_deny
def spawn_npc():
global current_npc, inspecting_passport, inspecting_phone, inspecting_bag
current_npc = NPC()
inspecting_passport = False
inspecting_phone = False
inspecting_bag = False
# Отрисовка основного интерфейса
def draw_ui():
screen.fill(BG_COLOR)
# Стол
pygame.draw.rect(screen, DESK_COLOR, (0, 330, WIDTH, HEIGHT - 330))
# Окно досмотра персонажа
pygame.draw.rect(screen, (20, 20, 20), (40, 30, 300, 270), border_radius=5)
if current_npc:
screen.blit(current_npc.avatar, (100, 55))
# Правила
rule_rect = pygame.Rect(370, 30, 480, 180)
pygame.draw.rect(screen, (245, 235, 210), rule_rect, border_radius=5)
pygame.draw.rect(screen, (100, 80, 50), rule_rect, 3, border_radius=5)
rules = [
"ПРАВИЛА КПП КНДР",
"1. Пропускать ТОЛЬКО: Россия, Китай, КНДР",
"2. Граждан США и других стран — СТРЕЛЯТЬ!",
"3. Проверяйте паспорт, телефон и содержимое сумки.",
"4. Обнаружение запрещенных фото/предметов = СТРЕЛЯТЬ!"
]
for i, line in enumerate(rules):
color = (180, 0, 0) if "СТРЕЛЯТЬ" in line else (0, 0, 0)
txt = (font_bold if i==0 else font_main).render(line, True, color)
screen.blit(txt, (385, 40 + i * 32))
# Кнопка ПАСПОРТ на столе
btn_passport = pygame.Rect(370, 230, 200, 70)
pygame.draw.rect(screen, (30, 60, 120), btn_passport, border_radius=8)
pygame.draw.rect(screen, (215, 165, 32), btn_passport, 3, border_radius=8)
txt_pass = font_large.render("ПАСПОРТ", True, (255, 215, 0))
screen.blit(txt_pass, txt_pass.get_rect(center=btn_passport.center))
# Кнопки действий
btn_allow = pygame.Rect(600, 430, 250, 55)
btn_deny = pygame.Rect(600, 500, 250, 55)
pygame.draw.rect(screen, BTN_GREEN, btn_allow, border_radius=8)
pygame.draw.rect(screen, BTN_RED, btn_deny, border_radius=8)
txt_allow = font_large.render("ВПУСТИТЬ", True, TEXT_COLOR)
txt_deny = font_large.render("СТРЕЛЯТЬ", True, TEXT_COLOR)
screen.blit(txt_allow, txt_allow.get_rect(center=btn_allow.center))
screen.blit(txt_deny, txt_deny.get_rect(center=btn_deny.center))
# Кнопки проверок
btn_phone = pygame.Rect(40, 570, 240, 45)
btn_bag = pygame.Rect(300, 570, 240, 45)
pygame.draw.rect(screen, BTN_BLUE, btn_phone, border_radius=8)
pygame.draw.rect(screen, BTN_BLUE, btn_bag, border_radius=8)
txt_phone = font_bold.render("Проверить телефон", True, TEXT_COLOR)
txt_bag = font_bold.render("Обыскать сумку", True, TEXT_COLOR)
screen.blit(txt_phone, txt_phone.get_rect(center=btn_phone.center))
screen.blit(txt_bag, txt_bag.get_rect(center=btn_bag.center))
# Статистика
stat_txt = font_large.render(f"Очки: {score} Жизни: {lives}", True, TEXT_COLOR)
screen.blit(stat_txt, (40, 310))
# --- ОВЕРЛЕИ И ОКНА ---
# 1. Отдельное окно Паспорта
if inspecting_passport and current_npc:
pass_box = pygame.Rect(250, 150, 400, 250)
pygame.draw.rect(screen, PASSPORT_BG, pass_box, border_radius=10)
pygame.draw.rect(screen, (100, 80, 50), pass_box, 4, border_radius=10)
screen.blit(current_npc.pass_avatar, (270, 180))
t1 = font_bold.render(f"Имя: {current_npc.name}", True, (0, 0, 0))
t2 = font_bold.render(f"Страна: {current_npc.country}", True, (0, 0, 0))
t3 = font_main.render(f"№: {current_npc.doc_id}", True, (50, 50, 50))
screen.blit(t1, (380, 180))
screen.blit(t2, (380, 220))
screen.blit(t3, (380, 260))
# 2. Окно Телефона с браузером и прокруткой фото
btn_next_photo = None
if inspecting_phone and current_npc:
phone_box = pygame.Rect(40, 320, 240, 240)
pygame.draw.rect(screen, (10, 10, 10), phone_box, border_radius=15)
pygame.draw.rect(screen, (70, 70, 70), phone_box, 3, border_radius=15)
# Шапка смартфона / Браузер
pygame.draw.rect(screen, (40, 40, 40), (50, 330, 220, 25), border_radius=5)
net_txt = font_main.render("Браузер / Галерея", True, (200, 200, 200))
screen.blit(net_txt, (60, 333))
if current_npc.phone_gallery:
idx = current_npc.phone_photo_index
_, photo_img = current_npc.phone_gallery[idx]
screen.blit(photo_img, (80, 360))
# Кнопка листания фото
btn_next_photo = pygame.Rect(70, 525, 180, 25)
pygame.draw.rect(screen, (60, 60, 60), btn_next_photo, border_radius=5)
ntxt = font_main.render(f"След. фото ({idx+1}/{len(current_npc.phone_gallery)})", True, TEXT_COLOR)
screen.blit(ntxt, ntxt.get_rect(center=btn_next_photo.center))
else:
empty_txt = font_main.render("Галерея пуста", True, (250, 250, 250))
screen.blit(empty_txt, (100, 420))
# 3. Отдельное окно Сумки
if inspecting_bag and current_npc:
bag_box = pygame.Rect(300, 320, 260, 240)
pygame.draw.rect(screen, PANEL_BG, bag_box, border_radius=10)
pygame.draw.rect(screen, (80, 80, 80), bag_box, 3, border_radius=10)
title_bag = font_bold.render("СОДЕРЖИМОЕ СУМКИ:", True, (0, 0, 0))
screen.blit(title_bag, (315, 330))
if not current_npc.items:
t = font_main.render("Запрещенных вещей нет", True, (100, 100, 100))
screen.blit(t, (315, 380))
else:
for idx, (iname, img) in enumerate(current_npc.items):
screen.blit(img, (315, 360 + idx * 55))
lbl = font_bold.render(iname, True, (0, 0, 0))
screen.blit(lbl, (380, 375 + idx * 55))
return btn_allow, btn_deny, btn_phone, btn_bag, btn_passport, btn_next_photo
# Главный цикл
spawn_npc()
clock = pygame.time.Clock()
while True:
btn_allow, btn_deny, btn_phone, btn_bag, btn_passport, btn_next_photo = draw_ui()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
mpos = event.pos
# Проверка нажатий по кнопкам
if btn_passport.collidepoint(mpos):
play_sound('click')
inspecting_passport = not inspecting_passport
inspecting_phone = False
inspecting_bag = False
elif btn_phone.collidepoint(mpos):
play_sound('click')
inspecting_phone = not inspecting_phone
inspecting_passport = False
inspecting_bag = False
elif btn_bag.collidepoint(mpos):
play_sound('click')
inspecting_bag = not inspecting_bag
inspecting_passport = False
inspecting_phone = False
elif btn_next_photo and btn_next_photo.collidepoint(mpos):
play_sound('click')
if current_npc and current_npc.phone_gallery:
current_npc.phone_photo_index = (current_npc.phone_photo_index + 1) % len(current_npc.phone_gallery)
elif btn_allow.collidepoint(mpos):
if current_npc.check_verdict('allow'):
play_sound('allow')
score += 100
else:
play_sound('deny')
lives -= 1
spawn_npc()
elif btn_deny.collidepoint(mpos):
if current_npc.check_verdict('deny'):
play_sound('deny')
score += 100
else:
play_sound('allow')
lives -= 1
spawn_npc()
if lives <= 0:
score = 0
lives = 3
spawn_npc()
pygame.display.flip()
clock.tick(30)