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') 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(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()