Ver 1.1.1
This commit is contained in:
parent
e0ba49f02e
commit
c655d5b815
68
README.md
68
README.md
@ -1,6 +1,6 @@
|
|||||||
# Шахматы с Открытым Миром 1.1
|
# Шахматы с Открытым Миром 1.1.1
|
||||||
|
|
||||||
Добро пожаловать в **Шахматы с Открытым Миром 1.1** – инновационную версию классической игры, обогащённую новыми механиками, бонусами и динамическим туманом войны. Погрузитесь в захватывающий мир стратегии, где каждое решение может изменить ход партии!
|
Добро пожаловать в **Шахматы с Открытым Миром 1.1.1** – инновационную версию классической игры, обогащённую новыми механиками, бонусами, магазином и динамическим туманом войны. Погрузитесь в захватывающий мир стратегии, где каждое решение может изменить ход партии!
|
||||||
|
|
||||||
## Содержание
|
## Содержание
|
||||||
|
|
||||||
@ -9,6 +9,7 @@
|
|||||||
- [Туман Войны](#туман-войны)
|
- [Туман Войны](#туман-войны)
|
||||||
- [Бонусные Поля](#бонусные-поля)
|
- [Бонусные Поля](#бонусные-поля)
|
||||||
- [Бои и HP Фигур](#бои-и-hp-фигур)
|
- [Бои и HP Фигур](#бои-и-hp-фигур)
|
||||||
|
- [Торговцы и Магазин](#торговцы-и-магазин)
|
||||||
3. [Механика Времени](#механика-времени)
|
3. [Механика Времени](#механика-времени)
|
||||||
4. [Процедурная Генерация Бонусов](#процедурная-генерация-бонусов)
|
4. [Процедурная Генерация Бонусов](#процедурная-генерация-бонусов)
|
||||||
5. [Баланс Фигур](#баланс-фигур)
|
5. [Баланс Фигур](#баланс-фигур)
|
||||||
@ -44,7 +45,7 @@
|
|||||||
- **Типы Бонусов**:
|
- **Типы Бонусов**:
|
||||||
- **Регенерация (regen)**: Восстанавливает 1-2 HP фигуре (кроме короля).
|
- **Регенерация (regen)**: Восстанавливает 1-2 HP фигуре (кроме короля).
|
||||||
- **Повышение HP (hp_upgrade)**: Увеличивает максимальный HP фигуры на 1 (кроме короля).
|
- **Повышение HP (hp_upgrade)**: Увеличивает максимальный HP фигуры на 1 (кроме короля).
|
||||||
- **Урон (damage)**: Наносит 1-5 урона фигуре.
|
- **Урон (damage)**: Вычитает 3 HP из фигуры противника без её уничтожения.
|
||||||
- **Повышение HP Короля (king_hp_upgrade)**: Увеличивает или восстанавливает HP короля.
|
- **Повышение HP Короля (king_hp_upgrade)**: Увеличивает или восстанавливает HP короля.
|
||||||
- **Добавление Фигуры (add_piece)**: Добавляет новую фигуру рядом с текущей, если возможно.
|
- **Добавление Фигуры (add_piece)**: Добавляет новую фигуру рядом с текущей, если возможно.
|
||||||
|
|
||||||
@ -70,12 +71,24 @@
|
|||||||
- **Взаимодействие Фигур**:
|
- **Взаимодействие Фигур**:
|
||||||
- **Атака**: Когда фигура перемещается на клетку с вражеской фигурой, начинается бой.
|
- **Атака**: Когда фигура перемещается на клетку с вражеской фигурой, начинается бой.
|
||||||
- **Исход Боя**:
|
- **Исход Боя**:
|
||||||
- Если HP атакующего меньше HP защитника: Защитник теряет HP атакующего, атакующий погибает.
|
- Если HP атакующего меньше HP защитника: Защитник теряет HP атакующего, атакующий теряет 3 HP (не умирает).
|
||||||
- Если HP атакующего больше HP защитника: Атакующий теряет HP защитника, защитник погибает.
|
- Если HP атакующего больше HP защитника: Атакующий теряет HP защитника, защитник теряет 3 HP (не умирает).
|
||||||
- Если HP равны: Атакующий остаётся с 1 HP, защитник погибает.
|
- Если HP равны: Атакующий остаётся с 1 HP, защитник теряет 3 HP (не умирает).
|
||||||
|
|
||||||
- **Убийство Короля**: Захват короля противника завершает игру.
|
- **Убийство Короля**: Захват короля противника завершает игру.
|
||||||
|
|
||||||
|
### Торговцы и Магазин
|
||||||
|
|
||||||
|
На поле расположены **торговцы**, представляющие специальные клетки, с которыми можно взаимодействовать:
|
||||||
|
|
||||||
|
- **Позиции Торговцев**: Центральная линия по краям поля.
|
||||||
|
- **Взаимодействие с Торговцем**: При перемещении на клетку торговца открывается **магазин**.
|
||||||
|
- **Магазин** предлагает следующие улучшения:
|
||||||
|
- **Расширить ход**: Увеличивает длину хода для специальных фигур до 5 клеток и для пешек до 2 клеток. Стоимость: 3 монеты.
|
||||||
|
- **Увеличить HP**: Увеличивает `max_hp` всех фигур на 3, кроме короля. Стоимость: 3 монеты.
|
||||||
|
- **Уменьшить HP врага**: Вычитает 3 HP у всех фигур противника без их уничтожения. Если HP противника меньше 3, устанавливает HP на 1. Стоимость: 3 монеты.
|
||||||
|
- **Проклятие**: Уменьшает вероятность появления бонусов у противника `regen` и `hp_upgrade` на 10% каждая. Стоимость: 3 монеты.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Механика Времени
|
## Механика Времени
|
||||||
@ -86,7 +99,9 @@
|
|||||||
- **Отсчёт Времени**:
|
- **Отсчёт Времени**:
|
||||||
- Таймер отображается в правом нижнем углу.
|
- Таймер отображается в правом нижнем углу.
|
||||||
- При истечении времени, таймер становится красным.
|
- При истечении времени, таймер становится красным.
|
||||||
- **Повторный Пропуск**: Если игрок снова пропустит свой ход, он автоматически проигрывает.
|
- **Переполнение Времени**:
|
||||||
|
- **Первый пропуск**: Таймер становится красным.
|
||||||
|
- **Второй пропуск**: Игрок автоматически проигрывает.
|
||||||
- **Переключение Хода**: После каждого хода время сбрасывается для следующего игрока.
|
- **Переключение Хода**: После каждого хода время сбрасывается для следующего игрока.
|
||||||
|
|
||||||
---
|
---
|
||||||
@ -97,10 +112,10 @@
|
|||||||
|
|
||||||
- **Когда Генерируются Бонусы**:
|
- **Когда Генерируются Бонусы**:
|
||||||
- При выходе клетки из тумана войны, с вероятностью **10%** может появиться бонусное поле.
|
- При выходе клетки из тумана войны, с вероятностью **10%** может появиться бонусное поле.
|
||||||
|
|
||||||
- **Тип Бонуса**:
|
- **Тип Бонуса**:
|
||||||
- Тип бонуса выбирается на основе текущих вероятностей.
|
- Тип бонуса выбирается на основе текущих вероятностей.
|
||||||
- После **100 ходов**, вероятность появления бонусов типа "урон" (красные поля) постепенно увеличивается до **50%**, делая игру более опасной.
|
- После **100 ходов**, вероятность появления бонусов типа "урон" (**damage**) постепенно увеличивается до **50%**, делая игру более опасной.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -118,27 +133,24 @@
|
|||||||
|
|
||||||
## Обновления и Изменения
|
## Обновления и Изменения
|
||||||
|
|
||||||
### Версия 1.1
|
### Версия 1.1.1
|
||||||
|
|
||||||
1. **Баланс Красных Полей**:
|
1. **Добавление Магазина и Монет**:
|
||||||
- **Урон**: Теперь красные поля наносят от **1 до 5 урона**, исключая возможность отсутствия урона.
|
- **Магазин**: Теперь доступен при взаимодействии с торговцами на поле. Магазин предлагает различные улучшения за монеты.
|
||||||
- **Исправление Бага**: При прохождении через красное поле и гибели фигуры, ход корректно переходит к противнику.
|
- **Монеты**: Появляются на поле с шансом **0.1%**, становясь более ценными и редкими.
|
||||||
|
|
||||||
|
2. **Исправление Механики Товара "Уменьшить HP врага"**:
|
||||||
|
- Теперь при покупке этого бонуса у всех фигур противника вычитается **3 HP**, но фигуры не умирают.
|
||||||
|
- Если HP противника меньше 3, устанавливается **1 HP**.
|
||||||
|
|
||||||
2. **Процедурная Генерация Бонусов**:
|
3. **Улучшение Баланса и Механик**:
|
||||||
- Бонусные поля теперь генерируются **процедурно** при выходе клеток из тумана войны.
|
- **Шанс генерации монет** снижен до **0.1%**, уменьшая их количество и повышая ценность.
|
||||||
- **Вероятность Появления**: Каждая новая открытая клетка имеет **10%** шанс стать бонусной.
|
- **Удалено отображение вероятностей** генерации бонусов и монет из интерфейса игры, упрощая визуальное восприятие.
|
||||||
- **Тип Бонуса**: Выбор типа бонуса осуществляется согласно текущим вероятностям.
|
|
||||||
|
|
||||||
3. **Баланс Фигур с Свободным Передвижением**:
|
4. **Прочие Улучшения**:
|
||||||
- **Ферзь и Ладья** теперь могут перемещаться до **3 клеток** вместо 5, обеспечивая более сбалансированную игру.
|
- Оптимизация интерфейса магазина для улучшения взаимодействия с пользователем.
|
||||||
|
- Устранение багов, связанных с переходом ходов после применения бонусов.
|
||||||
|
|
||||||
4. **Механика Повышения Вероятности Красных Полей**:
|
Спасибо за внимание и приятной игры в **Шахматы с Открытым Миром 1.1.1**!
|
||||||
- После **100 ходов**, вероятность появления бонусных полей типа "урон" постепенно увеличивается до **50%**.
|
|
||||||
- **Отображение Ходов**: Внизу экрана отображается счётчик ходов. После 100 ходов счётчик становится красным, сигнализируя о начале увеличения опасности.
|
|
||||||
|
|
||||||
5. **Механика Времени на Ход**:
|
---
|
||||||
- Каждый игрок имеет **2 минуты** на свой ход.
|
|
||||||
- **Отображение Таймера**: Таймер находится в правом нижнем углу экрана.
|
|
||||||
- **Переполнение Времени**:
|
|
||||||
- При первом переполнении таймер становится красным.
|
|
||||||
- При втором переполнении, игрок автоматически проигрывает.
|
|
||||||
|
@ -9,7 +9,8 @@ pygame.init()
|
|||||||
CELL_SIZE = 32
|
CELL_SIZE = 32
|
||||||
GRID_WIDTH = 30
|
GRID_WIDTH = 30
|
||||||
GRID_HEIGHT = 30
|
GRID_HEIGHT = 30
|
||||||
WINDOW_WIDTH = CELL_SIZE * GRID_WIDTH
|
PANEL_WIDTH = 200 # Ширина правой панели
|
||||||
|
WINDOW_WIDTH = CELL_SIZE * GRID_WIDTH + PANEL_WIDTH
|
||||||
WINDOW_HEIGHT = CELL_SIZE * GRID_HEIGHT
|
WINDOW_HEIGHT = CELL_SIZE * GRID_HEIGHT
|
||||||
|
|
||||||
# --- ЦВЕТА ---
|
# --- ЦВЕТА ---
|
||||||
@ -40,8 +41,14 @@ COLOR_PRE_FOG = (169, 169, 169) # Светло-серый
|
|||||||
COLOR_TIMER_NORMAL = (255, 255, 255) # Белый
|
COLOR_TIMER_NORMAL = (255, 255, 255) # Белый
|
||||||
COLOR_TIMER_WARNING = (255, 0, 0) # Красный
|
COLOR_TIMER_WARNING = (255, 0, 0) # Красный
|
||||||
|
|
||||||
|
# Цвет торговца
|
||||||
|
COLOR_MERCHANT = (139, 69, 19) # Коричневый
|
||||||
|
|
||||||
|
# Цвет монеты
|
||||||
|
COLOR_COIN = (255, 165, 0) # Оранжевый
|
||||||
|
|
||||||
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
|
screen = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
|
||||||
pygame.display.set_caption("Шахматы с открытым миром 1.0")
|
pygame.display.set_caption("Шахматы с Открытым Миром 1.1.1")
|
||||||
|
|
||||||
# Шрифты
|
# Шрифты
|
||||||
font = pygame.font.SysFont(None, CELL_SIZE // 2)
|
font = pygame.font.SysFont(None, CELL_SIZE // 2)
|
||||||
@ -49,6 +56,7 @@ victory_font = pygame.font.SysFont(None, 60)
|
|||||||
turn_font = pygame.font.SysFont(None, 30)
|
turn_font = pygame.font.SysFont(None, 30)
|
||||||
counter_font = pygame.font.SysFont(None, 30)
|
counter_font = pygame.font.SysFont(None, 30)
|
||||||
timer_font = pygame.font.SysFont(None, 25)
|
timer_font = pygame.font.SysFont(None, 25)
|
||||||
|
shop_font = pygame.font.SysFont(None, 24)
|
||||||
|
|
||||||
# --- Глобальное множество открытых клеток (туман войны) ---
|
# --- Глобальное множество открытых клеток (туман войны) ---
|
||||||
global_revealed = set()
|
global_revealed = set()
|
||||||
@ -59,15 +67,13 @@ piece_symbols = {
|
|||||||
'knight': 'К',
|
'knight': 'К',
|
||||||
'bishop': 'С',
|
'bishop': 'С',
|
||||||
'queen': 'Ф',
|
'queen': 'Ф',
|
||||||
'king': 'К', # Король (можно заменить на 'K' или другой символ)
|
'king': 'К', # Король
|
||||||
'pawn': 'П'
|
'pawn': 'П'
|
||||||
}
|
}
|
||||||
|
|
||||||
# === МЕХАНИКА БОНУСОВ ===
|
# === МЕХАНИКА БОНУСОВ ===
|
||||||
# Храним в глобальном словаре bonus_cells: {(x,y): {'type': ...}}
|
|
||||||
bonus_cells = {}
|
bonus_cells = {}
|
||||||
|
|
||||||
# Вероятности появления различных типов бонусов
|
|
||||||
base_bonus_probabilities = {
|
base_bonus_probabilities = {
|
||||||
'regen': 0.42, # 42%
|
'regen': 0.42, # 42%
|
||||||
'hp_upgrade': 0.32, # 32%
|
'hp_upgrade': 0.32, # 32%
|
||||||
@ -78,7 +84,6 @@ base_bonus_probabilities = {
|
|||||||
|
|
||||||
bonus_probabilities = base_bonus_probabilities.copy()
|
bonus_probabilities = base_bonus_probabilities.copy()
|
||||||
|
|
||||||
# Функция для выбора бонуса на основе вероятностей
|
|
||||||
def choose_bonus_type():
|
def choose_bonus_type():
|
||||||
rand = random.random()
|
rand = random.random()
|
||||||
cumulative = 0
|
cumulative = 0
|
||||||
@ -90,35 +95,20 @@ def choose_bonus_type():
|
|||||||
|
|
||||||
# === МЕХАНИКА БОЯ ===
|
# === МЕХАНИКА БОЯ ===
|
||||||
def resolve_combat(attacker, defender):
|
def resolve_combat(attacker, defender):
|
||||||
"""
|
|
||||||
Атакующая фигура (A) идёт на клетку защитника (B).
|
|
||||||
HP(A)=a, HP(B)=b.
|
|
||||||
- Если a < b: B теряет a (b := b-a), A погибает.
|
|
||||||
- Если a > b: A теряет b (a := a-b), B погибает.
|
|
||||||
- Если a == b: A побеждает, убивает B, а у A остаётся 1 HP.
|
|
||||||
Возвращаем кортеж: (attacker_alive, defender_alive)
|
|
||||||
при этом изменяем HP в самих объектах.
|
|
||||||
"""
|
|
||||||
a = attacker.hp
|
a = attacker.hp
|
||||||
b = defender.hp
|
b = defender.hp
|
||||||
|
|
||||||
if a < b:
|
if a < b:
|
||||||
# Защитник теряет a HP
|
|
||||||
defender.hp = b - a
|
defender.hp = b - a
|
||||||
# Атакующая погибает
|
|
||||||
attacker.hp = 0
|
attacker.hp = 0
|
||||||
return (False, True)
|
return (False, True)
|
||||||
|
|
||||||
elif a > b:
|
elif a > b:
|
||||||
# Атакующая теряет b HP
|
|
||||||
attacker.hp = a - b
|
attacker.hp = a - b
|
||||||
# Защитник погибает
|
|
||||||
defender.hp = 0
|
defender.hp = 0
|
||||||
return (True, False)
|
return (True, False)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# a == b
|
|
||||||
# Атакующая побеждает, остаётся с 1 HP
|
|
||||||
attacker.hp = 1
|
attacker.hp = 1
|
||||||
defender.hp = 0
|
defender.hp = 0
|
||||||
return (True, False)
|
return (True, False)
|
||||||
@ -156,12 +146,12 @@ class Piece:
|
|||||||
ny = self.y + dy
|
ny = self.y + dy
|
||||||
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
||||||
blocking = next((p for p in pieces if p.x == nx and p.y == ny), None)
|
blocking = next((p for p in pieces if p.x == nx and p.y == ny), None)
|
||||||
# Можем ходить, если клетка пуста или там враг
|
|
||||||
if not blocking or blocking.color != self.color:
|
if not blocking or blocking.color != self.color:
|
||||||
moves.append((nx, ny))
|
moves.append((nx, ny))
|
||||||
|
|
||||||
elif self.name in ['rook', 'bishop', 'queen']:
|
elif self.name in ['rook', 'bishop', 'queen']:
|
||||||
# Ограничиваем движение до 3 клеток
|
# Ограничиваем движение до 3 клеток или до 5 для улучшенного хода
|
||||||
|
max_steps = self.move_range if hasattr(self, 'move_range') else 3
|
||||||
if self.name == 'rook':
|
if self.name == 'rook':
|
||||||
directions = [(-1,0),(1,0),(0,-1),(0,1)]
|
directions = [(-1,0),(1,0),(0,-1),(0,1)]
|
||||||
elif self.name == 'bishop':
|
elif self.name == 'bishop':
|
||||||
@ -172,7 +162,7 @@ class Piece:
|
|||||||
(-1,-1),(1,-1),(1,1),(-1,1)
|
(-1,-1),(1,-1),(1,1),(-1,1)
|
||||||
]
|
]
|
||||||
for dx, dy in directions:
|
for dx, dy in directions:
|
||||||
for step in range(1, 4): # До 3 клеток
|
for step in range(1, max_steps + 1):
|
||||||
nx = self.x + dx * step
|
nx = self.x + dx * step
|
||||||
ny = self.y + dy * step
|
ny = self.y + dy * step
|
||||||
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
||||||
@ -242,9 +232,6 @@ def initialize_pieces():
|
|||||||
# Инициализация фигур
|
# Инициализация фигур
|
||||||
pieces = initialize_pieces()
|
pieces = initialize_pieces()
|
||||||
|
|
||||||
# Remove initial bonus cell generation
|
|
||||||
# initialize_bonus_cells(pieces, num_each=10)
|
|
||||||
|
|
||||||
selected_piece = None
|
selected_piece = None
|
||||||
possible_moves = []
|
possible_moves = []
|
||||||
game_over = False
|
game_over = False
|
||||||
@ -252,7 +239,8 @@ winner = None
|
|||||||
|
|
||||||
# --- Туман войны ---
|
# --- Туман войны ---
|
||||||
cell_counters = {} # {(x,y): turns_since_last_revealed}
|
cell_counters = {} # {(x,y): turns_since_last_revealed}
|
||||||
BONUS_GENERATION_CHANCE = 0.1 # 10% шанс появления бонуса при повторном открытии
|
BONUS_GENERATION_CHANCE = 0.10 # 10% шанс появления бонуса при повторном открытии
|
||||||
|
COIN_GENERATION_CHANCE = 0.001 # 0.1% шанс появления монеты
|
||||||
|
|
||||||
# --- Система ходов ---
|
# --- Система ходов ---
|
||||||
current_turn = 'white' # Начинаем с белых
|
current_turn = 'white' # Начинаем с белых
|
||||||
@ -264,13 +252,10 @@ def update_bonus_probabilities():
|
|||||||
if turn_count <= 100:
|
if turn_count <= 100:
|
||||||
bonus_probabilities = base_bonus_probabilities.copy()
|
bonus_probabilities = base_bonus_probabilities.copy()
|
||||||
else:
|
else:
|
||||||
# Calculate how much to increase 'damage' probability
|
|
||||||
extra_turns = turn_count - 100
|
extra_turns = turn_count - 100
|
||||||
# Let's say over the next 200 turns, it increases to 50%
|
|
||||||
max_extra = 200
|
max_extra = 200
|
||||||
increase_per_turn = (0.50 - base_bonus_probabilities['damage']) / max_extra
|
increase_per_turn = (0.50 - base_bonus_probabilities['damage']) / max_extra
|
||||||
new_damage_prob = min(base_bonus_probabilities['damage'] + increase_per_turn * extra_turns, 0.50)
|
new_damage_prob = min(base_bonus_probabilities['damage'] + increase_per_turn * extra_turns, 0.50)
|
||||||
# Adjust other probabilities accordingly
|
|
||||||
remaining_prob = 1 - new_damage_prob
|
remaining_prob = 1 - new_damage_prob
|
||||||
total_other_probs = sum(base_bonus_probabilities[bt] for bt in base_bonus_probabilities if bt != 'damage')
|
total_other_probs = sum(base_bonus_probabilities[bt] for bt in base_bonus_probabilities if bt != 'damage')
|
||||||
bonus_probabilities = {}
|
bonus_probabilities = {}
|
||||||
@ -302,11 +287,9 @@ def check_timer():
|
|||||||
timer_expired = True
|
timer_expired = True
|
||||||
player_timeouts[current_turn] += 1
|
player_timeouts[current_turn] += 1
|
||||||
if player_timeouts[current_turn] >= 2:
|
if player_timeouts[current_turn] >= 2:
|
||||||
# Opponent wins
|
|
||||||
winner = 'black' if current_turn == 'white' else 'white'
|
winner = 'black' if current_turn == 'white' else 'white'
|
||||||
game_over = True
|
game_over = True
|
||||||
else:
|
else:
|
||||||
# Switch turn
|
|
||||||
switch_turn()
|
switch_turn()
|
||||||
|
|
||||||
def switch_turn():
|
def switch_turn():
|
||||||
@ -327,10 +310,8 @@ def update_fog():
|
|||||||
"""
|
"""
|
||||||
global global_revealed, bonus_cells
|
global global_revealed, bonus_cells
|
||||||
|
|
||||||
# Сохраняем предыдущее состояние открытых клеток
|
|
||||||
previous_revealed = global_revealed.copy()
|
previous_revealed = global_revealed.copy()
|
||||||
|
|
||||||
# Определяем все открытые клетки на основе позиций фигур
|
|
||||||
new_revealed = set()
|
new_revealed = set()
|
||||||
for p in pieces:
|
for p in pieces:
|
||||||
for dx in range(-2, 3):
|
for dx in range(-2, 3):
|
||||||
@ -340,25 +321,24 @@ def update_fog():
|
|||||||
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
||||||
new_revealed.add((nx, ny))
|
new_revealed.add((nx, ny))
|
||||||
|
|
||||||
# Определяем только новые открытые клетки
|
# Исключаем клетки торговцев из тумана войны
|
||||||
|
for merchant_pos in merchant_positions:
|
||||||
|
new_revealed.add(merchant_pos)
|
||||||
|
|
||||||
newly_revealed = new_revealed - previous_revealed
|
newly_revealed = new_revealed - previous_revealed
|
||||||
|
|
||||||
# Обрабатываем все клетки
|
|
||||||
for y in range(GRID_HEIGHT):
|
for y in range(GRID_HEIGHT):
|
||||||
for x in range(GRID_WIDTH):
|
for x in range(GRID_WIDTH):
|
||||||
pos = (x, y)
|
pos = (x, y)
|
||||||
if pos in new_revealed:
|
if pos in new_revealed:
|
||||||
# Если клетка видна, сбрасываем счетчик
|
|
||||||
cell_counters[pos] = 0
|
cell_counters[pos] = 0
|
||||||
global_revealed.add(pos)
|
global_revealed.add(pos)
|
||||||
else:
|
else:
|
||||||
# Если клетка не видна, увеличиваем счетчик
|
|
||||||
if pos in cell_counters:
|
if pos in cell_counters:
|
||||||
cell_counters[pos] += 1
|
cell_counters[pos] += 1
|
||||||
else:
|
else:
|
||||||
cell_counters[pos] = 1
|
cell_counters[pos] = 1
|
||||||
|
|
||||||
# Если счетчик достигает 5, закрываем клетку
|
|
||||||
if cell_counters[pos] >= 5:
|
if cell_counters[pos] >= 5:
|
||||||
if pos in global_revealed:
|
if pos in global_revealed:
|
||||||
global_revealed.remove(pos)
|
global_revealed.remove(pos)
|
||||||
@ -366,19 +346,49 @@ def update_fog():
|
|||||||
if pos in bonus_cells and bonus_cells[pos]['type'] != 'damage':
|
if pos in bonus_cells and bonus_cells[pos]['type'] != 'damage':
|
||||||
del bonus_cells[pos]
|
del bonus_cells[pos]
|
||||||
|
|
||||||
# Генерируем бонусы только на новых открытых клетках
|
# Генерируем бонусы и монеты на новых открытых клетках
|
||||||
for pos in newly_revealed:
|
for pos in newly_revealed:
|
||||||
if pos not in bonus_cells and random.random() < BONUS_GENERATION_CHANCE:
|
if pos not in bonus_cells and pos not in coin_cells and random.random() < BONUS_GENERATION_CHANCE:
|
||||||
bonus_type = choose_bonus_type()
|
bonus_type = choose_bonus_type()
|
||||||
# Проверяем, чтобы бонус не был под фигурой
|
|
||||||
if not any(p.x == pos[0] and p.y == pos[1] for p in pieces):
|
if not any(p.x == pos[0] and p.y == pos[1] for p in pieces):
|
||||||
bonus_cells[pos] = {'type': bonus_type}
|
bonus_cells[pos] = {'type': bonus_type}
|
||||||
|
# Генерация монет
|
||||||
|
if pos not in coin_cells and random.random() < COIN_GENERATION_CHANCE:
|
||||||
|
if not any(p.x == pos[0] and p.y == pos[1] for p in pieces):
|
||||||
|
coin_cells.add(pos)
|
||||||
|
|
||||||
|
# --- Добавление торговцев ---
|
||||||
|
# Определяем позиции торговцев: центральная линия по краям
|
||||||
|
central_line_y = GRID_HEIGHT // 2
|
||||||
|
merchant_positions = [
|
||||||
|
(0, central_line_y),
|
||||||
|
(GRID_WIDTH - 1, central_line_y)
|
||||||
|
]
|
||||||
|
|
||||||
|
# Добавляем торговцы в глобальное множество открытых клеток
|
||||||
|
global_revealed.update(merchant_positions)
|
||||||
|
|
||||||
|
# --- Монеты на поле ---
|
||||||
|
coin_cells = set()
|
||||||
|
|
||||||
|
# --- Счет монет для игроков ---
|
||||||
|
player_coins = {'white': 0, 'black': 0}
|
||||||
|
|
||||||
|
# --- Механика магазина ---
|
||||||
|
shop_open = False
|
||||||
|
shop_items = {
|
||||||
|
'extend_move': {'name': 'Расширить ход', 'cost': 3},
|
||||||
|
'increase_hp': {'name': 'Увеличить HP', 'cost': 3},
|
||||||
|
'damage_enemy': {'name': 'Уменьшить HP врага', 'cost': 3},
|
||||||
|
'curse': {'name': 'Проклятие', 'cost': 3}
|
||||||
|
}
|
||||||
|
|
||||||
|
# --- Функции отрисовки ---
|
||||||
def draw_grid():
|
def draw_grid():
|
||||||
for x in range(0, WINDOW_WIDTH, CELL_SIZE):
|
for x in range(0, CELL_SIZE * GRID_WIDTH, CELL_SIZE):
|
||||||
pygame.draw.line(screen, COLOR_GRID, (x, 0), (x, WINDOW_HEIGHT))
|
pygame.draw.line(screen, COLOR_GRID, (x, 0), (x, CELL_SIZE * GRID_HEIGHT))
|
||||||
for y in range(0, WINDOW_HEIGHT, CELL_SIZE):
|
for y in range(0, CELL_SIZE * GRID_HEIGHT, CELL_SIZE):
|
||||||
pygame.draw.line(screen, COLOR_GRID, (0, y), (WINDOW_WIDTH, y))
|
pygame.draw.line(screen, COLOR_GRID, (0, y), (CELL_SIZE * GRID_WIDTH, y))
|
||||||
|
|
||||||
def draw_fog():
|
def draw_fog():
|
||||||
for y in range(GRID_HEIGHT):
|
for y in range(GRID_HEIGHT):
|
||||||
@ -388,22 +398,13 @@ def draw_fog():
|
|||||||
rect = pygame.Rect(x*CELL_SIZE, y*CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
rect = pygame.Rect(x*CELL_SIZE, y*CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
||||||
pygame.draw.rect(screen, COLOR_FOG, rect)
|
pygame.draw.rect(screen, COLOR_FOG, rect)
|
||||||
else:
|
else:
|
||||||
# Проверяем, будет ли клетка закрыта в следующем ходу
|
if pos in merchant_positions:
|
||||||
|
continue # Торговцы всегда видимы
|
||||||
if cell_counters.get(pos, 0) == 4:
|
if cell_counters.get(pos, 0) == 4:
|
||||||
# Помечаем клетку светло-серым
|
|
||||||
rect = pygame.Rect(x*CELL_SIZE, y*CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
rect = pygame.Rect(x*CELL_SIZE, y*CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
||||||
pygame.draw.rect(screen, COLOR_PRE_FOG, rect)
|
pygame.draw.rect(screen, COLOR_PRE_FOG, rect)
|
||||||
|
|
||||||
def draw_bonus_cells():
|
def draw_bonus_cells():
|
||||||
"""
|
|
||||||
Отрисовка бонусов (если клетка открыта или бонус типа 'damage').
|
|
||||||
Цвета:
|
|
||||||
- 'regen': (0,255,0) зелёный
|
|
||||||
- 'hp_upgrade': (0,128,255) синий
|
|
||||||
- 'damage': (255,0,0) красный
|
|
||||||
- 'king_hp_upgrade': (255,215,0) золотой
|
|
||||||
- 'add_piece': (255,255,255) белый с плюсом или розовый
|
|
||||||
"""
|
|
||||||
for (bx, by), info in bonus_cells.items():
|
for (bx, by), info in bonus_cells.items():
|
||||||
# Для 'damage' бонусов отображаем всегда, иначе только если клетка видна
|
# Для 'damage' бонусов отображаем всегда, иначе только если клетка видна
|
||||||
if info['type'] != 'damage' and (bx, by) not in global_revealed:
|
if info['type'] != 'damage' and (bx, by) not in global_revealed:
|
||||||
@ -424,7 +425,6 @@ def draw_bonus_cells():
|
|||||||
color = COLOR_KING_HP_UPGRADE
|
color = COLOR_KING_HP_UPGRADE
|
||||||
pygame.draw.circle(screen, color, (cx, cy), CELL_SIZE//4)
|
pygame.draw.circle(screen, color, (cx, cy), CELL_SIZE//4)
|
||||||
elif bonus_type == 'add_piece':
|
elif bonus_type == 'add_piece':
|
||||||
# Проверяем, возможно ли добавить фигуру рядом
|
|
||||||
possible = False
|
possible = False
|
||||||
for dx, dy in [(-1,0),(1,0),(0,-1),(0,1), (-1,-1),(1,-1),(1,1),(-1,1)]:
|
for dx, dy in [(-1,0),(1,0),(0,-1),(0,1), (-1,-1),(1,-1),(1,1),(-1,1)]:
|
||||||
nx = bx + dx
|
nx = bx + dx
|
||||||
@ -439,8 +439,40 @@ def draw_bonus_cells():
|
|||||||
pygame.draw.line(screen, (0,0,0), (cx - CELL_SIZE//8, cy), (cx + CELL_SIZE//8, cy), 2)
|
pygame.draw.line(screen, (0,0,0), (cx - CELL_SIZE//8, cy), (cx + CELL_SIZE//8, cy), 2)
|
||||||
pygame.draw.line(screen, (0,0,0), (cx, cy - CELL_SIZE//8), (cx, cy + CELL_SIZE//8), 2)
|
pygame.draw.line(screen, (0,0,0), (cx, cy - CELL_SIZE//8), (cx, cy + CELL_SIZE//8), 2)
|
||||||
|
|
||||||
|
def draw_coin_cells():
|
||||||
|
for pos in coin_cells:
|
||||||
|
if pos not in global_revealed:
|
||||||
|
continue # Монеты видны только в открытых клетках
|
||||||
|
x, y = pos
|
||||||
|
cx = x * CELL_SIZE + CELL_SIZE // 2
|
||||||
|
cy = y * CELL_SIZE + CELL_SIZE // 2
|
||||||
|
size = CELL_SIZE // 3
|
||||||
|
# Рисуем оранжевый треугольник
|
||||||
|
point1 = (cx, cy - size)
|
||||||
|
point2 = (cx - size, cy + size)
|
||||||
|
point3 = (cx + size, cy + size)
|
||||||
|
pygame.draw.polygon(screen, COLOR_COIN, [point1, point2, point3])
|
||||||
|
# Рисуем символ доллара
|
||||||
|
dollar_text = font.render('$', True, (0, 0, 0))
|
||||||
|
text_rect = dollar_text.get_rect(center=(cx, cy))
|
||||||
|
screen.blit(dollar_text, text_rect)
|
||||||
|
|
||||||
|
def draw_merchants():
|
||||||
|
for pos in merchant_positions:
|
||||||
|
x, y = pos
|
||||||
|
rect = pygame.Rect(x*CELL_SIZE, y*CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
||||||
|
pygame.draw.rect(screen, COLOR_MERCHANT, rect)
|
||||||
|
# Рисуем стрелку вверх
|
||||||
|
arrow_color = (255, 255, 255)
|
||||||
|
arrow_size = CELL_SIZE // 2
|
||||||
|
points = [
|
||||||
|
(x * CELL_SIZE + CELL_SIZE // 2, y * CELL_SIZE + CELL_SIZE // 4),
|
||||||
|
(x * CELL_SIZE + CELL_SIZE // 4, y * CELL_SIZE + 3 * CELL_SIZE // 4),
|
||||||
|
(x * CELL_SIZE + 3 * CELL_SIZE // 4, y * CELL_SIZE + 3 * CELL_SIZE // 4)
|
||||||
|
]
|
||||||
|
pygame.draw.polygon(screen, arrow_color, points)
|
||||||
|
|
||||||
def draw_pieces(pieces):
|
def draw_pieces(pieces):
|
||||||
"""Рисуем фигуры, их HP и подсвечиваем ходы."""
|
|
||||||
for p in pieces:
|
for p in pieces:
|
||||||
rect = pygame.Rect(p.x*CELL_SIZE, p.y*CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
rect = pygame.Rect(p.x*CELL_SIZE, p.y*CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
||||||
|
|
||||||
@ -472,36 +504,69 @@ def draw_pieces(pieces):
|
|||||||
r = pygame.Rect(mx*CELL_SIZE, my*CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
r = pygame.Rect(mx*CELL_SIZE, my*CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
||||||
pygame.draw.rect(screen, COLOR_MOVE, r, 2)
|
pygame.draw.rect(screen, COLOR_MOVE, r, 2)
|
||||||
|
|
||||||
def display_victory(winner):
|
def draw_statistics_panel():
|
||||||
text = victory_font.render(f"{winner.capitalize()} победил!", True, (255, 255, 255))
|
panel_rect = pygame.Rect(CELL_SIZE * GRID_WIDTH, 0, PANEL_WIDTH, WINDOW_HEIGHT)
|
||||||
text_rect = text.get_rect(center=(WINDOW_WIDTH//2, WINDOW_HEIGHT//2))
|
pygame.draw.rect(screen, (50, 50, 50), panel_rect)
|
||||||
screen.blit(text, text_rect)
|
|
||||||
|
|
||||||
def display_turn(current_turn):
|
# Заголовок
|
||||||
text = turn_font.render(f"Текущий ход: {current_turn.capitalize()}", True, COLOR_TURN_TEXT)
|
title_text = shop_font.render("Статистика", True, (255, 255, 255))
|
||||||
screen.blit(text, (10, WINDOW_HEIGHT - 30))
|
screen.blit(title_text, (CELL_SIZE * GRID_WIDTH + 10, 10))
|
||||||
|
|
||||||
def display_turn_counter():
|
# Текущий ход
|
||||||
global turn_count
|
turn_text = turn_font.render(f"Ход: {current_turn.capitalize()}", True, COLOR_TURN_TEXT)
|
||||||
if turn_count < 100:
|
screen.blit(turn_text, (CELL_SIZE * GRID_WIDTH + 10, 50))
|
||||||
color = (255, 255, 255)
|
|
||||||
else:
|
|
||||||
color = (255, 0, 0)
|
|
||||||
text = counter_font.render(f"Ход: {turn_count}", True, color)
|
|
||||||
text_rect = text.get_rect(center=(WINDOW_WIDTH//2, WINDOW_HEIGHT - 15))
|
|
||||||
screen.blit(text, text_rect)
|
|
||||||
|
|
||||||
def display_timer():
|
# Количество ходов
|
||||||
|
counter_text = counter_font.render(f"Ходов: {turn_count}", True, (255, 255, 255))
|
||||||
|
screen.blit(counter_text, (CELL_SIZE * GRID_WIDTH + 10, 80))
|
||||||
|
|
||||||
|
# Таймер
|
||||||
time_left = get_time_left()
|
time_left = get_time_left()
|
||||||
minutes = time_left // 60
|
minutes = time_left // 60
|
||||||
seconds = time_left % 60
|
seconds = time_left % 60
|
||||||
timer_text = f"{minutes:02}:{seconds:02}"
|
timer_text_str = f"Время: {minutes:02}:{seconds:02}"
|
||||||
if timer_expired and player_timeouts[current_turn] >=1:
|
if timer_expired and player_timeouts[current_turn] >=1:
|
||||||
color = COLOR_TIMER_WARNING
|
color = COLOR_TIMER_WARNING
|
||||||
else:
|
else:
|
||||||
color = COLOR_TIMER_NORMAL
|
color = COLOR_TIMER_NORMAL
|
||||||
text = timer_font.render(timer_text, True, color)
|
timer_text = timer_font.render(timer_text_str, True, color)
|
||||||
text_rect = text.get_rect(bottomright=(WINDOW_WIDTH - 10, WINDOW_HEIGHT - 10))
|
screen.blit(timer_text, (CELL_SIZE * GRID_WIDTH + 10, 110))
|
||||||
|
|
||||||
|
# Количество монет
|
||||||
|
coins_text_white = counter_font.render(f"Белые монеты: {player_coins['white']}", True, (255, 255, 0))
|
||||||
|
coins_text_black = counter_font.render(f"Чёрные монеты: {player_coins['black']}", True, (255, 255, 0))
|
||||||
|
screen.blit(coins_text_white, (CELL_SIZE * GRID_WIDTH + 10, 140))
|
||||||
|
screen.blit(coins_text_black, (CELL_SIZE * GRID_WIDTH + 10, 170))
|
||||||
|
|
||||||
|
# Если открыт магазин, отображаем его
|
||||||
|
if shop_open:
|
||||||
|
draw_shop()
|
||||||
|
|
||||||
|
def draw_shop():
|
||||||
|
shop_x = CELL_SIZE * GRID_WIDTH + 10
|
||||||
|
shop_y = 200
|
||||||
|
shop_title = shop_font.render("Магазин", True, (255, 255, 0))
|
||||||
|
screen.blit(shop_title, (shop_x, shop_y))
|
||||||
|
|
||||||
|
for idx, (key, item) in enumerate(shop_items.items()):
|
||||||
|
item_y = shop_y + 40 + idx * 60
|
||||||
|
# Кнопка
|
||||||
|
button_rect = pygame.Rect(shop_x, item_y, PANEL_WIDTH - 20, 50)
|
||||||
|
# Проверка, хватает ли монет
|
||||||
|
if player_coins[current_turn] >= item['cost']:
|
||||||
|
button_color = (0, 255, 0) # Зелёный
|
||||||
|
else:
|
||||||
|
button_color = (128, 128, 128) # Серый
|
||||||
|
pygame.draw.rect(screen, button_color, button_rect)
|
||||||
|
# Название предмета
|
||||||
|
item_text = shop_font.render(f"{item['name']} - {item['cost']} мон.", True, (0,0,0))
|
||||||
|
screen.blit(item_text, (shop_x + 5, item_y + 15))
|
||||||
|
# Хранение позиции кнопки для обработки кликов
|
||||||
|
shop_items[key]['button_rect'] = button_rect
|
||||||
|
|
||||||
|
def draw_victory(winner):
|
||||||
|
text = victory_font.render(f"{winner.capitalize()} победил!", True, (255, 255, 255))
|
||||||
|
text_rect = text.get_rect(center=(WINDOW_WIDTH//2, WINDOW_HEIGHT//2))
|
||||||
screen.blit(text, text_rect)
|
screen.blit(text, text_rect)
|
||||||
|
|
||||||
def apply_bonus(piece, bonus_type, pieces):
|
def apply_bonus(piece, bonus_type, pieces):
|
||||||
@ -525,48 +590,70 @@ def apply_bonus(piece, bonus_type, pieces):
|
|||||||
king = next((p for p in pieces if p.name == 'king' and p.color == piece.color), None)
|
king = next((p for p in pieces if p.name == 'king' and p.color == piece.color), None)
|
||||||
if king:
|
if king:
|
||||||
if king.hp == king.max_hp:
|
if king.hp == king.max_hp:
|
||||||
# Если король на полном здоровье,
|
# Увеличиваем max_hp на 1
|
||||||
# то увеличиваем max_hp на 1
|
|
||||||
king.max_hp += 1
|
king.max_hp += 1
|
||||||
king.hp = king.max_hp
|
king.hp = king.max_hp
|
||||||
else:
|
else:
|
||||||
# Если король не на полном, то
|
# Восстанавливаем HP до max
|
||||||
# просто восстанавливаем HP до max
|
|
||||||
king.hp = min(king.hp + 1, king.max_hp)
|
king.hp = min(king.hp + 1, king.max_hp)
|
||||||
|
|
||||||
elif bonus_type == 'damage':
|
elif bonus_type == 'damage':
|
||||||
# Нанесение урона (1..5)
|
# Урон при прохождении через клетку 'damage' уже обрабатывается отдельно
|
||||||
damage = random.randint(1, 5)
|
pass
|
||||||
piece.hp = max(piece.hp - damage, 0)
|
|
||||||
if piece.hp == 0:
|
|
||||||
# Удаляем фигуру, если HP равен 0
|
|
||||||
pieces.remove(piece)
|
|
||||||
if piece.name == 'king':
|
|
||||||
global winner, game_over
|
|
||||||
winner = 'black' if piece.color == 'white' else 'white'
|
|
||||||
game_over = True
|
|
||||||
|
|
||||||
elif bonus_type == 'add_piece':
|
elif bonus_type == 'add_piece':
|
||||||
# Добавление новой фигуры рядом, если возможно и не король
|
# Добавление новой фигуры рядом, если возможно и не король
|
||||||
if piece.name != 'king':
|
if piece.name != 'king':
|
||||||
# Определяем возможные соседние клетки
|
|
||||||
directions = [(-1,0),(1,0),(0,-1),(0,1), (-1,-1),(1,-1),(1,1),(-1,1)]
|
directions = [(-1,0),(1,0),(0,-1),(0,1), (-1,-1),(1,-1),(1,1),(-1,1)]
|
||||||
random.shuffle(directions)
|
random.shuffle(directions)
|
||||||
for dx, dy in directions:
|
for dx, dy in directions:
|
||||||
nx = piece.x + dx
|
nx = piece.x + dx
|
||||||
ny = piece.y + dy
|
ny = piece.y + dy
|
||||||
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
||||||
# Проверяем, что клетка пуста
|
if not any(p.x == nx and p.y == ny for p in pieces) and (nx, ny) not in bonus_cells and (nx, ny) not in merchant_positions:
|
||||||
if not any(p.x == nx and p.y == ny for p in pieces) and (nx, ny) not in bonus_cells:
|
|
||||||
# Создаём новую фигуру того же типа
|
|
||||||
new_piece = Piece(piece.name, piece.color, nx, ny)
|
new_piece = Piece(piece.name, piece.color, nx, ny)
|
||||||
pieces.append(new_piece)
|
pieces.append(new_piece)
|
||||||
break
|
break
|
||||||
# Если не удалось разместить, бонус не активируется
|
|
||||||
|
|
||||||
# Инициализируем туман войны в начале игры
|
def handle_shop_purchase(key):
|
||||||
|
if player_coins[current_turn] < shop_items[key]['cost']:
|
||||||
|
return # Недостаточно монет
|
||||||
|
player_coins[current_turn] -= shop_items[key]['cost']
|
||||||
|
if key == 'extend_move':
|
||||||
|
for p in pieces:
|
||||||
|
if p.color == current_turn:
|
||||||
|
if p.name in ['rook', 'bishop', 'queen']:
|
||||||
|
setattr(p, 'move_range', getattr(p, 'move_range', 3) + 2) # До 5
|
||||||
|
elif p.name == 'pawn':
|
||||||
|
setattr(p, 'move_range', getattr(p, 'move_range', 1) + 1) # До 2
|
||||||
|
elif key == 'increase_hp':
|
||||||
|
for p in pieces:
|
||||||
|
if p.color == current_turn and p.name != 'king':
|
||||||
|
p.max_hp += 3
|
||||||
|
p.hp = min(p.hp + 3, p.max_hp)
|
||||||
|
elif key == 'damage_enemy':
|
||||||
|
enemy_color = 'black' if current_turn == 'white' else 'white'
|
||||||
|
for p in pieces:
|
||||||
|
if p.color == enemy_color:
|
||||||
|
if p.hp > 3:
|
||||||
|
p.hp -= 3
|
||||||
|
elif p.hp > 1:
|
||||||
|
p.hp = 1
|
||||||
|
else:
|
||||||
|
p.hp = 1 # Уже 1, остаётся 1
|
||||||
|
elif key == 'curse':
|
||||||
|
# Уменьшаем вероятность появления 'regen' и 'hp_upgrade' на 10%
|
||||||
|
bonus_probabilities['regen'] = max(bonus_probabilities['regen'] - 0.10, 0)
|
||||||
|
bonus_probabilities['hp_upgrade'] = max(bonus_probabilities['hp_upgrade'] - 0.10, 0)
|
||||||
|
# Нормализуем вероятности
|
||||||
|
total_prob = sum(bonus_probabilities.values())
|
||||||
|
for bt in bonus_probabilities:
|
||||||
|
bonus_probabilities[bt] /= total_prob if total_prob > 0 else 1
|
||||||
|
|
||||||
|
# --- Инициализируем туман войны в начале игры ---
|
||||||
update_fog()
|
update_fog()
|
||||||
|
|
||||||
|
# --- Основной цикл игры ---
|
||||||
running = True
|
running = True
|
||||||
clock = pygame.time.Clock()
|
clock = pygame.time.Clock()
|
||||||
|
|
||||||
@ -579,149 +666,153 @@ while running:
|
|||||||
|
|
||||||
elif event.type == pygame.MOUSEBUTTONDOWN and not game_over:
|
elif event.type == pygame.MOUSEBUTTONDOWN and not game_over:
|
||||||
mx, my = pygame.mouse.get_pos()
|
mx, my = pygame.mouse.get_pos()
|
||||||
gx = mx // CELL_SIZE
|
if mx < CELL_SIZE * GRID_WIDTH and my < CELL_SIZE * GRID_HEIGHT:
|
||||||
gy = my // CELL_SIZE
|
gx = mx // CELL_SIZE
|
||||||
|
gy = my // CELL_SIZE
|
||||||
|
|
||||||
clicked_piece = next((p for p in pieces if p.x == gx and p.y == gy), None)
|
clicked_piece = next((p for p in pieces if p.x == gx and p.y == gy), None)
|
||||||
|
|
||||||
if selected_piece:
|
if selected_piece:
|
||||||
if (gx, gy) in possible_moves:
|
if (gx, gy) in possible_moves:
|
||||||
# Проверяем бонус
|
# Проверяем бонус
|
||||||
if (gx, gy) in bonus_cells:
|
if (gx, gy) in bonus_cells:
|
||||||
bonus_type = bonus_cells[(gx, gy)]['type']
|
bonus_type = bonus_cells[(gx, gy)]['type']
|
||||||
apply_bonus(selected_piece, bonus_type, pieces)
|
apply_bonus(selected_piece, bonus_type, pieces)
|
||||||
del bonus_cells[(gx, gy)]
|
del bonus_cells[(gx, gy)]
|
||||||
|
|
||||||
|
# Проверяем монету
|
||||||
|
if (gx, gy) in coin_cells:
|
||||||
|
player_coins[current_turn] += 1
|
||||||
|
coin_cells.remove((gx, gy))
|
||||||
|
|
||||||
|
# Проверяем, является ли клетка торговцем
|
||||||
|
if (gx, gy) in merchant_positions:
|
||||||
|
shop_open = True
|
||||||
|
|
||||||
|
# Проверяем, есть ли там вражеская фигура
|
||||||
|
defender = next((p for p in pieces if p.x == gx and p.y == gy), None)
|
||||||
|
if defender:
|
||||||
|
# Проводим бой
|
||||||
|
attacker = selected_piece
|
||||||
|
attacker_alive, defender_alive = resolve_combat(attacker, defender)
|
||||||
|
if not defender_alive:
|
||||||
|
if defender.name == 'king':
|
||||||
|
winner = attacker.color
|
||||||
|
game_over = True
|
||||||
|
pieces.remove(defender)
|
||||||
|
if not attacker_alive:
|
||||||
|
pieces.remove(attacker)
|
||||||
|
selected_piece = None
|
||||||
|
possible_moves.clear()
|
||||||
|
update_fog()
|
||||||
|
switch_turn()
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
# Перемещаем атакующего
|
||||||
|
path = []
|
||||||
|
if attacker.name in ['rook', 'bishop', 'queen']:
|
||||||
|
dx = gx - attacker.x
|
||||||
|
dy = gy - attacker.y
|
||||||
|
if dx != 0:
|
||||||
|
dx = dx // abs(dx)
|
||||||
|
if dy != 0:
|
||||||
|
dy = dy // abs(dy)
|
||||||
|
for step in range(1, max(abs(gx - attacker.x), abs(gy - attacker.y))):
|
||||||
|
path_x = attacker.x + dx * step
|
||||||
|
path_y = attacker.y + dy * step
|
||||||
|
path.append((path_x, path_y))
|
||||||
|
survived = True
|
||||||
|
for pos in path:
|
||||||
|
if pos in bonus_cells and bonus_cells[pos]['type'] == 'damage':
|
||||||
|
damage = random.randint(1,5)
|
||||||
|
attacker.hp = max(attacker.hp - damage, 0)
|
||||||
|
del bonus_cells[pos]
|
||||||
|
if attacker.hp == 0:
|
||||||
|
pieces.remove(attacker)
|
||||||
|
selected_piece = None
|
||||||
|
possible_moves.clear()
|
||||||
|
survived = False
|
||||||
|
switch_turn()
|
||||||
|
break
|
||||||
|
if survived:
|
||||||
|
attacker.x = gx
|
||||||
|
attacker.y = gy
|
||||||
|
attacker.selected = False
|
||||||
|
selected_piece = None
|
||||||
|
possible_moves.clear()
|
||||||
|
switch_turn()
|
||||||
|
|
||||||
# Проверяем, есть ли там вражеская фигура
|
|
||||||
defender = next((p for p in pieces if p.x == gx and p.y == gy), None)
|
|
||||||
if defender:
|
|
||||||
# Проводим бой
|
|
||||||
attacker = selected_piece
|
|
||||||
attacker_alive, defender_alive = resolve_combat(attacker, defender)
|
|
||||||
if not defender_alive:
|
|
||||||
# Защитник погиб
|
|
||||||
if defender.name == 'king':
|
|
||||||
winner = attacker.color
|
|
||||||
game_over = True
|
|
||||||
pieces.remove(defender)
|
|
||||||
if not attacker_alive:
|
|
||||||
# Атакующая погибла
|
|
||||||
pieces.remove(attacker)
|
|
||||||
# Снимаем выделение
|
|
||||||
selected_piece = None
|
|
||||||
possible_moves.clear()
|
|
||||||
# После изменения позиций фигур обновляем туман войны
|
|
||||||
update_fog()
|
|
||||||
# Смена хода
|
|
||||||
switch_turn()
|
|
||||||
continue
|
|
||||||
else:
|
else:
|
||||||
# Атакующая жива, перемещаем её
|
# Пустая клетка — просто ходим
|
||||||
# Проверка прохождения через клетки (для длинных ходов)
|
|
||||||
path = []
|
path = []
|
||||||
if attacker.name in ['rook', 'bishop', 'queen']:
|
if selected_piece.name in ['rook', 'bishop', 'queen']:
|
||||||
dx = gx - attacker.x
|
dx = gx - selected_piece.x
|
||||||
dy = gy - attacker.y
|
dy = gy - selected_piece.y
|
||||||
if dx != 0:
|
if dx != 0:
|
||||||
dx = dx // abs(dx)
|
dx = dx // abs(dx)
|
||||||
if dy != 0:
|
if dy != 0:
|
||||||
dy = dy // abs(dy)
|
dy = dy // abs(dy)
|
||||||
for step in range(1, max(abs(gx - attacker.x), abs(gy - attacker.y))):
|
for step in range(1, max(abs(gx - selected_piece.x), abs(gy - selected_piece.y))):
|
||||||
path_x = attacker.x + dx * step
|
path_x = selected_piece.x + dx * step
|
||||||
path_y = attacker.y + dy * step
|
path_y = selected_piece.y + dy * step
|
||||||
path.append((path_x, path_y))
|
path.append((path_x, path_y))
|
||||||
# Применяем урон при прохождении через клетки и удаляем 'damage' клетки
|
|
||||||
survived = True
|
survived = True
|
||||||
for pos in path:
|
for pos in path:
|
||||||
if pos in bonus_cells and bonus_cells[pos]['type'] == 'damage':
|
if pos in bonus_cells and bonus_cells[pos]['type'] == 'damage':
|
||||||
damage = random.randint(1,5) # Исправлено на 1..5
|
damage = random.randint(1,5)
|
||||||
attacker.hp = max(attacker.hp - damage, 0)
|
selected_piece.hp = max(selected_piece.hp - damage, 0)
|
||||||
# Удаляем 'damage' клетку как использованную
|
|
||||||
del bonus_cells[pos]
|
del bonus_cells[pos]
|
||||||
if attacker.hp == 0:
|
if selected_piece.hp == 0:
|
||||||
pieces.remove(attacker)
|
pieces.remove(selected_piece)
|
||||||
selected_piece = None
|
selected_piece = None
|
||||||
possible_moves.clear()
|
possible_moves.clear()
|
||||||
survived = False
|
survived = False
|
||||||
# Смена хода, так как игрок погиб
|
|
||||||
switch_turn()
|
switch_turn()
|
||||||
break
|
break
|
||||||
if survived:
|
if survived:
|
||||||
attacker.x = gx
|
selected_piece.x = gx
|
||||||
attacker.y = gy
|
selected_piece.y = gy
|
||||||
attacker.selected = False
|
selected_piece.selected = False
|
||||||
selected_piece = None
|
selected_piece = None
|
||||||
possible_moves.clear()
|
possible_moves.clear()
|
||||||
# Смена хода
|
|
||||||
switch_turn()
|
switch_turn()
|
||||||
|
|
||||||
|
update_fog()
|
||||||
else:
|
else:
|
||||||
# Пустая клетка — просто ходим
|
selected_piece.selected = False
|
||||||
# Проверка прохождения через клетки (для длинных ходов)
|
selected_piece = None
|
||||||
path = []
|
possible_moves.clear()
|
||||||
if selected_piece.name in ['rook', 'bishop', 'queen']:
|
|
||||||
dx = gx - selected_piece.x
|
|
||||||
dy = gy - selected_piece.y
|
|
||||||
if dx != 0:
|
|
||||||
dx = dx // abs(dx)
|
|
||||||
if dy != 0:
|
|
||||||
dy = dy // abs(dy)
|
|
||||||
for step in range(1, max(abs(gx - selected_piece.x), abs(gy - selected_piece.y))):
|
|
||||||
path_x = selected_piece.x + dx * step
|
|
||||||
path_y = selected_piece.y + dy * step
|
|
||||||
path.append((path_x, path_y))
|
|
||||||
# Применяем урон при прохождении через клетки и удаляем 'damage' клетки
|
|
||||||
survived = True
|
|
||||||
for pos in path:
|
|
||||||
if pos in bonus_cells and bonus_cells[pos]['type'] == 'damage':
|
|
||||||
damage = random.randint(1,5) # Исправлено на 1..5
|
|
||||||
selected_piece.hp = max(selected_piece.hp - damage, 0)
|
|
||||||
# Удаляем 'damage' клетку как использованную
|
|
||||||
del bonus_cells[pos]
|
|
||||||
if selected_piece.hp == 0:
|
|
||||||
pieces.remove(selected_piece)
|
|
||||||
selected_piece = None
|
|
||||||
possible_moves.clear()
|
|
||||||
survived = False
|
|
||||||
# Смена хода, так как игрок погиб
|
|
||||||
switch_turn()
|
|
||||||
break
|
|
||||||
if survived:
|
|
||||||
selected_piece.x = gx
|
|
||||||
selected_piece.y = gy
|
|
||||||
selected_piece.selected = False
|
|
||||||
selected_piece = None
|
|
||||||
possible_moves.clear()
|
|
||||||
# Смена хода
|
|
||||||
switch_turn()
|
|
||||||
|
|
||||||
# После успешного хода обновляем туман войны
|
|
||||||
update_fog()
|
|
||||||
else:
|
else:
|
||||||
# Клик вне возможных ходов
|
# Выбираем фигуру только если клетка видима и соответствует текущему ходу
|
||||||
selected_piece.selected = False
|
if clicked_piece and (gx, gy) in global_revealed and clicked_piece.color == current_turn:
|
||||||
selected_piece = None
|
selected_piece = clicked_piece
|
||||||
possible_moves.clear()
|
selected_piece.selected = True
|
||||||
|
possible_moves = selected_piece.get_possible_moves(pieces)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Выбираем фигуру только если клетка видима и соответствует текущему ходу
|
# Клик в правой панели
|
||||||
if clicked_piece and (gx, gy) in global_revealed and clicked_piece.color == current_turn:
|
if shop_open:
|
||||||
selected_piece = clicked_piece
|
for key, item in shop_items.items():
|
||||||
selected_piece.selected = True
|
if 'button_rect' in item and item['button_rect'].collidepoint(mx, my):
|
||||||
possible_moves = selected_piece.get_possible_moves(pieces)
|
if player_coins[current_turn] >= item['cost']:
|
||||||
|
handle_shop_purchase(key)
|
||||||
|
|
||||||
|
elif event.type == pygame.KEYDOWN:
|
||||||
|
if event.key == pygame.K_ESCAPE:
|
||||||
|
shop_open = False
|
||||||
|
|
||||||
# Отрисовка
|
# Отрисовка
|
||||||
screen.fill(COLOR_BG)
|
screen.fill(COLOR_BG)
|
||||||
draw_grid()
|
draw_grid()
|
||||||
draw_fog()
|
draw_fog()
|
||||||
|
draw_merchants()
|
||||||
draw_bonus_cells()
|
draw_bonus_cells()
|
||||||
|
draw_coin_cells()
|
||||||
draw_pieces(pieces)
|
draw_pieces(pieces)
|
||||||
|
draw_statistics_panel()
|
||||||
if game_over and winner:
|
if game_over and winner:
|
||||||
display_victory(winner)
|
draw_victory(winner)
|
||||||
else:
|
|
||||||
display_turn(current_turn)
|
|
||||||
display_turn_counter()
|
|
||||||
display_timer()
|
|
||||||
pygame.display.flip()
|
pygame.display.flip()
|
||||||
|
|
||||||
pygame.quit()
|
pygame.quit()
|
||||||
|
Loading…
x
Reference in New Issue
Block a user