"""Villager entity class."""
from .base_entity import BaseEntity
import pygame
import random
from ..utils.constants import *
from ..utils.asset_loader import AssetLoader # Import AssetLoader
[docs]
class Villager(BaseEntity):
"""Represents a villager entity in the game."""
def __init__(self, x, y):
[docs]
self.size = random.uniform(0.9, 1.1) # Add size variation like in Pig
# Use AssetLoader to load the sprite from a file
[docs]
self.asset_loader = AssetLoader()
[docs]
self.sprite = self._load_villager_sprite()
def _load_villager_sprite(self):
"""Load villager sprite from assets."""
# Load the base image for the villager
base_sprite = self.asset_loader.load_image("farmera1.png")
# Scale the sprite based on size variation, similar to the pig
sprite_size = int(32 * self.size) # Assuming a base size of 32x32
scaled_sprite = pygame.transform.scale(base_sprite, (sprite_size, sprite_size))
return scaled_sprite
def _create_villager_sprite(self):
"""Create a simple villager sprite as fallback."""
surface = pygame.Surface((20, 20), pygame.SRCALPHA)
# Draw body
pygame.draw.ellipse(surface, (139, 69, 19), (6, 8, 8, 12))
# Draw head
pygame.draw.circle(surface, (222, 184, 135), (10, 6), 4)
# Draw eyes
pygame.draw.circle(surface, (0, 0, 0), (8, 5), 1)
pygame.draw.circle(surface, (0, 0, 0), (12, 5), 1)
# Draw tool (simple axe)
pygame.draw.line(surface, (139, 69, 19), (15, 8), (18, 12), 2)
pygame.draw.polygon(surface, (192, 192, 192), [(17, 11), (19, 9), (19, 13)])
return surface
[docs]
def update(self, dt, isometric_map):
"""Update villager behavior."""
# Movement behavior
self.move_timer -= dt
if self.move_timer <= 0:
# Choose new target near forest
self._choose_forest_target(isometric_map)
self.move_timer = random.uniform(3, 6)
# Move towards target
self._step_towards_target(dt, VILLAGER_MOVE_SPEED)
# Working behavior
self.work_timer -= dt
if self.work_timer <= 0:
self._chop_trees(isometric_map)
self.work_timer = random.uniform(2, 4)
def _choose_forest_target(self, isometric_map):
"""Choose a forest target, preferring less degraded tiles."""
candidates = []
for _ in range(20):
new_x = random.randint(0, isometric_map.width - 1)
new_y = random.randint(0, isometric_map.height - 1)
if (isometric_map.is_valid_position(new_x, new_y) and
isometric_map.get_tile_type(new_x, new_y) in FOREST_TILES):
degradation = isometric_map.get_degradation(new_x, new_y)
candidates.append((degradation, new_x, new_y))
if candidates:
_, self.target_x, self.target_y = min(candidates)
def _chop_trees(self, isometric_map):
"""Chop trees and cause degradation."""
tile_x, tile_y = int(self.x), int(self.y)
# Work in radius around villager
for dx in range(-VILLAGER_CHOPPING_RADIUS, VILLAGER_CHOPPING_RADIUS + 1):
for dy in range(-VILLAGER_CHOPPING_RADIUS, VILLAGER_CHOPPING_RADIUS + 1):
chop_x, chop_y = tile_x + dx, tile_y + dy
if isometric_map.is_valid_position(chop_x, chop_y):
tile_type = isometric_map.get_tile_type(chop_x, chop_y)
if tile_type in FOREST_TILES:
# Add degradation
isometric_map.add_degradation(chop_x, chop_y, 0.02)
[docs]
def render(self, screen, isometric_map):
"""Render the villager."""
screen_x, screen_y = self.get_screen_position(isometric_map)
# Render sprite
sprite_rect = self.sprite.get_rect()
sprite_rect.center = (screen_x, screen_y - 10)
screen.blit(self.sprite, sprite_rect)
# Render working indicator
if self.work_timer > 3:
# Show working indicator
pygame.draw.circle(screen, (255, 255, 0), (screen_x, screen_y - 25), 3)