Source code for simulation_framework.src.actions.crafting

from __future__ import annotations

from typing import TYPE_CHECKING, Dict, Optional

from ..items.item import Item
from .base import Action, ActionResult, Event, ResourceCost

if TYPE_CHECKING:
    from ..core.world import World
    from ..entities.base import Entity


[docs] class CraftAction(Action): def __init__(self, actor_id: int, item_name: str, quantity: int = 1): super().__init__(actor_id) self.item_name = item_name self.quantity = quantity self.recipe = self._get_recipe(item_name) def _get_recipe(self, item_name: str) -> Dict: """Get crafting recipe for an item (simplified recipes)""" recipes = { "Wooden Sword": { "materials": {"Wood": 2}, "tool_required": None, "skill_required": ("crafting", 1), "crafting_time": 3, }, "Stone Axe": { "materials": {"Wood": 1, "Stone": 2}, "tool_required": None, "skill_required": ("crafting", 2), "crafting_time": 4, }, "Health Potion": { "materials": {"Herbs": 2, "Berries": 1}, "tool_required": None, "skill_required": ("alchemy", 1), "crafting_time": 2, }, "Bread": { "materials": {"Berries": 3}, "tool_required": None, "skill_required": ("cooking", 1), "crafting_time": 2, }, "Iron Sword": { "materials": {"Iron Ore": 3, "Wood": 1}, "tool_required": "anvil", "skill_required": ("smithing", 3), "crafting_time": 5, }, } return recipes.get(item_name, {})
[docs] def can_execute(self, actor: Entity, world: World) -> bool: if not self.recipe: return False # Check materials for material, needed in self.recipe.get("materials", {}).items(): if not actor.inventory.has_item(material, needed * self.quantity): return False # Check tool requirement tool_required = self.recipe.get("tool_required") if tool_required and not actor.inventory.get_equipped_tool(tool_required): return False # Check skill requirement skill_req = self.recipe.get("skill_required") if skill_req: skill_name, min_level = skill_req if hasattr(actor, "skills"): current_level = actor.skills.get(skill_name, 0) if current_level < min_level: return False return self.get_cost().can_afford(actor)
[docs] def execute(self, actor: Entity, world: World) -> ActionResult: if not self.can_execute(actor, world): return ActionResult.failure(f"Cannot craft {self.item_name}") # Consume resources cost = self.get_cost() if not cost.consume(actor): return ActionResult.failure("Insufficient resources") # Consume materials for material, needed in self.recipe.get("materials", {}).items(): actor.inventory.remove_item(material, needed * self.quantity) # Create the crafted item crafted_item = self._create_item(self.item_name) if crafted_item: remaining = actor.inventory.add_item(crafted_item, self.quantity) if remaining > 0: return ActionResult.failure( f"Inventory full, lost {remaining} {self.item_name}" ) # Gain skill experience skill_req = self.recipe.get("skill_required") if skill_req and hasattr(actor, "skills"): skill_name, _ = skill_req current_skill = actor.skills.get(skill_name, 0) actor.skills[skill_name] = current_skill + 2 event = Event( event_type="craft", actor_id=actor.id, data={ "item": self.item_name, "quantity": self.quantity, "skill_gained": 2, }, ) return ActionResult.success( f"Crafted {self.quantity}x {self.item_name}", [event] ) return ActionResult.failure(f"Failed to create {self.item_name}")
def _create_item(self, item_name: str) -> Optional[Item]: """Create the specified item""" item_data = { "Wooden Sword": { "id": 1001, "type": "weapon", "properties": {"damage": 8, "attack_type": "melee", "durability": 30}, "value": 15, }, "Stone Axe": { "id": 1002, "type": "tool", "properties": {"tool_type": "axe", "durability": 40, "efficiency": 1.2}, "value": 20, }, "Health Potion": { "id": 1003, "type": "consumable", "properties": {"effect": {"heal": 30}}, "value": 25, "max_stack": 10, }, "Bread": { "id": 1004, "type": "consumable", "properties": {"effect": {"heal": 15, "restore_stamina": 10}}, "value": 5, "max_stack": 20, }, "Iron Sword": { "id": 1005, "type": "weapon", "properties": { "damage": 18, "attack_type": "melee", "durability": 80, "critical_chance": 0.15, }, "value": 75, }, } data = item_data.get(item_name) if not data: return None return Item( id=data["id"], name=item_name, item_type=data["type"], properties=data["properties"], description=f"Crafted {item_name.lower()}", value=data["value"], max_stack_size=data.get("max_stack", 1), )
[docs] def get_duration(self) -> int: return self.recipe.get("crafting_time", 1)
[docs] def get_cost(self) -> ResourceCost: return ResourceCost(stamina=5)
def __repr__(self) -> str: return f"CraftAction({self.item_name}x{self.quantity})"