Update combat_system.py

main
Filips Kalniņš 2026-03-16 07:44:22 +00:00
parent f8b22aa8e9
commit 869d2ea540
1 changed files with 58 additions and 456 deletions

View File

@ -1,459 +1,61 @@
import pygame # combat_system.py
import random
from settings import * from settings import *
from items import get_item, ITEMS, WEAPON_STATS
from world import World
from player import Player class CombatSystem:
from camera import Camera def __init__(self, weapon_manager):
from inventory import Inventory self.weapon_manager = weapon_manager
from enemy_manager import EnemyManager
from menu_system import MainMenu, PauseMenu, NewGameDialog, LoadGameDialog, SettingsMenu, DeathScreen def player_attack(self, player, enemies):
from save_system import SaveSystem """
from weapon_system import WeaponManager Handles player attack on enemies using the currently equipped weapon.
from combat_system import CombatSystem """
from hotbar import Hotbar # Get weapon ID from weapon manager
from items import get_item weapon_id = self.weapon_manager.get_current_weapon()
if weapon_id is None:
print("DEBUG: No weapon equipped")
class Game: return
def __init__(self):
pygame.init() # Get weapon stats
damage = WEAPON_STATS.get(weapon_id, {}).get("damage", 1)
# ---------------------------------- attack_range = WEAPON_STATS.get(weapon_id, {}).get("range", 50)
# Display Setup
# ---------------------------------- player_pos = player.pos
self.setup_display()
# Attack enemies within range
self.clock = pygame.time.Clock() for enemy in enemies:
self.running = True if not getattr(enemy, "alive", True):
self.paused = False continue # Skip dead enemies
# ---------------------------------- enemy_pos = enemy.pos
# Game State Management distance = (enemy_pos - player_pos).length()
# ---------------------------------- if distance <= attack_range:
self.game_state = "menu" enemy.health -= damage
self.show_inventory = False print(f"DEBUG: {enemy.name if hasattr(enemy,'name') else 'Enemy'} took {damage} damage! (HP left: {enemy.health})")
self.world_name = "Default" if enemy.health <= 0:
enemy.alive = False
# ---------------------------------- print(f"DEBUG: {enemy.name if hasattr(enemy,'name') else 'Enemy'} has been defeated!")
# Menu Systems
# ---------------------------------- def enemy_attack(self, enemy, player):
self.main_menu = MainMenu(self) """
self.new_game_dialog = None Handles enemy attack on player.
self.load_game_dialog = None """
self.pause_menu = None if not getattr(enemy, "alive", True):
self.settings_menu = None return
self.death_screen = None
self.save_system = SaveSystem() # Ensure enemy has attack properties
attack_range = getattr(enemy, "attack_range", 50)
# ---------------------------------- attack_damage = getattr(enemy, "attack_damage", ENEMY_ATTACK_DAMAGE)
# Core Systems (initialized as None)
# ---------------------------------- distance = (enemy.pos - player.pos).length()
self.world = None if distance <= attack_range:
self.player = None player.health -= attack_damage
self.camera = None print(f"DEBUG: Player took {attack_damage} damage! (HP left: {player.health})")
self.inventory = None
self.enemy_manager = None
self.weapon_manager = None
self.combat_system = None
self.hotbar = None
# ----------------------------------
# Debug
# ----------------------------------
self.font = pygame.font.SysFont("consolas", 18)
def setup_display(self):
"""Setup display with current resolution and fullscreen setting"""
flags = pygame.SCALED
if FULLSCREEN:
flags |= pygame.FULLSCREEN
self.screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), flags)
pygame.display.set_caption(GAME_TITLE)
def toggle_fullscreen(self):
"""Toggle fullscreen mode"""
global FULLSCREEN
FULLSCREEN = not FULLSCREEN
self.setup_display()
def init_game(self):
"""Initialize game systems (called when starting new game or loading)"""
self.world = World()
self.weapon_manager = WeaponManager()
self.player = Player(100, 100, self.weapon_manager)
self.camera = Camera(self.player)
self.inventory = Inventory()
self.hotbar = Hotbar(self.inventory, self.weapon_manager)
self.enemy_manager = EnemyManager(self.world, self.player)
self.combat_system = CombatSystem(self.weapon_manager)
self.show_inventory = False
# Add starting items and WEAPONS
self.inventory.add_item(ITEM_WOOD, 10)
self.inventory.add_item(ITEM_STONE, 5)
# Add all weapons to inventory
self.inventory.add_item(ITEM_WOODEN_SWORD, 1)
self.inventory.add_item(ITEM_IRON_SWORD, 1)
self.inventory.add_item(ITEM_GOLD_SWORD, 1)
# Add weapons to weapon manager
self.weapon_manager.add_weapon(ITEM_WOODEN_SWORD)
self.weapon_manager.add_weapon(ITEM_IRON_SWORD)
self.weapon_manager.add_weapon(ITEM_GOLD_SWORD)
# ==========================================================
# MAIN LOOP
# ==========================================================
def run(self):
while self.running:
dt = self.clock.tick(FPS) / 1000
if self.game_state == "menu":
self.handle_menu_events()
self.update_menu()
self.draw_menu()
elif self.game_state == "settings":
self.handle_settings_events()
self.settings_menu.update(dt)
self.settings_menu.draw(self.screen)
elif self.game_state == "new_game_dialog":
self.handle_new_game_dialog_events()
self.new_game_dialog.update(dt)
self.new_game_dialog.draw(self.screen)
elif self.game_state == "load_game_dialog":
self.handle_load_game_dialog_events()
self.load_game_dialog.update()
self.load_game_dialog.draw(self.screen)
elif self.game_state == "playing":
self.handle_events()
if not self.paused:
self.update(dt)
self.draw()
elif self.game_state == "paused":
self.handle_pause_events()
self.pause_menu.update(dt)
self.draw_paused()
elif self.game_state == "dead":
self.handle_death_events()
self.death_screen.update(dt)
self.draw_dead()
pygame.quit()
# ==========================================================
# MAIN MENU STATE
# ==========================================================
def handle_menu_events(self):
action = self.main_menu.handle_events()
if action == "new_game":
self.new_game_dialog = NewGameDialog(self)
self.game_state = "new_game_dialog"
elif action == "load_game":
self.load_game_dialog = LoadGameDialog(self, self.save_system)
self.game_state = "load_game_dialog"
elif action == "settings":
self.settings_menu = SettingsMenu(self)
self.game_state = "settings"
elif action == "quit":
self.running = False
def update_menu(self):
self.main_menu.update()
def draw_menu(self):
self.main_menu.draw(self.screen)
# ==========================================================
# SETTINGS STATE
# ==========================================================
def handle_settings_events(self):
action = self.settings_menu.handle_events()
if action == "back":
self.game_state = "menu"
# ==========================================================
# NEW GAME DIALOG STATE
# ==========================================================
def handle_new_game_dialog_events(self):
action = self.new_game_dialog.handle_events()
if action and action.startswith("create:"):
world_name = action.replace("create:", "")
self.world_name = world_name
self.init_game()
self.game_state = "playing"
print(f"New game '{world_name}' started")
elif action == "cancel":
self.game_state = "menu"
# ==========================================================
# LOAD GAME DIALOG STATE
# ==========================================================
def handle_load_game_dialog_events(self):
action = self.load_game_dialog.handle_events()
if action and action.startswith("load:"):
save_index = int(action.replace("load:", ""))
saves = self.save_system.get_save_files()
if 0 <= save_index < len(saves):
save_file = saves[save_index]["name"]
self.init_game()
if self.save_system.load_game(self, save_file):
self.game_state = "playing"
print(f"Game loaded: {save_file}")
else:
print("Failed to load game")
self.game_state = "load_game_dialog"
elif action and action.startswith("delete:"):
save_index = int(action.replace("delete:", ""))
saves = self.save_system.get_save_files()
if 0 <= save_index < len(saves):
save_file = saves[save_index]["name"]
self.save_system.delete_save(save_file)
self.load_game_dialog = LoadGameDialog(self, self.save_system)
elif action == "cancel":
self.game_state = "menu"
# ==========================================================
# PAUSE STATE
# ==========================================================
def handle_pause_events(self):
action = self.pause_menu.handle_events()
if action == "resume":
self.paused = False
self.game_state = "playing"
elif action == "save":
self.save_system.save_game(self, self.world_name)
self.pause_menu.show_message("Game saved!")
elif action == "backup":
self.save_system.backup_game(self)
self.pause_menu.show_message("Backup created!")
elif action == "quit_to_menu":
self.paused = False
self.game_state = "menu"
def draw_paused(self):
self.screen.fill(BACKGROUND_COLOR)
self.world.draw(self.screen, self.camera)
self.enemy_manager.draw(self.screen, self.camera)
self.player.draw(self.screen, self.camera)
self.pause_menu.draw(self.screen)
# ==========================================================
# DEATH STATE
# ==========================================================
def handle_death_events(self):
action = self.death_screen.handle_events()
if action == "respawn":
# Reset player health and position
self.player.health = self.player.max_health
self.player.pos = pygame.Vector2(100, 100)
self.player.rect.x = 100
self.player.rect.y = 100
self.player.velocity = pygame.Vector2(0, 0)
self.game_state = "playing"
elif action == "quit_to_menu":
self.game_state = "menu"
def draw_dead(self):
self.screen.fill(BACKGROUND_COLOR)
self.world.draw(self.screen, self.camera)
self.enemy_manager.draw(self.screen, self.camera)
self.player.draw(self.screen, self.camera)
self.death_screen.draw(self.screen)
# ==========================================================
# GAMEPLAY STATE
# ==========================================================
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
self.running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
self.paused = True
self.pause_menu = PauseMenu(self)
self.game_state = "paused"
# Toggle inventory
if event.key == pygame.K_i:
self.show_inventory = not self.show_inventory
# Hotbar input
if self.hotbar:
self.hotbar.handle_input(event)
# Mouse input for attacking and placing
if event.type == pygame.MOUSEBUTTONDOWN:
if self.show_inventory:
continue
if event.button == 1: # Left click
# Get current held item
items_list = list(self.inventory.slots.items())
current_item = None
if self.hotbar.selected_slot < len(items_list):
current_item_id, _ = items_list[self.hotbar.selected_slot]
current_item = get_item(current_item_id)
# Check if holding a weapon
is_holding_weapon = (current_item is not None and
current_item.id in WEAPON_STATS)
if is_holding_weapon:
# Attack with sword
print(f"DEBUG: Attempting sword attack with {current_item.name}")
self.combat_system.player_attack(self.player, self.enemy_manager.enemies)
else:
# Mine block if not holding weapon
print("DEBUG: Mining block")
self.world.break_block(
pygame.mouse.get_pos(),
self.camera,
self.inventory,
self.player.rect
)
if event.button == 3: # Right click - place block
# Get current held item
items_list = list(self.inventory.slots.items())
if self.hotbar.selected_slot < len(items_list):
current_item_id, _ = items_list[self.hotbar.selected_slot]
current_item = get_item(current_item_id)
# Only place if it's placeable
if current_item and current_item.placeable:
print(f"DEBUG: Placing {current_item.name}")
self.world.place_block(
pygame.mouse.get_pos(),
self.camera,
self.player.rect,
current_item.place_tile
)
def update(self, dt): def update(self, dt):
if self.show_inventory: """
return Updates combat-related state per frame.
Currently placeholder for cooldowns or status effects.
self.player.update(dt, self.world) """
self.camera.update() pass
self.enemy_manager.update(dt)
self.combat_system.update(dt)
# Check if player is dead
if self.player.health <= 0:
self.death_screen = DeathScreen(self)
self.game_state = "dead"
return
# Enemy AI - attack player
for enemy in self.enemy_manager.enemies:
self.combat_system.enemy_attack(enemy, self.player)
def draw(self):
self.screen.fill(BACKGROUND_COLOR)
# Draw world relative to camera
self.world.draw(self.screen, self.camera)
# Draw entities
self.enemy_manager.draw(self.screen, self.camera)
self.player.draw(self.screen, self.camera)
# UI
if self.show_inventory:
self.inventory.draw(self.screen)
# Draw hotbar
if self.hotbar and not self.show_inventory:
self.hotbar.draw(self.screen)
self.draw_ui()
pygame.display.flip()
# ==========================================================
# UI / DEBUG
# ==========================================================
def draw_ui(self):
if SHOW_FPS:
fps = self.clock.get_fps()
fps_text = self.font.render(f"FPS: {int(fps)}", True, (255, 255, 255))
self.screen.blit(fps_text, (10, 10))
if DEBUG_MODE:
debug_text = self.font.render(
f"Player: ({int(self.player.rect.x)}, {int(self.player.rect.y)})",
True,
(255, 255, 255)
)
self.screen.blit(debug_text, (10, 30))
world_name_text = self.font.render(
f"World: {self.world_name}",
True,
(255, 255, 255)
)
self.screen.blit(world_name_text, (10, 50))
weapon = self.weapon_manager.get_current_weapon()
if weapon:
weapon_text = self.font.render(
f"Weapon: {weapon.name}",
True,
(255, 255, 255)
)
self.screen.blit(weapon_text, (10, 70))
# Health display
health_text = self.font.render(
f"Health: {int(self.player.health)}/{int(self.player.max_health)}",
True,
(255, 50, 50)
)
self.screen.blit(health_text, (10, 90))
# Enemy count
enemy_text = self.font.render(
f"Enemies: {len(self.enemy_manager.enemies)}",
True,
(255, 100, 100)
)
self.screen.blit(enemy_text, (10, 110))
# Draw currently holding item (top right)
items_list = list(self.inventory.slots.items())
if self.hotbar and items_list:
current_item_id, current_amount = items_list[self.hotbar.selected_slot] if self.hotbar.selected_slot < len(
items_list) else (None, 0)
if current_item_id:
item = get_item(current_item_id)
if item:
holding_text = self.font.render(f"Holding: {item.name}", True, (255, 255, 255))
self.screen.blit(holding_text, (SCREEN_WIDTH - 250, 10))