Участник:Prionosuchus

Материал из Абсурдопедии
Перейти к навигацииПерейти к поиску

Prionosuchus — древняя амфибия, жившая в пермском периоде (т.е. до Хренозоя).

Коды для игр[править]

(потом перемещу их в нужную статью, а пока проверяю их здесь)

import pygame

import random

import math

pygame.init()

WIDTH, HEIGHT = 1400, 1000

screen = pygame.display.set_mode((WIDTH, HEIGHT))

pygame.display.set_caption("Щучье озеро (вид сверху)")

clock = pygame.time.Clock()

FPS = 60

SAND_COLOR = (210, 180, 140)

WATER_CENTER_COLOR = (20, 80, 180)

BLUE = (50, 150, 250)

GREEN = (0, 150, 0)

BLACK = (0, 0, 0)

WHITE = (255, 255, 255)

RED = (200, 0, 0)

DARK_GREEN = (0, 100, 0)

YELLOW = (255, 255, 0)

ORANGE = (255, 165, 0)

MAX_LEECHES = 1000

MAX_EGGS = 3000

EGG_LIFETIME = 10000

GRID_DISPLAY_TIME = 1000

STARVATION_TIME = 60000

DEATH_SPAWN_EGGS = 20

SHORE_WIDTH = 80

SHORE_WIDTH_SMALL = 20

DARKEN_RECT_W = 340

DARKEN_RECT_H = 300

DARKEN_ALPHA = 80

DARKEN_RECT = pygame.Rect(

   WIDTH // 2 - DARKEN_RECT_W // 2,
   HEIGHT // 2 - DARKEN_RECT_H // 2,
   DARKEN_RECT_W,
   DARKEN_RECT_H

)

font = pygame.font.SysFont("Arial", 20)

big_font = pygame.font.SysFont("Arial", 36)

speech_font = pygame.font.SysFont("Arial", 18)

help_font = pygame.font.SysFont("Arial", 16)

PHRASES_EAT_LEECH = ["Вкуснятина!", "Ням-ням!", "Пиявка - вкусно!", "Ммм, пиявка!"]

PHRASES_EAT_PIKE = ["Ты слишком мал!", "Каннибализм!", "Я сильнее!", "Ай, как нехорошо!"]

PHRASES_EAT_EGG = ["Икорка!", "Вкусные яйца!", "Ням!"]

PHRASES_SPAWN = ["Потомство будет!", "Я папа!", "Я мама!", "Пора размножаться!"]

PHRASES_DEATH_OLD = ["Я устал, ухожу...", "Прощайте, потомки!", "Старость не радость...", "Тима раков, я ливаю!"]

PHRASES_DEATH_STARVE = ["Я голодал...", "Нет еды...", "Помогите!"]

PHRASES_CAUGHT = ["Ой, блесна!", "Попался!", "Твою дивизию!"]

PHRASES_WINTER = ["Капеееееец", "В спячку!", "Зима близко!", "Холодно"]

PHRASES_POST_WINTER = ["Весна пришла!", "Пора нереститься!", "Рота подъём!!!"]

PHRASES_FLEE = ["Я сделал дело, ухожу!", "Пока!", "Ну его нафиг!"]

PHRASES_RANDOM = ["Где еда?", "Я голоден", "Плыву", "Ой, что-то блестит", "Хочу пиявку", "Кто там?"]

PHRASES_FRY_SPAWN = ["Новая жизнь!", "Вперёд!!!", "Я родился!"]

MAX_MESSAGES = 5

messages = []

def add_message(text, x, y, duration=2000, probability=1.0):

   if random.random() > probability:
       return
   global messages
   if len(messages) >= MAX_MESSAGES:
       messages.pop(0)
   messages.append({'text': text, 'x': x, 'y': y, 'timer': pygame.time.get_ticks() + duration})

def random_leech_position():

   if random.random() < 0.7:
       side = random.randint(0, 3)
       if side == 0:
           x = random.uniform(SHORE_WIDTH, 2 * SHORE_WIDTH)
           y = random.uniform(SHORE_WIDTH, HEIGHT - SHORE_WIDTH)
       elif side == 1:
           x = random.uniform(WIDTH - 2 * SHORE_WIDTH, WIDTH - SHORE_WIDTH)
           y = random.uniform(SHORE_WIDTH, HEIGHT - SHORE_WIDTH)
       elif side == 2:
           x = random.uniform(SHORE_WIDTH, WIDTH - SHORE_WIDTH)
           y = random.uniform(SHORE_WIDTH, 2 * SHORE_WIDTH)
       else: 
           x = random.uniform(SHORE_WIDTH, WIDTH - SHORE_WIDTH)
           y = random.uniform(HEIGHT - 2 * SHORE_WIDTH, HEIGHT - SHORE_WIDTH)
   else:
       x = random.uniform(2 * SHORE_WIDTH, WIDTH - 2 * SHORE_WIDTH)
       y = random.uniform(2 * SHORE_WIDTH, HEIGHT - 2 * SHORE_WIDTH)
   return x, y

