"""Crafting commands.""" from collections import Counter from mudlib.commands import CommandDefinition, register from mudlib.crafting import recipes from mudlib.player import Player from mudlib.things import spawn_thing, thing_templates async def cmd_craft(player: Player, args: str) -> None: """Craft an item from a recipe. Args: player: The player crafting args: Recipe name """ if not args: await player.send("Usage: craft \r\n") return recipe_name = args.strip().lower() # Find recipe by name (case-insensitive, prefix match) matching_recipes = [ name for name in recipes if name.lower().startswith(recipe_name) ] if not matching_recipes: await player.send(f"Unknown recipe: {args}\r\n") return if len(matching_recipes) > 1: await player.send( f"Ambiguous recipe name. Matches: {', '.join(matching_recipes)}\r\n" ) return recipe = recipes[matching_recipes[0]] # Count required ingredients required = Counter(ingredient.lower() for ingredient in recipe.ingredients) # Count available ingredients in inventory inventory = player.contents available = Counter(obj.name.lower() for obj in inventory) # Check if player has all ingredients missing = [] for ingredient, count in required.items(): if available[ingredient] < count: needed = count - available[ingredient] missing.append(f"{ingredient} (need {needed} more)") if missing: await player.send(f"Missing ingredients: {', '.join(missing)}\r\n") return # Check if result template exists if recipe.result not in thing_templates: await player.send( f"Error: Recipe result '{recipe.result}' template not found.\r\n" ) return # Consume ingredients consumed = Counter() for obj in list(inventory): obj_name = obj.name.lower() if obj_name in required and consumed[obj_name] < required[obj_name]: obj.move_to(None) # Remove from world consumed[obj_name] += 1 # Create result item result_template = thing_templates[recipe.result] spawn_thing(result_template, player) await player.send(f"You craft a {result_template.name}.\r\n") async def cmd_recipes(player: Player, args: str) -> None: """List available recipes. Args: player: The player viewing recipes args: Optional recipe name for details """ if not recipes: await player.send("No recipes available.\r\n") return if args: # Show details for specific recipe recipe_name = args.strip().lower() matching = [name for name in recipes if name.lower().startswith(recipe_name)] if not matching: await player.send(f"Unknown recipe: {args}\r\n") return if len(matching) > 1: await player.send( f"Ambiguous recipe name. Matches: {', '.join(matching)}\r\n" ) return recipe = recipes[matching[0]] ingredient_counts = Counter(recipe.ingredients) ingredient_list = ", ".join( f"{count}x {name}" if count > 1 else name for name, count in sorted(ingredient_counts.items()) ) await player.send( f"Recipe: {recipe.name}\r\n" f"{recipe.description}\r\n" f"Ingredients: {ingredient_list}\r\n" f"Result: {recipe.result}\r\n" ) else: # List all recipes await player.send("Available recipes:\r\n") for name, recipe in sorted(recipes.items()): await player.send(f" {name}: {recipe.description}\r\n") register(CommandDefinition("craft", cmd_craft, help="Craft items from recipes.")) register( CommandDefinition("recipes", cmd_recipes, help="List available crafting recipes.") )