diff --git a/evennia/objects/objects.py b/evennia/objects/objects.py index 61890feca0..14d64b0323 100644 --- a/evennia/objects/objects.py +++ b/evennia/objects/objects.py @@ -1506,15 +1506,20 @@ class DefaultObject(ObjectDB, metaclass=TypeclassBase): Append 01, 02 etc to obj.key. Checks next higher number in the same location, then adds the next number available - returns the new clone name on the form keyXX + Returns the new clone name on the form keyXX """ key = self.key - num = sum( - 1 + if not self.location: + # no location means no clone numbering + return key + suffixes = [ + obj.key.removeprefix(key) for obj in self.location.contents - if obj.key.startswith(key) and obj.key.lstrip(key).isdigit() - ) - return "%s%03i" % (key, num) + ] + num = 1 + if nums := [int(suffix) for suffix in suffixes if suffix.isdigit()]: + num = max(nums) + 1 + return f"{key}{num:02d}" new_key = new_key or find_clone_key() new_obj = ObjectDB.objects.copy_object(self, new_key=new_key, **kwargs) diff --git a/evennia/objects/tests.py b/evennia/objects/tests.py index 97896e0189..f74f9ebaad 100644 --- a/evennia/objects/tests.py +++ b/evennia/objects/tests.py @@ -393,6 +393,41 @@ class TestObjectManager(BaseEvenniaTest): self.assertEqual(self.obj1.attributes.get(key="phrase", category="adventure"), "plugh") self.assertEqual(obj2.attributes.get(key="phrase", category="adventure"), "plugh") + def test_copy_object_clone_key(self): + # reset key to avoid overlap with other tests + self.obj1.key = "CopyMe" + copied = self.obj1.copy() + self.assertEqual(copied.key, "CopyMe01") + copied2 = self.obj1.copy() + self.assertEqual(copied2.key, "CopyMe02") + # verify that it increments based on max existing identifier + # both for skipped numbers... + copied.key = "CopyMe03" + copied3 = self.obj1.copy() + self.assertEqual(copied3.key, "CopyMe04") + copied3.delete() + # ...and for duplicate numbers + copied.key = "CopyMe01" + copied2.key = "CopyMe01" + copied3 = self.obj1.copy() + self.assertEqual(copied3.key, "CopyMe02") + # and that sharing a partial prefix doesn't count + copied3.delete() + copied.key = "CopyMeMe02" + copied2.key = "CopyMe01" + copied3 = self.obj1.copy() + self.assertEqual(copied3.key, "CopyMe02") + # and that nothing breaks if something in the room doesn't share the prefix + copied3.key = "NotACopy" + copied4 = self.obj1.copy() + self.assertEqual(copied4.key, "CopyMe02") + + + def test_copy_object_no_location(self): + self.obj1.location = None + # we just want to make sure this doesn't error + self.assertIsNotNone(self.obj1.copy()) + class TestContentHandler(BaseEvenniaTest): "Test the ContentHandler (obj.contents)"