ourgame/game.py

907 lines
37 KiB
Python

import pygame
import random
import sys
import os
import math
# --- Inicializācija ---
pygame.init()
# Ekrāna iestatījumi
WIDTH, HEIGHT = 1024, 576
SCREEN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Pixel Kombat: Ultimate")
CLOCK = pygame.time.Clock()
# --- KRĀSAS ---
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
BLUE = (0, 0, 255)
GRAY = (50, 50, 50)
DARK_GRAY = (20, 20, 20)
YELLOW = (255, 215, 0)
GREEN = (50, 200, 50)
CYAN = (0, 255, 255)
PURPLE = (160, 32, 240)
ORANGE = (255, 165, 0)
LIGHT_BLUE = (100, 149, 237)
# --- Fonti ---
def get_font(name, size):
if os.path.exists(name):
try:
return pygame.font.Font(name, size)
except:
return pygame.font.SysFont('arial', size)
else:
return pygame.font.SysFont('arial', size)
FONT_BIG = get_font("Act_Of_Rejection.ttf", 80)
FONT_MED = get_font("PressStart2P-Regular.ttf", 36)
FONT_SMALL = get_font("PressStart2P-Regular.ttf", 20)
FONT_TINY = get_font("PressStart2P-Regular.ttf", 14)
# --- GLOBĀLIE MAINĪGIE ---
STATE = "MENU"
SELECTED_BG = "BEACH"
GAME_MODE = "PVP"
# ============================================================
# --- HIGH SCORE FUNKCIJAS ---
# ============================================================
HIGHSCORE_FILE = "highscores.txt"
def save_highscore(winner_name):
try:
with open(HIGHSCORE_FILE, "a") as f:
f.write(f"{winner_name}\n")
except Exception as e:
print(f"Neizdevās saglabāt rezultātu: {e}")
def load_highscores():
scores = []
if os.path.exists(HIGHSCORE_FILE):
try:
with open(HIGHSCORE_FILE, "r") as f:
lines = f.readlines()
scores = [line.strip() for line in lines[-5:]]
except:
pass
return scores
# ============================================================
# --- TĒLU UN FONA DATU BĀZES ---
# ============================================================
FALLBACK_COLORS = [
(235, 64, 52), (52, 119, 235), (52, 235, 86), (255, 215, 0), (160, 32, 240), (255, 105, 180)
]
CHARACTER_FILES = [
"characters/first_char.png", "characters/second_char.png", "characters/third_char.png",
"characters/forth_char.png", "characters/fifth_char.png", "characters/sixth_char.png"
]
BOSS_FILES = ["boss/boss1.png", "boss/boss2.png", "boss/boss3.png"]
P1_CHAR_INDEX = 0
P2_CHAR_INDEX = 1
BG_FILES = {
"BEACH": "backgrounds/beach.jpg", "EVENINGSTREET": "backgrounds/evening_street.jpg",
"MARKET": "backgrounds/market.jpg", "RESTAURANT": "backgrounds/restaurant.jpg",
"SAKURASTREET": "backgrounds/sakura_street.jpg", "SHIP": "backgrounds/ship.jpg",
"STREETMARKETS": "backgrounds/street_markets.jpg"
}
def create_placeholder_image(color, size=(80, 160), text="", is_boss=False):
surf = pygame.Surface(size)
surf.fill(color)
pygame.draw.rect(surf, BLACK, (0, 0, size[0], size[1]), 2)
head_w = size[0] * 0.4
head_h = size[1] * 0.3
head_rect = pygame.Rect(size[0]//2 - head_w//2, 10, head_w, head_h)
pygame.draw.rect(surf, (200, 200, 200), head_rect)
pygame.draw.rect(surf, BLACK, head_rect, 2)
eye_y = head_rect.y + head_h // 3
eye_size = 6 if is_boss else 4
pygame.draw.circle(surf, BLACK, (int(head_rect.centerx - head_w//5), int(eye_y)), eye_size)
pygame.draw.circle(surf, BLACK, (int(head_rect.centerx + head_w//5), int(eye_y)), eye_size)
if is_boss:
horn_scale = size[0] // 10
pygame.draw.polygon(surf, RED, [
(head_rect.left, head_rect.top),
(head_rect.left - horn_scale, head_rect.top - horn_scale*2),
(head_rect.left + horn_scale, head_rect.top)
])
pygame.draw.polygon(surf, RED, [
(head_rect.right, head_rect.top),
(head_rect.right + horn_scale, head_rect.top - horn_scale*2),
(head_rect.right - horn_scale, head_rect.top)
])
if text:
font_size = 24 if is_boss else 18
font = pygame.font.SysFont('arial', font_size)
txt = font.render(text, True, WHITE)
surf.blit(txt, (size[0]//2 - txt.get_width()//2, size[1] - 40))
return surf
def load_character_images():
chars_data = []
SPRITE_SIZE = (80, 150)
ICON_SIZE = (100, 100)
for i, filename in enumerate(CHARACTER_FILES):
color = FALLBACK_COLORS[i % len(FALLBACK_COLORS)]
try:
if os.path.exists(filename):
img = pygame.image.load(filename).convert_alpha()
game_img = pygame.transform.scale(img, SPRITE_SIZE)
icon_img = pygame.transform.scale(img, ICON_SIZE)
else:
raise FileNotFoundError
except:
game_img = create_placeholder_image(color, SPRITE_SIZE, f"T{i+1}")
icon_surf = pygame.Surface(ICON_SIZE)
icon_surf.fill(color)
pygame.draw.rect(icon_surf, WHITE, (0,0,ICON_SIZE[0], ICON_SIZE[1]), 2)
font = pygame.font.SysFont('arial', 24)
txt = font.render(f"Char {i+1}", True, WHITE)
icon_surf.blit(txt, (ICON_SIZE[0]//2 - txt.get_width()//2, ICON_SIZE[1]//2 - txt.get_height()//2))
icon_img = icon_surf
chars_data.append({'game_img': game_img, 'icon': icon_img, 'color': color})
return chars_data
def load_boss_images():
bosses = []
BOSS_SIZE = (160, 300)
boss_colors = [(100, 0, 0), (0, 100, 0), (0, 0, 100)]
for i, filename in enumerate(BOSS_FILES):
try:
if os.path.exists(filename):
img = pygame.image.load(filename).convert_alpha()
img = pygame.transform.scale(img, BOSS_SIZE)
bosses.append(img)
else:
raise FileNotFoundError
except:
img = create_placeholder_image(boss_colors[i % len(boss_colors)], BOSS_SIZE, f"BOSS", is_boss=True)
bosses.append(img)
return bosses
def load_image_safe(filename, fallback_color, size=None):
try:
if os.path.exists(filename):
img = pygame.image.load(filename)
if size:
img = pygame.transform.scale(img, size)
else:
img = pygame.transform.scale(img, (WIDTH, HEIGHT))
return img
else:
raise FileNotFoundError
except:
surf = pygame.Surface(size if size else (WIDTH, HEIGHT))
surf.fill(fallback_color)
return surf
# --- RESURSU IELĀDE ---
CHARACTERS = load_character_images()
BOSS_IMAGES = load_boss_images()
# Menu bildes
MENU_PIC_WIDTH = 250
menupic1 = load_image_safe("menupic1.png", FALLBACK_COLORS[1], (MENU_PIC_WIDTH, HEIGHT))
menupic2 = load_image_safe("menupic2.png", FALLBACK_COLORS[0], (MENU_PIC_WIDTH, HEIGHT))
bg_images = {}
cols = {"BEACH": (194, 178, 128), "EVENINGSTREET": (30, 30, 50), "MARKET": (100, 80, 60),
"RESTAURANT": (150, 100, 50), "SAKURASTREET": (255, 183, 197), "SHIP": (0, 105, 148),
"STREETMARKETS": (90, 90, 90)}
for key, path in BG_FILES.items():
bg_images[key] = load_image_safe(path, cols.get(key, GRAY))
# --- BOOM. PNG IELĀDE ---
try:
if os.path.exists("boom.png"):
BOOM_IMG_ORIGINAL = pygame.image.load("boom.png").convert_alpha()
BOOM_IMG = pygame.transform.scale(BOOM_IMG_ORIGINAL, (80, 80))
BOOM_IMG_LARGE = pygame.transform.scale(BOOM_IMG_ORIGINAL, (160, 160))
else:
BOOM_IMG = pygame.Surface((80, 80)); BOOM_IMG.fill(YELLOW)
BOOM_IMG_LARGE = pygame.Surface((160, 160)); BOOM_IMG_LARGE.fill(ORANGE)
except:
BOOM_IMG = pygame.Surface((80, 80)); BOOM_IMG.fill(YELLOW)
BOOM_IMG_LARGE = pygame.Surface((160, 160)); BOOM_IMG_LARGE.fill(ORANGE)
# --- UI Klases ---
class Button:
def __init__(self, x, y, w, h, text, color, hover_color, action_code):
self.rect = pygame.Rect(x, y, w, h)
self.text = text
self.color = color
self.hover_color = hover_color
self.action_code = action_code
def draw(self, surface):
mouse_pos = pygame.mouse.get_pos()
is_hovered = self.rect.collidepoint(mouse_pos)
current_color = self.hover_color if is_hovered else self.color
text_surf = FONT_SMALL.render(self.text, True, current_color)
surface.blit(text_surf, (self.rect.centerx - text_surf.get_width()//2, self.rect.centery - text_surf.get_height()//2))
def is_clicked(self, event):
if event.type == pygame.MOUSEBUTTONDOWN:
if event.button == 1 and self.rect.collidepoint(event.pos):
return True
return False
# --- Palīgfunkcija Instrukciju pogām ---
def draw_key_visual(surface, x, y, w, h, key_text, action_text, color):
# Zīmē pogas rāmi
pygame.draw.rect(surface, color, (x, y, w, h), 2)
pygame.draw.rect(surface, DARK_GRAY, (x+4, y+4, w-8, h-8))
# Teksts uz pogas
txt_surf = FONT_SMALL.render(key_text, True, WHITE)
surface.blit(txt_surf, (x + w//2 - txt_surf.get_width()//2, y + 10))
# Paskaidrojums zem pogas
desc_surf = FONT_TINY.render(action_text, True, GRAY)
surface.blit(desc_surf, (x + w//2 - desc_surf.get_width()//2, y + h + 5))
# --- Klase Spēlētājam ---
class Fighter(pygame.sprite.Sprite):
def __init__(self, x, y, char_data, facing_right, controls):
super().__init__()
self.char_data = char_data
self.image = char_data['game_img']
self.color_accent = char_data['color']
self.start_x = x
self.start_y = y
self.facing_right_start = facing_right
self.rect = self.image.get_rect()
self.rect.center = (x, y)
self.rect.bottom = HEIGHT - 50
self.vel_y = 0
self.speed = 7
self.jump_power = -20
self.gravity = 0.8
self.on_ground = False
self.facing_right = facing_right
self.controls = controls
self.attacking = False
self.attack_cooldown = 0
self.attack_box = pygame.Rect(0, 0, 0, 0)
self.health = 100
self.hit_timer = 0
def reset_round(self):
self.health = 100
self.vel_y = 0
self.rect.center = (self.start_x, self.start_y)
self.rect.bottom = HEIGHT - 50
self.facing_right = self.facing_right_start
self.attacking = False
self.attack_cooldown = 0
self.hit_timer = 0
def move(self, keys):
dx = 0
if keys[self.controls['left']]:
dx = -self.speed
self.facing_right = False
if keys[self.controls['right']]:
dx = self.speed
self.facing_right = True
self.rect.x += dx
if self.rect.left < 0: self.rect.left = 0
if self.rect.right > WIDTH: self.rect.right = WIDTH
if keys[self.controls['jump']] and self.on_ground:
self.vel_y = self.jump_power
self.on_ground = False
self.vel_y += self.gravity
self.rect.y += self.vel_y
if self.rect.bottom >= HEIGHT - 50:
self.rect.bottom = HEIGHT - 50
self.vel_y = 0
self.on_ground = True
def attack(self):
if self.attack_cooldown == 0:
self.attacking = True
self.attack_cooldown = 20
if self.facing_right:
self.attack_box = pygame.Rect(self.rect.right, self.rect.y + 40, 80, 80)
else:
self.attack_box = pygame.Rect(self.rect.left - 80, self.rect.y + 40, 80, 80)
def update(self):
if self.attack_cooldown > 0: self.attack_cooldown -= 1
else: self.attacking = False
if self.hit_timer > 0: self.hit_timer -= 1
def draw(self, surface):
img_to_draw = pygame.transform.flip(self.image, not self.facing_right, False)
surface.blit(img_to_draw, self.rect)
if self.attacking:
surface.blit(BOOM_IMG, self.attack_box)
def take_damage(self, amount):
self.health -= amount
self.hit_timer = 10
self.vel_y = -5
if self.rect.centerx < WIDTH // 2: self.rect.x -= 20
else: self.rect.x += 20
# --- Klase Bossam ---
class Boss(pygame.sprite.Sprite):
def __init__(self, image):
super().__init__()
self.image = image
self.rect = self.image.get_rect()
self.rect.center = (WIDTH // 2, HEIGHT // 2)
self.rect.bottom = HEIGHT - 50
self.health = 150
self.max_health = 150
self.speed = 3
self.damage = 3
self.vel_y = 0
self.gravity = 0.8
self.on_ground = False
self.facing_right = True
self.attacking = False
self.attack_cooldown = 0
self.attack_box = pygame.Rect(0, 0, 0, 0)
self.hit_timer = 0
self.target = None
def ai_move(self, targets):
closest_dist = 99999
target = None
for t in targets:
if t.health > 0:
dist = abs(self.rect.centerx - t.rect.centerx)
if dist < closest_dist:
closest_dist = dist
target = t
if target:
self.target = target
if target.rect.centerx < self.rect.centerx:
self.rect.x -= self.speed
self.facing_right = False
else:
self.rect.x += self.speed
self.facing_right = True
if closest_dist < 180:
self.attack()
self.vel_y += self.gravity
self.rect.y += self.vel_y
if self.rect.bottom >= HEIGHT - 50:
self.rect.bottom = HEIGHT - 50
self.vel_y = 0
self.on_ground = True
def attack(self):
if self.attack_cooldown == 0:
self.attacking = True
self.attack_cooldown = 45
if self.facing_right:
self.attack_box = pygame.Rect(self.rect.right, self.rect.y + 80, 160, 160)
else:
self.attack_box = pygame.Rect(self.rect.left - 160, self.rect.y + 80, 160, 160)
def update(self):
if self.attack_cooldown > 0: self.attack_cooldown -= 1
else: self.attacking = False
if self.hit_timer > 0: self.hit_timer -= 1
def draw(self, surface):
img_to_draw = pygame.transform.flip(self.image, not self.facing_right, False)
surface.blit(img_to_draw, self.rect)
if self.attacking:
surface.blit(BOOM_IMG_LARGE, self.attack_box)
def take_damage(self, amount):
self.health -= amount
self.hit_timer = 10
if self.rect.centerx < WIDTH // 2: self.rect.x -= 5
else: self.rect.x += 5
# --- Fona Zīmēšana ---
def draw_background(surface, bg_name):
img = bg_images.get(bg_name, list(bg_images.values())[0])
surface.blit(img, (0, 0))
# --- Dialogi ---
class DialogueManager:
def __init__(self):
self.lines = ["PREPARE FOR BATTLE!", "Who will win today?", "Fight with honor!", "Show me your moves!"]
self.current_text = random.choice(self.lines)
self.active = False
self.timer = 0
def start(self, is_boss=False):
self.active = True
self.timer = pygame.time.get_ticks()
if is_boss:
self.current_text = "BOSS APPROACHING!"
else:
self.current_text = random.choice(self.lines)
def draw(self, surface):
if not self.active: return
text_surf = FONT_SMALL.render(self.current_text, True, YELLOW)
text_width = text_surf.get_width()
text_height = text_surf.get_height()
padding_x = 40
padding_y = 25
box_w = text_width + padding_x * 2
box_h = text_height + padding_y * 2
box_rect = pygame.Rect(WIDTH//2 - box_w//2, HEIGHT//2 - box_h//2, box_w, box_h)
pygame.draw.rect(surface, BLACK, box_rect)
pygame.draw.rect(surface, WHITE, box_rect, 4)
surface.blit(text_surf, (box_rect.centerx - text_width//2, box_rect.centery - text_height//2))
sub_surf = FONT_TINY.render("Nospiediet [SPACE] lai saktu", True, WHITE)
surface.blit(sub_surf, (WIDTH//2 - sub_surf.get_width()//2, box_rect.bottom + 15))
# --- Galvenā Spēle ---
def main():
global STATE, P1_CHAR_INDEX, P2_CHAR_INDEX, SELECTED_BG, GAME_MODE
controls_p1 = {'left': pygame.K_a, 'right': pygame.K_d, 'jump': pygame.K_w, 'attack': pygame.K_SPACE}
controls_p2 = {'left': pygame.K_LEFT, 'right': pygame.K_RIGHT, 'jump': pygame.K_UP, 'attack': pygame.K_RETURN}
dialogue_mgr = DialogueManager()
# Pogas (novietotas centrā, ņemot vērā malu bildes)
btn_x = WIDTH//2 - 100
menu_buttons = [
Button(btn_x, 180, 200, 50, "PvP", BLUE, RED, "START_PVP"),
Button(btn_x, 240, 200, 50, "Cina ar Bossu", PURPLE, ORANGE, "START_BOSS"),
Button(btn_x, 300, 200, 50, "Telu Izvele", BLUE, RED, "CHARS"),
Button(btn_x, 360, 200, 50, "Fona Izvele", BLUE, RED, "BG"),
Button(btn_x, 420, 200, 50, "Kontroles", GREEN, YELLOW, "INSTRUCTIONS"),
]
bg_buttons = [
Button(150, 200, 200, 50, "Beach", WHITE, YELLOW, "BEACH"),
Button(412, 200, 200, 50, "Evening St.", WHITE, YELLOW, "EVENINGSTREET"),
Button(674, 200, 200, 50, "Market", WHITE, YELLOW, "MARKET"),
Button(150, 280, 200, 50, "Restaurant", WHITE, YELLOW, "RESTAURANT"),
Button(412, 280, 200, 50, "Sakura St.", WHITE, YELLOW, "SAKURASTREET"),
Button(674, 280, 200, 50, "Ship", WHITE, YELLOW, "SHIP"),
Button(WIDTH//2 - 100, 360, 200, 50, "Street Markets", WHITE, YELLOW, "STREETMARKETS"),
Button(WIDTH//2 - 100, 450, 200, 50, "Atpakal", GRAY, WHITE, "BACK")
]
back_btn_chars = Button(WIDTH//2 - 100, HEIGHT - 80, 200, 50, "Atpakal", GRAY, WHITE, "BACK")
back_btn_inst = Button(WIDTH//2 - 100, HEIGHT - 80, 200, 50, "Atpakal", GRAY, WHITE, "BACK")
fighter1 = None
fighter2 = None
boss = None
p1_score = 0
p2_score = 0
current_round = 1
round_winner_name = ""
match_winner_name = ""
state_timer = 0
run = True
while run:
CLOCK.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if STATE == "MENU":
for btn in menu_buttons:
if btn.is_clicked(event):
if btn.action_code == "START_PVP":
GAME_MODE = "PVP"
p1_score = 0
p2_score = 0
current_round = 1
fighter1 = Fighter(200, 300, CHARACTERS[P1_CHAR_INDEX], True, controls_p1)
fighter2 = Fighter(800, 300, CHARACTERS[P2_CHAR_INDEX], False, controls_p2)
dialogue_mgr.start(is_boss=False)
STATE = "DIALOGUE"
elif btn.action_code == "START_BOSS":
GAME_MODE = "BOSS"
fighter1 = Fighter(150, 300, CHARACTERS[P1_CHAR_INDEX], True, controls_p1)
fighter2 = Fighter(300, 300, CHARACTERS[P2_CHAR_INDEX], True, controls_p2)
boss_img = random.choice(BOSS_IMAGES)
boss = Boss(boss_img)
dialogue_mgr.start(is_boss=True)
STATE = "DIALOGUE"
elif btn.action_code == "CHARS":
STATE = "CHAR_SELECT"
elif btn.action_code == "BG":
STATE = "BG_SELECT"
elif btn.action_code == "INSTRUCTIONS":
STATE = "INSTRUCTIONS"
elif STATE == "CHAR_SELECT":
icon_w = 100
gap = 10
total_w = len(CHARACTERS) * icon_w + (len(CHARACTERS)-1) * gap
start_x = (WIDTH - total_w) // 2
y_p1 = 150
for i, char in enumerate(CHARACTERS):
icon_rect = pygame.Rect(start_x + i * (icon_w + gap), y_p1, icon_w, icon_w)
if event.type == pygame.MOUSEBUTTONDOWN and icon_rect.collidepoint(event.pos):
P1_CHAR_INDEX = i
y_p2 = 350
for i, char in enumerate(CHARACTERS):
icon_rect = pygame.Rect(start_x + i * (icon_w + gap), y_p2, icon_w, icon_w)
if event.type == pygame.MOUSEBUTTONDOWN and icon_rect.collidepoint(event.pos):
P2_CHAR_INDEX = i
if back_btn_chars.is_clicked(event):
STATE = "MENU"
elif STATE == "BG_SELECT":
for btn in bg_buttons:
if btn.is_clicked(event):
if btn.action_code == "BACK":
STATE = "MENU"
else:
SELECTED_BG = btn.action_code
elif STATE == "INSTRUCTIONS":
if back_btn_inst.is_clicked(event):
STATE = "MENU"
elif STATE == "DIALOGUE":
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
dialogue_mgr.active = False
state_timer = pygame.time.get_ticks()
STATE = "ROUND_START"
elif STATE == "GAME":
if event.type == pygame.KEYDOWN:
if event.key == fighter1.controls['attack']: fighter1.attack()
if event.key == fighter2.controls['attack']: fighter2.attack()
elif STATE == "GAMEOVER":
if event.type == pygame.KEYDOWN and event.key == pygame.K_r:
STATE = "MENU"
# --- Zīmēšana un Loģika ---
if STATE == "MENU":
SCREEN.fill(BLACK)
# Zīmējam malu bildes (no augšas līdz lejai)
SCREEN.blit(menupic1, (0, 0)) # Kreisā puse
SCREEN.blit(menupic2, (WIDTH - MENU_PIC_WIDTH, 0)) # Labā puse
# Virsraksts centrā
title_text = "PIXEL KOMBAT"
shadow_text = FONT_BIG.render(title_text, True, (180, 0, 0))
SCREEN.blit(shadow_text, (WIDTH//2 - shadow_text.get_width()//2 + 3, 53))
main_text = FONT_BIG.render(title_text, True, YELLOW)
SCREEN.blit(main_text, (WIDTH//2 - main_text.get_width()//2, 50))
for btn in menu_buttons: btn.draw(SCREEN)
cp_text = "© PIXEL KOMBAT 2026"
cp_surf = FONT_TINY.render(cp_text, True, WHITE)
SCREEN.blit(cp_surf, (WIDTH//2 - cp_surf.get_width()//2, HEIGHT - 30))
elif STATE == "INSTRUCTIONS":
SCREEN.fill(BLACK)
# Virsraksts "KONTROLES" pašā augšā
title = FONT_BIG.render("KONTROLES", True, YELLOW)
SCREEN.blit(title, (WIDTH//2 - title.get_width()//2, 30))
# --- Izkārtojuma mainīgie ---
# Centri katrai kolonnai (simetriski attiecībā pret ekrāna centru)
p1_center_x = WIDTH // 2 - 200
p2_center_x = WIDTH // 2 + 200
# Y pozīcijas (palielinātas atstarpes)
title_y = 170 # Kur sākas "PLAYER X" teksts
key_row1_y = 240 # Augšējā poga (W / UP)
key_row2_y = 320 # Vidējās pogas (A,D / LEFT, RIGHT)
key_row3_y = 420 # Apakšējā poga (SPACE / ENTER)
# --- PLAYER 1 (Kreisā puse) ---
p1_title = FONT_MED.render("PLAYER 1", True, BLUE)
# Centrējam tekstu virs pogu kolonnas
SCREEN.blit(p1_title, (p1_center_x - p1_title.get_width()//2, title_y))
# W (Jump) - centrēta
draw_key_visual(SCREEN, p1_center_x - 35, key_row1_y, 70, 50, "W", "LEKT", BLUE)
# A (Left) - pa kreisi no centra
draw_key_visual(SCREEN, p1_center_x - 35 - 80, key_row2_y, 70, 50, "A", "KREISI", BLUE)
# D (Right) - pa labi no centra
draw_key_visual(SCREEN, p1_center_x - 35 + 80, key_row2_y, 70, 50, "D", "LABI", BLUE)
# SPACE (Hit) - plata poga apakšā, centrēta
space_w = 200
draw_key_visual(SCREEN, p1_center_x - space_w//2, key_row3_y, space_w, 50, "SPACE", "SIT", RED)
# --- PLAYER 2 (Labā puse) ---
p2_title = FONT_MED.render("PLAYER 2", True, RED)
# Centrējam tekstu virs pogu kolonnas
SCREEN.blit(p2_title, (p2_center_x - p2_title.get_width()//2, title_y))
# UP (Jump)
draw_key_visual(SCREEN, p2_center_x - 35, key_row1_y, 70, 50, "UP", "LEKT", RED)
# LEFT (Left)
draw_key_visual(SCREEN, p2_center_x - 35 - 80, key_row2_y, 70, 50, "LEFT", "KREISI", RED)
# RIGHT (Right)
draw_key_visual(SCREEN, p2_center_x - 35 + 80, key_row2_y, 70, 50, "RIGHT", "LABI", RED)
# ENTER (Hit)
enter_w = 150
draw_key_visual(SCREEN, p2_center_x - enter_w//2, key_row3_y, enter_w, 50, "ENTER", "SIT", BLUE)
back_btn_inst.draw(SCREEN)
elif STATE == "CHAR_SELECT":
SCREEN.fill(DARK_GRAY)
title1 = FONT_SMALL.render("IZVELIES TELU", True, WHITE)
SCREEN.blit(title1, (WIDTH//2 - title1.get_width()//2, 30))
icon_w = 100
gap = 10
total_w = len(CHARACTERS) * icon_w + (len(CHARACTERS)-1) * gap
start_x = (WIDTH - total_w) // 2
p1_text = FONT_SMALL.render("PLAYER 1", True, CHARACTERS[P1_CHAR_INDEX]['color'])
SCREEN.blit(p1_text, (WIDTH//2 - p1_text.get_width()//2, 110))
y_p1 = 150
for i, char in enumerate(CHARACTERS):
icon_rect = pygame.Rect(start_x + i * (icon_w + gap), y_p1, icon_w, icon_w)
SCREEN.blit(char['icon'], icon_rect.topleft)
border_color = WHITE if i != P1_CHAR_INDEX else YELLOW
border_width = 2 if i != P1_CHAR_INDEX else 4
pygame.draw.rect(SCREEN, border_color, icon_rect, border_width)
p2_text = FONT_SMALL.render("PLAYER 2", True, CHARACTERS[P2_CHAR_INDEX]['color'])
SCREEN.blit(p2_text, (WIDTH//2 - p2_text.get_width()//2, 300))
y_p2 = 340
for i, char in enumerate(CHARACTERS):
icon_rect = pygame.Rect(start_x + i * (icon_w + gap), y_p2, icon_w, icon_w)
SCREEN.blit(char['icon'], icon_rect.topleft)
border_color = WHITE if i != P2_CHAR_INDEX else YELLOW
border_width = 2 if i != P2_CHAR_INDEX else 4
pygame.draw.rect(SCREEN, border_color, icon_rect, border_width)
back_btn_chars.draw(SCREEN)
elif STATE == "BG_SELECT":
SCREEN.fill(BLACK)
title = FONT_MED.render("IZVELIES VIDI", True, WHITE)
SCREEN.blit(title, (WIDTH//2 - title.get_width()//2, 100))
for btn in bg_buttons:
btn.draw(SCREEN)
elif STATE == "DIALOGUE":
draw_background(SCREEN, SELECTED_BG)
dialogue_mgr.draw(SCREEN)
elif STATE == "ROUND_START":
draw_background(SCREEN, SELECTED_BG)
fighter1.draw(SCREEN)
fighter2.draw(SCREEN)
if GAME_MODE == "BOSS" and boss:
boss.draw(SCREEN)
if GAME_MODE == "BOSS" and boss:
pygame.draw.rect(SCREEN, BLACK, (WIDTH//2 - 302, 18, 604, 34))
pygame.draw.rect(SCREEN, RED, (WIDTH//2 - 300, 20, 600, 30))
w = (boss.health / boss.max_health) * 600
pygame.draw.rect(SCREEN, PURPLE, (WIDTH//2 - 300, 20, w, 30))
pygame.draw.rect(SCREEN, WHITE, (WIDTH//2 - 300, 20, 600, 30), 2)
else:
pygame.draw.rect(SCREEN, BLACK, (20, 20, 400, 40))
pygame.draw.rect(SCREEN, fighter1.color_accent, (20, 20, 400, 40))
pygame.draw.rect(SCREEN, WHITE, (20, 20, 400, 40), 2)
pygame.draw.rect(SCREEN, BLACK, (WIDTH-420, 20, 400, 40))
pygame.draw.rect(SCREEN, fighter2.color_accent, (WIDTH-420, 20, 400, 40))
pygame.draw.rect(SCREEN, WHITE, (WIDTH-420, 20, 400, 40), 2)
elapsed = pygame.time.get_ticks() - state_timer
if elapsed < 1500:
txt = FONT_MED.render(f"ROUND {current_round}" if GAME_MODE == "PVP" else "BOSS FIGHT", True, YELLOW)
SCREEN.blit(txt, (WIDTH//2 - txt.get_width()//2, HEIGHT//2 - 50))
elif elapsed < 3000:
txt = FONT_BIG.render("FIGHT!", True, WHITE)
offset_x = random.randint(-2, 2)
offset_y = random.randint(-2, 2)
SCREEN.blit(txt, (WIDTH//2 - txt.get_width()//2 + offset_x, HEIGHT//2 - 50 + offset_y))
else:
STATE = "GAME"
elif STATE == "GAME":
keys = pygame.key.get_pressed()
fighter1.move(keys)
fighter2.move(keys)
fighter1.update()
fighter2.update()
if GAME_MODE == "PVP":
if fighter1.attacking and fighter1.attack_box.colliderect(fighter2.rect):
if fighter2.hit_timer == 0: fighter2.take_damage(5)
if fighter2.attacking and fighter2.attack_box.colliderect(fighter1.rect):
if fighter1.hit_timer == 0: fighter1.take_damage(5)
if fighter1.health <= 0 or fighter2.health <= 0:
if fighter2.health <= 0:
p1_score += 1
round_winner_name = "PLAYER 1"
else:
p2_score += 1
round_winner_name = "PLAYER 2"
state_timer = pygame.time.get_ticks()
STATE = "ROUND_OVER"
elif GAME_MODE == "BOSS" and boss:
targets = [fighter1, fighter2]
boss.ai_move(targets)
boss.update()
if fighter1.attacking and fighter1.attack_box.colliderect(boss.rect):
if boss.hit_timer == 0: boss.take_damage(5)
if fighter2.attacking and fighter2.attack_box.colliderect(boss.rect):
if boss.hit_timer == 0: boss.take_damage(5)
if boss.attacking:
if boss.attack_box.colliderect(fighter1.rect):
if fighter1.hit_timer == 0: fighter1.take_damage(boss.damage)
if boss.attack_box.colliderect(fighter2.rect):
if fighter2.hit_timer == 0: fighter2.take_damage(boss.damage)
if boss.health <= 0:
match_winner_name = "PLAYERS"
save_highscore("Players (Team)")
STATE = "GAMEOVER"
if fighter1.health <= 0 and fighter2.health <= 0:
match_winner_name = "BOSS"
STATE = "GAMEOVER"
draw_background(SCREEN, SELECTED_BG)
fighter1.draw(SCREEN)
fighter2.draw(SCREEN)
if GAME_MODE == "BOSS" and boss:
boss.draw(SCREEN)
if GAME_MODE == "BOSS" and boss:
pygame.draw.rect(SCREEN, BLACK, (WIDTH//2 - 302, 18, 604, 34))
pygame.draw.rect(SCREEN, RED, (WIDTH//2 - 300, 20, 600, 30))
w = (boss.health / boss.max_health) * 600
pygame.draw.rect(SCREEN, PURPLE, (WIDTH//2 - 300, 20, w, 30))
pygame.draw.rect(SCREEN, WHITE, (WIDTH//2 - 300, 20, 600, 30), 2)
pygame.draw.rect(SCREEN, BLACK, (20, HEIGHT - 60, 200, 20))
pygame.draw.rect(SCREEN, fighter1.color_accent, (20, HEIGHT - 60, (fighter1.health/100)*200, 20))
pygame.draw.rect(SCREEN, WHITE, (20, HEIGHT - 60, 200, 20), 2)
pygame.draw.rect(SCREEN, BLACK, (WIDTH-220, HEIGHT - 60, 200, 20))
pygame.draw.rect(SCREEN, fighter2.color_accent, (WIDTH-220, HEIGHT - 60, (fighter2.health/100)*200, 20))
pygame.draw.rect(SCREEN, WHITE, (WIDTH-220, HEIGHT - 60, 200, 20), 2)
else:
pygame.draw.rect(SCREEN, BLACK, (20, 20, 400, 40))
pygame.draw.rect(SCREEN, RED, (20, 20, 400, 40))
pygame.draw.rect(SCREEN, fighter1.color_accent, (20, 20, (fighter1.health/100)*400, 40))
pygame.draw.rect(SCREEN, WHITE, (20, 20, 400, 40), 2)
pygame.draw.rect(SCREEN, BLACK, (WIDTH-420, 20, 400, 40))
pygame.draw.rect(SCREEN, RED, (WIDTH-420, 20, 400, 40))
pygame.draw.rect(SCREEN, fighter2.color_accent, (WIDTH-420, 20, (fighter2.health/100)*400, 40))
pygame.draw.rect(SCREEN, WHITE, (WIDTH-420, 20, 400, 40), 2)
score_text = FONT_MED.render(f"{p1_score} - {p2_score}", True, WHITE)
SCREEN.blit(score_text, (WIDTH//2 - score_text.get_width()//2, 25))
elif STATE == "ROUND_OVER":
draw_background(SCREEN, SELECTED_BG)
fighter1.draw(SCREEN)
fighter2.draw(SCREEN)
pygame.draw.rect(SCREEN, BLACK, (20, 20, 400, 40))
pygame.draw.rect(SCREEN, fighter1.color_accent, (20, 20, 400, 40))
pygame.draw.rect(SCREEN, WHITE, (20, 20, 400, 40), 2)
pygame.draw.rect(SCREEN, BLACK, (WIDTH-420, 20, 400, 40))
pygame.draw.rect(SCREEN, fighter2.color_accent, (WIDTH-420, 20, 400, 40))
pygame.draw.rect(SCREEN, WHITE, (WIDTH-420, 20, 400, 40), 2)
score_text = FONT_MED.render(f"{p1_score} - {p2_score}", True, WHITE)
SCREEN.blit(score_text, (WIDTH//2 - score_text.get_width()//2, 25))
txt1 = FONT_MED.render(f"{round_winner_name} WINS!", True, YELLOW)
SCREEN.blit(txt1, (WIDTH//2 - txt1.get_width()//2, HEIGHT//2 - 50))
elapsed = pygame.time.get_ticks() - state_timer
if elapsed > 2000:
if p1_score == 3 or p2_score == 3:
match_winner_name = "PLAYER 1" if p1_score == 3 else "PLAYER 2"
save_highscore(match_winner_name)
STATE = "GAMEOVER"
else:
current_round += 1
fighter1.reset_round()
fighter2.reset_round()
state_timer = pygame.time.get_ticks()
STATE = "ROUND_START"
elif STATE == "GAMEOVER":
SCREEN.fill(BLACK)
if GAME_MODE == "BOSS":
if match_winner_name == "PLAYERS":
txt = FONT_BIG.render("PLAYERS WIN!", True, GREEN)
else:
txt = FONT_BIG.render("PLAYERS LOSE!", True, RED)
SCREEN.blit(txt, (WIDTH//2 - txt.get_width()//2, 150))
else:
txt = FONT_BIG.render(f"{match_winner_name} WINS!", True, YELLOW)
SCREEN.blit(txt, (WIDTH//2 - txt.get_width()//2, 100))
hs_title = FONT_MED.render("HIGH SCORES", True, WHITE)
SCREEN.blit(hs_title, (WIDTH//2 - hs_title.get_width()//2, 200))
scores = load_highscores()
scores.reverse()
y_offset = 260
for i, score in enumerate(scores[:5]):
if score == match_winner_name:
color = YELLOW
else:
color = WHITE
s_text = FONT_SMALL.render(f"{i+1}. {score}", True, color)
SCREEN.blit(s_text, (WIDTH//2 - s_text.get_width()//2, y_offset))
y_offset += 35
restart = FONT_SMALL.render("Nospied [R] atgriezties uz izvelni", True, GRAY)
SCREEN.blit(restart, (WIDTH//2 - restart.get_width()//2, HEIGHT - 80))
pygame.display.update()
pygame.quit()
sys.exit()
if __name__ == "__main__":
main()