def initTotals(self, events): """ get total tires/avalanches """ self._totalTires = 0 self._totalAvalanches = 0 # detect number of avalanches self._totalAvalanches = sum( a['turns'] for a in eventDbMatch(events, {'bb_code': "avalanche"})) self._totalTires = sum( t['turns'] for t in eventDbMatch(events, {'bb_code': "tire"})) self.log("Detected {} avalanches".format(self._totalAvalanches)) self.log("Detected {} tire tosses".format(self._totalTires))
def initTotals(self, events): """ get total tires/avalanches """ self._totalTires = 0 self._totalAvalanches = 0 # detect number of avalanches self._totalAvalanches = sum(a['turns'] for a in eventDbMatch(events, {'bb_code': "avalanche"})) self._totalTires = sum(t['turns'] for t in eventDbMatch(events, {'bb_code': "tire"})) self.log("Detected {} avalanches".format(self._totalAvalanches)) self.log("Detected {} tire tosses".format(self._totalTires))
def initialize(self, state, initData): events = initData['events'] self._db = initData['event-db'] self._chatStrings = { d['heap_code']: d['chat'] for d in self._db if d['heap_code'] } self._unstenchStrings = [ d['chat'] for d in self._db if d['heap_code'] == "unstench" ] self._heapDone = False self._open = state['open'] self._numDives = sum( d['turns'] for d in eventDbMatch(events, {'heap_code': "dive"})) self._totalStench = ( 4 + sum(t['turns'] for t in eventDbMatch(events, {'heap_code': "trashcano"})) + sum(t['turns'] for t in eventDbMatch(events, {'heap_code': "stench"})) - sum(f['turns'] for f in eventDbMatch(events, {'heap_code': "unstench"}))) self._initStench = self._totalStench self.log("OldDives: {}, NewDives: {}".format(state['dives'], self._numDives)) self.log("Detected {} trashcanos".format(self._totalStench - 4)) if state['dives'] == self._numDives and state['stench'] is not None: # there have been no trashcanos since we went online # add stench difference self._stench = (state['stench'] + self._totalStench - state['totalstench']) self.log("Restored stench state to {}".format(self._stench)) elif (state['dives'] != self._numDives and state['totalstench'] == self._totalStench): # there has been a dive, but no other trashcanos self._stench = 0 self.log("Restored stench state to 0, dives present without " "any more stench") else: # there have been dives and more trashcanos self._stench = None self.log("...but it doesn't matter because we can't " "tell when the last treasure dive was") self._heapLastNotify = self._stench self._processLog(initData)
def _processLog(self, raidlog): events = raidlog['events'] if self.getCageState() in [UNKNOWN, EMPTY]: # don't know cage status self._inCageFreedTime = None else: if self._updateInCageActions: self._updateInCageActions = False self._inCageHoboActions = self.getHoboActions( self.inCage, events) self.log("{} action count = {}".format( self.inCage, self._inCageHoboActions)) # check if cage occupant has adventured in hobopolis currentHoboActions = self.getHoboActions(self.inCage, events) if currentHoboActions != self._inCageHoboActions: self.log("Detected {} escape: {} -> {}" .format(self.inCage, self._inCageHoboActions, currentHoboActions)) self.chat("{} has left the C.H.U.M. cage.".format(self.inCage)) self.setEscaped() # check sewer actions newTotalFreed = sum( f['turns'] for f in eventDbMatch( events, {'sewer_code': "rescue"})) if newTotalFreed > self._totalFreed and self.getCageState() == TRAPPED: self.setReleased(self.inCage) self._totalFreed = newTotalFreed self._totalSewerActions = sum( s['turns'] for s in events if s['category'] == "Sewers") return True
def initialize(self, state, initData): events = initData['events'] # see number of scarehobos killed self._killed = sum(k['turns'] for k in eventDbMatch( events, {'town_code': "combat"})) self._scareHoboDamage = state['damage'] killDiff = self._killed - state['killed'] # let's see if any scarehobos look like they were created # (indicated by a decrease in parts) self._guessState = state['scareHoboState'] if killDiff > 50: # we missed some hobo activity, let's say the state is guessed # for good measure self._guessState = GUESSED self._scareHoboParts = self.getParts() if self._scareHoboParts is None: # usually, this only happens if we are in between instances self._scareHoboParts = state['scareHoboParts'] self._guessState = GUESSED scareHobos = scareHobosCreated(state['scareHoboParts'], self._scareHoboParts) self._scareHoboDamage = state['damage'] if scareHobos > 0: guessText = "" if self._guessState == GUESSED: guessText = " (changing state to GUESSED)" self.log("Detected {} scarehobos ({} -> {}) {}" .format(scareHobos, state['scareHoboParts'], self._scareHoboParts, guessText)) self._scareHoboDamage += 8 * scareHobos self._initialized = True self._processLog(initData)
def _processLog(self, raidlog): events = raidlog['events'] if self.getCageState() in [UNKNOWN, EMPTY]: # don't know cage status self._inCageFreedTime = None else: if self._updateInCageActions: self._updateInCageActions = False self._inCageHoboActions = self.getHoboActions( self.inCage, events) self.log("{} action count = {}".format( self.inCage, self._inCageHoboActions)) # check if cage occupant has adventured in hobopolis currentHoboActions = self.getHoboActions(self.inCage, events) if currentHoboActions != self._inCageHoboActions: self.log("Detected {} escape: {} -> {}".format( self.inCage, self._inCageHoboActions, currentHoboActions)) self.chat("{} has left the C.H.U.M. cage.".format(self.inCage)) self.setEscaped() # check sewer actions newTotalFreed = sum( f['turns'] for f in eventDbMatch(events, {'sewer_code': "rescue"})) if newTotalFreed > self._totalFreed and self.getCageState() == TRAPPED: self.setReleased(self.inCage) self._totalFreed = newTotalFreed self._totalSewerActions = sum(s['turns'] for s in events if s['category'] == "Sewers") return True
def initialize(self, state, initData): events = initData['events'] # see number of scarehobos killed self._killed = sum( k['turns'] for k in eventDbMatch(events, {'town_code': "combat"})) self._scareHoboDamage = state['damage'] killDiff = self._killed - state['killed'] # let's see if any scarehobos look like they were created # (indicated by a decrease in parts) self._guessState = state['scareHoboState'] if killDiff > 50: # we missed some hobo activity, let's say the state is guessed # for good measure self._guessState = GUESSED self._scareHoboParts = self.getParts() if self._scareHoboParts is None: # usually, this only happens if we are in between instances self._scareHoboParts = state['scareHoboParts'] self._guessState = GUESSED scareHobos = scareHobosCreated(state['scareHoboParts'], self._scareHoboParts) self._scareHoboDamage = state['damage'] if scareHobos > 0: guessText = "" if self._guessState == GUESSED: guessText = " (changing state to GUESSED)" self.log("Detected {} scarehobos ({} -> {}) {}".format( scareHobos, state['scareHoboParts'], self._scareHoboParts, guessText)) self._scareHoboDamage += 8 * scareHobos self._initialized = True self._processLog(initData)
def _getNewEvents(self, events): t1 = time.time() newEvents = [] # first, get a list of all db entries and players dbEntries = [] players = set() for e in events: if e['db-match'] not in dbEntries: dbEntries.append(e['db-match']) players.add(e['userId']) # now, loop over all players and db entries for dbm in dbEntries: # skip unmatched events if not dbm: continue matchingDoneEvents = list( eventDbMatch(itertools.chain.from_iterable(self._snapshots), dbm)) matchingNewEvents = list(eventDbMatch(events, dbm)) for uid in players: matchesUser = lambda x: x['userId'] == uid playerEvents = filter(matchesUser, matchingNewEvents) doneEvents = filter(matchesUser, matchingDoneEvents) playerTotalEvents = sum(pe['turns'] for pe in playerEvents) doneTotalEvents = sum(de['turns'] for de in doneEvents) eventDiff = playerTotalEvents - doneTotalEvents if eventDiff < 0: self._log.warn("Snapshot: {}\nevents: {}".format( self._snapshots, events)) raise RuntimeError("Error: detected {} events but " "{} in snapshot for user {} and " "db entry {}".format( playerTotalEvents, doneTotalEvents, uid, dbm)) if eventDiff > 0: newEvent = deepcopy(playerEvents[0]) newEvent['turns'] = eventDiff newEvents.append(newEvent) self.debugLog("Built new DB entries in {} seconds".format(time.time() - t1)) return newEvents
def _processLog(self, raidlog): events = raidlog['events'] # first: check number of dances available # = 5 * flim-flams - dances so far # also see who has danced so far. self._watches = { w['userName']: w['turns'] for w in eventDbMatch(events, {'ahbg_code': "watch"}) } self._dances = { w['userName']: w['turns'] for w in eventDbMatch(events, {'ahbg_code': "dance"}) } self._availableDances = ( 5 * sum(f['turns'] for f in eventDbMatch(events, {'ahbg_code': "flimflam"})) - sum(f['turns'] for f in eventDbMatch(events, {'ahbg_code': "dance"})) - sum(f['turns'] for f in eventDbMatch(events, {'ahbg_code': "watch"})) - sum(f['turns'] for f in eventDbMatch(events, {'ahbg_code': "fail"}))) # any player in hobopolis is added to watch list for hoboplayer in set(item['userName'] for item in events if 'userName' in item): if hoboplayer not in self._watches: self._watches[hoboplayer] = 0 self._killed = ( sum(k['turns'] for k in eventDbMatch(events, { 'ahbg_code': "combat", })) - 9 * sum(t['turns'] for t in eventDbMatch(events, {'ahbg_code': "tomb"}))) self._ahbgDone = any(eventDbMatch(events, {'ahbg_code': "boss"})) if not self._open: if any( eventDbMatch( events, {'category': "The Ancient Hobo Burial Ground"})): self._open = True return True
def _processLog(self, raidlog): events = raidlog['events'] #check hot hobos killed (negative for hot door opened) # = defeated - 8 * hot doors opened self._hobosKilled = ( sum(k['turns'] for k in eventDbMatch(events, {'bb_code': "combat"})) - 8 * sum(d['turns'] for d in eventDbMatch(events, {'bb_code': "door"}))) # if Ol' Scratch is dead, set burnbarrel to finished self._bbDone = any(eventDbMatch(events, {'bb_code': "boss"})) if (self._hobosKilled > 0 or self._totalTires > 0 or self._totalAvalanches > 0): self._open = True return True
def _processLog(self, raidlog): events = raidlog['events'] #check hot hobos killed (negative for hot door opened) # = defeated - 8 * hot doors opened self._hobosKilled = ( sum(k['turns'] for k in eventDbMatch( events, {'bb_code': "combat"})) - 8 * sum(d['turns'] for d in eventDbMatch( events, {'bb_code': "door"}))) # if Ol' Scratch is dead, set burnbarrel to finished self._bbDone = any(eventDbMatch(events, {'bb_code': "boss"})) if (self._hobosKilled > 0 or self._totalTires > 0 or self._totalAvalanches > 0): self._open = True return True
def initialize(self, state, initData): events = initData['events'] self._db = initData['event-db'] self._chatStrings = { d['sewer_code']: d['chat'] for d in self._db if d['sewer_code'] } self._totalFreed = sum( f['turns'] for f in eventDbMatch(events, {'sewer_code': "rescue"})) self._startupSewerActions = sum(s['turns'] for s in events if s['category'] == "Sewers") self.debugLog("Detected {} sewer actions at startup".format( self._startupSewerActions)) self.inCage = state['inCage'] self._inCageHoboActions = state['inCageHoboActions'] self._inCageFreedTime = state['inCageFreedTime'] if self.inCage is None: # previously unknown self.setUnknown() elif self.inCage == "": # nobody was in cage, but now we can't tell anymore. self.log("Restored from empty cage state, setting to unknown...") self.setUnknown() elif self._inCageFreedTime is not None: # somebody was previously in the cage, but freed if (self.getHoboActions(self.inCage, events) != self._inCageHoboActions): # they've adventured self.log("Player {} was freed and adventured in Hobopolis. " "Setting to unknown...".format(self.inCage)) self.setUnknown() else: # everything is the same! pass else: # somebody was in the cage but not freed if self._totalFreed != state['totalFreed']: # they have been freed! if (self.getHoboActions(self.inCage, events) != self._inCageHoboActions): # and they've stayed put! self.log("Player {} was freed and has not adventured " "in Hobopolis. Setting to freed...".format( self.inCage)) self.setReleased(self.inCage) else: # they've moved. we have no idea of cage state self.log("Player {} was freed and adventured in Hobopolis." " Setting to unknown...".format(self.inCage)) self.setUnknown() else: # everything is the same pass
def initialize(self, state, initData): events = initData['events'] self._db = initData['event-db'] self._chatStrings = {d['sewer_code']: d['chat'] for d in self._db if d['sewer_code']} self._totalFreed = sum( f['turns'] for f in eventDbMatch( events, {'sewer_code': "rescue"})) self._startupSewerActions = sum( s['turns'] for s in events if s['category'] == "Sewers") self.debugLog("Detected {} sewer actions at startup" .format(self._startupSewerActions)) self.inCage = state['inCage'] self._inCageHoboActions = state['inCageHoboActions'] self._inCageFreedTime = state['inCageFreedTime'] if self.inCage is None: # previously unknown self.setUnknown() elif self.inCage == "": # nobody was in cage, but now we can't tell anymore. self.log("Restored from empty cage state, setting to unknown...") self.setUnknown() elif self._inCageFreedTime is not None: # somebody was previously in the cage, but freed if (self.getHoboActions(self.inCage, events) != self._inCageHoboActions): # they've adventured self.log("Player {} was freed and adventured in Hobopolis. " "Setting to unknown...".format(self.inCage)) self.setUnknown() else: # everything is the same! pass else: # somebody was in the cage but not freed if self._totalFreed != state['totalFreed']: # they have been freed! if (self.getHoboActions(self.inCage, events) != self._inCageHoboActions): # and they've stayed put! self.log("Player {} was freed and has not adventured " "in Hobopolis. Setting to freed..." .format(self.inCage)) self.setReleased(self.inCage) else: # they've moved. we have no idea of cage state self.log("Player {} was freed and adventured in Hobopolis." " Setting to unknown...".format(self.inCage)) self.setUnknown() else: # everything is the same pass
def correctDamage(self, events, damage): """ adjust damage if any areas are open but we "think" they are not. make sure to do this AFTER accounting for scarehobos """ minDamage = 0 if any(eventDbMatch(events, {'town_code': "stage"})): minDamage = 1500 + 100 * max(0, self._stageClears - 1) elif any(eventDbMatch(events, {'pld_code': "combat"})): minDamage = 1250 elif any(eventDbMatch(events, {'ahbg_code': "combat"})): minDamage = 1000 elif any(eventDbMatch(events, {'heap_code': "combat"}, {'heap_code': "trashcano"})): minDamage = 750 elif any(eventDbMatch(events, {'ee_code': "combat"})): minDamage = 500 elif any(eventDbMatch(events, {'bb_code': "combat"})): minDamage = 250 if minDamage > damage: oldDC = self._damageCorrection self._damageCorrection += minDamage - damage self.log("Correcting damage: Detected {} damage, " "minDamage = {}, old correction = {}, " "new correction = {}" .format(damage, minDamage, oldDC, self._damageCorrection)) damage = self.getDoneAndState()[0] return damage
def _processLog(self, raidlog): events = raidlog['events'] self._killed = sum( k['turns'] for k in eventDbMatch(events, {'town_code': "combat"})) if self._dungeonActive(): newScareHoboParts = self.getParts() if newScareHoboParts is not None: if newScareHoboParts != self._scareHoboParts: self.processPartChange(newScareHoboParts) self._scareHoboParts = newScareHoboParts else: self._scareHoboParts = [0] * 6 return True
def _processLog(self, raidlog): events = raidlog['events'] self._killed = sum(k['turns'] for k in eventDbMatch( events, {'town_code': "combat"})) if self._dungeonActive(): newScareHoboParts = self.getParts() if newScareHoboParts is not None: if newScareHoboParts != self._scareHoboParts: self.processPartChange(newScareHoboParts) self._scareHoboParts = newScareHoboParts else: self._scareHoboParts = [0] * 6 return True
def _processLog(self, raidlog): events = raidlog['events'] # first: check number of dances available # = 5 * flim-flams - dances so far # also see who has danced so far. self._watches = {w['userName']: w['turns'] for w in eventDbMatch(events, {'ahbg_code': "watch"})} self._dances = {w['userName']: w['turns'] for w in eventDbMatch(events, {'ahbg_code': "dance"})} self._availableDances = ( 5 * sum(f['turns'] for f in eventDbMatch( events, {'ahbg_code': "flimflam"})) - sum(f['turns'] for f in eventDbMatch( events, {'ahbg_code': "dance"})) - sum(f['turns'] for f in eventDbMatch( events, {'ahbg_code': "watch"})) - sum(f['turns'] for f in eventDbMatch( events, {'ahbg_code': "fail"}))) # any player in hobopolis is added to watch list for hoboplayer in set(item['userName'] for item in events if 'userName' in item): if hoboplayer not in self._watches: self._watches[hoboplayer] = 0 self._killed = ( sum(k['turns'] for k in eventDbMatch( events, {'ahbg_code': "combat",})) - 9 * sum(t['turns'] for t in eventDbMatch( events, {'ahbg_code': "tomb"}))) self._ahbgDone = any(eventDbMatch(events, {'ahbg_code': "boss"})) if not self._open: if any(eventDbMatch(events, {'category': "The Ancient Hobo Burial Ground"})): self._open = True 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 _doProcessLog(self, raidlog, suppressChat=False): events = raidlog['events'] doneAmt = self.getDoneAndState()[0] doneAmt = self.correctDamage(events, doneAmt) self._killed = sum(k['turns'] for k in eventDbMatch( events, {'town_code': "combat"})) newPerformers = stageCount(events) newStageClears = stageClearCount(events) if newStageClears > self._stageClears: self._tentOpen = KNOWN_CLOSED if not suppressChat: self.chat("{} The tent will open when 100 more hobos " "are killed.".format(self.getTag())) self._lastTent = self.getDoneAndState()[0] elif newPerformers > self._totalperformers: self._tentOpen = KNOWN_OPEN self._totalperformers = newPerformers self._stageClears = newStageClears self.checkOpenings(doneAmt, suppressChat) return True
def _processLog(self, raidlog): events = raidlog['events'] # hobos killed by non-yodels oldYodel = self._yodel oldPipes = self._pipes self._killed = sum( coldhobo['turns'] for coldhobo in eventDbMatch(events, {'ee_code': "combat"})) self._yodel = ([ sum(yodel0['turns'] for yodel0 in eventDbMatch(events, {'ee_code': "yodel0"})), sum(yodel1['turns'] for yodel1 in eventDbMatch(events, {'ee_code': "yodel1"})), sum(yodel2['turns'] for yodel2 in eventDbMatch(events, {'ee_code': "yodel2"})) ]) self._pipes = sum( pipeevent['turns'] for pipeevent in eventDbMatch(events, {'ee_code': "pipe3"})) self._exposureDone = any(eventDbMatch(events, {'ee_code': "boss"})) if self._killed > 0 or self._pipes > 0 or sum(self._yodel) > 0: self._open = True if oldPipes < self._pipes and oldPipes is not None: #self.log("Added {} pipes".format(self._pipes - oldPipes)) pass if oldYodel is not None: yodelDiff = [new - old for new, old in zip(self._yodel, oldYodel)] for _idx, diff in enumerate(yodelDiff): if diff > 0: #self.log("Added {} yodel{}".format(diff,_idx), 'exposure') pass return True
def _processLog(self, raidlog): events = raidlog['events'] # hobos killed by non-yodels oldYodel = self._yodel oldPipes = self._pipes self._killed = sum( coldhobo['turns'] for coldhobo in eventDbMatch( events, {'ee_code': "combat"})) self._yodel = ( [sum(yodel0['turns'] for yodel0 in eventDbMatch( events, {'ee_code': "yodel0"})), sum(yodel1['turns'] for yodel1 in eventDbMatch( events, {'ee_code': "yodel1"})), sum(yodel2['turns'] for yodel2 in eventDbMatch( events, {'ee_code': "yodel2"}))]) self._pipes = sum(pipeevent['turns'] for pipeevent in eventDbMatch( events, {'ee_code': "pipe3"})) self._exposureDone = any(eventDbMatch(events, {'ee_code': "boss"})) if self._killed > 0 or self._pipes > 0 or sum(self._yodel) > 0: self._open = True if oldPipes < self._pipes and oldPipes is not None: #self.log("Added {} pipes".format(self._pipes - oldPipes)) pass if oldYodel is not None: yodelDiff = [new-old for new,old in zip(self._yodel, oldYodel)] for _idx,diff in enumerate(yodelDiff): if diff > 0: #self.log("Added {} yodel{}".format(diff,_idx), 'exposure') pass return True
def _processLog(self, raidlog): events = raidlog['events'] # check stench hobos killed self._killed = ( sum(stenchhobo['turns'] for stenchhobo in eventDbMatch( events, {'heap_code': "combat"})) + 5 * sum(trash['turns'] for trash in eventDbMatch(events, {'heap_code': "trashcano"}))) self._totalStench = ( 4 + sum(t['turns'] for t in eventDbMatch(events, {'heap_code': "trashcano"})) + sum(t['turns'] for t in eventDbMatch(events, {'heap_code': "stench"})) - sum(f['turns'] for f in eventDbMatch(events, {'heap_code': "unstench"}))) # if Oscus is dead, set the heap to finished self._heapDone = any(eventDbMatch(events, {'heap_code': "boss"})) if self._killed > 0: self._open = True return True
def _processLog(self, raidlog): events = raidlog['events'] # check stench hobos killed self._unpopularity = ( sum(u['turns'] for u in eventDbMatch( events, {'pld_code': "unpopular"})) - sum(p['turns'] for p in eventDbMatch( events, {'pld_code': "popular"}))) self._pldKilled = ( sum(k['turns'] for k in eventDbMatch( events, {'pld_code': "combat"})) - 6 * sum(d['turns'] for d in eventDbMatch( events, {'pld_code': "dumpster"}))) self._pldFights = sum(f['turns'] for f in eventDbMatch( events, {'pld_code': "barfight"})) # if Chester is dead, set the heap to finished if self._pldKilled > 0 or self._pldFights > 0: self._open = True self._pldDone = any(eventDbMatch(events, {'pld_code': "boss"})) return True
def _eventTimeline(self, events, nameShorthands): timeline = [] timelineKills = [0, 0, 0] newEvents = self._getNewEvents(events) t1 = time.time() snapshots = deepcopy(self._snapshots) snapshots.append(newEvents) for snapshot in snapshots: timelineText = [] for area in range(3): txtList = [] areaName = _areas[area] # first, let's find kills kills = defaultdict(int) killEvents = eventDbMatch(snapshot, { 'category': areaName, 'zone': "(combat)", 'subzone': "normal" }) for e in killEvents: timelineKills[area] += e['turns'] kills[e['userId']] += e['turns'] for uid, k in kills.items(): txtList.append(" {}: {} kills".format( nameShorthands[uid], k)) bossEvents = eventDbMatch(snapshot, { 'category': areaName, 'zone': "(combat)", 'subzone': "boss" }, { 'category': areaName, 'zone': "(combat)", 'subzone': "boss_defeat" }) for e in bossEvents: txtList.append("*{} {}".format(nameShorthands[e['userId']], e['event'])) allEvents = eventDbMatch(snapshot, {'category': areaName}) for e in allEvents: dbm = e['db-match'] if dbm.get('zone') == "(combat)": continue if dbm.get('unique_text', "").strip() != "": txtList.append("*{} got {} at {}".format( nameShorthands[e['userId']], dbm['code'], dbm['zone'])) elif dbm.get('zone') == "(unlock)": txtList.append("-{} unlocked {}".format( nameShorthands[e['userId']], dbm['subzone'])) else: txtList.append("-{} did {} at {}".format( nameShorthands[e['userId']], dbm['code'], dbm['zone'])) txtList.sort() timelineText.append(txtList) timeline.append({ 'kills': deepcopy(timelineKills), 'text': timelineText }) self.debugLog("Built timeline in {} seconds".format(time.time() - t1)) return timeline
def buskCount(events): return sum(b['turns'] for b in eventDbMatch(events, {'town_code': "busk"}))
def moshCount(events): return sum(m['turns'] for m in eventDbMatch(events, {'town_code': "mosh"}))
def uniqueStagePlayers(events): players = set(s['userId'] for s in eventDbMatch(events, {'town_code': "stage"})) return len(players)
def stageCount(events): return sum(s['turns'] for s in eventDbMatch(events, {'town_code': "stage"}))
def ruinCount(events): return sum(r['turns'] for r in eventDbMatch(events, {'town_code': "ruin"}))
def ruinCount(events): return sum(r['turns'] for r in eventDbMatch( events, {'town_code': "ruin"}))
def uniqueStagePlayers(events): players = set(s['userId'] for s in eventDbMatch( events, {'town_code': "stage"})) return len(players)
def moshCount(events): return sum(m['turns'] for m in eventDbMatch( events, {'town_code': "mosh"}))
def buskCount(events): return sum(b['turns'] for b in eventDbMatch( events, {'town_code': "busk"}))
def initialize(self, state, initData): events = initData['events'] self._db = initData['event-db'] self._killed = sum(k['turns'] for k in eventDbMatch( events, {'town_code': "combat"})) self._stageClears = stageClearCount(events) self._totalperformers = stageCount(events) self._damageCorrection = state['damageCorrection'] # do an initial damage calculation (doneAmt, guessState) = self.getDoneAndState() doneAmt = self.correctDamage(events, doneAmt) self._doProcessLog(initData, suppressChat=True) self._lastOpening = self.getDoneAndState()[0] self.log("Last opening: {}".format(self._lastOpening)) # figure out the whole tent opening thing lastStageClears = state['stageClears'] lastPerformers = state['totalPerformers'] onStage = self.getOnStage()[0] killDiff = doneAmt - state['lastTent'] if onStage > 0: # we KNOW that the stage is open self._tentOpen = KNOWN_OPEN self._lastTent = doneAmt - 100 self.log("Detected {} or more players on stage -> OPEN" .format(onStage)) elif guessState == KNOWN and doneAmt < 1500: # we know it's not open self._tentOpen = KNOWN_UNOPENED self._lastTent = 0 elif doneAmt < 1250: # there have been no adventures in the PLD and we are fairly # certain the tent is not open yet. self._tentOpen = KNOWN_UNOPENED self._lastTent = 0 elif killDiff < 100: # we know that the stage still not reopened self._tentOpen = KNOWN_CLOSED self._lastTent = state['lastTent'] elif lastStageClears == self._stageClears: # unfortunately, busking with 0 players on stage is not logged, # so there's a chance that the stage is closed now. self._tentOpen = UNKNOWN self._lastTent = doneAmt elif lastPerformers == self._totalperformers: # the stage has been cleared, no new performers. But we don't # know when :/ self._tentOpen = UNKNOWN self._lastTent = doneAmt else: # stage is cleared, but there may be new performers self._tentOpen = UNKNOWN self._lastTent = doneAmt for numKills, areaName, procName, _tagName in self.openings: if doneAmt > numKills: self._raiseEvent("open", procName) self.log("Opening {}".format(areaName))
def _processLog(self, raidlog): events = raidlog['events'] self._done = [any(eventDbMatch(events, {'category': self._areas[i], 'zone': "(combat)", 'subzone': "boss"})) for i in range(3)] self._drunk = raidlog['dread']['drunkenness'] newKilled = [raidlog['dread'].get('forest', 0), raidlog['dread'].get('village', 0), raidlog['dread'].get('castle', 0)] areaNames = ["Woods are", "Village is", "Castle is"] if self._killed is not None: for old,new,area in zip(self._killed, newKilled, areaNames): for threshold in self._notifyPercent: if old < 10*threshold <= new: self.chat("The {} {}% complete.".format(area, int(new/10))) break self._killed = newKilled oldKills = self._kills oldDefeats = self._defeats oldBanished = self._banished self._banished = {} self._kills = {} self._defeats = {} prefix = r'defeated\s+(?:hot|cold|spooky|stench|sleaze)\s+' prefixDef = r'was defeated by\s+(?:hot|cold|spooky|stench|sleaze)\s+' for monster in self._monsters: self._kills[monster] = ( sum(e['turns'] for e in eventFilter(events, prefix + monster))) self._defeats[monster] = ( sum(e['turns'] for e in eventFilter(events, prefixDef + monster))) self._banished[monster] = ( sum(e['turns'] for e in eventFilter(events, "drove some " + self._plurals[monster]))) # do likelihood ratio test to determine which monsters are more # populous self._doLRT(oldBanished, oldKills, oldDefeats) self._balance = {i: (self._kills[self._monsters[2*i]] - self._kills[self._monsters[2*i+1]]) for i in range(3)} self._level = [1 + sum(e['turns'] for e in eventFilter(events, "made the " + a + " less")) for a in ["forest", "village", "castle"]] self._kisses = raidlog['dread'].get('kisses', 0) self._locked = [] for area in self._lockedAreas: if not any(eventDbMatch(events, area)): self._locked.append(area) return True
def stageClearCount(events): return sum(c['turns'] for c in eventDbMatch( events, {'town_code': "ruin"}, {'town_code': "busk"}, {'town_code': "mosh"}))