def test_list_to_string(self): self.assertEqual('1, 2, 3', utils.list_to_string([1, 2, 3], endsep="")) self.assertEqual( '"1", "2", "3"', utils.list_to_string([1, 2, 3], endsep="", addquote=True)) self.assertEqual('1, 2 and 3', utils.list_to_string([1, 2, 3])) self.assertEqual( '"1", "2" and "3"', utils.list_to_string([1, 2, 3], endsep="and", addquote=True))
def return_appearance(self, looker, **kwargs): """ This formats a description. It is the hook a 'look' command should call. Args: looker (Object): Object doing the looking. **kwargs (dict): Arbitrary, optional arguments for users overriding the call (unused by default). """ if not looker: return "" # get and identify all objects visible = (con for con in self.contents if con != looker and con.access(looker, "view")) exits, users, things = [], [], defaultdict(list) for con in visible: key = con.get_display_name(looker) if con.destination: exits.append(key) elif con.has_account: users.append("|c%s|n" % key) else: # things can be pluralized things[key].append(con) # get description, build string string = "|c%s|n\n" % self.get_display_name(looker) desc = self.db.desc if desc: string += "%s" % desc if exits: string += "\n|wExits:|n " + list_to_string(exits) if users or things: # handle pluralization of things (never pluralize users) thing_strings = [] for key, itemlist in sorted(things.items()): nitem = len(itemlist) if nitem == 1: if itemlist[ 0].stack.stackable and itemlist[0].stack.count > 1: key = itemlist[0].get_numbered_name( itemlist[0].stack.count, looker, key=key)[1] else: key, _ = itemlist[0].get_numbered_name(nitem, looker, key=key) else: key = [ item.get_numbered_name(nitem, looker, key=key)[1] for item in itemlist ][0] thing_strings.append(key) string += "\n|wYou see:|n " + list_to_string(users + thing_strings) return string
def func(self): ch = self.caller ch.msg(self.args) args = self.args.strip() zonedb = dict(GLOBAL_SCRIPTS.zonedb.vnum) if not zonedb: ch.msg("There are no zones within the game") return vnum_zonedb = zonedb.keys() min_ = min(vnum_zonedb) max_ = max(vnum_zonedb) legend = ["VNum", "Name", "Builders"] try: _ = zonedb[1] except KeyError: ch.msg("No zones are saved to database, try creating one first") return if not args: table = self.styled_table(*legend, border='incols') for vnum in range(min_, max_ + 1): data = zonedb[vnum] vnum = raw_ansi(f"[|G{vnum:<4}|n]") table.add_row(vnum, data['name'], list_to_string(data['builders'])) msg = str(table) ch.msg(msg) return args = args.split(' ') if len(args) < 2: ch.msg("Supply name to search for") return table = self.styled_table(*legend, border='incols') type_ = args[0] if type_ not in ('name'): ch.msg("Please supply name to search by") return criteria = args[1] for vnum in range(min_, max_ + 1): # for vnum, data in GLOBAL_SCRIPTS.objdb.vnum.items(): data = zonedb[vnum] if type_ == 'name': if match_string(criteria, data['name'].split()): vnum = raw_ansi(f"[|G{vnum:<4}|n]") table.add_row(vnum, data['name'], list_to_string(data['builders'])) continue msg = str(table) ch.msg(msg) return
def remove(self, wearer, quiet=False): """ Removes worn clothes and optionally echoes to the room. Args: wearer (obj): character object wearing this clothing object Kwargs: quiet (bool): If false, does not message the room """ self.db.worn = False remove_message = "%s removes %s." % (wearer, self.name) uncovered_list = [] # Check to see if any other clothes are covered by this object. for thing in wearer.contents: # If anything is covered by if thing.db.covered_by == self: thing.db.covered_by = False uncovered_list.append(thing.name) if len(uncovered_list) > 0: remove_message = "%s removes %s, revealing %s." % (wearer, self.name, list_to_string(uncovered_list)) # Echo a message to the room if not quiet: wearer.location.msg_contents(remove_message)
def wear(self, wearer, wearstyle, quiet=False): """ Sets clothes to 'worn' and optionally echoes to the room. Args: wearer (obj): character object wearing this clothing object wearstyle (True or str): string describing the style of wear or True for none quiet (bool): If false, does not message the room Notes: Optionally sets db.worn with a 'wearstyle' that appends a short passage to the end of the name of the clothing to describe how it's worn that shows up in the wearer's desc - I.E. 'around his neck' or 'tied loosely around her waist'. If db.worn is set to 'True' then just the name will be shown. """ # Set clothing as worn self.db.worn = wearstyle # Auto-cover appropriate clothing types, as specified above to_cover = [] if self.db.clothing_type and self.db.clothing_type in CLOTHING_TYPE_AUTOCOVER: for garment in get_worn_clothes(wearer): if garment.db.clothing_type and garment.db.clothing_type \ in CLOTHING_TYPE_AUTOCOVER[self.db.clothing_type]: to_cover.append(garment) garment.db.covered_by = self if quiet: return # Otherwise, display a message to the room message = "{wearer} puts on {item}" if wearstyle and wearstyle is not True: message = "{wearer} wears {item} %s" % wearstyle if to_cover: message = message + ", covering %s" % list_to_string(to_cover) wearer.location.msg_contents(message + ".", mapping=dict(wearer=wearer, item=self))
def wear(self, wearer, wearstyle, quiet=False): """ Sets clothes to 'worn' and optionally echoes to the room. Args: wearer (obj): character object wearing this clothing object wearstyle (True or str): string describing the style of wear or True for none quiet (bool): If false, does not message the room Notes: Optionally sets db.worn with a 'wearstyle' that appends a short passage to the end of the name of the clothing to describe how it's worn that shows up in the wearer's desc - I.E. 'around his neck' or 'tied loosely around her waist'. If db.worn is set to 'True' then just the name will be shown. """ # Set clothing as worn self.db.worn = wearstyle # Auto-cover appropriate clothing types, as specified above to_cover = [] if self.db.clothing_type and self.db.clothing_type in CLOTHING_TYPE_AUTOCOVER: for garment in get_worn_clothes(wearer): if garment.db.clothing_type and garment.db.clothing_type \ in CLOTHING_TYPE_AUTOCOVER[self.db.clothing_type]: to_cover.append(garment) garment.db.covered_by = self if quiet: return # Otherwise, display a message to the room message = "{wearer} puts on {item}" if wearstyle and wearstyle is not True: message = "{wearer} wears {item} %s" % wearstyle if to_cover: message = message + ", covering %s" % list_to_string(to_cover) wearer.location.msg_contents(message + ".", mapping=dict(wearer=wearer, item=self))
def remove(self, wearer, quiet=False): """ Removes worn clothes and optionally echoes to the room. Args: wearer (obj): character object wearing this clothing object Kwargs: quiet (bool): If false, does not message the room """ self.db.worn = False remove_message = "%s removes %s." % (wearer, self.name) uncovered_list = [] # Check to see if any other clothes are covered by this object. for thing in wearer.contents: # If anything is covered by if thing.db.covered_by == self: thing.db.covered_by = False uncovered_list.append(thing.name) if len(uncovered_list) > 0: remove_message = "%s removes %s, revealing %s." % (wearer, self.name, list_to_string(uncovered_list)) # Echo a message to the room if not quiet: wearer.location.msg_contents(remove_message)
def pretty_special(character, specialname): "Returns a pretty-looking readout of a special move." effectlist = character.db.Special_Moves[specialname][1] effectstring = utils.list_to_string(effectlist, endsep="|255and|455", addquote=False) effectstringlength = len(effectstring) if "|255and|455" in effectstring: effectstringlength -= 8 specialdesc = character.db.Special_Moves[specialname][2] paddinglength = max((80 - effectstringlength - len(specialname) - 9), 0) padding = ('{:-^%i}' % paddinglength).format('') text = "|455%s |255[|455%s|255] %s |455%i|255 SP|n\n%s" % (specialname, effectstring, padding, rules.special_cost(effectlist), specialdesc) return text
def node_join_room(caller, raw_string, **kwargs): room = kwargs["room"] stats = room.db.stats or {"progress": 0} players = [char.key for char in room.get_all_characters()] text = _JOIN_EXISTING_ROOM_TEXT.format( roomname=room.get_display_name(caller), percent=int(stats["progress"]), nplayers=len(players), players=list_to_string(players), ) options = ( {"key": ("|g[a]ccept|n (default)", "a"), "goto": (_move_to_room, kwargs)}, {"key": ("|r[c]ancel|n", "c"), "goto": "node_start"}, {"key": "_default", "goto": (_move_to_room, kwargs)}, ) return text, options
def return_appearance(self, looker): """ This formats a description. It is the hook a 'look' command should call. Args: looker (Object): Object doing the looking. Notes: The name of every clothing item carried and worn by the character is appended to their description. If the clothing's db.worn value is set to True, only the name is appended, but if the value is a string, the string is appended to the end of the name, to allow characters to specify how clothing is worn. """ if not looker: return "" # get description, build string string = "|c%s|n\n" % self.get_display_name(looker) desc = self.db.desc worn_string_list = [] clothes_list = get_worn_clothes(self, exclude_covered=True) # Append worn, uncovered clothing to the description for garment in clothes_list: # If 'worn' is True, just append the name if garment.db.worn is True: worn_string_list.append(garment.name) # Otherwise, append the name and the string value of 'worn' elif garment.db.worn: worn_string_list.append("%s %s" % (garment.name, garment.db.worn)) if desc: string += "%s" % desc # Append worn clothes. if worn_string_list: string += "|/|/%s is wearing %s." % ( self, list_to_string(worn_string_list)) else: string += "|/|/%s is not wearing anything." % self return string
def ms_withdraw(mover, target, distance, mode): # Performs multiple withdraw steps and spits out the result. moves = 0 blocks = 0 blockers = [] steps = distance while steps > 0: result = withdraw(mover, target, mode) if result[0] == "move": moves += 1 elif result[0] == "block": blocks += 1 if not result[1] in blockers: blockers.append(result[1]) elif result[0] == "stop": steps = 0 steps -= 1 # Then spit out a pretty message detailing what happened. if moves == 1: pluralmove = "step" else: pluralmove = "steps" if blocks == 1: pluralblock = "step" else: pluralblock = "steps" newrange = mover.db.Combat_Range[target] stringofblockers = utils.list_to_string(blockers, endsep="and", addquote=False) if mode == "normal": if moves > 0 and blocks == 0: mover.location.msg_contents("%s withdraws to %s range with %s! |552[|554%i|552 %s]|n" % (mover, rules.range_name(newrange).lower(), target, moves, pluralmove)) elif moves > 0 and blocks > 0: mover.location.msg_contents("%s has some movement blocked by %s, but withdraws to %s range with %s! |552[|554%i|552 %s, |554%i|552 blocked]|n" % (mover, stringofblockers, rules.range_name(newrange).lower(), target, moves, pluralmove, blocks)) elif moves == 0 and blocks > 0: mover.location.msg_contents("%s tries to withdraw from %s, but is blocked by %s! |552[|554%i|552 %s blocked]|n" % (mover, target, stringofblockers, blocks, pluralblock)) elif mode == "forced": mover.location.msg_contents("%s is pushed back to %s range with %s! |552[Forced |554%i|552 %s]|n" % (mover, rules.range_name(newrange).lower(), target, moves, pluralmove)) elif mode == "free": mover.location.msg_contents("%s withdraws to %s range with %s! |552[Free |554%i|552 %s]|n" % (mover, rules.range_name(newrange).lower(), target, moves, pluralmove))
def summarize(self): exit_summary = "" for ename, rvnum in self.obj['exits'].items(): room = "" if get_room(rvnum) is None else get_room(rvnum).db.name exit_summary += f" |y{ename.capitalize():<5}|n: {rvnum:<7} {room:<15}\n" edesc_msg = "" for key, edesc in self.obj['edesc'].items(): edesc_msg += f"|c{key}|n:\n{crop(edesc)}\n" room_flags = list_to_string(self.obj['flags']) sector = self.obj['type'] sector_symbol = VALID_ROOM_SECTORS[self.obj['type']].symbol status = "(|rCAN NOT EDIT|n)" if self.obj['zone'] != has_zone( self.caller) else "" msg = f""" ********Room Summary******* {status} VNUM: [{self.vnum}] ZONE:[|m{self.obj['zone']}|n] name : |y{self.obj['name']}|n desc : |y{self.obj['desc']}|n flags : |y{room_flags}|n sector : |m{sector}|n, [{sector_symbol}] exits : {exit_summary} edesc : {edesc_msg} ----------------Extras--------------------- """ for efield, evalue in self.obj['extra'].items(): msg += f"{efield:<7}: {crop(evalue, width=50)}\n" self.caller.msg(msg)
def return_appearance(self, looker): """ This formats a description. It is the hook a 'look' command should call. Args: looker (Object): Object doing the looking. Notes: The name of every clothing item carried and worn by the character is appended to their description. If the clothing's db.worn value is set to True, only the name is appended, but if the value is a string, the string is appended to the end of the name, to allow characters to specify how clothing is worn. """ if not looker: return "" # get description, build string string = "|c%s|n\n" % self.get_display_name(looker) desc = self.db.desc worn_string_list = [] clothes_list = get_worn_clothes(self, exclude_covered=True) # Append worn, uncovered clothing to the description for garment in clothes_list: # If 'worn' is True, just append the name if garment.db.worn is True: worn_string_list.append(garment.name) # Otherwise, append the name and the string value of 'worn' elif garment.db.worn: worn_string_list.append("%s %s" % (garment.name, garment.db.worn)) if desc: string += "%s" % desc # Append worn clothes. if worn_string_list: string += "|/|/%s is wearing %s." % (self, list_to_string(worn_string_list)) else: string += "|/|/%s is not wearing anything." % self return string
def return_appearance(self, viewer): """This formats a description. It is the hook a 'look' command should call. Args: viewer (Object): Object doing the looking. """ if not viewer: return '' if not viewer.is_typeclass('typeclasses.accounts.Account'): viewer = viewer.account # make viewer reference the account object char = viewer.puppet # get and identify all objects visible = (con for con in self.contents if con != viewer and con.access(viewer, 'view')) exits, users, things = [], [], [] for con in visible: if con.destination: exits.append(con) elif con.has_account: users.append(con) else: if not con.db.worn: things.append(con) string = "\n%s" % self.get_display_name(viewer, mxp='sense %s' % self.get_display_name(viewer, plain=True)) if self.location and self.location.tags.get('rp', category='flags'): pose = self.db.messages and self.db.messages.get('pose', None) string += ' %s' % pose or '' if self.traits.mass and self.traits.mass.actual > 0: string += " |y(%s)|n " % mass_unit(self.get_mass()) if self.traits.health: # Add character health bar if character has health. gradient = ["|[300", "|[300", "|[310", "|[320", "|[330", "|[230", "|[130", "|[030", "|[030"] health = make_bar(self.traits.health.actual, self.traits.health.max, 20, gradient) string += " %s\n" % health else: string += "\n" desc = self.db.desc desc_brief = self.db.desc_brief if desc: string += "%s" % desc elif desc_brief: string += "%s" % desc_brief else: string += 'A shimmering illusion shifts from form to form.' # ---- Allow clothes wearing to be seen worn_string_list = [] clothes_list = get_worn_clothes(self, exclude_covered=True) # Append worn, uncovered clothing to the description for garment in clothes_list: if garment.db.worn is True: # If 'worn' is True, worn_string_list.append(garment.name) # just append the name. # Otherwise, append the name and the string value of 'worn' elif garment.db.worn: worn_string_list.append("%s %s" % (garment.name, garment.db.worn)) if worn_string_list: # Append worn clothes. string += "|/|/%s is wearing %s." % (self, list_to_string(worn_string_list)) # ---- List things carried (excludes worn things) if users or things: user_list = ", ".join(u.get_display_name(viewer) for u in users) ut_joiner = ', ' if users and things else '' item_list = ", ".join(t.get_display_name(viewer) for t in things) string += "\n|wYou see:|n " + user_list + ut_joiner + item_list # ---- Look Notify system: if self != char: if not (self.db.settings and 'look notify' in self.db.settings and self.db.settings['look notify'] is False): self.msg("%s just looked at you." % char.get_display_name(self)) return string
def test_list_to_string(self): self.assertEqual('1, 2, 3', utils.list_to_string([1,2,3], endsep="")) self.assertEqual('"1", "2", "3"', utils.list_to_string([1,2,3], endsep="", addquote=True)) self.assertEqual('1, 2 and 3', utils.list_to_string([1,2,3])) self.assertEqual('"1", "2" and "3"', utils.list_to_string([1,2,3], endsep="and", addquote=True))
def menunode_fieldfill(caller, raw_string, **kwargs): """ This is an EvMenu node, which calls itself over and over in order to allow a player to enter values into a fillable form. When the form is submitted, the form data is passed to a callback as a dictionary. """ # Retrieve menu info - taken from ndb if not persistent or db if persistent if not caller.db._menutree: formdata = caller.ndb._menutree.formdata formtemplate = caller.ndb._menutree.formtemplate formcallback = caller.ndb._menutree.formcallback pretext = caller.ndb._menutree.pretext posttext = caller.ndb._menutree.posttext submitcmd = caller.ndb._menutree.submitcmd borderstyle = caller.ndb._menutree.borderstyle formhelptext = caller.ndb._menutree.formhelptext else: formdata = caller.db._menutree.formdata formtemplate = caller.db._menutree.formtemplate formcallback = caller.db._menutree.formcallback pretext = caller.db._menutree.pretext posttext = caller.db._menutree.posttext submitcmd = caller.db._menutree.submitcmd borderstyle = caller.db._menutree.borderstyle formhelptext = caller.db._menutree.formhelptext # Syntax error syntax_err = "Syntax: <field> = <new value>|/Or: clear <field>, help, look, quit|/'%s' to submit form" % submitcmd # Display current form data text = (display_formdata(formtemplate, formdata, pretext=pretext, posttext=posttext, borderstyle=borderstyle), formhelptext) options = ({"key": "_default", "goto": "menunode_fieldfill"}) if raw_string: # Test for given 'submit' command if raw_string.lower().strip() == submitcmd: # Test to see if any blank fields are required blank_and_required = [] for field in formtemplate: if "required" in field.keys(): # If field is required but current form data for field is blank if field["required"] is True and formdata[field["fieldname"]] is None: # Add to blank and required fields blank_and_required.append(field["fieldname"]) if len(blank_and_required) > 0: # List the required fields left empty to the player caller.msg("The following blank fields require a value: %s" % list_to_string(blank_and_required)) text = (None, formhelptext) return text, options # If everything checks out, pass form data to the callback and end the menu! try: formcallback(caller, formdata) except Exception: logger.log_trace("Error in fillable form callback.") return None, None # Test for 'look' command if raw_string.lower().strip() == "look" or raw_string.lower().strip() == "l": return text, options # Test for 'clear' command cleartest = raw_string.lower().strip().split(" ", 1) if cleartest[0].lower() == "clear": text = (None, formhelptext) if len(cleartest) < 2: caller.msg(syntax_err) return text, options matched_field = None for key in formdata.keys(): if cleartest[1].lower() in key.lower(): matched_field = key if not matched_field: caller.msg("Field '%s' does not exist!" % cleartest[1]) text = (None, formhelptext) return text, options # Test to see if field can be cleared for field in formtemplate: if field["fieldname"] == matched_field and "cantclear" in field.keys(): if field["cantclear"] is True: caller.msg("Field '%s' can't be cleared!" % matched_field) text = (None, formhelptext) return text, options # Clear the field formdata.update({matched_field: None}) caller.ndb._menutree.formdata = formdata caller.msg("Field '%s' cleared." % matched_field) return text, options if "=" not in raw_string: text = (None, formhelptext) caller.msg(syntax_err) return text, options # Extract field name and new field value entry = raw_string.split("=", 1) fieldname = entry[0].strip() newvalue = entry[1].strip() # Syntax error if field name is too short or blank if len(fieldname) < 1: caller.msg(syntax_err) text = (None, formhelptext) return text, options # Attempt to match field name to field in form data matched_field = None for key in formdata.keys(): if fieldname.lower() in key.lower(): matched_field = key # No matched field if matched_field is None: caller.msg("Field '%s' does not exist!" % fieldname) text = (None, formhelptext) return text, options # Set new field value if match # Get data from template fieldtype = None max_value = None min_value = None truestr = "True" falsestr = "False" verifyfunc = None for field in formtemplate: if field["fieldname"] == matched_field: fieldtype = field["fieldtype"] if "max" in field.keys(): max_value = field["max"] if "min" in field.keys(): min_value = field["min"] if "truestr" in field.keys(): truestr = field["truestr"] if "falsestr" in field.keys(): falsestr = field["falsestr"] if "verifyfunc" in field.keys(): verifyfunc = field["verifyfunc"] # Field type text verification if fieldtype == "text": # Test for max/min if max_value is not None: if len(newvalue) > max_value: caller.msg("Field '%s' has a maximum length of %i characters." % (matched_field, max_value)) text = (None, formhelptext) return text, options if min_value is not None: if len(newvalue) < min_value: caller.msg("Field '%s' reqiures a minimum length of %i characters." % (matched_field, min_value)) text = (None, formhelptext) return text, options # Field type number verification if fieldtype == "number": try: newvalue = int(newvalue) except: caller.msg("Field '%s' requires a number." % matched_field) text = (None, formhelptext) return text, options # Test for max/min if max_value is not None: if newvalue > max_value: caller.msg("Field '%s' has a maximum value of %i." % (matched_field, max_value)) text = (None, formhelptext) return text, options if min_value is not None: if newvalue < min_value: caller.msg("Field '%s' reqiures a minimum value of %i." % (matched_field, min_value)) text = (None, formhelptext) return text, options # Field type bool verification if fieldtype == "bool": if newvalue.lower() != truestr.lower() and newvalue.lower() != falsestr.lower(): caller.msg("Please enter '%s' or '%s' for field '%s'." % (truestr, falsestr, matched_field)) text = (None, formhelptext) return text, options if newvalue.lower() == truestr.lower(): newvalue = True elif newvalue.lower() == falsestr.lower(): newvalue = False # Call verify function if present if verifyfunc: if verifyfunc(caller, newvalue) is False: # No error message is given - should be provided by verifyfunc text = (None, formhelptext) return text, options elif verifyfunc(caller, newvalue) is not True: newvalue = verifyfunc(caller, newvalue) # Set '0' or '1' to True or False if the field type is bool if fieldtype == "bool": if newvalue == 0: newvalue = False elif newvalue == 1: newvalue = True # If everything checks out, update form!! formdata.update({matched_field: newvalue}) caller.ndb._menutree.formdata = formdata # Account for truestr and falsestr when updating a boolean form announced_newvalue = newvalue if newvalue is True: announced_newvalue = truestr elif newvalue is False: announced_newvalue = falsestr # Announce the new value to the player caller.msg("Field '%s' set to: %s" % (matched_field, str(announced_newvalue))) text = (None, formhelptext) return text, options
def return_appearance(self, viewer): """This formats a description. It is the hook a 'look' command should call. Args: viewer (Object): Object doing the looking. """ if not viewer: return '' if not viewer.is_typeclass('typeclasses.accounts.Account'): viewer = viewer.account # make viewer reference the account object char = viewer.puppet # get and identify all objects visible = (con for con in self.contents if con != viewer and con.access(viewer, 'view')) exits, users, things = [], [], [] for con in visible: if con.destination: exits.append(con) elif con.has_account: users.append(con) else: if not con.db.worn: things.append(con) string = "\n%s" % self.get_display_name( viewer, mxp='sense %s' % self.get_display_name(viewer, plain=True)) if self.location and self.location.tags.get('rp', category='flags'): pose = self.db.messages and self.db.messages.get('pose', None) string += ' %s' % pose or '' if self.traits.mass and self.traits.mass.actual > 0: string += " |y(%s)|n " % mass_unit(self.get_mass()) if self.traits.health: # Add character health bar if character has health. gradient = [ "|[300", "|[300", "|[310", "|[320", "|[330", "|[230", "|[130", "|[030", "|[030" ] health = make_bar(self.traits.health.actual, self.traits.health.max, 20, gradient) string += " %s\n" % health else: string += "\n" desc = self.db.desc desc_brief = self.db.desc_brief if desc: string += "%s" % desc elif desc_brief: string += "%s" % desc_brief else: string += 'A shimmering illusion shifts from form to form.' # ---- Allow clothes wearing to be seen worn_string_list = [] clothes_list = get_worn_clothes(self, exclude_covered=True) # Append worn, uncovered clothing to the description for garment in clothes_list: if garment.db.worn is True: # If 'worn' is True, worn_string_list.append(garment.name) # just append the name. # Otherwise, append the name and the string value of 'worn' elif garment.db.worn: worn_string_list.append("%s %s" % (garment.name, garment.db.worn)) if worn_string_list: # Append worn clothes. string += "|/|/%s is wearing %s." % ( self, list_to_string(worn_string_list)) # ---- List things carried (excludes worn things) if users or things: user_list = ", ".join(u.get_display_name(viewer) for u in users) ut_joiner = ', ' if users and things else '' item_list = ", ".join(t.get_display_name(viewer) for t in things) string += "\n|wYou see:|n " + user_list + ut_joiner + item_list # ---- Look Notify system: if self != char: if not (self.db.settings and 'look notify' in self.db.settings and self.db.settings['look notify'] is False): self.msg("%s just looked at you." % char.get_display_name(self)) return string
def menunode_fieldfill(caller, raw_string, **kwargs): """ This is an EvMenu node, which calls itself over and over in order to allow a player to enter values into a fillable form. When the form is submitted, the form data is passed to a callback as a dictionary. """ # Retrieve menu info - taken from ndb if not persistent or db if persistent if not caller.db._menutree: formdata = caller.ndb._menutree.formdata formtemplate = caller.ndb._menutree.formtemplate formcallback = caller.ndb._menutree.formcallback pretext = caller.ndb._menutree.pretext posttext = caller.ndb._menutree.posttext submitcmd = caller.ndb._menutree.submitcmd borderstyle = caller.ndb._menutree.borderstyle formhelptext = caller.ndb._menutree.formhelptext else: formdata = caller.db._menutree.formdata formtemplate = caller.db._menutree.formtemplate formcallback = caller.db._menutree.formcallback pretext = caller.db._menutree.pretext posttext = caller.db._menutree.posttext submitcmd = caller.db._menutree.submitcmd borderstyle = caller.db._menutree.borderstyle formhelptext = caller.db._menutree.formhelptext # Syntax error syntax_err = ( "Syntax: <field> = <new value>|/Or: clear <field>, help, look, quit|/'%s' to submit form" % submitcmd ) # Display current form data text = ( display_formdata( formtemplate, formdata, pretext=pretext, posttext=posttext, borderstyle=borderstyle ), formhelptext, ) options = {"key": "_default", "goto": "menunode_fieldfill"} if raw_string: # Test for given 'submit' command if raw_string.lower().strip() == submitcmd: # Test to see if any blank fields are required blank_and_required = [] for field in formtemplate: if "required" in field.keys(): # If field is required but current form data for field is blank if field["required"] is True and formdata[field["fieldname"]] is None: # Add to blank and required fields blank_and_required.append(field["fieldname"]) if len(blank_and_required) > 0: # List the required fields left empty to the player caller.msg( "The following blank fields require a value: %s" % list_to_string(blank_and_required) ) text = (None, formhelptext) return text, options # If everything checks out, pass form data to the callback and end the menu! try: formcallback(caller, formdata) except Exception: logger.log_trace("Error in fillable form callback.") return None, None # Test for 'look' command if raw_string.lower().strip() == "look" or raw_string.lower().strip() == "l": return text, options # Test for 'clear' command cleartest = raw_string.lower().strip().split(" ", 1) if cleartest[0].lower() == "clear": text = (None, formhelptext) if len(cleartest) < 2: caller.msg(syntax_err) return text, options matched_field = None for key in formdata.keys(): if cleartest[1].lower() in key.lower(): matched_field = key if not matched_field: caller.msg("Field '%s' does not exist!" % cleartest[1]) text = (None, formhelptext) return text, options # Test to see if field can be cleared for field in formtemplate: if field["fieldname"] == matched_field and "cantclear" in field.keys(): if field["cantclear"] is True: caller.msg("Field '%s' can't be cleared!" % matched_field) text = (None, formhelptext) return text, options # Clear the field formdata.update({matched_field: None}) caller.ndb._menutree.formdata = formdata caller.msg("Field '%s' cleared." % matched_field) return text, options if "=" not in raw_string: text = (None, formhelptext) caller.msg(syntax_err) return text, options # Extract field name and new field value entry = raw_string.split("=", 1) fieldname = entry[0].strip() newvalue = entry[1].strip() # Syntax error if field name is too short or blank if len(fieldname) < 1: caller.msg(syntax_err) text = (None, formhelptext) return text, options # Attempt to match field name to field in form data matched_field = None for key in formdata.keys(): if fieldname.lower() in key.lower(): matched_field = key # No matched field if matched_field is None: caller.msg("Field '%s' does not exist!" % fieldname) text = (None, formhelptext) return text, options # Set new field value if match # Get data from template fieldtype = None max_value = None min_value = None truestr = "True" falsestr = "False" verifyfunc = None for field in formtemplate: if field["fieldname"] == matched_field: fieldtype = field["fieldtype"] if "max" in field.keys(): max_value = field["max"] if "min" in field.keys(): min_value = field["min"] if "truestr" in field.keys(): truestr = field["truestr"] if "falsestr" in field.keys(): falsestr = field["falsestr"] if "verifyfunc" in field.keys(): verifyfunc = field["verifyfunc"] # Field type text verification if fieldtype == "text": # Test for max/min if max_value is not None: if len(newvalue) > max_value: caller.msg( "Field '%s' has a maximum length of %i characters." % (matched_field, max_value) ) text = (None, formhelptext) return text, options if min_value is not None: if len(newvalue) < min_value: caller.msg( "Field '%s' reqiures a minimum length of %i characters." % (matched_field, min_value) ) text = (None, formhelptext) return text, options # Field type number verification if fieldtype == "number": try: newvalue = int(newvalue) except: caller.msg("Field '%s' requires a number." % matched_field) text = (None, formhelptext) return text, options # Test for max/min if max_value is not None: if newvalue > max_value: caller.msg("Field '%s' has a maximum value of %i." % (matched_field, max_value)) text = (None, formhelptext) return text, options if min_value is not None: if newvalue < min_value: caller.msg( "Field '%s' reqiures a minimum value of %i." % (matched_field, min_value) ) text = (None, formhelptext) return text, options # Field type bool verification if fieldtype == "bool": if newvalue.lower() != truestr.lower() and newvalue.lower() != falsestr.lower(): caller.msg( "Please enter '%s' or '%s' for field '%s'." % (truestr, falsestr, matched_field) ) text = (None, formhelptext) return text, options if newvalue.lower() == truestr.lower(): newvalue = True elif newvalue.lower() == falsestr.lower(): newvalue = False # Call verify function if present if verifyfunc: if verifyfunc(caller, newvalue) is False: # No error message is given - should be provided by verifyfunc text = (None, formhelptext) return text, options elif verifyfunc(caller, newvalue) is not True: newvalue = verifyfunc(caller, newvalue) # Set '0' or '1' to True or False if the field type is bool if fieldtype == "bool": if newvalue == 0: newvalue = False elif newvalue == 1: newvalue = True # If everything checks out, update form!! formdata.update({matched_field: newvalue}) caller.ndb._menutree.formdata = formdata # Account for truestr and falsestr when updating a boolean form announced_newvalue = newvalue if newvalue is True: announced_newvalue = truestr elif newvalue is False: announced_newvalue = falsestr # Announce the new value to the player caller.msg("Field '%s' set to: %s" % (matched_field, str(announced_newvalue))) text = (None, formhelptext) return text, options