damage: add sorted list mode as default, cb mode

main
Bryce Allen 10 years ago
parent 7f0e79a850
commit 963a0f153d

@ -67,7 +67,7 @@ def parse_args(argv):
help="add Sharpness +1 skill, default off") help="add Sharpness +1 skill, default off")
parser.add_argument("-f", "--awaken", action="store_true", parser.add_argument("-f", "--awaken", action="store_true",
default=False, default=False,
help="add Awaken (FreeElement), default off") help="add Awaken (FreeElemnt), default off")
parser.add_argument("-a", "--attack-up", parser.add_argument("-a", "--attack-up",
type=int, choices=range(0, 5), default=0, type=int, choices=range(0, 5), default=0,
help="1-4 for AuS, M, L, XL") help="1-4 for AuS, M, L, XL")
@ -81,9 +81,21 @@ def parse_args(argv):
parser.add_argument("-t", "--artillery", parser.add_argument("-t", "--artillery",
type=int, choices=[0,1,2], default=0, type=int, choices=[0,1,2], default=0,
help="0-2 for no artillery, novice, god") help="0-2 for no artillery, novice, god")
parser.add_argument("-z", "--frenzy",
help="With virus affinity boost, must be either"
+" 15 (normal) or 30 (with Frenzy Res skill)",
type=int, choices=[0, 15, 30], default=0)
parser.add_argument("-p", "--parts", parser.add_argument("-p", "--parts",
help="Limit analysis to specified parts" help="Limit analysis to specified parts"
+" (comma separated list)") +" (comma separated list)")
parser.add_argument("-l", "--phial",
help="Show CB phial damage at the sepcified level"
+" (1, 2, 3, 5=ultra) instead of normal motion"
+" values.",
type=int, choices=[0, 1, 2, 3, 5], default=0)
parser.add_argument("-d", "--diff", action="store_true", default=False,
help="Show percent difference in damage to each part"
+" from first weapon in list.")
parser.add_argument("-m", "--match", nargs="*", parser.add_argument("-m", "--match", nargs="*",
help="WEAPON_TYPE,ELEMENT_OR_STATUS_OR_RAW" help="WEAPON_TYPE,ELEMENT_OR_STATUS_OR_RAW"
+" Include all matching weapons in their final form." +" Include all matching weapons in their final form."
@ -104,6 +116,121 @@ def parse_args(argv):
return parser.parse_args(argv) return parser.parse_args(argv)
def print_sorted_phial_damage(names, damage_map_base, weapon_damage_map, parts,
level):
def cb_levelN(weapon):
return avg_phial(weapon_damage_map[weapon], level=level)
def avg_phial(wd, level=5):
total = 0.0
for part in parts:
total += sum(wd.cb_phial_damage[part][level])
return total / len(parts)
names_sorted = list(names)
names_sorted.sort(key=cb_levelN, reverse=True)
_print_headers(parts, damage_map_base)
for name in names_sorted:
print "%-20s:" % name,
damage_map = weapon_damage_map[name]
print "%0.2f" % avg_phial(damage_map, level=level),
for part in parts:
part_damage = damage_map[part]
print "%0.2f" % sum(damage_map.cb_phial_damage[part][level]),
print
def _print_headers(parts, damage_map_base):
print
avg_hitbox = (sum(damage_map_base[part].hitbox for part in parts)
/ float(len(parts)))
cols = ["%s (%d)" % (part, damage_map_base[part].hitbox)
for part in parts]
cols = ["%s (%d)" % ("Avg", avg_hitbox)] + cols
print " | ".join(cols)
def print_sorted_damage(names, damage_map_base, weapon_damage_map, parts):
def uniform_average(weapon):
return weapon_damage_map[weapon].averages["uniform"]
names_sorted = list(names)
names_sorted.sort(key=uniform_average, reverse=True)
_print_headers(parts, damage_map_base)
#print
#print " | ".join(["%-15s" % "Avg"] + parts)
#print " | ".join([" "] + [str(damage_map_base[part].hitbox)
# for part in parts])
for name in names_sorted:
print "%-20s:" % name,
damage_map = weapon_damage_map[name]
print "%0.2f" % damage_map.averages["uniform"],
for part in parts:
part_damage = damage_map[part]
print "%0.2f" % part_damage.total,
print
def print_damage_percent_diff(names, damage_map_base, weapon_damage_map, parts):
for part in parts:
tdiffs = [percent_change(
damage_map_base[part].total,
weapon_damage_map[w][part].total
)
for w in names[1:]]
ediffs = [percent_change(
damage_map_base[part].element,
weapon_damage_map[w][part].element
)
for w in names[1:]]
bdiffs = [percent_change(
damage_map_base[part].break_diff(),
weapon_damage_map[w][part].break_diff()
)
for w in names[1:]]
tdiff_s = ",".join("%+0.1f%%" % i for i in tdiffs)
ediff_s = ",".join("%+0.1f%%" % i for i in ediffs)
bdiff_s = ",".join("%+0.1f%%" % i for i in bdiffs)
damage = damage_map_base[part]
print "%22s%s h%02d %0.2f (%s) h%02d %0.2f (%s) %+0.2f (%s)" \
% (part, "*" if damage.is_breakable() else " ",
damage.hitbox,
damage.total,
tdiff_s,
damage.ehitbox,
damage.element,
ediff_s,
damage.break_diff(),
bdiff_s)
if weapon_type == "Charge Blade":
for level in (0, 1, 2, 3, 5):
print " " * 20, level,
for wname in names:
wd = weapon_damage_map[wname]
damage = wd.cb_phial_damage[part][level]
print "(%0.f, %0.f, %0.f);" % damage,
print
print " --------------------"
for avg_type in "uniform raw weakpart_raw element weakpart_element break_raw break_element break_only".split():
base = damage_map_base.averages[avg_type]
diffs = [percent_change(
base,
weapon_damage_map[w].averages[avg_type]
)
for w in names[1:]]
diff_s = ",".join("%+0.1f%%" % i for i in diffs)
print "%22s %0.2f (%s)" % (avg_type, base, diff_s)
if __name__ == '__main__': if __name__ == '__main__':
args = parse_args(None) args = parse_args(None)
@ -117,20 +244,27 @@ if __name__ == '__main__':
weapons = [] weapons = []
weapon_type = None weapon_type = None
names_set = set()
for match_tuple in args.match:
# TODO: better validation
wtype, element = match_tuple
match_weapons = db.get_weapons_by_query(wtype=wtype, element=element,
final=1)
weapons.extend(match_weapons)
for name in args.weapon: for name in args.weapon:
weapon = db.get_weapon_by_name(name) weapon = db.get_weapon_by_name(name)
if not weapon: if not weapon:
raise ValueError("Weapon '%s' not found" % name) raise ValueError("Weapon '%s' not found" % name)
names_set.add(name)
weapons.append(weapon) weapons.append(weapon)
for match_tuple in args.match:
# TODO: better validation
wtype, element = match_tuple
match_weapons = db.get_weapons_by_query(wtype=wtype, element=element,
final=1)
for w in match_weapons:
# skip weapons already explicitly names in arg list.
# Especially useful in diff mode.
if w.name in names_set:
continue
weapons.append(w)
if not weapons: if not weapons:
print "Err: no matching weapons" print "Err: no matching weapons"
sys.exit(1) sys.exit(1)
@ -139,6 +273,9 @@ if __name__ == '__main__':
monster_breaks = db.get_monster_breaks(monster.id) monster_breaks = db.get_monster_breaks(monster.id)
weapon_type = weapons[0]["wtype"] weapon_type = weapons[0]["wtype"]
if args.phial and weapon_type != "Charge Blade":
print "ERROR: phial option is only supported for Charge Blade"
sys.exit(1)
motion = motiondb[weapon_type].average motion = motiondb[weapon_type].average
print "Weapon Type: %s" % weapon_type print "Weapon Type: %s" % weapon_type
print "Average Motion: %0.1f" % motion print "Average Motion: %0.1f" % motion
@ -171,7 +308,8 @@ if __name__ == '__main__':
element_skill=args.element_up, element_skill=args.element_up,
awaken=args.awaken, awaken=args.awaken,
artillery_level=args.artillery, artillery_level=args.artillery,
limit_parts=args.parts) limit_parts=args.parts,
frenzy_bonus=args.frenzy)
print "%-20s: %4.0f %2.0f%%" % (name, wd.attack, wd.affinity), print "%-20s: %4.0f %2.0f%%" % (name, wd.attack, wd.affinity),
if wd.etype: if wd.etype:
if wd.etype2: if wd.etype2:
@ -185,62 +323,20 @@ if __name__ == '__main__':
print str(e) print str(e)
sys.exit(1) sys.exit(1)
damage_map_base = weapon_damage_map[weapons[0].name] damage_map_base = weapon_damage_map[names[0]]
if limit_parts: if limit_parts:
parts = limit_parts parts = limit_parts
else: else:
parts = damage_map_base.parts parts = damage_map_base.parts
for part in parts: if args.diff:
tdiffs = [percent_change( print_damage_percent_diff(names, damage_map_base,
damage_map_base[part].total, weapon_damage_map, parts)
weapon_damage_map[w][part].total elif args.phial:
) print_sorted_phial_damage(names, damage_map_base,
for w in names[1:]] weapon_damage_map, parts,
ediffs = [percent_change( level=args.phial)
damage_map_base[part].element, else:
weapon_damage_map[w][part].element print_sorted_damage(names, damage_map_base,
) weapon_damage_map, parts)
for w in names[1:]]
bdiffs = [percent_change(
damage_map_base[part].break_diff(),
weapon_damage_map[w][part].break_diff()
)
for w in names[1:]]
tdiff_s = ",".join("%+0.1f%%" % i for i in tdiffs)
ediff_s = ",".join("%+0.1f%%" % i for i in ediffs)
bdiff_s = ",".join("%+0.1f%%" % i for i in bdiffs)
damage = damage_map_base[part]
print "%22s%s h%02d %0.2f (%s) h%02d %0.2f (%s) %+0.2f (%s)" \
% (part, "*" if damage.is_breakable() else " ",
damage.hitbox,
damage.total,
tdiff_s,
damage.ehitbox,
damage.element,
ediff_s,
damage.break_diff(),
bdiff_s)
if weapon_type == "Charge Blade":
for level in (0, 1, 2, 3, 5):
print " " * 20, level,
for wname in names:
wd = weapon_damage_map[wname]
damage = wd.cb_phial_damage[part][level]
print "(%0.f, %0.f, %0.f);" % damage,
print
print " --------------------"
for avg_type in "uniform raw weakpart_raw element weakpart_element break_raw break_element break_only".split():
base = damage_map_base.averages[avg_type]
diffs = [percent_change(
base,
weapon_damage_map[w].averages[avg_type]
)
for w in names[1:]]
diff_s = ",".join("%+0.1f%%" % i for i in diffs)
print "%22s %0.2f (%s)" % (avg_type, base, diff_s)

