Загрузка данных


import pygame, math, random

pygame.init()
W, H = 950, 700
screen = pygame.display.set_mode((W, H))
pygame.display.set_caption("CS-Lite")
clock = pygame.time.Clock()
font = pygame.font.SysFont("arial", 28)
font_big = pygame.font.SysFont("arial", 60, bold=True)
font_small = pygame.font.SysFont("arial", 20)

FLOOR_COLOR = (55, 50, 45)
WALL_COLOR = (90, 80, 70)
WALL_TOP = (120, 108, 95)

# ---------- КАРТА (стены как прямоугольники) ----------
walls = [
    pygame.Rect(0, 0, W, 20), pygame.Rect(0, H-20, W, 20),
    pygame.Rect(0, 0, 20, H), pygame.Rect(W-20, 0, 20, H),
    pygame.Rect(200, 100, 30, 250),
    pygame.Rect(400, 300, 250, 30),
    pygame.Rect(650, 80, 30, 300),
    pygame.Rect(120, 450, 300, 30),
    pygame.Rect(550, 500, 30, 180),
    pygame.Rect(750, 400, 150, 30),
]

def wall_blocks(x, y):
    for w in walls:
        if w.collidepoint(x, y):
            return True
    return False

def line_hits_wall(x1, y1, x2, y2, steps=40):
    for i in range(steps + 1):
        t = i / steps
        x = x1 + (x2 - x1) * t
        y = y1 + (y2 - y1) * t
        if wall_blocks(x, y):
            return (x, y)
    return None


class Particle:
    def __init__(self, x, y, color, speed_range=(1, 5), life_range=(10, 25), size=3):
        self.x, self.y = x, y
        angle = random.uniform(0, math.pi * 2)
        speed = random.uniform(*speed_range)
        self.vx = math.cos(angle) * speed
        self.vy = math.sin(angle) * speed
        self.life = random.uniform(*life_range)
        self.max_life = self.life
        self.color = color
        self.size = size

    def update(self):
        self.x += self.vx
        self.y += self.vy
        self.vx *= 0.9
        self.vy *= 0.9
        self.life -= 1

    def draw(self, surf):
        if self.life > 0:
            a = int(255 * (self.life / self.max_life))
            s = pygame.Surface((self.size*2, self.size*2), pygame.SRCALPHA)
            pygame.draw.circle(s, (*self.color, a), (self.size, self.size), self.size)
            surf.blit(s, (self.x - self.size, self.y - self.size))


class Bullet:
    def __init__(self, x, y, angle, owner):
        self.x, self.y = x, y
        self.vx = math.cos(angle) * 16
        self.vy = math.sin(angle) * 16
        self.owner = owner
        self.trail = [(x, y)]
        self.dead = False

    def update(self):
        self.x += self.vx
        self.y += self.vy
        self.trail.append((self.x, self.y))
        if len(self.trail) > 4:
            self.trail.pop(0)
        if wall_blocks(self.x, self.y) or self.x < 0 or self.x > W or self.y < 0 or self.y > H:
            self.dead = True

    def draw(self, surf):
        if len(self.trail) >= 2:
            pygame.draw.line(surf, (255, 240, 150), self.trail[0], self.trail[-1], 2)


class Entity:
    def __init__(self, x, y, color, is_player=False):
        self.x, self.y = x, y
        self.radius = 13
        self.color = color
        self.angle = 0
        self.hp = 100
        self.is_player = is_player
        self.alive = True
        self.reload_timer = 0
        self.shoot_cooldown = 0
        self.ai_dir_timer = 0
        self.ai_move_angle = random.uniform(0, math.pi*2)
        self.ai_shoot_timer = random.uniform(30, 90)

    def try_move(self, dx, dy):
        new_x = self.x + dx
        new_y = self.y + dy
        if not wall_blocks(new_x, self.y):
            self.x = new_x
        if not wall_blocks(self.x, new_y):
            self.y = new_y

    def draw(self, surf, light_pos=None):
        # тень
        shadow = pygame.Surface((self.radius*3, self.radius*1.5), pygame.SRCALPHA)
        pygame.draw.ellipse(shadow, (0, 0, 0, 90), shadow.get_rect())
        surf.blit(shadow, (self.x - self.radius*1.5, self.y + self.radius*0.6))

        # тело
        pygame.draw.circle(surf, (20, 20, 20), (int(self.x), int(self.y)), self.radius + 2)
        pygame.draw.circle(surf, self.color, (int(self.x), int(self.y)), self.radius)

        # оружие (линия в направлении взгляда)
        gx = self.x + math.cos(self.angle) * (self.radius + 16)
        gy = self.y + math.sin(self.angle) * (self.radius + 16)
        pygame.draw.line(surf, (30, 30, 30), (self.x, self.y), (gx, gy), 5)

        # полоска HP
        bar_w = 34
        pygame.draw.rect(surf, (40, 0, 0), (self.x - bar_w/2, self.y - self.radius - 16, bar_w, 6))
        pygame.draw.rect(surf, (60, 220, 90), (self.x - bar_w/2, self.y - self.radius - 16, bar_w * (self.hp/100), 6))


