"""Get, drop, and inventory commands for items.""" from mudlib.commands import CommandDefinition, register from mudlib.container import Container from mudlib.player import Player from mudlib.targeting import find_in_inventory, find_thing_on_tile from mudlib.thing import Thing from mudlib.zone import Zone def _find_thing_at(name: str, zone: Zone, x: int, y: int) -> Thing | None: """Find a thing on the ground matching name or alias. Deprecated: Use find_thing_on_tile from mudlib.targeting instead. """ return find_thing_on_tile(name, zone, x, y) def _find_thing_in_inventory(name: str, player: Player) -> Thing | None: """Find a thing in the player's inventory matching name or alias. Deprecated: Use find_in_inventory from mudlib.targeting instead. """ return find_in_inventory(name, player) def _format_thing_name(thing: Thing) -> str: """Format a thing's name with container state if applicable.""" if not isinstance(thing, Container): return thing.name if thing.closed: return f"{thing.name} (closed)" # Container is open contents = [obj for obj in thing.contents if isinstance(obj, Thing)] if not contents: return f"{thing.name} (open, empty)" names = ", ".join(item.name for item in contents) return f"{thing.name} (open, containing: {names})" async def cmd_get(player: Player, args: str) -> None: """Pick up an item from the ground or take from a container.""" if not args.strip(): await player.send("Get what?\r\n") return # Check if this is "take/get X from Y" syntax # Match " from " or "from " (at start) or " from" (at end) args_lower = args.lower() if ( " from " in args_lower or args_lower.startswith("from ") or args_lower.endswith(" from") or args_lower == "from" ): await _handle_take_from(player, args) return zone = player.location if zone is None or not isinstance(zone, Zone): await player.send("You are nowhere.\r\n") return thing = _find_thing_at(args.strip(), zone, player.x, player.y) if thing is None: await player.send(f"You don't see '{args.strip()}' here.\r\n") return if not player.can_accept(thing): await player.send("You can't pick that up.\r\n") return thing.move_to(player) await player.send(f"You pick up {thing.name}.\r\n") async def _handle_take_from(player: Player, args: str) -> None: """Handle 'take/get X from Y' to remove items from containers.""" # Parse "thing from container" parts = args.strip().split(" from ", 1) thing_name = parts[0].strip() if len(parts) > 0 else "" container_name = parts[1].strip() if len(parts) > 1 else "" if not thing_name or not container_name: await player.send("Take what from where? (take from )\r\n") return # Find container (on ground or in inventory) from mudlib.commands.containers import _find_container container_obj = _find_container(container_name, player) if container_obj is None: await player.send("You don't see that here.\r\n") return if not isinstance(container_obj, Container): await player.send("That's not a container.\r\n") return if container_obj.closed: await player.send(f"The {container_obj.name} is closed.\r\n") return # Handle "get all from container" if thing_name.lower() == "all": container_things = [ obj for obj in container_obj.contents if isinstance(obj, Thing) ] portable_things = [t for t in container_things if player.can_accept(t)] if not portable_things: msg = f"There's nothing in the {container_obj.name} to take.\r\n" await player.send(msg) return for thing in portable_things: thing.move_to(player) msg = f"You take the {thing.name} from the {container_obj.name}.\r\n" await player.send(msg) return # Find thing in container using targeting (supports prefix and ordinals) from mudlib.targeting import resolve_target container_things = [obj for obj in container_obj.contents if isinstance(obj, Thing)] thing = resolve_target(thing_name, container_things) if thing is None: await player.send(f"The {container_obj.name} doesn't contain that.\r\n") return thing.move_to(player) await player.send(f"You take the {thing.name} from the {container_obj.name}.\r\n") async def cmd_drop(player: Player, args: str) -> None: """Drop an item from inventory onto the ground.""" if not args.strip(): await player.send("Drop what?\r\n") return zone = player.location if zone is None or not isinstance(zone, Zone): await player.send("You can't drop things here.\r\n") return thing = _find_thing_in_inventory(args.strip(), player) if thing is None: await player.send(f"You're not carrying '{args.strip()}'.\r\n") return thing.move_to(zone, x=player.x, y=player.y) await player.send(f"You drop {thing.name}.\r\n") async def cmd_inventory(player: Player, args: str) -> None: """List items in the player's inventory.""" things = [obj for obj in player.contents if isinstance(obj, Thing)] if not things: await player.send("You aren't carrying anything.\r\n") return lines = ["You are carrying:\r\n"] for thing in things: lines.append(f" {_format_thing_name(thing)}\r\n") await player.send("".join(lines)) register(CommandDefinition("get", cmd_get, aliases=["take"])) register(CommandDefinition("drop", cmd_drop)) register(CommandDefinition("inventory", cmd_inventory, aliases=["i"]))