add object stacking to get/drop/give

This commit is contained in:
InspectorCaracal 2024-02-19 13:20:05 -07:00 committed by Cal
parent b5239e18c1
commit 829f32f573

View file

@ -395,39 +395,64 @@ class CmdGet(COMMAND_DEFAULT_CLASS):
locks = "cmd:all()" locks = "cmd:all()"
arg_regex = r"\s|$" arg_regex = r"\s|$"
def parse(self):
super().parse()
self.number = 0
if self.args:
# check for numbering
count, *args = self.args.split(maxsplit=1)
# we only use the first word as a count if it's a number and
# there is more text afterwards
if args and count.isdecimal():
self.number = int(count)
self.args = args[0]
def func(self): def func(self):
"""implements the command.""" """implements the command."""
caller = self.caller caller = self.caller
if not self.args: if not self.args:
caller.msg("Get what?") self.msg("Get what?")
return return
obj = caller.search(self.args, location=caller.location) objs = caller.search(self.args, location=caller.location, stacked=self.number)
if not obj: if not objs:
return return
if caller == obj: # the 'stacked' search sometimes returns a list, sometimes not, so we make it always a list
caller.msg("You can't get yourself.") # NOTE: this behavior may be a bug, see issue #3432
return objs = utils.make_iter(objs)
if not obj.access(caller, "get"):
if obj.db.get_err_msg: if len(objs) == 1 and caller == objs[0]:
caller.msg(obj.db.get_err_msg) self.msg("You can't get yourself.")
else:
caller.msg("You can't get that.")
return return
# calling at_pre_get hook method # if we aren't allowed to get any of the objects, cancel the get
if not obj.at_pre_get(caller): for obj in objs:
return # check the locks
if not obj.access(caller, "get"):
if obj.db.get_err_msg:
self.msg(obj.db.get_err_msg)
else:
self.msg("You can't get that.")
return
# calling at_pre_get hook method
if not obj.at_pre_get(caller):
return
success = obj.move_to(caller, quiet=True, move_type="get") moved = []
if not success: # attempt to move all of the objects
caller.msg("This can't be picked up.") for obj in objs:
if obj.move_to(caller, quiet=True, move_type="get"):
moved.append(obj)
# calling at_get hook method
obj.at_get(caller)
if not moved:
# none of the objects were successfully moved
self.msg("That can't be picked up.")
else: else:
singular, _ = obj.get_numbered_name(1, caller) singular, plural = moved[0].get_numbered_name(len(moved), caller)
caller.location.msg_contents(f"$You() $conj(pick) up {singular}.", from_obj=caller) caller.location.msg_contents(f"$You() $conj(pick) up {plural if len(moved) > 1 else singular}.", from_obj=caller)
# calling at_get hook method
obj.at_get(caller)
class CmdDrop(COMMAND_DEFAULT_CLASS): class CmdDrop(COMMAND_DEFAULT_CLASS):
@ -445,6 +470,18 @@ class CmdDrop(COMMAND_DEFAULT_CLASS):
locks = "cmd:all()" locks = "cmd:all()"
arg_regex = r"\s|$" arg_regex = r"\s|$"
def parse(self):
super().parse()
self.number = 0
if self.args:
# check for numbering
count, *args = self.args.split(maxsplit=1)
# we only use the first word as a count if it's a number and
# there is more text afterwards
if args and count.isdecimal():
self.number = int(count)
self.args = args[0]
def func(self): def func(self):
"""Implement command""" """Implement command"""
@ -455,27 +492,39 @@ class CmdDrop(COMMAND_DEFAULT_CLASS):
# Because the DROP command by definition looks for items # Because the DROP command by definition looks for items
# in inventory, call the search function using location = caller # in inventory, call the search function using location = caller
obj = caller.search( objs = caller.search(
self.args, self.args,
location=caller, location=caller,
nofound_string=f"You aren't carrying {self.args}.", nofound_string=f"You aren't carrying {self.args}.",
multimatch_string=f"You carry more than one {self.args}:", multimatch_string=f"You carry more than one {self.args}:",
stacked=self.number,
) )
if not obj: if not objs:
return return
# the 'stacked' search sometimes returns a list, sometimes not, so we make it always a list
# NOTE: this behavior may be a bug, see issue #3432
objs = utils.make_iter(objs)
# Call the object script's at_pre_drop() method. # if any objects fail the drop permission check, cancel the drop
if not obj.at_pre_drop(caller): for obj in objs:
return # Call the object's at_pre_drop() method.
if not obj.at_pre_drop(caller):
return
success = obj.move_to(caller.location, quiet=True, move_type="drop") # do the actual dropping
if not success: moved = []
caller.msg("This couldn't be dropped.") for obj in objs:
if obj.move_to(caller.location, quiet=True, move_type="drop"):
moved.append(obj)
# Call the object's at_drop() method.
obj.at_drop(caller)
if not moved:
# none of the objects were successfully moved
self.msg("That can't be dropped.")
else: else:
singular, _ = obj.get_numbered_name(1, caller) singular, plural = obj.get_numbered_name(len(moved), caller)
caller.location.msg_contents(f"$You() $conj(drop) {singular}.", from_obj=caller) caller.location.msg_contents(f"$You() $conj(drop) {plural if len(moved) > 1 else singular}.", from_obj=caller)
# Call the object script's at_drop() method.
obj.at_drop(caller)
class CmdGive(COMMAND_DEFAULT_CLASS): class CmdGive(COMMAND_DEFAULT_CLASS):
@ -494,6 +543,18 @@ class CmdGive(COMMAND_DEFAULT_CLASS):
locks = "cmd:all()" locks = "cmd:all()"
arg_regex = r"\s|$" arg_regex = r"\s|$"
def parse(self):
super().parse()
self.number = 0
if self.lhs:
# check for numbering
count, *args = self.lhs.split(maxsplit=1)
# we only use the first word as a count if it's a number and
# there is more text afterwards
if args and count.isdecimal():
self.number = int(count)
self.lhs = args[0]
def func(self): def func(self):
"""Implement give""" """Implement give"""
@ -501,37 +562,52 @@ class CmdGive(COMMAND_DEFAULT_CLASS):
if not self.args or not self.rhs: if not self.args or not self.rhs:
caller.msg("Usage: give <inventory object> = <target>") caller.msg("Usage: give <inventory object> = <target>")
return return
# find the thing(s) to give away
to_give = caller.search( to_give = caller.search(
self.lhs, self.lhs,
location=caller, location=caller,
nofound_string=f"You aren't carrying {self.lhs}.", nofound_string=f"You aren't carrying {self.lhs}.",
multimatch_string=f"You carry more than one {self.lhs}:", multimatch_string=f"You carry more than one {self.lhs}:",
stacked=self.number,
) )
if not to_give:
return
# find the target to give to
target = caller.search(self.rhs) target = caller.search(self.rhs)
if not (to_give and target): if not target:
return return
singular, _ = to_give.get_numbered_name(1, caller) # the 'stacked' search sometimes returns a list, sometimes not, so we make it always a list
# NOTE: this behavior may be a bug, see issue #3432
to_give = utils.make_iter(to_give)
singular, plural = to_give[0].get_numbered_name(len(to_give), caller)
if target == caller: if target == caller:
caller.msg(f"You keep {singular} to yourself.") caller.msg(f"You keep {plural if len(to_give) > 1 else singular} to yourself.")
return
if not to_give.location == caller:
caller.msg(f"You are not holding {singular}.")
return return
# calling at_pre_give hook method # if any of the objects aren't allowed to be given, cancel the give
if not to_give.at_pre_give(caller, target): for obj in to_give:
return # calling at_pre_give hook method
if not obj.at_pre_give(caller, target):
return
# give object # do the actual moving
success = to_give.move_to(target, quiet=True, move_type="give") moved = []
if not success: for obj in to_give:
caller.msg(f"You could not give {singular} to {target.key}.") if obj.move_to(target, quiet=True, move_type="give"):
moved.append(obj)
# Call the object's at_give() method.
obj.at_give(caller, target)
if not moved:
caller.msg(f"You could not give that to {target.get_display_name(caller)}.")
else: else:
caller.msg(f"You give {singular} to {target.key}.") singular, plural = to_give[0].get_numbered_name(len(moved), caller)
target.msg(f"{caller.key} gives you {singular}.") names = plural if len(moved) > 1 else singular
# Call the object script's at_give() method. caller.msg(f"You give {names} to {target.get_display_name(caller)}.")
to_give.at_give(caller, target) target.msg(f"{caller.get_display_name(target)} gives you {names}.")
class CmdSetDesc(COMMAND_DEFAULT_CLASS): class CmdSetDesc(COMMAND_DEFAULT_CLASS):