def random_water_position(small=False):

   limit = SHORE_WIDTH_SMALL if small else SHORE_WIDTH
   x = random.uniform(limit, WIDTH - limit)
   y = random.uniform(limit, HEIGHT - limit)
   return x, y

def create_water_surface(width, height, shore_width):

   surf = pygame.Surface((width, height), pygame.SRCALPHA)
   water_color = WATER_CENTER_COLOR
   surf.fill((water_color[0], water_color[1], water_color[2], 255))
   for y in range(height):
       for x in range(width):
           dx = min(x, width - 1 - x)
           dy = min(y, height - 1 - y)
           d = min(dx, dy)
           if d < shore_width:
               alpha = int(255 * (d / shore_width))
               surf.set_at((x, y), (water_color[0], water_color[1], water_color[2], alpha))
   return surf

sand_surf = pygame.Surface((WIDTH, HEIGHT))

sand_surf.fill(SAND_COLOR)

water_surf = create_water_surface(WIDTH, HEIGHT, SHORE_WIDTH)

winter_active = False

ice_surf = None

def create_ice_surface(width, height):

   """Создаёт полупрозрачную ледяную поверхность."""
   surf = pygame.Surface((width, height), pygame.SRCALPHA)
   surf.fill((200, 230, 255, 80))
   for _ in range(500):
       x = random.randint(0, width - 1)
       y = random.randint(0, height - 1)
       alpha = random.randint(30, 100)
       surf.set_at((x, y), (255, 255, 255, alpha))
   return surf

def toggle_winter():

   global winter_active, ice_surf, leeches, pikes, eggs
   if not winter_active:
       winter_active = True
       ice_surf = create_ice_surface(WIDTH, HEIGHT)
       if leeches:
           leeches = random.sample(leeches, max(1, int(len(leeches) * 0.2)))
       pikes = [p for p in pikes if p.length >= 70]
       center_rect = DARKEN_RECT
       for pike in pikes:
           pike.state = "wintering"
           pike.target_point = (
               random.uniform(center_rect.left, center_rect.right),
               random.uniform(center_rect.top, center_rect.bottom)
           )
           pike.current_speed = pike.base_speed
           pike.target = None
           pike.has_post_winter_spawned = False
           add_message(random.choice(PHRASES_WINTER), pike.x, pike.y, probability=1.0)
   else:
       winter_active = False
       ice_surf = None
       for pike in pikes:
           if pike.state == "wintering":
               pike.state = "post_winter"
               side = random.randint(0, 3)
               if side == 0:
                   x = random.uniform(SHORE_WIDTH, 2 * SHORE_WIDTH)
                   y = random.uniform(SHORE_WIDTH, HEIGHT - SHORE_WIDTH)
               elif side == 1:
                   x = random.uniform(WIDTH - 2 * SHORE_WIDTH, WIDTH - SHORE_WIDTH)
                   y = random.uniform(SHORE_WIDTH, HEIGHT - SHORE_WIDTH)
               elif side == 2:
                   x = random.uniform(SHORE_WIDTH, WIDTH - SHORE_WIDTH)
                   y = random.uniform(SHORE_WIDTH, 2 * SHORE_WIDTH)
               else:
                   x = random.uniform(SHORE_WIDTH, WIDTH - SHORE_WIDTH)
                   y = random.uniform(HEIGHT - 2 * SHORE_WIDTH, HEIGHT - SHORE_WIDTH)
               pike.target_point = (x, y)
               pike.current_speed = pike.base_speed
               pike.target = None
               pike.has_post_winter_spawned = False
               add_message(random.choice(PHRASES_POST_WINTER), pike.x, pike.y, probability=1.0)

