From 167e8f356f8e6f0ccd2e67064af479bd2c53ce80 Mon Sep 17 00:00:00 2001 From: Howard Abrams Date: Sat, 31 May 2025 08:47:56 -0700 Subject: [PATCH] Moved 'eat' command from food to people This handles better error messages. Also, cleaned up code warnings. --- commands/consumables.py | 16 ----- commands/default_cmdsets.py | 3 +- commands/everyone.py | 126 ++++++++++++++++++++++++++++-------- typeclasses/consumables.py | 6 +- typeclasses/objects.py | 4 ++ 5 files changed, 106 insertions(+), 49 deletions(-) diff --git a/commands/consumables.py b/commands/consumables.py index a74e692..05b8562 100755 --- a/commands/consumables.py +++ b/commands/consumables.py @@ -20,22 +20,6 @@ class CmdSetMakeConsumable(CmdSet): self.add(CmdMakeConsumable) -class CmdEat(Command): - """ - Eat something - """ - key = "eat" - aliases = "bite" - - def func(self): - self.obj.do_eat(self.caller) - - -class CmdSetEat(CmdSet): - def at_cmdset_creation(self): - self.add(CmdEat) - - class CmdMakeTea(Command): """ make [tea-type] diff --git a/commands/default_cmdsets.py b/commands/default_cmdsets.py index 26f7075..7df4770 100644 --- a/commands/default_cmdsets.py +++ b/commands/default_cmdsets.py @@ -20,7 +20,7 @@ from evennia.contrib.game_systems.gendersub import SetGender from evennia.contrib.rpg.rpsystem import RPSystemCmdSet from evennia.contrib.rpg.character_creator.character_creator import ContribChargenCmdSet from commands.sittables import CmdNoSitStand -from commands.everyone import CmdTake, CmdThink, CmdSay, CmdWhisper, CmdRead, CmdDrink +from commands.everyone import CmdTake, CmdThink, CmdSay, CmdWhisper, CmdRead, CmdEat, CmdDrink from commands.wizards import CmdGM, CmdSpell, CmdGMTrigger, CmdMakeCocktail class CharacterCmdSet(default_cmds.CharacterCmdSet): @@ -38,6 +38,7 @@ class CharacterCmdSet(default_cmds.CharacterCmdSet): """ super().at_cmdset_creation() self.add(CmdNoSitStand) + self.add(CmdEat) self.add(CmdDrink) self.add(CmdTake) self.add(CmdThink) diff --git a/commands/everyone.py b/commands/everyone.py index a77a046..8c9af9c 100755 --- a/commands/everyone.py +++ b/commands/everyone.py @@ -13,9 +13,12 @@ from typeclasses.readables import find_book from typeclasses.characters import Character from utils.word_list import routput, paragraph, choices + def speech_effect(speech, verb, target, effects): """ - Returns a tuple for what a user thinks he said, and what + Return speech after applying 'effects'. + + Return a tuple for what a user thinks he said, and what others actually here. If no effect, just return speech twice. Effects: @@ -38,7 +41,7 @@ def speech_effect(speech, verb, target, effects): class CmdWhisper(MuxCommand): """ - Speak privately as your character to another + Speak privately as your character to another. Usage: whisper = @@ -47,15 +50,14 @@ class CmdWhisper(MuxCommand): Talk privately to one or more characters in your current location, without others in the room being informed. """ + key = "whisper" priority = 0 locks = "cmd:all()" rhs_split = ("=") def func(self): - """ - Implements the new 'whisper' command. - """ + """Implement the new 'whisper' command.""" if not self.args: self.caller.msg("What are you whispering?") return @@ -75,7 +77,9 @@ class CmdWhisper(MuxCommand): class CmdSay(MuxCommand): """ - Say something to the characters in the same area. For instance: + Say something to the characters in the same area. + + For instance: |gsay Good evening!|n @@ -114,16 +118,15 @@ class CmdSay(MuxCommand): """ key = "say" - aliases = ["says", "speak", "shout", "yell", "exclaim", "scream", "ask", "reply", "respond", "\"", "'"] + aliases = ["says", "speak", "shout", "yell", "exclaim", "scream", "ask", + "reply", "respond", "\"", "'"] priority = 0 locks = "cmd:all()" rhs_split = ("=") arg_regex = None def func(self): - """ - Implements the new 'say' command with switches. - """ + """Implement the new 'say' command with switches.""" speaker = self.caller if not self.args: @@ -173,8 +176,8 @@ class CmdSay(MuxCommand): speech_effect(speech, verb, speaker, speaker.attributes.get(category="effect", - return_obj=True, - return_list=True)) + return_obj=True, + return_list=True)) to_who = to_whom = '' @@ -220,9 +223,11 @@ class CmdSay(MuxCommand): if verb == 'reply': verb = 'replie' - targets = [item for item in speaker.location.contents if item != speaker] + targets = [item for item in speaker.location.contents + if item != speaker] full_speech = f"/me {adverb}{verb}s{to_whom}, \"{for_others}\"" - send_emote(speaker, targets, full_speech, msg_type="say", anonymous_add=None) + send_emote(speaker, targets, full_speech, msg_type="say", + anonymous_add=None) class CmdThink(Command): @@ -234,21 +239,21 @@ class CmdThink(Command): Similar to the 'say' or 'pose' commands, this communicates an inner monologue to other players on the 'public' channel. """ + key = "think" aliases = ["thinks", "("] arg_regex = None def func(self): - """ - Implements the think out loud command. - """ + """Implement the think out loud command.""" if not self.args: self.caller.msg("What do you want to think out loud?") else: thought = self.args.strip() if (self.caller.db.thinking_count or 0) < 3 or random() < 0.4: msg = routput( - f"<< thinks ^ wonders >> << out loud ^ aloud >> ... o O ( {thought} )" + f"<< thinks ^ wonders >> << out loud ^ aloud >> " + f"... o O ( {thought} )" ) else: msg = f". o O ( {thought} )" @@ -269,11 +274,11 @@ class CmdRead(Command): @set /inside = 'This is the text to read.' """ + key = "read" def func(self): """Return the 'inside' attribute.""" - target_str = self.args.strip() if target_str == "": self.caller.msg("Usage: |gread |n") @@ -294,14 +299,17 @@ class CmdTake(Command, NumberedTargetCommand): Note that only some things can be stolen. For instance, the brass ring from the door knocker. """ + key = "take" aliases = ["steal"] rhs_split = ("=", " from ") def func(self): """ - Implements the take command. Since this command is designed - to work on the object, we operate only on self.obj. + Implement the take command. + + Since this command is designed to work on the object, we + operate only on self.obj. """ if not self.args: self.caller.msg("What do you want to take?") @@ -324,37 +332,99 @@ class CmdDrink(Command): This doesn't tell others of this particular activity. """ + key = "drink" aliases = ["sip", "quaff"] - def drinkable(self, item): - return hasattr(item, 'do_drink') and callable(item.do_drink) - def not_empty(self, item): + """Return true is the cup has some drink left in it.""" return (item.db.amount or 0) > 0 def drink_item(self, name): + """Find item in inventory, name, and call 'do_drink' on it.""" + notfound = f"You don't have {name} in your inventory." item = self.caller.search(name, location=self.caller, - nofound_string=f"You don't have {name} in your inventory.") + nofound_string=notfound) if item: - if self.drinkable(item): + if item.has_method('do_drink'): item.do_drink(self.caller) else: self.caller.msg(f"The {item.name} is not drinkable.") def drink_anything(self): + """Drink anything in your inventory, but only if you have one thing.""" containers = [item for item in self.caller.contents - if self.drinkable(item) and self.not_empty(item)] + if item.has_method('do_drink') and self.not_empty(item)] if len(containers) == 1: containers[0].do_drink(self.caller) elif len(containers) > 1: - self.caller.msg("You have two many things you can drink. Which one do you want?") + self.caller.msg("You have two many things you can drink. " + "Which one do you want?") else: self.caller.msg("You have nothing to drink.") def func(self): + """ + If given the name of something to drink, find and drink it. + + Otherwise, drink the first item you find in your inventory. + """ goal = self.args.strip() if goal and goal != "": self.drink_item(goal) else: self.drink_anything() + + +class CmdEat(Command): + """ + Eat something edible in your inventory. + + Usage: + + eat [ food-item ] + + This doesn't tell others of this particular activity. + """ + + key = "eat" + aliases = ["consume", "bite"] + + def not_gone(self, item): + """Return true is the cup has some eat left in it.""" + return (item.db.amount or 0) > 0 + + def eat_item(self, name): + """Find item in inventory, name, and call 'do_eat' on it.""" + notfound = f"You don't have {name} in your inventory." + item = self.caller.search(name, location=self.caller, + nofound_string=notfound) + if item: + if item.has_method('do_eat'): + item.do_eat(self.caller) + else: + self.caller.msg(f"The {item.name} is not edible.") + + def eat_anything(self): + """Eat something in your inventory, but only if you have one thing.""" + items = [item for item in self.caller.contents + if item.has_method('do_eat') and self.not_gone(item)] + if len(items) == 1: + items[0].do_eat(self.caller) + elif len(items) > 1: + self.caller.msg("You have too many things to eat. " + "Which one do you want?") + else: + self.caller.msg("You have nothing to eat.") + + def func(self): + """ + If given the name of something to eat, find and eat it. + + Otherwise, eat the first item you find in your inventory. + """ + goal = self.args.strip() + if goal and goal != "": + self.eat_item(goal) + else: + self.eat_anything() diff --git a/typeclasses/consumables.py b/typeclasses/consumables.py index e0c89a2..f021ffd 100755 --- a/typeclasses/consumables.py +++ b/typeclasses/consumables.py @@ -6,9 +6,8 @@ import random from evennia import TICKER_HANDLER from evennia.prototypes.spawner import spawn -from commands.consumables import ( - CmdSetEat, CmdSetTrolley, CmdSetMakeConsumable -) +from commands.consumables import CmdSetTrolley, CmdSetMakeConsumable + from typeclasses.objects import Object from utils.word_list import routput # , choices @@ -30,7 +29,6 @@ class Consumable(Object): eat_amount = 1 def at_object_creation(self): - self.cmdset.add_default(CmdSetEat) self.db.amount = self.amount self.db.eat_amount = self.eat_amount diff --git a/typeclasses/objects.py b/typeclasses/objects.py index 37fd529..655eceb 100755 --- a/typeclasses/objects.py +++ b/typeclasses/objects.py @@ -250,6 +250,10 @@ class Object(ObjectParent, ContribRPObject): return None + def has_method(self, method_name): + """True if this object has a method of a particular name.""" + return hasattr(self, method_name) and callable(getattr(self, method_name)) + def delay_sequence(self, sequence_str, time_delay=1, *args): """Run a sequence of messages or commands with a delay.