Source code for game.entities.villager

"""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.x = x
[docs] self.y = y
[docs] self.target_x = x
[docs] self.target_y = y
[docs] self.move_timer = 0
[docs] self.work_timer = 0
[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)