class Leech:

   def __init__(self, x, y):
       self.x = x
       self.y = y
       self.length = random.randint(2, 15)
       self.angle = random.uniform(0, 2 * math.pi)
       self.speed = 0.9
       self.segments = 4
       self.time = random.random() * 100
   def update(self):
       if random.random() < 0.02:
           self.angle += random.uniform(-0.5, 0.5)
       self.x += self.speed * math.cos(self.angle)
       self.y += self.speed * math.sin(self.angle)
       if self.x < 0:
           self.x = 0
           self.angle = math.pi - self.angle
       if self.x > WIDTH:
           self.x = WIDTH
           self.angle = math.pi - self.angle
       if self.y < 0:
           self.y = 0
           self.angle = -self.angle
       if self.y > HEIGHT:
           self.y = HEIGHT
           self.angle = -self.angle
       self.time += 0.1
   def draw(self, screen):
       points = []
       step = self.length / self.segments
       x, y = self.x, self.y
       angle = self.angle
       for i in range(self.segments + 1):
           points.append((x, y))
           bend = 0.3 * math.sin(self.time + i * 0.5)
           angle += bend * 0.1
           x += step * math.cos(angle)
           y += step * math.sin(angle)
       if len(points) > 1:
           pygame.draw.lines(screen, BLACK, False, points, 1)

class Egg:

   def __init__(self, x, y):
       self.x = x
       self.y = y
       self.radius = 3
       self.born_time = pygame.time.get_ticks()
   def update(self, pikes):
       if pygame.time.get_ticks() - self.born_time >= EGG_LIFETIME:
           fry_x = max(SHORE_WIDTH_SMALL, min(WIDTH - SHORE_WIDTH_SMALL, self.x))
           fry_y = max(SHORE_WIDTH_SMALL, min(HEIGHT - SHORE_WIDTH_SMALL, self.y))
           fry = Pike(fry_x, fry_y, initial_length=8, state="fleeing_from_spawn")
           angle = random.uniform(0, 2 * math.pi)
           dist = 50
           fry.target_point = (fry_x + dist * math.cos(angle), fry_y + dist * math.sin(angle))
           pikes.append(fry)
           add_message(random.choice(PHRASES_FRY_SPAWN), fry.x, fry.y, probability=1.0)
           return True
       return False
   def draw(self, screen):
       surf = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA)
       pygame.draw.circle(surf, (0, 200, 0, 128), (self.radius, self.radius), self.radius)
       pygame.draw.circle(surf, (0, 100, 0), (self.radius, self.radius), self.radius, 1)
       screen.blit(surf, (self.x - self.radius, self.y - self.radius))