player = Entity(80, 80, (70, 150, 230), is_player=True)
bots = [
    Entity(850, 620, (220, 70, 70)),
    Entity(880, 150, (220, 70, 70)),
    Entity(500, 630, (220, 70, 70)),
]

bullets = []
particles = []
kills = 0
game_over = False
win = False
ammo = 12
max_ammo = 12
RELOAD_TIME = 90

def shoot(entity, targets_particles=True):
    global ammo
    if entity.is_player:
        if ammo <= 0 or entity.reload_timer > 0:
            return
        ammo -= 1
    bullets.append(Bullet(
        entity.x + math.cos(entity.angle) * (entity.radius + 10),
        entity.y + math.sin(entity.angle) * (entity.radius + 10),
        entity.angle + random.uniform(-0.03, 0.03),
        entity
    ))
    for _ in range(6):
        particles.append(Particle(
            entity.x + math.cos(entity.angle) * (entity.radius + 12),
            entity.y + math.sin(entity.angle) * (entity.radius + 12),
            (255, 200, 80), speed_range=(2, 5), life_range=(6, 12), size=3
        ))

running = True
while running:
    clock.tick(60)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1 and not game_over:
            shoot(player)
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_r and not game_over:
                if ammo < max_ammo and player.reload_timer <= 0:
                    player.reload_timer = RELOAD_TIME
            if event.key == pygame.K_r and game_over:
                player = Entity(80, 80, (70, 150, 230), is_player=True)
                bots = [
                    Entity(850, 620, (220, 70, 70)),
                    Entity(880, 150, (220, 70, 70)),
                    Entity(500, 630, (220, 70, 70)),
                ]
                bullets, particles = [], []
                kills = 0
                ammo = max_ammo
                game_over = False
                win = False

    keys = pygame.key.get_pressed()
    mx, my = pygame.mouse.get_pos()

    if not game_over:
        player.angle = math.atan2(my - player.y, mx - player.x)

        speed = 4.2
        dx = dy = 0
        if keys[pygame.K_w]: dy -= speed
        if keys[pygame.K_s]: dy += speed
        if keys[pygame.K_a]: dx -= speed
        if keys[pygame.K_d]: dx += speed
        if dx and dy:
            dx *= 0.7071
            dy *= 0.7071
        player.try_move(dx, dy)

        if player.reload_timer > 0:
            player.reload_timer -= 1
            if player.reload_timer == 0:
                ammo = max_ammo

        # AI ботов
        for bot in bots:
            if not bot.alive:
                continue
            dist_to_player = math.hypot(player.x - bot.x, player.y - bot.y)
            los_block = line_hits_wall(bot.x, bot.y, player.x, player.y)

            if los_block is None and dist_to_player < 500:
                bot.angle = math.atan2(player.y - bot.y, player.x - bot.x)
                bot.ai_shoot_timer -= 1
                if bot.ai_shoot_timer <= 0:
                    shoot(bot)
                    bot.ai_shoot_timer = random.uniform(35, 70)
                if dist_to_player > 220:
                    bot.try_move(math.cos(bot.angle)*2.4, math.sin(bot.angle)*2.4)
            else:
                bot.ai_dir_timer -= 1
                if bot.ai_dir_timer <= 0:
                    bot.ai_move_angle = random.uniform(0, math.pi*2)
                    bot.ai_dir_timer = random.uniform(40, 90)
                bot.angle = bot.ai_move_angle
                bot.try_move(math.cos(bot.ai_move_angle)*1.8, math.sin(bot.ai_move_angle)*1.8)

        # пули
        for b in bullets[:]:
            b.update()
            targets = ([player] if not b.owner.is_player else bots)
            for t in targets:
                if t.alive and math.hypot(b.x - t.x, b.y - t.y) < t.radius + 4:
                    t.hp -= random.randint(18, 30)
                    for _ in range(14):
                        particles.append(Particle(t.x, t.y, (200, 30, 30), speed_range=(1,4), life_range=(15,30), size=3))
                    b.dead = True
                    if t.hp <= 0 and t.alive:
                        t.alive = False
                        if t.is_player:
                            game_over = True
                            win = False
                        else:
                            kills += 1
                    break
            if b.dead:
                bullets.remove(b)

        for p in particles[:]:
            p.update()
            if p.life <= 0:
                particles.remove(p)

        if all(not b.alive for b in bots):
            game_over = True
            win = True

    # ---------- ОТРИСОВКА ----------
    screen.fill(FLOOR_COLOR)
    # лёгкая текстура пола (полосы)
    for i in range(0, W, 40):
        pygame.draw.line(screen, (50, 45, 40), (i, 0), (i, H), 1)
    for i in range(0, H, 40):
        pygame.draw.line(screen, (50, 45, 40), (0, i), (W, i), 1)

    for w in walls:
        shadow_rect = w.copy()
        shadow_rect.x += 6
        shadow_rect.y += 6
        pygame.draw.rect(screen, (0, 0, 0, 60), shadow_rect)
        pygame.draw.rect(screen, WALL_COLOR, w)
        pygame.draw.rect(screen, WALL_TOP, w, 3)

    for b in bullets:
        b.draw(screen)
    for p in particles:
        p.draw(screen)

    if player.alive:
        player.draw(screen)
    for bot in bots:
        if bot.alive:
            bot.draw(screen)

    # ---------- ОСВЕЩЕНИЕ (затемнение + свет вокруг игрока) ----------
    darkness = pygame.Surface((W, H), pygame.SRCALPHA)
    darkness.fill((5, 5, 10, 235))
    light_radius = 260
    light = pygame.Surface((light_radius*2, light_radius*2), pygame.SRCALPHA)
    for i in range(light_radius, 0, -4):
        alpha = int(235 * (1 - i / light_radius) ** 2)
        pygame.draw.circle(light, (5, 5, 10, alpha), (light_radius, light_radius), i)
    darkness.blit(light, (player.x - light_radius, player.y - light_radius), special_flags=pygame.BLEND_RGBA_MIN)
    screen.blit(darkness, (0, 0))

    # HUD
    hud_ammo = font.render(f"{ammo} / {max_ammo}" + ("  ПЕРЕЗАРЯДКА..." if player.reload_timer > 0 else ""), True, (255, 255, 255))
    hud_kills = font.render(f"Убийств: {kills}/{len(bots)}", True, (255, 220, 100))
    hud_hp = font.render(f"HP: {max(0, player.hp)}", True, (100, 255, 130))
    screen.blit(hud_ammo, (20, H - 45))
    screen.blit(hud_kills, (20, 20))
    screen.blit(hud_hp, (20, 55))
    hint = font_small.render("WASD — движение, мышь — прицел, ЛКМ — стрелять, R — перезарядка", True, (200, 200, 200))
    screen.blit(hint, (W//2 - hint.get_width()//2, H - 30))

    if game_over:
        overlay = pygame.Surface((W, H), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 170))
        screen.blit(overlay, (0, 0))
        msg = "ПОБЕДА" if win else "ТЫ УБИТ"
        color = (100, 255, 130) if win else (255, 70, 70)
        text = font_big.render(msg, True, color)
        screen.blit(text, (W//2 - text.get_width()//2, H//2 - 60))
        restart = font.render("Нажми R чтобы сыграть заново", True, (255, 255, 255))
        screen.blit(restart, (W//2 - restart.get_width()//2, H//2 + 20))

    pygame.display.flip()

pygame.quit()