Загрузка данных
import pygame
import sys
import random
import os
import array
from pathlib import Path
pygame.init()
pygame.mixer.init()
# Размеры экрана
WIDTH, HEIGHT = 1000, 700
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("КПП: Пограничный досмотр")
# Базовый путь к папке скрипта
BASE_DIR = Path(__file__).parent.resolve()
# Шрифты
font = pygame.font.SysFont("Arial", 16)
big_font = pygame.font.SysFont("Arial", 20, bold=True)
small_font = pygame.font.SysFont("Arial", 13)
# Цвета
GRAY = (140, 140, 140)
DARK_WALL = (40, 42, 48)
BORDER_FRAME = (25, 27, 32)
DESK_COLOR = (70, 50, 35)
DESK_DARK = (50, 35, 22)
WINDOW_BG = (100, 140, 180)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (180, 30, 30)
GREEN = (30, 160, 30)
BLUE = (40, 80, 160)
YELLOW = (220, 170, 20)
BROWN = (110, 65, 25)
PASSPORT_COVER = (20, 45, 90)
PAPER_COLOR = (245, 240, 225)
PHONE_BG = (25, 25, 35)
# --- ЗВУКОВЫЕ ЭФФЕКТЫ ---
def create_synth_sound(freq, duration):
sample_rate = 44100
n_samples = int(sample_rate * duration)
buf = array.array('h', [0] * n_samples)
for i in range(n_samples):
t = float(i) / sample_rate
buf[i] = int(0.3 * 32767.0 * (1.0 if (int(t * freq * 2) % 2) else -1.0))
return pygame.mixer.Sound(buffer=buf)
def load_sound(filename, fallback_freq, fallback_dur):
sounds_dir = BASE_DIR / "sounds"
if sounds_dir.exists():
for ext in [".mp3", ".wav", ".MP3", ".WAV"]:
sound_path = sounds_dir / f"{filename}{ext}"
if sound_path.exists():
try:
return pygame.mixer.Sound(str(sound_path))
except Exception as e:
print(f"Ошибка загрузки звука {sound_path}: {e}")
return create_synth_sound(fallback_freq, fallback_dur)
sound_shoot = load_sound("shoot", 150, 0.2)
sound_boom = load_sound("boom", 60, 0.5)
sound_pass = load_sound("pass", 400, 0.15)
# --- УМНАЯ ЗАГРУЗКА ИЗОБРАЖЕНИЙ ДРУЗЕЙ (ХОРОШИЕ / ПЛОХИЕ) ---
good_friends_images = []
bad_friends_images = []
all_friends_images = []
friends_dir = BASE_DIR / "friends"
def load_photo(file_path):
try:
img = pygame.image.load(str(file_path)).convert_alpha()
return pygame.transform.scale(img, (180, 240))
except Exception as e:
print(f"Ошибка загрузки фото {file_path.name}: {e}")
return None
if friends_dir.exists():
# Проверяем подпапки friends/good и friends/bad если они есть
good_dir = friends_dir / "good"
bad_dir = friends_dir / "bad"
if good_dir.exists() or bad_dir.exists():
if good_dir.exists():
for f in good_dir.iterdir():
if f.suffix.lower() in [".png", ".jpg", ".jpeg"]:
img = load_photo(f)
if img: good_friends_images.append(img)
if bad_dir.exists():
for f in bad_dir.iterdir():
if f.suffix.lower() in [".png", ".jpg", ".jpeg"]:
img = load_photo(f)
if img: bad_friends_images.append(img)
else:
# Если подпапок нет, сортируем по имени файла (если есть 'bad' или 'плохой' в названии)
for f in friends_dir.iterdir():
if f.suffix.lower() in [".png", ".jpg", ".jpeg"]:
img = load_photo(f)
if img:
all_friends_images.append(img)
name_lower = f.name.lower()
if "bad" in name_lower or "плох" in name_lower or "vrag" in name_lower:
bad_friends_images.append(img)
else:
good_friends_images.append(img)
# Функция выбора фото с регулируемой вероятностью (по умолчанию 50 на 50)
def get_friend_photo(is_threat_person=False):
# Если персонаж нарушитель — отдаем приоритет плохим фото
# Настройка шансов выпадания: weights=[ШансХорошего, ШансПлохого]
# Настройки: [50, 50] — ровно пополам; [25, 75] — 75% плохих и 25% хороших
weights_config = [50, 50]
if good_friends_images and bad_friends_images:
chosen_type = random.choices(["good", "bad"], weights=weights_config)[0]
if chosen_type == "good":
return random.choice(good_friends_images)
else:
return random.choice(bad_friends_images)
elif all_friends_images:
return random.choice(all_friends_images)
elif good_friends_images:
return random.choice(good_friends_images)
elif bad_friends_images:
return random.choice(bad_friends_images)
return None
# --- ЗАГРУЗКА ПРЕДМЕТОВ ДЛЯ СУМКИ ---
items_images = {}
items_dir = BASE_DIR / "items"
if items_dir.exists():
for file_path in items_dir.iterdir():
if file_path.suffix.lower() in [".png", ".jpg", ".jpeg"]:
try:
item_name = file_path.stem.strip().lower()
img = pygame.image.load(str(file_path)).convert_alpha()
img = pygame.transform.scale(img, (80, 80))
items_images[item_name] = img
except Exception as e:
print(f"Ошибка загрузки предмета {file_path.name}: {e}")
# --- СПИСКИ ДАННЫХ И ПРАВИЛА ---
FRIENDLY_COUNTRIES = ["Россия", "Китай", "КНДР"]
UNFRIENDLY_COUNTRIES = ["США", "Великобритания", "Япония"]
NAMES = ["Алексей", "Иван", "Сергей", "Дмитрий", "Егор", "Максим"]
SAFE_ITEMS_NAMES = ["Вода", "Носки", "Консервы", "Книга"]
BAD_ITEMS_NAMES = ["Бомба", "Запрещенная рация", "Нож"]
GAMES_LIST = ["Brawl Stars", "Subway Surfers", "Roblox", "Minecraft"]
SUSPICIOUS_SEARCH = ["как обойти КПП незаметно", "карта секретных зон", "где купить рацию"]
SAFE_SEARCH = ["погода на завтра", "рецепт блинов", "видео с котиками"]
score = 0
lives = 3
current_screen = "MAIN"
phone_tab = "DESKTOP"
passport_open = False
visitor_x = -200.0
target_x = 180.0
is_walking = True
person_rect = pygame.Rect(180, 80, 180, 240)
def generate_visitor():
global visitor_x, is_walking, passport_open
visitor_x = -200.0
is_walking = True
passport_open = False
# Ровно 50% шанс генерации нарушителя
is_threat = random.choice([True, False])
name = random.choice(NAMES)
avatar = get_friend_photo(is_threat_person=is_threat)
if is_threat:
bad_country = random.choice([True, False])
bad_item = random.choice([True, False])
bad_search = random.choice([True, False])
if not (bad_country or bad_item or bad_search):
bad_country = True
country = random.choice(UNFRIENDLY_COUNTRIES) if bad_country else random.choice(FRIENDLY_COUNTRIES)
bag = random.sample(SAFE_ITEMS_NAMES, 2)
if bad_item:
bag.append(random.choice(BAD_ITEMS_NAMES))
searches = [
random.choice(SUSPICIOUS_SEARCH if bad_search else SAFE_SEARCH),
"погода на завтра"
]
else:
country = random.choice(FRIENDLY_COUNTRIES)
bag = random.sample(SAFE_ITEMS_NAMES, 2)
searches = [random.choice(SAFE_SEARCH), "погода на завтра"]
# Формируем галерею для телефона
gallery_source = (good_friends_images + bad_friends_images) or all_friends_images
gallery_photos = random.sample(gallery_source, min(len(gallery_source), 3)) if gallery_source else []
return {
"name": name,
"country": country,
"is_threat": is_threat,
"bag": bag,
"games": random.sample(GAMES_LIST, 2),
"searches": searches,
"gallery": gallery_photos,
"avatar": avatar
}
visitor = generate_visitor()
message = "Посетитель подходит к окну КПП..."
# Игровые области и кнопки
btn_allow = pygame.Rect(780, 520, 180, 50)
btn_shoot = pygame.Rect(780, 585, 180, 50)
btn_phone = pygame.Rect(40, 610, 200, 45)
btn_grab_bag = pygame.Rect(260, 610, 200, 45)
btn_back = pygame.Rect(780, 600, 160, 45)
# Паспорт на столе
passport_closed_rect = pygame.Rect(520, 400, 160, 110)
passport_open_rect = pygame.Rect(460, 330, 280, 190)
# Кнопки телефона
btn_phone_home = pygame.Rect(450, 580, 100, 30)
btn_app_browser = pygame.Rect(340, 160, 140, 45)
btn_app_gallery = pygame.Rect(500, 160, 140, 45)
clock = pygame.time.Clock()
while True:
screen.fill(BLACK)
dt = clock.tick(60) / 1000.0
if is_walking:
visitor_x += (target_x - visitor_x) * 5.0 * dt
person_rect.x = int(visitor_x)
if abs(target_x - visitor_x) < 1.0:
visitor_x = target_x
person_rect.x = int(target_x)
is_walking = False
message = "Нажмите на паспорт на столе, чтобы открыть его."
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.MOUSEBUTTONDOWN and not is_walking:
pos = event.pos
if current_screen == "MAIN":
if (passport_open_rect.collidepoint(pos) if passport_open else passport_closed_rect.collidepoint(pos)):
passport_open = not passport_open
elif btn_allow.collidepoint(pos):
if visitor["is_threat"]:
sound_boom.play()
lives -= 1
message = "ВЗРЫВ! Вы пропустили опасного нарушителя!"
else:
sound_pass.play()
score += 10
message = "Гражданин успешно пропущен."
visitor = generate_visitor()
elif btn_shoot.collidepoint(pos):
sound_shoot.play()
if visitor["is_threat"]:
score += 15
message = "Нарушитель ликвидирован!"
else:
score -= 10
message = "Ошибка! У человека не было нарушений."
visitor = generate_visitor()
elif btn_phone.collidepoint(pos):
current_screen = "PHONE"
phone_tab = "DESKTOP"
elif btn_grab_bag.collidepoint(pos):
current_screen = "BAG"
elif current_screen == "PHONE":
if btn_back.collidepoint(pos):
current_screen = "MAIN"
elif btn_phone_home.collidepoint(pos):
phone_tab = "DESKTOP"
elif phone_tab == "DESKTOP":
if btn_app_browser.collidepoint(pos):
phone_tab = "BROWSER"
elif btn_app_gallery.collidepoint(pos):
phone_tab = "GALLERY"
elif current_screen == "BAG":
if btn_back.collidepoint(pos):
current_screen = "MAIN"
# --- ЭКРАН КПП ---
if current_screen == "MAIN":
pygame.draw.rect(screen, WINDOW_BG, (100, 40, 360, 290))
if visitor["avatar"]:
screen.blit(visitor["avatar"], (person_rect.x, person_rect.y))
else:
pygame.draw.rect(screen, WHITE, person_rect)
screen.blit(font.render("2D Фото", True, BLACK), (person_rect.x + 50, person_rect.y + 100))
pygame.draw.rect(screen, DARK_WALL, (0, 0, WIDTH, HEIGHT))
pygame.draw.rect(screen, WINDOW_BG, (100, 40, 360, 290))
if visitor["avatar"]:
screen.blit(visitor["avatar"], (person_rect.x, person_rect.y))
else:
pygame.draw.rect(screen, WHITE, person_rect)
screen.blit(font.render("2D Фото", True, BLACK), (person_rect.x + 50, person_rect.y + 100))
pygame.draw.rect(screen, BORDER_FRAME, (100, 40, 360, 290), 12)
pygame.draw.rect(screen, DESK_COLOR, (0, 330, WIDTH, 330))
pygame.draw.rect(screen, DESK_DARK, (0, 330, WIDTH, 15))
# Правила КПП
rule_paper = pygame.Rect(510, 30, 440, 280)
pygame.draw.rect(screen, PAPER_COLOR, rule_paper)
pygame.draw.rect(screen, (200, 190, 170), rule_paper, 2)
pygame.draw.circle(screen, RED, (730, 42), 10)
pygame.draw.circle(screen, BLACK, (730, 42), 10, 2)
pygame.draw.circle(screen, WHITE, (728, 40), 3)
screen.blit(big_font.render("ПРАВИЛА КПП КНДР", True, BLACK), (630, 55))
screen.blit(font.render("1. Пропускать ТОЛЬКО: Россия, Китай, КНДР.", True, GREEN), (530, 100))
screen.blit(font.render("2. Граждан США и других стран — СТРЕЛЯТЬ!", True, RED), (530, 135))
screen.blit(font.render("3. Досматривайте сумку на вещи и оружие.", True, BLACK), (530, 170))
screen.blit(font.render("4. Проверяйте историю и Галерею в телефоне.", True, BLACK), (530, 205))
# Паспорт на столе
if not passport_open:
pygame.draw.rect(screen, PASSPORT_COVER, passport_closed_rect, border_radius=5)
pygame.draw.rect(screen, YELLOW, passport_closed_rect, 2, border_radius=5)
screen.blit(small_font.render("ПАСПОРТ", True, YELLOW), (passport_closed_rect.x + 48, passport_closed_rect.y + 30))
screen.blit(small_font.render("[ Кликни ]", True, WHITE), (passport_closed_rect.x + 48, passport_closed_rect.y + 65))
else:
pygame.draw.rect(screen, PAPER_COLOR, passport_open_rect, border_radius=5)
pygame.draw.rect(screen, BLACK, passport_open_rect, 2, border_radius=5)
pygame.draw.line(screen, GRAY, (passport_open_rect.x + 140, passport_open_rect.y),
(passport_open_rect.x + 140, passport_open_rect.y + 190), 2)
pygame.draw.rect(screen, GRAY, (passport_open_rect.x + 20, passport_open_rect.y + 35, 100, 120))
screen.blit(small_font.render("ФОТО", True, WHITE), (passport_open_rect.x + 50, passport_open_rect.y + 85))
country_is_bad = visitor["country"] in UNFRIENDLY_COUNTRIES
country_color = RED if country_is_bad else GREEN
screen.blit(small_font.render(f"Имя: {visitor['name']}", True, BLACK), (passport_open_rect.x + 150, passport_open_rect.y + 40))
screen.blit(small_font.render("Страна:", True, BLACK), (passport_open_rect.x + 150, passport_open_rect.y + 75))
screen.blit(big_font.render(visitor['country'], True, country_color), (passport_open_rect.x + 150, passport_open_rect.y + 95))
screen.blit(small_font.render("[Кликни чтобы закрыть]", True, GRAY), (passport_open_rect.x + 145, passport_open_rect.y + 160))
pygame.draw.rect(screen, BLUE, btn_phone, border_radius=5)
pygame.draw.rect(screen, BLUE, btn_grab_bag, border_radius=5)
screen.blit(font.render("Проверить телефон", True, WHITE), (btn_phone.x + 20, btn_phone.y + 10))
screen.blit(font.render("Обыскать сумку", True, WHITE), (btn_grab_bag.x + 30, btn_grab_bag.y + 10))
pygame.draw.rect(screen, GREEN, btn_allow, border_radius=5)
pygame.draw.rect(screen, RED, btn_shoot, border_radius=5)
screen.blit(big_font.render("ВПУСТИТЬ", True, WHITE), (btn_allow.x + 40, btn_allow.y + 12))
screen.blit(big_font.render("СТРЕЛЯТЬ", True, WHITE), (btn_shoot.x + 35, btn_shoot.y + 12))
# --- ЭКРАН СУМКИ ---
elif current_screen == "BAG":
pygame.draw.rect(screen, BROWN, (100, 40, 800, 540))
screen.blit(big_font.render("Содержимое сумки:", True, WHITE), (130, 60))
x_offset, y_offset = 140, 120
for item_name in visitor["bag"]:
item_box = pygame.Rect(x_offset, y_offset, 210, 170)
is_bad = item_name in BAD_ITEMS_NAMES
border_color = RED if is_bad else GREEN
pygame.draw.rect(screen, WHITE, item_box)
pygame.draw.rect(screen, border_color, item_box, 4)
key_name = item_name.strip().lower()
if key_name in items_images:
screen.blit(items_images[key_name], (x_offset + 65, y_offset + 20))
else:
pygame.draw.rect(screen, GRAY, (x_offset + 50, y_offset + 20, 110, 80))
screen.blit(font.render("Предмет", True, BLACK), (x_offset + 70, y_offset + 50))
screen.blit(font.render(item_name, True, BLACK), (x_offset + 20, y_offset + 120))
x_offset += 240
pygame.draw.rect(screen, DARK_WALL, btn_back, border_radius=5)
screen.blit(font.render("Назад к КПП", True, WHITE), (btn_back.x + 30, btn_back.y + 10))
# --- ЭКРАН ТЕЛЕФОНА ---
elif current_screen == "PHONE":
pygame.draw.rect(screen, BLACK, (300, 20, 400, 610), border_radius=20)
pygame.draw.rect(screen, PHONE_BG, (320, 60, 360, 510))
pygame.draw.rect(screen, BLACK, (320, 60, 360, 25))
screen.blit(font.render("12:45 | 87% [4G]", True, WHITE), (330, 63))
pygame.draw.rect(screen, GRAY, btn_phone_home, border_radius=5)
screen.blit(font.render("ДОМОЙ", True, BLACK), (btn_phone_home.x + 22, btn_phone_home.y + 5))
if phone_tab == "DESKTOP":
screen.blit(big_font.render("Рабочий стол", True, WHITE), (340, 100))
pygame.draw.rect(screen, GREEN, btn_app_browser, border_radius=8)
screen.blit(font.render("Браузер", True, WHITE), (btn_app_browser.x + 40, btn_app_browser.y + 12))
pygame.draw.rect(screen, BLUE, btn_app_gallery, border_radius=8)
screen.blit(font.render("Галерея", True, WHITE), (btn_app_gallery.x + 40, btn_app_gallery.y + 12))
screen.blit(font.render("Приложения:", True, YELLOW), (340, 250))
y_game = 280
for g in visitor["games"]:
pygame.draw.rect(screen, DARK_WALL, (340, y_game, 320, 35), border_radius=5)
screen.blit(font.render(f"[App] {g}", True, WHITE), (350, y_game + 7))
y_game += 45
elif phone_tab == "BROWSER":
screen.blit(big_font.render("История поиска:", True, WHITE), (340, 95))
y_s = 140
for s in visitor["searches"]:
is_bad = s in SUSPICIOUS_SEARCH
color = RED if is_bad else WHITE
pygame.draw.rect(screen, DARK_WALL, (330, y_s, 340, 40), border_radius=5)
screen.blit(font.render(f"Поиск: {s}", True, color), (340, y_s + 10))
y_s += 50
elif phone_tab == "GALLERY":
screen.blit(big_font.render("Галерея:", True, WHITE), (340, 95))
if visitor["gallery"]:
x_g = 340
for img in visitor["gallery"]:
small_img = pygame.transform.scale(img, (90, 120))
screen.blit(small_img, (x_g, 140))
pygame.draw.rect(screen, WHITE, (x_g, 140, 90, 120), 2)
x_g += 105
else:
screen.blit(font.render("Папка с фото пуста", True, GRAY), (340, 140))
pygame.draw.rect(screen, DARK_WALL, btn_back, border_radius=5)
screen.blit(font.render("Назад к КПП", True, WHITE), (btn_back.x + 30, btn_back.y + 10))
pygame.draw.rect(screen, BLACK, (0, 660, WIDTH, 40))
screen.blit(big_font.render(f"Очки: {score} Жизни: {lives}", True, WHITE), (20, 668))
screen.blit(font.render(message, True, RED if "ВЗРЫВ" in message or "Ошибка" in message else YELLOW), (300, 670))
pygame.display.flip()
clock.tick(60)