@ -166,7 +166,8 @@ class WeaponMonsterDamage(object):
attack_skill=skills.AttackUp.NONE, attack_skill=skills.AttackUp.NONE,
critical_eye_skill=skills.CriticalEye.NONE, critical_eye_skill=skills.CriticalEye.NONE,
element_skill=skills.ElementAttackUp.NONE, element_skill=skills.ElementAttackUp.NONE,
awaken=False, artillery_level=0, limit_parts=None): awaken=False, artillery_level=0, limit_parts=None,
frenzy_bonus=0):
self.weapon = weapon_row self.weapon = weapon_row
self.monster = monster_row self.monster = monster_row
self.monster_damage = monster_damage self.monster_damage = monster_damage
@ -179,6 +180,10 @@ class WeaponMonsterDamage(object):
self.awaken = awaken self.awaken = awaken
self.artillery_level = artillery_level self.artillery_level = artillery_level
self.limit_parts = limit_parts self.limit_parts = limit_parts
# 15 normaly for overcoming the virus, 30 with frenzy res skill
assert frenzy_bonus in (0, 15, 30)
self.frenzy_bonus = frenzy_bonus
self.chaotic = False
self.damage_map = defaultdict(PartDamage) self.damage_map = defaultdict(PartDamage)
self.average = 0 self.average = 0
@ -198,13 +203,22 @@ class WeaponMonsterDamage(object):
self.sharpness = self.weapon.sharpness.max self.sharpness = self.weapon.sharpness.max
#print "sharpness=", self.sharpness #print "sharpness=", self.sharpness
if self.weapon["affinity"]: if self.weapon["affinity"]:
# handle chaotic gore affinity - use average, which is if "/" in self.weapon["affinity"]:
# probably not quite right but at least allows an initial self.chaotic = True
# comparison point # Handle chaotic gore affinity, e.g. -35/10. This means that
parts = [int(x) for x in self.weapon["affinity"].split("/")] # 35% of the time it does a negative critical (75% damage)
self.affinity = sum(parts)/len(parts) # and 10% of the time does a positive critical (125%
# damage). If frenzied (overcome virus which lasts 45
# seconds), the negative affinity becomes positive
# instead (35 + 10 = 45 in the example).
self.affinity = sum(
abs(int(x)) if self.frenzy_bonus else int(x)
for x in self.weapon["affinity"].split("/"))
else:
self.affinity = int(self.weapon["affinity"])
else: else:
self.affinity = 0 self.affinity = 0
self.affinity += self.frenzy_bonus
self.damage_type = WeaponType.damage_type(self.weapon_type) self.damage_type = WeaponType.damage_type(self.weapon_type)
self.etype = self.weapon["element"] self.etype = self.weapon["element"]
self.eattack = self.weapon["element_attack"] self.eattack = self.weapon["element_attack"]
@ -305,7 +319,13 @@ class WeaponMonsterDamage(object):
self.max_raw_part = (part, hitbox) self.max_raw_part = (part, hitbox)
if ehitbox > self.max_element_part[1]: if ehitbox > self.max_element_part[1]:
self.max_element_part = (part, ehitbox) self.max_element_part = (part, ehitbox)
for d in self.damage_map.values():
for part in self.damage_map.keys():
if None not in self.damage_map[part].states:
#print "Failed to parse part:", part
del self.damage_map[part]
for part, d in self.damage_map.iteritems():
if d.is_breakable(): if d.is_breakable():
self.break_count += 1 self.break_count += 1
self.parts = self.damage_map.keys() self.parts = self.damage_map.keys()

Loading…
Cancel
Save