def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.saveskillfile = os.path.join(self.savedir, 'skills.txt') self.skills = PersistentDict(self.saveskillfile, 'c') self.skillsnamelookup = {} for i in self.skills: self.skillsnamelookup[self.skills[i]['name']] = i self.saverecovfile = os.path.join(self.savedir, 'recoveries.txt') self.recoveries = PersistentDict(self.saverecovfile, 'c') self.recoveriesnamelookup = {} for i in self.recoveries: self.recoveriesnamelookup[self.recoveries[i]['name']] = i self.current = '' self.isuptodatef = False self.cmdqueue = None self.api.get('dependency.add')('cmdq') self.api.get('api.add')('gets', self.api_getskill) self.api.get('api.add')('isspellup', self.api_isspellup) self.api.get('api.add')('getspellups', self.api_getspellups) self.api.get('api.add')('sendcmd', self.api_sendcmd) self.api.get('api.add')('isaffected', self.api_isaffected) self.api.get('api.add')('isblockedbyrecovery', self.api_isblockedbyrecovery) self.api.get('api.add')('ispracticed', self.api_ispracticed) self.api.get('api.add')('canuse', self.api_canuse) self.api.get('api.add')('isuptodate', self.api_isuptodate) self.api.get('api.add')('isbad', self.api_isbad)
def __init__(self, *args, **kwargs): """ init the class """ BasePlugin.__init__(self, *args, **kwargs) self.canreload = False self.cmds = {} self.nomultiplecmds = {} self.savehistfile = os.path.join(self.savedir, 'history.txt') self.cmdhistorydict = PersistentDict(self.savehistfile, 'c') if 'history' not in self.cmdhistorydict: self.cmdhistorydict['history'] = [] self.cmdhistory = self.cmdhistorydict['history'] self.api.get('api.add')('add', self.api_addcmd) self.api.get('api.add')('remove', self.api_removecmd) self.api.get('api.add')('change', self.api_changecmd) self.api.get('api.add')('default', self.api_setdefault) self.api.get('api.add')('removeplugin', self.api_removeplugin) self.api.get('api.add')('list', self.api_listcmds) self.api.get('api.add')('run', self.api_run) self.api.get('api.add')('cmdhelp', self.api_cmdhelp)
def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savelevelfile = os.path.join(self.savedir, 'level.txt') self.levelinfo = PersistentDict(self.savelevelfile, 'c')
def __init__(self): """ initialize the instance """ self.plugins = {} self.pluginl = {} self.pluginm = {} self.pluginp = {} self.options = {} self.plugininfo = {} index = __file__.rfind(os.sep) if index == -1: self.basepath = "." + os.sep else: self.basepath = __file__[:index] self.api = API() self.savefile = os.path.join(self.api.BASEPATH, 'data', 'plugins', 'loadedplugins.txt') self.loadedplugins = PersistentDict(self.savefile, 'c') self.sname = 'plugins' self.lname = 'Plugin Manager' self.api.add(self.sname, 'isinstalled', self.api_isinstalled) self.api.add(self.sname, 'getp', self.api_getp) self.api.add(self.sname, 'module', self.api_getmodule) self.api.add(self.sname, 'allplugininfo', self.api_allplugininfo) self.api.add(self.sname, 'savestate', self.savestate)
def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savequestfile = os.path.join(self.savedir, 'quest.txt') self.queststuff = PersistentDict(self.savequestfile, 'c')
def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.savesubfile = os.path.join(self.savedir, 'subs.txt') self._substitutes = PersistentDict(self.savesubfile, 'c')
def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.aliasfile = os.path.join(self.savedir, 'aliases.txt') self._aliases = PersistentDict(self.aliasfile, 'c') self.sessionhits = {}
def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.variablefile = os.path.join(self.savedir, 'variables.txt') self._variables = PersistentDict(self.variablefile, 'c') self.api.get('api.add')('getv', self.api_getv) self.api.get('api.add')('setv', self.api_setv) self.api.get('api.add')('replace', self.api_replace)
def __init__(self): """ initialize the instance """ # Examples: # name : 'Actions' - from plugin file variable NAME (long name) # sname : 'actions' - from plugin file variable SNAME (short name) # modpath : '/client/actions.py' - path relative to the plugins directory # basepath : '/home/src/games/bastproxy/bp/plugins' - the full path to the # plugins directory # fullimploc : 'plugins.client.actions' - import location #name, sname, modpath, basepath, fullimploc BasePlugin.__init__( self, 'Plugin Manager', #name, 'plugins', #sname, "/__init__.py", #modpath "$basepath$", # basepath "plugins.__init__", # fullimploc ) self.canreload = False #key: modpath #value: {'plugin', 'module'} self.loadedpluginsd = {} self.pluginlookupbysname = {} self.pluginlookupbyname = {} self.pluginlookupbyfullimploc = {} # key: modpath # value: {'sname', 'name', 'purpose', 'author', # 'version', 'modpath', 'fullimploc' self.allplugininfo = {} index = __file__.rfind(os.sep) if index == -1: self.basepath = "." + os.sep else: self.basepath = __file__[:index] self.savefile = os.path.join(self.api.BASEPATH, 'data', 'plugins', 'loadedplugins.txt') self.loadedplugins = PersistentDict(self.savefile, 'c') self.api('api.add')('isloaded', self._api_isloaded) self.api('api.add')('getp', self._api_getp) self.api('api.add')('module', self._api_getmodule) self.api('api.add')('allplugininfo', self._api_allplugininfo) self.api('api.add')('savestate', self.savestate)
def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savecpfile = os.path.join(self.savedir, 'cp.txt') self.cpinfo = PersistentDict(self.savecpfile, 'c') self.mobsleft = [] self.cpinfotimer = {} self.nextdeath = False self.cmdqueue = None self.api.get('dependency.add')('cmdq')
def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savegqfile = os.path.join(self.savedir, 'gq.txt') self.gqinfo = PersistentDict(self.savegqfile, 'c') self._gqsdeclared = {} self._gqsstarted = {} self.api.get('setting.add')('joined', -1, int, 'the gq number joined') self.api.get('setting.add')('maxkills', False, bool, 'no qp because of maxkills') self.mobsleft = [] self.linecount = 0
def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.canreload = True self.regexlookup = {} self.actiongroups = {} self.compiledregex = {} self.sessionhits = {} self.saveactionsfile = os.path.join(self.savedir, 'actions.txt') self.actions = PersistentDict(self.saveactionsfile, 'c')
def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.spellupfile = os.path.join(self.savedir, 'spellups.txt') self.spellups = PersistentDict(self.spellupfile, 'c') self.api('dependency.add')('aardwolf.skills') self.api('dependency.add')('aardwolf.move') self.initspellups() self.lastmana = -1 self.lastmoves = -1
def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.variablefile = os.path.join(self.savedir, 'variables.txt') self._variables = PersistentDict(self.variablefile, 'c') self.api('api.add')('getv', self.api_getv) self.api('api.add')('setv', self.api_setv) self.api('api.add')('replace', self.api_replace)
def __init__(self): """ initialize the instance """ # Examples: # name : 'Actions' - from plugin file variable NAME (long name) # sname : 'actions' - from plugin file variable SNAME (short name) # modpath : '/client/actions.py' - path relative to the plugins directory # basepath : '/home/src/games/bastproxy/bp/plugins' - the full path to the # plugins directory # fullimploc : 'plugins.client.actions' - import location #name, sname, modpath, basepath, fullimploc BasePlugin.__init__(self, 'Plugin Manager', #name, 'plugins', #sname, "/__init__.py", #modpath "$basepath$", # basepath "plugins.__init__", # fullimploc ) self.canreload = False #key: modpath #value: {'plugin', 'module'} self.loadedpluginsd = {} self.pluginlookupbysname = {} self.pluginlookupbyname = {} self.pluginlookupbyfullimploc = {} # key: modpath # value: {'sname', 'name', 'purpose', 'author', # 'version', 'modpath', 'fullimploc' self.allplugininfo = {} index = __file__.rfind(os.sep) if index == -1: self.basepath = "." + os.sep else: self.basepath = __file__[:index] self.savefile = os.path.join(self.api.BASEPATH, 'data', 'plugins', 'loadedplugins.txt') self.loadedplugins = PersistentDict(self.savefile, 'c') self.api('api.add')('isloaded', self._api_isloaded) self.api('api.add')('getp', self._api_getp) self.api('api.add')('module', self._api_getmodule) self.api('api.add')('allplugininfo', self._api_allplugininfo) self.api('api.add')('savestate', self.savestate)
def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savegqfile = os.path.join(self.savedir, 'gq.txt') self.gqinfo = PersistentDict(self.savegqfile, 'c') self._gqsdeclared = {} self._gqsstarted = {} self.api('setting.add')('joined', -1, int, 'the gq number joined') self.api('setting.add')('maxkills', False, bool, 'no qp because of maxkills') self.mobsleft = [] self.linecount = 0
def __init__(self, *args, **kwargs): """ init the class """ BasePlugin.__init__(self, *args, **kwargs) self.canreload = False #print('log api.api', self.api.api) #print('log basepath', self.api.BASEPATH) self.savedir = os.path.join(self.api.BASEPATH, 'data', 'plugins', self.sname) self.logdir = os.path.join(self.api.BASEPATH, 'data', 'logs') #print('logdir', self.logdir) try: os.makedirs(self.savedir) except OSError: pass self.dtypes = {} self.sendtoclient = PersistentDict( os.path.join(self.savedir, 'sendtoclient.txt'), 'c') self.sendtoconsole = PersistentDict( os.path.join(self.savedir, 'sendtoconsole.txt'), 'c') self.sendtofile = PersistentDict( os.path.join(self.savedir, 'sendtofile.txt'), 'c') self.currentlogs = {} self.colors = {} self.filenametemplate = '%a-%b-%d-%Y.log' #self.sendtofile['default'] = { #'logdir':os.path.join(self.logdir, 'default'), #'file':'%a-%b-%d-%Y.log', 'timestamp':True #} self.colors['error'] = '@x136' self.api('api.add')('msg', self.api_msg) self.api('api.add')('adddtype', self.api_adddtype) self.api('api.add')('console', self.api_toggletoconsole) self.api('api.add')('file', self.api_toggletofile) self.api('api.add')('client', self.api_toggletoclient) self.api('api.add')('writefile', self.api_writefile) # add some default datatypes self.api('log.adddtype')('default') self.api('log.adddtype')('frommud') self.api('log.adddtype')('startup') self.api('log.adddtype')('shutdown') self.api('log.adddtype')('error') # log some datatypes by default self.api('log.client')('error') self.api('log.console')('error') self.api('log.console')('default') self.api('log.console')('startup') self.api('log.console')('shutdown')
def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savecpfile = os.path.join(self.savedir, 'cp.txt') self.cpinfo = PersistentDict(self.savecpfile, 'c') self.mobsleft = [] self.cpinfotimer = {} self.nextdeath = False self.api('dependency.add')('cmdq') self.api('api.add')('oncp', self.api_oncp) self.api('api.add')('mobsleft', self.api_cpmobsleft)
class PluginMgr(BasePlugin): """ a class to manage plugins """ def __init__(self): """ initialize the instance """ # Examples: # name : 'Actions' - from plugin file variable NAME (long name) # sname : 'actions' - from plugin file variable SNAME (short name) # modpath : '/client/actions.py' - path relative to the plugins directory # basepath : '/home/src/games/bastproxy/bp/plugins' - the full path to the # plugins directory # fullimploc : 'plugins.client.actions' - import location #name, sname, modpath, basepath, fullimploc BasePlugin.__init__(self, 'Plugin Manager', #name, 'plugins', #sname, "/__init__.py", #modpath "$basepath$", # basepath "plugins.__init__", # fullimploc ) self.canreload = False #key: modpath #value: {'plugin', 'module'} self.loadedpluginsd = {} self.pluginlookupbysname = {} self.pluginlookupbyname = {} self.pluginlookupbyfullimploc = {} # key: modpath # value: {'sname', 'name', 'purpose', 'author', # 'version', 'modpath', 'fullimploc' self.allplugininfo = {} index = __file__.rfind(os.sep) if index == -1: self.basepath = "." + os.sep else: self.basepath = __file__[:index] self.savefile = os.path.join(self.api.BASEPATH, 'data', 'plugins', 'loadedplugins.txt') self.loadedplugins = PersistentDict(self.savefile, 'c') self.api('api.add')('isloaded', self._api_isloaded) self.api('api.add')('getp', self._api_getp) self.api('api.add')('module', self._api_getmodule) self.api('api.add')('allplugininfo', self._api_allplugininfo) self.api('api.add')('savestate', self.savestate) # return the dictionary of all plugins def _api_allplugininfo(self): """ return the plugininfo dictionary """ return self.allplugininfo def findloadedplugin(self, plugin): """ find a plugin """ return self.api('plugins.getp')(plugin) # get a plugin instance def _api_getmodule(self, pluginname): """ returns the module of a plugin @Ypluginname@w = the plugin to check for""" plugin = self.api('plugins.getp')(pluginname) if plugin: return self.loadedpluginsd[plugin.modpath]['module'] return None # get a plugin instance def _api_getp(self, pluginname): """ get a loaded plugin instance @Ypluginname@w = the plugin to get""" if isinstance(pluginname, basestring): if pluginname in self.loadedpluginsd: return self.loadedpluginsd[pluginname]['plugin'] if pluginname in self.pluginlookupbysname: return self.loadedpluginsd[self.pluginlookupbysname[pluginname]]['plugin'] if pluginname in self.pluginlookupbyname: return self.loadedpluginsd[self.pluginlookupbyname[pluginname]]['plugin'] if pluginname in self.pluginlookupbyfullimploc: return self.loadedpluginsd[self.pluginlookupbyfullimploc[pluginname]]['plugin'] elif isinstance(pluginname, BasePlugin): return pluginname return None # check if a plugin is loaded def _api_isloaded(self, pluginname): """ check if a plugin is loaded @Ypluginname@w = the plugin to check for""" plugin = self.api('plugins.getp')(pluginname) if plugin: return True return False # load plugin dependencies def _loaddependencies(self, pluginname, dependencies): """ load a list of modules """ for i in dependencies: plugin = self.api('plugins.getp')(i) if plugin: continue self.api('send.msg')('%s: loading dependency %s' % (pluginname, i), pluginname) name, path = imputils.findmodule(self.basepath, i) if name: modpath = name.replace(path, '') self._loadplugin(modpath, path, force=True) # get all not loaded plugins def _getnotloadedplugins(self): """ create a message of all not loaded plugins """ msg = [] badplugins = self._updateallplugininfo() pdiff = set(self.allplugininfo) - set(self.loadedpluginsd) for modpath in sorted(pdiff): msg.append("%-20s : %-25s %-10s %-5s %s@w" % \ (self.allplugininfo[modpath]['fullimploc'].replace('plugins.', ''), self.allplugininfo[modpath]['name'], self.allplugininfo[modpath]['author'], self.allplugininfo[modpath]['version'], self.allplugininfo[modpath]['purpose'])) if msg: msg.insert(0, '-' * 75) msg.insert(0, "%-20s : %-25s %-10s %-5s %s@w" % \ ('Location', 'Name', 'Author', 'Vers', 'Purpose')) msg.insert(0, 'The following plugins are not loaded') if badplugins: msg.append('') msg.append('The following files would not import') for bad in badplugins: msg.append(bad.replace('plugins.', '')) return msg # get plugins that are change on disk def _getchangedplugins(self): """ create a message of plugins that are changed on disk """ msg = [] plugins = sorted([i['plugin'] for i in self.loadedpluginsd.values()], key=operator.attrgetter('package')) packageheader = [] msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ ('Short Name', 'Name', 'Author', 'Vers', 'Purpose')) msg.append('-' * 75) found = False for tpl in plugins: if tpl.ischangedondisk(): found = True if tpl.package not in packageheader: if packageheader: msg.append('') packageheader.append(tpl.package) limp = 'plugins.%s' % tpl.package mod = __import__(limp) try: desc = getattr(mod, tpl.package).DESCRIPTION except AttributeError: desc = '' msg.append('@GPackage: %s%s@w' % \ (tpl.package, ' - ' + desc if desc else '')) msg.append('@G' + '-' * 75 + '@w') msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ (tpl.sname, tpl.name, tpl.author, tpl.version, tpl.purpose)) if found: return msg return ['No plugins are changed on disk.'] # get a message of plugins in a package def _getpackageplugins(self, package): """ create a message of plugins in a package """ msg = [] plist = [] for plugin in [i['plugin'] for i in self.loadedpluginsd.values()]: if plugin.package == package: plist.append(plugin) if plist: plugins = sorted(plist, key=operator.attrgetter('sname')) limp = 'plugins.%s' % package mod = __import__(limp) try: desc = getattr(mod, package).DESCRIPTION except AttributeError: desc = '' msg.append('@GPackage: %s%s@w' % \ (package, ' - ' + desc if desc else '')) msg.append('@G' + '-' * 75 + '@w') msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ ('Short Name', 'Name', 'Author', 'Vers', 'Purpose')) msg.append('-' * 75) for tpl in plugins: msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ (tpl.sname, tpl.name, tpl.author, tpl.version, tpl.purpose)) else: msg.append('That is not a valid package') return msg # create a message of all plugins def _getallplugins(self): """ create a message of all plugins """ msg = [] plugins = sorted([i['plugin'] for i in self.loadedpluginsd.values()], key=operator.attrgetter('package')) packageheader = [] msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ ('Short Name', 'Name', 'Author', 'Vers', 'Purpose')) msg.append('-' * 75) for tpl in plugins: if tpl.package not in packageheader: if packageheader: msg.append('') packageheader.append(tpl.package) limp = 'plugins.%s' % tpl.package mod = __import__(limp) try: desc = getattr(mod, tpl.package).DESCRIPTION except AttributeError: desc = '' msg.append('@GPackage: %s%s@w' % \ (tpl.package, ' - ' + desc if desc else '')) msg.append('@G' + '-' * 75 + '@w') msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ (tpl.sname, tpl.name, tpl.author, tpl.version, tpl.purpose)) return msg # command to list plugins def _cmd_list(self, args): """ @G%(name)s@w - @B%(cmdname)s@w List plugins @CUsage@w: list """ msg = [] if args['notloaded']: msg.extend(self._getnotloadedplugins()) elif args['changed']: msg.extend(self._getchangedplugins()) elif args['package']: msg.extend(self._getpackageplugins(args['package'])) else: msg.extend(self._getallplugins()) return True, msg # command to load plugins def _cmd_load(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Load a plugin @CUsage@w: load @Yplugin@w @Yplugin@w = the name of the plugin to load use the name without the .py """ tmsg = [] plugin = args['plugin'] if plugin: fname = plugin.replace('.', os.sep) _module_list = imputils.find_files(self.basepath, fname + ".py") if len(_module_list) > 1: tmsg.append('There is more than one module that matches: %s' % \ plugin) elif not _module_list: tmsg.append('There are no modules that match: %s' % plugin) else: modpath = _module_list[0].replace(self.basepath, '') sname, reason = self._loadplugin(modpath, self.basepath, True) plugin = self.api('plugins.getp')(sname) if sname: if reason == 'already': tmsg.append('Plugin %s is already loaded' % sname) else: tmsg.append('Load complete: %s - %s' % \ (sname, plugin.name)) else: tmsg.append('Could not load: %s' % plugin) return True, tmsg else: return False, ['@Rplease specify a plugin@w'] # command to unload a plugin def _cmd_unload(self, args): """ @G%(name)s@w - @B%(cmdname)s@w unload a plugin @CUsage@w: unload @Yplugin@w @Yplugin@w = the shortname of the plugin to load """ tmsg = [] plugina = args['plugin'] if not plugina: return False, ['@Rplease specify a plugin@w'] plugin = self.findloadedplugin(plugina) if plugin: if plugin.canreload: if self._unloadplugin(plugin.fullimploc): tmsg.append("Unloaded: %s" % plugin.fullimploc) else: tmsg.append("Could not unload:: %s" % plugin.fullimploc) else: tmsg.append("That plugin can not be unloaded") return True, tmsg elif plugin: tmsg.append('plugin %s does not exist' % plugin) return True, tmsg return False, ['@Rplease specify a plugin@w'] # command to reload a plugin def _cmd_reload(self, args): """ @G%(name)s@w - @B%(cmdname)s@w reload a plugin @CUsage@w: reload @Yplugin@w @Yplugin@w = the shortname of the plugin to reload """ tmsg = [] plugina = args['plugin'] if not plugina: return False, ['@Rplease specify a plugin@w'] plugin = self.findloadedplugin(plugina) if plugin: if plugin.canreload: tret, _ = self._reloadplugin(plugin.modpath, True) if tret and tret != True: plugin = self.findloadedplugin(plugina) tmsg.append("Reload complete: %s" % plugin.fullimploc) return True, tmsg else: tmsg.append("That plugin cannot be reloaded") return True, tmsg else: tmsg.append('plugin %s does not exist' % plugina) return True, tmsg return False, tmsg # load all plugins def _loadplugins(self, tfilter): """ load plugins in all directories under the plugin directory """ _module_list = imputils.find_files(self.basepath, tfilter) _module_list.sort() load = False for fullpath in _module_list: modpath = fullpath.replace(self.basepath, '') force = False if modpath in self.loadedplugins: force = True modname, dummy = self._loadplugin(modpath, self.basepath, force=force, runload=load) if modname == 'log': self.api('log.adddtype')(self.sname) self.api('log.console')(self.sname) self.api('log.adddtype')('upgrade') self.api('log.console')('upgrade') if not load: testsort = sorted([i['plugin'] for i in self.loadedpluginsd.values()], key=operator.attrgetter('priority')) for i in testsort: try: #check dependencies here self.loadplugin(i) except Exception: # pylint: disable=broad-except self.api('send.traceback')( "load: had problems running the load method for %s." \ % i.fullimploc) imputils.deletemodule(i.fullimploc) # update all plugin info def _updateallplugininfo(self): """ find plugins that are not in self.allplugininfo """ _plugin_list = imputils.find_files(self.basepath, '*.py') _plugin_list.sort() self.allplugininfo = {} badplugins = [] for fullpath in _plugin_list: modpath = fullpath.replace(self.basepath, '') imploc, modname = imputils.get_module_name(modpath) if not modname.startswith("_"): fullimploc = "plugins" + '.' + imploc if fullimploc in sys.modules: plugin = self.api('plugins.getp')(modpath) self.allplugininfo[modpath] = {} self.allplugininfo[modpath]['sname'] = plugin.sname self.allplugininfo[modpath]['name'] = plugin.name self.allplugininfo[modpath]['purpose'] = plugin.purpose self.allplugininfo[modpath]['author'] = plugin.author self.allplugininfo[modpath]['version'] = plugin.version self.allplugininfo[modpath]['modpath'] = modpath self.allplugininfo[modpath]['fullimploc'] = fullimploc else: try: _module = __import__(fullimploc) _module = sys.modules[fullimploc] self.allplugininfo[modpath] = {} self.allplugininfo[modpath]['sname'] = _module.SNAME self.allplugininfo[modpath]['name'] = _module.NAME self.allplugininfo[modpath]['purpose'] = _module.PURPOSE self.allplugininfo[modpath]['author'] = _module.AUTHOR self.allplugininfo[modpath]['version'] = _module.VERSION self.allplugininfo[modpath]['modpath'] = modpath self.allplugininfo[modpath]['fullimploc'] = fullimploc imputils.deletemodule(fullimploc) except Exception: # pylint: disable=broad-except badplugins.append(fullimploc) return badplugins # load a plugin def _loadplugin(self, modpath, basepath, force=False, runload=True): """ load a single plugin """ success, msg, module, fullimploc = imputils.importmodule(modpath, basepath, self, 'plugins') if success and msg == 'import': load = True if 'AUTOLOAD' in module.__dict__ and not force: if not module.AUTOLOAD: load = False elif 'AUTOLOAD' not in module.__dict__: load = False if modpath not in self.allplugininfo: self.allplugininfo[modpath] = {} self.allplugininfo[modpath]['sname'] = module.SNAME self.allplugininfo[modpath]['name'] = module.NAME self.allplugininfo[modpath]['purpose'] = module.PURPOSE self.allplugininfo[modpath]['author'] = module.AUTHOR self.allplugininfo[modpath]['version'] = module.VERSION self.allplugininfo[modpath]['modpath'] = modpath self.allplugininfo[modpath]['fullimploc'] = fullimploc if load: if "Plugin" in module.__dict__: self._addplugin(module, modpath, basepath, fullimploc, runload) else: self.api('send.msg')('Module %s has no Plugin class' % \ module.NAME) module.__dict__["proxy_import"] = 1 return module.SNAME, 'Loaded' else: imputils.deletemodule(fullimploc) self.api('send.msg')( 'Not loading %s (%s) because autoload is False' % \ (module.NAME, fullimploc), primary='plugins') return True, 'not autoloaded' return success, msg # unload a plugin def _unloadplugin(self, fullimploc): """ unload a module """ if fullimploc in sys.modules: _module = sys.modules[fullimploc] success = True try: if "proxy_import" in _module.__dict__: self.api('send.client')( 'unload: unloading %s' % fullimploc) if "unload" in _module.__dict__: try: _module.unload() except Exception: # pylint: disable=broad-except success = False self.api('send.traceback')( "unload: module %s didn't unload properly." % fullimploc) if not self._removeplugin(_module.SNAME): self.api('send.client')( 'could not remove plugin %s' % fullimploc) success = False except Exception: # pylint: disable=broad-except self.api('send.traceback')( "unload: had problems unloading %s." % fullimploc) success = False if success: imputils.deletemodule(fullimploc) self.api('send.client')("unload: unloaded %s." % fullimploc) return success # reload a plugin def _reloadplugin(self, modpath, force=False): """ reload a plugin """ if modpath in self.loadedpluginsd: plugin = self.api.get('plugins.getp')(modpath) fullimploc = plugin.fullimploc basepath = plugin.basepath modpath = plugin.modpath sname = plugin.sname try: reloaddependents = plugin.reloaddependents except Exception: # pylint: disable=broad-except reloaddependents = False plugin = None if not self._unloadplugin(fullimploc): return False, '' if modpath and basepath: retval = self._loadplugin(modpath, basepath, force) if retval and reloaddependents: self._reloadalldependents(sname) return retval else: return False, '' # reload all dependents def _reloadalldependents(self, reloadedplugin): """ reload all dependents """ testsort = sorted([i['plugin'] for i in self.loadedpluginsd.values()], key=operator.attrgetter('priority')) for plugin in testsort: if plugin.sname != reloadedplugin: if reloadedplugin in plugin.dependencies: self.api('send.msg')('reloading dependent %s of %s' % \ (plugin.sname, reloadedplugin), plugin.sname) plugin.savestate() self._reloadplugin(plugin.modpath, True) # load a plugin def loadplugin(self, plugin): """ check dependencies and run the load function """ self.api('send.msg')('loading dependencies for %s' % \ plugin.fullimploc, plugin.sname) self._loaddependencies(plugin.sname, plugin.dependencies) self.api('send.client')("load: loading %s with priority %s" % \ (plugin.fullimploc, plugin.priority)) self.api('send.msg')('loading %s (%s: %s)' % \ (plugin.fullimploc, plugin.sname, plugin.name), plugin.sname) plugin.load() self.api('send.client')("load: loaded %s" % plugin.fullimploc) self.api('send.msg')('loaded %s (%s: %s)' % \ (plugin.fullimploc, plugin.sname, plugin.name), plugin.sname) self.api('events.eraise')('%s_plugin_loaded' % plugin.sname, {}) self.api('events.eraise')('plugin_loaded', {'plugin':plugin.sname}) # add a plugin def _addplugin(self, module, modpath, basepath, fullimploc, load=True): # pylint: disable=too-many-arguments """ add a plugin to be managed """ pluginn = self.api('plugins.getp')(module.NAME) plugins = self.api('plugins.getp')(module.SNAME) if plugins or pluginn: self.api('send.msg')('Plugin %s already exists' % module.NAME, secondary=module.SNAME) return False plugin = module.Plugin(module.NAME, module.SNAME, modpath, basepath, fullimploc) plugin.author = module.AUTHOR plugin.purpose = module.PURPOSE plugin.version = module.VERSION try: plugin.priority = module.PRIORITY except AttributeError: pass if load: try: #check dependencies here self.loadplugin(plugin) except Exception: # pylint: disable=broad-except self.api('send.traceback')( "load: had problems running the load method for %s." \ % fullimploc) imputils.deletemodule(fullimploc) return False self.loadedpluginsd[modpath] = {} self.loadedpluginsd[modpath]['plugin'] = plugin self.loadedpluginsd[modpath]['module'] = module self.pluginlookupbysname[plugin.sname] = modpath self.pluginlookupbyname[plugin.name] = modpath self.pluginlookupbyfullimploc[fullimploc] = modpath self.loadedplugins[modpath] = True self.loadedplugins.sync() return True # remove a plugin def _removeplugin(self, pluginname): """ remove a plugin """ plugin = self.api('plugins.getp')(pluginname) if plugin: try: plugin.unload() self.api('events.eraise')('%s_plugin_unload' % plugin.sname, {}) self.api('events.eraise')('plugin_unloaded', {'name':plugin.sname}) self.api('send.msg')('Plugin %s unloaded' % plugin.sname, secondary=plugin.sname) except Exception: # pylint: disable=broad-except self.api('send.traceback')( "unload: had problems running the unload method for %s." \ % plugin.sname) return False del self.loadedpluginsd[plugin.modpath] del self.pluginlookupbyfullimploc[plugin.fullimploc] del self.pluginlookupbyname[plugin.name] del self.pluginlookupbysname[plugin.sname] del self.loadedplugins[plugin.modpath] self.loadedplugins.sync() plugin = None return True return False # get stats for this plugin def getstats(self): """ return stats for events """ stats = {} stats['Base Sizes'] = {} stats['Base Sizes']['showorder'] = ['Class', 'Api', 'loadedpluginsd', 'plugininfo'] stats['Base Sizes']['loadedpluginsd'] = '%s bytes' % \ sys.getsizeof(self.loadedpluginsd) stats['Base Sizes']['plugininfo'] = '%s bytes' % \ sys.getsizeof(self.allplugininfo) stats['Base Sizes']['Class'] = '%s bytes' % sys.getsizeof(self) stats['Base Sizes']['Api'] = '%s bytes' % sys.getsizeof(self.api) stats['Plugins'] = {} stats['Plugins']['showorder'] = ['Total', 'Loaded', 'Bad'] stats['Plugins']['Total'] = len(self.allplugininfo) stats['Plugins']['Loaded'] = len(self.loadedpluginsd) badplugins = self._updateallplugininfo() stats['Plugins']['Bad'] = len(badplugins) return stats def shutdown(self, args=None): # pylint: disable=unused-argument """ do tasks on shutdown """ self.savestate() # save all plugins def savestate(self, args=None): # pylint: disable=unused-argument """ save all plugins """ for i in self.loadedpluginsd.values(): i['plugin'].savestate() # load this plugin def load(self): """ load various things """ self._loadplugins("*.py") BasePlugin._loadcommands(self) parser = argp.ArgumentParser(add_help=False, description="list plugins") parser.add_argument('-n', "--notloaded", help="list plugins that are not loaded", action="store_true") parser.add_argument('-c', "--changed", help="list plugins that are load but are changed on disk", action="store_true") parser.add_argument('package', help='the to list', default='', nargs='?') self.api('commands.add')('list', self._cmd_list, lname='Plugin Manager', parser=parser) parser = argp.ArgumentParser(add_help=False, description="load a plugin") parser.add_argument('plugin', help='the plugin to load, don\'t include the .py', default='', nargs='?') self.api('commands.add')('load', self._cmd_load, lname='Plugin Manager', parser=parser) parser = argp.ArgumentParser(add_help=False, description="unload a plugin") parser.add_argument('plugin', help='the plugin to unload', default='', nargs='?') self.api('commands.add')('unload', self._cmd_unload, lname='Plugin Manager', parser=parser) parser = argp.ArgumentParser(add_help=False, description="reload a plugin") parser.add_argument('plugin', help='the plugin to reload', default='', nargs='?') self.api('commands.add')('reload', self._cmd_reload, lname='Plugin Manager', parser=parser) self.api('commands.default')('list', self.sname) self.api('timers.add')('save', self.savestate, 60, nodupe=True, log=False) self.api('events.register')('proxy_shutdown', self.shutdown)
class Plugin(AardwolfBasePlugin): """ a plugin to handle aardwolf cp events """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savecpfile = os.path.join(self.savedir, 'cp.txt') self.cpinfo = PersistentDict(self.savecpfile, 'c') self.mobsleft = [] self.cpinfotimer = {} self.nextdeath = False self.cmdqueue = None self.api.get('dependency.add')('cmdq') def load(self): """ load the plugins """ AardwolfBasePlugin.load(self) self.cmdqueue = self.api.get('cmdq.baseclass')()(self) self.cmdqueue.addcmdtype('cpcheck', 'campaign check', "^campaign check$", beforef=self.cpcheckbefore, afterf=self.cpcheckafter) parser = argparse.ArgumentParser(add_help=False, description='show cp info') self.api.get('commands.add')('show', self.cmd_show, parser=parser) parser = argparse.ArgumentParser(add_help=False, description='refresh cp info') self.api.get('commands.add')('refresh', self.cmd_refresh, parser=parser) self.api.get('watch.add')( 'cp_check', '^(cp|campa|campai|campaig|campaign) (c|ch|che|chec|check)$') self.api.get('triggers.add')('cpnew', "^Commander Barcett tells you " \ "'Type 'campaign info' to see what you must kill.'$") self.api.get('triggers.add')('cpnone', "^You are not currently on a campaign.$", enabled=False, group='cpcheck', omit=True) self.api.get('triggers.add')( 'cptime', "^You have (?P<time>.*) to finish this campaign.$", enabled=False, group='cpcheck', omit=True) self.api.get('triggers.add')('cpmob', "^You still have to kill \* (?P<mob>.*) " \ "\((?P<location>.*?)(?P<dead> - Dead|)\)$", enabled=False, group='cpcheck', omit=True) self.api.get('triggers.add')('cpscramble', "Note: One or more target names in this " \ "campaign might be slightly scrambled.$", enabled=False, group='cpcheck', omit=True) self.api.get('triggers.add')('cpneedtolevel', "^You will have to level before you" \ " can go on another campaign.$", enabled=False, group='cpin') #Note: One or more target names in this campaign might be slightly scrambled. self.api.get('triggers.add')( 'cpcantake', "^You may take a campaign at this level.$", enabled=False, group='cpin') self.api.get('triggers.add')( 'cpshnext', "^You cannot take another campaign for (?P<time>.*).$", enabled=False, group='cpin') self.api.get('triggers.add')( 'cpmobdead', "^Congratulations, that was one of your CAMPAIGN mobs!$", enabled=False, group='cpin') self.api.get('triggers.add')( 'cpcomplete', "^CONGRATULATIONS! You have completed your campaign.$", enabled=False, group='cpin') self.api.get('triggers.add')('cpclear', "^Campaign cleared.$", enabled=False, group='cpin') self.api.get('triggers.add')( 'cpreward', "^\s*Reward of (?P<amount>\d+) (?P<type>.+) .+ added.$", enabled=False, group='cprew', argtypes={ 'amount': int }) self.api.get('triggers.add')('cpcompdone', "^--------------------------" \ "------------------------------------$", enabled=False, group='cpdone') self.api.get('events.register')('trigger_cpnew', self._cpnew) self.api.get('events.register')('trigger_cpnone', self._cpnone) self.api.get('events.register')('trigger_cptime', self._cptime) #self.api.get('events.register')('watch_cp_check', self._cpcheckcmd) self.api.get('events.register')('trigger_cpmob', self._cpmob) self.api.get('events.register')('trigger_cpneedtolevel', self._cpneedtolevel) self.api.get('events.register')('trigger_cpcantake', self._cpcantake) self.api.get('events.register')('trigger_cpshnext', self._cpshnext) self.api.get('events.register')('trigger_cpmobdead', self._cpmobdead) self.api.get('events.register')('trigger_cpcomplete', self._cpcomplete) self.api.get('events.register')('trigger_cpclear', self._cpclear) self.api.get('events.register')('trigger_cpreward', self._cpreward) self.api.get('events.register')('trigger_cpcompdone', self._cpcompdone) def cmd_show(self, args): """ show the cp mobs """ msg = [] if self.cpinfo['oncp']: msg.append('Mobs left:') msg.append('%-40s %s' % ('Mob Name', 'Area/Room')) msg.append('@G' + '-' * 60) for i in self.mobsleft: color = '@w' if i['mobdead']: color = '@R' msg.append('%s%-40s %s' % (color, i['name'], i['location'])) else: msg.append('You are not on a cp') return True, msg def cmd_refresh(self, args): """ cmd to refresh cp info """ msg = [] if self.cpinfo['oncp']: msg.append('Refreshing cp mobs') self.cmdqueue.addtoqueue('cpcheck', '') else: msg.append('You are not on a cp') return True, msg def cpcheckbefore(self): """ function to run before send the command """ self.mobsleft = [] self.cpinfotimer = {} self.api.get('triggers.togglegroup')('cpcheck', True) def cpcheckafter(self): """ function to run after the command is finished """ self.api.get('triggers.togglegroup')("cpin", True) self.api.get('triggers.togglegroup')('cpcheck', False) def afterfirstactive(self, _=None): """ do something on connect """ AardwolfBasePlugin.afterfirstactive(self) self.cmdqueue.addtoqueue('cpcheck', '') def _cpreset(self): """ reset the cp """ self.cpinfo.clear() self.cpinfo['mobs'] = {} self.cpinfo['trains'] = 0 self.cpinfo['pracs'] = 0 self.cpinfo['gold'] = 0 self.cpinfo['tp'] = 0 self.cpinfo['qp'] = 0 self.cpinfo['bonusqp'] = 0 self.cpinfo['failed'] = 0 self.cpinfo['level'] = self.api.get('aardu.getactuallevel')( self.api.get('GMCP.getv')('char.status.level')) self.cpinfo['starttime'] = time.time() self.cpinfo['finishtime'] = 0 self.cpinfo['oncp'] = True self.cpinfo['cantake'] = False self.cpinfo['shtime'] = None self.savestate() def _cpnew(self, args=None): """ handle a new cp """ self.api.get('send.msg')('cpnew: %s' % args) self._cpreset() self.cmdqueue.addtoqueue('cpcheck', '') def _cpnone(self, _=None): """ handle a none cp """ self.api.get('send.msg')('cpnone') self.cpinfo['oncp'] = False self.savestate() self.api.get('triggers.togglegroup')('cpcheck', False) self.api.get('triggers.togglegroup')('cpin', False) self.api.get('triggers.togglegroup')('cprew', False) self.api.get('triggers.togglegroup')('cpdone', False) #check(EnableTimer("cp_timer", false)) self.cpinfotimer = {} self.cmdqueue.cmddone('cpcheck') def _cptime(self, _=None): """ handle cp time """ self.api.get('send.msg')('handling cp time') self.api.get('send.msg')('%s' % self.cpinfo) if not self.cpinfo['mobs']: self.api.get('send.msg')('copying mobsleft') self.cpinfo['mobs'] = self.mobsleft[:] self.api.get('events.eraise')('aard_cp_mobsorig', copy.deepcopy( {'mobsleft': self.mobsleft})) self.savestate() self.api.get('send.msg')('raising aard_cp_mobsleft %s' % self.mobsleft) self.api.get('events.eraise')('aard_cp_mobsleft', copy.deepcopy( {'mobsleft': self.mobsleft})) self.cmdqueue.cmddone('cpcheck') def _cpneedtolevel(self, _=None): """ handle cpneedtolevel """ self.cpinfo['cantake'] = False self.savestate() def _cpcantake(self, _=None): """ handle cpcantake """ self.cpinfo['cantake'] = True self.savestate() def _cpshnext(self, args=None): """ handle cpshnext """ self.cpinfo['shtime'] = args['time'] self.savestate() def _cpmob(self, args=None): """ handle cpmob """ name = args['mob'] mobdead = self.api.get('utils.verify')(args['dead'], bool) location = args['location'] if not name or not location: self.api.get('send.msg')("error parsing line: %s" % args['line']) else: self.mobsleft.append({ 'name': name, 'nocolorname': self.api.get('colors.stripansi')(name), 'location': location, 'mobdead': mobdead }) def _cpmobdead(self, _=None): """ handle cpmobdead """ self.api.get('events.register')('aard_mobkill', self._mobkillevent) #self.api.get('send.execute')("cp check") def _cpcomplete(self, _=None): """ handle cpcomplete """ self.api.get('triggers.togglegroup')('cprew', True) self.cpinfo['finishtime'] = time.time() self.cpinfo['oncp'] = False self.savestate() def _cpreward(self, args=None): """ handle cpreward """ rtype = args['type'] ramount = int(args['amount']) rewardt = self.api.get('aardu.rewardtable')() self.cpinfo[rewardt[rtype]] = ramount self.savestate() self.api.get('triggers.togglegroup')('cpdone', True) def _cpcompdone(self, _=None): """ handle cpcompdone """ self.api.get('events.register')('trigger_all', self._triggerall) def _triggerall(self, args=None): """ check to see if we have the bonus qp message """ if 'first campaign completed today' in args['line']: mat = re.match('^You receive (?P<bonus>\d*) quest points bonus ' \ 'for your first campaign completed today.$', args['line']) self.cpinfo['bonusqp'] = int(mat.groupdict()['bonus']) self.api.get('events.unregister')('trigger_all', self._triggerall) self.api.get('events.eraise')('aard_cp_comp', copy.deepcopy(self.cpinfo)) elif re.match("^You have completed (\d*) campaigns today.$", args['line']): self.api.get('events.unregister')('trigger_all', self._triggerall) self.api.get('events.eraise')('aard_cp_comp', copy.deepcopy(self.cpinfo)) def _cpclear(self, _=None): """ handle cpclear """ self.cpinfo['failed'] = 1 self.api.get('events.eraise')('aard_cp_failed', copy.deepcopy(self.cpinfo)) self._cpnone() def _cpcheckcmd(self, args=None): """ handle when we get a cp check """ self.mobsleft = [] self.cpinfotimer = {} self.api.get('triggers.togglegroup')('cpcheck', True) return args def _mobkillevent(self, args): """ this will be registered to the mobkill hook """ self.api.get('send.msg')('checking kill %s' % args['name']) self.api.get('events.unregister')('aard_mobkill', self._mobkillevent) found = False removeitem = None for i in range(len(self.mobsleft)): tmob = self.mobsleft[i] if tmob['name'] == args['name']: self.api.get('send.msg')('found %s' % tmob['name']) found = True removeitem = i if removeitem: del (self.mobsleft[removeitem]) if found: self.api.get('events.eraise')('aard_cp_mobsleft', copy.deepcopy( {'mobsleft': self.mobsleft})) else: self.api.get('send.msg')("BP CP: could not find mob: %s" % args['name']) self.cmdqueue.addtoqueue('cpcheck', '') def savestate(self): """ save states """ AardwolfBasePlugin.savestate(self) self.cpinfo.sync()
class Plugin(AardwolfBasePlugin): """ a plugin manage info about spells and skills """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.saveskillfile = os.path.join(self.savedir, 'skills.txt') self.skills = PersistentDict(self.saveskillfile, 'c') self.skillsnamelookup = {} for i in self.skills: self.skillsnamelookup[self.skills[i]['name']] = i self.saverecovfile = os.path.join(self.savedir, 'recoveries.txt') self.recoveries = PersistentDict(self.saverecovfile, 'c') self.recoveriesnamelookup = {} for i in self.recoveries: self.recoveriesnamelookup[self.recoveries[i]['name']] = i self.current = '' self.isuptodatef = False self.cmdqueue = None self.api.get('dependency.add')('cmdq') self.api.get('api.add')('gets', self.api_getskill) self.api.get('api.add')('isspellup', self.api_isspellup) self.api.get('api.add')('getspellups', self.api_getspellups) self.api.get('api.add')('sendcmd', self.api_sendcmd) self.api.get('api.add')('isaffected', self.api_isaffected) self.api.get('api.add')('isblockedbyrecovery', self.api_isblockedbyrecovery) self.api.get('api.add')('ispracticed', self.api_ispracticed) self.api.get('api.add')('canuse', self.api_canuse) self.api.get('api.add')('isuptodate', self.api_isuptodate) self.api.get('api.add')('isbad', self.api_isbad) def load(self): """ load the plugins """ AardwolfBasePlugin.load(self) self.api.get('send.msg')('running load function of skills') parser = argparse.ArgumentParser( add_help=False, description='refresh skills and spells') self.api.get('commands.add')('refresh', self.cmd_refresh, parser=parser) parser = argparse.ArgumentParser( add_help=False, description='lookup skill or spell by name or sn') parser.add_argument('skill', help='the skill to lookup', default='', nargs='?') self.api.get('commands.add')('lu', self.cmd_lu, parser=parser) self.api.get('triggers.add')('spellh_noprompt', "^\{spellheaders noprompt\}$", group='slist', enabled=False, omit=True) self.api.get('triggers.add')('spellh_spellup_noprompt', "^\{spellheaders spellup noprompt\}$", group='slist', enabled=False, omit=True) self.api.get('triggers.add')('spellh_affected_noprompt', "^\{spellheaders affected noprompt\}$", group='slist', enabled=False, omit=True) self.api.get('triggers.add')('spellh_spellline', "^(?P<sn>\d+),(?P<name>.+),(?P<target>\d+)," \ "(?P<duration>\d+),(?P<pct>\d+),(?P<rcvy>-?\d+),(?P<type>\d+)$", group='spellhead', enabled=False, omit=True) self.api.get('triggers.add')('spellh_end_noprompt', "^\{/spellheaders\}$", group='spellhead', enabled=False, omit=True) self.api.get('triggers.add')('affoff', "^\{affoff\}(?P<sn>\d+)$") self.api.get('triggers.add')( 'affon', "^\{affon\}(?P<sn>\d+),(?P<duration>\d+)$") self.api.get('triggers.add')('recov_noprompt', "^\{recoveries noprompt\}$", group='slist', enabled=False, omit=True) self.api.get('triggers.add')('recov_affected_noprompt', "^\{recoveries affected noprompt\}$", group='slist', enabled=False, omit=True) self.api.get('triggers.add')( 'spellh_recovline', "^(?P<sn>\d+),(?P<name>.+),(?P<duration>\d+)$", group='recoveries', enabled=False, omit=True) self.api.get('triggers.add')('recov_end_noprompt', "^\{/recoveries\}$", group='recoveries', enabled=False, omit=True) self.api.get('triggers.add')('recoff', "^\{recoff\}(?P<sn>\d+)$") self.api.get('triggers.add')( 'recon', "^\{recon\}(?P<sn>\d+),(?P<duration>\d+)$") self.api.get('triggers.add')( 'skillgain', "^\{skillgain\}(?P<sn>\d+),(?P<percent>\d+)$") self.api.get('triggers.add')('skillfail', "^\{sfail\}(?P<sn>\d+),(?P<target>\d+)," \ "(?P<reason>\d+),(?P<recovery>-?\d+)$") self.api.get('events.register')('trigger_spellh_noprompt', self.skillstart) self.api.get('events.register')('trigger_spellh_spellup_noprompt', self.skillstart) self.api.get('events.register')('trigger_spellh_affected_noprompt', self.skillstart) self.api.get('events.register')('trigger_spellh_spellline', self.skillline) self.api.get('events.register')('trigger_spellh_end_noprompt', self.skillend) self.api.get('events.register')('trigger_affoff', self.affoff) self.api.get('events.register')('trigger_affon', self.affon) self.api.get('events.register')('trigger_recov_noprompt', self.recovstart) self.api.get('events.register')('trigger_recov_affected_noprompt', self.recovstart) self.api.get('events.register')('trigger_spellh_recovline', self.recovline) self.api.get('events.register')('trigger_recov_end_noprompt', self.recovend) self.api.get('events.register')('trigger_recoff', self.recoff) self.api.get('events.register')('trigger_recon', self.recon) self.api.get('events.register')('trigger_skillgain', self.skillgain) self.api.get('events.register')('trigger_skillfail', self.skillfail) self.api.get('events.register')('GMCP:char.status', self.checkskills) self.api.get('events.register')('aard_level_tier', self.cmd_refresh) self.api.get('events.register')('aard_level_remort', self.cmd_refresh) self.cmdqueue = self.api.get('cmdq.baseclass')()(self) self.cmdqueue.addcmdtype('slist', 'slist', "^slist\s*(.*)$", beforef=self.slistbefore, afterf=self.slistafter) self.checkskills() def slistbefore(self): """ stuff to do before doing slist command """ self.api.get('triggers.togglegroup')('slist', True) def slistafter(self): """ stuff to do after doing slist command """ self.savestate() self.api.get('triggers.togglegroup')('slist', False) def afterfirstactive(self, _=None): """ do something on connect """ AardwolfBasePlugin.afterfirstactive(self) self.checkskills() # check if the spells/skills list is up to date def api_isuptodate(self): """ return True if we have seen affected or all spells refresh """ return self.isuptodatef def cmd_lu(self, args): """ cmd to lookup a spell """ msg = [] skill = self.api.get('skills.gets')(args['skill']) if skill: msg.append('%-8s : %s' % ('SN', skill['sn'])) msg.append('%-8s : %s' % ('Name', skill['name'])) msg.append('%-8s : %s' % ('Percent', skill['percent'])) if skill['duration'] > 0: msg.append( '%-8s : %s' % ('Duration', self.api.get('utils.timedeltatostring')( time.time(), skill['duration']))) msg.append('%-8s : %s' % ('Target', skill['target'])) msg.append('%-8s : %s' % ('Spellup', skill['spellup'])) msg.append('%-8s : %s' % ('Type', skill['type'])) if skill['recovery']: recov = skill['recovery'] if recov['duration'] > 0: duration = self.api.get('utils.timedeltatostring')( time.time(), recov['duration']) msg.append('%-8s : %s (%s)' % ('Recovery', recov['name'], duration)) else: msg.append('%-8s : %s' % ('Recovery', recov['name'])) else: msg.append('Could not find: %s' % args['skill']) return True, msg def cmd_refresh(self, args): """ refresh spells and skills """ self.skills.clear() self.recoveries.clear() self.cmdqueue.addtoqueue('slist', 'noprompt') self.cmdqueue.addtoqueue('slist', 'spellup noprompt') msg = ['Refreshing spells and skills'] return True, msg def checkskills(self, _=None): """ check to see if we have spells """ state = self.api.get('GMCP.getv')('char.status.state') if state == 3: self.api.get('send.msg')('refreshing skills') self.api.get('events.unregister')('GMCP:char.status', self.checkskills) self.api.get('A102.toggle')('SPELLUPTAGS', True) self.api.get('A102.toggle')('SKILLGAINTAGS', True) self.api.get('A102.toggle')('QUIETTAGS', False) if len(self.skills) == 0: self.cmd_refresh({}) else: self.resetskills() self.cmdqueue.addtoqueue('slist', 'affected noprompt') def resetskills(self): """ reset the skills """ for i in self.skills: self.skills[i]['duration'] = 0 for i in self.recoveries: self.recoveries[i]['duration'] = 0 def skillgain(self, args): """ handle a skillgain tag """ spellnum = int(args['sn']) pct = int(args['percent']) if spellnum in self.skills: self.skills[spellnum]['percent'] = pct self.api.get('events.eraise')('aard_skill_gain', { 'sn': spellnum, 'percent': pct }) def skillfail(self, args): """ raise an event when we fail a skill/spell """ spellnum = int(args['sn']) reason = FAILREASON[int(args['reason'])] ndict = { 'sn': spellnum, 'reason': reason, 'target': FAILTARG[int(args['target'])], 'recovery': int(args['recovery']) } if reason == 'dontknow' and self.skills[spellnum]['percent'] > 0: self.api.get('send.msg')( 'refreshing spells because of an unlearned spell') self.cmd_refresh({}) self.api.get('send.msg')('raising skillfail: %s' % ndict) self.api.get('events.eraise')('skill_fail_%s' % args['sn'], ndict) self.api.get('events.eraise')('skill_fail', ndict) def affoff(self, args): """ set the affect to off for spell that wears off """ spellnum = int(args['sn']) if spellnum in self.skills: self.skills[spellnum]['duration'] = 0 self.savestate() self.api.get('events.eraise')('aard_skill_affoff_%s' % spellnum, { 'sn': spellnum }) self.api.get('events.eraise')('aard_skill_affoff', { 'sn': spellnum }) def affon(self, args): """ set the spell's duration when we see an affon """ spellnum = int(args['sn']) duration = int(args['duration']) if spellnum in self.skills: self.skills[spellnum]['duration'] = time.mktime(time.localtime()) + \ duration self.savestate() self.api.get('events.eraise')( 'aard_skill_affon_%s' % spellnum, { 'sn': spellnum, 'duration': self.skills[spellnum]['duration'] }) self.api.get('events.eraise')( 'aard_skill_affon', { 'sn': spellnum, 'duration': self.skills[spellnum]['duration'] }) def recovstart(self, args): """ show that the trigger fired """ if 'triggername' in args \ and args['triggername'] == 'trigger_recov_affected_noprompt': self.current = 'affected' else: self.current = '' self.api.get('triggers.togglegroup')('recoveries', True) def recovline(self, args): """ parse a recovery line """ spellnum = int(args['sn']) name = args['name'] if int(args['duration']) != 0: duration = time.mktime(time.localtime()) + int(args['duration']) else: duration = 0 if not (spellnum in self.recoveries): self.recoveries[spellnum] = {} self.recoveries[spellnum]['name'] = name self.recoveries[spellnum]['duration'] = duration self.recoveries[spellnum]['sn'] = spellnum self.recoveriesnamelookup[name] = spellnum def recovend(self, args): """ reset current when seeing a spellheaders ending """ self.api.get('triggers.togglegroup')('recoveries', False) if self.current == '' or self.current == 'affected': self.isuptodatef = True self.api.get('send.msg')('sending skills_affected_update') self.api.get('events.eraise')('skills_affected_update', {}) self.cmdqueue.cmddone('slist') def recoff(self, args): """ set the affect to off for spell that wears off """ spellnum = int(args['sn']) if spellnum in self.recoveries: self.recoveries[spellnum]['duration'] = 0 self.savestate() self.api.get('events.eraise')('aard_skill_recoff', { 'sn': spellnum }) def recon(self, args): """ set the spell's duration when we see an affon """ spellnum = int(args['sn']) duration = int(args['duration']) if spellnum in self.recoveries: self.recoveries[spellnum]['duration'] = \ time.mktime(time.localtime()) + duration self.savestate() self.api.get('events.eraise')( 'aard_skill_recon', { 'sn': spellnum, 'duration': self.recoveries[spellnum]['duration'] }) def skillstart(self, args): """ show that the trigger fired """ if 'triggername' in args \ and args['triggername'] == 'spellh_spellup_noprompt': self.current = 'spellup' elif 'triggername' in args \ and args['triggername'] == 'spellh_affected_noprompt': self.current = 'affected' else: self.current = '' self.api.get('triggers.togglegroup')('spellhead', True) def skillline(self, args): """ parse spell lines """ spellnum = int(args['sn']) name = args['name'] target = int(args['target']) if int(args['duration']) != 0: duration = time.mktime(time.localtime()) + int(args['duration']) else: duration = 0 percent = int(args['pct']) recovery = int(args['rcvy']) stype = int(args['type']) if not (spellnum in self.skills): self.skills[spellnum] = {} self.skills[spellnum]['name'] = name self.skills[spellnum]['target'] = TARGET[target] self.skills[spellnum]['duration'] = duration self.skills[spellnum]['percent'] = percent self.skills[spellnum]['recovery'] = recovery self.skills[spellnum]['type'] = STYPE[stype] self.skills[spellnum]['sn'] = spellnum if not ('spellup' in self.skills[spellnum]): self.skills[spellnum]['spellup'] = False if self.current == 'spellup': self.skills[spellnum]['spellup'] = True self.skillsnamelookup[name] = spellnum def skillend(self, args): """ reset current when seeing a spellheaders ending """ self.api.get('triggers.togglegroup')('spellhead', False) self.savestate() if self.current: evname = 'aard_skill_ref_%s' % self.current else: evname = 'aard_skill_ref' self.api.get('events.eraise')(evname, {}) self.current = '' # get a spell/skill by number def api_getskill(self, tsn): """ get a skill """ #self.api.get('send.msg')('looking for %s' % tsn) spellnum = -1 name = tsn try: spellnum = int(tsn) except ValueError: pass tskill = None if spellnum >= 1: #self.api.get('send.msg')('%s >= 0' % spellnum) if spellnum in self.skills: #self.api.get('send.msg')('found spellnum') tskill = copy.deepcopy(self.skills[spellnum]) #tskill = self.skills[spellnum] else: self.api.get('send.msg')('did not find skill for %s' % spellnum) if not tskill and name: #self.api.get('send.msg')('trying name') tlist = self.api.get('utils.checklistformatch')( name, self.skillsnamelookup.keys()) if len(tlist) == 1: tskill = copy.deepcopy( self.skills[self.skillsnamelookup[tlist[0]]]) if tskill: if tskill['recovery'] and tskill['recovery'] != -1: tskill['recovery'] = copy.deepcopy( self.recoveries[tskill['recovery']]) else: tskill['recovery'] = None return tskill # send the command to active a skill/spell def api_sendcmd(self, spellnum): """ send the command to activate a skill/spell """ skill = self.api.get('skills.gets')(spellnum) if skill: if skill['type'] == 'spell': self.api.get('send.msg')('casting %s' % skill['name']) self.api.get('send.execute')('cast %s' % skill['sn']) else: name = skill['name'].split()[0] self.api.get('send.msg')('sending skill %s' % skill['name']) self.api.get('send.execute')(name) # check if a skill/spell can be used def api_canuse(self, spellnum): """ return True if the spell can be used """ if self.api.get('skills.isaffected')(spellnum) \ or self.api.get('skills.isblockedbyrecovery')(spellnum) \ or not self.api.get('skills.ispracticed')(spellnum): return False return True # check if a skill/spell is a spellup def api_isspellup(self, spellnum): """ return True for a spellup, else return False """ spellnum = int(spellnum) if spellnum in self.skills: return self.skills[spellnum]['spellup'] return False # check if a skill/spell is bad def api_isbad(self, spellnum): """ return True for a bad spell, False for a good spell """ skill = self.api.get('skill.gets')(spellnum) if (skill['target'] == 'attack' or skill['target'] == 'special') and \ not skill['spellup']: return True return False # check if a skill/spell is active def api_isaffected(self, spellnum): """ return True for a spellup, else return False """ skill = self.api.get('skills.gets')(spellnum) if skill: return skill['duration'] > 0 return False # check if a skill/spell is blocked by a recovery def api_isblockedbyrecovery(self, spellnum): """ check to see if a spell/skill is blocked by a recovery """ skill = self.api.get('skills.gets')(spellnum) if skill: if 'recovery' in skill and skill['recovery'] and \ skill['recovery']['duration'] > 0: return True return False # check if a skill/spell is practiced def api_ispracticed(self, spellnum): """ is the spell learned """ skill = self.api.get('skills.gets')(spellnum) if skill: if skill['percent'] > 10: return True return False # get the list of spellup spells/skills def api_getspellups(self): """ return a list of spellup spells """ sus = [x for x in self.skills.values() if x['spellup']] return sus def savestate(self): """ save states """ AardwolfBasePlugin.savestate(self) self.skills.sync() self.recoveries.sync()
class Plugin(AardwolfBasePlugin): """ a plugin manage info about spells and skills """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.saveskillfile = os.path.join(self.savedir, 'skills.txt') self.skills = PersistentDict(self.saveskillfile, 'c') self.skillsnamelookup = {} for i in self.skills: self.skillsnamelookup[self.skills[i]['name']] = i self.saverecovfile = os.path.join(self.savedir, 'recoveries.txt') self.recoveries = PersistentDict(self.saverecovfile, 'c') self.recoveriesnamelookup = {} for i in self.recoveries: self.recoveriesnamelookup[self.recoveries[i]['name']] = i self.current = '' self.isuptodatef = False self.cmdqueue = None self.api.get('dependency.add')('cmdq') self.api.get('api.add')('gets', self.api_getskill) self.api.get('api.add')('isspellup', self.api_isspellup) self.api.get('api.add')('getspellups', self.api_getspellups) self.api.get('api.add')('sendcmd', self.api_sendcmd) self.api.get('api.add')('isaffected', self.api_isaffected) self.api.get('api.add')('isblockedbyrecovery', self.api_isblockedbyrecovery) self.api.get('api.add')('ispracticed', self.api_ispracticed) self.api.get('api.add')('canuse', self.api_canuse) self.api.get('api.add')('isuptodate', self.api_isuptodate) self.api.get('api.add')('isbad', self.api_isbad) def load(self): """ load the plugins """ AardwolfBasePlugin.load(self) self.api.get('send.msg')('running load function of skills') parser = argparse.ArgumentParser(add_help=False, description='refresh skills and spells') self.api.get('commands.add')('refresh', self.cmd_refresh, parser=parser) parser = argparse.ArgumentParser(add_help=False, description='lookup skill or spell by name or sn') parser.add_argument('skill', help='the skill to lookup', default='', nargs='?') self.api.get('commands.add')('lu', self.cmd_lu, parser=parser) self.api.get('triggers.add')('spellh_noprompt', "^\{spellheaders noprompt\}$", group='slist', enabled=False, omit=True) self.api.get('triggers.add')('spellh_spellup_noprompt', "^\{spellheaders spellup noprompt\}$", group='slist', enabled=False, omit=True) self.api.get('triggers.add')('spellh_affected_noprompt', "^\{spellheaders affected noprompt\}$", group='slist', enabled=False, omit=True) self.api.get('triggers.add')('spellh_spellline', "^(?P<sn>\d+),(?P<name>.+),(?P<target>\d+)," \ "(?P<duration>\d+),(?P<pct>\d+),(?P<rcvy>-?\d+),(?P<type>\d+)$", group='spellhead', enabled=False, omit=True) self.api.get('triggers.add')('spellh_end_noprompt', "^\{/spellheaders\}$", group='spellhead', enabled=False, omit=True) self.api.get('triggers.add')('affoff', "^\{affoff\}(?P<sn>\d+)$") self.api.get('triggers.add')('affon', "^\{affon\}(?P<sn>\d+),(?P<duration>\d+)$") self.api.get('triggers.add')('recov_noprompt', "^\{recoveries noprompt\}$", group='slist', enabled=False, omit=True) self.api.get('triggers.add')('recov_affected_noprompt', "^\{recoveries affected noprompt\}$", group='slist', enabled=False, omit=True) self.api.get('triggers.add')('spellh_recovline', "^(?P<sn>\d+),(?P<name>.+),(?P<duration>\d+)$", group='recoveries', enabled=False, omit=True) self.api.get('triggers.add')('recov_end_noprompt', "^\{/recoveries\}$", group='recoveries', enabled=False, omit=True) self.api.get('triggers.add')('recoff', "^\{recoff\}(?P<sn>\d+)$") self.api.get('triggers.add')('recon', "^\{recon\}(?P<sn>\d+),(?P<duration>\d+)$") self.api.get('triggers.add')('skillgain', "^\{skillgain\}(?P<sn>\d+),(?P<percent>\d+)$") self.api.get('triggers.add')('skillfail', "^\{sfail\}(?P<sn>\d+),(?P<target>\d+)," \ "(?P<reason>\d+),(?P<recovery>-?\d+)$") self.api.get('events.register')('trigger_spellh_noprompt', self.skillstart) self.api.get('events.register')('trigger_spellh_spellup_noprompt', self.skillstart) self.api.get('events.register')('trigger_spellh_affected_noprompt', self.skillstart) self.api.get('events.register')('trigger_spellh_spellline', self.skillline) self.api.get('events.register')('trigger_spellh_end_noprompt', self.skillend) self.api.get('events.register')('trigger_affoff', self.affoff) self.api.get('events.register')('trigger_affon', self.affon) self.api.get('events.register')('trigger_recov_noprompt', self.recovstart) self.api.get('events.register')('trigger_recov_affected_noprompt', self.recovstart) self.api.get('events.register')('trigger_spellh_recovline', self.recovline) self.api.get('events.register')('trigger_recov_end_noprompt', self.recovend) self.api.get('events.register')('trigger_recoff', self.recoff) self.api.get('events.register')('trigger_recon', self.recon) self.api.get('events.register')('trigger_skillgain', self.skillgain) self.api.get('events.register')('trigger_skillfail', self.skillfail) self.api.get('events.register')('GMCP:char.status', self.checkskills) self.api.get('events.register')('aard_level_tier', self.cmd_refresh) self.api.get('events.register')('aard_level_remort', self.cmd_refresh) self.cmdqueue = self.api.get('cmdq.baseclass')()(self) self.cmdqueue.addcmdtype('slist', 'slist', "^slist\s*(.*)$", beforef=self.slistbefore, afterf=self.slistafter) self.checkskills() def slistbefore(self): """ stuff to do before doing slist command """ self.api.get('triggers.togglegroup')('slist', True) def slistafter(self): """ stuff to do after doing slist command """ self.savestate() self.api.get('triggers.togglegroup')('slist', False) def afterfirstactive(self, _=None): """ do something on connect """ AardwolfBasePlugin.afterfirstactive(self) self.checkskills() # check if the spells/skills list is up to date def api_isuptodate(self): """ return True if we have seen affected or all spells refresh """ return self.isuptodatef def cmd_lu(self, args): """ cmd to lookup a spell """ msg = [] skill = self.api.get('skills.gets')(args['skill']) if skill: msg.append('%-8s : %s' % ('SN', skill['sn'])) msg.append('%-8s : %s' % ('Name', skill['name'])) msg.append('%-8s : %s' % ('Percent', skill['percent'])) if skill['duration'] > 0: msg.append('%-8s : %s' % ('Duration', self.api.get('utils.timedeltatostring')(time.time(), skill['duration']))) msg.append('%-8s : %s' % ('Target', skill['target'])) msg.append('%-8s : %s' % ('Spellup', skill['spellup'])) msg.append('%-8s : %s' % ('Type', skill['type'])) if skill['recovery']: recov = skill['recovery'] if recov['duration'] > 0: duration = self.api.get('utils.timedeltatostring')(time.time(), recov['duration']) msg.append('%-8s : %s (%s)' % ('Recovery', recov['name'], duration)) else: msg.append('%-8s : %s' % ('Recovery', recov['name'])) else: msg.append('Could not find: %s' % args['skill']) return True, msg def cmd_refresh(self, args): """ refresh spells and skills """ self.skills.clear() self.recoveries.clear() self.cmdqueue.addtoqueue('slist', 'noprompt') self.cmdqueue.addtoqueue('slist', 'spellup noprompt') msg = ['Refreshing spells and skills'] return True, msg def checkskills(self, _=None): """ check to see if we have spells """ state = self.api.get('GMCP.getv')('char.status.state') if state == 3: self.api.get('send.msg')('refreshing skills') self.api.get('events.unregister')('GMCP:char.status', self.checkskills) self.api.get('A102.toggle')('SPELLUPTAGS', True) self.api.get('A102.toggle')('SKILLGAINTAGS', True) self.api.get('A102.toggle')('QUIETTAGS', False) if len(self.skills) == 0: self.cmd_refresh({}) else: self.resetskills() self.cmdqueue.addtoqueue('slist', 'affected noprompt') def resetskills(self): """ reset the skills """ for i in self.skills: self.skills[i]['duration'] = 0 for i in self.recoveries: self.recoveries[i]['duration'] = 0 def skillgain(self, args): """ handle a skillgain tag """ spellnum = int(args['sn']) pct = int(args['percent']) if spellnum in self.skills: self.skills[spellnum]['percent'] = pct self.api.get('events.eraise')('aard_skill_gain', {'sn':spellnum, 'percent':pct}) def skillfail(self, args): """ raise an event when we fail a skill/spell """ spellnum = int(args['sn']) reason = FAILREASON[int(args['reason'])] ndict = {'sn':spellnum, 'reason':reason, 'target':FAILTARG[int(args['target'])], 'recovery':int(args['recovery'])} if reason == 'dontknow' and self.skills[spellnum]['percent'] > 0: self.api.get('send.msg')('refreshing spells because of an unlearned spell') self.cmd_refresh({}) self.api.get('send.msg')('raising skillfail: %s' % ndict) self.api.get('events.eraise')('skill_fail_%s' % args['sn'], ndict) self.api.get('events.eraise')('skill_fail', ndict) def affoff(self, args): """ set the affect to off for spell that wears off """ spellnum = int(args['sn']) if spellnum in self.skills: self.skills[spellnum]['duration'] = 0 self.savestate() self.api.get('events.eraise')('aard_skill_affoff_%s' % spellnum, {'sn':spellnum}) self.api.get('events.eraise')('aard_skill_affoff', {'sn':spellnum}) def affon(self, args): """ set the spell's duration when we see an affon """ spellnum = int(args['sn']) duration = int(args['duration']) if spellnum in self.skills: self.skills[spellnum]['duration'] = time.mktime(time.localtime()) + \ duration self.savestate() self.api.get('events.eraise')('aard_skill_affon_%s' % spellnum, {'sn':spellnum, 'duration':self.skills[spellnum]['duration']}) self.api.get('events.eraise')('aard_skill_affon', {'sn':spellnum, 'duration':self.skills[spellnum]['duration']}) def recovstart(self, args): """ show that the trigger fired """ if 'triggername' in args \ and args['triggername'] == 'trigger_recov_affected_noprompt': self.current = 'affected' else: self.current = '' self.api.get('triggers.togglegroup')('recoveries', True) def recovline(self, args): """ parse a recovery line """ spellnum = int(args['sn']) name = args['name'] if int(args['duration']) != 0: duration = time.mktime(time.localtime()) + int(args['duration']) else: duration = 0 if not (spellnum in self.recoveries): self.recoveries[spellnum] = {} self.recoveries[spellnum]['name'] = name self.recoveries[spellnum]['duration'] = duration self.recoveries[spellnum]['sn'] = spellnum self.recoveriesnamelookup[name] = spellnum def recovend(self, args): """ reset current when seeing a spellheaders ending """ self.api.get('triggers.togglegroup')('recoveries', False) if self.current == '' or self.current == 'affected': self.isuptodatef = True self.api.get('send.msg')('sending skills_affected_update') self.api.get('events.eraise')('skills_affected_update', {}) self.cmdqueue.cmddone('slist') def recoff(self, args): """ set the affect to off for spell that wears off """ spellnum = int(args['sn']) if spellnum in self.recoveries: self.recoveries[spellnum]['duration'] = 0 self.savestate() self.api.get('events.eraise')('aard_skill_recoff', {'sn':spellnum}) def recon(self, args): """ set the spell's duration when we see an affon """ spellnum = int(args['sn']) duration = int(args['duration']) if spellnum in self.recoveries: self.recoveries[spellnum]['duration'] = \ time.mktime(time.localtime()) + duration self.savestate() self.api.get('events.eraise')('aard_skill_recon', {'sn':spellnum, 'duration':self.recoveries[spellnum]['duration']}) def skillstart(self, args): """ show that the trigger fired """ if 'triggername' in args \ and args['triggername'] == 'spellh_spellup_noprompt': self.current = 'spellup' elif 'triggername' in args \ and args['triggername'] == 'spellh_affected_noprompt': self.current = 'affected' else: self.current = '' self.api.get('triggers.togglegroup')('spellhead', True) def skillline(self, args): """ parse spell lines """ spellnum = int(args['sn']) name = args['name'] target = int(args['target']) if int(args['duration']) != 0: duration = time.mktime(time.localtime()) + int(args['duration']) else: duration = 0 percent = int(args['pct']) recovery = int(args['rcvy']) stype = int(args['type']) if not (spellnum in self.skills): self.skills[spellnum] = {} self.skills[spellnum]['name'] = name self.skills[spellnum]['target'] = TARGET[target] self.skills[spellnum]['duration'] = duration self.skills[spellnum]['percent'] = percent self.skills[spellnum]['recovery'] = recovery self.skills[spellnum]['type'] = STYPE[stype] self.skills[spellnum]['sn'] = spellnum if not ('spellup' in self.skills[spellnum]): self.skills[spellnum]['spellup'] = False if self.current == 'spellup': self.skills[spellnum]['spellup'] = True self.skillsnamelookup[name] = spellnum def skillend(self, args): """ reset current when seeing a spellheaders ending """ self.api.get('triggers.togglegroup')('spellhead', False) self.savestate() if self.current: evname = 'aard_skill_ref_%s' % self.current else: evname = 'aard_skill_ref' self.api.get('events.eraise')(evname, {}) self.current = '' # get a spell/skill by number def api_getskill(self, tsn): """ get a skill """ #self.api.get('send.msg')('looking for %s' % tsn) spellnum = -1 name = tsn try: spellnum = int(tsn) except ValueError: pass tskill = None if spellnum >= 1: #self.api.get('send.msg')('%s >= 0' % spellnum) if spellnum in self.skills: #self.api.get('send.msg')('found spellnum') tskill = copy.deepcopy(self.skills[spellnum]) #tskill = self.skills[spellnum] else: self.api.get('send.msg')('did not find skill for %s' % spellnum) if not tskill and name: #self.api.get('send.msg')('trying name') tlist = self.api.get('utils.checklistformatch')(name, self.skillsnamelookup.keys()) if len(tlist) == 1: tskill = copy.deepcopy(self.skills[self.skillsnamelookup[tlist[0]]]) if tskill: if tskill['recovery'] and tskill['recovery'] != -1: tskill['recovery'] = copy.deepcopy(self.recoveries[tskill['recovery']]) else: tskill['recovery'] = None return tskill # send the command to active a skill/spell def api_sendcmd(self, spellnum): """ send the command to activate a skill/spell """ skill = self.api.get('skills.gets')(spellnum) if skill: if skill['type'] == 'spell': self.api.get('send.msg')('casting %s' % skill['name']) self.api.get('send.execute')('cast %s' % skill['sn']) else: name = skill['name'].split()[0] self.api.get('send.msg')('sending skill %s' % skill['name']) self.api.get('send.execute')(name) # check if a skill/spell can be used def api_canuse(self, spellnum): """ return True if the spell can be used """ if self.api.get('skills.isaffected')(spellnum) \ or self.api.get('skills.isblockedbyrecovery')(spellnum) \ or not self.api.get('skills.ispracticed')(spellnum): return False return True # check if a skill/spell is a spellup def api_isspellup(self, spellnum): """ return True for a spellup, else return False """ spellnum = int(spellnum) if spellnum in self.skills: return self.skills[spellnum]['spellup'] return False # check if a skill/spell is bad def api_isbad(self, spellnum): """ return True for a bad spell, False for a good spell """ skill = self.api.get('skill.gets')(spellnum) if (skill['target'] == 'attack' or skill['target'] == 'special') and \ not skill['spellup']: return True return False # check if a skill/spell is active def api_isaffected(self, spellnum): """ return True for a spellup, else return False """ skill = self.api.get('skills.gets')(spellnum) if skill: return skill['duration'] > 0 return False # check if a skill/spell is blocked by a recovery def api_isblockedbyrecovery(self, spellnum): """ check to see if a spell/skill is blocked by a recovery """ skill = self.api.get('skills.gets')(spellnum) if skill: if 'recovery' in skill and skill['recovery'] and \ skill['recovery']['duration'] > 0: return True return False # check if a skill/spell is practiced def api_ispracticed(self, spellnum): """ is the spell learned """ skill = self.api.get('skills.gets')(spellnum) if skill: if skill['percent'] > 10: return True return False # get the list of spellup spells/skills def api_getspellups(self): """ return a list of spellup spells """ sus = [x for x in self.skills.values() if x['spellup']] return sus def savestate(self): """ save states """ AardwolfBasePlugin.savestate(self) self.skills.sync() self.recoveries.sync()
class Plugin(BasePlugin): """ a plugin for user actions """ def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.canreload = True self.regexlookup = {} self.actiongroups = {} self.compiledregex = {} self.sessionhits = {} self.saveactionsfile = os.path.join(self.savedir, 'actions.txt') self.actions = PersistentDict(self.saveactionsfile, 'c') for i in self.actions: self.compiledregex[i] = re.compile(self.actions[i]['regex']) def load(self): """ load the plugin """ BasePlugin.load(self) self.api.get('setting.add')('nextnum', 0, int, 'the number of the next action added', readonly=True) parser = argparse.ArgumentParser(add_help=False, description='add a action') parser.add_argument('regex', help='the regex to match', default='', nargs='?') parser.add_argument('action', help='the action to take', default='', nargs='?') parser.add_argument('send', help='where to send the action', default='execute', nargs='?', choices=self.api.get('api.getchildren')('send')) parser.add_argument('-c', "--color", help="match colors (@@colors)", action="store_true") parser.add_argument('-d', "--disable", help="disable the action", action="store_true") parser.add_argument('-g', "--group", help="the action group", default="") parser.add_argument('-o', "--overwrite", help="overwrite an action if it already exists", action="store_true") self.api.get('commands.add')('add', self.cmd_add, parser=parser) parser = argparse.ArgumentParser(add_help=False, description='list actions') parser.add_argument( 'match', help='list only actions that have this argument in them', default='', nargs='?') self.api.get('commands.add')('list', self.cmd_list, parser=parser) parser = argparse.ArgumentParser(add_help=False, description='remove an action') parser.add_argument('action', help='the action to remove', default='', nargs='?') self.api.get('commands.add')('remove', self.cmd_remove, parser=parser) parser = argparse.ArgumentParser(add_help=False, description='toggle enabled flag') parser.add_argument('action', help='the action to toggle', default='', nargs='?') self.api.get('commands.add')('toggle', self.cmd_toggle, parser=parser) parser = argparse.ArgumentParser( add_help=False, description='get detail for an action') parser.add_argument('action', help='the action to get details for', default='', nargs='?') self.api.get('commands.add')('detail', self.cmd_detail, parser=parser) parser = argparse.ArgumentParser( add_help=False, description='toggle all actions in a group') parser.add_argument('group', help='the group to toggle', default='', nargs='?') parser.add_argument('-d', "--disable", help="disable the group", action="store_true") self.api.get('commands.add')('groupt', self.cmd_grouptoggle, parser=parser) #self.api.get('commands.add')('stats', self.cmd_stats, # shelp='show action stats') self.api.get('events.register')('from_mud_event', self.checkactions, prio=5) # self.api.get('events.register')('plugin_stats', self.getpluginstats) def lookup_action(self, action): """ lookup an action by number or name """ nitem = None try: num = int(action) nitem = None for titem in self.actions.keys(): if num == self.actions[titem]['num']: nitem = titem break except ValueError: if action in self.actions: nitem = action return nitem @timeit def checkactions(self, args): """ check a line of text from the mud the is called whenever the from_mud_event is raised """ data = args['noansi'] colordata = args['convertansi'] for i in self.actions: if self.actions[i]['enabled']: trigre = self.compiledregex[i] datatomatch = data if 'matchcolor' in self.actions[i] and \ self.actions[i]['matchcolor']: datatomatch = colordata mat = trigre.match(datatomatch) self.api.get('send.msg')('attempting to match %s' % datatomatch) if mat: if i in self.sessionhits: self.sessionhits[i] = 0 self.sessionhits[i] = self.sessionhits[i] + 1 if 'hits' in self.actions[i]: self.actions[i]['hits'] = 0 self.actions[i]['hits'] = self.actions[i]['hits'] + 1 self.api.get('send.msg')('matched line: %s to action %s' % (data, i)) templ = Template(self.actions[i]['action']) newaction = templ.safe_substitute(mat.groupdict()) sendtype = 'send.' + self.actions[i]['send'] self.api.get('send.msg')('sent %s to %s' % (newaction, sendtype)) self.api.get(sendtype)(newaction) return args def cmd_add(self, args): """ add user defined actions """ if not args['regex']: return False, ['Please include a regex'] if not args['action']: return False, ['Please include an action'] if not args['overwrite'] and args['regex'] in self.actions: return True, ['Action: %s already exists.' % args['regex']] else: num = 0 if args['regex'] in self.actions: num = self.actions[args['regex']]['num'] else: num = self.api.get('setting.gets')('nextnum') self.api.get('setting.change')('nextnum', num + 1) self.actions[args['regex']] = { 'num': num, 'regex': args['regex'], 'action': args['action'], 'send': args['send'], 'matchcolor': args['color'], 'enabled': not args['disable'], 'group': args['group'] } self.actions.sync() self.compiledregex[args['regex']] = re.compile(args['regex']) return True, ['added action %s - regex: %s' % (num, args['regex'])] return False, ['You should never see this'] def cmd_remove(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Remove an action @CUsage@w: rem @Y<originalstring>@w @Yoriginalstring@w = The original string """ tmsg = [] if args['action']: retval = self.removeaction(args['action']) if retval: tmsg.append("@GRemoving action@w : '%s'" % (retval)) else: tmsg.append("@GCould not remove action@w : '%s'" % (args['action'])) return True, tmsg else: return False, ['@RPlease include an action to remove@w'] def cmd_list(self, args): """ @G%(name)s@w - @B%(cmdname)s@w List actiones @CUsage@w: list """ tmsg = self.listactions(args['match']) return True, tmsg def cmd_toggle(self, args): """ toggle the enabled flag """ tmsg = [] if args['action']: retval = self.toggleaction(args['action']) if retval: if self.actions[retval]['enabled']: tmsg.append("@GEnabled action@w : '%s'" % (retval)) else: tmsg.append("@GDisabled action@w : '%s'" % (retval)) else: tmsg.append("@GDoes not exist@w : '%s'" % (args['action'])) return True, tmsg else: return False, ['@RPlease include an action to toggle@w'] def cmd_grouptoggle(self, args): """ toggle all actions in a group """ tmsg = [] togglea = [] state = not args['disable'] if args['group']: for i in self.actions: if self.actions[i]['group'] == args['group']: self.actions[i]['enabled'] = state togglea.append('%s' % self.actions[i]['num']) if togglea: tmsg.append('The following actions were %s: %s' % \ ('enabled' if state else 'disabled', ','.join(togglea))) else: tmsg.append('No actions were modified') return True, tmsg else: return False, ['@RPlease include a group to toggle@w'] def cmd_detail(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Add a action @CUsage@w: add @Y<originalstring>@w @M<replacementstring>@w @Yoriginalstring@w = The original string to be replaced @Mreplacementstring@w = The new string """ tmsg = [] if args['action']: action = self.lookup_action(args['action']) if action: if 'hits' in self.actions[action]: self.actions[action]['hits'] = 0 if action in self.sessionhits: self.sessionhits[action] = 0 tmsg.append('%-12s : %d' % ('Num', self.actions[action]['num'])) tmsg.append('%-12s : %s' % \ ('Enabled', 'Y' if self.actions[action]['enabled'] else 'N')) tmsg.append('%-12s : %d' % ('Total Hits', self.actions[action]['hits'])) tmsg.append('%-12s : %d' % ('Session Hits', self.sessionhits[action])) tmsg.append('%-12s : %s' % ('Regex', self.actions[action]['regex'])) tmsg.append('%-12s : %s' % ('Action', self.actions[action]['action'])) tmsg.append('%-12s : %s' % ('Group', self.actions[action]['group'])) tmsg.append( '%-12s : %s' % ('Match Color', self.actions[action]['matchcolor'])) else: return True, [ '@RAction does not exits@w : \'%s\'' % (args['action']) ] return True, tmsg else: return False, ['@RPlease include all arguments@w'] def listactions(self, match): """ return a table of strings that list actiones """ tmsg = [] for action in sorted(self.actions.keys()): item = self.actions[action] if not match or match in item: regex = self.api.get('colors.stripansi')(item['regex']) if len(regex) > 30: regex = regex[:27] + '...' action = self.api.get('colors.stripansi')(item['action']) if len(action) > 30: action = action[:27] + '...' tmsg.append("%4s %2s %-10s %-32s : %s@w" % \ (item['num'], 'Y' if item['enabled'] else 'N', item['group'], regex, action)) if len(tmsg) == 0: tmsg = ['None'] else: tmsg.insert( 0, "%4s %2s %-10s %-32s : %s@w" % ('#', 'E', 'Group', 'Regex', 'Action')) tmsg.insert(1, '@B' + '-' * 60 + '@w') return tmsg def removeaction(self, item): """ internally remove a action """ action = self.lookup_action(item) print 'lookup_action', item, 'returned', action if action >= 0: del self.actions[action] self.actions.sync() return action def toggleaction(self, item): """ toggle an action """ action = self.lookup_action(item) if action: self.actions[action][ 'enabled'] = not self.actions[action]['enabled'] return action def clearactions(self): """ clear all actiones """ self.actions.clear() self.actions.sync() def reset(self): """ reset the plugin """ BasePlugin.reset(self) self.clearactions() def savestate(self): """ save states """ BasePlugin.savestate(self) self.actions.sync()
class PluginMgr(BasePlugin): """ a class to manage plugins """ def __init__(self): """ initialize the instance """ # Examples: # name : 'Actions' - from plugin file variable NAME (long name) # sname : 'actions' - from plugin file variable SNAME (short name) # modpath : '/client/actions.py' - path relative to the plugins directory # basepath : '/home/src/games/bastproxy/bp/plugins' - the full path to the # plugins directory # fullimploc : 'plugins.client.actions' - import location #name, sname, modpath, basepath, fullimploc BasePlugin.__init__( self, 'Plugin Manager', #name, 'plugins', #sname, "/__init__.py", #modpath "$basepath$", # basepath "plugins.__init__", # fullimploc ) self.canreload = False #key: modpath #value: {'plugin', 'module'} self.loadedpluginsd = {} self.pluginlookupbysname = {} self.pluginlookupbyname = {} self.pluginlookupbyfullimploc = {} # key: modpath # value: {'sname', 'name', 'purpose', 'author', # 'version', 'modpath', 'fullimploc' self.allplugininfo = {} index = __file__.rfind(os.sep) if index == -1: self.basepath = "." + os.sep else: self.basepath = __file__[:index] self.savefile = os.path.join(self.api.BASEPATH, 'data', 'plugins', 'loadedplugins.txt') self.loadedplugins = PersistentDict(self.savefile, 'c') self.api('api.add')('isloaded', self._api_isloaded) self.api('api.add')('getp', self._api_getp) self.api('api.add')('module', self._api_getmodule) self.api('api.add')('allplugininfo', self._api_allplugininfo) self.api('api.add')('savestate', self.savestate) # return the dictionary of all plugins def _api_allplugininfo(self): """ return the plugininfo dictionary """ return self.allplugininfo def findloadedplugin(self, plugin): """ find a plugin """ return self.api('plugins.getp')(plugin) # get a plugin instance def _api_getmodule(self, pluginname): """ returns the module of a plugin @Ypluginname@w = the plugin to check for""" plugin = self.api('plugins.getp')(pluginname) if plugin: return self.loadedpluginsd[plugin.modpath]['module'] return None # get a plugin instance def _api_getp(self, pluginname): """ get a loaded plugin instance @Ypluginname@w = the plugin to get""" if isinstance(pluginname, basestring): if pluginname in self.loadedpluginsd: return self.loadedpluginsd[pluginname]['plugin'] if pluginname in self.pluginlookupbysname: return self.loadedpluginsd[ self.pluginlookupbysname[pluginname]]['plugin'] if pluginname in self.pluginlookupbyname: return self.loadedpluginsd[ self.pluginlookupbyname[pluginname]]['plugin'] if pluginname in self.pluginlookupbyfullimploc: return self.loadedpluginsd[ self.pluginlookupbyfullimploc[pluginname]]['plugin'] elif isinstance(pluginname, BasePlugin): return pluginname return None # check if a plugin is loaded def _api_isloaded(self, pluginname): """ check if a plugin is loaded @Ypluginname@w = the plugin to check for""" plugin = self.api('plugins.getp')(pluginname) if plugin: return True return False # load plugin dependencies def _loaddependencies(self, pluginname, dependencies): """ load a list of modules """ for i in dependencies: plugin = self.api('plugins.getp')(i) if plugin: continue self.api('send.msg')('%s: loading dependency %s' % (pluginname, i), pluginname) name, path = imputils.findmodule(self.basepath, i) if name: modpath = name.replace(path, '') self._loadplugin(modpath, path, force=True) # get all not loaded plugins def _getnotloadedplugins(self): """ create a message of all not loaded plugins """ msg = [] badplugins = self._updateallplugininfo() pdiff = set(self.allplugininfo) - set(self.loadedpluginsd) for modpath in sorted(pdiff): msg.append("%-20s : %-25s %-10s %-5s %s@w" % \ (self.allplugininfo[modpath]['fullimploc'].replace('plugins.', ''), self.allplugininfo[modpath]['name'], self.allplugininfo[modpath]['author'], self.allplugininfo[modpath]['version'], self.allplugininfo[modpath]['purpose'])) if msg: msg.insert(0, '-' * 75) msg.insert(0, "%-20s : %-25s %-10s %-5s %s@w" % \ ('Location', 'Name', 'Author', 'Vers', 'Purpose')) msg.insert(0, 'The following plugins are not loaded') if badplugins: msg.append('') msg.append('The following files would not import') for bad in badplugins: msg.append(bad.replace('plugins.', '')) return msg # get plugins that are change on disk def _getchangedplugins(self): """ create a message of plugins that are changed on disk """ msg = [] plugins = sorted([i['plugin'] for i in self.loadedpluginsd.values()], key=operator.attrgetter('package')) packageheader = [] msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ ('Short Name', 'Name', 'Author', 'Vers', 'Purpose')) msg.append('-' * 75) found = False for tpl in plugins: if tpl.ischangedondisk(): found = True if tpl.package not in packageheader: if packageheader: msg.append('') packageheader.append(tpl.package) limp = 'plugins.%s' % tpl.package mod = __import__(limp) try: desc = getattr(mod, tpl.package).DESCRIPTION except AttributeError: desc = '' msg.append('@GPackage: %s%s@w' % \ (tpl.package, ' - ' + desc if desc else '')) msg.append('@G' + '-' * 75 + '@w') msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ (tpl.sname, tpl.name, tpl.author, tpl.version, tpl.purpose)) if found: return msg return ['No plugins are changed on disk.'] # get a message of plugins in a package def _getpackageplugins(self, package): """ create a message of plugins in a package """ msg = [] plist = [] for plugin in [i['plugin'] for i in self.loadedpluginsd.values()]: if plugin.package == package: plist.append(plugin) if plist: plugins = sorted(plist, key=operator.attrgetter('sname')) limp = 'plugins.%s' % package mod = __import__(limp) try: desc = getattr(mod, package).DESCRIPTION except AttributeError: desc = '' msg.append('@GPackage: %s%s@w' % \ (package, ' - ' + desc if desc else '')) msg.append('@G' + '-' * 75 + '@w') msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ ('Short Name', 'Name', 'Author', 'Vers', 'Purpose')) msg.append('-' * 75) for tpl in plugins: msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ (tpl.sname, tpl.name, tpl.author, tpl.version, tpl.purpose)) else: msg.append('That is not a valid package') return msg # create a message of all plugins def _getallplugins(self): """ create a message of all plugins """ msg = [] plugins = sorted([i['plugin'] for i in self.loadedpluginsd.values()], key=operator.attrgetter('package')) packageheader = [] msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ ('Short Name', 'Name', 'Author', 'Vers', 'Purpose')) msg.append('-' * 75) for tpl in plugins: if tpl.package not in packageheader: if packageheader: msg.append('') packageheader.append(tpl.package) limp = 'plugins.%s' % tpl.package mod = __import__(limp) try: desc = getattr(mod, tpl.package).DESCRIPTION except AttributeError: desc = '' msg.append('@GPackage: %s%s@w' % \ (tpl.package, ' - ' + desc if desc else '')) msg.append('@G' + '-' * 75 + '@w') msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ (tpl.sname, tpl.name, tpl.author, tpl.version, tpl.purpose)) return msg # command to list plugins def _cmd_list(self, args): """ @G%(name)s@w - @B%(cmdname)s@w List plugins @CUsage@w: list """ msg = [] if args['notloaded']: msg.extend(self._getnotloadedplugins()) elif args['changed']: msg.extend(self._getchangedplugins()) elif args['package']: msg.extend(self._getpackageplugins(args['package'])) else: msg.extend(self._getallplugins()) return True, msg # command to load plugins def _cmd_load(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Load a plugin @CUsage@w: load @Yplugin@w @Yplugin@w = the name of the plugin to load use the name without the .py """ tmsg = [] plugin = args['plugin'] if plugin: fname = plugin.replace('.', os.sep) _module_list = imputils.find_files(self.basepath, fname + ".py") if len(_module_list) > 1: tmsg.append('There is more than one module that matches: %s' % \ plugin) elif not _module_list: tmsg.append('There are no modules that match: %s' % plugin) else: modpath = _module_list[0].replace(self.basepath, '') sname, reason = self._loadplugin(modpath, self.basepath, True) plugin = self.api('plugins.getp')(sname) if sname: if reason == 'already': tmsg.append('Plugin %s is already loaded' % sname) else: tmsg.append('Load complete: %s - %s' % \ (sname, plugin.name)) else: tmsg.append('Could not load: %s' % plugin) return True, tmsg else: return False, ['@Rplease specify a plugin@w'] # command to unload a plugin def _cmd_unload(self, args): """ @G%(name)s@w - @B%(cmdname)s@w unload a plugin @CUsage@w: unload @Yplugin@w @Yplugin@w = the shortname of the plugin to load """ tmsg = [] plugina = args['plugin'] if not plugina: return False, ['@Rplease specify a plugin@w'] plugin = self.findloadedplugin(plugina) if plugin: if plugin.canreload: if self._unloadplugin(plugin.fullimploc): tmsg.append("Unloaded: %s" % plugin.fullimploc) else: tmsg.append("Could not unload:: %s" % plugin.fullimploc) else: tmsg.append("That plugin can not be unloaded") return True, tmsg elif plugin: tmsg.append('plugin %s does not exist' % plugin) return True, tmsg return False, ['@Rplease specify a plugin@w'] # command to reload a plugin def _cmd_reload(self, args): """ @G%(name)s@w - @B%(cmdname)s@w reload a plugin @CUsage@w: reload @Yplugin@w @Yplugin@w = the shortname of the plugin to reload """ tmsg = [] plugina = args['plugin'] if not plugina: return False, ['@Rplease specify a plugin@w'] plugin = self.findloadedplugin(plugina) if plugin: if plugin.canreload: tret, _ = self._reloadplugin(plugin.modpath, True) if tret and tret != True: plugin = self.findloadedplugin(plugina) tmsg.append("Reload complete: %s" % plugin.fullimploc) return True, tmsg else: tmsg.append("That plugin cannot be reloaded") return True, tmsg else: tmsg.append('plugin %s does not exist' % plugina) return True, tmsg return False, tmsg # load all plugins def _loadplugins(self, tfilter): """ load plugins in all directories under the plugin directory """ _module_list = imputils.find_files(self.basepath, tfilter) _module_list.sort() load = False for fullpath in _module_list: modpath = fullpath.replace(self.basepath, '') force = False if modpath in self.loadedplugins: force = True modname, dummy = self._loadplugin(modpath, self.basepath, force=force, runload=load) if modname == 'log': self.api('log.adddtype')(self.sname) self.api('log.console')(self.sname) self.api('log.adddtype')('upgrade') self.api('log.console')('upgrade') if not load: testsort = sorted( [i['plugin'] for i in self.loadedpluginsd.values()], key=operator.attrgetter('priority')) for i in testsort: try: #check dependencies here self.loadplugin(i) except Exception: # pylint: disable=broad-except self.api('send.traceback')( "load: had problems running the load method for %s." \ % i.fullimploc) imputils.deletemodule(i.fullimploc) # update all plugin info def _updateallplugininfo(self): """ find plugins that are not in self.allplugininfo """ _plugin_list = imputils.find_files(self.basepath, '*.py') _plugin_list.sort() self.allplugininfo = {} badplugins = [] for fullpath in _plugin_list: modpath = fullpath.replace(self.basepath, '') imploc, modname = imputils.get_module_name(modpath) if not modname.startswith("_"): fullimploc = "plugins" + '.' + imploc if fullimploc in sys.modules: plugin = self.api('plugins.getp')(modpath) self.allplugininfo[modpath] = {} self.allplugininfo[modpath]['sname'] = plugin.sname self.allplugininfo[modpath]['name'] = plugin.name self.allplugininfo[modpath]['purpose'] = plugin.purpose self.allplugininfo[modpath]['author'] = plugin.author self.allplugininfo[modpath]['version'] = plugin.version self.allplugininfo[modpath]['modpath'] = modpath self.allplugininfo[modpath]['fullimploc'] = fullimploc else: try: _module = __import__(fullimploc) _module = sys.modules[fullimploc] self.allplugininfo[modpath] = {} self.allplugininfo[modpath]['sname'] = _module.SNAME self.allplugininfo[modpath]['name'] = _module.NAME self.allplugininfo[modpath][ 'purpose'] = _module.PURPOSE self.allplugininfo[modpath]['author'] = _module.AUTHOR self.allplugininfo[modpath][ 'version'] = _module.VERSION self.allplugininfo[modpath]['modpath'] = modpath self.allplugininfo[modpath]['fullimploc'] = fullimploc imputils.deletemodule(fullimploc) except Exception: # pylint: disable=broad-except badplugins.append(fullimploc) return badplugins # load a plugin def _loadplugin(self, modpath, basepath, force=False, runload=True): """ load a single plugin """ success, msg, module, fullimploc = imputils.importmodule( modpath, basepath, self, 'plugins') if success and msg == 'import': load = True if 'AUTOLOAD' in module.__dict__ and not force: if not module.AUTOLOAD: load = False elif 'AUTOLOAD' not in module.__dict__: load = False if modpath not in self.allplugininfo: self.allplugininfo[modpath] = {} self.allplugininfo[modpath]['sname'] = module.SNAME self.allplugininfo[modpath]['name'] = module.NAME self.allplugininfo[modpath]['purpose'] = module.PURPOSE self.allplugininfo[modpath]['author'] = module.AUTHOR self.allplugininfo[modpath]['version'] = module.VERSION self.allplugininfo[modpath]['modpath'] = modpath self.allplugininfo[modpath]['fullimploc'] = fullimploc if load: if "Plugin" in module.__dict__: self._addplugin(module, modpath, basepath, fullimploc, runload) else: self.api('send.msg')('Module %s has no Plugin class' % \ module.NAME) module.__dict__["proxy_import"] = 1 return module.SNAME, 'Loaded' else: imputils.deletemodule(fullimploc) self.api('send.msg')( 'Not loading %s (%s) because autoload is False' % \ (module.NAME, fullimploc), primary='plugins') return True, 'not autoloaded' return success, msg # unload a plugin def _unloadplugin(self, fullimploc): """ unload a module """ if fullimploc in sys.modules: _module = sys.modules[fullimploc] success = True try: if "proxy_import" in _module.__dict__: self.api('send.client')('unload: unloading %s' % fullimploc) if "unload" in _module.__dict__: try: _module.unload() except Exception: # pylint: disable=broad-except success = False self.api('send.traceback')( "unload: module %s didn't unload properly." % fullimploc) if not self._removeplugin(_module.SNAME): self.api('send.client')('could not remove plugin %s' % fullimploc) success = False except Exception: # pylint: disable=broad-except self.api('send.traceback')( "unload: had problems unloading %s." % fullimploc) success = False if success: imputils.deletemodule(fullimploc) self.api('send.client')("unload: unloaded %s." % fullimploc) return success # reload a plugin def _reloadplugin(self, modpath, force=False): """ reload a plugin """ if modpath in self.loadedpluginsd: plugin = self.api.get('plugins.getp')(modpath) fullimploc = plugin.fullimploc basepath = plugin.basepath modpath = plugin.modpath sname = plugin.sname try: reloaddependents = plugin.reloaddependents except Exception: # pylint: disable=broad-except reloaddependents = False plugin = None if not self._unloadplugin(fullimploc): return False, '' if modpath and basepath: retval = self._loadplugin(modpath, basepath, force) if retval and reloaddependents: self._reloadalldependents(sname) return retval else: return False, '' # reload all dependents def _reloadalldependents(self, reloadedplugin): """ reload all dependents """ testsort = sorted([i['plugin'] for i in self.loadedpluginsd.values()], key=operator.attrgetter('priority')) for plugin in testsort: if plugin.sname != reloadedplugin: if reloadedplugin in plugin.dependencies: self.api('send.msg')('reloading dependent %s of %s' % \ (plugin.sname, reloadedplugin), plugin.sname) plugin.savestate() self._reloadplugin(plugin.modpath, True) # load a plugin def loadplugin(self, plugin): """ check dependencies and run the load function """ self.api('send.msg')('loading dependencies for %s' % \ plugin.fullimploc, plugin.sname) self._loaddependencies(plugin.sname, plugin.dependencies) self.api('send.client')("load: loading %s with priority %s" % \ (plugin.fullimploc, plugin.priority)) self.api('send.msg')('loading %s (%s: %s)' % \ (plugin.fullimploc, plugin.sname, plugin.name), plugin.sname) plugin.load() self.api('send.client')("load: loaded %s" % plugin.fullimploc) self.api('send.msg')('loaded %s (%s: %s)' % \ (plugin.fullimploc, plugin.sname, plugin.name), plugin.sname) self.api('events.eraise')('%s_plugin_loaded' % plugin.sname, {}) self.api('events.eraise')('plugin_loaded', {'plugin': plugin.sname}) # add a plugin def _addplugin(self, module, modpath, basepath, fullimploc, load=True): # pylint: disable=too-many-arguments """ add a plugin to be managed """ pluginn = self.api('plugins.getp')(module.NAME) plugins = self.api('plugins.getp')(module.SNAME) if plugins or pluginn: self.api('send.msg')('Plugin %s already exists' % module.NAME, secondary=module.SNAME) return False plugin = module.Plugin(module.NAME, module.SNAME, modpath, basepath, fullimploc) plugin.author = module.AUTHOR plugin.purpose = module.PURPOSE plugin.version = module.VERSION try: plugin.priority = module.PRIORITY except AttributeError: pass if load: try: #check dependencies here self.loadplugin(plugin) except Exception: # pylint: disable=broad-except self.api('send.traceback')( "load: had problems running the load method for %s." \ % fullimploc) imputils.deletemodule(fullimploc) return False self.loadedpluginsd[modpath] = {} self.loadedpluginsd[modpath]['plugin'] = plugin self.loadedpluginsd[modpath]['module'] = module self.pluginlookupbysname[plugin.sname] = modpath self.pluginlookupbyname[plugin.name] = modpath self.pluginlookupbyfullimploc[fullimploc] = modpath self.loadedplugins[modpath] = True self.loadedplugins.sync() return True # remove a plugin def _removeplugin(self, pluginname): """ remove a plugin """ plugin = self.api('plugins.getp')(pluginname) if plugin: try: plugin.unload() self.api('events.eraise')('%s_plugin_unload' % plugin.sname, {}) self.api('events.eraise')('plugin_unloaded', { 'name': plugin.sname }) self.api('send.msg')('Plugin %s unloaded' % plugin.sname, secondary=plugin.sname) except Exception: # pylint: disable=broad-except self.api('send.traceback')( "unload: had problems running the unload method for %s." \ % plugin.sname) return False del self.loadedpluginsd[plugin.modpath] del self.pluginlookupbyfullimploc[plugin.fullimploc] del self.pluginlookupbyname[plugin.name] del self.pluginlookupbysname[plugin.sname] del self.loadedplugins[plugin.modpath] self.loadedplugins.sync() plugin = None return True return False # get stats for this plugin def getstats(self): """ return stats for events """ stats = {} stats['Base Sizes'] = {} stats['Base Sizes']['showorder'] = [ 'Class', 'Api', 'loadedpluginsd', 'plugininfo' ] stats['Base Sizes']['loadedpluginsd'] = '%s bytes' % \ sys.getsizeof(self.loadedpluginsd) stats['Base Sizes']['plugininfo'] = '%s bytes' % \ sys.getsizeof(self.allplugininfo) stats['Base Sizes']['Class'] = '%s bytes' % sys.getsizeof(self) stats['Base Sizes']['Api'] = '%s bytes' % sys.getsizeof(self.api) stats['Plugins'] = {} stats['Plugins']['showorder'] = ['Total', 'Loaded', 'Bad'] stats['Plugins']['Total'] = len(self.allplugininfo) stats['Plugins']['Loaded'] = len(self.loadedpluginsd) badplugins = self._updateallplugininfo() stats['Plugins']['Bad'] = len(badplugins) return stats def shutdown(self, args=None): # pylint: disable=unused-argument """ do tasks on shutdown """ self.savestate() # save all plugins def savestate(self, args=None): # pylint: disable=unused-argument """ save all plugins """ for i in self.loadedpluginsd.values(): i['plugin'].savestate() # load this plugin def load(self): """ load various things """ self._loadplugins("*.py") BasePlugin._loadcommands(self) parser = argp.ArgumentParser(add_help=False, description="list plugins") parser.add_argument('-n', "--notloaded", help="list plugins that are not loaded", action="store_true") parser.add_argument( '-c', "--changed", help="list plugins that are load but are changed on disk", action="store_true") parser.add_argument('package', help='the to list', default='', nargs='?') self.api('commands.add')('list', self._cmd_list, lname='Plugin Manager', parser=parser) parser = argp.ArgumentParser(add_help=False, description="load a plugin") parser.add_argument('plugin', help='the plugin to load, don\'t include the .py', default='', nargs='?') self.api('commands.add')('load', self._cmd_load, lname='Plugin Manager', parser=parser) parser = argp.ArgumentParser(add_help=False, description="unload a plugin") parser.add_argument('plugin', help='the plugin to unload', default='', nargs='?') self.api('commands.add')('unload', self._cmd_unload, lname='Plugin Manager', parser=parser) parser = argp.ArgumentParser(add_help=False, description="reload a plugin") parser.add_argument('plugin', help='the plugin to reload', default='', nargs='?') self.api('commands.add')('reload', self._cmd_reload, lname='Plugin Manager', parser=parser) self.api('commands.default')('list', self.sname) self.api('timers.add')('save', self.savestate, 60, nodupe=True, log=False) self.api('events.register')('proxy_shutdown', self.shutdown)
class Plugin(AardwolfBasePlugin): """ a plugin that does spellups """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.spellupfile = os.path.join(self.savedir, 'spellups.txt') self.spellups = PersistentDict(self.spellupfile, 'c') self.api('dependency.add')('aardwolf.skills') self.api('dependency.add')('aardwolf.move') self.initspellups() self.lastmana = -1 self.lastmoves = -1 def load(self): """ load the plugins """ AardwolfBasePlugin.load(self) self.api('setting.add')('enabled', True, bool, 'auto spellup is enabled') self.api('setting.add')('waiting', -1, int, 'the spell that was just cast', readonly=True) self.api('setting.add')('nocast', False, bool, 'in a nocast room', readonly=True) self.api('setting.add')('nomoves', False, bool, 'need more moves', readonly=True) self.api('setting.add')('nomana', False, bool, 'need more mana', readonly=True) self.api('setting.add')('nocastrooms', {}, dict, 'list of nocast rooms', readonly=True) self.api('setting.add')('currentroom', -1, int, 'the current room', readonly=True) parser = argp.ArgumentParser(add_help=False, description='add a spellup to the self list') parser.add_argument( 'spell', help='the spells to add, use \'all\' to add all practiced spellups', default=[], nargs='*') parser.add_argument( '-o', "--override", help="add even if the spell is not flagged as a spellup by the mud", action="store_true") self.api('commands.add')('add', self.cmd_sadd, parser=parser, group='Spellups on Self') parser = argp.ArgumentParser(add_help=False, description='list spellups for self') parser.add_argument( 'match', help='list only spellups that have this argument in them', default='', nargs='?') self.api('commands.add')('list', self.cmd_slist, parser=parser, group='Spellups on Self') parser = argp.ArgumentParser(add_help=False, description='remove a spellup from the self list') parser.add_argument( 'spell', help='the spells to remove, use \'all\' to remove all spellups', default=[], nargs='*') self.api('commands.add')('rem', self.cmd_srem, parser=parser, group='Spellups on Self') parser = argp.ArgumentParser(add_help=False, description='enable spellups on self') parser.add_argument( 'spell', help='the spells to enable, use \'all\' to enable all spellups', default=[], nargs='*') self.api('commands.add')('en', self.cmd_en, parser=parser, group='Spellups on Self') parser = argp.ArgumentParser(add_help=False, description='disable spells on self') parser.add_argument( 'spell', help='the spells to disable, use \'all\' to disable all spellups', default=[], nargs='*') self.api('commands.add')('dis', self.cmd_dis, shelp='disable a spellup on self', parser=parser, group='Spellups on Self') self.api('commands.add')('check', self.cmd_check, shelp='check data status for casting', group='Spellups on Self') self.api('events.register')('GMCP:char.vitals', self._charvitals) self.api('events.register')('GMCP:char.status', self._charstatus) self.api('events.register')('moved_room', self._moved) self.api('events.register')('skill_fail', self._skillfail) self.api('events.register')('aard_skill_affon', self._affon) self.api('events.register')('aard_skill_affoff', self._affoff) self.api('events.register')('aard_skill_recoff', self._recoff) self.api('events.register')('aard_skill_gain', self.skillgain) self.api('events.register')('var_su_enabled', self.enabledchange) self.api('events.register')('skills_affected_update', self.nextspell) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) self.api('events.register')('skills_uptodate', self.nextspell) def skillgain(self, args=None): """ check skills when we gain them """ if args['sn'] in self.spellups['sorder'] and args['percent'] > 50: self.nextspell() def initspellups(self): """ initialize the spellups dictionary """ if 'sorder' not in self.spellups: self.spellups['sorder'] = [] if 'self' not in self.spellups: self.spellups['self'] = {} if 'oorder' not in self.spellups: self.spellups['oorder'] = [] if 'other' not in self.spellups: self.spellups['other'] = {} def enabledchange(self, args): """ do something when enabled is changed """ if args['newvalue']: self.nextspell() def _affon(self, args): """ catch an affon event """ if args['sn'] == self.api('setting.gets')('waiting'): self.api('setting.change')('waiting', -1) self.nextspell() def _affoff(self, _=None): """ catch an affoff event """ self.nextspell() def _recoff(self, _=None): """ catch a recoff event """ self.nextspell() def _skillfail(self, args): # pylint: disable=too-many-branches """ catch a skill fail event """ self.api('send.msg')('skillfail: %s' % args) spellnum = args['sn'] skill = self.api('skills.gets')(spellnum) waiting = self.api('setting.gets')('waiting') if args['reason'] == 'nomana': self.api('setting.change')('waiting', -1) self.api('setting.change')('nomana', True) self.lastmana = self.api('GMCP.getv')('char.vitals.mana') elif args['reason'] == 'nocastroom': self.api('setting.change')('waiting', -1) self.api('setting.change')('nocast', True) nocastrooms = self.api('setting.gets')('nocastrooms') currentroom = self.api('setting.gets')('currentroom') nocastrooms[currentroom] = True elif args['reason'] == 'fighting' or args['reason'] == 'notactive': self.api('setting.change')('waiting', -1) elif args['reason'] == 'nomoves': self.api('setting.change')('waiting', -1) self.api('setting.change')('nomoves', True) self.lastmana = self.api('GMCP.getv')('char.vitals.moves') elif waiting == spellnum: if args['reason'] == 'lostconc': self.api('skills.sendcmd')(waiting) elif args['reason'] == 'alreadyaff': self.api('setting.change')('waiting', -1) self.api('send.client')( "@BSpellup - disabled %s because you are already affected" % \ skill['name']) if spellnum in self.spellups['self']: self.spellups['self'][spellnum]['enabled'] = False #if spellnum in self.spellups['other']: #self.spellups['other'][spellnum]['enabled'] = False self.nextspell() elif args['reason'] == 'recblock': # do stuff when blocked by a recovery self.api('setting.change')('waiting', -1) self.nextspell() elif args['reason'] == 'dontknow': # do stuff when spell/skill isn't learned # don't disable it, hopefully the spell/skill has been updated and # won't be cast through nextspell self.api('setting.change')('waiting', -1) self.nextspell() elif args['reason'] == 'wrongtarget': # do stuff when a wrong target self.api('setting.change')('waiting', -1) self.nextspell() elif args['reason'] == 'disabled': self.api('setting.change')('waiting', -1) skill = self.api('skills.gets')(spellnum) self.api('send.client')( "@BSpellup - disabled %s because it is disabled mudside" % \ skill['name']) if spellnum in self.spellups['self']: self.spellups['self'][spellnum]['enabled'] = False if spellnum in self.spellups['other']: self.spellups['other'][spellnum]['enabled'] = False self.nextspell() def _moved(self, args): """ reset stuff if we move """ self.api('setting.change')('currentroom', args['to']['num']) nocastrooms = self.api('setting.gets')('nocastrooms') if args['to']['num'] in nocastrooms: self.api('setting.change')('nocast', True) else: lastval = self.api('setting.gets')('nocast') self.api('setting.change')('nocast', False) if lastval: self.nextspell() def _charvitals(self, _=None): """ check if we have more mana and moves """ if self.api('setting.gets')('nomana'): newmana = self.api('GMCP.getv')('char.vitals.mana') if newmana > self.lastmana: self.lastmana = -1 self.api('setting.change')('nomana', False) self.nextspell() if self.api('setting.gets')('nomoves'): newmoves = self.api('GMCP.getv')('char.vitals.moves') if newmoves > self.lastmoves: self.lastmoves = -1 self.api('setting.change')('nomoves', False) self.nextspell() def _charstatus(self, _=None): """ check if we have more mana and moves """ status = self.api('GMCP.getv')('char.status.state') if status == 3 and self.api('skills.isuptodate')(): self.nextspell() @timeit def check(self, _=None): """ check to cast the next spell """ mud = self.api('managers.getm')('mud') if not mud or not mud.connected: return False self.api('send.msg')('waiting type: %s' % \ type(self.api('setting.gets')('waiting'))) self.api('send.msg')('currentstatus = %s' % \ self.api('GMCP.getv')('char.status.state')) # pylint: disable=too-many-boolean-expressions if self.api('setting.gets')('nomoves') \ or self.api('setting.gets')('nomana') \ or self.api('setting.gets')('nocast') \ or self.api('setting.gets')('waiting') != -1 \ or not self.api('setting.gets')('enabled') \ or not self.api('skills.isuptodate')() or \ self.api('GMCP.getv')('char.status.state') != 3: self.api('send.msg')('checked returned False') return False self.api('send.msg')('checked returned True') return True @timeit def nextspell(self, _=None): """ try to cast the next spell """ self.api('send.msg')('nextspell') if self.check(): for i in self.spellups['sorder']: if self.spellups['self'][i]['enabled']: if self.api('skills.canuse')(i): self.api('setting.change')('waiting', int(i)) self.api('skills.sendcmd')(i) return def _savestate(self, _=None): """ save states """ self.spellups.sync() def _addselfspell(self, spellnum, place=-1, override=False): """ add a spell internally """ msg = [] spell = self.api('skills.gets')(spellnum) if not spell: msg.append('%-20s: does not exist' % spellnum) return msg if not override and not self.api('skills.isspellup')(spell['sn']): msg.append('%-20s: not a spellup' % spell['name']) return msg if spell['sn'] in self.spellups['sorder']: msg.append('%-30s: already activated' % spell['name']) return msg self.spellups['self'][spell['sn']] = {'enabled':True} if place > -1: self.spellups['sorder'].insert(place, spell['sn']) else: self.spellups['sorder'].append(spell['sn']) msg.append('%-20s: place %s' % \ (spell['name'], self.spellups['sorder'].index(spell['sn']))) return msg def cmd_sadd(self, args): """ add a spellup """ msg = [] if len(args['spell']) < 1: return False, ['Please supply a spell'] if args['spell'][0] == 'all': spellups = self.api('skills.getspellups')() for spell in spellups: if spell['percent'] > 1: tmsg = self._addselfspell(spell['sn']) msg.extend(tmsg) self.nextspell() else: for aspell in args['spell']: tspell = aspell place = -1 if ':' in aspell: tlist = aspell.split(':') tspell = tlist[0] place = int(tlist[1]) tmsg = self._addselfspell(tspell, place, args['override']) msg.extend(tmsg) self.nextspell() self.spellups.sync() return True, msg def cmd_slist(self, args): """ list the spellups """ msg = [] match = args['match'] if self.spellups['sorder']: msg.append('%-3s - %-30s : %2s %2s %2s %2s %-2s %-2s' % \ ('Num', 'Name', 'A', 'P', 'B', 'D', 'NP', 'NL')) msg.append('@B' + '-'* 60) for i in self.spellups['sorder']: skill = self.api('skills.gets')(i) if not skill: msg.append('%-3s: please check the skills plugin' % \ (self.spellups['sorder'].index(i))) elif not match or match in skill['name']: msg.append('%-3s - %-30s : %2s %2s %2s %2s %-2s %-2s' % \ (self.spellups['sorder'].index(i), skill['name'], 'A' if self.api('skills.isaffected')(i) else '', 'P' if self.api('setting.gets')('waiting') == i else '', 'B' if self.api('skills.isblockedbyrecovery')(i) else '', 'D' if not self.spellups['self'][i]['enabled'] else '', 'NP' if skill['percent'] == 1 else '', 'NL' if skill['percent'] == 0 else '',)) else: msg.append('There are no spellups') return True, msg def cmd_srem(self, args): """ remove a spellup """ if len(args['spell']) < 1: return True, ['Please supply a spell/skill to remove'] msg = [] if args['spell'][0].lower() == 'all': del self.spellups['sorder'] del self.spellups['self'] self.initspellups() msg.append('All spellups to be cast on self cleared') else: for spella in args['spell']: spell = self.api('skills.gets')(spella) if not spell: msg.append('%s does not exist' % spella) continue spellnum = spell['sn'] if spellnum in self.spellups['sorder']: self.spellups['sorder'].remove(spellnum) if spellnum in self.spellups['self']: del self.spellups['self'][spellnum] msg.append('Removed %s from spellups to self' % spell['name']) self.savestate() return True, msg def cmd_en(self, args): """ enable a spellup """ if len(args['spell']) < 1: return True, ['Please supply a spell/skill to enable'] msg = [] if args['spell'][0].lower() == 'all': for i in self.spellups['self']: self.spellups['self'][i]['enabled'] = True msg.append('All spellups enabled') self.nextspell() return True, msg for spellnum in args['spell']: skill = self.api('skills.gets')(spellnum) if skill: if skill['sn'] in self.spellups['sorder']: self.spellups['self'][skill['sn']]['enabled'] = True msg.append('%s: enabled' % skill['name']) else: msg.append('%s: not in self spellup list' % skill['name']) else: msg.append('%s: could not find spell' % spellnum) self.nextspell() return True, msg def cmd_dis(self, args): """ enable a spellup """ if len(args['spell']) < 1: return True, ['Please supply a spell/skill to enable'] msg = [] if args['spell'][0].lower() == 'all': for i in self.spellups['self']: self.spellups['self'][i]['enabled'] = False msg.append('All spellups disabled') return True, msg for spellnum in args['spell']: skill = self.api('skills.gets')(spellnum) if skill: if skill['sn'] in self.spellups['sorder']: self.spellups['self'][skill['sn']]['enabled'] = False msg.append('%s: disabled' % skill['name']) else: msg.append('%s: not in self spellup list' % skill['name']) else: msg.append('%s: could not find spell' % spellnum) return True, msg def cmd_check(self, _=None): """ list all items that are need for spellups and whether they are known """ tmsg = [] tformat = '%-25s : %-10s - %s' tmsg.append(tformat % \ ('enabled', self.api('setting.gets')('enabled'), 'should be True to cast spells')) tmsg.append(tformat % \ ('waiting', self.api('setting.gets')('waiting'), 'the spell that was last cast, should be -1 to cast spells')) tmsg.append(tformat % \ ('nocast', self.api('setting.gets')('nocast'), 'the current room is nocast, should be False to cast spells')) tmsg.append(tformat % \ ('nomoves', self.api('setting.gets')('nomoves'), 'ran out of moves, should be False to cast spells')) tmsg.append(tformat % \ ('nomana', self.api('setting.gets')('nomana'), 'ran out of mana, should be False to cast spells')) tmsg.append(tformat % \ ('Skills are up to date', self.api('skills.isuptodate')(), 'should be True to cast spells')) tmsg.append(tformat % \ ('Char state', self.api('GMCP.getv')('char.status.state'), 'should be 3 to cast spells')) return True, tmsg def reset(self): """ reset all spellups """ AardwolfBasePlugin.reset(self) self.spellups.clear() self.initspellups() self.spellups.sync()
class Plugin(BasePlugin): """ a class to manage internal commands """ def __init__(self, *args, **kwargs): """ init the class """ BasePlugin.__init__(self, *args, **kwargs) self.canreload = False self.cmds = {} self.nomultiplecmds = {} self.savehistfile = os.path.join(self.savedir, 'history.txt') self.cmdhistorydict = PersistentDict(self.savehistfile, 'c') if 'history' not in self.cmdhistorydict: self.cmdhistorydict['history'] = [] self.cmdhistory = self.cmdhistorydict['history'] self.api.get('api.add')('add', self.api_addcmd) self.api.get('api.add')('remove', self.api_removecmd) self.api.get('api.add')('change', self.api_changecmd) self.api.get('api.add')('default', self.api_setdefault) self.api.get('api.add')('removeplugin', self.api_removeplugin) self.api.get('api.add')('list', self.api_listcmds) self.api.get('api.add')('run', self.api_run) self.api.get('api.add')('cmdhelp', self.api_cmdhelp) def load(self): """ load external stuff """ BasePlugin.load(self) self.api.get('log.adddtype')(self.sname) #self.api.get('log.console')(self.sname) self.api.get('setting.add')('spamcount', 20, int, 'the # of times a command can ' \ 'be run before an antispam command') self.api.get('setting.add')('antispamcommand', 'look', str, 'the antispam command to send') self.api.get('setting.add')('cmdcount', 0, int, 'the # of times the current command has been run', readonly=True) self.api.get('setting.add')('lastcmd', '', str, 'the last command that was sent to the mud', readonly=True) self.api.get('setting.add')('historysize', 50, int, 'the size of the history to keep') parser = argparse.ArgumentParser(add_help=False, description='list commands in a category') parser.add_argument('category', help='the category to see help for', default='', nargs='?') parser.add_argument('cmd', help='the command in the category (can be left out)', default='', nargs='?') self.api.get('commands.add')('list', self.cmd_list, shelp='list commands', parser=parser, history=False) parser = argparse.ArgumentParser(add_help=False, description='list the command history') parser.add_argument('-c', "--clear", help="clear the history", action='store_true') self.api.get('commands.add')('history', self.cmd_history, shelp='list or run a command in history', parser=parser, history=False) parser = argparse.ArgumentParser(add_help=False, description='run a command in history') parser.add_argument('number', help='the history # to run', default=-1, nargs='?', type=int) self.api.get('commands.add')('!', self.cmd_runhistory, shelp='run a command in history', parser=parser, preamble=False, format=False, history=False) self.api.get('events.register')('from_client_event', self.chkcmd, prio=5) self.api.get('events.register')('plugin_unloaded', self.pluginunloaded) self.api.get('events.eraise')('plugin_cmdman_loaded', {}) def pluginunloaded(self, args): """ a plugin was unloaded """ self.api('send.msg')('removing commands for plugin %s' % args['name'], secondary=args['name']) self.api('%s.removeplugin' % self.sname)(args['name']) def formatretmsg(self, msg, sname, cmd): """ format a return message """ linelen = self.api('plugins.getp')('proxy').api('setting.gets')('linelen') msg.insert(0, '') msg.insert(1, '#bp.%s.%s' % (sname, cmd)) msg.insert(2, '@G' + '-' * linelen + '@w') msg.append('@G' + '-' * linelen + '@w') msg.append('') return msg # change an attribute for a command def api_changecmd(self, plugin, command, flag, value): """ change an attribute for a command """ if command not in self.cmds[plugin]: self.api('send.error')('command %s does not exist in plugin %s' % \ (command, plugin)) return False if flag not in self.cmds[plugin][command]: self.api('send.error')( 'flag %s does not exist in command %s in plugin %s' % \ (flag, command, plugin)) return False self.cmds[plugin][command][flag] = value return True # return the help for a command def api_cmdhelp(self, plugin, cmd): """ get the help for a command """ if plugin in self.cmds and cmd in self.cmds[plugin]: return self.cmds[plugin][cmd]['parser'].format_help() else: return '' # return a formatted list of commands for a plugin def api_listcmds(self, plugin, cformat=True): """ list commands for a plugin """ if cformat: return self.listcmds(plugin) else: if plugin in self.cmds: return self.cmds[plugin] else: return {} # run a command and return the output def api_run(self, plugin, cmdname, argstring): """ run a command and return the output """ if plugin in self.cmds and cmdname in self.cmds[plugin]: cmd = self.cmds[plugin][cmdname] args, dummy = cmd['parser'].parse_known_args(argstring) args = vars(args) if args['help']: return cmd['parser'].format_help().split('\n') else: return cmd['func'](args) def runcmd(self, cmd, targs, fullargs, data): """ run a command that has an ArgParser """ retval = False args, dummy = cmd['parser'].parse_known_args(targs) args = vars(args) args['fullargs'] = fullargs if args['help']: msg = cmd['parser'].format_help().split('\n') self.api.get('send.client')('\n'.join( self.formatretmsg(msg, cmd['sname'], cmd['commandname']))) else: args['data'] = data retvalue = cmd['func'](args) if isinstance(retvalue, tuple): retval = retvalue[0] msg = retvalue[1] else: retval = retvalue msg = [] if retval is False: msg.append('') msg.extend(cmd['parser'].format_help().split('\n')) self.api.get('send.client')('\n'.join( self.formatretmsg(msg, cmd['sname'], cmd['commandname']))) else: self.addtohistory(data, cmd) if (not cmd['format']) and msg: self.api.get('send.client')(msg, preamble=cmd['preamble']) elif msg: self.api.get('send.client')('\n'.join( self.formatretmsg(msg, cmd['sname'], cmd['commandname'])), preamble=cmd['preamble']) return retval def addtohistory(self, data, cmd=None): """ add to the command history """ if 'history' in data and not data['history']: return if cmd and not cmd['history']: return tdat = data['fromdata'] if data['fromclient']: if tdat in self.cmdhistory: self.cmdhistory.remove(tdat) self.cmdhistory.append(tdat) if len(self.cmdhistory) >= self.api('setting.gets')('historysize'): self.cmdhistory.pop(0) self.cmdhistorydict.sync() def chkcmd(self, data): # pylint: disable=too-many-nested-blocks,too-many-return-statements,too-many-branches # pylint: disable=too-many-statements """ check a line from a client for a command """ tdat = data['fromdata'] if tdat == '': return if tdat[0:3].lower() == '#bp': targs = shlex.split(tdat.strip()) try: tmpind = tdat.index(' ') fullargs = tdat[tmpind+1:] except ValueError: fullargs = '' cmd = targs.pop(0) cmdsplit = cmd.split('.') sname = '' if len(cmdsplit) >= 2: sname = cmdsplit[1].strip() scmd = '' if len(cmdsplit) >= 3: scmd = cmdsplit[2].strip() if 'help' in targs: try: del targs[targs.index('help')] except ValueError: pass cmd = self.cmds[self.sname]['list'] self.runcmd(cmd, [sname, scmd], fullargs, data) elif sname: if sname not in self.cmds: self.api.get('send.client')("@R%s.%s@W is not a command." % \ (sname, scmd)) else: if scmd: cmd = None if scmd in self.cmds[sname]: cmd = self.cmds[sname][scmd] if cmd: try: self.runcmd(cmd, targs, fullargs, data) except Exception: # pylint: disable=broad-except self.api.get('send.traceback')( 'Error when calling command %s.%s' % (sname, scmd)) return {'fromdata':''} else: self.api.get('send.client')("@R%s.%s@W is not a command" % \ (sname, scmd)) else: if 'default' in self.cmds[sname]: cmd = self.cmds[sname]['default'] try: self.runcmd(cmd, targs, fullargs, data) except Exception: # pylint: disable=broad-except self.api.get('send.traceback')( 'Error when calling command %s.%s' % (sname, scmd)) return {'fromdata':''} else: cmd = self.cmds[self.sname]['list'] try: self.runcmd(cmd, [sname, scmd], '', data) except Exception: # pylint: disable=broad-except self.api.get('send.traceback')( 'Error when calling command %s.%s' % (sname, scmd)) return {'fromdata':''} else: try: del targs[targs.index('help')] except ValueError: pass cmd = self.cmds[self.sname]['list'] try: self.runcmd(cmd, [sname, scmd], '', data) except Exception: # pylint: disable=broad-except self.api.get('send.traceback')( 'Error when calling command %s.%s' % (sname, scmd)) return {'fromdata':''} return {'fromdata':''} else: self.addtohistory(data) if tdat.strip() == self.api.get('setting.gets')('lastcmd'): self.api.get('setting.change')('cmdcount', self.api.get('setting.gets')('cmdcount') + 1) if self.api.get('setting.gets')('cmdcount') == \ self.api.get('setting.gets')('spamcount'): data['fromdata'] = self.api.get('setting.gets')('antispamcommand') \ + '|' + tdat self.api.get('send.msg')('adding look for 20 commands') self.api.get('setting.change')('cmdcount', 0) if tdat in self.nomultiplecmds: data['fromdata'] = '' else: self.api.get('setting.change')('cmdcount', 0) self.api.get('send.msg')('resetting command to %s' % tdat.strip()) self.api.get('setting.change')('lastcmd', tdat.strip()) return data # add a command def api_addcmd(self, cmdname, func, **kwargs): # pylint: disable=too-many-branches """ add a command @Ycmdname@w = the base that the api should be under @Yfunc@w = the function that should be run when this command is executed @Ykeyword arguments@w @Yshelp@w = the short help, a brief description of what the command does @Ylhelp@w = a longer description of what the command does @Ypreamble@w = show the preamble for this command (default: True) @Yformat@w = format this command (default: True) @Ygroup@w = the group this command is in The command will be added as sname.cmdname sname is gotten from the class the function belongs to or the sname key in args this function returns no values""" args = kwargs.copy() lname = None if not func: self.api.get('send.msg')('cmd %s has no function, not adding' % \ (cmdname)) return try: sname = func.im_self.sname except AttributeError: if 'sname' in args: sname = args['sname'] else: self.api.get('send.msg')('Function is not part of a plugin class: %s' \ % cmdname) return if 'parser' in args: tparser = args['parser'] tparser.formatter_class = CustomFormatter else: self.api.get('send.msg')('adding default parser to command %s.%s' % \ (sname, cmdname)) if 'shelp' not in args: args['shelp'] = 'there is no help for this command' tparser = argparse.ArgumentParser(add_help=False, description=args['shelp']) args['parser'] = tparser tparser.add_argument("-h", "--help", help="show help", action="store_true") tparser.prog = '@B#bp.%s.%s@w' % (sname, cmdname) if 'group' not in args: args['group'] = sname try: lname = func.im_self.name args['lname'] = lname except AttributeError: pass if 'lname' not in args: self.api.get('send.msg')('cmd %s.%s has no long name, not adding' % \ (sname, cmdname), secondary=sname) return self.api.get('send.msg')('added cmd %s.%s' % \ (sname, cmdname), secondary=sname) if sname not in self.cmds: self.cmds[sname] = {} args['func'] = func args['sname'] = sname args['lname'] = lname args['commandname'] = cmdname if 'preamble' not in args: args['preamble'] = True if 'format' not in args: args['format'] = True if 'history' not in args: args['history'] = True self.cmds[sname][cmdname] = args # remove a command def api_removecmd(self, sname, cmdname): """ remove a command @Ysname@w = the top level of the command @Ycmdname@w = the name of the command this function returns no values""" if sname in self.cmds and cmdname in self.cmds[sname]: del self.cmds[sname][cmdname] else: self.api.get('send.msg')('remove cmd: cmd %s.%s does not exist' % \ (sname, cmdname), secondary=sname) self.api.get('send.msg')('removed cmd %s.%s' % \ (sname, cmdname), secondary=sname) # set the default command for a plugin def api_setdefault(self, cmd, plugin=None): """ set the default command for a plugin @Ysname@w = the plugin of the command @Ycmdname@w = the name of the command this function returns True if the command exists, False if it doesn't""" if not plugin: plugin = self.api('utils.funccallerplugin')() if not plugin: print 'could not add a default cmd', cmd return False if plugin in self.cmds and cmd in self.cmds[plugin]: self.api('send.msg')('added default command %s for plugin %s' % (cmd, plugin), secondary=plugin) self.cmds[plugin]['default'] = self.cmds[plugin][cmd] return True return False # remove all commands for a plugin def api_removeplugin(self, plugin): """ remove all commands for a plugin @Ysname@w = the plugin to remove commands for this function returns no values""" if plugin in self.cmds: del self.cmds[plugin] else: self.api.get('send.msg')('removeplugin: plugin %s does not exist' % \ plugin) def format_cmdlist(self, category, cmdlist): """ format a list of commands """ tmsg = [] for i in cmdlist: if i != 'default': tlist = self.cmds[category][i]['parser'].description.split('\n') if not tlist[0]: tlist.pop(0) tmsg.append(' @B%-10s@w : %s' % (i, tlist[0])) return tmsg def listcmds(self, category): """ build a table of commands for a category """ tmsg = [] if category: if category in self.cmds: tmsg.append('Commands in %s:' % category) tmsg.append('@G' + '-' * 60 + '@w') groups = {} for i in sorted(self.cmds[category].keys()): if i != 'default': if self.cmds[category][i]['group'] not in groups: groups[self.cmds[category][i]['group']] = [] groups[self.cmds[category][i]['group']].append(i) if len(groups) == 1: tmsg.extend(self.format_cmdlist(category, self.cmds[category].keys())) else: for group in sorted(groups.keys()): if group != 'Base': tmsg.append('@M' + '-' * 5 + ' ' + group + ' ' + '-' * 5) tmsg.extend(self.format_cmdlist(category, groups[group])) tmsg.append('') tmsg.append('@M' + '-' * 5 + ' ' + 'Base' + ' ' + '-' * 5) tmsg.extend(self.format_cmdlist(category, groups['Base'])) #tmsg.append('@G' + '-' * 60 + '@w') return tmsg def cmd_list(self, args): """ list commands """ tmsg = [] category = args['category'] cmd = args['cmd'] if category: if category in self.cmds: if cmd and cmd in self.cmds[category]: msg = self.cmds[category][cmd]['parser'].format_help().split('\n') tmsg.extend(msg) else: tmsg.extend(self.listcmds(category)) else: tmsg.append('There is no category %s' % category) else: tmsg.append('Categories:') tkeys = self.cmds.keys() tkeys.sort() for i in tkeys: tmsg.append(' %s' % i) return True, tmsg def cmd_runhistory(self, args): """ act on the command history """ if len(self.cmdhistory) < abs(args['number']): return True, ['# is outside of history length'] if len(self.cmdhistory) >= self.api('setting.gets')('historysize'): cmd = self.cmdhistory[args['number'] - 1] else: cmd = self.cmdhistory[args['number']] self.api('send.client')('history: sending "%s"' % cmd) self.api('send.execute')(cmd) return True, [] def cmd_history(self, args): """ act on the command history """ tmsg = [] if args['clear']: del self.cmdhistorydict['history'][:] self.cmdhistorydict.sync() tmsg.append('Command history cleared') else: for i in self.cmdhistory: tmsg.append('%s : %s' % (self.cmdhistory.index(i), i)) return True, tmsg def savestate(self): """ save states """ BasePlugin.savestate(self) self.cmdhistorydict.sync()
class Plugin(BasePlugin): """ a plugin to do simple substitution """ def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.savesubfile = os.path.join(self.savedir, 'subs.txt') self._substitutes = PersistentDict(self.savesubfile, 'c') def load(self): """ load the plugins """ BasePlugin.load(self) parser = argp.ArgumentParser(add_help=False, description='add a simple substitute') parser.add_argument('original', help='the output to substitute', default='', nargs='?') parser.add_argument('replacement', help='the string to replace it with', default='', nargs='?') self.api('commands.add')('add', self.cmd_add, parser=parser) parser = argp.ArgumentParser(add_help=False, description='remove a substitute') parser.add_argument('substitute', help='the substitute to remove', default='', nargs='?') self.api('commands.add')('remove', self.cmd_remove, parser=parser) parser = argp.ArgumentParser(add_help=False, description='list substitutes') parser.add_argument( 'match', help='list only substitutes that have this argument in them', default='', nargs='?') self.api('commands.add')('list', self.cmd_list, parser=parser) parser = argp.ArgumentParser(add_help=False, description='clear all substitutes') self.api('commands.add')('clear', self.cmd_clear, parser=parser) self.api('commands.default')('list') self.api('events.register')('from_mud_event', self.findsub) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) def findsub(self, args): """ this function finds subs in mud data """ data = args['original'] dtype = args['dtype'] if dtype != 'fromproxy': for mem in self._substitutes.keys(): if mem in data: ndata = data.replace( mem, self.api('colors.convertcolors')( self._substitutes[mem]['sub'])) if ndata != data: args['trace']['changes'].append({'flag':'Modify', 'data':'changed "%s" to "%s"' % \ (data, ndata), 'plugin':self.sname, 'eventname':args['eventname']}) data = ndata args['original'] = data return args def cmd_add(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Add a substitute @CUsage@w: add @Y<originalstring>@w @M<replacementstring>@w @Yoriginalstring@w = The original string to be replaced @Mreplacementstring@w = The new string """ tmsg = [] if args['original'] and args['replacement']: tmsg.append("@GAdding substitute@w : '%s' will be replaced by '%s'" % \ (args['original'], args['replacement'])) self.addsub(args['original'], args['replacement']) return True, tmsg tmsg.append("@RPlease specify all arguments@w") return False, tmsg def cmd_remove(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Remove a substitute @CUsage@w: rem @Y<originalstring>@w @Yoriginalstring@w = The original string """ tmsg = [] if args['substitute']: tmsg.append("@GRemoving substitute@w : '%s'" % (args['substitute'])) self.removesub(args['substitute']) return True, tmsg return False, tmsg def cmd_list(self, args): """ @G%(name)s@w - @B%(cmdname)s@w List substitutes @CUsage@w: list """ tmsg = self.listsubs(args['match']) return True, tmsg def cmd_clear(self, args): # pylint: disable=unused-argument """ @G%(name)s@w - @B%(cmdname)s@w List substitutes @CUsage@w: list""" self.clearsubs() return True, ['Substitutes cleared'] def addsub(self, item, sub): """ internally add a substitute """ self._substitutes[item] = {'sub': sub} self._substitutes.sync() def removesub(self, item): """ internally remove a substitute """ if item in self._substitutes: del self._substitutes[item] self._substitutes.sync() def listsubs(self, match): """ return a table of strings that list subs """ tmsg = [] for item in self._substitutes: if not match or match in item: tmsg.append("%-35s : %s@w" % (item, self._substitutes[item]['sub'])) if not tmsg: tmsg = ['None'] return tmsg def clearsubs(self): """ clear all subs """ self._substitutes.clear() self._substitutes.sync() def reset(self): """ reset the plugin """ BasePlugin.reset(self) self.clearsubs() def _savestate(self, _=None): """ save states """ self._substitutes.sync()
class Plugin(BasePlugin): """ a plugin to handle user aliases """ def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.aliasfile = os.path.join(self.savedir, 'aliases.txt') self._aliases = PersistentDict(self.aliasfile, 'c') self.sessionhits = {} def load(self): """ load the plugin """ BasePlugin.load(self) self.api('setting.add')('nextnum', 0, int, 'the number of the next alias added', readonly=True) parser = argp.ArgumentParser(add_help=False, description='add an alias') parser.add_argument('original', help='the input to replace', default='', nargs='?') parser.add_argument('replacement', help='the string to replace it with', default='', nargs='?') parser.add_argument('-o', "--overwrite", help="overwrite an alias if it already exists", action="store_true") parser.add_argument('-d', "--disable", help="disable the alias", action="store_true") parser.add_argument('-g', "--group", help="the alias group", default="") self.api('commands.add')('add', self.cmd_add, parser=parser) parser = argp.ArgumentParser(add_help=False, description='remove an alias') parser.add_argument('alias', help='the alias to remove', default='', nargs='?') self.api('commands.add')('remove', self.cmd_remove, parser=parser) parser = argp.ArgumentParser(add_help=False, description='list aliases') parser.add_argument( 'match', help='list only aliases that have this argument in them', default='', nargs='?') self.api('commands.add')('list', self.cmd_list, parser=parser) parser = argp.ArgumentParser(add_help=False, description='toggle enabled flag') parser.add_argument('alias', help='the alias to toggle', default='', nargs='?') self.api('commands.add')('toggle', self.cmd_toggle, parser=parser) parser = argp.ArgumentParser( add_help=False, description='toggle all aliases in a group') parser.add_argument('group', help='the group to toggle', default='', nargs='?') parser.add_argument('-d', "--disable", help="disable the group", action="store_true") self.api('commands.add')('groupt', self.cmd_grouptoggle, parser=parser) parser = argp.ArgumentParser(add_help=False, description='get detail for an alias') parser.add_argument('alias', help='the alias to get details for', default='', nargs='?') self.api('commands.add')('detail', self.cmd_detail, parser=parser) self.api('commands.default')('list') self.api('events.register')('io_execute_event', self.checkalias, prio=2) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) def checkalias(self, args): # pylint: disable=too-many-branches """ this function finds aliases in client input """ data = args['fromdata'].strip() if not data: return args for mem in self._aliases.keys(): if self._aliases[mem]['enabled']: datan = data matchd = re.match(mem, data) if matchd: self.api('send.msg')('matched input on %s' % mem) tlistn = [data] for i in xrange(1, len(matchd.groups()) + 1): tlistn.append(matchd.group(i)) self.api('send.msg')('args: %s' % tlistn) try: datan = self._aliases[mem]['alias'].format(*tlistn) except Exception: # pylint: disable=broad-except self.api('send.traceback')('alias %s had an issue' % (mem)) else: cre = re.compile('^%s' % mem) datan = cre.sub(self._aliases[mem]['alias'], data) if datan != data: if 'trace' in args: args['trace']['changes'].append({'flag':'Modify', 'data':'changed "%s" to "%s"' % \ (data, datan), 'plugin':self.sname}) if not 'hits' in self._aliases[mem]: self._aliases[mem]['hits'] = 0 if not mem in self.sessionhits: self.sessionhits[mem] = 0 self.api('send.msg')('incrementing hits for %s' % mem) self._aliases[mem]['hits'] = self._aliases[mem]['hits'] + 1 self.sessionhits[mem] = self.sessionhits[mem] + 1 self.api('send.msg')('replacing "%s" with "%s"' % \ (data.strip(), datan.strip())) if datan[0:3] == '#bp': self.api('send.execute')(datan, showinhistory=False, fromclient=False) args['fromdata'] = '' args['history'] = False else: args['history'] = False args['fromclient'] = False args['fromdata'] = datan return args def lookup_alias(self, alias): """ lookup an alias by number or name """ nitem = None try: num = int(alias) nitem = None for titem in self._aliases.keys(): if num == self._aliases[titem]['num']: nitem = titem break except ValueError: if alias in self._aliases: nitem = alias return nitem def cmd_add(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Add a alias @CUsage@w: add @Y<originalstring>@w @M<replacementstring>@w @Yoriginalstring@w = The original string to be replaced @Mreplacementstring@w = The new string """ tmsg = [] if args['original'] and args['replacement']: if args['original'] in self._aliases and not args['overwrite']: return True, ['Alias: %s already exists.' % args['original']] else: tmsg.append("@GAdding alias@w : '%s' will be replaced by '%s'" % \ (args['original'], args['replacement'])) self.addalias(args['original'], args['replacement'], args['disable'], args['group']) return True, tmsg else: return False, ['@RPlease include all arguments@w'] def cmd_remove(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Remove a alias @CUsage@w: rem @Y<originalstring>@w @Yoriginalstring@w = The original string """ tmsg = [] if args['alias']: retval = self.removealias(args['alias']) if retval: tmsg.append("@GRemoving alias@w : '%s'" % (retval)) else: tmsg.append("@GCould not remove alias@w : '%s'" % (args['alias'])) return True, tmsg else: return False, ['@RPlease include an alias to remove@w'] def cmd_toggle(self, args): """ toggle the enabled flag """ tmsg = [] if args['alias']: retval = self.togglealias(args['alias']) if retval: if self._aliases[retval]['enabled']: tmsg.append("@GEnabled alias@w : '%s'" % (retval)) else: tmsg.append("@GDisabled alias@w : '%s'" % (retval)) else: tmsg.append("@GDoes not exist@w : '%s'" % (args['alias'])) return True, tmsg else: return False, ['@RPlease include an alias to toggle@w'] def cmd_detail(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Add a alias @CUsage@w: add @Y<originalstring>@w @M<replacementstring>@w @Yoriginalstring@w = The original string to be replaced @Mreplacementstring@w = The new string """ tmsg = [] if args['alias']: alias = self.lookup_alias(args['alias']) if alias: if 'hits' not in self._aliases[alias]: self._aliases[alias]['hits'] = 0 if alias not in self.sessionhits: self.sessionhits[alias] = 0 tmsg.append('%-12s : %d' % ('Num', self._aliases[alias]['num'])) tmsg.append('%-12s : %s' % \ ('Enabled', 'Y' if self._aliases[alias]['enabled'] else 'N')) tmsg.append('%-12s : %d' % ('Total Hits', self._aliases[alias]['hits'])) tmsg.append('%-12s : %d' % ('Session Hits', self.sessionhits[alias])) tmsg.append('%-12s : %s' % ('Alias', alias)) tmsg.append('%-12s : %s' % ('Replacement', self._aliases[alias]['alias'])) tmsg.append('%-12s : %s' % ('Group', self._aliases[alias]['group'])) else: return True, [ '@RAlias does not exits@w : \'%s\'' % (args['alias']) ] return True, tmsg else: return False, ['@RPlease include all arguments@w'] def cmd_list(self, args): """ @G%(name)s@w - @B%(cmdname)s@w List aliases @CUsage@w: list """ tmsg = self.listaliases(args['match']) return True, tmsg def cmd_grouptoggle(self, args): """ toggle all aliases in a group """ tmsg = [] togglea = [] state = not args['disable'] if args['group']: for i in self._aliases: if 'group' not in self._aliases[i]: self._aliases[i]['group'] = '' if self._aliases[i]['group'] == args['group']: self._aliases[i]['enabled'] = state togglea.append('%s' % self._aliases[i]['num']) if togglea: tmsg.append('The following aliases were %s: %s' % \ ('enabled' if state else 'disabled', ','.join(togglea))) else: tmsg.append('No aliases were modified') return True, tmsg else: return False, ['@RPlease include a group to toggle@w'] def addalias(self, item, alias, disabled, group): """ internally add a alias """ num = self.api('setting.gets')('nextnum') self._aliases[item] = { 'alias': alias, 'enabled': not disabled, 'num': num, 'group': group } self._aliases.sync() self.api('setting.change')('nextnum', num + 1) def removealias(self, item): """ internally remove a alias """ alias = self.lookup_alias(item) if alias: del self._aliases[alias] self._aliases.sync() return alias def togglealias(self, item): """ toggle an alias """ alias = self.lookup_alias(item) if alias: self._aliases[alias][ 'enabled'] = not self._aliases[alias]['enabled'] return alias def listaliases(self, match): """ return a table of strings that list aliases """ tmsg = [] for alias in sorted(self._aliases.iteritems(), key=lambda (x, y): y['num']): item = alias[0] if not match or match in item: lalias = self.api('colors.stripansi')( self._aliases[item]['alias']) if len(lalias) > 30: lalias = lalias[:27] + '...' tmsg.append("%4s %2s %-10s %-20s : %s@w" % \ (self._aliases[item]['num'], 'Y' if self._aliases[item]['enabled'] else 'N', self._aliases[item]['group'], item, lalias)) if not tmsg: tmsg = ['None'] else: tmsg.insert( 0, "%4s %2s %-10s %-20s : %s@w" % ('#', 'E', 'Group', 'Alias', 'Replacement')) tmsg.insert(1, '@B' + '-' * 60 + '@w') return tmsg def clearaliases(self): """ clear all aliases """ self._aliases.clear() self._aliases.sync() def reset(self): """ reset the plugin """ BasePlugin.reset(self) self.clearaliases() def _savestate(self, _=None): """ save states """ self._aliases.sync()
class Plugin(BasePlugin): """ a plugin to handle user aliases """ def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.aliasfile = os.path.join(self.savedir, 'aliases.txt') self._aliases = PersistentDict(self.aliasfile, 'c') self.sessionhits = {} def load(self): """ load the plugin """ BasePlugin.load(self) self.api.get('setting.add')('nextnum', 0, int, 'the number of the next alias added', readonly=True) parser = argparse.ArgumentParser(add_help=False, description='add an alias') parser.add_argument('original', help='the input to replace', default='', nargs='?') parser.add_argument('replacement', help='the string to replace it with', default='', nargs='?') parser.add_argument('-o', "--overwrite", help="overwrite an alias if it already exists", action="store_true") parser.add_argument('-d', "--disable", help="disable the alias", action="store_true") parser.add_argument('-g', "--group", help="the alias group", default="") self.api.get('commands.add')('add', self.cmd_add, parser=parser) parser = argparse.ArgumentParser(add_help=False, description='remove an alias') parser.add_argument('alias', help='the alias to remove', default='', nargs='?') self.api.get('commands.add')('remove', self.cmd_remove, parser=parser) parser = argparse.ArgumentParser(add_help=False, description='list aliases') parser.add_argument('match', help='list only aliases that have this argument in them', default='', nargs='?') self.api.get('commands.add')('list', self.cmd_list, parser=parser) parser = argparse.ArgumentParser(add_help=False, description='toggle enabled flag') parser.add_argument('alias', help='the alias to toggle', default='', nargs='?') self.api.get('commands.add')('toggle', self.cmd_toggle, parser=parser) parser = argparse.ArgumentParser(add_help=False, description='toggle all aliases in a group') parser.add_argument('group', help='the group to toggle', default='', nargs='?') parser.add_argument('-d', "--disable", help="disable the group", action="store_true") self.api.get('commands.add')('groupt', self.cmd_grouptoggle, parser=parser) parser = argparse.ArgumentParser(add_help=False, description='get detail for an alias') parser.add_argument('alias', help='the alias to get details for', default='', nargs='?') self.api.get('commands.add')('detail', self.cmd_detail, parser=parser) self.api.get('commands.default')('list') self.api.get('events.register')('from_client_event', self.checkalias, prio=2) def checkalias(self, args): """ this function finds aliases in client input """ data = args['fromdata'].strip() if not data: return args for mem in self._aliases.keys(): if self._aliases[mem]['enabled']: datan = data matchd = re.match(mem, data) if matchd: self.api.get('send.msg')('matched input on %s' % mem) tlistn = [data] for i in xrange(1, len(matchd.groups()) + 1): tlistn.append(matchd.group(i)) self.api.get('send.msg')('args: %s' % tlistn) try: datan = self._aliases[mem]['alias'].format(*tlistn) except Exception: # pylint: disable=broad-except self.api.get('send.traceback')('alias %s had an issue' % (mem)) else: cre = re.compile('^%s' % mem) datan = cre.sub(self._aliases[mem]['alias'], data) if datan != data: if not 'hits' in self._aliases[mem]: self._aliases[mem]['hits'] = 0 if not mem in self.sessionhits: self.sessionhits[mem] = 0 self.api.get('send.msg')('incrementing hits for %s' % mem) self._aliases[mem]['hits'] = self._aliases[mem]['hits'] + 1 self.sessionhits[mem] = self.sessionhits[mem] + 1 self.api.get('send.msg')('replacing "%s" with "%s"' % \ (data.strip(), datan.strip())) if datan[0:3] == '#bp': self.api.get('send.execute')(datan, history=False, fromclient=False) args['fromdata'] = '' args['history'] = False else: args['history'] = False args['fromclient'] = False args['fromdata'] = datan return args def lookup_alias(self, alias): """ lookup an alias by number or name """ nitem = None try: num = int(alias) nitem = None for titem in self._aliases.keys(): if num == self._aliases[titem]['num']: nitem = titem break except ValueError: if alias in self._aliases: nitem = alias return nitem def cmd_add(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Add a alias @CUsage@w: add @Y<originalstring>@w @M<replacementstring>@w @Yoriginalstring@w = The original string to be replaced @Mreplacementstring@w = The new string """ tmsg = [] if args['original'] and args['replacement']: if args['original'] in self._aliases and not args['overwrite']: return True, ['Alias: %s already exists.' % args['original']] else: tmsg.append("@GAdding alias@w : '%s' will be replaced by '%s'" % \ (args['original'], args['replacement'])) self.addalias(args['original'], args['replacement'], args['disable'], args['group']) return True, tmsg else: return False, ['@RPlease include all arguments@w'] def cmd_remove(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Remove a alias @CUsage@w: rem @Y<originalstring>@w @Yoriginalstring@w = The original string """ tmsg = [] if args['alias']: retval = self.removealias(args['alias']) if retval: tmsg.append("@GRemoving alias@w : '%s'" % (retval)) else: tmsg.append("@GCould not remove alias@w : '%s'" % (args['alias'])) return True, tmsg else: return False, ['@RPlease include an alias to remove@w'] def cmd_toggle(self, args): """ toggle the enabled flag """ tmsg = [] if args['alias']: retval = self.togglealias(args['alias']) if retval: if self._aliases[retval]['enabled']: tmsg.append("@GEnabled alias@w : '%s'" % (retval)) else: tmsg.append("@GDisabled alias@w : '%s'" % (retval)) else: tmsg.append("@GDoes not exist@w : '%s'" % (args['alias'])) return True, tmsg else: return False, ['@RPlease include an alias to toggle@w'] def cmd_detail(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Add a alias @CUsage@w: add @Y<originalstring>@w @M<replacementstring>@w @Yoriginalstring@w = The original string to be replaced @Mreplacementstring@w = The new string """ tmsg = [] if args['alias']: alias = self.lookup_alias(args['alias']) if alias: if 'hits' not in self._aliases[alias]: self._aliases[alias]['hits'] = 0 if alias not in self.sessionhits: self.sessionhits[alias] = 0 tmsg.append('%-12s : %d' % ('Num', self._aliases[alias]['num'])) tmsg.append('%-12s : %s' % \ ('Enabled', 'Y' if self._aliases[alias]['enabled'] else 'N')) tmsg.append('%-12s : %d' % ('Total Hits', self._aliases[alias]['hits'])) tmsg.append('%-12s : %d' % ('Session Hits', self.sessionhits[alias])) tmsg.append('%-12s : %s' % ('Alias', alias)) tmsg.append('%-12s : %s' % ('Replacement', self._aliases[alias]['alias'])) tmsg.append('%-12s : %s' % ('Group', self._aliases[alias]['group'])) else: return True, ['@RAlias does not exits@w : \'%s\'' % (args['alias'])] return True, tmsg else: return False, ['@RPlease include all arguments@w'] def cmd_list(self, args): """ @G%(name)s@w - @B%(cmdname)s@w List aliases @CUsage@w: list """ tmsg = self.listaliases(args['match']) return True, tmsg def cmd_grouptoggle(self, args): """ toggle all aliases in a group """ tmsg = [] togglea = [] state = not args['disable'] if args['group']: for i in self._aliases: if 'group' not in self._aliases[i]: self._aliases[i]['group'] = '' if self._aliases[i]['group'] == args['group']: self._aliases[i]['enabled'] = state togglea.append('%s' % self._aliases[i]['num']) if togglea: tmsg.append('The following aliases were %s: %s' % \ ('enabled' if state else 'disabled', ','.join(togglea))) else: tmsg.append('No aliases were modified') return True, tmsg else: return False, ['@RPlease include a group to toggle@w'] def addalias(self, item, alias, disabled, group): """ internally add a alias """ num = self.api.get('setting.gets')('nextnum') self._aliases[item] = {'alias':alias, 'enabled':not disabled, 'num':num, 'group':group} self._aliases.sync() self.api.get('setting.change')('nextnum', num + 1) def removealias(self, item): """ internally remove a alias """ alias = self.lookup_alias(item) if alias: del self._aliases[alias] self._aliases.sync() return alias def togglealias(self, item): """ toggle an alias """ alias = self.lookup_alias(item) if alias: self._aliases[alias]['enabled'] = not self._aliases[alias]['enabled'] return alias def listaliases(self, match): """ return a table of strings that list aliases """ tmsg = [] for alias in sorted(self._aliases.iteritems(), key=lambda (x, y): y['num']): item = alias[0] if not match or match in item: lalias = self.api.get('colors.stripansi')(self._aliases[item]['alias']) if len(lalias) > 30: lalias = lalias[:27] + '...' tmsg.append("%4s %2s %-10s %-20s : %s@w" % \ (self._aliases[item]['num'], 'Y' if self._aliases[item]['enabled'] else 'N', self._aliases[item]['group'], item, lalias)) if len(tmsg) == 0: tmsg = ['None'] else: tmsg.insert(0, "%4s %2s %-10s %-20s : %s@w" % ('#', 'E', 'Group', 'Alias', 'Replacement')) tmsg.insert(1, '@B' + '-' * 60 + '@w') return tmsg def clearaliases(self): """ clear all aliases """ self._aliases.clear() self._aliases.sync() def reset(self): """ reset the plugin """ BasePlugin.reset(self) self.clearaliases() def savestate(self): """ save states """ BasePlugin.savestate(self) self._aliases.sync()
class Plugin(AardwolfBasePlugin): """ a plugin to handle aardwolf quest events """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savequestfile = os.path.join(self.savedir, 'quest.txt') self.queststuff = PersistentDict(self.savequestfile, 'c') def load(self): """ load the plugins """ AardwolfBasePlugin.load(self) self.api('events.register')('GMCP:comm.quest', self.quest) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) def resetquest(self): """ reset the quest info """ self.queststuff.clear() self.queststuff['finishtime'] = -1 self.queststuff['starttime'] = time.time() self.queststuff['killedtime'] = -1 self.queststuff['mobname'] = '' self.queststuff['mobarea'] = '' self.queststuff['mobroom'] = '' self.queststuff['level'] = self.api('aardu.getactuallevel')( self.api('GMCP.getv')('char.status.level')) self.queststuff['failed'] = 0 def quest(self, args): """ process the quest event """ questi = args['data'] self.api('send.msg')('quest: %s' % questi) if questi['action'] == 'ready': self.api('events.eraise')('aard_quest_ready', {}) elif questi['action'] == 'start': self.resetquest() self.queststuff['mobname'] = questi['targ'] self.queststuff['mobarea'] = questi['area'] self.queststuff['mobroom'] = questi['room'] self.queststuff['stimer'] = questi['timer'] self.api('events.eraise')('aard_quest_start', self.queststuff) elif questi['action'] == 'killed': self.queststuff['killedtime'] = time.time() self.api('events.eraise')('aard_quest_killed', self.queststuff) elif questi['action'] == 'comp': self.queststuff['finishtime'] = time.time() self.queststuff.update(questi) self.api('events.eraise')('aard_quest_comp', copy.deepcopy(self.queststuff)) elif questi['action'] == 'fail' or questi['action'] == 'timeout': self.queststuff['finishtime'] = time.time() self.queststuff['failed'] = 1 self.api('events.eraise')('aard_quest_failed', copy.deepcopy(self.queststuff)) elif questi['action'] == 'status': self.api('events.eraise')('aard_quest_status', questi) elif questi['action'] == 'reset': #reset the timer to 60 seconds #when_required = os.time() + (stuff.timer * 60) #update_timer() self.api('events.eraise')('aard_quest_reset', {}) self.queststuff.sync() def _savestate(self, _=None): """ save states """ self.queststuff.sync()
class Plugin(BasePlugin): """ a plugin for user actions """ def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.canreload = True self.regexlookup = {} self.actiongroups = {} self.compiledregex = {} self.sessionhits = {} self.saveactionsfile = os.path.join(self.savedir, 'actions.txt') self.actions = PersistentDict(self.saveactionsfile, 'c') def load(self): """ load the plugin """ BasePlugin.load(self) self.api('setting.add')('nextnum', 0, int, 'the number of the next action added', readonly=True) parser = argp.ArgumentParser(add_help=False, description='add a action') parser.add_argument('regex', help='the regex to match', default='', nargs='?') parser.add_argument('action', help='the action to take', default='', nargs='?') parser.add_argument('send', help='where to send the action', default='execute', nargs='?', choices=self.api('api.getchildren')('send')) parser.add_argument('-c', "--color", help="match colors (@@colors)", action="store_true") parser.add_argument('-d', "--disable", help="disable the action", action="store_true") parser.add_argument('-g', "--group", help="the action group", default="") parser.add_argument('-o', "--overwrite", help="overwrite an action if it already exists", action="store_true") self.api('commands.add')('add', self.cmd_add, parser=parser) parser = argp.ArgumentParser(add_help=False, description='list actions') parser.add_argument('match', help='list only actions that have this argument in them', default='', nargs='?') self.api('commands.add')('list', self.cmd_list, parser=parser) parser = argp.ArgumentParser(add_help=False, description='remove an action') parser.add_argument('action', help='the action to remove', default='', nargs='?') self.api('commands.add')('remove', self.cmd_remove, parser=parser) parser = argp.ArgumentParser(add_help=False, description='toggle enabled flag') parser.add_argument('action', help='the action to toggle', default='', nargs='?') action = parser.add_mutually_exclusive_group() action.add_argument('-t', '--toggle', action='store_const', dest='togact', const='toggle', default='toggle', help='toggle the action') action.add_argument('-d', '--disable', action='store_const', dest='togact', const='disable', help='disable the action') action.add_argument('-e', '--enable', action='store_const', dest='togact', const='enable', help='enable the action') self.api('commands.add')('toggle', self.cmd_toggle, parser=parser) parser = argp.ArgumentParser(add_help=False, description='get detail for an action') parser.add_argument('action', help='the action to get details for', default='', nargs='?') self.api('commands.add')('detail', self.cmd_detail, parser=parser) parser = argp.ArgumentParser(add_help=False, description='toggle all actions in a group') parser.add_argument('group', help='the group to toggle', default='', nargs='?') action = parser.add_mutually_exclusive_group() action.add_argument('-t', '--toggle', action='store_const', dest='togact', const='toggle', default='toggle', help='toggle the action') action.add_argument('-d', '--disable', action='store_const', dest='togact', const='disable', help='disable the action') action.add_argument('-e', '--enable', action='store_const', dest='togact', const='enable', help='enable the action') self.api('commands.add')('groupt', self.cmd_grouptoggle, parser=parser) for action in self.actions.values(): self.register_action(action) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) def register_action(self, action): """ register an action as a trigger """ if 'triggername' not in action: action['triggername'] = "action_%s" % action['num'] self.api('triggers.add')(action['triggername'], action['regex']) self.api('events.register')('trigger_%s' % action['triggername'], self.action_matched) def unregister_action(self, action): """ unregister an action """ self.api('events.unregister')('trigger_%s' % action['triggername'], self.action_matched) self.api('triggers.remove')(action['triggername']) def action_matched(self, args): """ do something when an action is matched """ actionnum = int(args['triggername'].split('_')[-1]) action = self.lookup_action(actionnum) if action: akey = action['regex'] if akey not in self.sessionhits: self.sessionhits[akey] = 0 self.sessionhits[akey] = self.sessionhits[akey] + 1 action['hits'] = action['hits'] + 1 self.api('send.msg')('matched line: %s to action %s' % (args['line'], akey)) templ = Template(action['action']) newaction = templ.safe_substitute(args) sendtype = 'send.' + action['send'] self.api('send.msg')('sent %s to %s' % (newaction, sendtype)) self.api(sendtype)(newaction) else: self.api('send.error')("Bug: could not find action for trigger %s" % \ args['triggername']) def lookup_action(self, action): """ lookup an action by number or name """ nitem = None try: num = int(action) nitem = None for titem in self.actions.keys(): if num == self.actions[titem]['num']: nitem = self.actions[titem] break except ValueError: if action in self.actions: nitem = action return nitem def cmd_add(self, args): """ add user defined actions """ if not args['regex']: return False, ['Please include a regex'] if not args['action']: return False, ['Please include an action'] if not args['overwrite'] and args['regex'] in self.actions: return True, ['Action: %s already exists.' % args['regex']] else: num = 0 if args['regex'] in self.actions: num = self.actions[args['regex']]['num'] else: num = self.api('setting.gets')('nextnum') self.api('setting.change')('nextnum', num + 1) self.actions[args['regex']] = { 'num':num, 'hits':0, 'regex': args['regex'], 'action':args['action'], 'send':args['send'], 'matchcolor':args['color'], 'enabled':not args['disable'], 'group':args['group'], 'triggername':"action_%s" % num } self.actions.sync() self.register_action(self.actions[args['regex']]) return True, ['added action %s - regex: %s' % (num, args['regex'])] return False, ['You should never see this'] def cmd_remove(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Remove an action @CUsage@w: rem @Y<originalstring>@w @Yoriginalstring@w = The original string """ tmsg = [] if args['action']: retval = self.removeaction(args['action']) if retval: tmsg.append("@GRemoving action@w : '%s'" % (retval)) else: tmsg.append("@GCould not remove action@w : '%s'" % (args['action'])) return True, tmsg else: return False, ['@RPlease include an action to remove@w'] def cmd_list(self, args): """ @G%(name)s@w - @B%(cmdname)s@w List actiones @CUsage@w: list """ tmsg = self.listactions(args['match']) return True, tmsg def cmd_toggle(self, args): """ toggle the enabled flag """ tmsg = [] if args['togact'] == 'disable': state = False elif args['togact'] == 'enable': state = True else: state = "toggle" if args['action']: action = self.toggleaction(args['action'], flag=state) if action: if action['enabled']: tmsg.append("@GEnabled action@w : '%s'" % (action['num'])) else: tmsg.append("@GDisabled action@w : '%s'" % (action['num'])) else: tmsg.append("@GDoes not exist@w : '%s'" % (args['action'])) return True, tmsg else: return False, ['@RPlease include an action to toggle@w'] def cmd_grouptoggle(self, args): """ toggle all actions in a group """ tmsg = [] togglea = [] if args['togact'] == 'disable': state = False elif args['togact'] == 'enable': state = True else: state = "toggle" if args['group']: for i in self.actions: if self.actions[i]['group'] == args['group']: self.toggleaction(self.actions[i]['num'], flag=state) togglea.append('%s' % self.actions[i]['num']) if togglea: tmsg.append('The following actions were %s: %s' % \ ('enabled' if state else 'disabled', ','.join(togglea))) else: tmsg.append('No actions were modified') return True, tmsg else: return False, ['@RPlease include a group to toggle@w'] def cmd_detail(self, args): """ @G%(name)s@w - @B%(cmdname)s@w get details of an action @CUsage@w: detail 1 @Yaction@w = the action to get details, either the number or regex """ tmsg = [] if args['action']: action = self.lookup_action(args['action']) if action: if 'hits' not in action: action['hits'] = 0 if action['regex'] not in self.sessionhits: self.sessionhits[action['regex']] = 0 tmsg.append('%-12s : %d' % ('Num', action['num'])) tmsg.append('%-12s : %s' % \ ('Enabled', 'Y' if action['enabled'] else 'N')) tmsg.append('%-12s : %d' % ('Total Hits', action['hits'])) tmsg.append('%-12s : %d' % ('Session Hits', self.sessionhits[action['regex']])) tmsg.append('%-12s : %s' % ('Regex', action['regex'])) tmsg.append('%-12s : %s' % ('Action', action['action'])) tmsg.append('%-12s : %s' % ('Group', action['group'])) tmsg.append('%-12s : %s' % ('Match Color', action['matchcolor'])) tmsg.append('%-12s : %s' % ('Trigger Name', action['triggername'])) else: return True, ['@RAction does not exist@w : \'%s\'' % (args['action'])] return True, tmsg else: return False, ['@RPlease include all arguments@w'] def listactions(self, match): """ return a table of strings that list actions """ tmsg = [] for action in sorted(self.actions.keys()): item = self.actions[action] if not match or match in item: regex = self.api('colors.stripansi')(item['regex']) if len(regex) > 30: regex = regex[:27] + '...' action = self.api('colors.stripansi')(item['action']) if len(action) > 30: action = action[:27] + '...' tmsg.append("%4s %2s %-10s %-32s : %s@w" % \ (item['num'], 'Y' if item['enabled'] else 'N', item['group'], regex, action)) if not tmsg: tmsg = ['None'] else: tmsg.insert(0, "%4s %2s %-10s %-32s : %s@w" % ('#', 'E', 'Group', 'Regex', 'Action')) tmsg.insert(1, '@B' + '-' * 60 + '@w') return tmsg def removeaction(self, item): """ internally remove a action """ action = self.lookup_action(item) if action and action['regex'] in self.actions: self.unregister_action(action) del self.actions[action['regex']] self.actions.sync() return action def toggleaction(self, item, flag="toggle"): """ toggle an action """ action = self.lookup_action(item) if action: if flag == "toggle": action['enabled'] = not action['enabled'] else: action['enabled'] = bool(flag) if action['enabled']: self.register_action(action) else: self.unregister_action(action) return action def clearactions(self): """ clear all actiones """ for action in self.actions.values(): self.unregister_action(action) self.actions.clear() self.actions.sync() def reset(self): """ reset the plugin """ BasePlugin.reset(self) self.clearactions() def _savestate(self, _=None): """ save states """ self.actions.sync()
class Plugin(BasePlugin): """ a plugin to handle global variables, if something goes through send.execute (this includes from the client), a variable can be specified with $varname and will be substituted. """ def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.variablefile = os.path.join(self.savedir, 'variables.txt') self._variables = PersistentDict(self.variablefile, 'c') self.api('api.add')('getv', self.api_getv) self.api('api.add')('setv', self.api_setv) self.api('api.add')('replace', self.api_replace) def load(self): """ load the plugin """ BasePlugin.load(self) parser = argp.ArgumentParser(add_help=False, description='add a variable') parser.add_argument('name', help='the name of the variable', default='', nargs='?') parser.add_argument('value', help='the value of the variable', default='', nargs='?') self.api('commands.add')('add', self.cmd_add, parser=parser) parser = argp.ArgumentParser(add_help=False, description='remove a variable') parser.add_argument('name', help='the variable to remove', default='', nargs='?') self.api('commands.add')('remove', self.cmd_remove, parser=parser) parser = argp.ArgumentParser(add_help=False, description='list variables') parser.add_argument('match', help='list only variables that have this argument in their name', default='', nargs='?') self.api('commands.add')('list', self.cmd_list, parser=parser) self.api('commands.default')('list') self.api('events.register')('io_execute_event', self.checkline, prio=99) self.api('events.register')('io_execute_event', self.checkline, prio=1) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) # get a variable def api_getv(self, varname): """ get the variable with a specified name @Yvarname@w = the variable to get this function returns the value of variable with the name of the argument """ if varname in self._variables: return self._variables[varname] return None # set a variable def api_setv(self, varname, value): """ set the variable with a specified name to the specified value @Yvarname@w = the variable to set @Yvalue@w = the value to set this function returns True if the value was set, False if an error was encountered """ try: self._variables[varname] = value return True except Exception: # pylint: disable=broad-except return False # replace variables in data def api_replace(self, data): """replace the variables in data @Ydata@w = the variable to get this function returns the data after variable substition """ templ = Template(data) return templ.safe_substitute(self._variables) def checkline(self, args): """ this function checks for variables in input """ data = args['fromdata'].strip() datan = self.api('vars.replace')(data) if datan != data: if 'trace' in args: args['trace']['changes'].append({'flag':'Modify', 'data':'changed "%s" to "%s"' % (data, datan), 'plugin':self.sname}) self.api('send.msg')('replacing "%s" with "%s"' % (data.strip(), datan.strip())) args['fromdata'] = datan args['beforevar'] = data return args def cmd_add(self, args): """ command to add a variable """ tmsg = [] if args['name'] and args['value']: tmsg.append("@GAdding variable@w : '%s' will be replaced by '%s'" % \ (args['name'], args['value'])) self.addvariable(args['name'], args['value']) return True, tmsg tmsg.append("@RPlease include all arguments@w") return False, tmsg def cmd_remove(self, args): """ command to remove a variable """ tmsg = [] if args['name']: tmsg.append("@GRemoving variable@w : '%s'" % (args['name'])) self.removevariable(args['name']) return True, tmsg return False, ['@RPlease specifiy a variable to remove@w'] def cmd_list(self, args): """ command to list variables """ tmsg = self.listvariables(args['match']) return True, tmsg def addvariable(self, item, value): """ internally add a variable """ self._variables[item] = value self._variables.sync() def removevariable(self, item): """ internally remove a variable """ if item in self._variables: del self._variables[item] self._variables.sync() def listvariables(self, match): """ return a table of variables """ tmsg = [] for item in self._variables: if not match or match in item: tmsg.append("%-20s : %s@w" % (item, self._variables[item])) if not tmsg: tmsg = ['None'] return tmsg def clearvariables(self): """ clear all variables """ self._variables.clear() self._variables.sync() def reset(self): """ reset the plugin """ BasePlugin.reset(self) self.clearvariables() def _savestate(self, _=None): """ save states """ self._variables.sync()
class Plugin(AardwolfBasePlugin): """ a plugin to handle aardwolf cp events """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savewhoisfile = os.path.join(self.savedir, 'whois.txt') self.whois = PersistentDict(self.savewhoisfile, 'c') def load(self): """ load the plugins """ AardwolfBasePlugin.load(self) self.api('watch.add')('whois', '^(whoi|whois)$') self.api('triggers.add')('whoisheader', r"^\[.*\]\s+.*\s*\((?P<sex>\w+)\s+\w+\)$", enabled=False, group='whois') self.api('triggers.add')('whoisclasses', r"^\[Multiclass Player: (?P<classes>.*) \]$", enabled=False, group='whois') self.api('triggers.add')( 'whois1', r"^(?P<name1>[\w\s]*)\s*:\s*\[\s*(?P<val1>[\w\d\s]*)\s*\]\s*$", enabled=False, group='whois') self.api('triggers.add')( 'whois2', r"^(?P<name1>[\w\s]*)\s*:\s*\[\s*(?P<val1>[\w\d\s]*)\s*\]" \ r"\s*(?P<name2>[\w\s]*)\s*:\s*\[\s*(?P<val2>[\w\d\s]*)\s*\]\s*$", enabled=False, group='whois') self.api('triggers.add')( 'whois3', r"^(?P<name1>[\w\s]*)\s*:\s*\[\s*(?P<val1>[\w\d\s]*)\s*\]" \ r"\s*(?P<name2>[\w\s]*)\s*:\s*\[\s*(?P<val2>[\w\d\s]*)\s*\]" \ r"\s*(?P<name3>[\w\s]*)\s*:\s*\[\s*(?P<val3>[\w\d\s]*)\s*\]\s*$", enabled=False, group='whois') self.api('triggers.add')( 'whoispowerup', r"^(?P<name1>[\w\s]*)\s*:\s*\[\s*(?P<val1>[\w\d\s]*)\s*\]" \ r"\s*([\w\s]*)\s*:\s*\[\s*(?P<pval1>[\w\d\s]*)\s*\]\s*\[\s*" \ r"(?P<pval2>[\w\d\s]*)\s*\]\s*$", enabled=False, group='whois') self.api('triggers.add')('whoisend', r"^-{74,74}$", enabled=False) self.api('events.register')('watch_whois', self._whois) self.api('events.register')('trigger_whoisheader', self._whoisheader) self.api('events.register')('trigger_whoisclasses', self._whoisclasses) self.api('events.register')('trigger_whois1', self._whoisstats) self.api('events.register')('trigger_whois2', self._whoisstats) self.api('events.register')('trigger_whois3', self._whoisstats) self.api('events.register')('trigger_whoispowerup', self._whoisstats) self.api('events.register')('trigger_whoisend', self._whoisend) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) def _whois(self, args=None): """ reset the whois info when a "whois" command is sent """ self.whois.clear() self.api('triggers.togglegroup')('whois', True) return args def _whoisstats(self, args=None): """ parse a whois line """ for i in range(1, 4): akey = 'name%s' % i aval = 'val%s' % i if akey in args: kname = args[akey].lower().strip() kname = kname.replace(' ', '') kval = args[aval].strip() self.whois[kname] = kval if 'pval1' in args: self.whois['powerupsall'] = args['pval1'] if 'pval2' in args: self.whois['powerupsmort'] = args['pval2'] def _whoisheader(self, args=None): """ do stuff when we see the whois header """ self.whois["name"] = self.api('GMCP.getv')('char.base.name') self.whois['level'] = self.api('GMCP.getv')('char.status.level') self.whois['tiers'] = self.api('GMCP.getv')('char.base.tier') self.whois['redos'] = int(self.api('GMCP.getv')('char.base.redos')) self.whois['race'] = self.api('GMCP.getv')('char.base.race').lower() self.whois['sex'] = args['sex'].lower() self.whois['subclass'] = self.api('GMCP.getv')( 'char.base.subclass').lower() self.whois['powerupsall'] = 0 self.whois['powerupsmort'] = 0 self.whois['remorts'] = self.api('GMCP.getv')('char.base.remorts') if self.whois['remorts'] == 1: classabs = self.api('aardu.classabb')() self.whois['classes'] = [] self.whois['classes'].append({ 'remort': 1, 'class': classabs[self.api('GMCP.getv')('char.base.class').lower()] }) self.api('triggers.toggle')('whoisend', True) def _whoisclasses(self, args): """ add classes """ classabs = self.api('aardu.classabb')() tlist = args['classes'].split("/") remorts = len(tlist) self.whois['classes'] = [] for i in range(remorts): tclass = tlist[i].strip().lower() self.whois['classes'].append({ 'remort': i + 1, 'class': classabs[tclass.lower()] }) self.whois['remorts'] = remorts def _whoisend(self, _=None): """ send a whois """ self.whois['totallevels'] = self.api('aardu.getactuallevel')( self.whois['level'], self.whois['remorts'], self.whois['tiers'], self.whois['redos']) self.whois.sync() self.api('triggers.togglegroup')('whois', False) self.api('triggers.toggle')('whoisend', False) self.api('events.eraise')('aard_whois', copy.deepcopy(self.whois)) self.api('send.msg')('whois: %s' % self.whois) def _savestate(self, _=None): """ save states """ self.whois.sync()
class Plugin(AardwolfBasePlugin): """ a plugin to handle aardwolf cp events """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savewhoisfile = os.path.join(self.savedir, 'whois.txt') self.whois = PersistentDict(self.savewhoisfile, 'c') def load(self): """ load the plugins """ AardwolfBasePlugin.load(self) self.api.get('watch.add')('whois', '^(whoi|whois)$') self.api.get('triggers.add')('whoisheader', "^\[.*\]\s+.*\s*\((?P<sex>\w+)\s+\w+\)$", enabled=False, group='whois') self.api.get('triggers.add')('whoisclasses', "^\[Multiclass Player: (?P<classes>.*) \]$", enabled=False, group='whois') self.api.get('triggers.add')('whois1', "^(?P<name1>[\w\s]*)\s*:\s*\[\s*(?P<val1>[\w\d\s]*)\s*\]\s*$", enabled=False, group='whois') self.api.get('triggers.add')('whois2', "^(?P<name1>[\w\s]*)\s*:\s*\[\s*(?P<val1>[\w\d\s]*)\s*\]" \ "\s*(?P<name2>[\w\s]*)\s*:\s*\[\s*(?P<val2>[\w\d\s]*)\s*\]\s*$", enabled=False, group='whois') self.api.get('triggers.add')('whois3', "^(?P<name1>[\w\s]*)\s*:\s*\[\s*(?P<val1>[\w\d\s]*)\s*\]" \ "\s*(?P<name2>[\w\s]*)\s*:\s*\[\s*(?P<val2>[\w\d\s]*)\s*\]" \ "\s*(?P<name3>[\w\s]*)\s*:\s*\[\s*(?P<val3>[\w\d\s]*)\s*\]\s*$", enabled=False, group='whois') self.api.get('triggers.add')('whoispowerup', "^(?P<name1>[\w\s]*)\s*:\s*\[\s*(?P<val1>[\w\d\s]*)\s*\]" \ "\s*([\w\s]*)\s*:\s*\[\s*(?P<pval1>[\w\d\s]*)\s*\]\s*\[\s*" \ "(?P<pval2>[\w\d\s]*)\s*\]\s*$", enabled=False, group='whois') self.api.get('triggers.add')('whoisend', "^-{74,74}$", enabled=False) self.api.get('events.register')('watch_whois', self._whois) self.api.get('events.register')('trigger_whoisheader', self._whoisheader) self.api.get('events.register')('trigger_whoisclasses', self._whoisclasses) self.api.get('events.register')('trigger_whois1', self._whoisstats) self.api.get('events.register')('trigger_whois2', self._whoisstats) self.api.get('events.register')('trigger_whois3', self._whoisstats) self.api.get('events.register')('trigger_whoispowerup', self._whoisstats) self.api.get('events.register')('trigger_whoisend', self._whoisend) def _whois(self, args=None): """ reset the whois info when a "whois" command is sent """ self.whois.clear() self.api.get('triggers.togglegroup')('whois', True) return args def _whoisstats(self, args=None): """ parse a whois line """ for i in range(1, 4): akey = 'name%s' % i aval = 'val%s' % i if akey in args: kname = args[akey].lower().strip() kname = kname.replace(' ', '') kval = args[aval].strip() self.whois[kname] = kval if 'pval1' in args: self.whois['powerupsall'] = args['pval1'] if 'pval2' in args: self.whois['powerupsmort'] = args['pval2'] def _whoisheader(self, args=None): """ do stuff when we see the whois header """ self.whois["name"] = self.api.get('GMCP.getv')('char.base.name') self.whois['level'] = self.api.get('GMCP.getv')('char.status.level') self.whois['tiers'] = self.api.get('GMCP.getv')('char.base.tier') self.whois['redos'] = int(self.api.get('GMCP.getv')('char.base.redos')) self.whois['race'] = self.api.get('GMCP.getv')('char.base.race').lower() self.whois['sex'] = args['sex'].lower() self.whois['subclass'] = self.api.get('GMCP.getv')( 'char.base.subclass').lower() self.whois['powerupsall'] = 0 self.whois['powerupsmort'] = 0 self.whois['remorts'] = self.api.get('GMCP.getv')('char.base.remorts') if self.whois['remorts'] == 1: classabs = self.api.get('aardu.classabb')() self.whois['classes'] = [] self.whois['classes'].append({'remort':1, 'class':classabs[self.api.get('GMCP.getv')( 'char.base.class').lower()]}) self.api.get('triggers.toggle')('whoisend', True) def _whoisclasses(self, args): """ add classes """ classabs = self.api.get('aardu.classabb')() tlist = args['classes'].split("/") remorts = len(tlist) self.whois['classes'] = [] for i in range(remorts): tclass = tlist[i].strip().lower() self.whois['classes'].append({'remort':i + 1, 'class':classabs[tclass.lower()]}) self.whois['remorts'] = remorts def _whoisend(self, _=None): """ send a whois """ self.whois['totallevels'] = self.api.get('aardu.getactuallevel')( self.whois['level'], self.whois['remorts'], self.whois['tiers'], self.whois['redos']) self.whois.sync() self.api.get('triggers.togglegroup')('whois', False) self.api.get('triggers.toggle')('whoisend', False) self.api.get('events.eraise')('aard_whois', copy.deepcopy(self.whois)) self.api.get('send.msg')('whois: %s' % self.whois) def savestate(self): """ save states """ AardwolfBasePlugin.savestate(self) self.whois.sync()
class Plugin(AardwolfBasePlugin): """ a plugin to handle aardwolf cp events """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savelevelfile = os.path.join(self.savedir, 'level.txt') self.levelinfo = PersistentDict(self.savelevelfile, 'c') def load(self): """ load the plugins """ AardwolfBasePlugin.load(self) self.api.get('setting.add')('preremort', False, bool, 'flag for pre remort') self.api.get('setting.add')('remortcomp', False, bool, 'flag for remort completion') self.api.get('setting.add')('tiering', False, bool, 'flag for tiering') self.api.get('setting.add')('seen2', False, bool, 'we saw a state 2 after tiering') self.api.get('watch.add')('shloud', '^superhero loud$') self.api.get('watch.add')('shsilent', '^superhero silent$') self.api.get('watch.add')('shconfirm', '^superhero confirm$') self.api.get('watch.add')('shloudconfirm', '^superhero loud confirm$') self.api.get('triggers.add')( 'lvlpup', "^Congratulations, hero. You have increased your powers!$") self.api.get('triggers.add')('lvlpupbless', "^You gain a powerup\.$") self.api.get('triggers.add')( 'lvllevel', "^You raise a level! You are now level (?P<level>\d*).$", argtypes={ 'level': int }) self.api.get('triggers.add')( 'lvlsh', "^Congratulations! You are now a superhero!$", argtypes={ 'level': int }) self.api.get('triggers.add')( 'lvlbless', "^You gain a level - you are now level (?P<level>\d*).$", argtypes={ 'level': int }) self.api.get('triggers.add')('lvlgains', "^You gain (?P<hp>\d*) hit points, (?P<mp>\d*) mana, "\ "(?P<mv>\d*) moves, (?P<pr>\d*) practices and (?P<tr>\d*) trains.$", enabled=False, group='linfo', argtypes={'hp':int, 'mn':int, 'mv':int, 'pr':int, 'tr':int}) self.api.get('triggers.add')( 'lvlblesstrain', "^You gain (?P<tr>\d*) extra trains? daily blessing bonus.$", enabled=False, group='linfo', argtypes={ 'tr': int }) self.api.get('triggers.add')('lvlpupgains', "^You gain (?P<tr>\d*) trains.$", enabled=False, group='linfo', argtypes={ 'tr': int }) self.api.get('triggers.add')( 'lvlbonustrains', "^Lucky! You gain an extra (?P<tr>\d*) training sessions?!$", enabled=False, group='linfo', argtypes={ 'tr': int }) self.api.get('triggers.add')('lvlbonusstat', "^You gain a bonus (?P<stat>.*) point!$", enabled=False, group='linfo') self.api.get('triggers.add')('lvlshbadstar', "^%s$" % re.escape("*******************************" \ "****************************************"), enabled=False, group='superhero') self.api.get('triggers.add')('lvlshbad', "^Use either: 'superhero loud' - (?P<mins>.*) mins of " \ "double xp, (?P<qp>.*)qp and (?P<gold>.*) gold$", enabled=False, group='superhero') self.api.get('triggers.add')( 'lvlshnogold', "^You must be carrying at least 500,000 gold coins.$", enabled=False, group='superhero') self.api.get('triggers.add')( 'lvlshnoqp', "^You must have at least 1000 quest points.$", enabled=False, group='superhero') self.api.get('triggers.add')('lvlpreremort', "^You are now flagged as remorting.$", enabled=True, group='remort') self.api.get('triggers.add')('lvlremortcomp', "^\* Remort transformation complete!$", enabled=True, group='remort') self.api.get('triggers.add')( 'lvltier', "^## You have already remorted the max number of times.$", enabled=True, group='remort') self.api.get('events.register')('trigger_lvlpup', self._lvl) self.api.get('events.register')('trigger_lvlpupbless', self._lvl) self.api.get('events.register')('trigger_lvllevel', self._lvl) self.api.get('events.register')('trigger_lvlbless', self._lvl) self.api.get('events.register')('trigger_lvlgains', self._lvlgains) self.api.get('events.register')('trigger_lvlpupgains', self._lvlgains) self.api.get('events.register')('trigger_lvlblesstrain', self._lvlblesstrains) self.api.get('events.register')('trigger_lvlbonustrains', self._lvlbonustrains) self.api.get('events.register')('trigger_lvlbonusstat', self._lvlbonusstat) self.api.get('events.register')('trigger_lvlshbadstar', self._superherobad) self.api.get('events.register')('trigger_lvlshbad', self._superherobad) self.api.get('events.register')('trigger_lvlshnogold', self._superherobad) self.api.get('events.register')('trigger_lvlshnoqp', self._superherobad) self.api.get('events.register')('watch_shloud', self.cmd_superhero) self.api.get('events.register')('watch_shsilent', self.cmd_superhero) self.api.get('events.register')('watch_shconfirm', self.cmd_superhero) self.api.get('events.register')('watch_shloudconfirm', self.cmd_superhero) self.api.get('events.register')('trigger_lvlpreremort', self._preremort) self.api.get('events.register')('trigger_lvlremortcomp', self._remortcomp) self.api.get('events.register')('trigger_lvltier', self._tier) def _gmcpstatus(self, _=None): """ check gmcp status when tiering """ state = self.api.get('GMCP.getv')('char.status.state') if state == 2: self.api.get('ouput.client')('seen2') self.api.get('setting.change')('seen2', True) self.api.get('events.unregister')('GMCP:char.status', self._gmcpstatus) self.api.get('events.register')('GMCP:char.base', self._gmcpbase) def _gmcpbase(self, _=None): """ look for a new base when we remort """ self.api.get('send.client')('called char.base') state = self.api.get('GMCP.getv')('char.status.state') tiering = self.api.get('setting.gets')('tiering') seen2 = self.api.get('setting.gets')('seen2') if tiering and seen2 and state == 3: self.api.get('send.client')('in char.base') self.api.get('events.unregister')('GMCP:char.base', self._gmcpstatus) self._lvl({'level': 1}) def _tier(self, _=None): """ about to tier """ self.api.get('setting.change')('tiering', True) self.api.get('send.client')('tiering') self.api.get('events.register')('GMCP:char.status', self._gmcpstatus) def _remortcomp(self, _=None): """ do stuff when a remort is complete """ self.api.get('setting.change')('preremort', False) self.api.get('setting.change')('remortcomp', True) self._lvl({'level': 1}) def _preremort(self, _=None): """ set the preremort flag """ self.api.get('setting.change')('preremort', True) self.api.get('events.eraise')('aard_level_preremort', {}) def cmd_superhero(self, _=None): """ figure out what is done when superhero is typed """ self.api.get('send.client')('superhero was typed') self.api.get('triggers.togglegroup')('superhero', True) self._lvl({'level': 201}) def _superherobad(self, _=None): """ undo things that we typed if we didn't really superhero """ self.api.get('send.client')('didn\'t sh though') self.api.get('triggers.togglegroup')('superhero', False) self.api.get('triggers.togglegroup')('linfo', False) self.api.get('events.unregister')('trigger_emptyline', self._finish) def resetlevel(self): """ reset the level info, use the finishtime of the last level as the starttime of the next level """ if 'finishtime' in self.levelinfo and self.levelinfo['finishtime'] > 0: starttime = self.levelinfo['finishtime'] else: starttime = time.time() self.levelinfo.clear() self.levelinfo['type'] = "" self.levelinfo['level'] = -1 self.levelinfo['str'] = 0 self.levelinfo['int'] = 0 self.levelinfo['wis'] = 0 self.levelinfo['dex'] = 0 self.levelinfo['con'] = 0 self.levelinfo['luc'] = 0 self.levelinfo['starttime'] = starttime self.levelinfo['hp'] = 0 self.levelinfo['mp'] = 0 self.levelinfo['mv'] = 0 self.levelinfo['pracs'] = 0 self.levelinfo['trains'] = 0 self.levelinfo['bonustrains'] = 0 self.levelinfo['blessingtrains'] = 0 self.levelinfo['totallevels'] = 0 def _lvl(self, args=None): """ trigger for leveling """ if not args: return self.resetlevel() if 'triggername' in args and (args['triggername'] == 'lvlpup' \ or args['triggername'] == 'lvlpupbless'): self.levelinfo['level'] = self.api.get('GMCP.getv')( 'char.status.level') self.levelinfo['totallevels'] = self.api.get( 'aardu.getactuallevel')() self.levelinfo['type'] = 'pup' else: self.levelinfo['level'] = args['level'] self.levelinfo['totallevels'] = self.api.get( 'aardu.getactuallevel')(args['level']) self.levelinfo['type'] = 'level' self.api.get('triggers.togglegroup')('linfo', True) self.api.get('events.register')('trigger_emptyline', self._finish) def _lvlblesstrains(self, args): """ trigger for blessing trains """ self.levelinfo['blessingtrains'] = args['tr'] def _lvlbonustrains(self, args): """ trigger for bonus trains """ self.levelinfo['bonustrains'] = args['tr'] def _lvlbonusstat(self, args): """ trigger for bonus stats """ self.levelinfo[args['stat'][:3].lower()] = 1 def _lvlgains(self, args): """ trigger for level gains """ self.levelinfo['trains'] = args['tr'] if args['triggername'] == "lvlgains": self.levelinfo['hp'] = args['hp'] self.levelinfo['mp'] = args['mp'] self.levelinfo['mv'] = args['mv'] self.levelinfo['pracs'] = args['pr'] def _finish(self, _): """ finish up and raise the level event """ remortcomp = self.api.get('setting.gets')('remortcomp') tiering = self.api.get('setting.gets')('tiering') if self.levelinfo['trains'] == 0 and not remortcomp or tiering: return self.levelinfo['finishtime'] = time.time() self.levelinfo.sync() self.api.get('triggers.togglegroup')('linfo', False) self.api.get('events.unregister')('trigger_emptyline', self._finish) self.api.get('events.eraise')('aard_level_gain', copy.deepcopy(self.levelinfo)) if self.levelinfo['level'] == 200 and self.levelinfo['type'] == 'level': self.api.get('send.msg')('raising hero event', 'level') self.api.get('events.eraise')('aard_level_hero', {}) elif self.levelinfo['level'] == 201 and self.levelinfo[ 'type'] == 'level': self.api.get('send.msg')('raising superhero event', 'level') self.api.get('events.eraise')('aard_level_superhero', {}) elif self.levelinfo['level'] == 1: if self.api.get('setting.gets')('tiering'): self.api.get('send.msg')('raising tier event', 'level') self.api.get('setting.change')('tiering', False) self.api.get('setting.change')('seen2', False) self.api.get('events.eraise')('aard_level_tier', {}) else: self.api.get('send.msg')('raising remort event', 'level') self.api.get('setting.change')('remortcomp', False) self.api.get('events.eraise')('aard_level_remort', {}) def savestate(self): """ save states """ AardwolfBasePlugin.savestate(self) self.levelinfo.sync()
class Plugin(AardwolfBasePlugin): """ a plugin to handle aardwolf cp events """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savelevelfile = os.path.join(self.savedir, 'level.txt') self.levelinfo = PersistentDict(self.savelevelfile, 'c') def load(self): # pylint: disable=too-many-statements """ load the plugins """ AardwolfBasePlugin.load(self) self.api('setting.add')('preremort', False, bool, 'flag for pre remort') self.api('setting.add')('remortcomp', False, bool, 'flag for remort completion') self.api('setting.add')('tiering', False, bool, 'flag for tiering') self.api('setting.add')('seen2', False, bool, 'we saw a state 2 after tiering') self.api('watch.add')('shloud', '^superhero loud$') self.api('watch.add')('shsilent', '^superhero silent$') self.api('watch.add')('shconfirm', '^superhero confirm$') self.api('watch.add')('shloudconfirm', '^superhero loud confirm$') self.api('triggers.add')('lvlpup', r"^Congratulations, hero. You have increased your powers!$") self.api('triggers.add')('lvlpupbless', r"^You gain a powerup\.$") self.api('triggers.add')('lvllevel', r"^You raise a level! You are now level (?P<level>\d*).$", argtypes={'level':int}) self.api('triggers.add')('lvlshloud', r"^Congratulations! You are now a superhero!" \ r" You receive (?P<trains>) trains for superhero loud.$", argtypes={'trains':int}) self.api('triggers.add')('lvlsh', r"^Congratulations! You are now a superhero!") self.api('triggers.add')('lvlbless', r"^You gain a level - you are now level (?P<level>\d*).$", argtypes={'level':int}) self.api('triggers.add')('lvlgains', r"^You gain (?P<hp>\d*) hit points, (?P<mp>\d*) mana, "\ r"(?P<mv>\d*) moves, (?P<pr>\d*) practices and " \ r"(?P<tr>\d*) trains.$", enabled=False, group='linfo', argtypes={'hp':int, 'mn':int, 'mv':int, 'pr':int, 'tr':int}) self.api('triggers.add')('lvlblesstrain', r"^You gain (?P<tr>\d*) extra trains? " \ r"daily blessing bonus.$", enabled=False, group='linfo', argtypes={'tr':int}) self.api('triggers.add')('lvlpupgains', r"^You gain (?P<tr>\d*) trains.$", enabled=False, group='linfo', argtypes={'tr':int}) self.api('triggers.add')('lvlbattlelearntrains', r"^You gain (?P<tr>\d*) additional training sessions? " \ r"from your enhanced battle learning.$", enabled=False, group='linfo', argtypes={'tr':int}) self.api('triggers.add')('lvlbonustrains', r"^Lucky! You gain an extra (?P<tr>\d*) " \ r"training sessions?!$", enabled=False, group='linfo', argtypes={'tr':int}) self.api('triggers.add')('lvlbonusstat', r"^You gain a bonus (?P<stat>.*) point!$", enabled=False, group='linfo') self.api('triggers.add')('lvlshbadstar', r"^%s$" % re.escape("*******************************" \ "****************************************"), enabled=False, group='superhero') self.api('triggers.add')('lvlshbad', r"^Use either: 'superhero loud' - (?P<mins>.*) mins of " \ r"double xp, (?P<qp>.*)qp and (?P<gold>.*) gold$", enabled=False, group='superhero') self.api('triggers.add')('lvlshnogold', r"^You must be carrying at least 500,000 gold coins.$", enabled=False, group='superhero') self.api('triggers.add')('lvlshnoqp', r"^You must have at least 1000 quest points.$", enabled=False, group='superhero') self.api('triggers.add')('lvlshnodbl', r"^You cannot superhero loud until double exp is over.$", enabled=False, group='superhero') self.api('triggers.add')('lvlshnot200', r"^You have to be level 200 to superhero.$", enabled=False, group='superhero') self.api('triggers.add')('lvlpreremort', r"^You are now flagged as remorting.$", enabled=True, group='remort') self.api('triggers.add')('lvlremortcomp', r"^\* Remort transformation complete!$", enabled=True, group='remort') self.api('triggers.add')('lvltier', r"^## You have already remorted the max number of times.$", enabled=True, group='remort') self.api('events.register')('trigger_lvlpup', self._lvl) self.api('events.register')('trigger_lvlpupbless', self._lvl) self.api('events.register')('trigger_lvllevel', self._lvl) self.api('events.register')('trigger_lvlbless', self._lvl) #self.api('events.register')('trigger_lvlsh', self._lvl) self.api('events.register')('trigger_lvlgains', self._lvlgains) self.api('events.register')('trigger_lvlpupgains', self._lvlgains) self.api('events.register')('trigger_lvlblesstrain', self._lvlblesstrains) self.api('events.register')('trigger_lvlbonustrains', self._lvlbonustrains) self.api('events.register')('trigger_lvlbonusstat', self._lvlbonusstat) self.api('events.register')('trigger_lvlbattlelearntrains', self._lvlbattlelearntrains) self.api('events.register')('trigger_lvlshbadstar', self._superherobad) self.api('events.register')('trigger_lvlshbad', self._superherobad) self.api('events.register')('trigger_lvlshnogold', self._superherobad) self.api('events.register')('trigger_lvlshnoqp', self._superherobad) self.api('events.register')('trigger_lvlshnodbl', self._superherobad) self.api('events.register')('trigger_lvlshnot200', self._superherobad) self.api('events.register')('watch_shloud', self.cmd_superhero) self.api('events.register')('watch_shsilent', self.cmd_superhero) self.api('events.register')('watch_shconfirm', self.cmd_superhero) self.api('events.register')('watch_shloudconfirm', self.cmd_superhero) self.api('events.register')('trigger_lvlpreremort', self._preremort) self.api('events.register')('trigger_lvlremortcomp', self._remortcomp) self.api('events.register')('trigger_lvltier', self._tier) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) def _gmcpstatus(self, _=None): """ check gmcp status when tiering """ state = self.api('GMCP.getv')('char.status.state') if state == 2: self.api('ouput.client')('seen2') self.api('setting.change')('seen2', True) self.api('events.unregister')('GMCP:char.status', self._gmcpstatus) self.api('events.register')('GMCP:char.base', self._gmcpbase) def _gmcpbase(self, _=None): """ look for a new base when we remort """ self.api('send.client')('called char.base') state = self.api('GMCP.getv')('char.status.state') tiering = self.api('setting.gets')('tiering') seen2 = self.api('setting.gets')('seen2') if tiering and seen2 and state == 3: self.api('send.client')('in char.base') self.api('events.unregister')('GMCP:char.base', self._gmcpstatus) self._lvl({'level':1}) def _tier(self, _=None): """ about to tier """ self.api('setting.change')('tiering', True) self.api('send.client')('tiering') self.api('events.register')('GMCP:char.status', self._gmcpstatus) def _remortcomp(self, _=None): """ do stuff when a remort is complete """ self.api('setting.change')('preremort', False) self.api('setting.change')('remortcomp', True) self._lvl({'level':1}) def _preremort(self, _=None): """ set the preremort flag """ self.api('setting.change')('preremort', True) self.api('events.eraise')('aard_level_preremort', {}) def cmd_superhero(self, _=None): """ figure out what is done when superhero is typed """ self.api('send.client')('superhero was typed') self.api('triggers.togglegroup')('superhero', True) self._lvl({'level':201}) def _superherobad(self, _=None): """ undo things that we typed if we didn't really superhero """ self.api('send.client')('didn\'t sh though') self.api('triggers.togglegroup')('superhero', False) self.api('triggers.togglegroup')('linfo', False) self.api('events.unregister')('trigger_emptyline', self._finish) def resetlevel(self): """ reset the level info, use the finishtime of the last level as the starttime of the next level """ if 'finishtime' in self.levelinfo and self.levelinfo['finishtime'] > 0: starttime = self.levelinfo['finishtime'] else: starttime = time.time() self.levelinfo.clear() self.levelinfo['type'] = "" self.levelinfo['level'] = -1 self.levelinfo['str'] = 0 self.levelinfo['int'] = 0 self.levelinfo['wis'] = 0 self.levelinfo['dex'] = 0 self.levelinfo['con'] = 0 self.levelinfo['luc'] = 0 self.levelinfo['starttime'] = starttime self.levelinfo['hp'] = 0 self.levelinfo['mp'] = 0 self.levelinfo['mv'] = 0 self.levelinfo['pracs'] = 0 self.levelinfo['trains'] = 0 self.levelinfo['bonustrains'] = 0 self.levelinfo['blessingtrains'] = 0 self.levelinfo['battlelearntrains'] = 0 self.levelinfo['totallevels'] = 0 def _lvl(self, args=None): """ trigger for leveling """ if not args: return self.resetlevel() if 'triggername' in args and (args['triggername'] == 'lvlpup' \ or args['triggername'] == 'lvlpupbless'): self.levelinfo['level'] = self.api('GMCP.getv')('char.status.level') self.levelinfo['totallevels'] = self.api('aardu.getactuallevel')() self.levelinfo['type'] = 'pup' else: self.levelinfo['level'] = args['level'] self.levelinfo['totallevels'] = self.api('aardu.getactuallevel')( args['level']) self.levelinfo['type'] = 'level' self.api('triggers.togglegroup')('linfo', True) self.api('events.register')('trigger_emptyline', self._finish) def _lvlblesstrains(self, args): """ trigger for blessing trains """ self.levelinfo['blessingtrains'] = args['tr'] def _lvlbonustrains(self, args): """ trigger for bonus trains """ self.levelinfo['bonustrains'] = args['tr'] def _lvlbattlelearntrains(self, args): """ trigger for bonus trains """ self.levelinfo['battlelearntrains'] = args['tr'] def _lvlbonusstat(self, args): """ trigger for bonus stats """ self.levelinfo[args['stat'][:3].lower()] = 1 def _lvlgains(self, args): """ trigger for level gains """ self.levelinfo['trains'] = args['tr'] if args['triggername'] == "lvlgains": self.levelinfo['hp'] = args['hp'] self.levelinfo['mp'] = args['mp'] self.levelinfo['mv'] = args['mv'] self.levelinfo['pracs'] = args['pr'] def _finish(self, _): """ finish up and raise the level event """ remortcomp = self.api('setting.gets')('remortcomp') tiering = self.api('setting.gets')('tiering') if self.levelinfo['trains'] == 0 and not remortcomp or tiering: return self.levelinfo['finishtime'] = time.time() self.levelinfo.sync() self.api('triggers.togglegroup')('linfo', False) self.api('events.unregister')('trigger_emptyline', self._finish) self.api('events.eraise')('aard_level_gain', copy.deepcopy(self.levelinfo)) if self.levelinfo['level'] == 200 and self.levelinfo['type'] == 'level': self.api('send.msg')('raising hero event', 'level') self.api('events.eraise')('aard_level_hero', {}) elif self.levelinfo['level'] == 201 and self.levelinfo['type'] == 'level': self.api('send.msg')('raising superhero event', 'level') self.api('events.eraise')('aard_level_superhero', {}) elif self.levelinfo['level'] == 1: if self.api('setting.gets')('tiering'): self.api('send.msg')('raising tier event', 'level') self.api('setting.change')('tiering', False) self.api('setting.change')('seen2', False) self.api('events.eraise')('aard_level_tier', {}) else: self.api('send.msg')('raising remort event', 'level') self.api('setting.change')('remortcomp', False) self.api('events.eraise')('aard_level_remort', {}) def _savestate(self, _=None): """ save states """ self.levelinfo.sync()
class Plugin(BasePlugin): """ a plugin to do simple substitution """ def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.savesubfile = os.path.join(self.savedir, 'subs.txt') self._substitutes = PersistentDict(self.savesubfile, 'c') def load(self): """ load the plugins """ BasePlugin.load(self) parser = argp.ArgumentParser(add_help=False, description='add a simple substitute') parser.add_argument('original', help='the output to substitute', default='', nargs='?') parser.add_argument('replacement', help='the string to replace it with', default='', nargs='?') self.api('commands.add')('add', self.cmd_add, parser=parser) parser = argp.ArgumentParser(add_help=False, description='remove a substitute') parser.add_argument('substitute', help='the substitute to remove', default='', nargs='?') self.api('commands.add')('remove', self.cmd_remove, parser=parser) parser = argp.ArgumentParser(add_help=False, description='list substitutes') parser.add_argument('match', help='list only substitutes that have this argument in them', default='', nargs='?') self.api('commands.add')('list', self.cmd_list, parser=parser) parser = argp.ArgumentParser(add_help=False, description='clear all substitutes') self.api('commands.add')('clear', self.cmd_clear, parser=parser) self.api('commands.default')('list') self.api('events.register')('from_mud_event', self.findsub) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) def findsub(self, args): """ this function finds subs in mud data """ data = args['original'] dtype = args['dtype'] if dtype != 'fromproxy': for mem in self._substitutes.keys(): if mem in data: ndata = data.replace(mem, self.api('colors.convertcolors')( self._substitutes[mem]['sub'])) if ndata != data: args['trace']['changes'].append({'flag':'Modify', 'data':'changed "%s" to "%s"' % \ (data, ndata), 'plugin':self.sname, 'eventname':args['eventname']}) data = ndata args['original'] = data return args def cmd_add(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Add a substitute @CUsage@w: add @Y<originalstring>@w @M<replacementstring>@w @Yoriginalstring@w = The original string to be replaced @Mreplacementstring@w = The new string """ tmsg = [] if args['original'] and args['replacement']: tmsg.append("@GAdding substitute@w : '%s' will be replaced by '%s'" % \ (args['original'], args['replacement'])) self.addsub(args['original'], args['replacement']) return True, tmsg tmsg.append("@RPlease specify all arguments@w") return False, tmsg def cmd_remove(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Remove a substitute @CUsage@w: rem @Y<originalstring>@w @Yoriginalstring@w = The original string """ tmsg = [] if args['substitute']: tmsg.append("@GRemoving substitute@w : '%s'" % (args['substitute'])) self.removesub(args['substitute']) return True, tmsg return False, tmsg def cmd_list(self, args): """ @G%(name)s@w - @B%(cmdname)s@w List substitutes @CUsage@w: list """ tmsg = self.listsubs(args['match']) return True, tmsg def cmd_clear(self, args): # pylint: disable=unused-argument """ @G%(name)s@w - @B%(cmdname)s@w List substitutes @CUsage@w: list""" self.clearsubs() return True, ['Substitutes cleared'] def addsub(self, item, sub): """ internally add a substitute """ self._substitutes[item] = {'sub':sub} self._substitutes.sync() def removesub(self, item): """ internally remove a substitute """ if item in self._substitutes: del self._substitutes[item] self._substitutes.sync() def listsubs(self, match): """ return a table of strings that list subs """ tmsg = [] for item in self._substitutes: if not match or match in item: tmsg.append("%-35s : %s@w" % (item, self._substitutes[item]['sub'])) if not tmsg: tmsg = ['None'] return tmsg def clearsubs(self): """ clear all subs """ self._substitutes.clear() self._substitutes.sync() def reset(self): """ reset the plugin """ BasePlugin.reset(self) self.clearsubs() def _savestate(self, _=None): """ save states """ self._substitutes.sync()
class Plugin(BasePlugin): """ a plugin to handle global variables, if something goes through send.execute (this includes from the client), a variable can be specified with $varname and will be substituted. """ def __init__(self, *args, **kwargs): """ initialize the instance """ BasePlugin.__init__(self, *args, **kwargs) self.variablefile = os.path.join(self.savedir, 'variables.txt') self._variables = PersistentDict(self.variablefile, 'c') self.api.get('api.add')('getv', self.api_getv) self.api.get('api.add')('setv', self.api_setv) self.api.get('api.add')('replace', self.api_replace) def load(self): """ load the plugin """ BasePlugin.load(self) parser = argparse.ArgumentParser(add_help=False, description='add a variable') parser.add_argument('name', help='the name of the variable', default='', nargs='?') parser.add_argument('value', help='the value of the variable', default='', nargs='?') self.api.get('commands.add')('add', self.cmd_add, parser=parser) parser = argparse.ArgumentParser(add_help=False, description='remove a variable') parser.add_argument('name', help='the variable to remove', default='', nargs='?') self.api.get('commands.add')('remove', self.cmd_remove, parser=parser) parser = argparse.ArgumentParser(add_help=False, description='list variables') parser.add_argument('match', help='list only variables that have this argument in their name', default='', nargs='?') self.api.get('commands.add')('list', self.cmd_list, parser=parser) self.api.get('commands.default')('list') #self.api.get('events.register')('from_client_event', self.checkvariable, #prio=1) self.api.get('events.register')('from_client_event', self.checkline, prio=99) # get a variable def api_getv(self, varname): """ get the variable with a specified name @Yvarname@w = the variable to get this function returns the value of variable with the name of the argument """ if varname in self._variables: return self._variables[varname] return None # set a variable def api_setv(self, varname, value): """ set the variable with a specified name to the specified value @Yvarname@w = the variable to set @Yvalue@w = the value to set this function returns True if the value was set, False if an error was encountered """ try: self._variables[varname] = value return True except Exception: # pylint: disable=broad-except return False # replace variables in data def api_replace(self, data): """replace the variables in data @Ydata@w = the variable to get this function returns the data after variable substition """ templ = Template(data) return templ.safe_substitute(self._variables) def checkline(self, args): """ this function checks for variables in input """ data = args['fromdata'].strip() datan = self.api('vars.replace')(data) if datan != data: self.api.get('send.msg')('replacing "%s" with "%s"' % (data.strip(), datan.strip())) args['fromdata'] = datan args['beforevar'] = data return args def cmd_add(self, args): """ command to add a variable """ tmsg = [] if args['name'] and args['value']: tmsg.append("@GAdding variable@w : '%s' will be replaced by '%s'" % \ (args['name'], args['value'])) self.addvariable(args['name'], args['value']) return True, tmsg else: tmsg.append("@RPlease include all arguments@w") return False, tmsg def cmd_remove(self, args): """ command to remove a variable """ tmsg = [] if args['name']: tmsg.append("@GRemoving variable@w : '%s'" % (args['name'])) self.removevariable(args['name']) return True, tmsg else: return False, ['@RPlease specifiy a variable to remove@w'] def cmd_list(self, args): """ command to list variables """ tmsg = self.listvariables(args['match']) return True, tmsg def addvariable(self, item, value): """ internally add a variable """ self._variables[item] = value self._variables.sync() def removevariable(self, item): """ internally remove a variable """ if item in self._variables: del self._variables[item] self._variables.sync() def listvariables(self, match): """ return a table of variables """ tmsg = [] for item in self._variables: if not match or match in item: tmsg.append("%-20s : %s@w" % (item, self._variables[item])) if len(tmsg) == 0: tmsg = ['None'] return tmsg def clearvariables(self): """ clear all variables """ self._variables.clear() self._variables.sync() def reset(self): """ reset the plugin """ BasePlugin.reset(self) self.clearvariables() def savestate(self): """ save states """ BasePlugin.savestate(self) self._variables.sync()
class Plugin(AardwolfBasePlugin): """ a plugin to handle aardwolf quest events """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savegqfile = os.path.join(self.savedir, 'gq.txt') self.gqinfo = PersistentDict(self.savegqfile, 'c') self._gqsdeclared = {} self._gqsstarted = {} self.api('setting.add')('joined', -1, int, 'the gq number joined') self.api('setting.add')('maxkills', False, bool, 'no qp because of maxkills') self.mobsleft = [] self.linecount = 0 def load(self): """ load the plugins """ AardwolfBasePlugin.load(self) self.api('watch.add')('gq_check', r'^(gq|gqu|gque|gques|gquest) (c|ch|che|chec|check)$') self.api('triggers.add')( 'gqdeclared', r"^Global Quest: Global quest \# *(?P<gqnum>\d*) has been " \ r"declared for levels (?P<lowlev>\d*) to (?P<highlev>\d*)( - .*)*\.$", argtypes={'gqnum':int}) self.api('triggers.add')( 'gqjoined', r"^You have now joined Global Quest \# *(?P<gqnum>\d*)\. .*$", argtypes={'gqnum':int}) self.api('triggers.add')( 'gqstarted', r"^Global Quest: Global quest \# *(?P<gqnum>\d*) for levels .* "\ r"to .* has now started\.$", argtypes={'gqnum':int}) self.api('triggers.add')( 'gqcancelled', r"^Global Quest: Global quest \# *(?P<gqnum>\d*) has been " \ r"cancelled due to lack of (activity|participants)\.$", argtypes={'gqnum':int}) self.api('triggers.add')( 'gqquit', r"^You are no longer part of Global Quest \# *(?P<gqnum>\d*) " \ r"and will be unable to rejoin.$", argtypes={'gqnum':int}) # GQ Check triggers self.api('triggers.add')( 'gqnone', r"^You are not in a global quest\.$", enabled=False, group='gqcheck') self.api('triggers.add')( 'gqitem', r"^You still have to kill (?P<num>[\d]*) \* " \ r"(?P<mob>.*?) \((?P<location>.*?)\)(|\.)$", enabled=False, group='gqcheck', argtypes={'num':int}) self.api('triggers.add')( 'gqnotstarted', r"^Global Quest \# *(?P<gqnum>\d*) has not yet started.", enabled=False, group='gqcheck', argtypes={'gqnum':int}) self.api('triggers.add')( 'gqwins', r"^You may win .* more gquests* at this level\.$", enabled=False, group='gqcheck') self.api('triggers.add')( 'gqreward', r"^\s*Reward of (?P<amount>\d+) (?P<type>.+) .+ added\.$", enabled=False, group='gqrew', argtypes={'amount':int}) self.api('triggers.add')( 'gqmobdead', r"^Congratulations, that was one of the GLOBAL QUEST mobs!$", enabled=False, group='gqin') self.api('triggers.add')( 'gqextended', r"^Global Quest: Global Quest \# *(?P<gqnum>\d*) will go " \ r"into extended time for 3 more minutes.$", enabled=False, group='gqin', argtypes={'gqnum':int}) self.api('triggers.add')( 'gqwon', r"^You were the first to complete this quest!$", enabled=False, group='gqin') self.api('triggers.add')( 'gqextfin', r"^You have finished this global quest.$", enabled=False, group='gqin') self.api('triggers.add')( 'gqwonannounce', r"Global Quest: Global Quest \#(?P<gqnum>.*) has been won " \ r"by (?P<winner>.*) - (.*) win.$", enabled=False, group='gqin', argtypes={'gqnum':int}) self.api('triggers.add')( 'gqnote', r"^INFO: New post \#(?P<bdnum>.*) in forum Gquest from " \ r"Aardwolf Subj: Lvl (?P<low>.*) to (?P<high>.*) - " \ r"Global quest \# *(?P<gqnum>\d*)$", argtypes={'gqnum':int}) self.api('triggers.add')( 'gqmaxkills', r"^You have reached the " \ r"maximum (.*) kills for which you can earn quest points this level\.$") self.api('events.register')('trigger_gqdeclared', self._gqdeclared) self.api('events.register')('trigger_gqjoined', self._gqjoined) self.api('events.register')('trigger_gqstarted', self._gqstarted) self.api('events.register')('trigger_gqcancelled', self._gqcancelled) self.api('events.register')('trigger_gqquit', self._gqquit) self.api('events.register')('trigger_gqnone', self._notstarted) self.api('events.register')('trigger_gqitem', self._gqitem) self.api('events.register')('trigger_gqnotstarted', self._notstarted) self.api('events.register')('trigger_gqwins', self._gqwins) self.api('events.register')('trigger_gqreward', self._gqreward) self.api('events.register')('trigger_gqmobdead', self._gqmobdead) self.api('events.register')('trigger_gqextended', self._gqextended) self.api('events.register')('trigger_gqwon', self._gqwon) self.api('events.register')('trigger_gqextfin', self._gqextfin) self.api('events.register')('trigger_gqwonannounce', self._gqwonannounce) self.api('events.register')('trigger_gqnote', self._gqnote) self.api('events.register')('trigger_gqmaxkills', self._gqmaxkills) self.api('events.register')('watch_gq_check', self._gqcheckcmd) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) def _gqnew(self): """ reset the gq info """ self.mobsleft = {} self.gqinfo.clear() self.gqinfo['mobs'] = {} self.gqinfo['trains'] = 0 self.gqinfo['pracs'] = 0 self.gqinfo['gold'] = 0 self.gqinfo['tp'] = 0 self.gqinfo['qp'] = 0 self.gqinfo['qpmobs'] = 0 self.gqinfo['level'] = self.api('aardu.getactuallevel')( self.api('GMCP.getv')('char.status.level')) self.gqinfo['starttime'] = 0 self.gqinfo['finishtime'] = 0 self.gqinfo['length'] = 0 self.gqinfo['won'] = 0 self.gqinfo['completed'] = 0 self.gqinfo['extended'] = 0 self.api('setting.change')('maxkills', False) self.savestate() def _gqdeclared(self, args): """ do something when a gq is declared """ self._gqsdeclared[args['gqnum']] = True self._checkgqavailable() self._raisegq('aard_gq_declared', args) def _gqjoined(self, args): """ do something when a gq is joined """ self._gqnew() self.api('setting.change')('joined', args['gqnum']) self.mobsleft = [] if args['gqnum'] in self._gqsstarted: self._gqstarted(args) elif args['gqnum'] not in self._gqsdeclared: self._gqsdeclared[args['gqnum']] = True self._gqstarted(args) self._raisegq('aard_gq_joined', args) def _gqstarted(self, args): """ do something when a gq starts """ if args['gqnum'] not in self._gqsstarted: self._gqsstarted[args['gqnum']] = True self._raisegq('aard_gq_started', args) self._checkgqavailable() if self.api('setting.gets')('joined') == args['gqnum']: self.gqinfo['starttime'] = time.time() self.api('triggers.togglegroup')("gqin", True) self.api('send.execute')("gq check") def _gqcancelled(self, args): """ the gq has been cancelled """ self._raisegq('aard_gq_cancelled', {'gqnum':args['gqnum']}) if args['gqnum'] == self.api('setting.gets')('joined'): if self.gqinfo['qpmobs'] > 0: self.gqinfo['finishtime'] = time.time() self._raisegq('aard_gq_done', self.gqinfo) self._gqreset({'gqnum':args['gqnum']}) else: if args['gqnum'] in self._gqsdeclared: del self._gqsdeclared[args['gqnum']] if args['gqnum'] in self._gqsstarted: del self._gqsstarted[args['gqnum']] self._checkgqavailable() def _gqitem(self, args): """ do something with a gq item """ name = args['mob'] num = args['num'] location = args['location'] if not name or not location or not num: self.api('send.client')("error parsing line: %s" % args['line']) else: self.mobsleft.append({'name':name, 'nocolorname':self.api('colors.stripansi')(name), 'location':location, 'num':num}) def _notstarted(self, _=None): """ this will be called when a gq check returns the not started message """ self.api('triggers.togglegroup')('gqcheck', False) self.api('triggers.togglegroup')('gqin', False) def _gqwins(self, _=None): """ this will be enabled when gq check is enabled """ if not self.gqinfo['mobs']: self.gqinfo['mobs'] = self.mobsleft[:] self.savestate() self.api('triggers.togglegroup')('gqcheck', False) self._raisegq('aard_gq_mobsleft', {'mobsleft':copy.deepcopy(self.mobsleft)}) def _gqmobdead(self, _=None): """ called when a gq mob is killed """ if not self.api('setting.gets')('maxkills'): self.gqinfo['qpmobs'] = self.gqinfo['qpmobs'] + 3 self.api('events.register')('aard_mobkill', self._mobkillevent) def _gqextended(self, args): """ gquest went into extended time """ if args['gqnum'] == self.api('setting.gets')('joined'): self.gqinfo['extended'] = 1 def _gqmaxkills(self, _=None): """ didn't get xp for that last kill """ self.api('setting.change')('maxkills', True) def _mobkillevent(self, args): """ this will be registered to the mobkill hook """ self.api('send.msg')('checking kill %s' % args['name']) self.api('events.register')('aard_mobkill', self._mobkillevent) found = False removeitem = None for i in range(len(self.mobsleft)): tmob = self.mobsleft[i] if tmob['name'] == args['name']: self.api('send.msg')('found %s' % tmob['name']) found = True if tmob['num'] == 1: removeitem = i else: tmob['num'] = tmob['num'] - 1 if removeitem: del self.mobsleft[removeitem] if found: self._raisegq('aard_gq_mobsleft', {'mobsleft':self.mobsleft}) else: self.api('send.msg')("BP GQ: could not find mob: %s" % args['name']) self.api('send.execute')("gq check") def _gqwon(self, _=None): """ the gquest was won """ self.gqinfo['won'] = 1 self.gqinfo['finishtime'] = time.time() self.api('triggers.togglegroup')("gqrew", True) def _gqwonannounce(self, args): """ the mud announced that someone won the gquest """ if self.api('GMCP.getv')('char.base.name') == args['winner']: # we won self._raisegq('aard_gq_won', self.gqinfo) self._gqreset(args) def _gqreward(self, args=None): """ handle cpreward """ rtype = args['type'] ramount = args['amount'] rewardt = self.api('aardu.rewardtable')() self.gqinfo[rewardt[rtype]] = ramount self.savestate() def _gqcheckcmd(self, args=None): """ do something after we see a gq check """ self.mobsleft = [] self.api('triggers.togglegroup')('gqcheck', True) return args def _gqquit(self, args): """ quit the gq """ if self.gqinfo['qpmobs'] > 0: self.gqinfo['finishtime'] = time.time() self._raisegq('aard_gq_done', self.gqinfo) self._gqreset(args) def _gqextfin(self, _=None): """ the character finished the extended gq """ if self.gqinfo['qpmobs'] > 0: self.gqinfo['completed'] = 1 self.gqinfo['finishtime'] = time.time() self._raisegq('aard_gq_completed', self.gqinfo) self._gqreset({'gqnum':self.api('setting.gets')('joined')}) def _raisegq(self, event, data=None): """ raise a gq event """ self.api('send.msg')('raising %s with %s' % (event, data)) self.savestate() if data: self.api('events.eraise')(event, copy.deepcopy(data)) else: self.api('events.eraise')(event) def _gqnote(self, args): """ do something on the gquest note """ if args['gqnum'] == self.api('setting.gets')('joined'): if self.gqinfo['qpmobs'] > 0: self.gqinfo['finishtime'] = time.time() self._raisegq('aard_gq_done', self.gqinfo) self._gqreset(args) if args['gqnum'] in self._gqsdeclared: del self._gqsdeclared[args['gqnum']] if args['gqnum'] in self._gqsstarted: del self._gqsstarted[args['gqnum']] self._checkgqavailable() def _gqreset(self, args=None): """ reset gq settings """ self._gqnew() if args: if args['gqnum'] in self._gqsdeclared: del self._gqsdeclared[args['gqnum']] if args['gqnum'] in self._gqsstarted: del self._gqsstarted[args['gqnum']] self._checkgqavailable() self.api('triggers.togglegroup')("gqcheck", False) self.api('triggers.togglegroup')("gqin", False) self.api('triggers.togglegroup')("gqrew", False) self.api('events.unregister')('aard_mobkill', self._mobkillevent) self.api('setting.change')('joined', 'default') self.api('setting.change')('maxkills', False) self.savestate() def _checkgqavailable(self): if self._gqsdeclared: self._raisegq('aard_gq_available') else: self._raisegq('aard_gq_notavailable') def _savestate(self, _=None): """ save states """ self.gqinfo.sync()
class Plugin(AardwolfBasePlugin): """ a plugin to handle aardwolf quest events """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savegqfile = os.path.join(self.savedir, 'gq.txt') self.gqinfo = PersistentDict(self.savegqfile, 'c') self._gqsdeclared = {} self._gqsstarted = {} self.api.get('setting.add')('joined', -1, int, 'the gq number joined') self.api.get('setting.add')('maxkills', False, bool, 'no qp because of maxkills') self.mobsleft = [] self.linecount = 0 def load(self): """ load the plugins """ AardwolfBasePlugin.load(self) self.api.get('watch.add')( 'gq_check', '^(gq|gqu|gque|gques|gquest) (c|ch|che|chec|check)$') self.api.get('triggers.add')('gqdeclared', "^Global Quest: Global quest \# *(?P<gqnum>\d*) has been " \ "declared for levels (?P<lowlev>\d*) to (?P<highlev>\d*)( - .*)*\.$", argtypes={'gqnum':int}) self.api.get('triggers.add')( 'gqjoined', "^You have now joined Global Quest \# *(?P<gqnum>\d*)\. .*$", argtypes={ 'gqnum': int }) self.api.get('triggers.add')('gqstarted', "^Global Quest: Global quest \# *(?P<gqnum>\d*) for levels .* "\ "to .* has now started\.$", argtypes={'gqnum':int}) self.api.get('triggers.add')('gqcancelled', "^Global Quest: Global quest \# *(?P<gqnum>\d*) has been " \ "cancelled due to lack of (activity|participants)\.$", argtypes={'gqnum':int}) self.api.get('triggers.add')('gqquit', "^You are no longer part of Global Quest \# *(?P<gqnum>\d*) " \ "and will be unable to rejoin.$", argtypes={'gqnum':int}) # GQ Check triggers self.api.get('triggers.add')('gqnone', "^You are not in a global quest\.$", enabled=False, group='gqcheck') self.api.get('triggers.add')('gqitem', "^You still have to kill (?P<num>[\d]*) \* " \ "(?P<mob>.*?) \((?P<location>.*?)\)(|\.)$", enabled=False, group='gqcheck', argtypes={'num':int}) self.api.get('triggers.add')( 'gqnotstarted', "^Global Quest \# *(?P<gqnum>\d*) has not yet started.", enabled=False, group='gqcheck', argtypes={ 'gqnum': int }) self.api.get('triggers.add')( 'gqwins', "^You may win .* more gquests* at this level\.$", enabled=False, group='gqcheck') self.api.get('triggers.add')( 'gqreward', "^\s*Reward of (?P<amount>\d+) (?P<type>.+) .+ added\.$", enabled=False, group='gqrew', argtypes={ 'amount': int }) self.api.get('triggers.add')( 'gqmobdead', "^Congratulations, that was one of the GLOBAL QUEST mobs!$", enabled=False, group='gqin') self.api.get('triggers.add')('gqextended', "^Global Quest: Global Quest \# *(?P<gqnum>\d*) will go " \ "into extended time for 3 more minutes.$", enabled=False, group='gqin', argtypes={'gqnum':int}) self.api.get('triggers.add')( 'gqwon', "^You were the first to complete this quest!$", enabled=False, group='gqin') self.api.get('triggers.add')('gqextfin', "^You have finished this global quest.$", enabled=False, group='gqin') self.api.get('triggers.add')('gqwonannounce', "Global Quest: Global Quest \#(?P<gqnum>.*) has been won " \ "by (?P<winner>.*) - (.*) win.$", enabled=False, group='gqin', argtypes={'gqnum':int}) self.api.get('triggers.add')('gqnote', "^INFO: New post \#(?P<bdnum>.*) in forum Gquest from " \ "Aardwolf Subj: Lvl (?P<low>.*) to (?P<high>.*) - " \ "Global quest \# *(?P<gqnum>\d*)$", argtypes={'gqnum':int}) self.api.get('triggers.add')('gqmaxkills', "^You have reached the " \ "maximum (.*) kills for which you can earn quest points this level\.$") self.api.get('events.register')('trigger_gqdeclared', self._gqdeclared) self.api.get('events.register')('trigger_gqjoined', self._gqjoined) self.api.get('events.register')('trigger_gqstarted', self._gqstarted) self.api.get('events.register')('trigger_gqcancelled', self._gqcancelled) self.api.get('events.register')('trigger_gqquit', self._gqquit) self.api.get('events.register')('trigger_gqnone', self._notstarted) self.api.get('events.register')('trigger_gqitem', self._gqitem) self.api.get('events.register')('trigger_gqnotstarted', self._notstarted) self.api.get('events.register')('trigger_gqwins', self._gqwins) self.api.get('events.register')('trigger_gqreward', self._gqreward) self.api.get('events.register')('trigger_gqmobdead', self._gqmobdead) self.api.get('events.register')('trigger_gqextended', self._gqextended) self.api.get('events.register')('trigger_gqwon', self._gqwon) self.api.get('events.register')('trigger_gqextfin', self._gqextfin) self.api.get('events.register')('trigger_gqwonannounce', self._gqwonannounce) self.api.get('events.register')('trigger_gqnote', self._gqnote) self.api.get('events.register')('trigger_gqmaxkills', self._gqmaxkills) self.api.get('events.register')('watch_gq_check', self._gqcheckcmd) def _gqnew(self): """ reset the gq info """ self.mobsleft = {} self.gqinfo.clear() self.gqinfo['mobs'] = {} self.gqinfo['trains'] = 0 self.gqinfo['pracs'] = 0 self.gqinfo['gold'] = 0 self.gqinfo['tp'] = 0 self.gqinfo['qp'] = 0 self.gqinfo['qpmobs'] = 0 self.gqinfo['level'] = self.api.get('aardu.getactuallevel')( self.api.get('GMCP.getv')('char.status.level')) self.gqinfo['starttime'] = 0 self.gqinfo['finishtime'] = 0 self.gqinfo['length'] = 0 self.gqinfo['won'] = 0 self.gqinfo['completed'] = 0 self.gqinfo['extended'] = 0 self.api.get('setting.change')('maxkills', False) self.savestate() def _gqdeclared(self, args): """ do something when a gq is declared """ self._gqsdeclared[args['gqnum']] = True self._checkgqavailable() self._raisegq('aard_gq_declared', args) def _gqjoined(self, args): """ do something when a gq is joined """ self._gqnew() self.api.get('setting.change')('joined', args['gqnum']) self.mobsleft = [] if args['gqnum'] in self._gqsstarted: self._gqstarted(args) elif not (args['gqnum'] in self._gqsdeclared): self._gqsdeclared[args['gqnum']] = True self._gqstarted(args) self._raisegq('aard_gq_joined', args) def _gqstarted(self, args): """ do something when a gq starts """ if not (args['gqnum'] in self._gqsstarted): self._gqsstarted[args['gqnum']] = True self._raisegq('aard_gq_started', args) self._checkgqavailable() if self.api.get('setting.gets')('joined') == args['gqnum']: self.gqinfo['starttime'] = time.time() self.api.get('triggers.togglegroup')("gqin", True) self.api.get('send.execute')("gq check") def _gqcancelled(self, args): """ the gq has been cancelled """ self._raisegq('aard_gq_cancelled', {'gqnum': args['gqnum']}) if args['gqnum'] == self.api('setting.gets')('joined'): if self.gqinfo['qpmobs'] > 0: self.gqinfo['finishtime'] = time.time() self._raisegq('aard_gq_done', self.gqinfo) self._gqreset({'gqnum': args['gqnum']}) else: if args['gqnum'] in self._gqsdeclared: del (self._gqsdeclared[args['gqnum']]) if args['gqnum'] in self._gqsstarted: del (self._gqsstarted[args['gqnum']]) self._checkgqavailable() def _gqitem(self, args): """ do something with a gq item """ name = args['mob'] num = args['num'] location = args['location'] if not name or not location or not num: self.api.get('send.client')("error parsing line: %s" % args['line']) else: self.mobsleft.append({ 'name': name, 'nocolorname': self.api.get('colors.stripansi')(name), 'location': location, 'num': num }) def _notstarted(self, _=None): """ this will be called when a gq check returns the not started message """ self.api.get('triggers.togglegroup')('gqcheck', False) self.api.get('triggers.togglegroup')('gqin', False) def _gqwins(self, _=None): """ this will be enabled when gq check is enabled """ if not self.gqinfo['mobs']: self.gqinfo['mobs'] = self.mobsleft[:] self.savestate() self.api.get('triggers.togglegroup')('gqcheck', False) self._raisegq('aard_gq_mobsleft', {'mobsleft': copy.deepcopy(self.mobsleft)}) def _gqmobdead(self, _=None): """ called when a gq mob is killed """ if not self.api.get('setting.gets')('maxkills'): self.gqinfo['qpmobs'] = self.gqinfo['qpmobs'] + 3 self.api.get('events.register')('aard_mobkill', self._mobkillevent) def _gqextended(self, args): """ gquest went into extended time """ if args['gqnum'] == self.api('setting.gets')('joined'): self.gqinfo['extended'] = 1 def _gqmaxkills(self, args): """ didn't get xp for that last kill """ self.api.get('setting.change')('maxkills', True) def _mobkillevent(self, args): """ this will be registered to the mobkill hook """ self.api.get('send.msg')('checking kill %s' % args['name']) self.api.get('events.register')('aard_mobkill', self._mobkillevent) found = False removeitem = None for i in range(len(self.mobsleft)): tmob = self.mobsleft[i] if tmob['name'] == args['name']: self.api.get('send.msg')('found %s' % tmob['name']) found = True if tmob['num'] == 1: removeitem = i else: tmob['num'] = tmob['num'] - 1 if removeitem: del (self.mobsleft[removeitem]) if found: self._raisegq('aard_gq_mobsleft', {'mobsleft': self.mobsleft}) else: self.api.get('send.msg')("BP GQ: could not find mob: %s" % args['name']) self.api.get('send.execute')("gq check") def _gqwon(self, _=None): """ the gquest was won """ self.gqinfo['won'] = 1 self.gqinfo['finishtime'] = time.time() self.api.get('triggers.togglegroup')("gqrew", True) def _gqwonannounce(self, args): """ the mud announced that someone won the gquest """ if self.api('GMCP.getv')('char.base.name') == args['winner']: # we won self._raisegq('aard_gq_won', self.gqinfo) self._gqreset(args) def _gqreward(self, args=None): """ handle cpreward """ rtype = args['type'] ramount = args['amount'] rewardt = self.api.get('aardu.rewardtable')() self.gqinfo[rewardt[rtype]] = ramount self.savestate() def _gqcheckcmd(self, args=None): """ do something after we see a gq check """ self.mobsleft = [] self.api.get('triggers.togglegroup')('gqcheck', True) return args def _gqquit(self, args): """ quit the gq """ if self.gqinfo['qpmobs'] > 0: self.gqinfo['finishtime'] = time.time() self._raisegq('aard_gq_done', self.gqinfo) self._gqreset(args) def _gqextfin(self, _=None): """ the character finished the extended gq """ if self.gqinfo['qpmobs'] > 0: self.gqinfo['completed'] = 1 self.gqinfo['finishtime'] = time.time() self._raisegq('aard_gq_completed', self.gqinfo) self._gqreset({'gqnum': self.api('setting.gets')('joined')}) def _raisegq(self, event, data=None): """ raise a gq event """ self.api('send.msg')('raising %s with %s' % (event, data)) self.savestate() if data: self.api.get('events.eraise')(event, copy.deepcopy(data)) else: self.api.get('events.eraise')(event) def _gqnote(self, args): """ do something on the gquest note """ if args['gqnum'] == self.api('setting.gets')('joined'): if self.gqinfo['qpmobs'] > 0: self.gqinfo['finishtime'] = time.time() self._raisegq('aard_gq_done', self.gqinfo) self._gqreset(args) if args['gqnum'] in self._gqsdeclared: del (self._gqsdeclared[args['gqnum']]) if args['gqnum'] in self._gqsstarted: del (self._gqsstarted[args['gqnum']]) self._checkgqavailable() def _gqreset(self, args={}): """ reset gq settings """ self._gqnew() if args: if args['gqnum'] in self._gqsdeclared: del (self._gqsdeclared[args['gqnum']]) if args['gqnum'] in self._gqsstarted: del (self._gqsstarted[args['gqnum']]) self._checkgqavailable() self.api.get('triggers.togglegroup')("gqcheck", False) self.api.get('triggers.togglegroup')("gqin", False) self.api.get('triggers.togglegroup')("gqrew", False) self.api.get('events.unregister')('aard_mobkill', self._mobkillevent) self.api.get('setting.change')('joined', 'default') self.api.get('setting.change')('maxkills', False) self.savestate() def _checkgqavailable(self): if len(self._gqsdeclared) > 0: self._raisegq('aard_gq_available') else: self._raisegq('aard_gq_notavailable') def savestate(self): """ save states """ AardwolfBasePlugin.savestate(self) self.gqinfo.sync()
class Plugin(BasePlugin): """ a class to manage logging """ def __init__(self, *args, **kwargs): """ init the class """ BasePlugin.__init__(self, *args, **kwargs) self.canreload = False #print('log api.api', self.api.api) #print('log basepath', self.api.BASEPATH) self.savedir = os.path.join(self.api.BASEPATH, 'data', 'plugins', self.sname) self.logdir = os.path.join(self.api.BASEPATH, 'data', 'logs') #print('logdir', self.logdir) try: os.makedirs(self.savedir) except OSError: pass self.dtypes = {} self.sendtoclient = PersistentDict( os.path.join(self.savedir, 'sendtoclient.txt'), 'c') self.sendtoconsole = PersistentDict( os.path.join(self.savedir, 'sendtoconsole.txt'), 'c') self.sendtofile = PersistentDict( os.path.join(self.savedir, 'sendtofile.txt'), 'c') self.openlogs = {} self.currentlogs = {} self.colors = {} #self.sendtofile['default'] = { #'logdir':os.path.join(self.logdir, 'default'), #'file':'%a-%b-%d-%Y.log', 'timestamp':True #} self.colors['error'] = '@x136' self.api.get('api.add')('msg', self.api_msg) self.api.get('api.add')('adddtype', self.api_adddtype) self.api.get('api.add')('console', self.api_toggletoconsole) self.api.get('api.add')('file', self.api_toggletofile) self.api.get('api.add')('client', self.api_toggletoclient) self.api.get('log.adddtype')('default') self.api.get('log.adddtype')('frommud') self.api.get('log.adddtype')('startup') self.api.get('log.adddtype')('error') self.api.get('log.client')('error') self.api.get('log.console')('error') self.api.get('log.console')('default') self.api.get('log.console')('startup') #self.api.get('log.file')('default') # add a datatype to the log def api_adddtype(self, datatype): """ add a datatype @Ydatatype@w = the datatype to add this function returns no values""" if datatype not in self.dtypes: self.dtypes[datatype] = True self.sendtoclient[datatype] = False self.sendtoconsole[datatype] = False def process_msg(self, msg, dtype, priority='primary'): """ process a message """ tstring = '%s - %-10s : ' % (time.strftime('%a %b %d %Y %H:%M:%S', time.localtime()), dtype) if self.api.get('api.has')('colors.convertcolors') and \ dtype in self.colors: tstring = self.api.get('colors.convertcolors')(self.colors[dtype] + tstring) tmsg = [tstring] tmsg.append(msg) timestampmsg = ''.join(tmsg) nontimestamp = msg if dtype in self.sendtoclient and self.sendtoclient[dtype]: self.api.get('send.client')(timestampmsg) if dtype in self.sendtoconsole and self.sendtoconsole[dtype]: print(timestampmsg, file=sys.stderr) if priority == 'primary': if dtype in self.sendtofile and self.sendtofile[dtype]['file']: if self.api.get('api.has')('colors.stripansi'): self.logtofile( self.api.get('colors.stripansi')(nontimestamp), dtype) else: self.logtofile(nontimestamp, dtype) if 'default' in self.sendtofile: self.logtofile(timestampmsg, 'default') # process a message, use send.msg instead for the api def api_msg(self, args, dtypedict=None): """ send a message @Ymsg@w = This message to send @Ydatatype@w = the type to toggle this function returns no values""" if not dtypedict: dtypedict = {'primary': 'default'} dtype = dtypedict['primary'] if 'primary' in args: dtype = args['primary'] self.process_msg(args['msg'], dtype) if 'secondary' in dtypedict: for i in dtypedict['secondary']: if i and i != 'None' \ and i != 'default': self.process_msg(args['msg'], i, priority='secondary') # archive a log fle def archivelog(self, dtype): """ archive the previous log """ tfile = os.path.split(self.currentlogs[dtype])[-1] self.openlogs[self.currentlogs[dtype]].close() backupfile = os.path.join(self.logdir, dtype, tfile) backupzipfile = os.path.join(self.logdir, dtype, 'archive', tfile + '.zip') with zipfile.ZipFile(backupzipfile, 'w', zipfile.ZIP_DEFLATED, allowZip64=True) as myzip: myzip.write(backupfile, arcname=self.currentlogs[dtype]) os.remove(backupfile) del self.openlogs[self.currentlogs[dtype]] # log something to a file def logtofile(self, msg, dtype): """ send a message to a log file """ #print('logging', dtype) tfile = os.path.join( self.logdir, dtype, time.strftime(self.sendtofile[dtype]['file'], time.localtime())) if not os.path.exists(os.path.join(self.logdir, dtype)): os.makedirs(os.path.join(self.logdir, dtype, 'archive')) if (dtype not in self.currentlogs) or \ (dtype in self.currentlogs and not self.currentlogs[dtype]): self.currentlogs[dtype] = tfile elif tfile != self.currentlogs[dtype]: self.archivelog(dtype) self.currentlogs[dtype] = tfile if self.currentlogs[dtype] not in self.openlogs: self.openlogs[self.currentlogs[dtype]] = \ open(self.currentlogs[dtype], 'a') #print('logging to %s' % tfile) if self.sendtofile[dtype]['timestamp']: tstring = '%s : ' % \ (time.strftime(self.api.timestring, time.localtime())) msg = tstring + msg if self.api.get('api.has')('colors.stripansi'): self.openlogs[self.currentlogs[dtype]].write( self.api.get('colors.stripansi')(msg) + '\n') else: self.openlogs[self.currentlogs[dtype]].write(msg + '\n') self.openlogs[self.currentlogs[dtype]].flush() # toggle logging a datatype to the clients def api_toggletoclient(self, datatype, flag=True): """ toggle a data type to show to clients @Ydatatype@w = the type to toggle, can be multiple (list) @Yflag@w = True to send to clients, false otherwise (default: True) this function returns no values""" if datatype in self.sendtoclient and datatype != 'frommud': self.sendtoclient[datatype] = flag self.api.get('send.msg')('setting %s to log to client' % \ datatype) self.sendtoclient.sync() # toggle logging datatypes to the clients def cmd_client(self, args): """ toggle datatypes shown to client """ tmsg = [] if len(args['datatype']) > 0: for i in args['datatype']: if i in self.sendtoclient and i != 'frommud': self.sendtoclient[i] = not self.sendtoclient[i] if self.sendtoclient[i]: tmsg.append('sending %s to client' % i) else: tmsg.append('no longer sending %s to client' % i) elif i != 'frommud': tmsg.append('Type %s does not exist' % i) self.sendtoclient.sync() return True, tmsg else: tmsg.append('Current types going to client') for i in self.sendtoclient: if self.sendtoclient[i]: tmsg.append(i) return True, tmsg # toggle logging a datatype to the console def api_toggletoconsole(self, datatype, flag=True): """ toggle a data type to show to console @Ydatatype@w = the type to toggle @Yflag@w = True to send to console, false otherwise (default: True) this function returns no values""" if datatype in self.sendtoconsole and datatype != 'frommud': self.sendtoconsole[datatype] = flag self.api.get('send.msg')('setting %s to log to console' % \ datatype, self.sname) self.sendtoconsole.sync() # toggle logging datatypes to the console def cmd_console(self, args): """ log datatypes to the console """ tmsg = [] if len(args['datatype']) > 0: for i in args['datatype']: if i in self.sendtoconsole and i != 'frommud': self.sendtoconsole[i] = not self.sendtoconsole[i] if self.sendtoconsole[i]: tmsg.append('sending %s to console' % i) else: tmsg.append('no longer sending %s to console' % i) elif i != 'frommud': tmsg.append('Type %s does not exist' % i) self.sendtoconsole.sync() return True, tmsg else: tmsg.append('Current types going to console') for i in self.sendtoconsole: if self.sendtoconsole[i]: tmsg.append(i) return True, tmsg # toggle logging a datatype to a file def api_toggletofile(self, datatype, timestamp=True): """ toggle a data type to show to file @Ydatatype@w = the type to toggle @Yflag@w = True to send to file, false otherwise (default: True) this function returns no values""" if datatype in self.sendtofile: del self.sendtofile[datatype] else: tfile = '%a-%b-%d-%Y.log' self.sendtofile[datatype] = {'file': tfile, 'timestamp': timestamp} self.api.get('send.msg')('setting %s to log to %s' % \ (datatype, self.sendtofile[datatype]['file']), self.sname) self.sendtofile.sync() # toggle a datatype to log to a file def cmd_file(self, args): """ toggle a datatype to log to a file """ tmsg = [] timestamp = True if args['datatype'] != 'list': dtype = args['datatype'] timestamp = args['notimestamp'] if dtype in self.sendtofile: del self.sendtofile[dtype] tmsg.append('removing %s from logging' % dtype) else: tfile = '%a-%b-%d-%Y.log' self.sendtofile[dtype] = { 'file': tfile, 'logdir': os.path.join(self.logdir, dtype), 'timestamp': timestamp } tmsg.append('setting %s to log to %s' % \ (dtype, self.sendtofile[dtype]['file'])) self.sendtofile.sync() return True, tmsg else: tmsg.append('Current types going to file') for i in self.sendtofile: if self.sendtofile[i]: tmsg.append('%s - %s - %s' % \ (i, self.sendtofile[i]['file'], self.sendtofile[i]['timestamp'])) return True, tmsg # archive a datatype def cmd_archive(self, args): """ archive a datatype """ tmsg = [] if len(args) > 0: for i in args: if i in self.dtypes: self.archivelog(i) else: tmsg.append('%s does not exist' % i) return True, tmsg else: tmsg = ['Please specifiy a datatype to archive'] return False, tmsg # show all types def cmd_types(self, args): """ list data types """ tmsg = [] tmsg.append('Data Types') tmsg.append('-' * 30) match = args['match'] tkeys = self.dtypes.keys() tkeys.sort() for i in tkeys: if not match or match in i: tmsg.append(i) return True, tmsg def logmud(self, args): """ log all data from the mud """ if 'frommud' in self.sendtofile and self.sendtofile['frommud']['file']: if args['eventname'] == 'from_mud_event': data = args['noansi'] elif args['eventname'] == 'to_mud_event': data = 'tomud: ' + args['data'].strip() self.logtofile(data, 'frommud') return args def load(self): """ load external stuff """ BasePlugin.load(self) #print('log api before adding', self.api.api) #print('log api after adding', self.api.api) self.api.get('events.register')('from_mud_event', self.logmud) self.api.get('events.register')('to_mud_event', self.logmud) parser = argparse.ArgumentParser(add_help=False, description="""\ toggle datatypes to clients if no arguments, data types that are currenty sent to clients will be listed""" ) parser.add_argument('datatype', help='a list of datatypes to toggle', default=[], nargs='*') self.api.get('commands.add')('client', self.cmd_client, lname='Logger', parser=parser) parser = argparse.ArgumentParser(add_help=False, description="""\ toggle datatype to log to a file the file will be located in the data/logs/<dtype> directory the filename for the log will be <date>.log Example: Tue-Feb-26-2013.log if no arguments, types that are sent to file will be listed""") parser.add_argument('datatype', help='the datatype to toggle', default='list', nargs='?') parser.add_argument("-n", "--notimestamp", help="do not log to file with a timestamp", action="store_false") self.api.get('commands.add')('file', self.cmd_file, lname='Logger', parser=parser) parser = argparse.ArgumentParser(add_help=False, description="""\ toggle datatypes to the console if no arguments, data types that are currenty sent to the console will be listed""" ) parser.add_argument('datatype', help='a list of datatypes to toggle', default=[], nargs='*') self.api.get('commands.add')('console', self.cmd_console, lname='Logger', parser=parser) parser = argparse.ArgumentParser(add_help=False, description="list all datatypes") parser.add_argument( 'match', help='only list datatypes that have this argument in their name', default='', nargs='?') self.api.get('commands.add')('types', self.cmd_types, lname='Logger', parser=parser)
class PluginMgr(object): # pylint: disable=too-many-public-methods """ a class to manage plugins """ def __init__(self): """ initialize the instance """ self.plugins = {} self.pluginl = {} self.pluginm = {} self.pluginp = {} self.options = {} self.plugininfo = {} index = __file__.rfind(os.sep) if index == -1: self.basepath = "." + os.sep else: self.basepath = __file__[:index] self.api = API() self.savefile = os.path.join(self.api.BASEPATH, 'data', 'plugins', 'loadedplugins.txt') self.loadedplugins = PersistentDict(self.savefile, 'c') self.sname = 'plugins' self.lname = 'Plugin Manager' self.api.add(self.sname, 'isinstalled', self.api_isinstalled) self.api.add(self.sname, 'getp', self.api_getp) self.api.add(self.sname, 'module', self.api_getmodule) self.api.add(self.sname, 'allplugininfo', self.api_allplugininfo) self.api.add(self.sname, 'savestate', self.savestate) # return the dictionary of all plugins def api_allplugininfo(self): """ return the plugininfo dictionary """ return self.plugininfo def findplugin(self, name): """ find a plugin file """ if '.' in name: tlist = name.split('.') name = tlist[-1] del tlist[-1] npath = os.sep.join(tlist) _module_list = find_files(self.basepath, name + ".py") if len(_module_list) == 1: return _module_list[0], self.basepath else: for i in _module_list: if npath in i: return i, self.basepath return '', '' def findloadedplugin(self, plugin): """ find a plugin """ if plugin and plugin in self.plugins: return plugin fullimploc = 'plugins.' + plugin for tplugin in self.plugins: if self.plugins[tplugin].fullimploc == fullimploc: return tplugin return None # get a plugin instance def api_getmodule(self, pluginname): """ returns the module of a plugin @Ypluginname@w = the plugin to check for""" if pluginname in self.pluginm: return self.pluginm[pluginname] return None # get a plugin instance def api_getp(self, pluginname): """ get a plugin instance @Ypluginname@w = the plugin to get for""" if isinstance(pluginname, basestring): if pluginname in self.plugins: return self.plugins[pluginname] if pluginname in self.pluginl: return self.pluginl[pluginname] if pluginname in self.pluginm: return self.pluginm[pluginname] if pluginname in self.pluginp: return self.pluginp[pluginname] elif isinstance(pluginname, BasePlugin): return pluginname return None # check if a plugin is installed def api_isinstalled(self, pluginname): """ check if a plugin is installed @Ypluginname@w = the plugin to check for""" if pluginname in self.plugins or pluginname in self.pluginl: return True return False def loaddependencies(self, pluginname, dependencies): """ load a list of modules """ for i in dependencies: if i in self.plugins or i in self.pluginl: continue self.api.get('send.msg')('%s: loading dependency %s' % (pluginname, i), pluginname) name, path = self.findplugin(i) if name: modpath = name.replace(path, '') self.load_module(modpath, path, force=True) def getnotloadedplugins(self): """ create a message of all not loaded plugins """ msg = [] badplugins = self.updateallplugininfo() for modpath in sorted(self.plugininfo.keys()): sname = self.plugininfo[modpath]['sname'] fullimploc = self.plugininfo[modpath]['fullimploc'] if sname not in self.plugins: msg.append("%-20s : %-25s %-10s %-5s %s@w" % \ (fullimploc.replace('plugins.', ''), self.plugininfo[modpath]['name'], self.plugininfo[modpath]['author'], self.plugininfo[modpath]['version'], self.plugininfo[modpath]['purpose'])) if len(msg) > 0: msg.insert(0, '-' * 75) msg.insert(0, "%-20s : %-25s %-10s %-5s %s@w" % \ ('Location', 'Name', 'Author', 'Vers', 'Purpose')) msg.insert(0, 'The following plugins are not loaded') if badplugins: msg.append('') msg.append('The following files would not import') for bad in badplugins: msg.append(bad.replace('plugins.', '')) return msg def getchangedplugins(self): """ create a message of plugins that are changed on disk """ msg = [] plugins = sorted(self.plugins.values(), key=operator.attrgetter('package')) packageheader = [] msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ ('Short Name', 'Name', 'Author', 'Vers', 'Purpose')) msg.append('-' * 75) for tpl in plugins: if tpl.ischangedondisk(): if tpl.package not in packageheader: if len(packageheader) > 0: msg.append('') packageheader.append(tpl.package) limp = 'plugins.%s' % tpl.package mod = __import__(limp) try: desc = getattr(mod, tpl.package).DESCRIPTION except AttributeError: desc = '' msg.append('@GPackage: %s%s@w' % \ (tpl.package, ' - ' + desc if desc else '')) msg.append('@G' + '-' * 75 + '@w') msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ (tpl.sname, tpl.name, tpl.author, tpl.version, tpl.purpose)) return msg def getpackageplugins(self, package): """ create a message of plugins in a package """ msg = [] plist = [] for plugin in self.plugins.values(): if plugin.package == package: plist.append(plugin) if len(plist) > 0: plugins = sorted(plist, key=operator.attrgetter('sname')) limp = 'plugins.%s' % package mod = __import__(limp) try: desc = getattr(mod, package).DESCRIPTION except AttributeError: desc = '' msg.append('@GPackage: %s%s@w' % \ (package, ' - ' + desc if desc else '')) msg.append('@G' + '-' * 75 + '@w') msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ ('Short Name', 'Name', 'Author', 'Vers', 'Purpose')) msg.append('-' * 75) for tpl in plugins: msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ (tpl.sname, tpl.name, tpl.author, tpl.version, tpl.purpose)) else: msg.append('That is not a valid package') return msg def getallplugins(self): """ create a message of all plugins """ msg = [] plugins = sorted(self.plugins.values(), key=operator.attrgetter('package')) packageheader = [] msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ ('Short Name', 'Name', 'Author', 'Vers', 'Purpose')) msg.append('-' * 75) for tpl in plugins: if tpl.package not in packageheader: if len(packageheader) > 0: msg.append('') packageheader.append(tpl.package) limp = 'plugins.%s' % tpl.package mod = __import__(limp) try: desc = getattr(mod, tpl.package).DESCRIPTION except AttributeError: desc = '' msg.append('@GPackage: %s%s@w' % \ (tpl.package, ' - ' + desc if desc else '')) msg.append('@G' + '-' * 75 + '@w') msg.append("%-10s : %-25s %-10s %-5s %s@w" % \ (tpl.sname, tpl.name, tpl.author, tpl.version, tpl.purpose)) return msg def cmd_list(self, args): """ @G%(name)s@w - @B%(cmdname)s@w List plugins @CUsage@w: list """ msg = [] if args['notloaded']: msg.extend(self.getnotloadedplugins()) elif args['changed']: msg.extend(self.getchangedplugins()) elif args['package']: msg.extend(self.getpackageplugins(args['package'])) else: msg.extend(self.getallplugins()) return True, msg def cmd_load(self, args): """ @G%(name)s@w - @B%(cmdname)s@w Load a plugin @CUsage@w: load @Yplugin@w @Yplugin@w = the name of the plugin to load use the name without the .py """ tmsg = [] plugin = args['plugin'] if plugin: fname = plugin.replace('.', os.sep) _module_list = find_files(self.basepath, fname + ".py") if len(_module_list) > 1: tmsg.append('There is more than one module that matches: %s' % \ plugin) elif len(_module_list) == 0: tmsg.append('There are no modules that match: %s' % plugin) else: modpath = _module_list[0].replace(self.basepath, '') sname, reason = self.load_module(modpath, self.basepath, True) if sname: if reason == 'already': tmsg.append('Module %s is already loaded' % sname) else: tmsg.append('Load complete: %s - %s' % \ (sname, self.plugins[sname].name)) else: tmsg.append('Could not load: %s' % plugin) return True, tmsg else: return False, ['@Rplease specify a plugin@w'] def cmd_unload(self, args): """ @G%(name)s@w - @B%(cmdname)s@w unload a plugin @CUsage@w: unload @Yplugin@w @Yplugin@w = the shortname of the plugin to load """ tmsg = [] plugina = args['plugin'] if not plugina: return False, ['@Rplease specify a plugin@w'] plugin = self.findloadedplugin(plugina) if plugin and plugin in self.plugins: if self.plugins[plugin].canreload: if self.unload_module(self.plugins[plugin].fullimploc): tmsg.append("Unloaded: %s" % plugin) else: tmsg.append("Could not unload:: %s" % plugin) else: tmsg.append("That plugin can not be unloaded") return True, tmsg elif plugin: tmsg.append('plugin %s does not exist' % plugin) return True, tmsg return False, ['@Rplease specify a plugin@w'] def cmd_reload(self, args): """ @G%(name)s@w - @B%(cmdname)s@w reload a plugin @CUsage@w: reload @Yplugin@w @Yplugin@w = the shortname of the plugin to reload """ tmsg = [] plugina = args['plugin'] if not plugina: return False, ['@Rplease specify a plugin@w'] plugin = self.findloadedplugin(plugina) if plugin and plugin in self.plugins: if self.plugins[plugin].canreload: tret, _ = self.reload_module(plugin, True) if tret and tret != True: tmsg.append("Reload complete: %s" % self.plugins[tret].fullimploc) return True, tmsg else: tmsg.append("That plugin cannot be reloaded") return True, tmsg else: tmsg.append('plugin %s does not exist' % plugin) return True, tmsg return False, tmsg def load_modules(self, tfilter): """ load modules in all directories under plugins """ _module_list = find_files(self.basepath, tfilter) _module_list.sort() load = False for fullpath in _module_list: modpath = fullpath.replace(self.basepath, '') force = False if modpath in self.loadedplugins: force = True modname, dummy = self.load_module(modpath, self.basepath, force=force, runload=load) if modname == 'log': self.api.get('log.adddtype')(self.sname) self.api.get('log.console')(self.sname) self.api.get('log.adddtype')('upgrade') self.api.get('log.console')('upgrade') if not load: testsort = sorted(self.plugins.values(), key=operator.attrgetter('priority')) for i in testsort: try: #check dependencies here self.loadplugin(i) except Exception: # pylint: disable=broad-except self.api.get('send.traceback')( "load: had problems running the load method for %s." \ % i.fullimploc) del sys.modules[i.fullimploc] def updateallplugininfo(self): """ find plugins that are not in self.plugininfo """ _module_list = find_files(self.basepath, '*.py') _module_list.sort() self.plugininfo = {} badplugins = [] for fullpath in _module_list: modpath = fullpath.replace(self.basepath, '') imploc, modname = get_module_name(modpath) if not modname.startswith("_"): fullimploc = "plugins" + '.' + imploc if fullimploc in sys.modules: self.plugininfo[modpath] = {} self.plugininfo[modpath]['sname'] = self.pluginp[ modpath].sname self.plugininfo[modpath]['name'] = self.pluginp[ modpath].name self.plugininfo[modpath]['purpose'] = self.pluginp[ modpath].purpose self.plugininfo[modpath]['author'] = self.pluginp[ modpath].author self.plugininfo[modpath]['version'] = self.pluginp[ modpath].version self.plugininfo[modpath]['modpath'] = modpath self.plugininfo[modpath]['fullimploc'] = fullimploc else: try: _module = __import__(fullimploc) _module = sys.modules[fullimploc] self.plugininfo[modpath] = {} self.plugininfo[modpath]['sname'] = _module.SNAME self.plugininfo[modpath]['name'] = _module.NAME self.plugininfo[modpath]['purpose'] = _module.PURPOSE self.plugininfo[modpath]['author'] = _module.AUTHOR self.plugininfo[modpath]['version'] = _module.VERSION self.plugininfo[modpath]['modpath'] = modpath self.plugininfo[modpath]['fullimploc'] = fullimploc del sys.modules[fullimploc] except Exception: # pylint: disable=broad-except badplugins.append(fullimploc) return badplugins def load_module(self, modpath, basepath, force=False, runload=True): # pylint: disable=too-many-branches """ load a single module """ if basepath in modpath: modpath = modpath.replace(basepath, '') imploc, modname = get_module_name(modpath) if modname.startswith("_"): return False, 'dev' try: fullimploc = "plugins" + '.' + imploc if fullimploc in sys.modules: return sys.modules[fullimploc].SNAME, 'already' self.api.get('send.msg')('importing %s' % fullimploc, self.sname) _module = __import__(fullimploc) _module = sys.modules[fullimploc] self.api.get('send.msg')('imported %s' % fullimploc, self.sname) load = True if 'AUTOLOAD' in _module.__dict__ and not force: if not _module.AUTOLOAD: load = False elif 'AUTOLOAD' not in _module.__dict__: load = False if modpath not in self.plugininfo: self.plugininfo[modpath] = {} self.plugininfo[modpath]['sname'] = _module.SNAME self.plugininfo[modpath]['name'] = _module.NAME self.plugininfo[modpath]['purpose'] = _module.PURPOSE self.plugininfo[modpath]['author'] = _module.AUTHOR self.plugininfo[modpath]['version'] = _module.VERSION self.plugininfo[modpath]['modpath'] = modpath self.plugininfo[modpath]['fullimploc'] = fullimploc if load: if "Plugin" in _module.__dict__: self.add_plugin(_module, modpath, basepath, fullimploc, runload) else: self.api.get('send.msg')('Module %s has no Plugin class' % \ _module.NAME, self.sname) _module.__dict__["proxy_import"] = 1 return _module.SNAME, 'Loaded' else: if fullimploc in sys.modules: del sys.modules[fullimploc] self.api.get('send.msg')( 'Not loading %s (%s) because autoload is False' % \ (_module.NAME, fullimploc), self.sname) return True, 'not autoloaded' except Exception: # pylint: disable=broad-except if fullimploc in sys.modules: del sys.modules[fullimploc] self.api.get('send.traceback')( "Module '%s' refuses to import/load." % fullimploc) return False, 'error' def unload_module(self, fullimploc): """ unload a module """ if fullimploc in sys.modules: _module = sys.modules[fullimploc] try: if "proxy_import" in _module.__dict__: self.api.get('send.client')('unload: unloading %s' % fullimploc) if "unload" in _module.__dict__: try: _module.unload() except Exception: # pylint: disable=broad-except self.api.get('send.traceback')( "unload: module %s didn't unload properly." % fullimploc) if not self.remove_plugin(_module.SNAME): self.api.get('send.client')( 'could not remove plugin %s' % fullimploc) del sys.modules[fullimploc] self.api.get('send.client')("unload: unloaded %s." % fullimploc) except Exception: # pylint: disable=broad-except self.api.get('send.traceback')( "unload: had problems unloading %s." % fullimploc) return False return True def reload_module(self, modname, force=False): """ reload a module """ if modname in self.plugins: plugin = self.plugins[modname] fullimploc = plugin.fullimploc basepath = plugin.basepath modpath = plugin.modpath sname = plugin.sname try: reloaddependents = plugin.reloaddependents except Exception: # pylint: disable=broad-except reloaddependents = False plugin = None if not self.unload_module(fullimploc): return False, '' if modpath and basepath: retval = self.load_module(modpath, basepath, force) if retval and reloaddependents: self.reloaddependents(sname) return retval else: return False, '' def reloaddependents(self, reloadedplugin): """ reload all dependents """ testsort = sorted(self.plugins.values(), key=operator.attrgetter('priority')) for plugin in testsort: if plugin.sname != reloadedplugin: if reloadedplugin in plugin.dependencies: self.api.get('send.msg')('reloading dependent %s of %s' % \ (plugin.sname, reloadedplugin)) plugin.savestate() self.reload_module(plugin.sname, True) def loadplugin(self, plugin): """ check dependencies and run the load function """ self.api.get('send.msg')('loading dependencies for %s' % \ plugin.fullimploc, self.sname) self.loaddependencies(plugin.sname, plugin.dependencies) self.api.get('send.client')("load: loading %s with priority %s" % \ (plugin.fullimploc, plugin.priority)) self.api.get('send.msg')('loading %s (%s: %s)' % \ (plugin.fullimploc, plugin.sname, plugin.name), self.sname) plugin.load() self.api.get('send.client')("load: loaded %s" % plugin.fullimploc) self.api.get('send.msg')('loaded %s (%s: %s)' % \ (plugin.fullimploc, plugin.sname, plugin.name), self.sname) self.api.get('events.eraise')('%s_plugin_loaded' % plugin.sname, {}) self.api.get('events.eraise')('plugin_loaded', { 'plugin': plugin.sname }) def add_plugin(self, module, modpath, basepath, fullimploc, load=True): # pylint: disable=too-many-arguments """ add a plugin to be managed """ module.__dict__["lyntin_import"] = 1 plugin = module.Plugin(module.NAME, module.SNAME, modpath, basepath, fullimploc) plugin.author = module.AUTHOR plugin.purpose = module.PURPOSE plugin.version = module.VERSION try: plugin.priority = module.PRIORITY except AttributeError: pass if plugin.name in self.pluginl: self.api.get('send.msg')('Plugin %s already exists' % plugin.name, self.sname) return False if plugin.sname in self.plugins: self.api.get('send.msg')('Plugin %s already exists' % plugin.sname, self.sname) return False if load: try: #check dependencies here self.loadplugin(plugin) except Exception: # pylint: disable=broad-except self.api.get('send.traceback')( "load: had problems running the load method for %s." \ % fullimploc) del sys.modules[fullimploc] return False self.pluginl[plugin.name] = plugin self.plugins[plugin.sname] = plugin self.pluginm[plugin.sname] = module self.pluginp[modpath] = plugin self.loadedplugins[modpath] = True self.loadedplugins.sync() return True def remove_plugin(self, pluginname): """ remove a plugin """ plugin = None if pluginname in self.plugins: plugin = self.plugins[pluginname] try: plugin.unload() self.api.get('events.eraise')('%s_plugin_unload' % plugin.sname, {}) self.api.get('events.eraise')('plugin_unloaded', { 'name': plugin.sname }) self.api.get('send.msg')('Plugin %s unloaded' % plugin.sname, self.sname, plugin.sname) except Exception: # pylint: disable=broad-except self.api.get('send.traceback')( "unload: had problems running the unload method for %s." \ % plugin.sname) return False del self.plugins[plugin.sname] del self.pluginl[plugin.name] del self.pluginm[plugin.sname] del self.loadedplugins[plugin.modpath] self.loadedplugins.sync() plugin = None return True else: return False # save all plugins def savestate(self): """ save all plugins """ for i in self.plugins: self.plugins[i].savestate() def load(self): """ load various things """ self.load_modules("*.py") parser = argparse.ArgumentParser(add_help=False, description="list plugins") parser.add_argument('-n', "--notloaded", help="list plugins that are not loaded", action="store_true") parser.add_argument( '-c', "--changed", help="list plugins that are load but are changed on disk", action="store_true") parser.add_argument('package', help='the to list', default='', nargs='?') self.api.get('commands.add')('list', self.cmd_list, lname='Plugin Manager', parser=parser) parser = argparse.ArgumentParser(add_help=False, description="load a plugin") parser.add_argument('plugin', help='the plugin to load, don\'t include the .py', default='', nargs='?') self.api.get('commands.add')('load', self.cmd_load, lname='Plugin Manager', parser=parser) parser = argparse.ArgumentParser(add_help=False, description="unload a plugin") parser.add_argument('plugin', help='the plugin to unload', default='', nargs='?') self.api.get('commands.add')('unload', self.cmd_unload, lname='Plugin Manager', parser=parser) parser = argparse.ArgumentParser(add_help=False, description="reload a plugin") parser.add_argument('plugin', help='the plugin to reload', default='', nargs='?') self.api.get('commands.add')('reload', self.cmd_reload, lname='Plugin Manager', parser=parser) self.api.get('commands.default')('list', self.sname) self.api.get('events.register')('savestate', self.savestate, plugin=self.sname) self.api.get('timers.add')('save', self.savestate, 60, nodupe=True, log=False)
class Plugin(BasePlugin): """ a class to manage logging """ def __init__(self, *args, **kwargs): """ init the class """ BasePlugin.__init__(self, *args, **kwargs) self.canreload = False #print('log api.api', self.api.api) #print('log basepath', self.api.BASEPATH) self.savedir = os.path.join(self.api.BASEPATH, 'data', 'plugins', self.sname) self.logdir = os.path.join(self.api.BASEPATH, 'data', 'logs') #print('logdir', self.logdir) try: os.makedirs(self.savedir) except OSError: pass self.dtypes = {} self.sendtoclient = PersistentDict( os.path.join(self.savedir, 'sendtoclient.txt'), 'c') self.sendtoconsole = PersistentDict( os.path.join(self.savedir, 'sendtoconsole.txt'), 'c') self.sendtofile = PersistentDict( os.path.join(self.savedir, 'sendtofile.txt'), 'c') self.currentlogs = {} self.colors = {} self.filenametemplate = '%a-%b-%d-%Y.log' #self.sendtofile['default'] = { #'logdir':os.path.join(self.logdir, 'default'), #'file':'%a-%b-%d-%Y.log', 'timestamp':True #} self.colors['error'] = '@x136' self.api('api.add')('msg', self.api_msg) self.api('api.add')('adddtype', self.api_adddtype) self.api('api.add')('console', self.api_toggletoconsole) self.api('api.add')('file', self.api_toggletofile) self.api('api.add')('client', self.api_toggletoclient) self.api('api.add')('writefile', self.api_writefile) # add some default datatypes self.api('log.adddtype')('default') self.api('log.adddtype')('frommud') self.api('log.adddtype')('startup') self.api('log.adddtype')('shutdown') self.api('log.adddtype')('error') # log some datatypes by default self.api('log.client')('error') self.api('log.console')('error') self.api('log.console')('default') self.api('log.console')('startup') self.api('log.console')('shutdown') def api_writefile(self, dtype, data, stripcolor=False): """ write directly to a file """ if dtype not in self.sendtofile: self.api('%s.file' % self.sname)(dtype) if stripcolor and self.api('api.has')('colors.stripansi'): data = self.api('colors.stripansi')(data) tfile = os.path.join(self.logdir, dtype, time.strftime(self.sendtofile[dtype]['file'], time.localtime())) if not os.path.exists(os.path.join(self.logdir, dtype)): os.makedirs(os.path.join(self.logdir, dtype, 'archive')) if (dtype not in self.currentlogs) or \ (dtype in self.currentlogs and not self.currentlogs[dtype]): self.currentlogs[dtype] = {} self.currentlogs[dtype]['filename'] = tfile self.currentlogs[dtype]['fhandle'] = None elif tfile != self.currentlogs[dtype]['filename']: self.archivelog(dtype) self.currentlogs[dtype]['filename'] = tfile if not self.currentlogs[dtype]['fhandle']: self.currentlogs[dtype]['fhandle'] = \ open(self.currentlogs[dtype]['filename'], 'a') if self.sendtofile[dtype]['timestamp']: tstring = '%s : ' % \ (time.strftime(self.api.timestring, time.localtime())) data = tstring + data if self.api('api.has')('colors.stripansi'): self.currentlogs[dtype]['fhandle'].write( self.api('colors.stripansi')(data) + '\n') else: self.currentlogs[dtype]['fhandle'].write(data + '\n') self.currentlogs[dtype]['fhandle'].flush() return True # add a datatype to the log def api_adddtype(self, datatype): """ add a datatype @Ydatatype@w = the datatype to add this function returns no values""" if datatype not in self.dtypes: self.dtypes[datatype] = True self.sendtoclient[datatype] = False self.sendtoconsole[datatype] = False # process a message, use send.msg instead for the api def api_msg(self, msg, tags=None): """ send a message @Ymsg@w = This message to send @Ydatatype@w = the type to toggle this function returns no values""" senttoconsole = False senttoclient = False ttime = time.strftime(self.api.timestring, time.localtime()) self.logtofile(msg, 'default') for dtag in tags: if dtag and dtag != 'None' \ and dtag != 'default': tstring = '%s - %-10s : ' % (ttime, dtag) timestampmsg = tstring + msg self.logtofile(msg, dtag) if self.api('api.has')('colors.convertcolors') and \ dtag in self.colors: timestampmsg = self.api('colors.convertcolors')( self.colors[dtag] + timestampmsg) if dtag in self.sendtoclient and self.sendtoclient[dtag] and not senttoclient: self.api('send.client')(timestampmsg) senttoclient = True if dtag in self.sendtoconsole and self.sendtoconsole[dtag] and not senttoconsole: print(timestampmsg, file=sys.stderr) senttoconsole = True # archive a log fle def archivelog(self, dtype): """ archive the previous log """ tfile = os.path.split(self.currentlogs[dtype]['filename'])[-1] self.currentlogs[dtype]['fhandle'].close() self.currentlogs[dtype]['fhandle'] = None backupfile = os.path.join(self.logdir, dtype, tfile) backupzipfile = os.path.join(self.logdir, dtype, 'archive', tfile + '.zip') with zipfile.ZipFile(backupzipfile, 'w', zipfile.ZIP_DEFLATED, allowZip64=True) as myzip: myzip.write(backupfile, arcname=self.currentlogs[dtype]['filename']) os.remove(backupfile) # log something to a file def logtofile(self, msg, dtype, stripcolor=True): """ send a message to a log file """ #print('logging', dtype) if dtype in self.sendtofile and self.sendtofile[dtype]['file']: return self.api('%s.writefile'% self.sname)(dtype, msg, stripcolor) return False # toggle logging a datatype to the clients def api_toggletoclient(self, datatype, flag=True): """ toggle a data type to show to clients @Ydatatype@w = the type to toggle, can be multiple (list) @Yflag@w = True to send to clients, false otherwise (default: True) this function returns no values""" if datatype in self.sendtoclient and datatype != 'frommud': self.sendtoclient[datatype] = flag self.api('send.msg')('setting %s to log to client' % \ datatype) self.sendtoclient.sync() # toggle logging datatypes to the clients def cmd_client(self, args): """ toggle datatypes shown to client """ tmsg = [] if args['datatype']: for i in args['datatype']: if i in self.sendtoclient and i != 'frommud': self.sendtoclient[i] = not self.sendtoclient[i] if self.sendtoclient[i]: tmsg.append('sending %s to client' % i) else: tmsg.append('no longer sending %s to client' % i) elif i != 'frommud': tmsg.append('Type %s does not exist' % i) self.sendtoclient.sync() return True, tmsg tmsg.append('Current types going to client') for i in self.sendtoclient: if self.sendtoclient[i]: tmsg.append(i) return True, tmsg # toggle logging a datatype to the console def api_toggletoconsole(self, datatype, flag=True): """ toggle a data type to show to console @Ydatatype@w = the type to toggle @Yflag@w = True to send to console, false otherwise (default: True) this function returns no values""" if datatype in self.sendtoconsole and datatype != 'frommud': self.sendtoconsole[datatype] = flag self.api('send.msg')('setting %s to log to console' % \ datatype, self.sname) self.sendtoconsole.sync() # toggle logging datatypes to the console def cmd_console(self, args): """ log datatypes to the console """ tmsg = [] if args['datatype']: for i in args['datatype']: if i in self.sendtoconsole and i != 'frommud': self.sendtoconsole[i] = not self.sendtoconsole[i] if self.sendtoconsole[i]: tmsg.append('sending %s to console' % i) else: tmsg.append('no longer sending %s to console' % i) elif i != 'frommud': tmsg.append('Type %s does not exist' % i) self.sendtoconsole.sync() return True, tmsg tmsg.append('Current types going to console') for i in self.sendtoconsole: if self.sendtoconsole[i]: tmsg.append(i) return True, tmsg # toggle logging a datatype to a file def api_toggletofile(self, datatype, timestamp=True): """ toggle a data type to show to file @Ydatatype@w = the type to toggle @Yflag@w = True to send to file, false otherwise (default: True) this function returns no values""" if datatype in self.sendtofile: if self.currentlogs[datatype]['fhandle']: self.currentlogs[datatype]['fhandle'].close() self.currentlogs[datatype]['fhandle'] = None del self.sendtofile[datatype] else: self.sendtofile[datatype] = {'file':self.filenametemplate, 'timestamp':timestamp} self.api('send.msg')('setting %s to log to %s' % \ (datatype, self.sendtofile[datatype]['file']), self.sname) self.sendtofile.sync() # toggle a datatype to log to a file def cmd_file(self, args): """ toggle a datatype to log to a file """ tmsg = [] timestamp = True if args['datatype'] != 'list': dtype = args['datatype'] timestamp = args['notimestamp'] if dtype in self.sendtofile: if dtype in self.currentlogs: self.currentlogs[dtype]['fhandle'].close() self.currentlogs[dtype]['fhandle'] = None del self.sendtofile[dtype] tmsg.append('removing %s from logging' % dtype) else: self.sendtofile[dtype] = {'file':self.filenametemplate, 'logdir':os.path.join(self.logdir, dtype), 'timestamp':timestamp} tmsg.append('setting %s to log to %s' % \ (dtype, self.sendtofile[dtype]['file'])) self.sendtofile.sync() return True, tmsg else: tmsg.append('Current types going to file') for i in self.sendtofile: if self.sendtofile[i]: tmsg.append('%s - %s - %s' % \ (i, self.sendtofile[i]['file'], self.sendtofile[i]['timestamp'])) return True, tmsg # archive a datatype def cmd_archive(self, args): """ archive a datatype """ tmsg = [] if args: for i in args: if i in self.dtypes: self.archivelog(i) else: tmsg.append('%s does not exist' % i) return True, tmsg tmsg = ['Please specifiy a datatype to archive'] return False, tmsg # show all types def cmd_types(self, args): """ list data types """ tmsg = [] tmsg.append('Data Types') tmsg.append('-' * 30) match = args['match'] tkeys = self.dtypes.keys() tkeys.sort() for i in tkeys: if not match or match in i: tmsg.append(i) return True, tmsg def logmud(self, args): """ log all data from the mud """ if 'frommud' in self.sendtofile and self.sendtofile['frommud']['file']: if args['eventname'] == 'from_mud_event': data = args['noansi'] elif args['eventname'] == 'to_mud_event': data = 'tomud: ' + args['data'].strip() self.logtofile(data, 'frommud', stripcolor=False) return args def load(self): """ load external stuff """ BasePlugin.load(self) #print('log api before adding', self.api.api) #print('log api after adding', self.api.api) self.api('events.register')('from_mud_event', self.logmud) self.api('events.register')('to_mud_event', self.logmud) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) parser = argp.ArgumentParser(add_help=False, description="""\ toggle datatypes to clients if no arguments, data types that are currenty sent to clients will be listed""") parser.add_argument('datatype', help='a list of datatypes to toggle', default=[], nargs='*') self.api('commands.add')('client', self.cmd_client, lname='Logger', parser=parser) parser = argp.ArgumentParser(add_help=False, description="""\ toggle datatype to log to a file the file will be located in the data/logs/<dtype> directory the filename for the log will be <date>.log Example: Tue-Feb-26-2013.log if no arguments, types that are sent to file will be listed""") parser.add_argument('datatype', help='the datatype to toggle', default='list', nargs='?') parser.add_argument("-n", "--notimestamp", help="do not log to file with a timestamp", action="store_false") self.api('commands.add')('file', self.cmd_file, lname='Logger', parser=parser) parser = argp.ArgumentParser(add_help=False, description="""\ toggle datatypes to the console if no arguments, data types that are currenty sent to the console will be listed""") parser.add_argument('datatype', help='a list of datatypes to toggle', default=[], nargs='*') self.api('commands.add')('console', self.cmd_console, lname='Logger', parser=parser) parser = argp.ArgumentParser(add_help=False, description="list all datatypes") parser.add_argument('match', help='only list datatypes that have this argument in their name', default='', nargs='?') self.api('commands.add')('types', self.cmd_types, lname='Logger', parser=parser) #print('log loaded') def _savestate(self, _=None): """ save items not covered by baseplugin class """ self.sendtoclient.sync() self.sendtofile.sync() self.sendtoconsole.sync()
class Plugin(AardwolfBasePlugin): """ a plugin to handle aardwolf cp events """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.savecpfile = os.path.join(self.savedir, 'cp.txt') self.cpinfo = PersistentDict(self.savecpfile, 'c') self.mobsleft = [] self.cpinfotimer = {} self.nextdeath = False self.api('dependency.add')('cmdq') self.api('api.add')('oncp', self.api_oncp) self.api('api.add')('mobsleft', self.api_cpmobsleft) def load(self): """ load the plugins """ AardwolfBasePlugin.load(self) self.api('cmdq.addcmdtype')('cpcheck', 'campaign check', "^campaign check$", beforef=self.cpcheckbefore, afterf=self.cpcheckafter) parser = argp.ArgumentParser(add_help=False, description='show cp info') self.api('commands.add')('show', self.cmd_show, parser=parser) parser = argp.ArgumentParser(add_help=False, description='refresh cp info') self.api('commands.add')('refresh', self.cmd_refresh, parser=parser) self.api('watch.add')('cp_check', '^(cp|campa|campai|campaig|campaign) (c|ch|che|chec|check)$') self.api('triggers.add')('cpnew', "^Commander Barcett tells you " \ "'Type 'campaign info' to see what you must kill.'$") self.api('triggers.add')('cpnone', "^You are not currently on a campaign.$", enabled=False, group='cpcheck', omit=True) self.api('triggers.add')('cptime', "^You have (?P<time>.*) to finish this campaign.$", enabled=False, group='cpcheck', omit=True) self.api('triggers.add')('cpmob', r"^You still have to kill \* (?P<mob>.*) " \ r"\((?P<location>.*?)(?P<dead> - Dead|)\)$", enabled=False, group='cpcheck', omit=True) self.api('triggers.add')('cpscramble', "Note: One or more target names in this " \ "campaign might be slightly scrambled.$", enabled=False, group='cpcheck', omit=True) self.api('triggers.add')('cpneedtolevel', "^You will have to level before you" \ " can go on another campaign.$", enabled=False, group='cpin') self.api('triggers.add')('cpcantake', "^You may take a campaign at this level.$", enabled=False, group='cpin') self.api('triggers.add')('cpshnext', "^You cannot take another campaign for (?P<time>.*).$", enabled=False, group='cpin') self.api('triggers.add')('cpmobdead', "^Congratulations, that was one of your CAMPAIGN mobs!$", enabled=False, group='cpin') self.api('triggers.add')('cpcomplete', "^CONGRATULATIONS! You have completed your campaign.$", enabled=False, group='cpin') self.api('triggers.add')('cpclear', "^Campaign cleared.$", enabled=False, group='cpin') self.api('triggers.add')('cpreward', r"^\s*Reward of (?P<amount>\d+) (?P<type>.+) .+ added.$", enabled=False, group='cprew', argtypes={'amount':int}) self.api('triggers.add')('cpcompdone', "^--------------------------" \ "------------------------------------$", enabled=False, group='cpdone') self.api('events.register')('trigger_cpnew', self._cpnew) self.api('events.register')('trigger_cpnone', self._cpnone) self.api('events.register')('trigger_cptime', self._cptime) #self.api('events.register')('watch_cp_check', self._cpcheckcmd) self.api('events.register')('trigger_cpmob', self._cpmob) self.api('events.register')('trigger_cpneedtolevel', self._cpneedtolevel) self.api('events.register')('trigger_cpcantake', self._cpcantake) self.api('events.register')('trigger_cpshnext', self._cpshnext) self.api('events.register')('trigger_cpmobdead', self._cpmobdead) self.api('events.register')('trigger_cpcomplete', self._cpcomplete) self.api('events.register')('trigger_cpclear', self._cpclear) self.api('events.register')('trigger_cpreward', self._cpreward) self.api('events.register')('trigger_cpcompdone', self._cpcompdone) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) def api_oncp(self): """ return if we are on a cp """ return self.cpinfo['oncp'] def api_cpmobsleft(self): """ return the list of cp mobs left """ return copy.copy(self.mobsleft) def cmd_show(self, _=None): """ show the cp mobs """ msg = [] if self.cpinfo['oncp']: msg.append('Mobs left:') msg.append('%-40s %s' % ('Mob Name', 'Area/Room')) msg.append('@G' + '-' * 60) for i in self.mobsleft: color = '@w' if i['mobdead']: color = '@R' msg.append('%s%-40s %s' % (color, i['name'], i['location'])) else: msg.append('You are not on a cp') return True, msg def cmd_refresh(self, _=None): """ cmd to refresh cp info """ msg = [] if self.cpinfo['oncp']: msg.append('Refreshing cp mobs') self.api('cmdq.addtoqueue')('cpcheck', '') else: msg.append('You are not on a cp') return True, msg def cpcheckbefore(self): """ function to run before send the command """ self.mobsleft = [] self.cpinfotimer = {} self.api('triggers.togglegroup')('cpcheck', True) self.api('cmdq.cmdstart')('cpcheck') def cpcheckafter(self): """ function to run after the command is finished """ self.api('triggers.togglegroup')("cpin", True) self.api('triggers.togglegroup')('cpcheck', False) def afterfirstactive(self, _=None): """ do something on connect """ AardwolfBasePlugin.afterfirstactive(self) self.api('cmdq.addtoqueue')('cpcheck', '') def _cpreset(self): """ reset the cp """ self.cpinfo.clear() self.cpinfo['mobs'] = {} self.cpinfo['trains'] = 0 self.cpinfo['pracs'] = 0 self.cpinfo['gold'] = 0 self.cpinfo['tp'] = 0 self.cpinfo['qp'] = 0 self.cpinfo['bonusqp'] = 0 self.cpinfo['failed'] = 0 self.cpinfo['level'] = self.api('aardu.getactuallevel')( self.api('GMCP.getv')('char.status.level')) self.cpinfo['starttime'] = time.time() self.cpinfo['finishtime'] = 0 self.cpinfo['oncp'] = True self.cpinfo['cantake'] = False self.cpinfo['shtime'] = None self.savestate() def _cpnew(self, args=None): """ handle a new cp """ self.api('send.msg')('cpnew: %s' % args) self._cpreset() self.api('cmdq.addtoqueue')('cpcheck', '') def _cpnone(self, _=None): """ handle a none cp """ self.api('send.msg')('cpnone') self.cpinfo['oncp'] = False self.savestate() self.api('triggers.togglegroup')('cpcheck', False) self.api('triggers.togglegroup')('cpin', False) self.api('triggers.togglegroup')('cprew', False) self.api('triggers.togglegroup')('cpdone', False) self.cpinfotimer = {} self.api('cmdq.cmdfinish')('cpcheck') def _cptime(self, _=None): """ handle cp time """ self.api('send.msg')('handling cp time') self.api('send.msg')('%s' % self.cpinfo) if not self.cpinfo['mobs']: self.api('send.msg')('copying mobsleft') self.cpinfo['mobs'] = self.mobsleft[:] self.api('events.eraise')('aard_cp_mobsorig', copy.deepcopy({'mobsleft':self.mobsleft})) self.savestate() self.api('send.msg')('raising aard_cp_mobsleft %s' % self.mobsleft) self.api('events.eraise')('aard_cp_mobsleft', copy.deepcopy({'mobsleft':self.mobsleft})) self.api('cmdq.cmdfinish')('cpcheck') def _cpneedtolevel(self, _=None): """ handle cpneedtolevel """ self.cpinfo['cantake'] = False self.savestate() def _cpcantake(self, _=None): """ handle cpcantake """ self.cpinfo['cantake'] = True self.savestate() def _cpshnext(self, args=None): """ handle cpshnext """ self.cpinfo['shtime'] = args['time'] self.savestate() def _cpmob(self, args=None): """ handle cpmob """ name = args['mob'] mobdead = self.api('utils.verify')(args['dead'], bool) location = args['location'] if not name or not location: self.api('send.msg')("error parsing line: %s" % args['line']) else: self.mobsleft.append({'name':name, 'nocolorname':self.api('colors.stripansi')(name), 'location':location, 'mobdead':mobdead}) def _cpmobdead(self, _=None): """ handle cpmobdead """ self.api('events.register')('aard_mobkill', self._mobkillevent) #self.api('send.execute')("cp check") def _cpcomplete(self, _=None): """ handle cpcomplete """ self.api('triggers.togglegroup')('cprew', True) self.cpinfo['finishtime'] = time.time() self.cpinfo['oncp'] = False self.savestate() def _cpreward(self, args=None): """ handle cpreward """ rtype = args['type'] ramount = int(args['amount']) rewardt = self.api('aardu.rewardtable')() self.cpinfo[rewardt[rtype]] = ramount self.savestate() self.api('triggers.togglegroup')('cpdone', True) def _cpcompdone(self, _=None): """ handle cpcompdone """ self.api('events.register')('trigger_all', self._triggerall) def _triggerall(self, args=None): """ check to see if we have the bonus qp message """ if 'first campaign completed today' in args['line']: mat = re.match(r'^You receive (?P<bonus>\d*) quest points bonus ' \ r'for your first campaign completed today.$', args['line']) self.cpinfo['bonusqp'] = int(mat.groupdict()['bonus']) self.api('events.unregister')('trigger_all', self._triggerall) self.api('events.eraise')('aard_cp_comp', copy.deepcopy(self.cpinfo)) elif re.match(r"^You have completed (\d*) campaigns today.$", args['line']): self.api('events.unregister')('trigger_all', self._triggerall) self.api('events.eraise')('aard_cp_comp', copy.deepcopy(self.cpinfo)) def _cpclear(self, _=None): """ handle cpclear """ self.cpinfo['failed'] = 1 self.api('events.eraise')('aard_cp_failed', copy.deepcopy(self.cpinfo)) self._cpnone() def _cpcheckcmd(self, args=None): """ handle when we get a cp check """ self.mobsleft = [] self.cpinfotimer = {} self.api('triggers.togglegroup')('cpcheck', True) return args def _mobkillevent(self, args): """ this will be registered to the mobkill hook """ self.api('send.msg')('checking kill %s' % args['name']) self.api('events.unregister')('aard_mobkill', self._mobkillevent) found = False removeitem = None for i in range(len(self.mobsleft)): tmob = self.mobsleft[i] if tmob['name'] == args['name']: self.api('send.msg')('found %s' % tmob['name']) found = True removeitem = i if removeitem: del self.mobsleft[removeitem] if found: self.api('events.eraise')('aard_cp_mobsleft', copy.deepcopy({'mobsleft':self.mobsleft})) else: self.api('send.msg')("BP CP: could not find mob: %s" % args['name']) self.api('cmdq.addtoqueue')('cpcheck', '') def _savestate(self, _=None): """ save states """ self.cpinfo.sync()
class Plugin(AardwolfBasePlugin): """ a plugin that does spellups """ def __init__(self, *args, **kwargs): """ initialize the instance """ AardwolfBasePlugin.__init__(self, *args, **kwargs) self.spellupfile = os.path.join(self.savedir, 'spellups.txt') self.spellups = PersistentDict(self.spellupfile, 'c') self.api('dependency.add')('aardwolf.skills') self.api('dependency.add')('aardwolf.move') self.initspellups() self.lastmana = -1 self.lastmoves = -1 def load(self): """ load the plugins """ AardwolfBasePlugin.load(self) self.api('setting.add')('enabled', True, bool, 'auto spellup is enabled') self.api('setting.add')('waiting', -1, int, 'the spell that was just cast', readonly=True) self.api('setting.add')('nocast', False, bool, 'in a nocast room', readonly=True) self.api('setting.add')('nomoves', False, bool, 'need more moves', readonly=True) self.api('setting.add')('nomana', False, bool, 'need more mana', readonly=True) self.api('setting.add')('nocastrooms', {}, dict, 'list of nocast rooms', readonly=True) self.api('setting.add')('currentroom', -1, int, 'the current room', readonly=True) parser = argp.ArgumentParser( add_help=False, description='add a spellup to the self list') parser.add_argument( 'spell', help='the spells to add, use \'all\' to add all practiced spellups', default=[], nargs='*') parser.add_argument( '-o', "--override", help="add even if the spell is not flagged as a spellup by the mud", action="store_true") self.api('commands.add')('add', self.cmd_sadd, parser=parser, group='Spellups on Self') parser = argp.ArgumentParser(add_help=False, description='list spellups for self') parser.add_argument( 'match', help='list only spellups that have this argument in them', default='', nargs='?') self.api('commands.add')('list', self.cmd_slist, parser=parser, group='Spellups on Self') parser = argp.ArgumentParser( add_help=False, description='remove a spellup from the self list') parser.add_argument( 'spell', help='the spells to remove, use \'all\' to remove all spellups', default=[], nargs='*') self.api('commands.add')('rem', self.cmd_srem, parser=parser, group='Spellups on Self') parser = argp.ArgumentParser(add_help=False, description='enable spellups on self') parser.add_argument( 'spell', help='the spells to enable, use \'all\' to enable all spellups', default=[], nargs='*') self.api('commands.add')('en', self.cmd_en, parser=parser, group='Spellups on Self') parser = argp.ArgumentParser(add_help=False, description='disable spells on self') parser.add_argument( 'spell', help='the spells to disable, use \'all\' to disable all spellups', default=[], nargs='*') self.api('commands.add')('dis', self.cmd_dis, shelp='disable a spellup on self', parser=parser, group='Spellups on Self') self.api('commands.add')('check', self.cmd_check, shelp='check data status for casting', group='Spellups on Self') self.api('events.register')('GMCP:char.vitals', self._charvitals) self.api('events.register')('GMCP:char.status', self._charstatus) self.api('events.register')('moved_room', self._moved) self.api('events.register')('skill_fail', self._skillfail) self.api('events.register')('aard_skill_affon', self._affon) self.api('events.register')('aard_skill_affoff', self._affoff) self.api('events.register')('aard_skill_recoff', self._recoff) self.api('events.register')('aard_skill_gain', self.skillgain) self.api('events.register')('var_su_enabled', self.enabledchange) self.api('events.register')('skills_affected_update', self.nextspell) self.api('events.register')('plugin_%s_savestate' % self.sname, self._savestate) self.api('events.register')('skills_uptodate', self.nextspell) def skillgain(self, args=None): """ check skills when we gain them """ if args['sn'] in self.spellups['sorder'] and args['percent'] > 50: self.nextspell() def initspellups(self): """ initialize the spellups dictionary """ if 'sorder' not in self.spellups: self.spellups['sorder'] = [] if 'self' not in self.spellups: self.spellups['self'] = {} if 'oorder' not in self.spellups: self.spellups['oorder'] = [] if 'other' not in self.spellups: self.spellups['other'] = {} def enabledchange(self, args): """ do something when enabled is changed """ if args['newvalue']: self.nextspell() def _affon(self, args): """ catch an affon event """ if args['sn'] == self.api('setting.gets')('waiting'): self.api('setting.change')('waiting', -1) self.nextspell() def _affoff(self, _=None): """ catch an affoff event """ self.nextspell() def _recoff(self, _=None): """ catch a recoff event """ self.nextspell() def _skillfail(self, args): # pylint: disable=too-many-branches """ catch a skill fail event """ self.api('send.msg')('skillfail: %s' % args) spellnum = args['sn'] skill = self.api('skills.gets')(spellnum) waiting = self.api('setting.gets')('waiting') if args['reason'] == 'nomana': self.api('setting.change')('waiting', -1) self.api('setting.change')('nomana', True) self.lastmana = self.api('GMCP.getv')('char.vitals.mana') elif args['reason'] == 'nocastroom': self.api('setting.change')('waiting', -1) self.api('setting.change')('nocast', True) nocastrooms = self.api('setting.gets')('nocastrooms') currentroom = self.api('setting.gets')('currentroom') nocastrooms[currentroom] = True elif args['reason'] == 'fighting' or args['reason'] == 'notactive': self.api('setting.change')('waiting', -1) elif args['reason'] == 'nomoves': self.api('setting.change')('waiting', -1) self.api('setting.change')('nomoves', True) self.lastmana = self.api('GMCP.getv')('char.vitals.moves') elif waiting == spellnum: if args['reason'] == 'lostconc': self.api('skills.sendcmd')(waiting) elif args['reason'] == 'alreadyaff': self.api('setting.change')('waiting', -1) self.api('send.client')( "@BSpellup - disabled %s because you are already affected" % \ skill['name']) if spellnum in self.spellups['self']: self.spellups['self'][spellnum]['enabled'] = False #if spellnum in self.spellups['other']: #self.spellups['other'][spellnum]['enabled'] = False self.nextspell() elif args['reason'] == 'recblock': # do stuff when blocked by a recovery self.api('setting.change')('waiting', -1) self.nextspell() elif args['reason'] == 'dontknow': # do stuff when spell/skill isn't learned # don't disable it, hopefully the spell/skill has been updated and # won't be cast through nextspell self.api('setting.change')('waiting', -1) self.nextspell() elif args['reason'] == 'wrongtarget': # do stuff when a wrong target self.api('setting.change')('waiting', -1) self.nextspell() elif args['reason'] == 'disabled': self.api('setting.change')('waiting', -1) skill = self.api('skills.gets')(spellnum) self.api('send.client')( "@BSpellup - disabled %s because it is disabled mudside" % \ skill['name']) if spellnum in self.spellups['self']: self.spellups['self'][spellnum]['enabled'] = False if spellnum in self.spellups['other']: self.spellups['other'][spellnum]['enabled'] = False self.nextspell() def _moved(self, args): """ reset stuff if we move """ self.api('setting.change')('currentroom', args['to']['num']) nocastrooms = self.api('setting.gets')('nocastrooms') if args['to']['num'] in nocastrooms: self.api('setting.change')('nocast', True) else: lastval = self.api('setting.gets')('nocast') self.api('setting.change')('nocast', False) if lastval: self.nextspell() def _charvitals(self, _=None): """ check if we have more mana and moves """ if self.api('setting.gets')('nomana'): newmana = self.api('GMCP.getv')('char.vitals.mana') if newmana > self.lastmana: self.lastmana = -1 self.api('setting.change')('nomana', False) self.nextspell() if self.api('setting.gets')('nomoves'): newmoves = self.api('GMCP.getv')('char.vitals.moves') if newmoves > self.lastmoves: self.lastmoves = -1 self.api('setting.change')('nomoves', False) self.nextspell() def _charstatus(self, _=None): """ check if we have more mana and moves """ status = self.api('GMCP.getv')('char.status.state') if status == 3 and self.api('skills.isuptodate')(): self.nextspell() @timeit def check(self, _=None): """ check to cast the next spell """ mud = self.api('managers.getm')('mud') if not mud or not mud.connected: return False self.api('send.msg')('waiting type: %s' % \ type(self.api('setting.gets')('waiting'))) self.api('send.msg')('currentstatus = %s' % \ self.api('GMCP.getv')('char.status.state')) # pylint: disable=too-many-boolean-expressions if self.api('setting.gets')('nomoves') \ or self.api('setting.gets')('nomana') \ or self.api('setting.gets')('nocast') \ or self.api('setting.gets')('waiting') != -1 \ or not self.api('setting.gets')('enabled') \ or not self.api('skills.isuptodate')() or \ self.api('GMCP.getv')('char.status.state') != 3: self.api('send.msg')('checked returned False') return False self.api('send.msg')('checked returned True') return True @timeit def nextspell(self, _=None): """ try to cast the next spell """ self.api('send.msg')('nextspell') if self.check(): for i in self.spellups['sorder']: if self.spellups['self'][i]['enabled']: if self.api('skills.canuse')(i): self.api('setting.change')('waiting', int(i)) self.api('skills.sendcmd')(i) return def _savestate(self, _=None): """ save states """ self.spellups.sync() def _addselfspell(self, spellnum, place=-1, override=False): """ add a spell internally """ msg = [] spell = self.api('skills.gets')(spellnum) if not spell: msg.append('%-20s: does not exist' % spellnum) return msg if not override and not self.api('skills.isspellup')(spell['sn']): msg.append('%-20s: not a spellup' % spell['name']) return msg if spell['sn'] in self.spellups['sorder']: msg.append('%-30s: already activated' % spell['name']) return msg self.spellups['self'][spell['sn']] = {'enabled': True} if place > -1: self.spellups['sorder'].insert(place, spell['sn']) else: self.spellups['sorder'].append(spell['sn']) msg.append('%-20s: place %s' % \ (spell['name'], self.spellups['sorder'].index(spell['sn']))) return msg def cmd_sadd(self, args): """ add a spellup """ msg = [] if len(args['spell']) < 1: return False, ['Please supply a spell'] if args['spell'][0] == 'all': spellups = self.api('skills.getspellups')() for spell in spellups: if spell['percent'] > 1: tmsg = self._addselfspell(spell['sn']) msg.extend(tmsg) self.nextspell() else: for aspell in args['spell']: tspell = aspell place = -1 if ':' in aspell: tlist = aspell.split(':') tspell = tlist[0] place = int(tlist[1]) tmsg = self._addselfspell(tspell, place, args['override']) msg.extend(tmsg) self.nextspell() self.spellups.sync() return True, msg def cmd_slist(self, args): """ list the spellups """ msg = [] match = args['match'] if self.spellups['sorder']: msg.append('%-3s - %-30s : %2s %2s %2s %2s %-2s %-2s' % \ ('Num', 'Name', 'A', 'P', 'B', 'D', 'NP', 'NL')) msg.append('@B' + '-' * 60) for i in self.spellups['sorder']: skill = self.api('skills.gets')(i) if not skill: msg.append('%-3s: please check the skills plugin' % \ (self.spellups['sorder'].index(i))) elif not match or match in skill['name']: msg.append('%-3s - %-30s : %2s %2s %2s %2s %-2s %-2s' % \ (self.spellups['sorder'].index(i), skill['name'], 'A' if self.api('skills.isaffected')(i) else '', 'P' if self.api('setting.gets')('waiting') == i else '', 'B' if self.api('skills.isblockedbyrecovery')(i) else '', 'D' if not self.spellups['self'][i]['enabled'] else '', 'NP' if skill['percent'] == 1 else '', 'NL' if skill['percent'] == 0 else '',)) else: msg.append('There are no spellups') return True, msg def cmd_srem(self, args): """ remove a spellup """ if len(args['spell']) < 1: return True, ['Please supply a spell/skill to remove'] msg = [] if args['spell'][0].lower() == 'all': del self.spellups['sorder'] del self.spellups['self'] self.initspellups() msg.append('All spellups to be cast on self cleared') else: for spella in args['spell']: spell = self.api('skills.gets')(spella) if not spell: msg.append('%s does not exist' % spella) continue spellnum = spell['sn'] if spellnum in self.spellups['sorder']: self.spellups['sorder'].remove(spellnum) if spellnum in self.spellups['self']: del self.spellups['self'][spellnum] msg.append('Removed %s from spellups to self' % spell['name']) self.savestate() return True, msg def cmd_en(self, args): """ enable a spellup """ if len(args['spell']) < 1: return True, ['Please supply a spell/skill to enable'] msg = [] if args['spell'][0].lower() == 'all': for i in self.spellups['self']: self.spellups['self'][i]['enabled'] = True msg.append('All spellups enabled') self.nextspell() return True, msg for spellnum in args['spell']: skill = self.api('skills.gets')(spellnum) if skill: if skill['sn'] in self.spellups['sorder']: self.spellups['self'][skill['sn']]['enabled'] = True msg.append('%s: enabled' % skill['name']) else: msg.append('%s: not in self spellup list' % skill['name']) else: msg.append('%s: could not find spell' % spellnum) self.nextspell() return True, msg def cmd_dis(self, args): """ enable a spellup """ if len(args['spell']) < 1: return True, ['Please supply a spell/skill to enable'] msg = [] if args['spell'][0].lower() == 'all': for i in self.spellups['self']: self.spellups['self'][i]['enabled'] = False msg.append('All spellups disabled') return True, msg for spellnum in args['spell']: skill = self.api('skills.gets')(spellnum) if skill: if skill['sn'] in self.spellups['sorder']: self.spellups['self'][skill['sn']]['enabled'] = False msg.append('%s: disabled' % skill['name']) else: msg.append('%s: not in self spellup list' % skill['name']) else: msg.append('%s: could not find spell' % spellnum) return True, msg def cmd_check(self, _=None): """ list all items that are need for spellups and whether they are known """ tmsg = [] tformat = '%-25s : %-10s - %s' tmsg.append(tformat % \ ('enabled', self.api('setting.gets')('enabled'), 'should be True to cast spells')) tmsg.append(tformat % \ ('waiting', self.api('setting.gets')('waiting'), 'the spell that was last cast, should be -1 to cast spells')) tmsg.append(tformat % \ ('nocast', self.api('setting.gets')('nocast'), 'the current room is nocast, should be False to cast spells')) tmsg.append(tformat % \ ('nomoves', self.api('setting.gets')('nomoves'), 'ran out of moves, should be False to cast spells')) tmsg.append(tformat % \ ('nomana', self.api('setting.gets')('nomana'), 'ran out of mana, should be False to cast spells')) tmsg.append(tformat % \ ('Skills are up to date', self.api('skills.isuptodate')(), 'should be True to cast spells')) tmsg.append(tformat % \ ('Char state', self.api('GMCP.getv')('char.status.state'), 'should be 3 to cast spells')) return True, tmsg def reset(self): """ reset all spellups """ AardwolfBasePlugin.reset(self) self.spellups.clear() self.initspellups() self.spellups.sync()