#!/usr/bin/python import os, re, sys from time import strftime from datetime import datetime #import matplotlib.pyplot as plt ## Declaring the points for first line plot #X1 = [1,2,3,4,5] #Y1 = [2,4,6,8,10] ## Setting the figure size #fig = plt.figure(figsize=(10,5)) ## plotting the first plot #plt.plot(X1, Y1, label = "plot 1") ## Declaring the points for second line plot #X2 = [1,2,3,4,5] #Y2 = [1,4,9,16,25] ## plotting the second plot #plt.plot(X2, Y2, label = "plot 2") ## Labeling the X-axis #plt.xlabel('X-axis') ## Labeling the Y-axis #plt.ylabel('Y-axis') ## Give a title to the graph #plt.title('Two plots on the same graph') ## Show a legend on the plot #plt.legend() ##Saving the plot as an image #fig.savefig('line plot.png', bbox_inches='tight', dpi=150) ##Showing the plot #plt.show() # [03/16/2012 22:53:45] [@Asdffljklasdfj] [@Asdffljklasdfj] [Unnatural Might {1781509484707840}] [RemoveEffect {836045448945478}: Unnatural Might {1781509484707840}] () # [21:18:16.172] [@Comendatore] [@Comendatore] [] [Event {836045448945472}: EnterCombat {836045448945489}] (Asation (8 Player Story)) #[date] [src] [target] [ability] [effect] (value) #src = [foo {id}] or [@player] # ability = abil {id} # effect = type:effect # value = # or # type # roll? int listEncounters = [ ## The Dread Fortress 'Nefra, Who Bars the Way {3266533082005504}','Gate Commander Draxus {3273924720721920}','Grob\'thok, Who Feeds the Forge {3273929015689216}','Corruptor Zero {3273933310656512}','Dread Master Brontes {3273937605623808}', ## Eternity Vault 'Soa {2289823159156736}', ## 'The Writhing Horror {2938874321960960}','Heirad {2938002443599872}','Ciphas {2938011033534464}','Kel\'sara {2938006738567168}','Operator IX {2942606648541184}','Kephess the Undying {2937620191510528}','The Terror From Beyond {2978340776443904}','The Terror From Beyond {3025233229381632}', ## 'The Eyeless {3328380611067904}','Golden Fury {3232800408862720}','Golden Fury {3232817588731904}', ## The False Emperor 'Tregg the Destroyer {1690314444111872}','Jindo Krey {770959514533888}','HK-47 {770955219566592}','Chondrus Berani {1690331623981056}','Sith Entity {1695962326106112}','Forsaken Sith Lord {781830076760064}','Darth Malgus {770963809501184}', ## Battle of Rishi 'Marko Ka {3533564083699712}','Rarrook {3533559788732416}','Lord Vodd {3533585558536192}','Shield Squadron Unit 1 {3533594148470784}','Darth Yun {4257506591244288}', ## Objective Meridian 'Commander Aster {4258021987319808}','Darth Malgus {4257502296276992}', ## Heart of Ruin 'Colossal Monolith {3541140406009856}', ## 'Toxxun {3340011382505472}', ## Mutated Geonosian Queen 'Mutated Geonosian Queen {4197299739688960}', ## 'SCYVA {4108140513591296}' ] dmgTypes = ['energy','elemental','kinetic','internal'] instTypes = ['Story','Veteran','Master'] zoneNames = [ # Planet zones 'Corellia','Coruscant','CZ-198','Rishi','Taris','Tatooine','Voss','Yavin 4','Ziost', # Instances zones 'Asation','Lair of the Eyeless','Toborro\'s Palace Courtyard','The False Emperor','Battle of Rishi','Objective Meridian','Hive of the Mountain Queen', # Operations Zones 'Valley of the Machine Gods' ] class Event: regex = r'[\[<\(]([^\[<\(\]>\)]*)[\]>\)]' def __init__(self, x): data = re.findall(Event.regex, x) data.append('') self.to_string = ' '.join(data) dateandtime = datetime.strptime(list(sys.argv[1].split("_"))[1]+" "+data[0], '%Y-%m-%d %H:%M:%S.%f') self.date = dateandtime self.source = Entity(data[1]) self.target = Entity(data[2]) self.ability = Ability(data[3]) self.effect = Effect(data[4]) self.value = Value(data[5]) self.threat = Threat(data[6]) class Entity: def __init__(self, x): if not x: self.name = x self.player = False #print(x+" is not a player !") elif x[0] == '@': self.name = x[1:] self.player = True #print(x+" is a player !") else: self.name = x self.player = False #print(x+" is not a player !") class Ability: def __init__(self, x): self.name = x class Effect: def __init__(self, x): if not x: self.type = '' self.detail = '' return foo = x.split(':') if len(foo) > 1: self.type = foo[0] self.detail = foo[1] else: self.type = x self.detail = '' #class Value: #def __init__(self, x): #if not x: #self.value = 0 #self.type = '' #return #foo = x.replace('*','').split(' ') #self.value = int(foo[0]) #if len(foo) > 1: #self.type = foo[1] #else: #self.type='' # [20:06:53.053] [@Comendatore] [@Comendatore] [] [Event {836045448945472}: EnterCombat {836045448945489}] (Ziost) # [21:31:45.974] [@Comendatore] [@Comendatore] [] [Event {836045448945472}: EnterCombat {836045448945489}] (Hive of the Mountain Queen (8 Player Story)) # [21:32:18.105] [@Bidobulle] [@Comendatore] [Slow-release Medpac {3406415871868928}] [ApplyEffect {836045448945477}: Heal {836045448945500}] (5683*) # [21:32:19.499] [@Bidobulle] [@Comendatore] [Slow-release Medpac {3406415871868928}] [ApplyEffect {836045448945477}: Heal {836045448945500}] (3641) # [22:37:11.036] [@Comendatore] [Colossal Monolith {3541140406009856}:15814000004760] [Shocked {2044520397013249}] [ApplyEffect {836045448945477}: Damage {836045448945501}] (165 energy {836045448940874}) <1646> # [22:37:46.168] [@Comendatore] [Colossal Monolith {3541140406009856}:15814000004760] [Ion Storm {3389987621961728}] [ApplyEffect {836045448945477}: Damage {836045448945501}] (20879* elemental {836045448940875}) <52197> # [22:37:51.623] [Colossal Monolith {3541140406009856}:15814000004760] [@Comendatore] [Great Slam {3543287889657856}] [ApplyEffect {836045448945477}: Damage {836045448945501}] (86 kinetic {836045448940873} -shield {836045448945509} (86 absorbed {836045448945511})) <86> # [22:38:30.231] [Colossal Monolith {3541140406009856}:15814000004760] [@Comendatore] [Bleeding {3546045258662192}] [ApplyEffect {836045448945477}: Damage {836045448945501}] (10668 internal {836045448940876}) <10668> class Value: def __init__(self, x): if not x: self.value = 0 self.type = '' return foo = x.replace('*','') #print(foo) #if not re.search('[a-zA-Z]+', x): #print(foo) if any(z in foo for z in dmgTypes) and not any(y in foo for y in instTypes) or not any(w in foo for w in zoneNames) or foo.isdigit(): foo = x.replace('*','').split(' ') if foo[0].isdigit(): self.value = int(foo[0]) else: self.value = 0 if len(foo) > 1: self.type = foo[1] else: self.type='' else: #print(foo) self.type = '' class Threat: def __init__(self, x): if not x: self.value = 0 self.type = '' return foo = x.replace('*','').split(' ') self.value = int(foo[0]) if len(foo) > 1: self.type = foo[1] else: self.type='' #date, source, target, ability, effect.type/detail, value.value/type, threat # TODO: # multiple sources # more interesting output, graphs? What about that metric site? Google charts? # App engine seems fun # Details for abilities: # dmg per ability # Combine multiple entries per ability def main(): if len(sys.argv) == 1: filename = 'combat_2020-07-25_22_39_58_532658.txt' print('File not specified, defaulting to ' + filename) else: filename = sys.argv[1] file = open(filename, 'r') events = [] for line in file.readlines(): events.append(Event(line)) players = set([event.source.name for event in events]) fights = [] isBoss = False fight = [] for event in events: if 'EnterCombat' in event.effect.detail: fight = [] #fight.extend(fight) #isBoss = False if 'Death' in event.effect.detail: #print(event.effect.detail) #if any(t in event.target.name for t in listEncounters): fight.append(event) #print(listEncounters) #isBoss = False for event in fight: ##print(event.source.name) if any(t in event.target.name for t in listEncounters): isBoss = True if isBoss: fights.append(fight) fight = [] continue if 'ExitCombat' in event.effect.detail: #if any(t in event.effect.detail for t in ['ExitCombat','Death']): fight.append(event) #print(listEncounters) isBoss = False for event in fight: #print(event.source.name) if any(t in event.target.name for t in listEncounters): isBoss = True if isBoss: fights.append(fight) fight = [] continue fight.append(event) for i, fight in enumerate(fights): duration = fight[-1].date - fight[0].date for event in fight: if any(t in event.target.name for t in listEncounters): namedTarget = event.target.name.split(' {') namedTarget = namedTarget[0] #print('\nCombat Statistics for Fight # %d (duration: %s)' %(i+1, str(duration))) print('\nCombat Statistics for Fight #%d -> %s (%s)' %(i+1, namedTarget, str(duration))) print("Started: " + str(fight[0].date) +" Ended: " + str(fight[-1].date)) for player in players: if '{' not in player: dmg = 0 tdmg = 0 heal = 0 theal = 0 threat = 0 death = False for event in fight: ## Domages done by player (DPS) if event.source.name == player and 'Damage ' in event.effect.detail: dmg += event.value.value ## Domages taken by player (DTPS) if event.target.name == player and 'Damage ' in event.effect.detail: tdmg += event.value.value ## Heal done by player (HPS) if event.source.name == player and 'Heal ' in event.effect.detail: heal += event.value.value ## Heal received by player (HTPS) if event.target.name == player and 'Heal ' in event.effect.detail: theal += event.value.value ## Generated threat by player (TPS) if event.source.name == player and event.threat.value: threat += event.threat.value ## Dead if event.source.name == player and 'Death' in event.effect.detail: death = True secs = duration.seconds if not secs: secs = 1 if dmg: print('%s did %d damage in %s (%d DPS)' % (player, dmg, str(duration), dmg/secs)) if tdmg: print('%s took %d damage in %s (%d DTPS)' % (player, tdmg, str(duration), tdmg/secs)) if heal: print('%s did %d heals in %s (%d HPS)' % (player, heal, str(duration), heal/secs)) if theal: print('%s received %d heals in %s (%d HTPS)' % (player, theal, str(duration), theal/secs)) if threat: print('%s did %d threat in %s (%d TPS)' % (player, threat, str(duration), threat/secs)) if death: print('%s died on %s' % (player, namedTarget)) #print("\n".join([event.to_string for event in events])) if __name__ == "__main__": main()