McRogueFace/roguelike_tutorial/README_PART_06.md

5.5 KiB

Part 6: Doing (and Taking) Damage

Overview

Part 6 transforms our basic combat into a complete gameplay loop with visual feedback, enemy AI, and win/lose conditions. We add a health bar, message log, enemy AI that pursues the player, and proper game over handling.

What's New in Part 6

User Interface Components

Health Bar

A visual representation of the player's current health:

class HealthBar:
    def create_ui(self) -> List[mcrfpy.UIDrawable]:
        # Dark red background
        self.background = mcrfpy.Frame(pos=(x, y), size=(width, height))
        self.background.fill_color = mcrfpy.Color(100, 0, 0, 255)
        
        # Bright colored bar (green/yellow/red based on HP)
        self.bar = mcrfpy.Frame(pos=(x, y), size=(width, height))
        
        # Text overlay showing HP numbers
        self.text = mcrfpy.Caption(pos=(x+5, y+2), 
                                   text=f"HP: {hp}/{max_hp}")

The bar changes color based on health percentage:

  • Green (>60% health)
  • Yellow (30-60% health)
  • Red (<30% health)

Message Log

A scrolling combat log that replaces console print statements:

class MessageLog:
    def __init__(self, max_messages: int = 5):
        self.messages: deque[str] = deque(maxlen=max_messages)
    
    def add_message(self, message: str) -> None:
        self.messages.append(message)
        self.update_display()

Messages include:

  • Combat actions ("Rat attacks Player for 3 hit points.")
  • Death notifications ("Spider is dead!")
  • Game state changes ("You have died! Press Escape to quit.")

Enemy AI System

Basic AI Component

Enemies now actively pursue and attack the player:

class BasicAI:
    def take_turn(self, engine: Engine) -> None:
        distance = max(abs(dx), abs(dy))  # Chebyshev distance
        
        if distance <= 1:
            # Adjacent: Attack!
            MeleeAction(self.entity, attack_dx, attack_dy).perform(engine)
        elif distance <= 6:
            # Can see player: Move closer
            MovementAction(self.entity, move_dx, move_dy).perform(engine)

Turn-Based System

After each player action, all enemies take their turn:

def handle_enemy_turns(self) -> None:
    for entity in self.game_map.entities:
        if isinstance(entity, Actor) and entity.ai and entity.is_alive:
            entity.ai.take_turn(self)

Game Over Condition

When the player dies:

  1. Game state flag is set (engine.game_over = True)
  2. Player becomes a gravestone (sprite changes)
  3. Input is restricted (only Escape works)
  4. Death message appears in the message log
def handle_player_death(self) -> None:
    self.game_over = True
    self.message_log.add_message("You have died! Press Escape to quit.")

Architecture Improvements

UI Module (game/ui.py)

Separates UI concerns from game logic:

  • MessageLog: Manages combat messages
  • HealthBar: Displays player health
  • Clean interface for updating displays

AI Module (game/ai.py)

Encapsulates enemy behavior:

  • BasicAI: Simple pursue-and-attack behavior
  • Extensible for different AI types
  • Uses existing action system

Turn Management

Player actions trigger enemy turns:

  • Movement → Enemy turns
  • Attack → Enemy turns
  • Wait → Enemy turns
  • Maintains turn-based feel

Key Implementation Details

UI Updates

Health bar updates occur:

  • After player takes damage
  • Automatically via engine.update_ui()
  • Color changes based on HP percentage

Message Flow

Combat messages follow this pattern:

  1. Action generates message text
  2. engine.message_log.add_message(text)
  3. Message appears in UI Caption
  4. Old messages scroll up

AI Decision Making

Basic AI uses simple rules:

  1. Check if player is adjacent → Attack
  2. Check if player is visible (within 6 tiles) → Move toward
  3. Otherwise → Do nothing

Game State Management

The game_over flag prevents:

  • Player movement
  • Player attacks
  • Player waiting
  • But allows Escape to quit

Files Modified

  • game/ui.py: New module for UI components
  • game/ai.py: New module for enemy AI
  • game/engine.py: Added UI setup, enemy turns, game over handling
  • game/entity.py: Added AI component to Actor
  • game/entity_factories.py: Attached AI to enemies
  • game/actions.py: Integrated message log, added enemy turn triggers
  • main.py: Updated part description

What's Next

Part 7 will expand the user interface further with:

  • More detailed entity inspection
  • Possibly inventory display
  • Additional UI panels
  • Mouse interaction

Learning Points

  1. UI Separation: Keep UI logic separate from game logic
  2. Component Systems: AI as a component allows different behaviors
  3. Turn-Based Flow: Player action → Enemy reactions creates tactical gameplay
  4. Visual Feedback: Health bars and message logs improve player understanding
  5. State Management: Game over flag controls available actions

Running Part 6

cd simple_tcod_tutorial/build
./mcrogueface scripts/main.py

You'll now see:

  • Health bar at the top showing your current HP
  • Message log at the bottom showing combat events
  • Enemies that chase you when you're nearby
  • Enemies that attack when adjacent
  • Death state when HP reaches 0

Combat Strategy

With enemy AI active, combat becomes more tactical:

  • Enemies pursue when they see you
  • Fighting in corridors limits how many can attack
  • Running away is sometimes the best option
  • Health management becomes critical

The game now has a complete combat loop with clear win/lose conditions!