def __init__(self, parent, args): super(_LuciferHealer, self).__init__(parent, args) self.extHealer = toTypeOrNone( args.setdefault('external_healer', 'none'), str) try: self.maxFull = toTypeOrNone(args.setdefault('max_full', 'none'), int) except ValueError: raise FatalError("Invalid max_full value for Lucifer: {}".format( args['max_full'])) self.buyFromMall = stringToBool(args.setdefault('use_mall', 'true'))
def __init__(self, parent, args): super(_LuciferHealer, self).__init__(parent, args) self.extHealer = toTypeOrNone( args.setdefault('external_healer', 'none'), str) try: self.maxFull = toTypeOrNone(args.setdefault('max_full', 'none'), int) except ValueError: raise FatalError("Invalid max_full value for Lucifer: {}" .format(args['max_full'])) self.buyFromMall = stringToBool(args.setdefault('use_mall', 'true'))
def __init__(self, parent, args): self._itemMaxHealPoints = None self._seen = 0 super(_ItemHealer, self).__init__(parent, args) itemId = args.setdefault('id', "UNKNOWN") try: self.id = int(itemId) except ValueError: raise FatalError("{}: Invalid item id: {}".format( self.parent.id, itemId)) self.buyFrom = toTypeOrNone(args.setdefault('buy_from', "none"), str)
def __init__(self, parent, args): self._itemMaxHealPoints = None self._seen = 0 super(_ItemHealer, self).__init__(parent, args) itemId = args.setdefault('id', "UNKNOWN") try: self.id = int(itemId) except ValueError: raise FatalError("{}: Invalid item id: {}" .format(self.parent.id, itemId)) self.buyFrom = toTypeOrNone(args.setdefault('buy_from', "none"), str)
def _processLog(self, raidlog): events = raidlog['events'] # get dread status try: replies = self._raiseEvent("dread", "dread-overview", data={'style': 'dict', 'keys': ['status', 'index', 'locked']}) self._dread = replies[0].data except IndexError: raise FatalError("DreadUniquesModule requires a " "DreadOverviewModule with higher priority") newClaimed = defaultdict(list) userNames = {} for record in self._uniques: itemTxt = record['unique_text'] quantity = toTypeOrNone(record['quantity'], int) if quantity is None: quantity = 1 # see how many items were taken and who did it itemsAcquired = 0 logMessage = "" for e in eventDbMatch(events, record): logMessage = e['event'] newClaimed[itemTxt].extend([e['userId']] * e['turns']) userNames[e['userId']] = e['userName'] itemsAcquired += e['turns'] # compare to old list and announce if specified in the options if self._claimed is not None: # count up which users got this log message c1 = Counter(self._claimed.get(itemTxt, [])) c2 = Counter(newClaimed.get(itemTxt, [])) for k,v in c2.items(): # iterate through each user numCollected = v - c1[k] # print a pickup message for each time user X got item # should be only once for dreadsylvania for _ in range(numCollected): self.chat("{} {} ({} remaining)." .format(userNames[k], logMessage, quantity - itemsAcquired)) self._claimed = newClaimed return True
def _configure(self, config): self._daysUntilBoot = int(config.setdefault('boot_after_days', 180)) safeRanks = stringToList( config.setdefault('safe_ranks', "rank1, rank2")) safeTitles = stringToList( config.setdefault('safe_titles', "DO NOT DELETE, " "DO NOT ERASE")) self._safeRanks = map(_rankTransform, safeRanks) self._safeTitles = map(_rankTransform, safeTitles) self._bootMessage = toTypeOrNone( config.setdefault('boot_message', "none")) self._simulate = stringToBool(config.setdefault('simulate', "false")) self._immediate = stringToBool( config.setdefault('run_immediately', "false")) try: self._bootFrequencyDays = int( config.setdefault('boot_every_n_days', 1)) except ValueError: raise FatalError("ClanRankModule: boot_every_n_days must " "be integral") rules = config.setdefault( 'rules', { 'Normal Member': { 'demotion_allowed': "false", 'min_karma': 0, 'min_days_until_next_promotion': 7, 'min_days_in_clan': 0, 'next_rank': 'Rank2' }, 'Rank2': { 'demotion_allowed': "true", 'min_karma': 0, 'min_days_until_next_promotion': 0, 'min_days_in_clan': 0, 'next_rank': "none" } }) for rule in rules.values(): rule.setdefault('demotion_allowed', True) rule.setdefault('min_karma', 0) rule.setdefault('min_days_until_next_promotion', 0) rule.setdefault('min_days_in_clan', 0) rule.setdefault('next_rank', "none") self._ruleConfig = rules
def _configure(self, config): self._hpMethods = [] self._mpMethods = [] self._hp = config.setdefault('hp', {'external_mp_healer': 'none', '1': {'type': 'skill', 'id': 3012, 'required_mp': 20, 'only_heal_over': 116}, '2': {'type': 'skill', 'required_mp': 12, 'id': 3009}, '3': {'type': 'galaktik', 'method': 'ointment'}, '4': {'type': 'rest'}}) self._mp = config.setdefault('mp', {'1': {'type': 'item', 'buy_from': 'none', 'id': 1687, 'only_heal_over': 100}, '2': {'type': 'lucifer', 'external_healer': 'none', 'max_full': 'none', 'only_heal_over': 100}, '3': {'type': 'item', 'buy_from': '2', 'id': 518}, '4': {'type': 'item', 'buy_from': 'l', 'id': 2639}, '5': {'type': 'item', 'buy_from': 'k', 'id': 344}, '6': {'type': 'galaktik', 'method': 'tonic'}}) self._extMp = None extMp = toTypeOrNone(self._hp['external_mp_healer'], str) if extMp is not None: self._extMp = "__" + extMp.lower() + "__" hpPriorities = dict((int(k), v) for k,v in self._hp.items() if k.isdigit()) mpPriorities = dict((int(k), v) for k,v in self._mp.items() if k.isdigit()) for p in sorted(hpPriorities.keys()): self._hpMethods.append(self._createHealer(hpPriorities[p])) for p in sorted(mpPriorities.keys()): self._mpMethods.append(self._createHealer(mpPriorities[p]))
def _sendBuffKmail(self, message): txt = "The following buffs are available:\n" spellList = set(v['id'] for v in self._buffs.values()) for sid in spellList: matches = [(k,v) for k,v in self._buffs.items() if v['id'] == sid and v['cost'] > 0] matches.sort(key=lambda x: x[1]['cost']) for k,v in matches: desc = toTypeOrNone(v['description']) if desc is None: desc = "{} castings of {}".format(v['casts'], k) lim = v['daily_limit'] limTxt = "" if lim == 0 else " ({} per day)".format(lim) cost = v['cost'] txt += "\n{} meat for {}{}".format(cost, desc, limTxt) txt += "\n" m = self.newMessage(message.uid, txt) return m
def _getUniqueData(self, typeList): for record in self._uniques: if record['unique_type'] not in typeList: continue itemData = self._dread[record['category']] if itemData['status'] in ["done", "boss"]: continue quantity = toTypeOrNone(record['quantity'], int) if quantity is None: quantity = 1 itemName = record['unique_text'] numAvailable = (quantity - len(self._claimed[itemName])) if numAvailable <= 0: continue isLocked = (record['subzone'] in itemData['locked']) yield (record, numAvailable, isLocked)
def _sendBuffKmail(self, message): txt = "The following buffs are available:\n" spellList = set(v['id'] for v in self._buffs.values()) for sid in spellList: matches = [(k,v) for k,v in self._buffs.items() if v['id'] == sid and v['cost'] > 0] matches.sort(key=lambda x: x[1]['cost']) for k,v in matches: desc = toTypeOrNone(v['description']) if desc is None: desc = "{} castings of {}".format(v['casts'], k) lim = v['daily_limit'] limTxt = "" if lim == 0 else " ({} per day)".format(lim) cost = v['cost'] txt += "\n{} meat for {}{}".format(cost, desc, limTxt) txt += "\n" m = self.newMessage(message.uid, txt) return m
def _addModules(self, config): """ Dynamically import the modules specified in modules.ini. This should not be overridden. """ base = config['base'] # loop through modules for k,v in config.items(): if isinstance(v, dict): cfg = v perm = toTypeOrNone(v['permission'], str) priority = v['priority'] clanOnly = v['clan_only'] # import class try: ModuleClass = easyImportClass(base, v['type']) except ImportError: raise FatalError("Error importing module/class {0} " "from base {1}. Either the module does " "not exist, or there was an error. To " "check for errors, use the command line " "'python -m {1}.{0}'; the actual path " "may vary." .format(v['type'], base)) self._modules.append(ModuleEntry( ModuleClass, priority, perm, clanOnly, self, k, cfg)) # sort by decreasing priority self._modules.sort(key=lambda x: -x.priority) self._log.info("---- {} creating module instances... ----" .format(self.identity)) for m in self._modules: self._log.info("Creating {0.className} with priority " "{0.priority}, permission {0.permission}." .format(m)) try: m.createInstance() except TypeError as e: self._log.exception("Error!") raise FatalError("Error instantiating class {}: {}" .format(m.className, e.args[0])) self._log.info("---- All modules created. ----")
def _addModules(self, config): """ Dynamically import the modules specified in modules.ini. This should not be overridden. """ base = config['base'] # loop through modules for k, v in config.items(): if isinstance(v, dict): cfg = v perm = toTypeOrNone(v['permission'], str) priority = v['priority'] clanOnly = v['clan_only'] # import class try: ModuleClass = easyImportClass(base, v['type']) except ImportError: raise FatalError("Error importing module/class {0} " "from base {1}. Either the module does " "not exist, or there was an error. To " "check for errors, use the command line " "'python -m {1}.{0}'; the actual path " "may vary.".format(v['type'], base)) self._modules.append( ModuleEntry(ModuleClass, priority, perm, clanOnly, self, k, cfg)) # sort by decreasing priority self._modules.sort(key=lambda x: -x.priority) self._log.info("---- {} creating module instances... ----".format( self.identity)) for m in self._modules: self._log.info( "Creating {0.className} with priority " "{0.priority}, permission {0.permission}.".format(m)) try: m.createInstance() except TypeError as e: self._log.exception("Error!") raise FatalError("Error instantiating class {}: {}".format( m.className, e.args[0])) self._log.info("---- All modules created. ----")
def _configure(self, config): self._buffs = {} self._used = {} healer = toTypeOrNone(config.setdefault('healer', "none"), str) if healer is not None: healer = "__" + healer + "__" self._healer = healer try: self._mpMax = int(config.setdefault('restore_mp_to_percent', 80)) except ValueError: raise FatalError("Invalid restore_mp_to_percent: {}".format( config['restore_mp_to_percent'])) buffs = config.setdefault( 'buffs', { 'The Ode To Booze': { 'id': 6014, 'cost': 1, 'casts': 1, 'daily_limit': 2, 'outfit': 'none' } }) for k, v in buffs.items(): _integerize(v, 'id', "UNKNOWN", k) _integerize(v, 'cost', "UNKNOWN", k) _integerize(v, 'casts', "UNKNOWN", k) _integerize(v, 'daily_limit', "0", k) v.setdefault('outfit', "none") v.setdefault('description', "none") try: if "mp_cost" not in v: skill = getSkillFromId(str(v['id']), self.session) v['mp_cost'] = skill['mpCost'] else: _integerize(v, 'mp_cost', "UNKNOWN", k) except kol.Error.Error: _integerize(v, 'mp_cost', "UNKNOWN", k) self._buffs[k] = v priceList = [v['cost'] for v in self._buffs.values() if v['cost'] > 0] if len(priceList) != len(set(priceList)): raise FatalError("Duplicate buff prices for module {}".format( self.id))
def _configure(self, config): self._buffs = {} self._used = {} healer = toTypeOrNone(config.setdefault('healer', "none"), str) if healer is not None: healer = "__" + healer + "__" self._healer = healer try: self._mpMax = int(config.setdefault('restore_mp_to_percent', 80)) except ValueError: raise FatalError("Invalid restore_mp_to_percent: {}" .format(config['restore_mp_to_percent'])) buffs = config.setdefault('buffs', {'The Ode To Booze': { 'id': 6014, 'cost': 1, 'casts': 1, 'daily_limit': 2, 'outfit': 'none'}}) for k,v in buffs.items(): _integerize(v, 'id', "UNKNOWN", k) _integerize(v, 'cost', "UNKNOWN", k) _integerize(v, 'casts', "UNKNOWN", k) _integerize(v, 'daily_limit', "0", k) v.setdefault('outfit', "none") v.setdefault('description', "none") try: if "mp_cost" not in v: skill = getSkillFromId(str(v['id']), self.session) v['mp_cost'] = skill['mpCost'] else: _integerize(v, 'mp_cost', "UNKNOWN", k) except kol.Error.Error: _integerize(v, 'mp_cost', "UNKNOWN", k) self._buffs[k] = v priceList = [v['cost'] for v in self._buffs.values() if v['cost'] > 0] if len(priceList) != len(set(priceList)): raise FatalError("Duplicate buff prices for module {}" .format(self.id))
def _equipForBuff(self, buff): outfitName = toTypeOrNone(buff['outfit'], str) if outfitName is None: return equipCustomOutfitByName(self.session, outfitName)
def _configure(self, config): self._buffer = toTypeOrNone(config.setdefault('buff_module', 'none')) buffList = config.setdefault('buffs', {}) self._buffs = dict( (k.strip().lower(), v.strip()) for k, v in buffList.items())
def _configure(self, config): self._buffer = toTypeOrNone(config.setdefault('buff_module', 'none')) buffList = config.setdefault('buffs', {}) self._buffs = dict((k.strip().lower(), v.strip()) for k,v in buffList.items())
def _finishInitialization(self): # get list of clan members (both in whitelist and roster) self.log("Initializing ranks...") r1 = ClanWhitelistRequest(self.session) d1 = self.tryRequest(r1) self._ranks = { _rankTransform(rank['rankName']): rank for rank in d1['ranks'] } r2 = StatusRequest(self.session) d2 = self.tryRequest(r2) self._rolloverTime = int(d2['rollover']) # load promotion rules self._promotionRules = {} for rankname, rule in self._ruleConfig.items(): key = _rankTransform(rankname) nextRankName = toTypeOrNone(rule['next_rank']) nextkey = _rankTransform(nextRankName) if nextRankName else None nextRankId = self._ranks.get(nextkey, {}).get('rankId') if key not in self._ranks: raise FatalError( "Invalid clan rank: {} (available ranks: {})".format( key, ", ".join(self._ranks.keys()))) if nextkey is not None and nextkey not in self._ranks: raise FatalError( "Invalid clan rank: {} (available ranks: {})".format( nextkey, ", ".join(self._ranks.keys()))) try: self._promotionRules[self._ranks[key]['rankId']] = ({ 'demotionAllowed': stringToBool(rule['demotion_allowed']), 'minKarma': int(rule['min_karma']), 'minDaysBeforePromotion': int(rule['min_days_until_next_promotion']), 'minDaysInClan': int(rule['min_days_in_clan']), 'nextRankId': nextRankId, 'rankName': rankname }) except ValueError: raise "ClanRankModule: error parsing rank {}".format(rankname) # pick a random time to run today assumedExecTime = 7200 latestPossibleExecTime = self._rolloverTime - assumedExecTime if time.time() < self._lastRun: self.log("Already performed ranking today.") elif time.time() > latestPossibleExecTime: self.log("Too late to run rankings today.") else: if self._immediate: self._execTime = int(time.time()) + 15 else: self._execTime = random.randint(int(time.time()), latestPossibleExecTime) self.log("Running rankings in {} minutes.".format( int((self._execTime - time.time()) / 60)))
def _configure(self, config): self._hpMethods = [] self._mpMethods = [] self._hp = config.setdefault( 'hp', { 'external_mp_healer': 'none', '1': { 'type': 'skill', 'id': 3012, 'required_mp': 20, 'only_heal_over': 116 }, '2': { 'type': 'skill', 'required_mp': 12, 'id': 3009 }, '3': { 'type': 'galaktik', 'method': 'ointment' }, '4': { 'type': 'rest' } }) self._mp = config.setdefault( 'mp', { '1': { 'type': 'item', 'buy_from': 'none', 'id': 1687, 'only_heal_over': 100 }, '2': { 'type': 'lucifer', 'external_healer': 'none', 'max_full': 'none', 'only_heal_over': 100 }, '3': { 'type': 'item', 'buy_from': '2', 'id': 518 }, '4': { 'type': 'item', 'buy_from': 'l', 'id': 2639 }, '5': { 'type': 'item', 'buy_from': 'k', 'id': 344 }, '6': { 'type': 'galaktik', 'method': 'tonic' } }) self._extMp = None extMp = toTypeOrNone(self._hp['external_mp_healer'], str) if extMp is not None: self._extMp = "__" + extMp.lower() + "__" hpPriorities = dict( (int(k), v) for k, v in self._hp.items() if k.isdigit()) mpPriorities = dict( (int(k), v) for k, v in self._mp.items() if k.isdigit()) for p in sorted(hpPriorities.keys()): self._hpMethods.append(self._createHealer(hpPriorities[p])) for p in sorted(mpPriorities.keys()): self._mpMethods.append(self._createHealer(mpPriorities[p]))
def _equipForBuff(self, buff): outfitName = toTypeOrNone(buff['outfit'], str) if outfitName is None: return equipCustomOutfitByName(self.session, outfitName)
def _processCommand(self, unused_msg, cmd, unused_args): if cmd in ["unique", "uniques"]: if not self._dungeonActive() or self._claimed is None: return ("Dreadsylvania has faded into the mist, along with " "all its stuff. Don't you just hate when that " "happens?") messages = {} lockedTxt = {True: "LOCKED ", False: ""} areaItems = defaultdict(list) for record,available,locked in self._getUniqueData(['pencil', 'unique', 'uncommon']): areaItems[record['category']].append( (record, available,locked)) for k,v in areaItems.items(): itemTxt = [] for record,available,locked in v: quantity = toTypeOrNone(record['quantity'], int) if quantity is None: quantity = 1 txt = "" if quantity > 1: txt += "{}x ".format(available) txt += lockedTxt[locked] txt += record['unique_text'] itemTxt.append(txt) messages[k] = "({}) {}".format(k[4:], ", ".join(itemTxt)) # get list of areas by index areas = dict((v['index'], k) for k,v in self._dread.items()) txtSegments = [] for idx in sorted(areas.keys()): areaname = areas[idx] if areaname in messages: txtSegments.append(messages[areaname]) txt = ["; ".join(txtSegments)] if txtSegments else [] # show FKs fkTxt = [] for record,available,locked in self._getUniqueData(['fk']): fkTxt.append("{} {}x{}".format(record['zone'], lockedTxt[locked], available)) if fkTxt: txt.append("FKs available: {}".format(", ".join(fkTxt))) if txt: return "\n".join(txt) return ("Looks like adventurers have combed over Dreadsylvania " "pretty well.") if cmd in ["pencil", "pencils"]: if not self._dungeonActive() or self._claimed is None: return ("Dreadsylvania has dissappeared once again, along " "with its ghost pencil factory. You probably can't " "find them in stores anymore.") pencils = list(self._getUniqueData(['pencil'])) if not pencils: return ("All the ghost pencils are gone. Now nobody can do " "their ghost homework assignment from ghost math " "class.") (_,available,locked) = pencils[0] if locked: return "The schoolhouse is still locked." return "{} pencils available.".format(available) return None