def func(self): "implements the command." caller = self.caller args = self.args.strip() wield = self.wield # reset flag, this should stay at the beginning of the command if wield: self.wield = False if not args: caller.msg("Wear what?") return # this will search for a target obj = caller.search(args) if not obj: return if not obj in caller.contents: caller.msg("You don't have %s in your inventory." % obj) slots = utils.make_iter(obj.db.slot) if wield: if not caller.equip.primary_hand in slots \ and not caller.equip.secondary_hand in slots: caller.msg("You can't wield %s." % obj) return # equip primary and secondary hands with the proper feedback if caller.equip.primary_hand in slots \ or caller.equip.secondary_hand in slots: action = 'wield' else: action = 'wear' if not obj.db.slot or not obj.access(caller, 'equip'): caller.msg("You can't equip %s." % obj) return if obj in caller.equip.items: caller.msg("You're already %sing %s." % (action, obj.name)) return if not caller.equip.add(obj): string = "You can't equip %s." % obj if [slot for slot in slots if slot in caller.equip.slots]: string += " You already have something there." caller.msg(string) return # call hook if hasattr(obj, "at_equip"): obj.at_equip(caller) caller.msg("You %s %s." % (action, obj)) caller.location.msg_contents("%s %ss %s." % (caller.name.capitalize(), action, obj), exclude=caller)
def func(self): """ Handle the looking - add fallback to details. """ caller = self.caller args = self.args if args: looking_at_obj = caller.search(args, use_nicks=True, quiet=True) if not looking_at_obj: # no object found. Check if there is a matching # detail at location. location = caller.location if location and hasattr(location, "return_detail") and callable(location.return_detail): detail = location.return_detail(args) if detail: # we found a detail instead. Show that. caller.msg("{y%s{n\n" % args + detail) return # no detail found. Trigger delayed error messages _AT_SEARCH_RESULT(caller, args, looking_at_obj, False) return else: if len(looking_at_obj) >1: caller.msg("Есть несколько объектов с таким именем(укажи нужный):") i=1 for item in looking_at_obj: if item.has_player: caller.msg("%s-%s (Игрок)" % (i,item.key)) elif item.db.is_corpse: caller.msg("%s-%s (Труп)" % (i,item.key)) elif item.db.npc: caller.msg("%s-%s (NPC)" % (i,item.key)) elif item.db.is_weapon: caller.msg("%s-%s (Оружие)" % (i,item.key)) else: caller.msg("%s-%s (Объект)" % (i,item.key)) i = i +1 return else: # we need to extract the match manually. looking_at_obj = utils.make_iter(looking_at_obj)[0] else: looking_at_obj = caller.location if not looking_at_obj: caller.msg("Тебе некуда смотреть!") return if not hasattr(looking_at_obj, 'return_appearance'): # this is likely due to us having a player instead looking_at_obj = looking_at_obj.character if not looking_at_obj.access(caller, "view"): caller.msg("Не могу найти '%s'." % args) return # get object's appearance caller.msg(looking_at_obj.return_appearance(caller)) # the object's at_desc() method. looking_at_obj.at_desc(looker=caller)
def combat_msg(self, message, actor, target=None, exclude=(), **kwargs): """Sends messaging to combat participants and vicinity. Args: message (str): Message string in director stance to be delivered. Contains string format keys matching the other arguments as described below. exclude (tuple, optional): Not substituted into the message string; a tuple or list of objects to exclude from receiving the message. actor (Character): the character taking the action, keyed in messages as {actor}. target (Character, optional): the character or object being targeted in the action, keyed in messages as {target}. kwargs: any other format substitution keys should be passed in as kwargs. Example: ch.combat_msg("{actor} attacks {target} with {weapon}.", actor=attacker, target=defender, weapon=weapon) """ exclude = make_iter(exclude) if exclude else [] kwargs.update(dict(actor=actor, target=target)) for character in self.db.characters.values(): if character == actor: cbt_prefix = '|b->|n ' elif character == target: cbt_prefix = '|m<-|n ' else: cbt_prefix = '|x..|n ' if character not in exclude: mapping = {token: val.get_display_name(character) if hasattr(val, 'get_display_name') else str(val) for token, val in kwargs.items()} character.msg( (cbt_prefix + message).format(**mapping), prompt=_COMBAT_PROMPT.format(tr=character.traits)) # send messaging to others in the same room but not in combat actor.location.msg_contents( text=message, mapping=kwargs, exclude=exclude + self.db.characters.values() )
def add(self, obj): """ Add an object to character's equip. """ slots = utils.make_iter(obj.db.slot) free_slots = [sl for sl in slots if sl in self.empty_slots] if not free_slots: return False if obj.db.slot_operator == 'AND': if len(free_slots) != len(slots): return False for slot in free_slots: self._set(slot, obj) return True slot = free_slots[0] self._set(slot, obj) return True
def search_targets(self, namelist): """ Search a list of targets of the same type as caller. Args: caller (Object or Account): The type of object to search. namelist (list): List of strings for objects to search for. Returns: targetlist (list): List of matches, if any. """ nameregex = r"|".join(r"^%s$" % re.escape(name) for name in make_iter(namelist)) if hasattr(self.caller, "account") and self.caller.account: matches = list(ObjectDB.objects.filter(db_key__iregex=nameregex)) else: matches = list(AccountDB.objects.filter(username__iregex=nameregex)) return matches
def func(self): """ Handle the looking - add fallback to details. """ caller = self.caller args = self.args if args: looking_at_obj = caller.search(args, candidates=caller.location.contents + caller.contents, use_nicks=True, quiet=True) if not looking_at_obj: # no object found. Check if there is a matching # detail at location. location = caller.location if location and hasattr(location, "return_detail") and callable(location.return_detail): detail = location.return_detail(args) if detail: # we found a detail instead. Show that. caller.msg(detail) return # no detail found. Trigger delayed error messages _AT_SEARCH_RESULT(looking_at_obj, caller, args, quiet=False) return else: # we need to extract the match manually. looking_at_obj = utils.make_iter(looking_at_obj)[0] else: looking_at_obj = caller.location if not looking_at_obj: caller.msg("You have no location to look at!") return if not hasattr(looking_at_obj, 'return_appearance'): # this is likely due to us having a player instead looking_at_obj = looking_at_obj.character if not looking_at_obj.access(caller, "view"): caller.msg("Could not find '%s'." % args) return # get object's appearance caller.msg(looking_at_obj.return_appearance(caller)) # the object's at_desc() method. looking_at_obj.at_desc(looker=caller)
def search_targets(self, namelist): """ Search a list of targets of the same type as caller. Args: caller (Object or Account): The type of object to search. namelist (list): List of strings for objects to search for. Returns: targetlist (list): List of matches, if any. """ nameregex = r"|".join(r"^%s$" % re.escape(name) for name in make_iter(namelist)) if hasattr(self.caller, "account") and self.caller.account: matches = list(ObjectDB.objects.filter(db_key__iregex=nameregex)) else: matches = list( AccountDB.objects.filter(username__iregex=nameregex)) return matches
def setup_home(self, owners=None, sethomespace=True): owners = utils.make_iter(owners) for owner in owners: self.add_homeowner(owner, sethomespace) self.tags.add("home") for ent in self.entrances: ent.locks.add("usekey: perm(builders) or roomkey(%s)" % self.id) if "HomeCmdSet" not in [ob.key for ob in self.cmdset.all()]: self.cmdset.add(HOMECMD, permanent=True) from world.dominion.models import AssetOwner try: # add our room owner as a homeowner if they're a player aowner = AssetOwner.objects.get(id=self.db.room_owner) char = aowner.player.player.char_ob if char not in owners: self.add_homeowner(char, False) except (AttributeError, AssetOwner.DoesNotExist, ValueError, TypeError): pass
def func(self): """Handle sensing objects in different ways. WIP: Expanding to handle other senses.""" char = self.character # player = self.player args = self.args.strip() cmd = self.cmdstring if cmd != 'l' and 'look' not in cmd: if 'sense' in cmd: if char and char.location: obj_list = char.search(args, candidates=[char.location] + char.location.contents + char.contents) if args else char if obj_list and obj_list.db.senses: char.msg('You can sense %s in the following ways: %s' % (obj_list, obj_list.db.senses.keys())) obj = obj_list verb_msg = "You can interact with %s: " % obj_list.get_display_name( self.session) else: obj = char verb_msg = "You can be interacted with by: " verbs = obj.locks collector = '' show_red = True if obj.access(char, 'examine') else False for verb in ("%s" % verbs).split(';'): element = verb.split(':')[0] if element == 'call': continue name = element[2:] if element[:2] == 'v-' else element if obj.access( char, element): # obj lock checked against actor collector += "|lctry %s #%s|lt|g%s|n|le " % ( name, obj.id, name) elif show_red: collector += "|r%s|n " % name char.msg(verb_msg + "%s" % collector) elif 'taste' in cmd or 'touch' in cmd or 'smell' in cmd or 'listen' in cmd: # Specific sense (not look) obj_list = char.search(args, candidates=[char.location] + char.location.contents + char.contents)\ if args else char char.msg('You try to sense %s.' % (obj_list if obj_list else 'something')) # Object to sense might have been found. Check the senses dictionary. if obj_list and obj_list.db.senses and cmd in obj_list.db.senses: senses_of = obj_list.db.senses[cmd] if None in senses_of: details_of = obj_list.db.details if details_of and senses_of[None] in details_of: entry = details_of[senses_of[None]] char.msg('You sense %s from %s.' % (entry, obj_list)) # First case: look for an object in room, inventory, room contents, their contents, # and their contents contents with tagged restrictions, then if no match is found # in their name or alias, look at the senses tables in each of these objects: The # Senses attribute is a dictionary of senses that point to the details dictionary # entries. Senses dictionary allows for aliases in the details and pointing # specific senses to specific entries. # # If not looking for a specific object or entry, list objects and aspects of the particular # sense. Start with that first, and start with the char's own self and inventory. # when the /self;me and /inv;inventory switch is used? return if args: # Parsing for object/aspect/detail: # Box's wheel = Red spinners lit with pyrotechnics. # object, aspect = args.rsplit("'s ", 1) # detail = self.rhs.strip() obj = char.search(args, candidates=char.location.contents + char.contents, use_nicks=True, quiet=True) if not obj: # no object found. Check if there is a matching detail around the location. # TODO: Restrict search for details by possessive parse: [object]'s [aspect] candidates = [char.location ] + char.location.contents + char.contents for location in candidates: # TODO: Continue if look location is not visible to looker. if location and hasattr(location, "return_detail") and callable( location.return_detail): detail = location.return_detail(args) if detail: # Show found detail. char.msg(detail) return # TODO: Add /all switch to override return here to view all details. # no detail found. Trigger delayed error messages _AT_SEARCH_RESULT(obj, char, args, quiet=False) return else: # we need to extract the match manually. obj = utils.make_iter(obj)[0] else: obj = char.location if not obj: char.msg("There is nothing to sense here.") return if not hasattr(obj, 'return_appearance'): # this is likely due to a player calling the command. obj = obj.character if not obj.access(char, 'view'): char.msg("You are unable to sense '%s'." % args) return # get object's appearance char.msg(obj.return_appearance(char)) # the object's at_desc() method. obj.at_desc(looker=char)
def prompt_choice(caller, question="", prompts=None, choicefunc=None, force_choose=False): """ This sets up a simple choice questionnaire. Question will be asked, followed by a series of prompts. Note that this isn't making use of the menu node system but uses the MenuCmdSet. Args: caller (object): The object calling and being offered the choice question (str, optional): Text describing the offered choice prompts (list, optional): List of strings defining the available choises. choicefunc (function, optional): A function called as `choicefunc(self)` when a choice is made. Inside this function, `self.caller` is available and `self.prompt_index` is the index (starting with 0) matching the chosen prompt in the `prompts` list. force_choose - force user to make a choice Examples: ```python def mychoice(self): self.caller.msg("Index of choice is %s." % self.prompt_index) prompt_choice(caller, "Make a choice:", prompts=["A","B","C"], choicefunc=mychoice) ``` When triggering the above from a command or @py prompt you get the following options: >>> Make a choice: [1] A [2] B [3] C <<< 2 >>> Index of choice is 1. """ # creating and defining commands count = 0 choices = "" commands = [] for choice in utils.make_iter(prompts): # create the available choice-commands count += 1 choices += "\n{lc%d{lt[%d]{le %s" % (count, count, choice) cmdfunc = CmdMenuNode(key="%d" % count) cmdfunc.prompt_index = count-1 if choicefunc: cmdfunc.choicefunc = choicefunc def _choicefunc(self): self.caller.cmdset.delete('menucmdset') del self.caller.db._menu_data self.choicefunc(self) # set a new method "callback" on cmdfunc cmdfunc.callback = MethodType(_choicefunc, cmdfunc, CmdMenuNode) commands.append(cmdfunc) if not force_choose: choices += "\n{lc{lt[No choice]{le" prompt = question + choices + "\nPlease choose one." # create the error-reporting command errorcmd = CmdMenuNode(key=CMD_NOMATCH) if force_choose: def _errorcmd(self): self.caller.msg("You can only choose given choices.") else: if choicefunc: errorcmd.choicefunc = choicefunc def _errorcmd(self): self.caller.msg("No choice.") self.caller.cmdset.delete('menucmdset') del self.caller.db._menu_data self.choicefunc(self) errorcmd.callback = MethodType(_errorcmd, errorcmd, CmdMenuNode) # create the fallback command defaultcmd = CmdMenuNode(key=CMD_NOINPUT) if force_choose: def _defaultcmd(self): caller.msg(prompt) else: if choicefunc: defaultcmd.choicefunc = choicefunc def _defaultcmd(self): self.caller.msg("No choice.") self.caller.cmdset.delete('menucmdset') del self.caller.db._menu_data self.choicefunc(self) defaultcmd.callback = MethodType(_defaultcmd, defaultcmd, CmdMenuNode) # creating cmdset (this will already have look/help commands) choicecmdset = MenuCmdSet() for cmdfunc in commands: choicecmdset.add(cmdfunc) choicecmdset.add(errorcmd) choicecmdset.add(defaultcmd) choicecmdset.add(CmdMenuLook()) choicecmdset.add(CmdMenuHelp()) # assigning menu data flags to caller. caller.db._menu_data = {"help": "Please select.", "look": prompt} # assign cmdset and ask question caller.cmdset.add(choicecmdset) caller.msg(prompt)
def match_string(criteria, string): string = make_iter(string) return True if string_partial_matching(string, criteria) else False
def prompt_choice(caller, question="", prompts=None, choicefunc=None, force_choose=False): """ This sets up a simple choice questionnaire. Question will be asked, followed by a series of prompts. Note that this isn't making use of the menu node system. caller - the object calling and being offered the choice question - text describing the offered choice prompts - list of choices choicefunc - functions callback to be called as func(self) when make choice (self.caller is available) The function's definition should be like func(self, menu_node), and menu_node.key is user's choice. force_choose - force user to make a choice or not """ # creating and defining commands count = 0 choices = "" commands = [] for choice in utils.make_iter(prompts): count += 1 choices += "\n{lc%d{lt[%d]{le %s" % (count, count, choice) cmdfunc = CmdMenuNode(key="%d" % count) if choicefunc: cmdfunc.choicefunc = choicefunc def _choicefunc(self): self.caller.cmdset.delete('menucmdset') del self.caller.db._menu_data self.choicefunc(self) cmdfunc.callback = MethodType(_choicefunc, cmdfunc, CmdMenuNode) commands.append(cmdfunc) if not force_choose: choices += "\n{lc{lt[No choice]{le" prompt = question + choices + "\nPlease choose one." errorcmd = CmdMenuNode(key=CMD_NOMATCH) if force_choose: def _errorcmd(self): self.caller.msg("You can only choose given choices.") else: if choicefunc: errorcmd.choicefunc = choicefunc def _errorcmd(self): self.caller.msg("No choice.") self.caller.cmdset.delete('menucmdset') del self.caller.db._menu_data self.choicefunc(self) errorcmd.callback = MethodType(_errorcmd, errorcmd, CmdMenuNode) defaultcmd = CmdMenuNode(key=CMD_NOINPUT) if force_choose: def _defaultcmd(self): caller.msg(prompt) else: if choicefunc: defaultcmd.choicefunc = choicefunc def _defaultcmd(self): self.caller.msg("No choice.") self.caller.cmdset.delete('menucmdset') del self.caller.db._menu_data self.choicefunc(self) defaultcmd.callback = MethodType(_defaultcmd, defaultcmd, CmdMenuNode) # creating cmdset (this will already have look/help commands) choicecmdset = MenuCmdSet() for cmdfunc in commands: choicecmdset.add(cmdfunc) choicecmdset.add(errorcmd) choicecmdset.add(defaultcmd) choicecmdset.add(CmdMenuLook()) choicecmdset.add(CmdMenuHelp()) # assigning menu data flags to caller. caller.db._menu_data = {"help": "Please select.", "look": prompt} # assign cmdset and ask question caller.cmdset.add(choicecmdset) caller.msg(prompt)
def func(self): """Create the nickname""" def _cy(string): "add color to the special markers" return re.sub(r"(\$[0-9]+|\*|\?|\[.+?\])", r"|Y\1|n", string) caller = self.caller switches = self.switches nicktypes = [ switch for switch in switches if switch in ("object", "account", "inputline") ] specified_nicktype = bool(nicktypes) nicktypes = nicktypes if specified_nicktype else ["inputline"] nicklist = ( utils.make_iter( caller.nicks.get(category="inputline", return_obj=True) or []) + utils.make_iter( caller.nicks.get(category="object", return_obj=True) or []) + utils.make_iter( caller.nicks.get(category="account", return_obj=True) or [])) if "list" in switches or self.cmdstring in ("nicks", ): if not nicklist: string = "|wNessun alias definito.|n" else: table = self.styled_table("#", "Type", "Nick match", "Replacement") for inum, nickobj in enumerate(nicklist): _, _, nickvalue, replacement = nickobj.value table.add_row( str(inum + 1), nickobj.db_category, _cy(nickvalue), _cy(replacement), ) string = "|wAlias definiti:|n\n%s" % table caller.msg(string) return if "clearall" in switches: caller.nicks.clear() caller.account.nicks.clear() caller.msg("Rimossi tutti gli alias.") return if "delete" in switches or "del" in switches: if not self.args or not self.lhs: caller.msg( "Uso: nick/delete <nick> OPPURE <#num> ('alias' per la lista)" ) return # see if a number was given arg = self.args.lstrip("#") oldnicks = [] if arg.isdigit(): # we are given a index in nicklist delindex = int(arg) if 0 < delindex <= len(nicklist): oldnicks.append(nicklist[delindex - 1]) else: caller.msg( "Non è un alias valido. Vedi 'alias' per la lista.") return else: if not specified_nicktype: nicktypes = ("object", "account", "inputline") for nicktype in nicktypes: oldnicks.append( caller.nicks.get(arg, category=nicktype, return_obj=True)) oldnicks = [oldnick for oldnick in oldnicks if oldnick] if oldnicks: for oldnick in oldnicks: nicktype = oldnick.category nicktypestr = "%s-nick" % nicktype.capitalize() _, _, old_nickstring, old_replstring = oldnick.value caller.nicks.remove(old_nickstring, category=nicktype) caller.msg("%s rimosso: '|w%s|n' -> |w%s|n." % (nicktypestr, old_nickstring, old_replstring)) else: caller.msg("Nessun alias corrispondente da rimuovere.") return if not self.rhs and self.lhs: # check what a nick is set to strings = [] if not specified_nicktype: nicktypes = ("object", "account", "inputline") for nicktype in nicktypes: nicks = [ nick for nick in utils.make_iter( caller.nicks.get(category=nicktype, return_obj=True)) if nick ] for nick in nicks: _, _, nick, repl = nick.value if nick.startswith(self.lhs): strings.append("{}-nick: '{}' -> '{}'".format( nicktype.capitalize(), nick, repl)) if strings: caller.msg("\n".join(strings)) else: caller.msg("Non è stato trovato nessun alias per '{}'".format( self.lhs)) return if not self.rhs and self.lhs: # check what a nick is set to strings = [] if not specified_nicktype: nicktypes = ("object", "account", "inputline") for nicktype in nicktypes: if nicktype == "account": obj = account else: obj = caller nicks = utils.make_iter( obj.nicks.get(category=nicktype, return_obj=True)) for nick in nicks: _, _, nick, repl = nick.value if nick.startswith(self.lhs): strings.append("{}-nick: '{}' -> '{}'".format( nicktype.capitalize(), nick, repl)) if strings: caller.msg("\n".join(strings)) else: caller.msg("Non è stato trovato nessun alias per '{}'".format( self.lhs)) return if not self.rhs and self.lhs: # check what a nick is set to strings = [] if not specified_nicktype: nicktypes = ("object", "account", "inputline") for nicktype in nicktypes: if nicktype == "account": obj = account else: obj = caller nicks = utils.make_iter( obj.nicks.get(category=nicktype, return_obj=True)) for nick in nicks: _, _, nick, repl = nick.value if nick.startswith(self.lhs): strings.append("{}-nick: '{}' -> '{}'".format( nicktype.capitalize(), nick, repl)) if strings: caller.msg("\n".join(strings)) else: caller.msg("Non è stato trovato nessun alias per '{}'".format( self.lhs)) return if not self.args or not self.lhs: caller.msg("Uso: nick[/switches] <alias> = [nome completo]") return # setting new nicks nickstring = self.lhs replstring = self.rhs if replstring == nickstring: caller.msg( "Non ha senso settare un alias uguale al nome da rimpiazzare..." ) return # check so we have a suitable nick type errstring = "" string = "" for nicktype in nicktypes: nicktypestr = "%s-nick" % nicktype.capitalize() old_nickstring = None old_replstring = None oldnick = caller.nicks.get(key=nickstring, category=nicktype, return_obj=True) if oldnick: _, _, old_nickstring, old_replstring = oldnick.value if replstring: # creating new nick errstring = "" if oldnick: if replstring == old_replstring: string += "\nGià presente: %s." % nicktypestr.lower() else: string += "\n%s '|w%s|n' aggiornato: '|w%s|n'." % ( nicktypestr, old_nickstring, replstring, ) else: string += "\n%s '|w%s|n' impostato: '|w%s|n'." % ( nicktypestr, nickstring, replstring, ) try: caller.nicks.add(nickstring, replstring, category=nicktype) except NickTemplateInvalid: caller.msg( "È necessario usare gli stessi $-markers sia nell'alias che nel testo da rimpiazzare." ) return elif old_nickstring and old_replstring: # just looking at the nick string += "\n%s '|w%s|n' sostituisce: '|w%s|n'." % ( nicktypestr, old_nickstring, old_replstring, ) errstring = "" string = errstring if errstring else string caller.msg(_cy(string))
def func(self): """Handle sensing objects in different ways, including look.""" char = self.character here = char.location if char else None account = self.account if not (char and here): account.msg('You sense only |222Nothingness|n.') message = '|gback|n or |ghome' if char else '|g@ic' account.msg('(Type %s|n to return to the NOW.)' % message) return args = self.args.strip() cmd = self.cmdstring lhs = self.lhs.strip() rhs = self.rhs obj_string, aspect = [lhs, None] if "'s " not in lhs else lhs.rsplit("'s ", 1) if obj_string and obj_string.lower() in ('outside', 'out') and here and here.location: char.msg('From within {}, you see:'.format(here.get_display_name(char))) obj = [here.location] else: obj = char.search(obj_string, quiet=True, candidates=[here] + here.contents + char.contents) if args else [char] if obj: obj = obj[0] obj_string = obj.key else: _AT_SEARCH_RESULT(obj, char, args, quiet=False) return # Trying to sense something that isn't there. "Could not find ''." style = obj.STYLE if obj and hasattr(obj, 'STYLE') else '|g' if cmd == 'glance': if here and not args: obj = here sights = obj.return_glance(char) if sights: account.msg('|/You glance at %s and see: %s ' % (obj.get_display_name(char), sights)) else: account.msg('|/You glance at %s, but see nothing.' % obj.get_display_name(char)) return # senses = obj.db.senses # details = obj.db.details if self.rhs is not None: # Equals sign exists. if not self.rhs: # Nothing on the right side # TODO: Delete and verify intent with switches. Mock-up command without switches. # Scan senses before deleting details - make sure not to remove detail if another sense uses it. account.msg('Functionality to delete aspects and details is not yet implemented.' % self.switches) if aspect: account.msg("|w%s|n (object) %s%s|n's |g%s|n (aspect) = |r (detail removed)" % (cmd, style, obj_string, aspect)) else: account.msg("|w%s|n (object) %s%s|n = |r (detail removed)" % (cmd, style, obj_string)) else: # TODO: Add and verify intent with switches. Mock-up command without switches. account.msg('Functionality to add aspects and details is not yet implemented.' % self.switches) if aspect: account.msg("|w%s|n (object) %s%s|n's |g%s|n (aspect) = |c%s|n (detail)" % (cmd, style, obj_string, aspect, rhs)) else: account.msg("|w%s|n (object) %s%s|n = |c%s|n (detail)" % (cmd, style, obj_string, rhs)) return if cmd != 'l' and 'look' not in cmd: # Doing non-LOOK stuff in here. if 'sense' in cmd: char.msg('|wSensing...') if obj: if obj.db.senses: # Object must be database object to be sensed. string = '* Senses available for %s: ' % obj.get_display_name(account) string += ", ".join('|lc%s %s|lt|g%s|n|le' % (element, obj.get_display_name(char, plain=True), element) for element in obj.db.senses.keys()) char.msg(string) aspect_list = [] # list aspects. for element in obj.db.senses.keys(): for aspect in obj.db.senses[element].keys(): aspect_list.append("|lc%s %s's %s|lt|g%s|n|le " % (element, obj.key, aspect, aspect) if aspect else '') if len(aspect_list) > 0: char.msg(obj.get_display_name(account) + ' has the following aspects that can be sensed: ' + ''.join(aspect_list)) if obj != char: verb_msg = "%s responds to: " % obj.get_display_name(account) else: verb_msg = "%sYou|n respond to: " % char.STYLE verbs = obj.locks collector_list = [] show_red = True if obj.access(char, 'examine') else False for verb in ("%s" % verbs).split(';'): element = verb.split(':')[0] if element == 'call': continue name = element[2:] if element[:2] == 'v-' else element if obj.access(char, element): # obj lock checked against actor collector_list.append("|lctry %s %s|lt|g%s|n|le " % (name, obj.get_display_name(char, plain=True), name)) elif show_red: collector_list.append("|r%s|n " % name) char.msg(verb_msg + ''.join(collector_list)) elif 'taste' in cmd or 'touch' in cmd or 'smell' in cmd or 'listen' in cmd: # Specific sense (not look) if not obj: return # Object to sense might have been found. Check the senses dictionary. if obj.db.senses and cmd in obj.db.senses: senses_of = obj.db.senses[cmd] # senses_of is the sense dictionary for current sense. if aspect in senses_of: details_of = obj.db.details if details_of and senses_of[aspect] in details_of: entry = details_of[senses_of[aspect]] char.msg('%sYou|n sense %s from %s.' % (char.STYLE, entry, obj.get_display_name(account))) else: if aspect: char.msg("%sYou|n try to %s %s's %s, but can not." % (char.STYLE, cmd, obj.get_display_name(account), aspect)) else: char.msg("%sYou|n try to %s %s, but can not." % (char.STYLE, cmd, obj.get_display_name(account))) else: if aspect: char.msg("%sYou|n try to %s %s's %s, but can not." % (char.STYLE, cmd, obj.get_display_name(account), aspect)) else: char.msg("%sYou|n try to %s %s, but can not." % (char.STYLE, cmd, obj.get_display_name(account))) else: char.msg('%sYou|n try to %s %s, but can not.' % (char.STYLE, cmd, obj.get_display_name(account))) # First case: look for an object in room, inventory, room contents, their contents, # and their contents contents with tagged restrictions, then if no match is found # in their name or alias, look at the senses tables in each of these objects: The # Senses attribute is a dictionary of senses that point to the details dictionary # entries. Senses dictionary allows for aliases in the details and pointing # specific senses to specific entries. # # If not looking for a specific object or entry, list objects and aspects of the particular # sense. Start with that first, and start with the char's own self and inventory. # when the /self;me and /inv;inventory switch is used? return if args: # < LOOK begins here. ------------------------------------------- > if not obj: # If no object was found, then look for a detail on the object. # no object found. Check if there is a matching detail around the location. # TODO: Restrict search for details by possessive parse: [object]'s [aspect] candidates = [here] + here.contents + char.contents for location in candidates: # TODO: Continue if look location is not visible to looker. if location and hasattr(location, "return_detail") and callable(location.return_detail): detail = location.return_detail(args) if detail: char.msg(detail) # Show found detail. return # TODO: Add /all switch to override return here to view all details. _AT_SEARCH_RESULT(obj, char, args, quiet=False) # no detail found. Trigger delayed error messages return else: obj = utils.make_iter(obj)[0] # Use the first match in the list. else: obj = here if not obj.access(char, 'view'): char.msg("You are unable to sense '%s'." % args) return account.msg(obj.return_appearance(char)) # get object's appearance as seen by char obj.at_desc(looker=char) # the object's at_desc() method - includes look-notify.
def search( self, searchdata, global_search=False, use_nicks=True, typeclass=None, location=None, attribute_name=None, quiet=False, exact=False, candidates=None, nofound_string=None, multimatch_string=None, use_dbref=None, ): """ Returns an Object matching a search string/condition Perform a standard object search in the database, handling multiple results and lack thereof gracefully. By default, only objects in the current `location` of `self` or its inventory are searched for. Args: searchdata (str or obj): Primary search criterion. Will be matched against `object.key` (with `object.aliases` second) unless the keyword attribute_name specifies otherwise. **Special strings:** - `#<num>`: search by unique dbref. This is always a global search. - `me,self`: self-reference to this object - `<num>-<string>` - can be used to differentiate between multiple same-named matches. The exact form of this input is given by `settings.SEARCH_MULTIMATCH_REGEX`. global_search (bool): Search all objects globally. This overrules 'location' data. use_nicks (bool): Use nickname-replace (nicktype "object") on `searchdata`. typeclass (str or Typeclass, or list of either): Limit search only to `Objects` with this typeclass. May be a list of typeclasses for a broader search. location (Object or list): Specify a location or multiple locations to search. Note that this is used to query the *contents* of a location and will not match for the location itself - if you want that, don't set this or use `candidates` to specify exactly which objects should be searched. attribute_name (str): Define which property to search. If set, no key+alias search will be performed. This can be used to search database fields (db_ will be automatically prepended), and if that fails, it will try to return objects having Attributes with this name and value equal to searchdata. A special use is to search for "key" here if you want to do a key-search without including aliases. quiet (bool): don't display default error messages - this tells the search method that the user wants to handle all errors themselves. It also changes the return value type, see below. exact (bool): if unset (default) - prefers to match to beginning of string rather than not matching at all. If set, requires exact matching of entire string. candidates (list of objects): this is an optional custom list of objects to search (filter) between. It is ignored if `global_search` is given. If not set, this list will automatically be defined to include the location, the contents of location and the caller's contents (inventory). nofound_string (str): optional custom string for not-found error message. multimatch_string (str): optional custom string for multimatch error header. use_dbref (bool or None, optional): If `True`, allow to enter e.g. a query "#123" to find an object (globally) by its database-id 123. If `False`, the string "#123" will be treated like a normal string. If `None` (default), the ability to query by #dbref is turned on if `self` has the permission 'Builder' and is turned off otherwise. Returns: match (Object, None or list): will return an Object/None if `quiet=False`, otherwise it will return a list of 0, 1 or more matches. Notes: To find Accounts, use eg. `evennia.account_search`. If `quiet=False`, error messages will be handled by `settings.SEARCH_AT_RESULT` and echoed automatically (on error, return will be `None`). If `quiet=True`, the error messaging is assumed to be handled by the caller. """ is_string = isinstance(searchdata, str) if is_string: # searchdata is a string; wrap some common self-references if searchdata.lower() in ("here", ): return [self.location] if quiet else self.location if searchdata.lower() in ("me", "self"): return [self] if quiet else self if use_dbref is None: use_dbref = self.locks.check_lockstring(self, "_dummy:perm(Builder)") if use_nicks: # do nick-replacement on search searchdata = self.nicks.nickreplace(searchdata, categories=("objet", "account"), include_account=True) if global_search or (is_string and searchdata.startswith("#") and len(searchdata) > 1 and searchdata[1:].isdigit()): # only allow exact matching if searching the entire database # or unique #dbrefs exact = True candidates = None elif candidates is None: # no custom candidates given - get them automatically if location: # location(s) were given candidates = [] for obj in make_iter(location): candidates.extend(obj.contents) else: # local search. Candidates are taken from # self.contents, self.location and # self.location.contents location = self.location candidates = self.contents if location: candidates = candidates + [location] + location.contents else: # normally we don't need this since we are # included in location.contents candidates.append(self) results = ObjectDB.objects.object_search( searchdata, attribute_name=attribute_name, typeclass=typeclass, candidates=candidates, exact=exact, use_dbref=use_dbref, ) if quiet: return list(results) return _AT_SEARCH_RESULT( results, self, query=searchdata, nofound_string=nofound_string, multimatch_string=multimatch_string, )
def func(self): """ Handle the looking - add fallback to details. """ caller = self.caller args = self.args looking_at_obj = None if args: alist = args.split("'s ") if len(alist) == 2: obj = caller.search(alist[0], use_nicks=True, quiet=True) if obj: obj = utils.make_iter(obj) looking_at_obj = caller.search(alist[1], location=obj[0], use_nicks=True, quiet=True) else: looking_at_obj = caller.search(args, use_nicks=True, quiet=True) # originally called search with invalid arg of no_error or something instead of quiet if not looking_at_obj: # no object found. Check if there is a matching # detail at location. if self.check_detail(): return # no detail found. Trigger delayed error messages _AT_SEARCH_RESULT(looking_at_obj, caller, args, False) return else: # we need to extract the match manually. if len(utils.make_iter(looking_at_obj)) > 1: _AT_SEARCH_RESULT(looking_at_obj, caller, args, False) self.check_detail() return looking_at_obj = utils.make_iter(looking_at_obj)[0] else: looking_at_obj = caller.location if not looking_at_obj: caller.msg("You have no location to look at!") return if not hasattr(looking_at_obj, "return_appearance"): # this is likely due to us having a player instead looking_at_obj = looking_at_obj.character if not looking_at_obj.access(caller, "view"): caller.msg("Could not find '%s'." % args) self.check_detail() return # get object's appearance desc = looking_at_obj.return_appearance(caller, detailed=False) # if it's a written object, we'll paginate the description if looking_at_obj.db.written: from server.utils import arx_more desc = desc.replace("%r", "\n") arx_more.msg(caller, desc, pages_by_char=True) else: caller.msg(desc) # the object's at_desc() method. looking_at_obj.at_desc(looker=caller) self.check_detail()
def func(self): """Handle sensing objects in different ways. WIP: Expanding to handle other senses.""" char = self.character # player = self.player args = self.args.strip() cmd = self.cmdstring if cmd != 'l' and 'look' not in cmd: if 'sense' in cmd: if char and char.location: obj_list = char.search(args, candidates=[char.location] + char.location.contents + char.contents) if args else char if obj_list and obj_list.db.senses: char.msg('You can sense %s in the following ways: %s' % (obj_list, obj_list.db.senses.keys())) obj = obj_list verb_msg = "You can interact with %s: " % obj_list.get_display_name(self.session) else: obj = char verb_msg = "You can be interacted with by: " verbs = obj.locks collector = '' show_red = True if obj.access(char, 'examine') else False for verb in ("%s" % verbs).split(';'): element = verb.split(':')[0] if element == 'call': continue name = element[2:] if element[:2] == 'v-' else element if obj.access(char, element): # obj lock checked against actor collector += "|lctry %s #%s|lt|g%s|n|le " % (name, obj.id, name) elif show_red: collector += "|r%s|n " % name char.msg(verb_msg + "%s" % collector) elif 'taste' in cmd or 'touch' in cmd or 'smell' in cmd or 'listen' in cmd: # Specific sense (not look) obj_list = char.search(args, candidates=[char.location] + char.location.contents + char.contents)\ if args else char char.msg('You try to sense %s.' % (obj_list if obj_list else 'something')) # Object to sense might have been found. Check the senses dictionary. if obj_list and obj_list.db.senses and cmd in obj_list.db.senses: senses_of = obj_list.db.senses[cmd] if None in senses_of: details_of = obj_list.db.details if details_of and senses_of[None] in details_of: entry = details_of[senses_of[None]] char.msg('You sense %s from %s.' % (entry, obj_list)) # First case: look for an object in room, inventory, room contents, their contents, # and their contents contents with tagged restrictions, then if no match is found # in their name or alias, look at the senses tables in each of these objects: The # Senses attribute is a dictionary of senses that point to the details dictionary # entries. Senses dictionary allows for aliases in the details and pointing # specific senses to specific entries. # # If not looking for a specific object or entry, list objects and aspects of the particular # sense. Start with that first, and start with the char's own self and inventory. # when the /self;me and /inv;inventory switch is used? return if args: # Parsing for object/aspect/detail: # Box's wheel = Red spinners lit with pyrotechnics. # object, aspect = args.rsplit("'s ", 1) # detail = self.rhs.strip() obj = char.search(args, candidates=char.location.contents + char.contents, use_nicks=True, quiet=True) if not obj: # no object found. Check if there is a matching detail around the location. # TODO: Restrict search for details by possessive parse: [object]'s [aspect] candidates = [char.location] + char.location.contents + char.contents for location in candidates: # TODO: Continue if look location is not visible to looker. if location and hasattr(location, "return_detail") and callable(location.return_detail): detail = location.return_detail(args) if detail: # Show found detail. char.msg(detail) return # TODO: Add /all switch to override return here to view all details. # no detail found. Trigger delayed error messages _AT_SEARCH_RESULT(obj, char, args, quiet=False) return else: # we need to extract the match manually. obj = utils.make_iter(obj)[0] else: obj = char.location if not obj: char.msg("There is nothing to sense here.") return if not hasattr(obj, 'return_appearance'): # this is likely due to a player calling the command. obj = obj.character if not obj.access(char, 'view'): char.msg("You are unable to sense '%s'." % args) return # get object's appearance char.msg(obj.return_appearance(char)) # the object's at_desc() method. obj.at_desc(looker=char)
def prompt_choice(caller, question="", prompts=None, choicefunc=None, force_choose=False): """ This sets up a simple choice questionnaire. Question will be asked, followed by a series of prompts. Note that this isn't making use of the menu node system but uses the MenuCmdSet. Args: caller (object): The object calling and being offered the choice question (str, optional): Text describing the offered choice prompts (list, optional): List of strings defining the available choises. choicefunc (function, optional): A function called as `choicefunc(self)` when a choice is made. Inside this function, `self.caller` is available and `self.prompt_index` is the index (starting with 0) matching the chosen prompt in the `prompts` list. force_choose - force user to make a choice Examples: ```python def mychoice(self): self.caller.msg("Index of choice is %s." % self.prompt_index) prompt_choice(caller, "Make a choice:", prompts=["A","B","C"], choicefunc=mychoice) ``` When triggering the above from a command or @py prompt you get the following options: >>> Make a choice: [1] A [2] B [3] C <<< 2 >>> Index of choice is 1. """ # creating and defining commands count = 0 choices = "" commands = [] for choice in utils.make_iter(prompts): # create the available choice-commands count += 1 choices += "\n{lc%d{lt[%d]{le %s" % (count, count, choice) cmdfunc = CmdMenuNode(key="%d" % count) cmdfunc.prompt_index = count - 1 if choicefunc: cmdfunc.choicefunc = choicefunc def _choicefunc(self): self.caller.cmdset.delete('menucmdset') del self.caller.db._menu_data self.choicefunc(self) # set a new method "callback" on cmdfunc cmdfunc.callback = MethodType(_choicefunc, cmdfunc, CmdMenuNode) commands.append(cmdfunc) if not force_choose: choices += "\n{lc{lt[No choice]{le" prompt = question + choices + "\nPlease choose one." # create the error-reporting command errorcmd = CmdMenuNode(key=CMD_NOMATCH) if force_choose: def _errorcmd(self): self.caller.msg("You can only choose given choices.") else: if choicefunc: errorcmd.choicefunc = choicefunc def _errorcmd(self): self.caller.msg("No choice.") self.caller.cmdset.delete('menucmdset') del self.caller.db._menu_data self.choicefunc(self) errorcmd.callback = MethodType(_errorcmd, errorcmd, CmdMenuNode) # create the fallback command defaultcmd = CmdMenuNode(key=CMD_NOINPUT) if force_choose: def _defaultcmd(self): caller.msg(prompt) else: if choicefunc: defaultcmd.choicefunc = choicefunc def _defaultcmd(self): self.caller.msg("No choice.") self.caller.cmdset.delete('menucmdset') del self.caller.db._menu_data self.choicefunc(self) defaultcmd.callback = MethodType(_defaultcmd, defaultcmd, CmdMenuNode) # creating cmdset (this will already have look/help commands) choicecmdset = MenuCmdSet() for cmdfunc in commands: choicecmdset.add(cmdfunc) choicecmdset.add(errorcmd) choicecmdset.add(defaultcmd) choicecmdset.add(CmdMenuLook()) choicecmdset.add(CmdMenuHelp()) # assigning menu data flags to caller. caller.db._menu_data = {"help": "Please select.", "look": prompt} # assign cmdset and ask question caller.cmdset.add(choicecmdset) caller.msg(prompt)
def func(self): """ Handle the looking - add fallback to details. """ caller = self.caller args = self.args if args: looking_at_obj = caller.search(args, use_nicks=True, quiet=True) if not looking_at_obj: # no object found. Check if there is a matching # detail at location. location = caller.location if location and hasattr(location, "return_detail") and callable( location.return_detail): detail = location.return_detail(args) if detail: # we found a detail instead. Show that. caller.msg("{y%s{n\n" % args + detail) return # no detail found. Trigger delayed error messages _AT_SEARCH_RESULT(caller, args, looking_at_obj, False) return else: if len(looking_at_obj) > 1: caller.msg( "Есть несколько объектов с таким именем(укажи нужный):" ) i = 1 for item in looking_at_obj: if item.has_player: caller.msg("%s-%s (Игрок)" % (i, item.key)) elif item.db.is_corpse: caller.msg("%s-%s (Труп)" % (i, item.key)) elif item.db.npc: caller.msg("%s-%s (NPC)" % (i, item.key)) elif item.db.is_weapon: caller.msg("%s-%s (Оружие)" % (i, item.key)) else: caller.msg("%s-%s (Объект)" % (i, item.key)) i = i + 1 return else: # we need to extract the match manually. looking_at_obj = utils.make_iter(looking_at_obj)[0] else: looking_at_obj = caller.location if not looking_at_obj: caller.msg("Тебе некуда смотреть!") return if not hasattr(looking_at_obj, 'return_appearance'): # this is likely due to us having a player instead looking_at_obj = looking_at_obj.character if not looking_at_obj.access(caller, "view"): caller.msg("Не могу найти '%s'." % args) return # get object's appearance caller.msg(looking_at_obj.return_appearance(caller)) # the object's at_desc() method. looking_at_obj.at_desc(looker=caller)