def __init__(self, parent, args): self._skillMaxHealPoints = None self._seen = 0 super(_SkillHealer, self).__init__(parent, args) skillId = args.setdefault('id', "UNKNOWN") try: self.id = int(skillId) except ValueError: raise FatalError("{}: Invalid skill id: {}".format( self.parent.id, skillId)) if 'required_mp' not in args: try: skill = getSkillFromId(str(self.id), parent.session) args['required_mp'] = skill['mpCost'] except kol.Error.Error: args['required_mp'] = "UNKNOWN" try: self._mpCost = int(args['required_mp']) except ValueError: raise FatalError("{}: Invalid mp cost: {}".format( self.parent.id, args['required_mp'])) try: self.typicalCasts = int( args.setdefault('typical_number_casts', '1')) except ValueError: raise FatalError("{}: Invalid typical casts: {}".format( self.parent.id, args['typical_number_casts']))
def _configure(self, config): try: self._minPoints = int(config.setdefault('min_points_to_win', 1)) self._killPoints = int(config.setdefault('kills', 1)) self._bossPoints = int(config.setdefault('boss', 1)) self._machinePoints = int(config.setdefault('machine_assist', 10)) except ValueError: raise FatalError("DreadPointsModule: kills, boss, min_points " "must be integers") try: self._drunkPoints = float(config.setdefault('drunk', 0.01)) except ValueError: raise FatalError("DreadPointsModule: drunk must be float") self._keyUnlocks = config.setdefault( 'keys', { 'Attic': 25, 'Fire Tower': 25, 'Suite': 25, 'School': 25, 'Lab': 25, 'Ballroom': 25 }) self._codePts = config.setdefault('codes', {}) self._regexPts = config.setdefault('regex', {}) try: self._keyUnlocks = {k: int(v) for k, v in self._keyUnlocks.items()} self._codePts = {k: int(v) for k, v in self._codePts.items()} self._regexPts = {k: int(v) for k, v in self._regexPts.items()} except ValueError: raise FatalError("DreadPointsModule: points " "must be integers")
def _loadConfig(self, configFile): """ Load ini file and parse some values from it """ self._log.debug("Loading config file...") try: c = ConfigObj(configFile, configspec=StringIO(MODULE_SPEC), list_values=False, raise_errors=True, create_empty=True) passed = c.validate(Validator(), copy=True, preserve_errors=True) except ParseError as e: raise FatalError("Parse error in modules.ini:{}: \"{}\"".format( e.line_number, e.line)) if passed != True: f = flatten_errors(c, passed) error1 = f[0] raise FatalError( "Invalid module configuration. First error " "found in section [{}], key \"{}\". Error: {}".format( '/'.join(error1[0]), error1[1], error1[2])) self._overWriteConfig = c['overwrite_config'] self._config = c with open(configFile) as f: txt = f.read() self._saveConfig(configFile, txt) self._chatDelay = c['system']['communication_interval'] self._log.debug("{} loaded.".format(configFile)) return txt
def _configure(self, config): for k, v in config.items(): if isinstance(v, dict): modeStr = v.setdefault('mode', 'cycle').lower() periodStr = v.setdefault('period', 1440) try: period = int(periodStr) except ValueError: raise FatalError( "Invalid period specified: {}".format(periodStr)) offsetStr = v.setdefault('offset', 'random') try: offset = int(offsetStr) except ValueError: if offsetStr.lower() != "random": raise FatalError( ("Invalid offset: {}, must be " "integer or 'random'").format(offsetStr)) else: offset = random.randint(0, period) try: mode = self._modes[modeStr] except IndexError: raise FatalError( "Invalid mode specified: {}".format(modeStr)) channels = stringToList(v.setdefault('channel', 'clan,')) messages = {} for key_, val_ in v.items(): if key_.lower().startswith("message"): try: keyVal = "message{:06d}".format(int(key_[7:])) except ValueError: raise FatalError(("Invalid message name: {}; " "messages must be message1, " "message2, ...").format(key_)) messages[keyVal] = val_ self._messages[k] = { 'mode': mode, 'period': period, 'channels': channels, 'messages': messages, 'offset': offset, 'order': [], 'index': 0, 'hard': True, 'last': 0, 'expires': 0, 'description': "" }
def _configure(self, config): try: self._notifyPercent = map(int, stringToList( config.setdefault('update-percent', "25,50,75,90,100"))) except ValueError: raise FatalError("update-percent must be a list of integers") try: self._perror = float(config.setdefault("p_error", "0.001")) if not 0 < self._perror < 1: raise ValueError() except ValueError: raise FatalError("p_error must be a float between 0 and 1")
def _buff(self, uid, buff): n = buff['casts'] cost = buff['mp_cost'] mpRequired = n * cost r2 = StatusRequest(self.session) d2 = self.tryRequest(r2) mpBefore = int(d2['mp']) self.log("Preparing to cast buff {} (requires {} mp)" .format(buff['description'], mpRequired)) if mpBefore < mpRequired: try: self.debugLog("Requesting healing from module {}" .format(self._healer)) replies = self._raiseEvent("heal", self._healer, {'type': 'mp', 'points': mpRequired, 'percent': self._mpMax}) healResult = replies[-1].data mpBefore = healResult['mp'] except IndexError: raise FatalError("Invalid healer {}".format(self._healer)) self.log("Casting skill {} x{}".format(buff['id'], n)) r1 = UseSkillRequest(self.session, str(buff['id']), n, uid) _d1 = self.tryRequest(r1, numTries=1) r2 = StatusRequest(self.session) d2 = self.tryRequest(r2) mpAfter = int(d2['mp']) self.log("Used {} mp. (Now at {}/{})" .format(mpBefore - mpAfter, mpAfter, d2['maxmp'])) return mpBefore - mpAfter
def _processLog(self, raidlog): events = raidlog['events'] self._userAdventures = {} self._properUserNames = {} for e in events: zone = e['db-match'].get('zone') user = _nameKey(e['userName']) if e['category'] != "Miscellaneous": self._userAdventures.setdefault(user, []) self._properUserNames[user] = e['userName'] if zone in self._choiceLocations: self._userAdventures[user].append(e['db-match']) try: replies = self._raiseEvent("dread", "dread-overview", data={ 'style': 'dict', 'keys': ['status'] }) self._dread = replies[0].data except IndexError: raise FatalError("DreadChoicesModule requires a " "DreadOverviewModule with higher priority") return True
def __init__(self, manager, identity, config): super(WarbearBlackboxModule, self).__init__(manager, identity, config) self.inventoryManager.refreshInventory() inventory = self.inventoryManager.inventory() blackBoxes = inventory.get(7035, 0) if blackBoxes == 0: raise FatalError("No warbear black box in inventory.")
def __init__(self, parent, args): minHeal = args.setdefault('only_heal_over', 0) try: self._minHealAmount = int(minHeal) except ValueError: raise FatalError("{}: Invalid only_heal_over value: {}".format( self.parent.id, minHeal)) self.parent = weakref.proxy(parent)
def _initialize(self): if self._modules: raise FatalError("WalkieTalkieRepeater cannot use modules.") if "__numchanges__" in self._persist: self._numChanges = self._persist["__numchanges__"] lastKey = self._persist.get('__lastKey__', None) if lastKey != self._key: self._changeFrequencies(self._numChanges) self._playerDb = defaultdict(lambda: [None] * len(self._otherBots))
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 initialize(self, state, initData): self._db = initData['event-db'] lockedSubzones = set(record['subzone'] for record in self._db if record['zone'] == "(unlock)") keySubzones = set(self._keyUnlocks.keys()) if lockedSubzones != keySubzones: missing = lockedSubzones.difference(keySubzones) if missing: raise FatalError( "DreadPointsModule: no 'keys' entry for '{}'".format( missing.pop())) extra = keySubzones.difference(lockedSubzones) if extra: raise FatalError( "DreadPointsModule: no such locked area '{}'".format( extra.pop())) self._grantedPoints = state['granted'] self._processLog(initData)
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 __init__(self, parent, name, iData, config): """ Initialize the manager """ self._playerDb = None self._numChanges = 0 self._ready = False self._otherBots = None self._myFreq = None self._numPlayersForFreqChange = None self._freqChangeTimeout = None self._format, self._emoteFormat = None, None super(WalkieTalkieRepeater, self).__init__(parent, name, iData, config) self._invMan.refreshInventory() self._lastOutsiderCheck = 0 self._changeFreqRequests = {} inventory = self._invMan.inventory() numTalkies = inventory.get(6846, 0) if numTalkies == 0: numUnusedTalkies = inventory.get(6845, 0) if numUnusedTalkies > 0: try: r = UseItemRequest(self._s, 6845) d = tryRequest(r) numTalkies = 1 except Error: raise FatalError("Could not use unused walkie talkie.") else: raise FatalError("Cannot use WalkieTalkieRepeater with " "no walkie talkie!") replies = self.sendChatMessage("/kenneth", None, waitForReply=True, raw=True) for reply in replies: txt = reply['text'] freq = re.search(r"The frequency is (\d+.\d), Mr. Rather", txt) if freq: self._myFreq = freq.group(1) self._log.info("My walkie talkie frequency is {}".format( freq.group(1))) if self._myFreq is None: raise RuntimeError("Could not determine walkie talkie frequency.") self._ready = 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 _processLog(self, raidlog): try: replies = self._raiseEvent("dread", "dread-overview", data={ 'style': "dict", 'keys': ['status', 'locked'] }) self._dread = replies[0].data except IndexError: raise FatalError("DreadKeyModule requires a DreadOverviewModule " "with higher priority") return True
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): BaseChatManager._configure(self, config) try: otherBots = stringToList(config.setdefault('other_bots', "none")) self._otherBots = map(int, otherBots) except ValueError: raise FatalError("Error configuring WalkieTalkieRepeater: " "other_bots must be list of integers (userIds)") try: self._numPlayersForFreqChange = int( config.setdefault('num_players_to_change', 3)) self._freqChangeTimeout = int( config.setdefault('change_timeout', 10)) except ValueError: raise FatalError("Error configuring WalkieTalkieRepeater: " "num_players_to_change and change_timeout must " "be integral") self._format = config.setdefault('format', "[[%username%]] %text%") self._emoteFormat = config.setdefault('emote_format', "[[%username% %text%]]") self._key = str(config.setdefault('key', random.randint(0, 999999))) if self._key.strip() == "": config['key'] = random.randint(0, 999999) self._key = str(config['key'])
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 _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 _integerize(map_, keyname, defaultval, desc): try: map_[keyname] = int(map_.setdefault(keyname, defaultval)) except ValueError: raise FatalError("Invalid value for key '{}' in {}: {}" .format(keyname, desc, map_[keyname]))