def func(self): """ Get all connected players by polling session. """ player = self.player session_list = SESSIONS.get_sessions() session_list = sorted(session_list, key=lambda o: o.player.key) if self.cmdstring == "doing": show_session_data = False else: show_session_data = player.check_permstring( "Immortals") or player.check_permstring("Wizards") nplayers = (SESSIONS.player_count()) if show_session_data: # privileged info table = prettytable.PrettyTable([ "{wPlayer Name", "{wOn for", "{wIdle", "{wPuppeting", "{wRoom", "{wCmds", "{wProtocol", "{wHost" ]) for session in session_list: if not session.logged_in: continue delta_cmd = time.time() - session.cmd_last_visible delta_conn = time.time() - session.conn_time player = session.get_player() puppet = session.get_puppet() location = puppet.location.key if puppet else "None" table.add_row([ utils.crop(player.name, width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1), utils.crop(puppet.key if puppet else "None", width=25), utils.crop(location, width=25), session.cmd_total, session.protocol_key, isinstance(session.address, tuple) and session.address[0] or session.address ]) else: # unprivileged table = prettytable.PrettyTable( ["{wPlayer name", "{wOn for", "{wIdle"]) for session in session_list: if not session.logged_in: continue delta_cmd = time.time() - session.cmd_last_visible delta_conn = time.time() - session.conn_time player = session.get_player() table.add_row([ utils.crop(player.key, width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1) ]) isone = nplayers == 1 string = "{wPlayers:{n\n%s\n%s unique account%s logged in." % ( table, "One" if isone else nplayers, "" if isone else "s") self.msg(string)
def get_text(self): """Display the app.""" try: number = self.app.phone_number pretty_number = self.app.pretty_phone_number except ValueError: self.msg("Your phone number couldn't be found.") self.back() return # Load the threads (conversations) to which "number" participated threads = Text.objects.get_threads_for(number) string = "Texts for {}".format(pretty_number) string += "\n" self.db["threads"] = {} stored_threads = self.db["threads"] if threads: len_i = 3 if len(threads) < 100 else 4 string += " Create a {new} message.\n".format( new=self.format_cmd("new")) i = 1 table = EvTable(pad_left=0, border="none") table.add_column("S", width=2) table.add_column("I", width=len_i, align="r", valign="t") table.add_column("Sender", width=21) table.add_column("Content", width=36) table.add_column("Ago", width=15) for thread_id, text in threads.items(): thread = text.db_thread stored_threads[i] = thread sender = text.recipients sender = [self.app.format(num) for num in sender] sender = ", ".join(sender) if thread.name: sender = thread.name sender = crop(sender, 20, "") content = text.content.replace("\n", " ") if text.sender.db_phone_number == number: content = "[You] " + content content = crop(content, 35) status = " " if thread.has_read(number) else "|rU|n" table.add_row(status, self.format_cmd(str(i)), sender, content, text.sent_ago.capitalize()) i += 1 lines = str(table).splitlines() del lines[0] lines = [line.rstrip() for line in lines] string += "\n" + "\n".join(lines) string += "\n\n(Type a number to open this text.)" else: string += "\n You have no texts yet. Want to create a {new} one?".format( new=self.format_cmd("new")) string += "\n\n(Enter {settings} to edit the app settings).".format( settings=self.format_cmd("settings")) count = Text.objects.get_texts_for(number).count() s = "" if count == 1 else "s" string += "\n\nText app: {} saved message{s}.".format(count, s=s) return string
def func(self): """ Get all connected players by polling session. """ player = self.player session_list = SESSIONS.get_sessions() session_list = sorted(session_list, key=lambda o: o.player.key) if self.cmdstring == "doing": show_session_data = False else: show_session_data = player.check_permstring("Immortals") or player.check_permstring("Wizards") nplayers = (SESSIONS.player_count()) if show_session_data: # privileged info table = prettytable.PrettyTable(["{wPlayer Name", "{wOn for", "{wIdle", "{wPuppeting", "{wRoom", "{wCmds", "{wProtocol", "{wHost"]) for session in session_list: if not session.logged_in: continue delta_cmd = time.time() - session.cmd_last_visible delta_conn = time.time() - session.conn_time player = session.get_player() puppet = session.get_puppet() location = puppet.location.key if puppet else "None" table.add_row([utils.crop(player.name, width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1), utils.crop(puppet.key if puppet else "None", width=25), utils.crop(location, width=25), session.cmd_total, session.protocol_key, isinstance(session.address, tuple) and session.address[0] or session.address]) else: # unprivileged table = prettytable.PrettyTable(["{wPlayer name", "{wOn for", "{wIdle"]) for session in session_list: if not session.logged_in: continue delta_cmd = time.time() - session.cmd_last_visible delta_conn = time.time() - session.conn_time player = session.get_player() table.add_row([utils.crop(player.key, width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1)]) isone = nplayers == 1 string = "{wPlayers:{n\n%s\n%s unique account%s logged in." % (table, "One" if isone else nplayers, "" if isone else "s") self.msg(string)
def func(self): """ Get all connected accounts by polling session. """ account = self.account session_list = SESSIONS.get_sessions() session_list = sorted(session_list, key=lambda o: o.account.key) if self.cmdstring == "doing": show_session_data = False else: show_session_data = account.check_permstring( "Developer") or account.check_permstring("Admins") naccounts = SESSIONS.account_count() if show_session_data: # privileged info table = self.styled_table("|wAccount Name", "|wOn for", "|wIdle", "|wPuppeting", "|wRoom", "|wCmds", "|wProtocol", "|wHost") for session in session_list: if not session.logged_in: continue delta_cmd = time.time() - session.cmd_last_visible delta_conn = time.time() - session.conn_time account = session.get_account() puppet = session.get_puppet() location = puppet.location.key if puppet and puppet.location else "None" table.add_row( utils.crop(account.get_display_name(account), width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1), utils.crop( puppet.get_display_name(account) if puppet else "None", width=25), utils.crop(location, width=25), session.cmd_total, session.protocol_key, isinstance(session.address, tuple) and session.address[0] or session.address) else: # unprivileged table = self.styled_table("|wAccount name", "|wOn for", "|wIdle") for session in session_list: if not session.logged_in: continue delta_cmd = time.time() - session.cmd_last_visible delta_conn = time.time() - session.conn_time account = session.get_account() table.add_row( utils.crop(account.get_display_name(account), width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1)) is_one = naccounts == 1 self.msg( "|wAccounts:|n\n%s\n%s unique account%s logged in." % (table, "One" if is_one else naccounts, "" if is_one else "s"))
def func(self): """ Get all connected players by polling session. """ player = self.player session_list = SESSIONS.get_sessions() session_list = sorted(session_list, key=lambda o: o.player.key) if self.cmdstring == "doing": show_session_data = False else: show_session_data = player.check_permstring("Immortals") or player.check_permstring("Wizards") nplayers = (SESSIONS.player_count()) if show_session_data: # privileged info table = prettytable.PrettyTable(["{wИмя игрока", "{wВ игре", "{wIdle", "{wУправляет", "{wКомната", "{wCmds", "{wПротокол", "{wХост"]) for session in session_list: if not session.logged_in: continue delta_cmd = time.time() - session.cmd_last_visible delta_conn = time.time() - session.conn_time player = session.get_player() puppet = session.get_puppet() location = puppet.location.key if puppet and puppet.location else "None" table.add_row([utils.crop(player.name, width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1), utils.crop(puppet.key if puppet else "None", width=25), utils.crop(location, width=25), session.cmd_total, session.protocol_key, isinstance(session.address, tuple) and session.address[0] or session.address]) else: # unprivileged table = prettytable.PrettyTable(["{wИмя игрока", "{wВ игре", "{wIdle"]) for session in session_list: if not session.logged_in: continue delta_cmd = time.time() - session.cmd_last_visible delta_conn = time.time() - session.conn_time player = session.get_player() table.add_row([utils.crop(player.key, width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1)]) isone = nplayers == 1 string = "{wИгроков:{n\n%s\n%s уникальных аккаунтов%s залогинено." % (table, "Один" if isone else nplayers, "" if isone else "") self.msg(string)
def func(self): """ Get all connected accounts by polling session. """ account = self.account session_list = SESSIONS.get_sessions() session_list = sorted(session_list, key=lambda o: o.account.key) if self.cmdstring == "doing": show_session_data = False else: show_session_data = account.check_permstring("Developer") or account.check_permstring("Admins") naccounts = (SESSIONS.account_count()) if show_session_data: # privileged info table = evtable.EvTable("|wAccount Name", "|wOn for", "|wIdle", "|wPuppeting", "|wRoom", "|wCmds", "|wProtocol", "|wHost") for session in session_list: if not session.logged_in: continue delta_cmd = time.time() - session.cmd_last_visible delta_conn = time.time() - session.conn_time account = session.get_account() puppet = session.get_puppet() location = puppet.location.key if puppet and puppet.location else "None" table.add_row(utils.crop(account.name, width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1), utils.crop(puppet.key if puppet else "None", width=25), utils.crop(location, width=25), session.cmd_total, session.protocol_key, isinstance(session.address, tuple) and session.address[0] or session.address) else: # unprivileged table = evtable.EvTable("|wAccount name", "|wOn for", "|wIdle") for session in session_list: if not session.logged_in: continue delta_cmd = time.time() - session.cmd_last_visible delta_conn = time.time() - session.conn_time account = session.get_account() table.add_row(utils.crop(account.key, width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1)) is_one = naccounts == 1 self.msg("|wAccounts:|n\n%s\n%s unique account%s logged in." % (table, "One" if is_one else naccounts, "" if is_one else "s"))
def __str__(self): """ This handles what is shown when e.g. printing the message. """ senders = ",".join(obj.key for obj in self.senders) receivers = ",".join(["[%s]" % obj.key for obj in self.channels] + [obj.key for obj in self.receivers]) return "%s->%s: %s" % (senders, receivers, crop(self.message, width=40))
def crop(*args, **kwargs): """ Inlinefunc. Crops ingoing text to given widths. Args: text (str, optional): Text to crop. width (str, optional): Will be converted to an integer. Width of crop in characters. suffix (str, optional): End string to mark the fact that a part of the string was cropped. Defaults to `[...]`. Kwargs: session (Session): Session performing the crop. Example: `$crop(text, width=78, suffix='[...]')` """ text, width, suffix = "", 78, "[...]" nargs = len(args) if nargs > 0: text = args[0] if nargs > 1: width = int(args[1]) if args[1].strip().isdigit() else 78 if nargs > 2: suffix = args[2] return utils.crop(text, width=width, suffix=suffix)
def format_script_list(scripts): """Takes a list of scripts and formats the output.""" if not scripts: return "<No scripts>" table = EvTable("|wdbref|n", "|wobj|n", "|wkey|n", "|wintval|n", "|wnext|n", "|wrept|n", "|wdb", "|wtypeclass|n", "|wdesc|n", align='r', border="tablecols") for script in scripts: nextrep = script.time_until_next_repeat() if nextrep is None: nextrep = "PAUS" if script.db._paused_time else "--" else: nextrep = "%ss" % nextrep maxrepeat = script.repeats if maxrepeat: rept = "%i/%i" % (maxrepeat - script.remaining_repeats(), maxrepeat) else: rept = "-/-" table.add_row(script.id, script.obj.key if (hasattr(script, 'obj') and script.obj) else "<Global>", script.key, script.interval if script.interval > 0 else "--", nextrep, rept, "*" if script.persistent else "-", script.typeclass_path.rsplit('.', 1)[-1], crop(script.desc, width=20)) return "%s" % table
def __str__(self): "This handles what is shown when e.g. printing the message" senders = ",".join( getattr(obj, "key", str(obj)) for obj in self.senders) receivers = ",".join( ["[%s]" % getattr(obj, "key", str(obj)) for obj in self.channels] + [getattr(obj, "key", str(obj)) for obj in self.receivers]) return "%s->%s: %s" % (senders, receivers, crop(self.message, width=40))
def crop(text, *args, **kwargs): "Crop to width. crop(text, width=78, suffix='[...]')" width = _DEFAULT_WIDTH suffix = "[...]" for iarg, arg in enumerate(args): if iarg == 0: width = int(arg) if arg.isdigit() else width elif iarg == 1: suffix = arg else: break return utils.crop(text, width=width, suffix=suffix)
def page_formatter(self, scripts): """Takes a page of scripts and formats the output into an EvTable.""" if not scripts: return "<No scripts>" table = EvTable( "|wdbref|n", "|wobj|n", "|wkey|n", "|wintval|n", "|wnext|n", "|wrept|n", "|wdb", "|wtypeclass|n", "|wdesc|n", align="r", border="tablecols", width=self.width ) for script in scripts: nextrep = script.time_until_next_repeat() if nextrep is None: nextrep = "PAUSED" if script.db._paused_time else "--" else: nextrep = "%ss" % nextrep maxrepeat = script.repeats remaining = script.remaining_repeats() or 0 if maxrepeat: rept = "%i/%i" % (maxrepeat - remaining, maxrepeat) else: rept = "-/-" table.add_row( script.id, f"{script.obj.key}({script.obj.dbref})" if (hasattr(script, "obj") and script.obj) else "<Global>", script.key, script.interval if script.interval > 0 else "--", nextrep, rept, "*" if script.persistent else "-", script.typeclass_path.rsplit(".", 1)[-1], crop(script.desc, width=20), ) return str(table)
def func(self): session_list = SESSIONS.get_sessions() table = evtable.EvTable(" |w|uName:|n", "|w|uIdle:|n", "|w|uConn:|n", "|w|uClearance:|n", table=None, border=None, width=78) for session in session_list: player = session.get_account() idle = time.time() - session.cmd_last_visible conn = time.time() - session.conn_time clearance = session.get_puppet().db.clearance flag = None if player.locks.check_lockstring(player, "dummy:perm(Admin)"): flag = "|y!|n" elif player.locks.check_lockstring(player, "dummy:perm(Builder)"): flag = "|g&|n" elif player.locks.check_lockstring(player, "dummy:perm(Helper)"): flag = "|r$|n" else: flag = " " table.add_row( flag + utils.crop(player.name), utils.time_format(idle, 0), utils.time_format(conn, 0), "|{}{}|n".format(clearance_color(CLEARANCE.get(clearance)), CLEARANCE.get(clearance))) table.reformat_column(0, width=24) table.reformat_column(1, width=12) table.reformat_column(2, width=12) table.reformat_column(3, width=30) self.caller.msg("|w_|n" * 78) title = ansi.ANSIString("|[002|w|u{}|n".format(settings.SERVERNAME)) self.caller.msg(title.center(78, '^').replace('^', "|[002|w_|n")) self.caller.msg(table) self.caller.msg("|w_|n" * 78) self.caller.msg("Total Connected: %s" % SESSIONS.account_count()) whotable = evtable.EvTable("", "", "", header=False, border=None) whotable.reformat_column(0, width=26) whotable.reformat_column(1, width=26) whotable.reformat_column(2, width=26) whotable.add_row("|y!|n - Administrators", "|g&|n - Storytellers", "|r$|n - Player Helpers") self.caller.msg(whotable) self.caller.msg("|w_|n" * 78 + "\n")
def func(self): """check inventory""" items = self.caller.contents if not items: string = "You are not carrying anything." else: from evennia.utils.ansi import raw as raw_ansi table = self.styled_table(border="header") for item in items: table.add_row( f"|C{item.name}|n", "{}|n".format( utils.crop(raw_ansi(item.db.desc), width=50) or "")) string = f"|wYou are carrying:\n{table}" self.caller.msg(string)
def format_header(caller, entry): """ Formats a header """ width = _HEADER_WIDTH - 10 entry = entry.strip() header = utils.crop(entry, width=width) ptr = caller.ndb.batch_stackptr + 1 stacklen = len(caller.ndb.batch_stack) header = "{w%02i/%02i{G: %s{n" % (ptr, stacklen, header) # add extra space to the side for padding. header = "%s%s" % (header, " " * (width - len(header))) header = header.replace('\n', '\\n') return header
def test_crop(self): # No text, return no text self.assertEqual("", utils.crop("", width=10, suffix="[...]")) # Input length equal to max width, no crop self.assertEqual("0123456789", utils.crop("0123456789", width=10, suffix="[...]")) # Input length greater than max width, crop (suffix included in width) self.assertEqual("0123[...]", utils.crop("0123456789", width=9, suffix="[...]")) # Input length less than desired width, no crop self.assertEqual("0123", utils.crop("0123", width=9, suffix="[...]")) # Width too small or equal to width of suffix self.assertEqual("012", utils.crop("0123", width=3, suffix="[...]")) self.assertEqual("01234", utils.crop("0123456", width=5, suffix="[...]"))
def format_header(caller, entry): """ Formats a header """ width = _HEADER_WIDTH - 10 # strip all comments for the header if caller.ndb.batch_batchmode != "batch_commands": # only do cleanup for batchcode entry = _RE_CODE_START.split(entry, 1)[1] entry = _RE_COMMENT.sub("", entry).strip() header = utils.crop(entry, width=width) ptr = caller.ndb.batch_stackptr + 1 stacklen = len(caller.ndb.batch_stack) header = "{w%02i/%02i{G: %s{n" % (ptr, stacklen, header) # add extra space to the side for padding. header = "%s%s" % (header, " " * (width - len(header))) header = header.replace('\n', '\\n') return header
def format_header(caller, entry): """ Formats a header """ width = _HEADER_WIDTH - 10 # strip all comments for the header if caller.ndb.batch_batchmode != "batch_commands": # only do cleanup for batchcode entry = _RE_CODE_START.split(entry, 1)[1] entry = _RE_COMMENT.sub("", entry).strip() header = utils.crop(entry, width=width) ptr = caller.ndb.batch_stackptr + 1 stacklen = len(caller.ndb.batch_stack) header = "|w%02i/%02i|G: %s|n" % (ptr, stacklen, header) # add extra space to the side for padding. header = "%s%s" % (header, " " * (width - len(header))) header = header.replace('\n', '\\n') return header
def return_appearance(type, looker, number=False, header=""): """Return the formatted appearance for a phone or computer.""" phone_number = type.obj.tags.get(category="phone number") if not isinstance(phone_number, str): phone_number = "|gunset|n" else: phone_number = phone_number[:3] + "-" + phone_number[3:] date = datetime.datetime.fromtimestamp(gametime.gametime(absolute=True)) text = dedent(""" {header} {time} {date} """.strip("\n")).format( header=header, date=date.strftime("%A, %B {}, %Y".format(date.day)), time=date.strftime("%I:%M %p"), ) # If a phone number, display it if number: text += "\n\n" + """ {number} """.rstrip("\n").format(number=phone_number) # Display the notifications notifications = type.notifications.all() if notifications: text += "\n\n" for notification in notifications: title = crop(notification.title, 55, "...") content = "\n ".join(wrap(notification.content, 74)) text += "\n- {:<55} ({})".format(title, notification.ago) if content: text += "\n " + content return text
def prayer_text(self, obj): return crop(obj.text, width=120)
def inner_func(self): """Get all connected accounts by polling session.""" account = self.account session_list = SESSIONS.get_sessions() session_list = sorted(session_list, key=lambda o: o.account.key) show_session_data = account.check_permstring( "Developer") or account.check_permstring("Admins") naccounts = SESSIONS.account_count() if show_session_data: # privileged info table = self.styled_table( "|wAccount Name", "|wOn for", "|wIdle", "|wPuppeting", "|wLevel", "|wClass", "|wRoom", "|wCmds", "|wProtocol", "|wHost", ) for session in session_list: if not session.logged_in: continue delta_cmd = time.time() - session.cmd_last_visible delta_conn = time.time() - session.conn_time account = session.get_account() puppet = session.get_puppet() location = puppet.location.key if puppet and puppet.location else "None" table.add_row( utils.crop(account.get_display_name(account), width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1), utils.crop( puppet.get_display_name(account) if puppet else "None", width=25), puppet.level if hasattr(puppet, "level") else 0, puppet.classname if hasattr(puppet, "classname") else "None", utils.crop(location, width=25), session.cmd_total, session.protocol_key, isinstance(session.address, tuple) and session.address[0] or session.address, ) else: # unprivileged table = self.styled_table( "|wUsername", "|wGame Name", "|wLevel", "|wClass", "|wWhere", ) for session in session_list: if not session.logged_in: continue delta_cmd = time.time() - session.cmd_last_visible delta_conn = time.time() - session.conn_time account = session.get_account() puppet = session.get_puppet() location = puppet.location.key if puppet and puppet.location else "None" table.add_row( utils.crop(account.get_display_name(account), width=25), utils.crop( puppet.get_display_name(account) if puppet else "None", width=25), puppet.level if hasattr(puppet, "level") else 0, puppet.classname if hasattr(puppet, "classname") else "None", utils.crop(location, width=25), ) self.msg( "|w Monster Status\n 26-FEB-1991 8:38pm\n * - Monster Operator|n\n%s" % table)
def execute_cmd(self, session=None, txt=None, **kwargs): """ Take incoming data and send it to connected channel. This is triggered by the bot_data_in Inputfunc. Args: session (Session, optional): Session responsible for this command. Note that this is the bot. txt (str, optional): Command string. Keyword Args: user (str): The name of the user who sent the message. channel (str): The name of channel the message was sent to. type (str): Nature of message. Either 'msg', 'action', 'nicklist' or 'ping'. nicklist (list, optional): Set if `type='nicklist'`. This is a list of nicks returned by calling the `self.get_nicklist`. It must look for a list `self._nicklist_callers` which will contain all callers waiting for the nicklist. timings (float, optional): Set if `type='ping'`. This is the return (in seconds) of a ping request triggered with `self.ping`. The return must look for a list `self._ping_callers` which will contain all callers waiting for the ping return. """ if kwargs["type"] == "nicklist": # the return of a nicklist request if hasattr(self, "_nicklist_callers") and self._nicklist_callers: chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})" nicklist = ", ".join( sorted(kwargs["nicklist"], key=lambda n: n.lower())) for obj in self._nicklist_callers: obj.msg( _("Nicks at {chstr}:\n {nicklist}").format( chstr=chstr, nicklist=nicklist)) self._nicklist_callers = [] return elif kwargs["type"] == "ping": # the return of a ping if hasattr(self, "_ping_callers") and self._ping_callers: chstr = f"{self.db.irc_channel} ({self.db.irc_network}:{self.db.irc_port})" for obj in self._ping_callers: obj.msg( _("IRC ping return from {chstr} took {time}s.").format( chstr=chstr, time=kwargs["timing"])) self._ping_callers = [] return elif kwargs["type"] == "privmsg": # A private message to the bot - a command. user = kwargs["user"] if txt.lower().startswith("who"): # return server WHO list (abbreviated for IRC) global _SESSIONS if not _SESSIONS: from evennia.server.sessionhandler import SESSIONS as _SESSIONS whos = [] t0 = time.time() for sess in _SESSIONS.get_sessions(): delta_cmd = t0 - sess.cmd_last_visible delta_conn = t0 - session.conn_time account = sess.get_account() whos.append("%s (%s/%s)" % ( utils.crop("|w%s|n" % account.name, width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1), )) text = f"Who list (online/idle): {', '.join(sorted(whos, key=lambda w: w.lower()))}" elif txt.lower().startswith("about"): # some bot info text = f"This is an Evennia IRC bot connecting from '{settings.SERVERNAME}'." else: text = "I understand 'who' and 'about'." super().msg(privmsg=((text, ), {"user": user})) else: # something to send to the main channel if kwargs["type"] == "action": # An action (irc pose) text = f"{kwargs['user']}@{kwargs['channel']} {txt}" else: # msg - A normal channel message text = f"{kwargs['user']}@{kwargs['channel']}: {txt}" if not self.ndb.ev_channel and self.db.ev_channel: # cache channel lookup self.ndb.ev_channel = self.db.ev_channel if self.ndb.ev_channel: self.ndb.ev_channel.msg(text, senders=self)
def execute_cmd(self, session=None, txt=None, **kwargs): """ Take incoming data and send it to connected channel. This is triggered by the bot_data_in Inputfunc. Args: session (Session, optional): Session responsible for this command. Note that this is the bot. txt (str, optional): Command string. Kwargs: user (str): The name of the user who sent the message. channel (str): The name of channel the message was sent to. type (str): Nature of message. Either 'msg', 'action', 'nicklist' or 'ping'. nicklist (list, optional): Set if `type='nicklist'`. This is a list of nicks returned by calling the `self.get_nicklist`. It must look for a list `self._nicklist_callers` which will contain all callers waiting for the nicklist. timings (float, optional): Set if `type='ping'`. This is the return (in seconds) of a ping request triggered with `self.ping`. The return must look for a list `self._ping_callers` which will contain all callers waiting for the ping return. """ if kwargs["type"] == "nicklist": # the return of a nicklist request if hasattr(self, "_nicklist_callers") and self._nicklist_callers: chstr = "%s (%s:%s)" % (self.db.irc_channel, self.db.irc_network, self.db.irc_port) nicklist = ", ".join(sorted(kwargs["nicklist"], key=lambda n: n.lower())) for obj in self._nicklist_callers: obj.msg("Nicks at %s:\n %s" % (chstr, nicklist)) self._nicklist_callers = [] return elif kwargs["type"] == "ping": # the return of a ping if hasattr(self, "_ping_callers") and self._ping_callers: chstr = "%s (%s:%s)" % (self.db.irc_channel, self.db.irc_network, self.db.irc_port) for obj in self._ping_callers: obj.msg("IRC ping return from %s took %ss." % (chstr, kwargs["timing"])) self._ping_callers = [] return elif kwargs["type"] == "privmsg": # A private message to the bot - a command. user = kwargs["user"] if txt.lower().startswith("who"): # return server WHO list (abbreviated for IRC) global _SESSIONS if not _SESSIONS: from evennia.server.sessionhandler import SESSIONS as _SESSIONS whos = [] t0 = time.time() for sess in _SESSIONS.get_sessions(): delta_cmd = t0 - sess.cmd_last_visible delta_conn = t0 - session.conn_time player = sess.get_player() whos.append("%s (%s/%s)" % (utils.crop("|w%s|n" % player.name, width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1))) text = "Who list (online/idle): %s" % ", ".join(sorted(whos, key=lambda w: w.lower())) elif txt.lower().startswith("about"): # some bot info text = "This is an Evennia IRC bot connecting from '%s'." % settings.SERVERNAME else: text = "I understand 'who' and 'about'." super(IRCBot, self).msg(privmsg=((text,), {"user": user})) else: # something to send to the main channel if kwargs["type"] == "action": # An action (irc pose) text = "%s@%s %s" % (kwargs["user"], kwargs["channel"], txt) else: # msg - A normal channel message text = "%s@%s: %s" % (kwargs["user"], kwargs["channel"], txt) if not self.ndb.ev_channel and self.db.ev_channel: # cache channel lookup self.ndb.ev_channel = self.db.ev_channel if self.ndb.ev_channel: self.ndb.ev_channel.msg(text, senders=self.id)
def __str__(self): return "<Option {key}: {value}>".format(key=self.key, value=crop(str(self.value), width=10))
def execute_cmd(self, session=None, txt=None, **kwargs): """ Take incoming data and make the appropriate action. This acts as a CommandHandler of sorts for the various "type" of actions the Portal bot returns to the Server. This is triggered by the bot_data_in Inputfunc. Args: session (Session, optional): Session responsible for this command. Note that this is the bot. txt (str, optional): Command string. Kwargs: user (str): The name of the user who sent the message. channel (str): The name of channel the message was sent to. nicklist (list, optional): Set if `type='nicklist'`. This is a list of nicks returned by calling the `self.get_nicklist`. It must look for a list `self._nicklist_callers` which will contain all callers waiting for the nicklist. timings (float, optional): Set if `type='ping'`. This is the return (in seconds) of a ping request triggered with `self.ping`. The return must look for a list `self._ping_callers` which will contain all callers waiting for the ping return. type (str): The type of response returned by the IRC bot. Including: "nicklist": Returned when first joining a channel. "joined": Returned when a new user joins a channel. "left": Returned when a user leaves a channel. "privmsg": Returned when the bot is directly messaged. "action": Returned when a user uses /me in IRC Everything else is assumed to be text to speak. """ if kwargs["type"] == "nicklist": """ Returned when first joining a channel. """ if hasattr(self, "_nicklist_callers") and self._nicklist_callers: chstr = "%s (%s:%s)" % (self.db.irc_channel, self.db.irc_network, self.db.irc_port) nicklist = ", ".join( sorted(kwargs["nicklist"], key=lambda n: n.lower())) for obj in self._nicklist_callers: obj.msg("Nicks at %s:\n %s" % (chstr, nicklist)) self._nicklist_callers = [] return else: # Prepare blank reference dictionary. self.db.puppetdict = {} # Prepare listener. self.prep_listener() # Prepare puppets. for nick in kwargs["nicklist"]: self.prep_puppet(ansi.strip_ansi(nick)) # Hide stale puppets. for puppet in search.search_tag(self.key + "-puppet"): if puppet.location is not None \ and puppet not in self.db.puppetdict.values(): puppet.move_to(None, to_none=True) return elif kwargs["type"] == "ping": """ Returned by the ping command. """ if hasattr(self, "_ping_callers") and self._ping_callers: chstr = "%s (%s:%s)" % (self.db.irc_channel, self.db.irc_network, self.db.irc_port) for obj in self._ping_callers: obj.msg("IRC ping return from %s took %ss." % (chstr, kwargs["timing"])) self._ping_callers = [] return elif kwargs["type"] == "joined": """ Returned when a new user joins a channel. """ # Prepare puppet. for nick in kwargs["nicklist"]: self.prep_puppet(ansi.strip_ansi(nick)) return elif kwargs["type"] == "renamed": """ Returned when IRC user changes nick. """ puppetdict = self.db.puppetdict newname = kwargs["newname"] oldname = kwargs["oldname"] newkey = self.db.puppetprefix + newname + self.db.puppetsuffix oldkey = self.db.puppetprefix + oldname + self.db.puppetsuffix # List of puppet objects matching newname. puppetlist = [ puppet for puppet in search.search_tag(self.key + "-puppet") if puppet.key == newkey ] # Use an existing puppet. if puppetlist: # Set up new puppet puppetdict[newname] = puppetlist[0] if not puppetdict[newname].location == self.db.ev_location: puppetdict[newname].move_to(self.db.ev_location, quiet=True) self.db.ev_location.msg_contents(oldkey + " has become " + newkey) # Pack up old puppet self.db.puppetdict[oldname].move_to(None, to_none=True) del self.db.puppetdict[oldname] # Else recycle old puppet. elif oldname in puppetdict: print('Reusing puppetbot from puppetdict: ', oldname, puppetdict[oldname]) puppetdict[oldname].key = newkey puppetdict[newname] = puppetdict.pop(oldname) self.db.ev_location.msg_contents(oldkey + " has become " + newkey) return elif kwargs["type"] == "left": """ Returned when a user leaves a channel. """ # Pack up puppet. for nick in kwargs["nicklist"]: nick = ansi.strip_ansi(nick) if nick in self.db.puppetdict: self.db.puppetdict[nick].move_to(None, to_none=True) self.db.ev_location.msg_contents( self.db.puppetdict[nick].key + self.db.puppetexitmsg) del self.db.puppetdict[nick] return elif kwargs["type"] == "privmsg": """ Returned when the bot is directly messaged. Users can issue commands to the Server bot through IRC PM. "Who" - Return a list of current users in the MUD "About" - Describes the bot and the connected MUD "Look" - Look at the Evennia location and those within it. "whisper" - Whisper in-game account "whisper user = msg" "Desc" - If empty, shows in-game bots description. Else, sets bots in-game bot description to given value. All other messages return a help message. """ user = kwargs["user"] # Who command - Returns online users in game. if txt.lower().startswith("who"): # return server WHO list (abbreviated for IRC) global _SESSIONS if not _SESSIONS: from evennia.server.sessionhandler import \ SESSIONS as _SESSIONS whos = [] t0 = time.time() for sess in _SESSIONS.get_sessions(): delta_cmd = t0 - sess.cmd_last_visible delta_conn = t0 - session.conn_time account = sess.get_account() whos.append("%s (%s/%s)" % (utils.crop("|w%s|n" % account.name, width=25), utils.time_format(delta_conn, 0), utils.time_format(delta_cmd, 1))) text = "Who list (online/idle): %s" % ", ".join( sorted(whos, key=lambda w: w.lower())) # Return Message. super(ServerBot, self).msg(privmsg=((text, ), {"user": user})) # About command - Return a blurb explaining origin of bot. elif txt.lower().startswith("about"): # some bot info text = self.db.botdesc # Return Message. super(ServerBot, self).msg(privmsg=((text, ), {"user": user})) # Look command - Look at the Evennia location and those within it. elif txt.lower().startswith("look"): # Mirror in-game look command. txt = txt.partition(" ")[2] if not txt: target = self.db.ev_location else: result = search.object_search( txt, candidates=self.db.ev_location.contents) target = result[0] if len(result) > 0 else None if not target: text = "'%s' could not be located." % txt else: text = target.return_appearance( self.db.puppetdict[user]).replace('\n', ' ') # Return Message. super(ServerBot, self).msg(privmsg=((text, ), {"user": user})) # Desc command - If empty, shows in-game bots description. Else, # sets bots in-game bot description to given value. elif txt.lower().startswith("desc"): # Split text - set desc as text or return current desc if none. txt = txt.partition(" ")[2] if not txt: text = self.db.puppetdict[user].db.desc else: self.db.puppetdict[user].db.desc = txt text = "Desc changed to: " + txt # Return Message. super(ServerBot, self).msg(privmsg=((text, ), {"user": user})) # Whisper command - Whisper a user in game through a puppet. elif txt.lower().startswith("whisper"): # Parse input. Must be in form 'whisper nick = msg' txt = txt.split(" ", 1)[1] try: nick, msg = txt.split("=") except Exception: text = "Whisper Usage: 'Whisper Character = Msg'" super(ServerBot, self).msg(privmsg=((text, ), { "user": user })) return if not nick or not msg: text = "Whisper Usage: 'Whisper Character = Msg'" super(ServerBot, self).msg(privmsg=((text, ), { "user": user })) return puppet = self.db.puppetdict[ansi.strip_ansi(user)] target = puppet.search(nick) if not target: text = "Whisper Aborted: Character could not be found." # Return Message. super(ServerBot, self).msg(privmsg=((text, ), { "user": user })) return puppet.execute_cmd("whisper " + nick + "=" + msg) text = 'You whisper to ' + nick + ', "' + msg + '"' super(ServerBot, self).msg(privmsg=((text, ), {"user": user})) return # Default message - Acts as help information. else: text = ( "Command list: \n" ' "Who": Return a list of online users on %s.\n' ' "About": Returns information about %s.\n' ' "Look": Look at the Evennia location and those within it.\n' ' "Desc": If empty, shows in-game bots description. Else, sets\n' ' "whisper" - Whisper in-game account "whisper user = msg"\n' ' bots in-game bot description to given value.\n' ' All other messages return this help message.') % ( settings.SERVERNAME, settings.SERVERNAME) # Return Message. super(ServerBot, self).msg(privmsg=((text, ), {"user": user})) elif kwargs["type"] == "action": """ Returned when a user uses /me in IRC """ # Cause puppet to act out pose. if ansi.strip_ansi(kwargs["user"]) in self.db.puppetdict: user = ansi.strip_ansi(kwargs["user"]) self.db.puppetdict[user].execute_cmd("pose " + txt) return else: """ Everything else is assumed to be text to speak. """ # Cause the puppet to say the message. if ansi.strip_ansi(kwargs["user"]) in self.db.puppetdict: user = ansi.strip_ansi(kwargs["user"]) self.db.puppetdict[user].execute_cmd("say " + txt) return
def func(self): """ Implements the multidescer. We will use `db.desc` for the description in use and `db.multidesc` to store all descriptions. """ caller = self.caller args = self.args.strip() switches = self.switches try: if "list" in switches or "all" in switches: # list all stored descriptions, either in full or cropped. # Note that we list starting from 1, not from 0. _update_store(caller) do_crop = "full" not in switches if do_crop: outtext = ["|w%s:|n %s" % (key, crop(desc)) for key, desc in caller.db.multidesc] else: outtext = ["\n|w%s:|n|n\n%s\n%s" % (key, "-" * (len(key) + 1), desc) for key, desc in caller.db.multidesc] caller.msg("|wStored descs:|n\n" + "\n".join(outtext)) return elif "edit" in switches: # Use the eveditor to edit/create the named description if not args: caller.msg("Usage: %s/edit key" % self.key) return # this is used by the editor to know what to edit; it's deleted automatically caller.db._multidesc_editkey = args # start the editor EvEditor(caller, loadfunc=_load_editor, savefunc=_save_editor, quitfunc=_quit_editor, key="multidesc editor", persistent=True) elif "delete" in switches or "del" in switches: # delete a multidesc entry. if not args: caller.msg("Usage: %s/delete key" % self.key) return _update_store(caller, args, delete=True) caller.msg("Deleted description with key '%s'." % args) elif "swap" in switches or "switch" in switches or "reorder" in switches: # Reorder list by swapping two entries. We expect numbers starting from 1 keys = [arg for arg in args.split("-", 1)] if not len(keys) == 2: caller.msg("Usage: %s/swap key1-key2" % self.key) return key1, key2 = keys # perform the swap _update_store(caller, key1, swapkey=key2) caller.msg("Swapped descs '%s' and '%s'." % (key1, key2)) elif "set" in switches: # switches one (or more) of the multidescs to be the "active" description _update_store(caller) if not args: caller.msg("Usage: %s/set key [+ key2 + key3 + ...]" % self.key) return new_desc = [] multidesc = caller.db.multidesc for key in args.split("+"): notfound = True lokey = key.strip().lower() for mkey, desc in multidesc: if lokey == mkey: new_desc.append(desc) notfound = False continue if notfound: # if we get here, there is no desc match, we add it as a normal string new_desc.append(key) new_desc = "".join(new_desc) caller.db.desc = new_desc caller.msg("%s\n\n|wThe above was set as the current description.|n" % new_desc) elif self.rhs or "add" in switches: # add text directly to a new entry or an existing one. if not (self.lhs and self.rhs): caller.msg("Usage: %s/add key = description" % self.key) return key, desc = self.lhs, self.rhs _update_store(caller, key, desc) caller.msg("Stored description '%s': \"%s\"" % (key, crop(desc))) else: # display the current description or a numbered description _update_store(caller) if args: key = args.lower() multidesc = caller.db.multidesc for mkey, desc in multidesc: if key == mkey: caller.msg("|wDecsription %s:|n\n%s" % (key, desc)) return caller.msg("Description key '%s' not found." % key) else: caller.msg("|wCurrent desc:|n\n%s" % caller.db.desc) except DescValidateError as err: # This is triggered by _key_to_index caller.msg(err)
def func(self): """ Implements the multidescer. We will use `db.desc` for the description in use and `db.multidesc` to store all descriptions. """ caller = self.caller args = self.args.strip() switches = self.switches try: if "list" in switches or "all" in switches: # list all stored descriptions, either in full or cropped. # Note that we list starting from 1, not from 0. _update_store(caller) do_crop = not "full" in switches if do_crop: outtext = [ "|w%s:|n %s" % (key, crop(desc)) for key, desc in caller.db.multidesc ] else: outtext = [ "\n|w%s:|n|n\n%s\n%s" % (key, "-" * (len(key) + 1), desc) for key, desc in caller.db.multidesc ] caller.msg("|wStored descs:|n\n" + "\n".join(outtext)) return elif "edit" in switches: # Use the eveditor to edit/create the named description if not args: caller.msg("Usage: %s/edit key" % self.key) return # this is used by the editor to know what to edit; it's deleted automatically caller.db._multidesc_editkey = args # start the editor EvEditor(caller, loadfunc=_load_editor, savefunc=_save_editor, quitfunc=_quit_editor, key="multidesc editor", persistent=True) elif "delete" in switches or "del" in switches: # delete a multidesc entry. if not args: caller.msg("Usage: %s/delete key" % self.key) return _update_store(caller, args, delete=True) caller.msg("Deleted description with key '%s'." % args) elif "swap" in switches or "switch" in switches or "reorder" in switches: # Reorder list by swapping two entries. We expect numbers starting from 1 keys = [arg for arg in args.split("-", 1)] if not len(keys) == 2: caller.msg("Usage: %s/swap key1-key2" % self.key) return key1, key2 = keys # perform the swap _update_store(caller, key1, swapkey=key2) caller.msg("Swapped descs '%s' and '%s'." % (key1, key2)) elif "set" in switches: # switches one (or more) of the multidescs to be the "active" description _update_store(caller) if not args: caller.msg("Usage: %s/set key [+ key2 + key3 + ...]" % self.key) return new_desc = [] multidesc = caller.db.multidesc for key in args.split("+"): notfound = True lokey = key.strip().lower() for mkey, desc in multidesc: if lokey == mkey: new_desc.append(desc) notfound = False continue if notfound: # if we get here, there is no desc match, we add it as a normal string new_desc.append(key) new_desc = "".join(new_desc) caller.db.desc = new_desc caller.msg( "%s\n\n|wThe above was set as the current description.|n" % new_desc) elif self.rhs or "add" in switches: # add text directly to a new entry or an existing one. if not (self.lhs and self.rhs): caller.msg("Usage: %s/add key = description" % self.key) return key, desc = self.lhs, self.rhs _update_store(caller, key, desc) caller.msg("Stored description '%s': \"%s\"" % (key, crop(desc))) else: # display the current description or a numbered description _update_store(caller) if args: key = args.lower() multidesc = caller.db.multidesc for mkey, desc in multidesc: if key == mkey: caller.msg("|wDecsription %s:|n\n%s" % (key, desc)) return caller.msg("Description key '%s' not found." % key) else: caller.msg("|wCurrent desc:|n\n%s" % caller.db.desc) except DescValidateError, err: # This is triggered by _key_to_index caller.msg(err)