class Bait:

   def __init__(self, x, y):
       self.x = x
       self.y = y
       self.width = 12
       self.height = 8
       self.speed = 5
   def update(self, keys):
       if keys[pygame.K_UP]:
           self.y -= self.speed
       if keys[pygame.K_DOWN]:
           self.y += self.speed
       if keys[pygame.K_LEFT]:
           self.x -= self.speed
       if keys[pygame.K_RIGHT]:
           self.x += self.speed
       self.x = max(SHORE_WIDTH + self.width // 2, min(WIDTH - SHORE_WIDTH - self.width // 2, self.x))
       self.y = max(SHORE_WIDTH + self.height // 2, min(HEIGHT - SHORE_WIDTH - self.height // 2, self.y))
   def draw(self, screen):
       pygame.draw.ellipse(screen, RED, (self.x - self.width // 2, self.y - self.height // 2, self.width, self.height))

class Pike:

   def __init__(self, x, y, initial_length=12, state="normal"):
       self.x = x
       self.y = y
       self.length = initial_length
       self.width = max(5, self.length / 7)
       self.angle = random.uniform(0, 2 * math.pi)
       self.base_speed = self.calc_base_speed(initial_length)
       self.current_speed = self.base_speed
       self.target = None
       self.state = state
       self.target_point = None
       self.max_length_reached = False
       self.time_at_max = 0
       self.last_eat_egg_time = 0
       self.last_meal_time = pygame.time.get_ticks()
       self.last_update_time = pygame.time.get_ticks()
       self.has_spawned_on_death = False
       self.has_post_winter_spawned = False
       self.last_random_speech = random.randint(0, 5000)
       self.generate_sprite()
   def calc_base_speed(self, length):
       return 3.0 - (length - 8) / 152 * 1.0
   def get_shore_limit(self):
       return SHORE_WIDTH_SMALL if self.length <= 29 else SHORE_WIDTH
   def generate_sprite(self):
       w = int(self.length)
       h = int(self.width)
       if w < 5 or h < 3:
           surf = pygame.Surface((w, h), pygame.SRCALPHA)
           pygame.draw.ellipse(surf, GREEN, (0, 0, w, h))
           self.sprite = surf
           return
       surf = pygame.Surface((w, h), pygame.SRCALPHA)
       body_color = (30, 80, 30)
       pygame.draw.ellipse(surf, body_color, (0, 0, w, h))
       spine_color = (20, 60, 20)
       belly_color = (30, 80, 30)
       spine_rect = pygame.Rect(0, 0, w, h // 2 + 2)
       pygame.draw.ellipse(surf, spine_color, spine_rect)
       belly_rect = pygame.Rect(0, h // 2 - 2, w, h // 2 + 2)
       pygame.draw.ellipse(surf, belly_color, belly_rect)
       eye_radius = max(2, int(0.09 * h))
       pupil_radius = max(1, int(0.05 * h))
       eye_x = int(0.8 * w)
       eye_y1 = int(0.35 * h)
       eye_y2 = int(0.65 * h)
       pygame.draw.circle(surf, WHITE, (eye_x, eye_y1), eye_radius)
       pygame.draw.circle(surf, WHITE, (eye_x, eye_y2), eye_radius)
       pupil_offset = int(0.2 * eye_radius)
       pygame.draw.circle(surf, BLACK, (eye_x + pupil_offset, eye_y1), pupil_radius)
       pygame.draw.circle(surf, BLACK, (eye_x + pupil_offset, eye_y2), pupil_radius)
       dorsal_color = (20, 60, 20)
       dorsal_x = int(0.2 * w)
       dorsal_w = int(0.5 * w)
       dorsal_h = max(2, int(h * 0.25))
       pygame.draw.ellipse(surf, dorsal_color, (dorsal_x, 0, dorsal_w, dorsal_h))
       pectoral_color = (20, 60, 20)
       pect_w = int(0.06 * w)
       pect_h = int(0.15 * h)
       pygame.draw.ellipse(surf, pectoral_color, (int(0.6 * w), int(0.05 * h), pect_w, pect_h))
       pygame.draw.ellipse(surf, pectoral_color, (int(0.6 * w), int(0.8 * h), pect_w, pect_h))
       tail_color = ORANGE
       tail_w = int(0.3 * w)
       tail_h = int(0.9 * h)
       tail_x = -tail_w // 2
       tail_y = (h - tail_h) // 2
       pygame.draw.ellipse(surf, tail_color, (tail_x, tail_y, tail_w, tail_h))
       num_spots = random.randint(3, 6)
       for _ in range(num_spots):
           cx = random.uniform(0.2, 0.8) * w
           cy = random.uniform(0.15, 0.4) * h
           rx = random.uniform(0.02, 0.08) * w
           ry = random.uniform(0.02, 0.08) * h
           color = random.choice([(0, 30, 0), (10, 50, 10), (20, 70, 20)])
           pygame.draw.ellipse(surf, color, (int(cx - rx / 2), int(cy - ry / 2), int(rx), int(ry)))
           pygame.draw.ellipse(surf, color, (int(cx - rx / 2), int(h - cy - ry / 2), int(rx), int(ry)))
       for _ in range(random.randint(2, 4)):
           cx = random.uniform(0.3, 0.7) * w
           cy = random.uniform(0.05, 0.2) * h
           rx = random.uniform(0.02, 0.06) * w
           ry = random.uniform(0.01, 0.04) * h
           pygame.draw.ellipse(surf, (0, 20, 0), (int(cx - rx / 2), int(cy - ry / 2), int(rx), int(ry)))
       self.sprite = surf
   def get_tint(self):
       if DARKEN_RECT.collidepoint(self.x, self.y):
           return (0, 0, 0, DARKEN_ALPHA)
       return (0, 0, 0, 0)
   def find_target(self, leeches, pikes, eggs, bait):
       if self.state != "normal":
           self.target = None
           return
       if self.length >= 160 and bait is not None:
           self.target = bait
           return
       min_dist = float('inf')
       target = None
       if self.length < 40:
           for leech in leeches:
               dist = math.hypot(self.x - leech.x, self.y - leech.y)
               if dist < min_dist:
                   min_dist = dist
                   target = leech
       if self.length >= 30:
           for other in pikes:
               if other is self:
                   continue
               if other.length < self.length / 2:
                   dist = math.hypot(self.x - other.x, self.y - other.y)
                   if dist < min_dist:
                       min_dist = dist
                       target = other
       if min_dist == float('inf') or min_dist > 200:
           for egg in eggs:
               dist = math.hypot(self.x - egg.x, self.y - egg.y)
               if dist < min_dist:
                   min_dist = dist
                   target = egg
       self.target = target
   def update(self, leeches, pikes, eggs, bait, current_time):
       dt = current_time - self.last_update_time
       self.last_update_time = current_time
       limit = self.get_shore_limit()
       if self.state == "wintering":
           if self.target_point is not None:
               tx, ty = self.target_point
               dx = tx - self.x
               dy = ty - self.y
               dist = math.hypot(dx, dy)
               if dist > 0:
                   self.angle = math.atan2(dy, dx)
                   if dist < self.current_speed:
                       self.x = tx
                       self.y = ty
                       self.current_speed = 0
                   else:
                       self.x += self.current_speed * dx / dist
                       self.y += self.current_speed * dy / dist
           self.x = max(limit, min(WIDTH - limit, self.x))
           self.y = max(limit, min(HEIGHT - limit, self.y))
           return
       if self.state == "post_winter":
           if self.target_point is not None:
               tx, ty = self.target_point
               dx = tx - self.x
               dy = ty - self.y
               dist = math.hypot(dx, dy)
               if dist > 0:
                   self.angle = math.atan2(dy, dx)
                   if dist < self.current_speed:
                       self.x = tx
                       self.y = ty
                       if not self.has_post_winter_spawned:
                           if self.length >= 50 and len(eggs) < MAX_EGGS:
                               num_eggs = int(0.5 * self.length)
                               for _ in range(num_eggs):
                                   angle = random.uniform(0, 2 * math.pi)
                                   dist2 = random.uniform(10, 30)
                                   ex = self.x + dist2 * math.cos(angle)
                                   ey = self.y + dist2 * math.sin(angle)
                                   ex = max(SHORE_WIDTH + 5, min(WIDTH - SHORE_WIDTH - 5, ex))
                                   ey = max(SHORE_WIDTH + 5, min(HEIGHT - SHORE_WIDTH - 5, ey))
                                   eggs.append(Egg(ex, ey))
                               add_message(random.choice(PHRASES_SPAWN), self.x, self.y, probability=1.0)
                           self.has_post_winter_spawned = True
                       self.state = "normal"
                       self.target_point = None
                       self.current_speed = self.base_speed
                   else:
                       self.x += self.current_speed * dx / dist
                       self.y += self.current_speed * dy / dist
           self.x = max(limit, min(WIDTH - limit, self.x))
           self.y = max(limit, min(HEIGHT - limit, self.y))
           return
       if self.state in ("fleeing_from_spawn", "fleeing_from_eggs"):
           if self.target_point is not None:
               tx, ty = self.target_point
               dx = tx - self.x
               dy = ty - self.y
               dist = math.hypot(dx, dy)
               if dist > 0:
                   self.angle = math.atan2(dy, dx)
                   if dist < self.current_speed:
                       self.x = tx
                       self.y = ty
                   else:
                       self.x += self.current_speed * dx / dist
                       self.y += self.current_speed * dy / dist
               if dist <= self.current_speed + 2:
                   self.state = "normal"
                   self.target_point = None
                   self.current_speed = self.base_speed
           else:
               self.state = "normal"
           self.x = max(limit, min(WIDTH - limit, self.x))
           self.y = max(limit, min(HEIGHT - limit, self.y))
           return
       self.find_target(leeches, pikes, eggs, bait)
       if self.target is not None:
           dx = self.target.x - self.x
           dy = self.target.y - self.y
           dist = math.hypot(dx, dy)
           if dist > 0:
               self.angle = math.atan2(dy, dx)
               if dist < self.current_speed:
                   self.x = self.target.x
                   self.y = self.target.y
               else:
                   self.x += self.current_speed * dx / dist
                   self.y += self.current_speed * dy / dist
       self.x = max(limit, min(WIDTH - limit, self.x))
       self.y = max(limit, min(HEIGHT - limit, self.y))
       if self.state == "normal" and current_time - self.last_random_speech > 5000:
           if random.random() < 0.01:
               phrase = random.choice(PHRASES_RANDOM)
               add_message(phrase, self.x, self.y, duration=1500, probability=1.0)
           self.last_random_speech = current_time
   def check_eat(self, leeches, pikes, eggs, bait, current_time):
       if self.state != "normal":
           return False
       if self.length >= 160 and bait is not None:
           dist = math.hypot(self.x - bait.x, self.y - bait.y)
           if dist < max(10, self.length / 2 + 5):
               add_message(random.choice(PHRASES_CAUGHT), self.x, self.y, probability=1.0)
               return "bait_eaten"
       if self.length < 40:
           for leech in leeches:
               dist = math.hypot(self.x - leech.x, self.y - leech.y)
               if dist < max(10, self.length / 2 + 5):
                   leeches.remove(leech)
                   self.last_meal_time = current_time
                   if not self.max_length_reached:
                       self.length += leech.length
                       self.width = max(5, self.length / 7)
                       self.generate_sprite()
                   prob = 1.0 if self.length > 50 else 0.5
                   add_message(random.choice(PHRASES_EAT_LEECH), self.x, self.y, probability=prob)
                   return True
       if self.length >= 30:
           for other in pikes:
               if other is self:
                   continue
               if other.length < self.length / 2:
                   dist = math.hypot(self.x - other.x, self.y - other.y)
                   if dist < max(10, self.length / 2 + 5):
                       pikes.remove(other)
                       self.last_meal_time = current_time
                       if not self.max_length_reached:
                           self.length += other.length
                           self.width = max(5, self.length / 7)
                           self.generate_sprite()
                       prob = 1.0 if self.length > 50 else 0.5
                       add_message(random.choice(PHRASES_EAT_PIKE), self.x, self.y, probability=prob)
                       return True
       if current_time - self.last_eat_egg_time >= 1000:
           for egg in eggs:
               dist = math.hypot(self.x - egg.x, self.y - egg.y)
               if dist < max(10, self.length / 2 + 5):
                   eggs.remove(egg)
                   self.last_eat_egg_time = current_time
                   self.last_meal_time = current_time
                   if not self.max_length_reached:
                       self.length += 1
                       self.width = max(5, self.length / 7)
                       self.generate_sprite()
                   prob = 1.0 if self.length > 50 else 0.5
                   add_message(random.choice(PHRASES_EAT_EGG), self.x, self.y, probability=prob)
                   return True
       return False
   def draw(self, screen):
       if self.sprite is None:
           return
       rotated = pygame.transform.rotate(self.sprite, -math.degrees(self.angle))
       rect = rotated.get_rect(center=(self.x, self.y))
       tint = self.get_tint()
       if tint[3] > 0:
           tint_surf = pygame.Surface(rotated.get_size(), pygame.SRCALPHA)
           tint_surf.fill(tint)
           rotated.blit(tint_surf, (0, 0), special_flags=pygame.BLEND_RGBA_MULT)
       screen.blit(rotated, rect)

def draw_help_panel(screen):

   panel_x = WIDTH - 260
   panel_y = 20
   panel_w = 240
   panel_h = 300
   s = pygame.Surface((panel_w, panel_h), pygame.SRCALPHA)
   s.fill((0, 0, 0, 80))
   screen.blit(s, (panel_x, panel_y))
   pygame.draw.rect(screen, WHITE, (panel_x, panel_y, panel_w, panel_h), 1)
   lines = [
       ("Управление:", WHITE),
       ("Щ - создать щуку", YELLOW),
       ("1 - установить приманку", YELLOW),
       ("Стрелки - управлять приманкой", YELLOW),
       ("И - создать икру", YELLOW),
       ("З - зима/лето", YELLOW),
       ("Выделение мышью - поймать", YELLOW),
       ("существ в области", YELLOW),
   ]
   y_offset = panel_y + 10
   for text, color in lines:
       surf = help_font.render(text, True, color)
       screen.blit(surf, (panel_x + 10, y_offset))
       y_offset += 22

leeches = []

for _ in range(100):

   x, y = random_leech_position()
   leeches.append(Leech(x, y))

pikes = []

eggs = []

bait = None

last_spawn_time = pygame.time.get_ticks()

spawn_interval = 10000

last_reproduction_time = pygame.time.get_ticks()

reproduction_interval = 15000

catch_message = ""

catch_message_timer = 0

selecting = False

select_start = None

select_end = None

grid_rect = None

grid_timer = 0

running = True

while running:

   current_time = pygame.time.get_ticks()
   keys = pygame.key.get_pressed()
   for event in pygame.event.get():
       if event.type == pygame.QUIT:
           running = False
       if event.type == pygame.KEYDOWN:
           if event.unicode == 'щ':
               x, y = random_water_position(small=True)
               pikes.append(Pike(x, y))
           if event.key == pygame.K_ESCAPE:
               running = False
           if event.key == pygame.K_1:
               mx, my = pygame.mouse.get_pos()
               mx = max(SHORE_WIDTH, min(WIDTH - SHORE_WIDTH, mx))
               my = max(SHORE_WIDTH, min(HEIGHT - SHORE_WIDTH, my))
               bait = Bait(mx, my)
           if event.key == pygame.K_b:
               mx, my = pygame.mouse.get_pos()
               mx = max(SHORE_WIDTH, min(WIDTH - SHORE_WIDTH, mx))
               my = max(SHORE_WIDTH, min(HEIGHT - SHORE_WIDTH, my))
               for _ in range(40):
                   if len(eggs) < MAX_EGGS:
                       angle = random.uniform(0, 2 * math.pi)
                       dist = random.uniform(10, 30)
                       x = mx + dist * math.cos(angle)
                       y = my + dist * math.sin(angle)
                       x = max(SHORE_WIDTH + 5, min(WIDTH - SHORE_WIDTH - 5, x))
                       y = max(SHORE_WIDTH + 5, min(HEIGHT - SHORE_WIDTH - 5, y))
                       eggs.append(Egg(x, y))
           if event.key == pygame.K_p:
               toggle_winter()
       if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
           selecting = True
           select_start = event.pos
           select_end = event.pos
       if event.type == pygame.MOUSEMOTION and selecting:
           select_end = event.pos
       if event.type == pygame.MOUSEBUTTONUP and event.button == 1 and selecting:
           selecting = False
           x1, y1 = select_start
           x2, y2 = select_end
           left = min(x1, x2)
           right = max(x1, x2)
           top = min(y1, y2)
           bottom = max(y1, y2)
           rect = pygame.Rect(left, top, right - left, bottom - top)
           for pike in pikes[:]:
               if rect.collidepoint(pike.x, pike.y):
                   pikes.remove(pike)
           for egg in eggs[:]:
               if rect.collidepoint(egg.x, egg.y):
                   eggs.remove(egg)
           for leech in leeches[:]:
               if rect.collidepoint(leech.x, leech.y):
                   leeches.remove(leech)
           grid_rect = rect
           grid_timer = current_time + GRID_DISPLAY_TIME
   if not winter_active and current_time - last_spawn_time >= spawn_interval:
       last_spawn_time = current_time
       current_count = len(leeches)
       if current_count < MAX_LEECHES:
           new_count = min(current_count * 3, MAX_LEECHES)
           for _ in range(new_count - current_count):
               x, y = random_leech_position()
               leeches.append(Leech(x, y))
   if not winter_active and current_time - last_reproduction_time >= reproduction_interval:
       last_reproduction_time = current_time
       mature = [p for p in pikes if p.length >= 50 and p.state == "normal"]
       if len(mature) >= 2:
           parent = random.choice(mature)
           spawn_x, spawn_y = parent.x, parent.y
           num_eggs = int(1 * parent.length)
           if len(eggs) + num_eggs <= MAX_EGGS:
               for _ in range(num_eggs):
                   angle = random.uniform(0, 2 * math.pi)
                   dist = random.uniform(10, 30)
                   x = spawn_x + dist * math.cos(angle)
                   y = spawn_y + dist * math.sin(angle)
                   x = max(SHORE_WIDTH + 5, min(WIDTH - SHORE_WIDTH - 5, x))
                   y = max(SHORE_WIDTH + 5, min(HEIGHT - SHORE_WIDTH - 5, y))
                   eggs.append(Egg(x, y))
               add_message(random.choice(PHRASES_SPAWN), parent.x, parent.y, probability=1.0)
           parent.state = "fleeing_from_eggs"
           angle = random.uniform(0, 2 * math.pi)
           target_x = spawn_x + 500 * math.cos(angle)
           target_y = spawn_y + 500 * math.sin(angle)
           target_x = max(SHORE_WIDTH, min(WIDTH - SHORE_WIDTH, target_x))
           target_y = max(SHORE_WIDTH, min(HEIGHT - SHORE_WIDTH, target_y))
           parent.target_point = (target_x, target_y)
           parent.target = None
           add_message(random.choice(PHRASES_FLEE), parent.x, parent.y, probability=1.0)
   for egg in eggs[:]:
       if egg.update(pikes):
           eggs.remove(egg)
   if bait is not None:
       bait.update(keys)
   for leech in leeches:
       leech.update()
   for pike in pikes:
       pike.update(leeches, pikes, eggs, bait, current_time)
   for pike in pikes[:]:
       if pike in pikes:
           result = pike.check_eat(leeches, pikes, eggs, bait, current_time)
           if result == "bait_eaten":
               pikes.remove(pike)
               bait = None
               catch_message = "Рыба выловлена!"
               catch_message_timer = current_time + 3000
   for pike in pikes[:]:
       if pike.state in ("wintering", "post_winter"):
           continue
       if not pike.max_length_reached and pike.length >= 160:
           pike.max_length_reached = True
           pike.time_at_max = current_time
       if pike.max_length_reached and (current_time - pike.time_at_max) > 6000:
           if not pike.has_spawned_on_death:
               pike.has_spawned_on_death = True
               for _ in range(DEATH_SPAWN_EGGS):
                   if len(eggs) < MAX_EGGS:
                       angle = random.uniform(0, 2 * math.pi)
                       dist = random.uniform(10, 30)
                       x = pike.x + dist * math.cos(angle)
                       y = pike.y + dist * math.sin(angle)
                       x = max(SHORE_WIDTH + 5, min(WIDTH - SHORE_WIDTH - 5, x))
                       y = max(SHORE_WIDTH + 5, min(HEIGHT - SHORE_WIDTH - 5, y))
                       eggs.append(Egg(x, y))
           add_message(random.choice(PHRASES_DEATH_OLD), pike.x, pike.y, probability=1.0)
           pikes.remove(pike)
           continue
       if pike.length < 160 and (current_time - pike.last_meal_time) > STARVATION_TIME:
           add_message(random.choice(PHRASES_DEATH_STARVE), pike.x, pike.y, probability=1.0)
           pikes.remove(pike)
   screen.blit(sand_surf, (0, 0))
   screen.blit(water_surf, (0, 0))
   if ice_surf is not None:
       screen.blit(ice_surf, (0, 0))
   for leech in leeches:
       leech.draw(screen)
   for egg in eggs:
       egg.draw(screen)
   if bait is not None:
       bait.draw(screen)
   for pike in pikes:
       pike.draw(screen)
   # Отрисовка панели подсказок (поверх всего)
   draw_help_panel(screen)
   messages = [msg for msg in messages if msg['timer'] > current_time]
   if len(messages) > MAX_MESSAGES:
       messages = messages[-MAX_MESSAGES:]
   for msg in messages:
       text_surf = speech_font.render(msg['text'], True, WHITE)
       outline_surf = speech_font.render(msg['text'], True, BLACK)
       x_pos = msg['x'] - text_surf.get_width() // 2
       y_pos = msg['y'] - 30 - text_surf.get_height() // 2
       for dx, dy in [(-1, -1), (-1, 1), (1, -1), (1, 1)]:
           screen.blit(outline_surf, (x_pos + dx, y_pos + dy))
       screen.blit(text_surf, (x_pos, y_pos))
   if selecting and select_start and select_end:
       x1, y1 = select_start
       x2, y2 = select_end
       left = min(x1, x2)
       right = max(x1, x2)
       top = min(y1, y2)
       bottom = max(y1, y2)
       s = pygame.Surface((right - left, bottom - top), pygame.SRCALPHA)
       s.fill((255, 255, 255, 30))
       screen.blit(s, (left, top))
       pygame.draw.rect(screen, WHITE, (left, top, right - left, bottom - top), 1)
   if grid_rect and current_time < grid_timer:
       left, top, w, h = grid_rect
       cell_size = 4
       for y in range(top, top + h + 1, cell_size):
           if y <= HEIGHT:
               pygame.draw.line(screen, BLACK, (left, y), (left + w, y), 1)
       for x in range(left, left + w + 1, cell_size):
           if x <= WIDTH:
               pygame.draw.line(screen, BLACK, (x, top), (x, top + h), 1)
   if grid_rect and current_time >= grid_timer:
       grid_rect = None
   text = font.render(f"Пиявок: {len(leeches)}  Щук: {len(pikes)}  Икринок: {len(eggs)}", True, WHITE)
   screen.blit(text, (10, 10))
   if catch_message and current_time < catch_message_timer:
       msg_surf = big_font.render(catch_message, True, YELLOW)
       screen.blit(msg_surf, (WIDTH // 2 - msg_surf.get_width() // 2, 50))
   elif catch_message:
       catch_message = ""
   pygame.display.flip()
   clock.tick(FPS)

pygame.quit()