def antisubstitute_cmd(ses, args, input): """ Allows you to create antisubstitutes. For any line that contains an antisubstitute, we won't do substitutions on it. category: commands """ item = args["item"] quiet = args["quiet"] sm = exported.get_manager("substitute") if not item: data = sm.getAntiSubstitutesInfo(ses) if not data: data = ["antisubstitute: no antisubstitutes defined."] exported.write_message("antisubstitutes:\n" + "\n".join(data), ses) return sm.addAntiSubstitute(ses, item) if not quiet: exported.write_message("antisubstitute: {%s} added." % item, ses)
def chr_cmd(ses, args, input): """ Allows you to assign arbitrary characters to variables. For example, if you wanted to assign ASCII char 7 to variable ctrlG you could do: #chr {ctrlG} {7} Since this creates a variable, you should remove the variable with the unvariable command. Note: This won't work if you don't have the variable module loaded. category: commands """ var = args["var"] ascii = args["ascii"] quiet = args["quiet"] vm = exported.get_manager("variable") if not vm: exported.write_error("chr: no variable manager found.") return if ascii < 0 or ascii > 127: exported.write_error("chr: ascii argument out of range of 0 to 127.") return vm.addVariable(ses, var, chr(ascii)) if not quiet: exported.write_message("chr: variable %s added." % var)
def changeSession(self, name=''): """ Changes the current session to another named session. If they don't pass in a name, we get the next available non-common session if possible. @param name: the name of the session to switch to @type name: string """ if name == '': keys = self._sessions.keys() # it's a little bit of finagling here to make sure # that the common session is the last one we would # switch to name = self._current_session.getName() keys.remove(name) if not name == "common": keys.remove("common") keys.append("common") self._current_session = self._sessions[keys[0]] # if they pass in a name, we switch to that session. elif self._sessions.has_key(name): self._current_session = self._sessions[name] else: exported.write_error("No session of that name.") return exported.write_message("Switching to session '%s'." % self._current_session.getName())
def unload_cmd(ses, args, input): """ Unloads a module from Lyntin by calling the module's "unload" function and then removing references to it in the Python environment. examples: #unload wbgscheduler #unload modules.alias category: commands """ mod = args["modulename"] if sys.modules.has_key(mod): _module = sys.modules[mod] if _module.__dict__.has_key("lyntin_import"): if _module.__dict__.has_key("unload"): try: _module.unload() except: exported.write_traceback("unload: module %s didn't unload properly." % mod) else: exported.write_error("unload: module %s doesn't have an unload function." % mod) del sys.modules[mod] exported.write_message("unload: module %s unloaded." % mod) config.lyntinmodules.remove(mod) return else: exported.write_error("unload: module %s cannot be unloaded." % mod) return exported.write_error("unload: module %s is not loaded." % mod)
def tick_cmd(ses, args, input): """ Displays the number of seconds left before this session's ticker ticks. When a tick happens, it will look for a TICK!!! alias then a TICK alias. Finding none, it will print TICK!!! to the ui. When a tickwarning happens, it will look for a TICKWARN!!! alias and then a TICKWARN alias. Finding none, it will print a tickwarning message to the ui. This allows you to perform an event every x number of seconds. see also: tick, tickon, tickoff, ticksize, tickwarnsize category: commands """ global myscheduler if not hasattr(ses, "_ticker"): ses._ticker = DEFAULT_TICKER.copy() if ses._ticker["enabled"] == 1: tick = myscheduler._current_tick sevent = myscheduler.getEventById(ses.getName() + "tick") delta = sevent._next_tick - tick exported.write_message("tick: next tick in %d seconds." % delta, ses) else: exported.write_message("tick: ticker is not enabled.", ses)
def swexclude_cmd(ses, args, input): """ Adds words that should be excluded from speedwalk expansion as well as tells you which words are currently being excluded. If you had swdirs "n", "e", "s", and "w", you might want to create excludes for the words "sense", "news", "sew", ... Which are real words that you most likely don't want to be expanded. examples: #swexclude {end} #swexclude {news} see also: swdir category: commands """ # originally written by Sebastian John excludes = args["exclude"] quiet = args["quiet"] # they typed '#swexclude'--print out all current speedwalking excludes if len(excludes) == 0: data = exported.get_manager("speedwalk").getExcludesInfo(ses) if not data: data = ["swexcl: no speedwalking excludes defined."] exported.write_message("swexcludes:\n" + "\n".join(data), ses) return for exclude in excludes: exported.get_manager("speedwalk").addExclude(ses, exclude) if not quiet: exported.write_message("swexclude: {%s} added." % exclude, ses)
def antigag_cmd(ses, args, input): """ Allows you to create antigags. For any line that contains an antigag, we won't do gags on it. category: commands """ item = args["item"] quiet = args["quiet"] gm = exported.get_manager("gag") gd = gm.getGagData(ses) if not item: data = gd.getAntiGagsInfo() if not data: data = ["antigag: no antigags defined."] exported.write_message("antigags\n" + "\n".join(data), ses) return gd.addAntiGag(item) if not quiet: exported.write_message("antigag: {%s} added." % item, ses)
def history_cmd(ses, args, input): """ #history prints the current history buffer. ! will call an item in the history indexed by the number after the !. You can also do replacements via the sub=repl syntax. examples: #history [count=30] prints the last count entries in the history buffer ! executes the last thing you did !4 executes the fourth to last thing you did !4 3k=gk executes the fourth to last thing you did after replacing 3k with gk in it category: commands """ count = args["count"] historylist = exported.get_history(count) for i in range(0, len(historylist)): historylist[i] = "%d %s" % ((i+1), historylist[i]) historylist.reverse() exported.write_message("History:\n" + "\n".join(historylist))
def substitute_cmd(ses, args, input): """ With no arguments, prints all substitutes. With one argument, prints all substitutes which match the argument. Otherwise creates a substitution. Braces are advised around both 'item' and 'substitution'. category: commands """ item = args["item"] substitution = args["substitution"] quiet = args["quiet"] sm = exported.get_manager("substitute") if not substitution: data = sm.getInfo(ses, item) if not data: data = ["substitute: no substitutes defined."] exported.write_message("substitutes:\n" + "\n".join(data), ses) return sm.addSubstitute(ses, item, substitution) if not quiet: exported.write_message("substitute: {%s} {%s} added." % (item, substitution), ses)
def find_nmes(args): global exits_line,targets text= args['data'] if "[ Exits:" in text: exits_line = 1 if exits_line == 1: found = re.search('[A|An] (\w+) ',text) if found: exported.write_message(targets) targets.append(found.group(1)) if '>' in text: exits_line = 0 try: if health< 500: exported.lyntin_command('treat') except: pass health =re.search('(\d+/\d+)hp',text) if health: health = int(health.group(1).split('/')[0]) if 'Fighting:' in text: if random.choice(range(7)) == 1: exported.lyntin_command('kick' if random.choice('kb')== 'k' else 'bash') exported.lyntin_command('dirt' if random.choice('es') == 'e' else 'stun') if random.choice(range(7)) == 1: exported.lyntin_command('intimidate') if health < 300 : exported.write_message('trying to flee \n') exported.lyntin_command('flee') if health < 100 : exported.lyntin_command('fle') return args['data']
def snoop_cmd(ses, args, input): """ Sets the session specified into or out of snooping mode. When a session is in snoop mode, you will see mud data from that session regardless of what session is the current session. examples: #snoop a -- tells you whether a is in snoop mode #snoop a on -- sets snoop mode for a category: commands """ snoopsession = args["session"] mode = args["mode"] ses = exported.get_session(snoopsession) if ses == None: exported.write_error("snoop: session '%s' does not exist." % snoopsession) return if mode != None: ses.setSnoop(mode) if exported.get_config("snoop", ses, 1) == 1: exported.write_message("snoop: snooping is enabled for %s." % snoopsession) else: exported.write_message("snoop: snooping is disabled for %s." % snoopsession)
def textin_cmd(ses, args, input): """ Takes the contents of the file and outputs it directly to the mud without processing it (like #read does). If you don't specify a directory, Lyntin will look for the file in the datadir. category: commands """ if (ses.getName() == "common"): exported.write_error("textin cannot be applied to common session.", ses) return filename = args["file"] if os.sep not in filename: filename = config.options["datadir"] + filename try: f = open(filename, "r") contents = f.readlines() f.close() for mem in contents: mem = utils.chomp(mem) ses.getSocketCommunicator().write(mem + "\n") exported.write_message("textin: file %s read and sent to mud." % filename, ses) except IOError: exported.write_error("textin: file %s is not readable." % filename, ses) except Exception, e: exported.write_error("textin: exception thrown %s." % e, ses)
def tickon_cmd(ses, args, input): """ Turns on the ticker for this session. see also: tick, tickon, tickoff, ticksize, tickwarnsize category: commands """ global myscheduler if not hasattr(ses, "_ticker"): ses._ticker = DEFAULT_TICKER.copy() tick_tagname = ses.getName() + "tick" tickwarn_tagname = ses.getName() + "tickwarn" # quick check to make sure there isn't already a tick event # for this session if myscheduler.getEventById(tick_tagname): exported.write_error("tickon: ticker is already enabled.", ses) return _addtickevents(ses) ses._ticker["enabled"] = 1 exported.write_message("tickon: session %s ticker enabled." % ses.getName(), ses)
def ticksize_cmd(ses, args, input): """ Sets and displays the number of seconds between ticks for this session. examples: #ticksize #ticksize 6 #ticksize 1h2m30s see also: tick, tickon, tickoff, ticksize, tickwarnsize category: commands """ if not hasattr(ses, "_ticker"): ses._ticker = DEFAULT_TICKER.copy() size = args["size"] if size == 0: exported.write_message("ticksize: ticksize is %d seconds." % ses._ticker["len"], ses) return ses._ticker["len"] = size ret = _removetickevents(ses) if ret: _addtickevents(ses) exported.write_message("ticksize: tick length set to %s." % str(size), ses)
def unschedule_cmd(ses, args, input): """ Allows you to remove a scheduled event by id. To remove all events scheduled use *. To see a list of the events and ids for the current session use the #sched command. examples: #unschedule * #unschedule 44 category: commands """ global myscheduler id = args["str"] quiet = args["quiet"] if id: ret = myscheduler.removeById(id) if not ret: if id == "*": exported.write_error("unschedule: no scheduled events to unschedule.") else: exported.write_error("unschedule: id '%s' is not valid." % id) return if not quiet: exported.write_message("events removed:\n%s" % "\n".join(ret)) return exported.write_message("not implemented yet.")
def run(self): """ This is the poll loop for user input.""" try: while not self.shutdownflag: if os.name == 'posix': if self._rline == 1: data = self._posix_readline_input() else: data = self._posix_input() else: data = self._non_posix_input() if data != None: self.handleinput(data) # FIXME - this is just plain icky. the issue is that # we need to know we're ending _before_ we block for # the next input. otherwise Lyntin will shut down except # for this thread which will hang around blocking until # the user hits the enter key. # # any good ideas for dealing with this are more than welcome. if data.find("#end") == 0: break except select.error, e: (errno,name) = e if errno == 4: exported.write_message("system exit: select.error.") event.ShutdownEvent().enqueue() return
def highlight_cmd(ses, args, input): """ With no arguments, prints all highlights. With one argument, prints all highlights which match the arg. With multiple arguments, creates a highlight. Highlights enable you to colorfully "tag" text that's of interest to you with the given style. Styles available are: styles foreground colors background colors bold black grey b black blink red light red b red reverse green light green b green underline yellow light yellow b yellow blue light blue b blue magenta light magenta b magenta cyan light cyan b cyan white light white b white Highlights handle * at the beginning and end of non-regular expression texts. Highlights will handle regular expression texts as well. See "#help regexp" for more details. Note: blink, underline, and reverse may not be available in all ui's. examples: #highlight {green} {Sven arrives.} #highlight {reverse,green} {Sven arrives.} #highlight {blue} {r[^.*?says:]} which is the same as: #highlight {blue} {*says:} category: commands """ style = args["style"] text = args["text"] quiet = args["quiet"] if not text: data = exported.get_manager("highlight").getInfo(ses, style, 1) if not data: data = ["highlight: no highlights defined."] exported.write_message("highlights:\n" + "\n".join(data), ses) return style = style.lower() stylelist = style.split(",") for mem in stylelist: if mem not in ansi.STYLEMAP: exported.write_error("highlight: '%s' not a valid style.\nCheck out the highglight help file for more information." % mem) return exported.get_manager("highlight").addHighlight(ses, style, text) if not quiet: exported.write_message("highlight: {%s} {%s} added." % (style, text), ses)
def runui(self): global HELP_TEXT exported.add_help("tkui", HELP_TEXT) exported.write_message('For tk help type "#help tkui".') exported.add_command("colorcheck", colorcheck_cmd) # run the tk mainloop here self._tk.mainloop()
def version_cmd(ses, args, input): """ Displays the version number, contact information, and web-site for Lyntin. category: commands """ exported.write_message(constants.VERSION)
def sound_cmd(ses, args, input): """ This command allows you to play a sound. """ filename = args["filename"] try: play('sounds/%s' % filename) except: exported.write_message("couldn't play sound: %s" % filename)
def killall_cmd(ses, args, input): """ Clears all sessions of session oriented stuff: aliases, substitutions, gags, variables, so on so forth. category: commands """ for mem in exported.get_active_sessions(): mem.clear() exported.write_message("killall: session %s cleared." % mem.getName())
def grep_cmd(ses, args, input): """ Similar to the unix grep command, this allows you to extract information from the session's data buffer using regular expressions. It prints matching lines in their entirety. examples: #grep {says:} 1000 Greps the last 1000 lines of the databuffer for lines that have "says:" in them. category: commands """ if ses.getName() == "common": exported.write_error("grep cannot be applied to common session.", ses) return pattern = args["pattern"] size = args["size"] context = args["context"] buffer = ses.getDataBuffer() ret = [] cpattern = re.compile(pattern) for i in range(max(len(buffer) - size, 0), len(buffer)): mem = buffer[i] if cpattern.search(mem): if context > 0: mem = [] if i > 0: bound = i - context if bound < 0: bound = 0 for j in range(bound, i): mem.append(" " + buffer[j]) mem.append("+ " + buffer[i]) if i < len(buffer): bound = i + context + 1 if bound > len(buffer) - 1: bound = len(buffer) - 1 for j in range(i + 1, bound): mem.append(" " + buffer[j]) mem = "".join(mem) ret.append(mem) if context == 0: splitter = "" else: splitter = "---\n" exported.write_message("grep %s results:\n%s" % (pattern, splitter.join(ret)), ses)
def handle_timer(args): # tick tock global ticks for session in ticks.keys(): ticks[session] += 1 if ticks[session] >= 200: exported.write_message("You have been idle.", ses=session) exported.lyntin_command("#raw", internal=1, session=session) ticks[session] = 0
def info_cmd(ses, args, input): """ Prints all the information about the active session: actions, aliases, gags, highlights, variables, ticker, verbose, speedwalking, and other various things. category: commands """ data = exported.myengine.getStatus(ses) data = "\n".join(data) exported.write_message(data, ses)
def wshowme_cmd(ses, args, input): """ Writes the text into the named window, if the current ui supports named windows. If named windows are unsupported, writes the text into the main window. examples: #action {^%0 annihilates you!} {#wshowme Alert {EJECT! EJECT! EJECT!}} category: commands """ exported.write_message(args["text"], ses, window=args["window"])
def clear_cmd(ses, words, input): """ This command clears a session of all session data (except the actual connection). This covers gags, subs, actions, aliases... category: commands """ try: ses.clear() exported.write_message("clear: session %s cleared." % ses.getName(), ses) except Exception, e: exported.write_traceback("clear: error in clearing session %s" % ses)
def set_current_session(self, newsession): """ Changes the current session to another session. @param newsession: the session to change to @type newsession: session.Session instance """ previous_session = self._current_session self._current_session = newsession exported.hook_spam("session_change_hook", {"new": newsession, "previous": previous_session}) exported.write_message("%s now current session." % newsession.getName())
def tickoff_cmd(ses, args, input): """ Turns off the ticker for this session. see also: tick, tickon, tickoff, ticksize, tickwarnsize category: commands """ _removetickevents(ses) ses._ticker["enabled"] = 0 exported.write_message("tickoff: session %s ticker disabled." % ses.getName(), ses)
def action_tags_cmd(ses, args, input): """ Shows all the tags available see also: action, unaction, enable, disable category: commands """ list = exported.get_manager("action").listTags(ses) if list: exported.write_message("\n".join(list)) else: exported.write_message("No tags defined.")
def get_targs(): global immd_tars,taking_inputs,exits if immd_tars: exported.lyntin_command('kill '+ immd_tars.pop()) exported.write_message('\nthese are current tars '+ str(immd_tars)) else: if exits: exported.lyntin_command(random.choice(exits)) taking_inputs = 'yes' exits = [] else: exported.lyntin_command(random.choice('eswn')) taking_inputs = 'yes'
def __init__(self, cmd_engine, event_classifier, group_list): exported.write_message("ClerMod: DEBUG: init {0}".format(self)) factory = group.GroupColumnFactory() healView = group.GroupView() healView.add_column(factory.get_num_column()) healView.add_column(factory.get_name_column()) healView.add_column(factory.get_hp_column()) healView.add_column(factory.get_position_column()) healView.add_column(factory.get_near_column()) healView.add_column(factory.get_drain_column()) self._mode = False event_classifier.add_event("group_health_header", healView.header()) event_classifier.add_event("group_health_member", healView.member()) event_classifier.add_callback("group_health_header", self) event_classifier.add_callback("group_health_member", self) event_classifier.add_callback("prompt", self) self._event_classifier = event_classifier self._group_list = group_list self._cmd_engine = cmd_engine
def _tickwarnfunc(ses, warnlen): """ Handles executing the command or displaying a message to the user. @param ses: the Session instance @type ses: Session @param warnlen: the warning length @type warnlen: int """ am = exported.get_manager("alias") if am: tickaction = am.getAlias(ses, "TICKWARN!!!") if not tickaction: tickaction = am.getAlias(ses, "TICKWARN") if tickaction: event.InputEvent(tickaction, internal=1, ses=ses).enqueue() else: exported.write_message("ticker: %d seconds to tick!" % warnlen)
def help_cmd(ses, args, input): """ With no arguments, shows all the help files available. With an argument, shows that specific help file or lists the contents of that category of help files. examples: #help - lists all help files in the root #help help - shows help for the help command #help commands.substitute - shows help for the substitute command #help commands - shows help for the commands category Items that have a number in parentheses after them are a category. The number is how many help topics are below that category. example: > #help lyntin: ::Lyntin Help:: lyntin: lyntin: category: root lyntin: lyntin: commands(55) readme(13) lyntin: textui > category: commands """ item = args["item"] keys = item.split(".") data = "Help:\n\n" error, breadcrumbs, text = exported.get_help(item) if error: data += "%s\n\n" % error if breadcrumbs: data += "category: %s\n\n" % breadcrumbs data += text exported.write_message(data)
def on_event(self, ev_type, match): if not self._enabled: exported.write_message("FragMod: WARN: disabled Mod got on_event") if ev_type == "group_position_near_header": self._event_classifier.gag_current() self._mode = True if ev_type == "group_position_near_member" and self._mode: self._event_classifier.gag_current() #exported.write_message("FragMod: DEBUG: FragMod on group_position_near_member") self.group_member_pos(match) if (ev_type == "prompt") and self._mode: self._mode = False if self._group_list.myself().position() == "SIT": self._cmd_engine.put(cmds.Cmd("stand"), True) return self._fight = False for m in self._group_list.values(): if m.position() == "FIGHT": self._fight = True self._cmd_engine.put(cmds.CastCmd(self.get_next_spell())) return if ((ev_type == "you_followed") or (ev_type == "you_unmute") or (ev_type == "you_unhardmute") or (ev_type == "you_stood_up")): if ev_type == "you_followed": self._spell_index = 0 self._cmd_engine.put(self._check_cmd) if (ev_type == "you_casted"): self.advance_rotation(match.group("spell")) self._cmd_engine.put(self._check_cmd) if (ev_type == "room_cast") and (not self._fight) and (not self._mode): self._fight = True self._cmd_engine.put(self._check_cmd)
def tickwarnsize_cmd(ses, args, input): """ Sets and displays the number of seconds you get warned before a Tick actually happens. examples: #tickwarnsize #tickwarnsize 6 #tickwarnsize 0 see also: tick, tickon, tickoff, ticksize, tickwarnsize category: commands """ if not hasattr(ses, "_ticker"): ses._ticker = DEFAULT_TICKER.copy() size = args["size"] if size == 0: exported.write_message( "tickwarnsize: tickwarnsize is %d seconds." % ses._ticker["warn_len"], ses) return if size > ses._ticker["len"]: exported.write_error( "tickwarnsize: tickwarn length cannot be >= " + "to ticksize.\nCurrent ticksize is %s." % ses._ticker["len"], ses) return ses._ticker["warn_len"] = size ret = _removetickevents(ses) if ret: _addtickevents(ses) exported.write_message( "tickwarnsize: tickwarn length set to %s." % str(size), ses)
def run(self): """ This is the poll loop for user input.""" try: while not self.shutdownflag: if os.name == 'posix': if self._rline == 1: data = self._posix_readline_input() else: data = self._posix_input() else: data = self._non_posix_input() if data != None: self.handleinput(data) # FIXME - this is just plain icky. the issue is that # we need to know we're ending _before_ we block for # the next input. otherwise Lyntin will shut down except # for this thread which will hang around blocking until # the user hits the enter key. # # any good ideas for dealing with this are more than welcome. if data.find("#end") == 0: break except select.error as e: (errno, name) = e if errno == 4: exported.write_message("system exit: select.error.") event.ShutdownEvent().enqueue() return except SystemExit: exported.write_message("system exit: you'll be back...") event.ShutdownEvent().enqueue() except: exported.write_traceback() event.ShutdownEvent().enqueue()
def mudfilter(self, args): ses = args["session"] text = args["dataadj"] colorline = utils.filter_cm(text) nocolorline = ansi.filter_ansi(colorline) if nocolorline == "\n": return text #if self._enabled: self._event_classifier.mudfilter(text) if self._event_classifier.is_gagged(): text = "" with open('nocolor.log', 'ab') as f: try: f.write(ansi.filter_ansi(text).encode("utf-8")) except TypeError: exported.write_message("sowmud.mudfilter: ERROR: unexpected return type by submodule: {0}".format(type(text))) text = "" self._proxy.send(text) return text
def log_cmd(ses, args, input): """ Will start or stop logging to a given filename for that session. Each session can have its own logfile. If USERPREFIX is set, then every line from the user will be prepended with this prefix and immediately written into log file. If USERPREFIX is omitted, then the user input will be attached to mud prompts before logging. category: commands """ logfile = args["logfile"] databuffer = args["databuffer"] stripansi = args["stripansi"] userprefix = args["userprefix"] if not ses.isConnected(): exported.write_error("log: You must have a session to log.", ses) return lm = exported.get_manager("logger") loggerdata = lm.getLogData(ses) if not logfile: exported.write_message(loggerdata.getStatus(), ses) return # handle stopping logging if loggerdata.isLogging() == 1: try: logname = loggerdata._logfile.name loggerdata.closeLogFile() exported.write_message("log: stopped logging to '%s'." % logname, ses) except Exception, e: exported.write_error("log: logfile cannot be closed (%s)." % (e), ses) return
def math_cmd(ses, args, input): """ Implements the #math command which allows you to manipulate variables above and beyond setting them. examples: #math {hps} {$hps + 5} category: commands """ var = args["var"] ops = args["operation"] quiet = args["quiet"] try: rvalue = eval(ops) varman = exported.get_manager("variable") if varman: varman.addVariable(ses, var, str(rvalue)) if not quiet: exported.write_message( "math: %s = %s = %s." % (var, ops, str(rvalue)), ses) except Exception, e: exported.write_error("math: exception: %s\n%s" % (ops, e), ses)
def unload_cmd(ses, args, input): """ Unloads a module from Lyntin by calling the module's "unload" function and then removing references to it in the Python environment. examples: #unload wbgscheduler #unload modules.alias category: commands """ mod = args["modulename"] if mod in sys.modules: _module = sys.modules[mod] if "lyntin_import" in _module.__dict__: if "unload" in _module.__dict__: try: _module.unload() except: exported.write_traceback( "unload: module %s didn't unload properly." % mod) else: exported.write_error( "unload: module %s doesn't have an unload function." % mod) del sys.modules[mod] exported.write_message("unload: module %s unloaded." % mod) config.lyntinmodules.remove(mod) return else: exported.write_error("unload: module %s cannot be unloaded." % mod) return exported.write_error("unload: module %s is not loaded." % mod)
def deed_cmd(ses, args, input): """ Deeds serve as a kind of notebook - whatever you don't want to forget, store it in a deed. examples:: #deed -- prints all the deeds for that session #deed {$TIMESTAMP Joe healed me} -- adds a new deed to the list #deed 10 -- prints the last 10 deeds Before a deed is stored, variables are expanded--this allows you to use system, global, and session variables in your deeds like $TIMESTAMP which will mark when the deed was created. category: commands """ # original deed_cmd code contributied by Sebastian John if (ses.getName() == "common"): exported.write_error("deed cannot be applied to common session.", ses) return deedtext = args["text"] quiet = args["quiet"] if not deedtext: data = exported.get_manager("deed").getInfo(ses) if data == "": data = "deed: no deeds defined." exported.write_message(data, ses) return if deedtext.isdigit(): data = exported.get_manager("deed").getInfo(ses, deedtext) if data == "": data = "deed: no deeds defined." exported.write_message(data, ses) return exported.get_manager("deed").getDeedData(ses).addDeed(deedtext) if not quiet: exported.write_message("deed: {%s} added." % deedtext, ses)
def remove_callback(self, ev_type, listener): try: self.__callbacks[ev_type].remove(listener) exported.write_message("EventClassifier: DEBUG: " + "successfully removed callback {0} {1}". format(ev_type, listener)) except KeyError: exported.write_message( "EventClassifier: DEBUG: " + "failed to remove callback {0} {1}, KeyError".format( ev_type, listener)) return except ValueError: exported.write_message( "EventClassifier: DEBUG: " + "failed to remove callback {0} {1}, ValueError".format( ev_type, listener)) pass
def read_cmd(ses, args, input): """ Reads in a file running each line as a Lyntin command. This is the opposite of #write which allows you to save session settings and restore them using #read. You can also read in via the commandline when you start Lyntin: lyntin --read 3k And read can handle HTTP urls: lyntin --read http://lyntin.sourceforge.net/lyntinrc #read http://lyntin.sourceforge.net/lyntinrc Note: the first non-whitespace char is used to set the Lyntin command character. If you use non Lyntin commands in your file, make sure the first one is a command char. If not, use #nop . It will skip blank lines. If you don't specify a directory, Lyntin will look for the file in your datadir. category: commands """ filename = args["filename"] import os if os.sep not in filename and not filename.startswith("http://"): filename = config.options["datadir"] + filename if filename.startswith("~"): filename = os.path.expanduser(filename) try: # http reading contributed by Sebastian John if filename.startswith("http://"): contents = utils.http_get(filename).split("\n") else: f = open(filename, "rb") contents = f.readlines() f.close() except Exception as e: exported.write_error( "read: file %s cannot be opened.\n%s" % (filename, e), ses) return contents = [x.decode("utf-8") for x in contents] contents = [m for m in contents if len(m.strip()) > 0] if len(contents) == 0: exported.write_message("read: %s had no data." % filename, ses) return c = exported.get_config("commandchar") if not contents[0].startswith(c): exported.lyntin_command("%sconfig commandchar %s" % (c, contents[0][0]), internal=1, session=ses) command = "" continued = 0 # FIXME - should this be a config setting? esc = "\\" for mem in contents: mem = mem.strip() if len(mem) > 0: # handle multi-line commands if mem.endswith(esc): mem = mem.rstrip(esc) continued = 1 else: continued = 0 command = command + mem if not continued: exported.lyntin_command(command, internal=1, session=ses) command = "" exported.write_message("read: file %s read." % filename, ses)
def load_cmd(ses, args, input): """ Loads/reloads a module. When reloading, it looks for an "unload" function and executes it prior to reloading the module. After reloading/loading, it looks for a "load" function and executes it. Lyntin modules located in the modules package are safe to reload in-game. Lyntin core modules (engine, helpmanager, event...) are NOT safe to import in-game. examples: #load modules.action #load exportuser #load will look for the module on the sys.path. So if your module is not on the sys.path, you should first add the directory using #@: #@ import sys #@ sys.path.append("/directory/where/my/module/exists") Directories specified by the moduledir command-line argument are added to the sys.path upon Lyntin startup. category: commands """ mod = args["modulename"] reload = args["reload"] # if this module has previously been loaded, we try to reload it. if mod in sys.modules: _module = sys.modules[mod] _oldmodule = _module try: if "lyntin_import" in _module.__dict__: # if we're told not to reload it, we toss up a message and then # do nothing if not reload: exported.write_message( "load: module %s has already been loaded." % mod) return # if we loaded it via a lyntin_import mechanism and it has an # unload method, then we try calling that if "unload" in _module.__dict__: try: _module.unload() except: exported.write_traceback( "load: module %s didn't unload properly." % mod) del sys.modules[mod] exported.write_message("load: reloading %s." % mod) except: exported.write_traceback("load: had problems unloading %s." % mod) return else: _oldmodule = None # here's where we import the module try: _module = __import__(mod) _module = sys.modules[mod] if (_oldmodule and "reload" in _oldmodule.__dict__): try: _oldmodule.reload() except: exported.write_traceback( "load: had problems calling reload on %s." % mod) if ("load" in _module.__dict__): _module.load() _module.__dict__["lyntin_import"] = 1 exported.write_message("load successful.") if mod not in config.lyntinmodules: config.lyntinmodules.append(mod) except: exported.write_traceback("load: had problems with %s." % mod)
if not command: data = ad.getInfo(name) if not data: data = ["alias: no aliases defined."] exported.write_message("aliases:\n" + "\n".join(data), ses) return # they're creating an alias try: ad.addAlias(name, command) except ValueError, e: exported.write_error("alias: %s" % e, ses) if not quiet: exported.write_message("alias: {%s} {%s} added." % (name, command), ses) commands_dict["alias"] = (alias_cmd, "alias= expansion= quiet:boolean=false") def unalias_cmd(ses, args, input): """ Allows you to remove aliases. category: commands """ func = exported.get_manager("alias").getAliasData(ses).removeAliases modutils.unsomething_helper(args, func, None, "alias", "aliases") commands_dict["unalias"] = (unalias_cmd, "str= quiet:boolean=false")
# for this thread which will hang around blocking until # the user hits the enter key. # # any good ideas for dealing with this are more than welcome. if data.find("#end") == 0: break except select.error, e: (errno, name) = e if errno == 4: exported.write_message("system exit: select.error.") event.ShutdownEvent().enqueue() return except SystemExit: exported.write_message("system exit: you'll be back...") event.ShutdownEvent().enqueue() except: exported.write_traceback() event.ShutdownEvent().enqueue() def write(self, args): """ Handles writing information from the mud and/or Lyntin to the user. """ msg = args["message"] if type(msg) == types.StringType: msg = message.Message(msg, message.LTDATA)
def status(self): status = self._bot.status() exported.write_message(status)
def diagnostics_cmd(ses, args, input): """ This is very useful for finding out all the information about Mudder while it's running. This will print out operating system information, Python version, what threads are running (assuming they're registered with the ThreadManager), hooks, functions connected to hooks, and #info for every session. It's very helpful in debugging problems that are non-obvious or are platform specific. It's also invaluable in bug-reporting. It can take a filename argument and will copy the #diagnostics output to that file. This allows you easier method of submitting diagnostics output along with bug reports. Note: Windows users should either use two \\'s or use / to separate directory names. category: commands """ import os, sys message = [] message.append("Diagnostics:") message.append(exported.myengine.getDiagnostics()) message.append("Hook state:") data = exported.myengine.checkHooks() data.sort() for mem in data: message.append(mem) message.append("Thread state:") data = exported.myengine.checkthreads() data.sort() for mem in data: message.append(mem) message.append("OS/Python information:") try: message.append(" sys.version: %s" % sys.version) except: message.append(" sys.version not available.") try: message.append(" os.name: %s" % os.name) except: message.append(" os.name not available.") message.append(" Mudder version 0.1 (lyntin: %s)" % (constants.VERSION[:constants.VERSION.find("\n")])) message.append("Lyntin Options:") for mem in config.options.keys(): message.append(" %s: %s" % (mem, repr(config.options[mem]))) exported.write_message("\n".join(message)) exported.write_message("This information can be dumped to a " "file by doing:\n #diagnostics dumpfile.txt") logfile = args["logfile"] if logfile: import time try: f = open(logfile, "w") f.write("This file was created on: %s" % time.asctime()) f.write(os.linesep + os.linesep) f.write(os.linesep.join(message)) f.close() exported.write_message("diagnostics: written out to file %s." % logfile) except Exception, e: exported.write_error("diagnostics: Error writing to file %s. %s" % (logfile, e))
def session_cmd(ses, args, input): """ This command creates a connection to a specific mud. When you create a session, that session becomes the active Lyntin session. To create a session to 3k.org named "3k": #session 3k www.3k.org 5000 To create a session and initialize it with commands from a specific file: #session 3k www.3k.org 5000 /home/david/3k/3k.lyntin Then to create another session to another mud: #session eto gytje.pvv.unit.no 4000 Then if 3k was your active session, you could do things on the eto session by prepending your command with "#eto ": #eto say hello or switch to the eto session by typing just "#eto". category: commands """ name = args["sessionname"] host = args["host"] port = args["port"] filename = args["filename"] if not name and not host and (not port or port == -1): data = "Sessions available:\n" for mem in exported.get_active_sessions(): data += " %s: %r\n" % (mem.getName(), mem._socket) exported.write_message(data[:-1]) return if not name or not host or port == -1: exported.write_error("syntax: #session <sesname> <host> <port>") return if name.isdigit(): exported.write_error("session: session name cannot be all numbers.") return e = exported.myengine ses = e.getSession(name) if ses != None: preexistingsession = 1 else: preexistingsession = 0 if preexistingsession == 1 and ses.isConnected(): exported.write_error("session: session of that name already exists.") return try: # create and register a session for this connection.... if ses == None: ses = e.createSession(name) sock = net.SocketCommunicator(e, ses, host, port) ses.setSocketCommunicator(sock) ses._host = host ses._port = port e.changeSession(name) # connect to the mud... # this might take a while--we block here until this is done. sock.connect(host, port, name) # start the network thread e.startthread("network", sock.run) except: exported.write_traceback("session: had problems creating the session.") ses.setSocketCommunicator(None) if preexistingsession == 0: try: e.unregisterSession(ses) except: pass try: e.closeSession(name) except: pass # populate the session using the specified file if filename: read_cmd(ses, args, '')
def config_cmd(ses, args, input): """ Allows you to view and change configuration options that affect how Lyntin functions. Configuration options can be session oriented or global to all of Lyntin. examples: #config displays global configuration and session configuration for the current session #a #config displays global configuration and session configuration for the session named 'a' #config ansicolor displays information about the mudecho configuration option #config ansicolor on sets the ansicolor configuration option to on category: commands """ name = args["name"] value = args["value"] quiet = args["quiet"] c = exported.myengine.getConfigManager() # if they didn't specify a name, then we print out all the # configuration stuff for general and this session if not name: general = c.getConfigItems(None) globmap = {} for mem in general: globmap[mem._name] = mem.toString() seslisting = c.getConfigItems(ses) sesmap = {} for mem in seslisting: sesmap[mem._name] = mem.toString() output = "Commandline:\n" output += _fixmap(16, config.options) + "\n" output += "Global:\n" output += _fixmap(16, globmap) + "\n" output += "Session:\n" output += _fixmap(16, sesmap) + "\n" exported.write_message(output, ses) return # try to find a session item first ci = c.getConfigItem(name, ses) if not ci: ci = c.getConfigItem(name) if not ci: exported.write_error( "config: config manager does not recognize %s as a config item." % name) return if not value: # we print out everything we know about this config item. output = "config: %s\n\ncurrent value: %s\n\n%s\n" % \ (name, ci.toString(), utils.wrap_text(ci._description, wraplength=60)) exported.write_message(output) return try: try: c.change(name, value, ses) except: c.change(name, value) exported.write_message("config: %s set to %s." % (name, value), ses) except Exception, e: exported.write_error(e)
def python_cmd(ses, words, input): """ #@ allows you to execute arbitrary Python code inside of Lyntin. It will first look for a module named "lyntinuser" and execute the code inside that module's __dict__ environment. If no such module exists, it will execute the code inside modules.advanced . At present it can only handle one-line Python statements. examples: #@ print "hello" #@ print "\\n".join(exported.get_commands()) category: commands """ global execdictglobals, execdictlocals # NOTE: if we ever get to handling multiple-lines, we'll need # to change this function completely. try: if execdictlocals == None: execdictlocals = {} execdictlocals["session"] = ses execdictlocals["exported"] = exported my_usermodule = _get_user_module() if my_usermodule: dictglobals = my_usermodule.__dict__ else: if execdictglobals == None: execdictglobals = {} exported.write_error( "No lyntinuser module loaded--executing with no context.") dictglobals = execdictglobals source = input[1:].lstrip() compiled = compile_command(source) # # XXX for one-liners only: # if not compiled: compiled = compile_command(source + "\n") old_stdout = sys.stdout old_stderr = sys.stderr old_stdin = sys.stdin sys_stdout = io.StringIO() sys_stderr = io.StringIO() sys_stdin = io.StringIO() try: sys.stdout = sys_stdout sys.stderr = sys_stderr sys.stdin = sys_stdin exec(compiled, dictglobals, execdictlocals) finally: sys.stdout = old_stdout sys.stderr = old_stderr sys.stdin = old_stdin error = sys_stderr.getvalue() if error: exported.write_error(error) text = sys_stdout.getvalue() if text.endswith("\n"): text = text[:-1] if text: exported.write_message(text) except (OverflowError, SyntaxError, ValueError, NameError): import traceback exported.write_error("".join( traceback.format_exception_only(*(sys.exc_info()[:2])))) except: exported.write_traceback("@: error in raw python stuff.") exported.tally_error()
def main(defaultoptions={}): """ This parses the command line arguments and makes sure they're all valid, instantiates a ui, does some setup, spins off an engine thread, and goes into the ui's mainloop. @param defaultoptions: the boot options to use. we update the config.options dict with these options--this is the easiest way to override the ui, moduledir, datadir, et al from a Lyntin run script. @type defaultoptions: dict """ try: import sys, os, traceback, ConfigParser from lyntin import config, event, utils, exported from lyntin.ui import base import locale locale.setlocale(locale.LC_ALL, '') config.options.update(defaultoptions) # read through options and arguments optlist = utils.parse_args(sys.argv[1:]) for mem in optlist: if mem[0] == '--help': print constants.HELPTEXT sys.exit(0) elif mem[0] == '--version': print constants.VERSION sys.exit(0) elif mem[0] in ["--configuration", "-c"]: # ini files OVERRIDE the default options # they can provide multiple ini files, but each new # ini file will OVERRIDE the contents of the previous ini file # where the two files intersect. parser = ConfigParser.ConfigParser() parser.read([mem[1]]) newoptions = {} for s in parser.sections(): for o in parser.options(s): c = parser.get(s, o).split(",") if newoptions.has_key(o): newoptions[o] += c else: newoptions[o] = c config.options.update(newoptions) else: opt = mem[0] while opt.startswith("-"): opt = opt[1:] if len(opt) > 0: if config.options.has_key(opt): if type(config.options[opt]) is list: config.options[opt].append(mem[1]) else: config.options[opt] = mem[1] else: config.options[opt] = [mem[1]] for mem in ["datadir", "ui", "commandchar"]: if config.options.has_key(mem) and type( config.options[mem]) is list: config.options[mem] = config.options[mem][0] # if they haven't set the datadir via the command line, then # we go see if they have a HOME in their environment variables.... if not config.options["datadir"]: if os.environ.has_key("HOME"): config.options["datadir"] = os.environ["HOME"] config.options["datadir"] = utils.fixdir(config.options["datadir"]) def on_shutdown(): """ This gets called by the Python interpreter atexit. The reason we do shutdown stuff here is we're more likely to catch things here than we are to let everything cycle through the ShutdownEvent. This should probably get fixed up at some point in the future. """ sys.stderr.write("goodbye.\n") #exported.hook_spam("shutdown_hook", {}) import atexit atexit.register(on_shutdown) # instantiate the engine Engine.instance = Engine() exported.myengine = Engine.instance Engine.instance._setupConfiguration() # instantiate the ui uiinstance = None try: uiname = str(config.options['ui']) modulename = uiname + "ui" uiinstance = base.get_ui(modulename) if not uiinstance: raise ValueError("No ui instance.") except Exception, e: print "Cannot start '%s': %s" % (uiname, e) traceback.print_exc() sys.exit(0) Engine.instance.setUI(uiinstance) # do some more silly initialization stuff # adds the .lyntinrc file to the readfile list if it exists. if config.options["datadir"]: lyntinrcfile = config.options["datadir"] + ".lyntinrc" if os.path.exists(lyntinrcfile): # we want the .lyntinrc file read in first, so then other # files can overwrite the contents therein config.options['readfile'].insert(0, lyntinrcfile) # import modules listed in modulesinit exported.write_message("Loading Lyntin modules.") try: import modules.__init__ modules.__init__.load_modules() except: exported.write_traceback("Modules did not load correctly.") sys.exit(1) # spam the startup hook exported.hook_spam("startup_hook", {}) commandchar = Engine.instance._managers["config"].get("commandchar") # handle command files for mem in config.options['readfile']: exported.write_message("Reading in file " + mem) # we have to escape windows os separators because \ has a specific # meaning in the argparser mem = mem.replace("\\", "\\\\") exported.lyntin_command("%sread %s" % (commandchar, mem), internal=1) # we're done initialization! exported.write_message(constants.STARTUPTEXT) Engine.instance.writePrompt() engine_thread = Engine.instance.startthread("engine", Engine.instance.runengine) timer_thread = Engine.instance.startthread("timer", Engine.instance.runtimer) try: Engine.instance._ui.runui() finally: sys.stderr.write("Shutting down...") event.ShutdownEvent().enqueue() engine_thread.join(10) timer_thread.join(10)
def handleUserData(self, input, internal=0, session=None): """ This handles input lines from the user in a session-less context. The engine.handleUserData deals with global stuff and then passes the modified input to the session for session-oriented handling. The session can call this method again with expanded input--this method is considered recursive. internal tells whether to spam the input hook and things of that nature. @param input: the data from the user @type input: string @param internal: whether this should be executed internally or not. 0 if we should spam the input hook and record the input to the historymanager; 1 if we shouldn't @type internal: boolean @param session: the session scoping to execute this user input in @type session: session.Session instance @return: the commands that were actually executed (may not be exactly what the user typed--this is for the history manager) @rtype: string """ if self._managers["config"].get("debugmode") == 1: exported.write_message("evaluating: %s" % input) inputlist = utils.split_commands( self._managers["config"].get("splitchar"), input) if session == None: session = self._current_session historyitems = [] commandchar = self._managers["config"].get("commandchar") for mem in inputlist: # mem = mem.strip() if len(mem) == 0: mem = commandchar + "cr" # if it's not internal we spam the hook with the raw input if internal == 0: exported.hook_spam("from_user_hook", {"data": mem}) if mem.startswith("!"): memhistory = self.getManager("history").getHistoryItem(mem) if memhistory != None: self.handleUserData(memhistory, 1, session) historyitems.append(memhistory) continue # if it starts with a # it's a loop, session or command if len(mem) > 0 and mem.startswith(commandchar): # pull off the first token without the commandchar ses = mem.split(" ", 1)[0][1:] # is it a loop (aka repeating command)? if ses.isdigit(): num = int(ses) if mem.find(" ") != -1: command = mem.split(" ", 1)[1] command = utils.strip_braces(command) if num > 0: for i in range(num): loopcommand = self.handleUserData( command, 1, session) historyitems.append(commandchar + ses + " {" + loopcommand + "}") continue # is it a session? if self._sessions.has_key(ses): input = mem.split(" ", 1) if len(input) < 2: self.set_current_session(self._sessions[ses]) else: self.handleUserData(input[1], internal=1, session=self._sessions[ses]) historyitems.append(mem) continue # is it "all" sessions? if ses == "all": newinput = mem.split(" ", 1) if len(newinput) > 1: newinput = newinput[1] else: newinput = commandchar + "cr" for sessionname in self._sessions.keys(): if sessionname != "common": self._sessions[sessionname].handleUserData( newinput, internal) historyitems.append(mem) continue # if we get here then it is not a valid !-expression. and it's going # to the default session historyitems.append(mem) # no command char, so we pass it on to the session.handleUserData # to do session oriented things session.handleUserData(mem, internal) # we don't record internal stuff or input that isn't supposed # to be echo'd executed = ";".join(historyitems) if internal == 0 and self.getConfigManager().get("mudecho") == 1: self.getManager("history").recordHistory(executed) return executed
def highlight_cmd(ses, args, input): """ With no arguments, prints all highlights. With one argument, prints all highlights which match the arg. With multiple arguments, creates a highlight. Highlights enable you to colorfully "tag" text that's of interest to you with the given style. Styles available are: styles foreground colors background colors bold black grey b black blink red light red b red reverse green light green b green underline yellow light yellow b yellow blue light blue b blue magenta light magenta b magenta cyan light cyan b cyan white light white b white Highlights handle * at the beginning and end of non-regular expression texts. Highlights will handle regular expression texts as well. See "#help regexp" for more details. Note: blink, underline, and reverse may not be available in all ui's. examples: #highlight {green} {Sven arrives.} #highlight {reverse,green} {Sven arrives.} #highlight {blue} {r[^.*?says:]} which is the same as: #highlight {blue} {*says:} category: commands """ style = args["style"] text = args["text"] quiet = args["quiet"] if not text: data = exported.get_manager("highlight").getInfo(ses, style, 1) if not data: data = ["highlight: no highlights defined."] exported.write_message("highlights:\n" + "\n".join(data), ses) return style = style.lower() stylelist = style.split(",") for mem in stylelist: if mem not in ansi.STYLEMAP: exported.write_error( "highlight: '%s' not a valid style.\nCheck out the highglight help file for more information." % mem) return exported.get_manager("highlight").addHighlight(ses, style, text) if not quiet: exported.write_message("highlight: {%s} {%s} added." % (style, text), ses)
def schedule_cmd(ses, args, input): """ With no arguments lets you view the scheduled events. lyntin: Scheduled events: lyntin: 1 [a] 200 {#showme Will is super duper!} First column is the event id. Second column is the session it's in. Third column is the tick offset or time it's going to kick off at. Fourth column is the command to execute. With arguments it creates a scheduled event to kick off (and possibly repeat) at TICK seconds from now at which point it will execute EVENT which could be any valid user input. examples: #schedule {5} {#showme blah} will kick off 5 ticks from now (a tick is approx one second) and will execute "#showme blah". #schedule {1m30s} {#showme blah} will kick off in 1 minute and 30 seconds. #schedule {10} {#showme blah} {true} will kick off every 10 seconds. category: commands """ global myscheduler tick = args["tick"] cmd = args["event"] quiet = args["quiet"] repeat = args["repeat"] if not tick: output = myscheduler.getEvents(ses) if not output: exported.write_message("schedule: there are no scheduled events.") return if not quiet: exported.write_message("scheduled events:\n" + "\n".join(output)) return setimespan = 0 setime = 0 try: setimespan = utils.parse_timespan(tick) except: try: setime = utils.parse_time(tick) except: exported.write_error( "schedule: %s is not a valid time or timespan." % tick) return if setimespan != 0: sevent = SchedEvent(setimespan, ses, cmd, repeat, quiet) tick = setimespan + myscheduler._current_tick myscheduler.addEvent(tick, sevent) else: repeat = 0 sevent = SchedTimeEvent(setime, ses, cmd, repeat, quiet) myscheduler.addEvent(setime, sevent, real=1) if not quiet: exported.write_message("schedule: event scheduled: %r" % sevent)
loggerdata.closeLogFile() exported.write_message("log: stopped logging to '%s'." % logname, ses) except Exception, e: exported.write_error("log: logfile cannot be closed (%s)." % (e), ses) return # handle starting logging try: if os.sep not in logfile: logfile = config.options["datadir"] + logfile if databuffer: f = open(logfile, "w") buffer = "".join(ses.getDataBuffer()) f.write(buffer) exported.write_message("log: dumped %d lines of databuffer to logfile" % buffer.count("\n"), ses) loggerdata.setLogFile(f, stripansi, userprefix) else: loggerdata.openLogFile(logfile, stripansi, userprefix) if stripansi: stripansimessage = " stripping ansi" else: stripansimessage = "" exported.write_message("log: starting logging to '%s'%s." % (logfile, stripansimessage), ses) except Exception, e: exported.write_error("log: logfile cannot be opened for appending. %s" % (e), ses) commands_dict["log"] = (log_cmd, 'logfile= databuffer:boolean=false stripansi:boolean=true userprefix=')
def action_cmd(ses, args, input): """ With no trigger, no action and no tag, prints all actions. With no trigger and no action, prints all actions with given tag. With a trigger and no action, prints actions that match the trigger statement. With a trigger and an action, creates an action. When data from the mud matches the trigger clause, the response will be executed. Trigger clauses can use anchors (^ and $) to anchor the text to the beginning and end of the line respectively. Triggers can also contain Lyntin pattern-variables which start with a % sign and have digits: %0, %1, %10... When Lyntin sees a pattern-variable in an action trigger, it tries to match any pattern against it, and saves any match it finds so you can use it in the response. See below for examples. Note: As a note, actions are matched via regular expressions. %1 gets translated to (.+?) and %_1 gets translated to (\S+?). The special variable "%a" means "the whole matched line". We handle regular expressions with a special r[ ... ] syntax. If you put an "i" or "I" after the ], then we'll ignorecase as well. The onetime argument can be set to true to have the action remove itself automatically after it is triggered. examples: #action {^You are hungry} {get bread bag;eat bread} #action {%0 gives you %5} {say thanks for the %5, %0!} #action {r[^%_1 tells\\s+you %2$]} {say %1 just told me %2} #action {r[sven dealt .+? to %1$]i} {say i just killed %1!} see also: unaction, enable, disable, atags category: commands """ trigger = args["trigger"] action = args["action"] color = args["color"] priority = args["priority"] onetime = args["onetime"] quiet = args["quiet"] tag = args["tag"] am = exported.get_manager("action") ad = am.getActionData(ses) # they typed '#action'--print out all the current actions if not action: data = ad.getInfo(trigger, tag) if not data: data = ["action: no actions defined."] message = "actions" if tag: message += " with tag={%s}" % tag data += ad.getDisabledInfo(tag) exported.write_message(message + "\n" + "\n".join(data), ses) return try: ad.addAction(trigger, action, color, priority, onetime, tag) if not quiet: exported.write_message( "action: {%s} {%s} color={%d} priority={%d} tag={%s} added." % (trigger, action, color, priority, str(tag)), ses) except: exported.write_traceback("action: exception thrown.", ses)
def reconnect(self, args): prev_ses = args['session'].getName() self.turn_off() exported.write_message("disconnected from SoW, {0}".format(prev_ses)) exported.lyntin_command("#session a{0} sowmud.ru 5555".format(prev_ses))
# http reading contributed by Sebastian John if filename.startswith("http://"): contents = utils.http_get(filename).split("\n") else: f = open(filename, "r") contents = f.readlines() f.close() except Exception, e: exported.write_error( "read: file %s cannot be opened.\n%s" % (filename, e), ses) return contents = [m for m in contents if len(m.strip()) > 0] if len(contents) == 0: exported.write_message("read: %s had no data." % filename, ses) return c = exported.get_config("commandchar") if not contents[0].startswith(c): exported.lyntin_command("%sconfig commandchar %s" % (c, contents[0][0]), internal=1, session=ses) command = "" continued = 0 # FIXME - should this be a config setting? esc = "\\" for mem in contents:
def __del__(self): exported.write_message( "ClerBot: DEBUG: deleting ClerMod object {0}".format(self)) if self._timer is not None: self._timer.cancel()