5.2 KiB
		
	
	
	
	
	
			
		
		
	
	Part 5: Placing Enemies and Fighting Them
Overview
Part 5 brings our dungeon to life with enemies! We add rats and spiders that populate the rooms, implement a combat system with melee attacks, and handle entity death by turning creatures into gravestones.
What's New in Part 5
Actor System
- Actor Class: Extends Entity with combat stats (HP, defense, power)
 - Combat Properties: Health tracking, damage calculation, alive status
 - Death Handling: Entities become gravestones when killed
 
Enemy Types
Using our sprite sheet, we have two enemy types:
- Rat (sprite 5): 10 HP, 0 defense, 3 power - Common enemy
 - Spider (sprite 4): 16 HP, 1 defense, 4 power - Tougher enemy
 
Combat System
Bump-to-Attack
When the player tries to move into an enemy:
# In MovementAction.perform()
target = engine.game_map.get_blocking_entity_at(dest_x, dest_y)
if target:
    if self.entity == engine.player:
        from game.entity import Actor
        if isinstance(target, Actor) and target != engine.player:
            return MeleeAction(self.entity, self.dx, self.dy).perform(engine)
Damage Calculation
Simple formula with defense reduction:
damage = attacker.power - target.defense
Death System
Dead entities become gravestones:
def die(self) -> None:
    """Handle death by becoming a gravestone."""
    self.sprite_index = 6  # Tombstone sprite
    self.blocks_movement = False
    self.name = f"Grave of {self.name}"
Entity Factories
Factory functions create pre-configured entities:
def rat(x: int, y: int, texture: mcrfpy.Texture) -> Actor:
    return Actor(
        x=x, y=y,
        sprite_id=5,  # Rat sprite
        texture=texture,
        name="Rat",
        hp=10, defense=0, power=3,
    )
Dungeon Population
Enemies are placed randomly in rooms:
def place_entities(room, dungeon, max_monsters, texture):
    number_of_monsters = random.randint(0, max_monsters)
    
    for _ in range(number_of_monsters):
        x = random.randint(room.x1 + 1, room.x2 - 1)
        y = random.randint(room.y1 + 1, room.y2 - 1)
        
        if not any(entity.x == x and entity.y == y for entity in dungeon.entities):
            # 80% rats, 20% spiders
            if random.random() < 0.8:
                monster = entity_factories.rat(x, y, texture)
            else:
                monster = entity_factories.spider(x, y, texture)
            monster.place(x, y, dungeon)
Key Implementation Details
FOV and Enemy Visibility
Enemies are automatically shown/hidden by the FOV system:
def update_fov(self) -> None:
    # Update visibility for all entities
    for entity in self.game_map.entities:
        entity.update_visibility()
Action System Extension
The action system now handles combat:
- MovementAction: Detects collision, triggers attack
 - MeleeAction: New action for melee combat
 - Actions remain decoupled from entity logic
 
Gravestone System
Instead of removing dead entities:
- Sprite changes to tombstone (index 6)
 - Name changes to "Grave of [Name]"
 - No longer blocks movement
 - Remains visible as dungeon decoration
 
Architecture Notes
Why Actor Extends Entity?
- Maintains entity hierarchy
 - Combat stats only for creatures
 - Future items/decorations won't have HP
 - Clean separation of concerns
 
Why Factory Functions?
- Centralized entity configuration
 - Easy to add new enemy types
 - Consistent stat management
 - Type-safe entity creation
 
Combat in Actions
Combat logic lives in actions, not entities:
- Entities store stats
 - Actions perform combat
 - Clean separation of data and behavior
 - Extensible for future combat types
 
Files Modified
game/entity.py: Added Actor class with combat stats and death handlinggame/entity_factories.py: New module with entity creation functionsgame/actions.py: Added MeleeAction for combatgame/procgen.py: Added enemy placement in roomsgame/engine.py: Updated to use Actor type and handle all entity visibilitymain.py: Updated to use entity factories and Part 5 description
What's Next
Part 6 will enhance the combat experience with:
- Health display UI
 - Game over conditions
 - Combat messages window
 - More strategic combat mechanics
 
Learning Points
- Entity Specialization: Use inheritance to add features to specific entity types
 - Factory Pattern: Centralize object creation for consistency
 - State Transformation: Dead entities become decorations, not deletions
 - Action Extensions: Combat fits naturally into the action system
 - Automatic Systems: FOV handles entity visibility without special code
 
Running Part 5
cd simple_tcod_tutorial/build
./mcrogueface scripts/main.py
You'll now encounter rats and spiders as you explore! Walk into them to attack. Dead enemies become gravestones that mark your battles.
Sprite Adaptations
Following our sprite sheet (sprite_sheet.md), we made these thematic changes:
- Orcs → Rats (same stats, different sprite)
 - Trolls → Spiders (same stats, different sprite)
 - Corpses → Gravestones (all use same tombstone sprite)
 
The gameplay remains identical to the TCOD tutorial, just with different visual theming.