ver 1.1.2
@ -21,13 +21,13 @@ COLOR_SELECTED = (255, 0, 0)
|
|||||||
COLOR_MOVE = (0, 255, 0)
|
COLOR_MOVE = (0, 255, 0)
|
||||||
|
|
||||||
COLOR_WHITE_PIECE = (255, 255, 255) # Заливка белых фигур
|
COLOR_WHITE_PIECE = (255, 255, 255) # Заливка белых фигур
|
||||||
COLOR_BLACK_PIECE = (0, 0, 0) # Заливка чёрных фигур
|
COLOR_BLACK_PIECE = (0, 0, 0) # Заливка чёрных фигур
|
||||||
|
|
||||||
# Новые цвета для бонусов
|
# Новые цвета для бонусов
|
||||||
COLOR_REGEN = (0, 255, 0) # Зелёный
|
COLOR_REGEN = (0, 255, 0) # Зелёный
|
||||||
COLOR_HP_UPGRADE = (0, 128, 255) # Синий
|
COLOR_HP_UPGRADE = (0, 128, 255) # Синий
|
||||||
COLOR_DAMAGE = (255, 0, 0) # Красный
|
COLOR_DAMAGE = (255, 0, 0) # Красный
|
||||||
COLOR_KING_HP_UPGRADE = (255, 215, 0) # Золотой
|
COLOR_KING_HP_UPGRADE = (255, 215, 0) # Золотой
|
||||||
COLOR_ADD_PIECE = (255, 255, 255) # Белый (с плюсом)
|
COLOR_ADD_PIECE = (255, 255, 255) # Белый (с плюсом)
|
||||||
COLOR_ADD_PIECE_PINK = (255, 192, 203) # Розовый
|
COLOR_ADD_PIECE_PINK = (255, 192, 203) # Розовый
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ 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.1.1")
|
pygame.display.set_caption("Шахматы с Открытым Миром 1.1.1")
|
||||||
|
|
||||||
# Шрифты
|
# --- Шрифты ---
|
||||||
font = pygame.font.SysFont(None, CELL_SIZE // 2)
|
font = pygame.font.SysFont(None, CELL_SIZE // 2)
|
||||||
victory_font = pygame.font.SysFont(None, 60)
|
victory_font = pygame.font.SysFont(None, 60)
|
||||||
turn_font = pygame.font.SysFont(None, 30)
|
turn_font = pygame.font.SysFont(None, 30)
|
||||||
@ -61,7 +61,7 @@ shop_font = pygame.font.SysFont(None, 24)
|
|||||||
# --- Глобальное множество открытых клеток (туман войны) ---
|
# --- Глобальное множество открытых клеток (туман войны) ---
|
||||||
global_revealed = set()
|
global_revealed = set()
|
||||||
|
|
||||||
# --- Словарь символов ---
|
# --- Словарь символов (фолбэк, если спрайт не найден) ---
|
||||||
piece_symbols = {
|
piece_symbols = {
|
||||||
'rook': 'Л',
|
'rook': 'Л',
|
||||||
'knight': 'К',
|
'knight': 'К',
|
||||||
@ -78,7 +78,7 @@ base_bonus_probabilities = {
|
|||||||
'regen': 0.42, # 42%
|
'regen': 0.42, # 42%
|
||||||
'hp_upgrade': 0.32, # 32%
|
'hp_upgrade': 0.32, # 32%
|
||||||
'damage': 0.2, # 20%
|
'damage': 0.2, # 20%
|
||||||
'king_hp_upgrade': 0.05, # 5%
|
'king_hp_upgrade': 0.05, # 5%
|
||||||
'add_piece': 0.01 # 1%
|
'add_piece': 0.01 # 1%
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -97,17 +97,14 @@ def choose_bonus_type():
|
|||||||
def resolve_combat(attacker, defender):
|
def resolve_combat(attacker, defender):
|
||||||
a = attacker.hp
|
a = attacker.hp
|
||||||
b = defender.hp
|
b = defender.hp
|
||||||
|
|
||||||
if a < b:
|
if a < b:
|
||||||
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:
|
||||||
attacker.hp = a - b
|
attacker.hp = a - b
|
||||||
defender.hp = 0
|
defender.hp = 0
|
||||||
return (True, False)
|
return (True, False)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
attacker.hp = 1
|
attacker.hp = 1
|
||||||
defender.hp = 0
|
defender.hp = 0
|
||||||
@ -121,6 +118,7 @@ class Piece:
|
|||||||
self.x = x
|
self.x = x
|
||||||
self.y = y
|
self.y = y
|
||||||
self.selected = False
|
self.selected = False
|
||||||
|
self.has_moved = False # Для ограничения повторного хода за один ход
|
||||||
|
|
||||||
# Инициализация HP
|
# Инициализация HP
|
||||||
if self.name == 'king':
|
if self.name == 'king':
|
||||||
@ -136,11 +134,9 @@ class Piece:
|
|||||||
def get_possible_moves(self, pieces):
|
def get_possible_moves(self, pieces):
|
||||||
moves = []
|
moves = []
|
||||||
if self.name == 'pawn':
|
if self.name == 'pawn':
|
||||||
directions = [
|
directions = [(-1,-1), (0,-1), (1,-1),
|
||||||
(-1,-1), (0,-1), (1,-1),
|
(-1, 0), (1, 0),
|
||||||
(-1, 0), (1, 0),
|
(-1, 1), (0, 1), (1, 1)]
|
||||||
(-1, 1), (0, 1), (1, 1)
|
|
||||||
]
|
|
||||||
for dx, dy in directions:
|
for dx, dy in directions:
|
||||||
nx = self.x + dx
|
nx = self.x + dx
|
||||||
ny = self.y + dy
|
ny = self.y + dy
|
||||||
@ -148,19 +144,14 @@ class Piece:
|
|||||||
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 клеток или до 5 для улучшенного хода
|
|
||||||
max_steps = self.move_range if hasattr(self, 'move_range') else 3
|
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':
|
||||||
directions = [(-1,-1),(1,-1),(1,1),(-1,1)]
|
directions = [(-1,-1),(1,-1),(1,1),(-1,1)]
|
||||||
elif self.name == 'queen':
|
elif self.name == 'queen':
|
||||||
directions = [
|
directions = [(-1,0),(1,0),(0,-1),(0,1),(-1,-1),(1,-1),(1,1),(-1,1)]
|
||||||
(-1,0),(1,0),(0,-1),(0,1),
|
|
||||||
(-1,-1),(1,-1),(1,1),(-1,1)
|
|
||||||
]
|
|
||||||
for dx, dy in directions:
|
for dx, dy in directions:
|
||||||
for step in range(1, max_steps + 1):
|
for step in range(1, max_steps + 1):
|
||||||
nx = self.x + dx * step
|
nx = self.x + dx * step
|
||||||
@ -174,62 +165,52 @@ class Piece:
|
|||||||
moves.append((nx, ny))
|
moves.append((nx, ny))
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
|
||||||
elif self.name == 'knight':
|
elif self.name == 'knight':
|
||||||
deltas = [(-2,-1),(-1,-2),(1,-2),(2,-1),
|
deltas = [(-2,-1),(-1,-2),(1,-2),(2,-1),
|
||||||
(2,1),(1,2),(-1,2),(-2,1)]
|
(2,1),(1,2),(-1,2),(-2,1)]
|
||||||
for dx, dy in deltas:
|
for dx, dy in deltas:
|
||||||
nx, ny = self.x+dx, self.y+dy
|
nx, ny = self.x + dx, 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 == 'king':
|
elif self.name == 'king':
|
||||||
directions = [
|
directions = [(-1,0),(1,0),(0,-1),(0,1),(-1,-1),(1,-1),(1,1),(-1,1)]
|
||||||
(-1,0),(1,0),(0,-1),(0,1),
|
|
||||||
(-1,-1),(1,-1),(1,1),(-1,1)
|
|
||||||
]
|
|
||||||
for dx, dy in directions:
|
for dx, dy in directions:
|
||||||
nx, ny = self.x+dx, self.y+dy
|
nx, ny = self.x + dx, 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))
|
||||||
|
|
||||||
return moves
|
return moves
|
||||||
|
|
||||||
# --- Инициализация фигур ---
|
# --- Инициализация фигур ---
|
||||||
def initialize_pieces():
|
def initialize_pieces():
|
||||||
"""Чёрные: y=2(back), y=3(pawns). Белые: y=27(back), y=26(pawns)."""
|
"""Чёрные: y=2 (back), y=3 (pawns). Белые: y=27 (back), y=26 (pawns)."""
|
||||||
pieces = []
|
pieces = []
|
||||||
cx = GRID_WIDTH//2
|
cx = GRID_WIDTH // 2
|
||||||
|
# Чёрные
|
||||||
# ЧЁРНЫЕ
|
|
||||||
black_back = ['rook','knight','bishop','king','queen','bishop','knight','rook']
|
black_back = ['rook','knight','bishop','king','queen','bishop','knight','rook']
|
||||||
for i,pname in enumerate(black_back):
|
for i, pname in enumerate(black_back):
|
||||||
x = cx - 3 + i
|
x = cx - 3 + i
|
||||||
y = 2
|
y = 2
|
||||||
pieces.append(Piece(pname,'black',x,y))
|
pieces.append(Piece(pname, 'black', x, y))
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
x = cx-3 + i
|
x = cx - 3 + i
|
||||||
y = 3
|
y = 3
|
||||||
pieces.append(Piece('pawn','black',x,y))
|
pieces.append(Piece('pawn', 'black', x, y))
|
||||||
|
# Белые
|
||||||
# БЕЛЫЕ
|
|
||||||
white_back = ['rook','knight','bishop','king','queen','bishop','knight','rook']
|
white_back = ['rook','knight','bishop','king','queen','bishop','knight','rook']
|
||||||
for i,pname in enumerate(white_back):
|
for i, pname in enumerate(white_back):
|
||||||
x = cx - 3 + i
|
x = cx - 3 + i
|
||||||
y = 27
|
y = 27
|
||||||
pieces.append(Piece(pname,'white',x,y))
|
pieces.append(Piece(pname, 'white', x, y))
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
x = cx-3 + i
|
x = cx - 3 + i
|
||||||
y = 26
|
y = 26
|
||||||
pieces.append(Piece('pawn','white',x,y))
|
pieces.append(Piece('pawn', 'white', x, y))
|
||||||
|
|
||||||
return pieces
|
return pieces
|
||||||
|
|
||||||
# Инициализация фигур
|
|
||||||
pieces = initialize_pieces()
|
pieces = initialize_pieces()
|
||||||
|
|
||||||
selected_piece = None
|
selected_piece = None
|
||||||
@ -239,12 +220,13 @@ winner = None
|
|||||||
|
|
||||||
# --- Туман войны ---
|
# --- Туман войны ---
|
||||||
cell_counters = {} # {(x,y): turns_since_last_revealed}
|
cell_counters = {} # {(x,y): turns_since_last_revealed}
|
||||||
BONUS_GENERATION_CHANCE = 0.10 # 10% шанс появления бонуса при повторном открытии
|
# Каждая новая клетка имеет 10% шанс стать бонусной.
|
||||||
COIN_GENERATION_CHANCE = 0.001 # 0.1% шанс появления монеты
|
BONUS_GENERATION_CHANCE = 0.10
|
||||||
|
|
||||||
# --- Система ходов ---
|
# --- Система ходов и многоперемещений ---
|
||||||
current_turn = 'white' # Начинаем с белых
|
current_turn = 'white' # Начинаем с белых
|
||||||
turn_count = 0
|
turn_count = 0
|
||||||
|
moves_remaining = 3 # За один ход игрок может сделать 3 перемещения
|
||||||
|
|
||||||
# --- Механика повышения вероятности красных полей ---
|
# --- Механика повышения вероятности красных полей ---
|
||||||
def update_bonus_probabilities():
|
def update_bonus_probabilities():
|
||||||
@ -292,26 +274,31 @@ def check_timer():
|
|||||||
else:
|
else:
|
||||||
switch_turn()
|
switch_turn()
|
||||||
|
|
||||||
|
# При переключении хода сбрасываем число оставшихся ходов и флаг has_moved у фигур текущего игрока.
|
||||||
def switch_turn():
|
def switch_turn():
|
||||||
global current_turn, turn_count, timer_expired
|
global current_turn, turn_count, timer_expired, moves_remaining
|
||||||
current_turn = 'black' if current_turn == 'white' else 'white'
|
current_turn = 'black' if current_turn == 'white' else 'white'
|
||||||
turn_count += 1
|
turn_count += 1
|
||||||
reset_timer()
|
reset_timer()
|
||||||
timer_expired = False
|
timer_expired = False
|
||||||
update_bonus_probabilities()
|
update_bonus_probabilities()
|
||||||
|
moves_remaining = 3
|
||||||
|
for p in pieces:
|
||||||
|
if p.color == current_turn:
|
||||||
|
p.has_moved = False
|
||||||
|
|
||||||
|
# После успешного перемещения фигуры вызываем эту функцию.
|
||||||
|
def end_move(moved_piece):
|
||||||
|
global moves_remaining
|
||||||
|
moved_piece.has_moved = True
|
||||||
|
moves_remaining -= 1
|
||||||
|
if moves_remaining <= 0:
|
||||||
|
switch_turn()
|
||||||
|
|
||||||
|
# --- Обновление тумана войны и генерация бонусов/монет ---
|
||||||
def update_fog():
|
def update_fog():
|
||||||
"""
|
|
||||||
Обновляет туман войны:
|
|
||||||
- Открытые клетки остаются открытыми.
|
|
||||||
- Закрытые клетки, которые не находятся рядом с любыми фигурами на расстоянии 2 клеток,
|
|
||||||
становятся закрытыми через 5 ходов.
|
|
||||||
- При повторном открытии клетки шанс на появление нового бонуса.
|
|
||||||
"""
|
|
||||||
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):
|
||||||
@ -320,13 +307,9 @@ def update_fog():
|
|||||||
ny = p.y + dy
|
ny = p.y + dy
|
||||||
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:
|
for merchant_pos in merchant_positions:
|
||||||
new_revealed.add(merchant_pos)
|
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)
|
||||||
@ -338,34 +321,24 @@ def update_fog():
|
|||||||
cell_counters[pos] += 1
|
cell_counters[pos] += 1
|
||||||
else:
|
else:
|
||||||
cell_counters[pos] = 1
|
cell_counters[pos] = 1
|
||||||
|
|
||||||
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)
|
||||||
# Удаляем бонус, если клетка закрывается и бонус не является 'damage'
|
|
||||||
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 pos not in coin_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()
|
if random.random() < 0.90:
|
||||||
if not any(p.x == pos[0] and p.y == pos[1] for p in pieces):
|
bonus_type = choose_bonus_type()
|
||||||
bonus_cells[pos] = {'type': bonus_type}
|
if not any(p.x == pos[0] and p.y == pos[1] for p in pieces):
|
||||||
# Генерация монет
|
bonus_cells[pos] = {'type': bonus_type}
|
||||||
if pos not in coin_cells and random.random() < COIN_GENERATION_CHANCE:
|
else:
|
||||||
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):
|
||||||
coin_cells.add(pos)
|
coin_cells.add(pos)
|
||||||
|
|
||||||
# --- Добавление торговцев ---
|
# --- Добавление торговцев ---
|
||||||
# Определяем позиции торговцев: центральная линия по краям
|
|
||||||
central_line_y = GRID_HEIGHT // 2
|
central_line_y = GRID_HEIGHT // 2
|
||||||
merchant_positions = [
|
merchant_positions = [(0, central_line_y), (GRID_WIDTH - 1, central_line_y)]
|
||||||
(0, central_line_y),
|
|
||||||
(GRID_WIDTH - 1, central_line_y)
|
|
||||||
]
|
|
||||||
|
|
||||||
# Добавляем торговцы в глобальное множество открытых клеток
|
|
||||||
global_revealed.update(merchant_positions)
|
global_revealed.update(merchant_positions)
|
||||||
|
|
||||||
# --- Монеты на поле ---
|
# --- Монеты на поле ---
|
||||||
@ -375,14 +348,44 @@ coin_cells = set()
|
|||||||
player_coins = {'white': 0, 'black': 0}
|
player_coins = {'white': 0, 'black': 0}
|
||||||
|
|
||||||
# --- Механика магазина ---
|
# --- Механика магазина ---
|
||||||
|
# Повышенные цены: 6 монет за покупку
|
||||||
shop_open = False
|
shop_open = False
|
||||||
shop_items = {
|
shop_items = {
|
||||||
'extend_move': {'name': 'Расширить ход', 'cost': 3},
|
'extend_move': {'name': 'Расширить ход', 'cost': 6},
|
||||||
'increase_hp': {'name': 'Увеличить HP', 'cost': 3},
|
'increase_hp': {'name': 'Увеличить HP', 'cost': 6},
|
||||||
'damage_enemy': {'name': 'Уменьшить HP врага', 'cost': 3},
|
'damage_enemy': {'name': 'Уменьшить HP врага', 'cost': 6},
|
||||||
'curse': {'name': 'Проклятие', 'cost': 3}
|
'curse': {'name': 'Проклятие', 'cost': 6}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# --- Реализация спрайтов фигур ---
|
||||||
|
# Ожидается, что в папке "sprites" находятся файлы: wK.png, wQ.png, wR.png, wB.png, wN.png, wP.png для белых,
|
||||||
|
# и bK.png, bQ.png, bR.png, bB.png, bN.png, bP.png для чёрных.
|
||||||
|
piece_sprites = {}
|
||||||
|
|
||||||
|
def load_piece_sprites():
|
||||||
|
piece_names_map = {
|
||||||
|
'king': 'K',
|
||||||
|
'queen': 'Q',
|
||||||
|
'rook': 'R',
|
||||||
|
'bishop': 'B',
|
||||||
|
'knight': 'N',
|
||||||
|
'pawn': 'P'
|
||||||
|
}
|
||||||
|
colors = ['white', 'black']
|
||||||
|
for color in colors:
|
||||||
|
letter = 'w' if color == 'white' else 'b'
|
||||||
|
for name in piece_names_map:
|
||||||
|
filename = f"sprites/{letter}{piece_names_map[name]}.png"
|
||||||
|
try:
|
||||||
|
image = pygame.image.load(filename).convert_alpha()
|
||||||
|
image = pygame.transform.scale(image, (CELL_SIZE, CELL_SIZE))
|
||||||
|
piece_sprites[(color, name)] = image
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Ошибка загрузки спрайта {filename}: {e}")
|
||||||
|
piece_sprites[(color, name)] = None
|
||||||
|
|
||||||
|
load_piece_sprites()
|
||||||
|
|
||||||
# --- Функции отрисовки ---
|
# --- Функции отрисовки ---
|
||||||
def draw_grid():
|
def draw_grid():
|
||||||
for x in range(0, CELL_SIZE * GRID_WIDTH, CELL_SIZE):
|
for x in range(0, CELL_SIZE * GRID_WIDTH, CELL_SIZE):
|
||||||
@ -395,38 +398,37 @@ def draw_fog():
|
|||||||
for x in range(GRID_WIDTH):
|
for x in range(GRID_WIDTH):
|
||||||
pos = (x, y)
|
pos = (x, y)
|
||||||
if pos not in global_revealed:
|
if pos not in global_revealed:
|
||||||
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:
|
if pos in merchant_positions:
|
||||||
continue # Торговцы всегда видимы
|
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():
|
||||||
for (bx, by), info in bonus_cells.items():
|
for (bx, by), info in bonus_cells.items():
|
||||||
# Для 'damage' бонусов отображаем всегда, иначе только если клетка видна
|
|
||||||
if info['type'] != 'damage' and (bx, by) not in global_revealed:
|
if info['type'] != 'damage' and (bx, by) not in global_revealed:
|
||||||
continue
|
continue
|
||||||
cx = bx*CELL_SIZE + CELL_SIZE//2
|
cx = bx * CELL_SIZE + CELL_SIZE // 2
|
||||||
cy = by*CELL_SIZE + CELL_SIZE//2
|
cy = by * CELL_SIZE + CELL_SIZE // 2
|
||||||
bonus_type = info['type']
|
bonus_type = info['type']
|
||||||
if bonus_type == 'regen':
|
if bonus_type == 'regen':
|
||||||
color = COLOR_REGEN
|
color = COLOR_REGEN
|
||||||
pygame.draw.circle(screen, color, (cx, cy), CELL_SIZE//4)
|
pygame.draw.circle(screen, color, (cx, cy), CELL_SIZE // 4)
|
||||||
elif bonus_type == 'hp_upgrade':
|
elif bonus_type == 'hp_upgrade':
|
||||||
color = COLOR_HP_UPGRADE
|
color = COLOR_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 == 'damage':
|
elif bonus_type == 'damage':
|
||||||
color = COLOR_DAMAGE
|
color = COLOR_DAMAGE
|
||||||
pygame.draw.circle(screen, color, (cx, cy), CELL_SIZE//4)
|
pygame.draw.circle(screen, color, (cx, cy), CELL_SIZE // 4)
|
||||||
elif bonus_type == 'king_hp_upgrade':
|
elif bonus_type == 'king_hp_upgrade':
|
||||||
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
|
||||||
ny = by + dy
|
ny = by + dy
|
||||||
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
if 0 <= nx < GRID_WIDTH and 0 <= ny < GRID_HEIGHT:
|
||||||
@ -434,25 +436,22 @@ def draw_bonus_cells():
|
|||||||
possible = True
|
possible = True
|
||||||
break
|
break
|
||||||
color = COLOR_ADD_PIECE if possible else COLOR_ADD_PIECE_PINK
|
color = COLOR_ADD_PIECE if possible else COLOR_ADD_PIECE_PINK
|
||||||
pygame.draw.circle(screen, color, (cx, cy), CELL_SIZE//4)
|
pygame.draw.circle(screen, color, (cx, cy), CELL_SIZE // 4)
|
||||||
# Рисуем плюс
|
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():
|
def draw_coin_cells():
|
||||||
for pos in coin_cells:
|
for pos in coin_cells:
|
||||||
if pos not in global_revealed:
|
if pos not in global_revealed:
|
||||||
continue # Монеты видны только в открытых клетках
|
continue
|
||||||
x, y = pos
|
x, y = pos
|
||||||
cx = x * CELL_SIZE + CELL_SIZE // 2
|
cx = x * CELL_SIZE + CELL_SIZE // 2
|
||||||
cy = y * CELL_SIZE + CELL_SIZE // 2
|
cy = y * CELL_SIZE + CELL_SIZE // 2
|
||||||
size = CELL_SIZE // 3
|
size = CELL_SIZE // 3
|
||||||
# Рисуем оранжевый треугольник
|
|
||||||
point1 = (cx, cy - size)
|
point1 = (cx, cy - size)
|
||||||
point2 = (cx - size, cy + size)
|
point2 = (cx - size, cy + size)
|
||||||
point3 = (cx + size, cy + size)
|
point3 = (cx + size, cy + size)
|
||||||
pygame.draw.polygon(screen, COLOR_COIN, [point1, point2, point3])
|
pygame.draw.polygon(screen, COLOR_COIN, [point1, point2, point3])
|
||||||
# Рисуем символ доллара
|
|
||||||
dollar_text = font.render('$', True, (0, 0, 0))
|
dollar_text = font.render('$', True, (0, 0, 0))
|
||||||
text_rect = dollar_text.get_rect(center=(cx, cy))
|
text_rect = dollar_text.get_rect(center=(cx, cy))
|
||||||
screen.blit(dollar_text, text_rect)
|
screen.blit(dollar_text, text_rect)
|
||||||
@ -460,151 +459,123 @@ def draw_coin_cells():
|
|||||||
def draw_merchants():
|
def draw_merchants():
|
||||||
for pos in merchant_positions:
|
for pos in merchant_positions:
|
||||||
x, y = pos
|
x, y = pos
|
||||||
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_MERCHANT, rect)
|
pygame.draw.rect(screen, COLOR_MERCHANT, rect)
|
||||||
# Рисуем стрелку вверх
|
|
||||||
arrow_color = (255, 255, 255)
|
|
||||||
arrow_size = CELL_SIZE // 2
|
|
||||||
points = [
|
points = [
|
||||||
(x * CELL_SIZE + CELL_SIZE // 2, y * CELL_SIZE + CELL_SIZE // 4),
|
(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 + CELL_SIZE // 4, y * CELL_SIZE + 3 * CELL_SIZE // 4),
|
||||||
(x * CELL_SIZE + 3 * 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)
|
pygame.draw.polygon(screen, (255, 255, 255), points)
|
||||||
|
|
||||||
def draw_pieces(pieces):
|
def draw_pieces(pieces):
|
||||||
for p in pieces:
|
for p in pieces:
|
||||||
rect = pygame.Rect(p.x*CELL_SIZE, p.y*CELL_SIZE, CELL_SIZE, CELL_SIZE)
|
x = p.x * CELL_SIZE
|
||||||
|
y = p.y * CELL_SIZE
|
||||||
if p.color == 'white':
|
sprite = piece_sprites.get((p.color, p.name))
|
||||||
pygame.draw.rect(screen, COLOR_WHITE_PIECE, rect)
|
if sprite:
|
||||||
symbol = piece_symbols.get(p.name,'?')
|
screen.blit(sprite, (x, y))
|
||||||
text = font.render(symbol, True, (255,0,0))
|
|
||||||
text_rect = text.get_rect(center=rect.center)
|
|
||||||
screen.blit(text, text_rect)
|
|
||||||
# HP чёрным
|
|
||||||
hp_str = f"{p.hp}/{p.max_hp}"
|
|
||||||
hp_text = font.render(hp_str, True, (0,0,0))
|
|
||||||
screen.blit(hp_text, (rect.x+2, rect.y+2))
|
|
||||||
else:
|
else:
|
||||||
pygame.draw.rect(screen, COLOR_BLACK_PIECE, rect)
|
rect = pygame.Rect(x, y, CELL_SIZE, CELL_SIZE)
|
||||||
symbol = piece_symbols.get(p.name,'?')
|
if p.color == 'white':
|
||||||
text = font.render(symbol, True, (255,0,0))
|
pygame.draw.rect(screen, COLOR_WHITE_PIECE, rect)
|
||||||
|
else:
|
||||||
|
pygame.draw.rect(screen, COLOR_BLACK_PIECE, rect)
|
||||||
|
symbol = piece_symbols.get(p.name, '?')
|
||||||
|
text = font.render(symbol, True, (255, 0, 0))
|
||||||
text_rect = text.get_rect(center=rect.center)
|
text_rect = text.get_rect(center=rect.center)
|
||||||
screen.blit(text, text_rect)
|
screen.blit(text, text_rect)
|
||||||
# HP белым
|
# Отрисовка HP с полупрозрачным фоном для лучшей читаемости:
|
||||||
hp_str = f"{p.hp}/{p.max_hp}"
|
hp_str = f"{p.hp}/{p.max_hp}"
|
||||||
hp_text = font.render(hp_str, True, (255,255,255))
|
# Определяем цвета: для белых фигур текст будет черным, для черных – белым;
|
||||||
screen.blit(hp_text, (rect.x+2, rect.y+2))
|
# фон выбираем противоположный
|
||||||
|
if p.color == 'white':
|
||||||
|
text_color = (0, 0, 0)
|
||||||
|
bg_color = (255, 255, 255)
|
||||||
|
else:
|
||||||
|
text_color = (255, 255, 255)
|
||||||
|
bg_color = (0, 0, 0)
|
||||||
|
hp_text = font.render(hp_str, True, text_color)
|
||||||
|
text_rect = hp_text.get_rect(topleft=(x + 2, y + 2))
|
||||||
|
# Создаем временную поверхность для фона с альфа-каналом
|
||||||
|
bg_surf = pygame.Surface(text_rect.size)
|
||||||
|
bg_surf.set_alpha(200) # степень прозрачности (0-255)
|
||||||
|
bg_surf.fill(bg_color)
|
||||||
|
screen.blit(bg_surf, text_rect.topleft)
|
||||||
|
screen.blit(hp_text, text_rect.topleft)
|
||||||
if p.selected:
|
if p.selected:
|
||||||
|
rect = pygame.Rect(x, y, CELL_SIZE, CELL_SIZE)
|
||||||
pygame.draw.rect(screen, COLOR_SELECTED, rect, 2)
|
pygame.draw.rect(screen, COLOR_SELECTED, rect, 2)
|
||||||
|
|
||||||
for (mx, my) in possible_moves:
|
for (mx, my) in possible_moves:
|
||||||
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 draw_statistics_panel():
|
def draw_statistics_panel():
|
||||||
panel_rect = pygame.Rect(CELL_SIZE * GRID_WIDTH, 0, PANEL_WIDTH, WINDOW_HEIGHT)
|
panel_rect = pygame.Rect(CELL_SIZE * GRID_WIDTH, 0, PANEL_WIDTH, WINDOW_HEIGHT)
|
||||||
pygame.draw.rect(screen, (50, 50, 50), panel_rect)
|
pygame.draw.rect(screen, (50, 50, 50), panel_rect)
|
||||||
|
|
||||||
# Заголовок
|
|
||||||
title_text = shop_font.render("Статистика", True, (255, 255, 255))
|
title_text = shop_font.render("Статистика", True, (255, 255, 255))
|
||||||
screen.blit(title_text, (CELL_SIZE * GRID_WIDTH + 10, 10))
|
screen.blit(title_text, (CELL_SIZE * GRID_WIDTH + 10, 10))
|
||||||
|
|
||||||
# Текущий ход
|
|
||||||
turn_text = turn_font.render(f"Ход: {current_turn.capitalize()}", True, COLOR_TURN_TEXT)
|
turn_text = turn_font.render(f"Ход: {current_turn.capitalize()}", True, COLOR_TURN_TEXT)
|
||||||
screen.blit(turn_text, (CELL_SIZE * GRID_WIDTH + 10, 50))
|
screen.blit(turn_text, (CELL_SIZE * GRID_WIDTH + 10, 50))
|
||||||
|
|
||||||
# Количество ходов
|
|
||||||
counter_text = counter_font.render(f"Ходов: {turn_count}", True, (255, 255, 255))
|
counter_text = counter_font.render(f"Ходов: {turn_count}", True, (255, 255, 255))
|
||||||
screen.blit(counter_text, (CELL_SIZE * GRID_WIDTH + 10, 80))
|
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_str = f"Время: {minutes:02}:{seconds:02}"
|
timer_text_str = f"Время: {minutes:02}:{seconds:02}"
|
||||||
if timer_expired and player_timeouts[current_turn] >=1:
|
color = COLOR_TIMER_WARNING if timer_expired and player_timeouts[current_turn] >= 1 else COLOR_TIMER_NORMAL
|
||||||
color = COLOR_TIMER_WARNING
|
|
||||||
else:
|
|
||||||
color = COLOR_TIMER_NORMAL
|
|
||||||
timer_text = timer_font.render(timer_text_str, True, color)
|
timer_text = timer_font.render(timer_text_str, True, color)
|
||||||
screen.blit(timer_text, (CELL_SIZE * GRID_WIDTH + 10, 110))
|
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_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))
|
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_white, (CELL_SIZE * GRID_WIDTH + 10, 140))
|
||||||
screen.blit(coins_text_black, (CELL_SIZE * GRID_WIDTH + 10, 170))
|
screen.blit(coins_text_black, (CELL_SIZE * GRID_WIDTH + 10, 170))
|
||||||
|
moves_text = counter_font.render(f"Осталось ходов: {moves_remaining}", True, (255, 255, 255))
|
||||||
# Если открыт магазин, отображаем его
|
screen.blit(moves_text, (CELL_SIZE * GRID_WIDTH + 10, 200))
|
||||||
if shop_open:
|
if shop_open:
|
||||||
draw_shop()
|
draw_shop()
|
||||||
|
|
||||||
def draw_shop():
|
def draw_shop():
|
||||||
shop_x = CELL_SIZE * GRID_WIDTH + 10
|
shop_x = CELL_SIZE * GRID_WIDTH + 10
|
||||||
shop_y = 200
|
shop_y = 240
|
||||||
shop_title = shop_font.render("Магазин", True, (255, 255, 0))
|
shop_title = shop_font.render("Магазин", True, (255, 255, 0))
|
||||||
screen.blit(shop_title, (shop_x, shop_y))
|
screen.blit(shop_title, (shop_x, shop_y))
|
||||||
|
|
||||||
for idx, (key, item) in enumerate(shop_items.items()):
|
for idx, (key, item) in enumerate(shop_items.items()):
|
||||||
item_y = shop_y + 40 + idx * 60
|
item_y = shop_y + 40 + idx * 60
|
||||||
# Кнопка
|
|
||||||
button_rect = pygame.Rect(shop_x, item_y, PANEL_WIDTH - 20, 50)
|
button_rect = pygame.Rect(shop_x, item_y, PANEL_WIDTH - 20, 50)
|
||||||
# Проверка, хватает ли монет
|
button_color = (0, 255, 0) if player_coins[current_turn] >= item['cost'] else (128, 128, 128)
|
||||||
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)
|
pygame.draw.rect(screen, button_color, button_rect)
|
||||||
# Название предмета
|
item_text = shop_font.render(f"{item['name']} - {item['cost']} мон.", True, (0, 0, 0))
|
||||||
item_text = shop_font.render(f"{item['name']} - {item['cost']} мон.", True, (0,0,0))
|
|
||||||
screen.blit(item_text, (shop_x + 5, item_y + 15))
|
screen.blit(item_text, (shop_x + 5, item_y + 15))
|
||||||
# Хранение позиции кнопки для обработки кликов
|
|
||||||
shop_items[key]['button_rect'] = button_rect
|
shop_items[key]['button_rect'] = button_rect
|
||||||
|
|
||||||
def draw_victory(winner):
|
def draw_victory(winner):
|
||||||
text = victory_font.render(f"{winner.capitalize()} победил!", True, (255, 255, 255))
|
text = victory_font.render(f"{winner.capitalize()} победил!", True, (255, 255, 255))
|
||||||
text_rect = text.get_rect(center=(WINDOW_WIDTH//2, WINDOW_HEIGHT//2))
|
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):
|
||||||
"""Применяем эффект бонуса к фигуре piece в зависимости от типа."""
|
|
||||||
if bonus_type == 'regen':
|
if bonus_type == 'regen':
|
||||||
# Регенерация (1..2) для НЕ короля
|
|
||||||
if piece.name != 'king':
|
if piece.name != 'king':
|
||||||
amt = random.randint(1, 2)
|
amt = random.randint(1, 2)
|
||||||
piece.hp = min(piece.hp + amt, piece.max_hp)
|
piece.hp = min(piece.hp + amt, piece.max_hp)
|
||||||
|
|
||||||
elif bonus_type == 'hp_upgrade':
|
elif bonus_type == 'hp_upgrade':
|
||||||
# Повышение max_hp только НЕ королю без восстановления HP
|
|
||||||
if piece.name != 'king':
|
if piece.name != 'king':
|
||||||
piece.max_hp += 1
|
piece.max_hp += 1
|
||||||
# piece.hp остается неизменным
|
|
||||||
|
|
||||||
elif bonus_type == 'king_hp_upgrade':
|
elif bonus_type == 'king_hp_upgrade':
|
||||||
# Только для короля, бонус активируется другим игроком
|
|
||||||
if piece.name != 'king':
|
if piece.name != 'king':
|
||||||
# Найти короля той же команды
|
|
||||||
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
|
|
||||||
king.max_hp += 1
|
king.max_hp += 1
|
||||||
king.hp = king.max_hp
|
king.hp = king.max_hp
|
||||||
else:
|
else:
|
||||||
# Восстанавливаем 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':
|
||||||
# Урон при прохождении через клетку 'damage' уже обрабатывается отдельно
|
|
||||||
pass
|
pass
|
||||||
|
|
||||||
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
|
||||||
@ -617,15 +588,15 @@ def apply_bonus(piece, bonus_type, pieces):
|
|||||||
|
|
||||||
def handle_shop_purchase(key):
|
def handle_shop_purchase(key):
|
||||||
if player_coins[current_turn] < shop_items[key]['cost']:
|
if player_coins[current_turn] < shop_items[key]['cost']:
|
||||||
return # Недостаточно монет
|
return
|
||||||
player_coins[current_turn] -= shop_items[key]['cost']
|
player_coins[current_turn] -= shop_items[key]['cost']
|
||||||
if key == 'extend_move':
|
if key == 'extend_move':
|
||||||
for p in pieces:
|
for p in pieces:
|
||||||
if p.color == current_turn:
|
if p.color == current_turn:
|
||||||
if p.name in ['rook', 'bishop', 'queen']:
|
if p.name in ['rook', 'bishop', 'queen']:
|
||||||
setattr(p, 'move_range', getattr(p, 'move_range', 3) + 2) # До 5
|
setattr(p, 'move_range', getattr(p, 'move_range', 3) + 2)
|
||||||
elif p.name == 'pawn':
|
elif p.name == 'pawn':
|
||||||
setattr(p, 'move_range', getattr(p, 'move_range', 1) + 1) # До 2
|
setattr(p, 'move_range', getattr(p, 'move_range', 1) + 1)
|
||||||
elif key == 'increase_hp':
|
elif key == 'increase_hp':
|
||||||
for p in pieces:
|
for p in pieces:
|
||||||
if p.color == current_turn and p.name != 'king':
|
if p.color == current_turn and p.name != 'king':
|
||||||
@ -640,12 +611,10 @@ def handle_shop_purchase(key):
|
|||||||
elif p.hp > 1:
|
elif p.hp > 1:
|
||||||
p.hp = 1
|
p.hp = 1
|
||||||
else:
|
else:
|
||||||
p.hp = 1 # Уже 1, остаётся 1
|
p.hp = 1
|
||||||
elif key == 'curse':
|
elif key == 'curse':
|
||||||
# Уменьшаем вероятность появления 'regen' и 'hp_upgrade' на 10%
|
|
||||||
bonus_probabilities['regen'] = max(bonus_probabilities['regen'] - 0.10, 0)
|
bonus_probabilities['regen'] = max(bonus_probabilities['regen'] - 0.10, 0)
|
||||||
bonus_probabilities['hp_upgrade'] = max(bonus_probabilities['hp_upgrade'] - 0.10, 0)
|
bonus_probabilities['hp_upgrade'] = max(bonus_probabilities['hp_upgrade'] - 0.10, 0)
|
||||||
# Нормализуем вероятности
|
|
||||||
total_prob = sum(bonus_probabilities.values())
|
total_prob = sum(bonus_probabilities.values())
|
||||||
for bt in bonus_probabilities:
|
for bt in bonus_probabilities:
|
||||||
bonus_probabilities[bt] /= total_prob if total_prob > 0 else 1
|
bonus_probabilities[bt] /= total_prob if total_prob > 0 else 1
|
||||||
@ -663,36 +632,25 @@ while running:
|
|||||||
for event in pygame.event.get():
|
for event in pygame.event.get():
|
||||||
if event.type == pygame.QUIT:
|
if event.type == pygame.QUIT:
|
||||||
running = False
|
running = False
|
||||||
|
|
||||||
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()
|
||||||
if mx < CELL_SIZE * GRID_WIDTH and my < CELL_SIZE * GRID_HEIGHT:
|
if mx < CELL_SIZE * GRID_WIDTH and my < CELL_SIZE * GRID_HEIGHT:
|
||||||
gx = mx // CELL_SIZE
|
gx = mx // CELL_SIZE
|
||||||
gy = my // 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:
|
if (gx, gy) in coin_cells:
|
||||||
player_coins[current_turn] += 1
|
player_coins[current_turn] += 1
|
||||||
coin_cells.remove((gx, gy))
|
coin_cells.remove((gx, gy))
|
||||||
|
|
||||||
# Проверяем, является ли клетка торговцем
|
|
||||||
if (gx, gy) in merchant_positions:
|
if (gx, gy) in merchant_positions:
|
||||||
shop_open = True
|
shop_open = True
|
||||||
|
|
||||||
# Проверяем, есть ли там вражеская фигура
|
|
||||||
defender = next((p for p in pieces if p.x == gx and p.y == gy), None)
|
defender = next((p for p in pieces if p.x == gx and p.y == gy), None)
|
||||||
if defender:
|
if defender:
|
||||||
# Проводим бой
|
|
||||||
attacker = selected_piece
|
attacker = selected_piece
|
||||||
attacker_alive, defender_alive = resolve_combat(attacker, defender)
|
attacker_alive, defender_alive = resolve_combat(attacker, defender)
|
||||||
if not defender_alive:
|
if not defender_alive:
|
||||||
@ -708,15 +666,14 @@ while running:
|
|||||||
switch_turn()
|
switch_turn()
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
# Перемещаем атакующего
|
|
||||||
path = []
|
path = []
|
||||||
if attacker.name in ['rook', 'bishop', 'queen']:
|
if attacker.name in ['rook', 'bishop', 'queen']:
|
||||||
dx = gx - attacker.x
|
dx = gx - attacker.x
|
||||||
dy = gy - attacker.y
|
dy = gy - attacker.y
|
||||||
if dx != 0:
|
if dx != 0:
|
||||||
dx = dx // abs(dx)
|
dx //= abs(dx)
|
||||||
if dy != 0:
|
if dy != 0:
|
||||||
dy = dy // abs(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 - attacker.x), abs(gy - attacker.y))):
|
||||||
path_x = attacker.x + dx * step
|
path_x = attacker.x + dx * step
|
||||||
path_y = attacker.y + dy * step
|
path_y = attacker.y + dy * step
|
||||||
@ -724,7 +681,7 @@ while running:
|
|||||||
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)
|
damage = random.randint(1, 5)
|
||||||
attacker.hp = max(attacker.hp - damage, 0)
|
attacker.hp = max(attacker.hp - damage, 0)
|
||||||
del bonus_cells[pos]
|
del bonus_cells[pos]
|
||||||
if attacker.hp == 0:
|
if attacker.hp == 0:
|
||||||
@ -738,20 +695,18 @@ while running:
|
|||||||
attacker.x = gx
|
attacker.x = gx
|
||||||
attacker.y = gy
|
attacker.y = gy
|
||||||
attacker.selected = False
|
attacker.selected = False
|
||||||
|
end_move(attacker)
|
||||||
selected_piece = None
|
selected_piece = None
|
||||||
possible_moves.clear()
|
possible_moves.clear()
|
||||||
switch_turn()
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Пустая клетка — просто ходим
|
|
||||||
path = []
|
path = []
|
||||||
if selected_piece.name in ['rook', 'bishop', 'queen']:
|
if selected_piece.name in ['rook', 'bishop', 'queen']:
|
||||||
dx = gx - selected_piece.x
|
dx = gx - selected_piece.x
|
||||||
dy = gy - selected_piece.y
|
dy = gy - selected_piece.y
|
||||||
if dx != 0:
|
if dx != 0:
|
||||||
dx = dx // abs(dx)
|
dx //= abs(dx)
|
||||||
if dy != 0:
|
if dy != 0:
|
||||||
dy = dy // abs(dy)
|
dy //= abs(dy)
|
||||||
for step in range(1, max(abs(gx - selected_piece.x), abs(gy - selected_piece.y))):
|
for step in range(1, max(abs(gx - selected_piece.x), abs(gy - selected_piece.y))):
|
||||||
path_x = selected_piece.x + dx * step
|
path_x = selected_piece.x + dx * step
|
||||||
path_y = selected_piece.y + dy * step
|
path_y = selected_piece.y + dy * step
|
||||||
@ -759,7 +714,7 @@ while running:
|
|||||||
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)
|
damage = random.randint(1, 5)
|
||||||
selected_piece.hp = max(selected_piece.hp - damage, 0)
|
selected_piece.hp = max(selected_piece.hp - damage, 0)
|
||||||
del bonus_cells[pos]
|
del bonus_cells[pos]
|
||||||
if selected_piece.hp == 0:
|
if selected_piece.hp == 0:
|
||||||
@ -773,36 +728,28 @@ while running:
|
|||||||
selected_piece.x = gx
|
selected_piece.x = gx
|
||||||
selected_piece.y = gy
|
selected_piece.y = gy
|
||||||
selected_piece.selected = False
|
selected_piece.selected = False
|
||||||
|
end_move(selected_piece)
|
||||||
selected_piece = None
|
selected_piece = None
|
||||||
possible_moves.clear()
|
possible_moves.clear()
|
||||||
switch_turn()
|
|
||||||
|
|
||||||
update_fog()
|
update_fog()
|
||||||
else:
|
else:
|
||||||
selected_piece.selected = False
|
selected_piece.selected = False
|
||||||
selected_piece = None
|
selected_piece = None
|
||||||
possible_moves.clear()
|
possible_moves.clear()
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Выбираем фигуру только если клетка видима и соответствует текущему ходу
|
if clicked_piece and (gx, gy) in global_revealed and clicked_piece.color == current_turn and not clicked_piece.has_moved:
|
||||||
if clicked_piece and (gx, gy) in global_revealed and clicked_piece.color == current_turn:
|
|
||||||
selected_piece = clicked_piece
|
selected_piece = clicked_piece
|
||||||
selected_piece.selected = True
|
selected_piece.selected = True
|
||||||
possible_moves = selected_piece.get_possible_moves(pieces)
|
possible_moves = selected_piece.get_possible_moves(pieces)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
# Клик в правой панели
|
|
||||||
if shop_open:
|
if shop_open:
|
||||||
for key, item in shop_items.items():
|
for key, item in shop_items.items():
|
||||||
if 'button_rect' in item and item['button_rect'].collidepoint(mx, my):
|
if 'button_rect' in item and item['button_rect'].collidepoint(mx, my):
|
||||||
if player_coins[current_turn] >= item['cost']:
|
if player_coins[current_turn] >= item['cost']:
|
||||||
handle_shop_purchase(key)
|
handle_shop_purchase(key)
|
||||||
|
|
||||||
elif event.type == pygame.KEYDOWN:
|
elif event.type == pygame.KEYDOWN:
|
||||||
if event.key == pygame.K_ESCAPE:
|
if event.key == pygame.K_ESCAPE:
|
||||||
shop_open = False
|
shop_open = False
|
||||||
|
|
||||||
# Отрисовка
|
|
||||||
screen.fill(COLOR_BG)
|
screen.fill(COLOR_BG)
|
||||||
draw_grid()
|
draw_grid()
|
||||||
draw_fog()
|
draw_fog()
|
||||||
|
BIN
sprites/bB.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
sprites/bK.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
sprites/bN.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
sprites/bP.png
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
sprites/bQ.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
sprites/bR.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
sprites/wB.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
sprites/wK.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
sprites/wN.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
sprites/wP.png
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
sprites/wQ.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
sprites/wR.png
Normal file
After Width: | Height: | Size: 2.8 KiB |