#!/usr/bin/env python3 import sys import argparse import shlex import copy import codecs import os import os.path from collections import defaultdict import _pathfix from mhapi.db import MHDB, MHDBX from mhapi.damage import MotionValueDB, WeaponMonsterDamage, WeaponType from mhapi.model import SharpnessLevel, Weapon, ItemStars from mhapi import skills from mhapi.util import ELEMENTS, WEAPON_TYPES, WTYPE_ABBR, DAMAGE_TYPES def weapon_match_tuple(arg): parts = arg.split(",") if len(parts) == 1: wtype = parts[0] element = None elif len(parts) == 2: wtype = parts[0] element = parts[1] else: raise ValueError("Bad arg, use 'weapon_type,element_or_status'") wtype = get_wtype_match(wtype) if element is not None: element = get_element_match(element) return (wtype, element) ANY = object() def parse_stars(arg): if arg is None: return None arg = arg.lower() if arg in ("*", "any"): return ANY if arg in ("none", ""): return None return int(arg) def quest_level_tuple(arg): parts = arg.split(",") while len(parts) < 4: parts.append(None) return [parse_stars(p) for p in parts] def _make_db_sharpness_string(level_string): #print "level string", level_string level_value = SharpnessLevel.__dict__[level_string.upper()] #print "level value", level_value values = [] for i in range(SharpnessLevel.PURPLE+1): if i <= level_value: values.append("1") else: values.append("0") #print "sharp values %r" % values return " ".join([".".join(values)] * 2) def weapon_stats_tuple(arg): parts = arg.split(",") #print("parts %r" % parts) if len(parts) < 4: print("not enough parts") raise ValueError("Bad arg, use 'name,weapon_type,sharpness,raw'") weapon = {} weapon["name"] = parts[0] weapon["wtype"] = get_wtype_match(parts[1]) weapon["attack"] = int(parts[2]) weapon["affinity"] = parts[3] weapon["sharpness"] = _make_db_sharpness_string(parts[4]) if len(parts) == 5: weapon["element"] = None weapon["element_attack"] = None if len(parts) == 7: weapon["element"] = get_element_match(parts[5]) weapon["element_attack"] = int(parts[6]) else: #print "bad part number" raise ValueError("Bad arg, use 'name,weapon_type,sharpness,raw'") weapon["element_2"] = None weapon["awaken"] = None weapon["element_2_attack"] = None weapon["_id"] = -1 #print "making model" return Weapon(weapon) def get_wtype_match(term): abbr_result = WTYPE_ABBR.get(term.upper()) if abbr_result is not None: return abbr_result term = term.title() for wtype in WEAPON_TYPES: if wtype.startswith(term): return wtype raise ValueError("Unknown weapon type: %s" % term) def get_element_match(term): term = term.title() for element in ELEMENTS: if element.startswith(term): return element if term.lower() == "raw": return "Raw" raise ValueError("Unknown element or status: %s" % term) def parse_weapon_arg(arg, base_args): """ Return (name, skill_args), where skill_args is None if not specified. """ parts = arg.split(";") if len(parts) == 1: return parts[0], None elif len(parts) == 2: parser = argparse.ArgumentParser(description="Parse per-weapon skills") _add_skill_args(parser) skill_args = shlex.split(parts[1]) base_copy = copy.copy(base_args) return parts[0], parser.parse_args(skill_args, namespace=base_copy) else: raise ValueError("invalid weapon-skills arg: " + arg) def get_skill_names(args): return ["Sharpness +%d" % args.sharpness_plus if args.sharpness_plus else "", "Awaken" if args.awaken else "", skills.AttackUp.name(args.attack_up), skills.CriticalEye.name(args.critical_eye), skills.ElementAttackUp.name(args.element_up), "Blunt Power" if args.blunt_power else ""] def percent_change(a, b): if a == 0: return b return (100.0 * (b-a) / a) def _add_skill_args(parser): parser.add_argument("-s", "--sharpness-plus", type=int, default=False, help="add Sharpness +1 or +2 skill, default off") parser.add_argument("-f", "--awaken", action="store_true", default=False, help="add Awaken (FreeElemnt), default off") parser.add_argument("-a", "--attack-up", type=int, choices=list(range(0, 5)), default=0, help="1-4 for AuS, M, L, XL") parser.add_argument("-c", "--critical-eye", type=int, choices=list(range(0, 5)), default=0, help="1-4 for CE+1, +2, +3 and Critical God") parser.add_argument("-e", "--element-up", type=int, choices=list(range(0, 6)), default=0, help="1-5 for (element) Atk +1, +2, +3 and" " Element Attack Up") parser.add_argument("-t", "--artillery", type=int, choices=[0,1,2], default=0, 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("-b", "--blunt-power", action="store_true", default=False, help="Blunt Power (MHX), default off") def parse_args(argv): parser = argparse.ArgumentParser(description= "Calculate damage to monster from different weapons of the" " same class. The average motion value for the weapon class" " is used for raw damage calculations, to get a rough idea of" " the relative damage from raw vs element when comparing." ) _add_skill_args(parser) parser.add_argument("-p", "--parts", help="Limit analysis to specified parts" +" (comma separated list)") parser.add_argument("-o", "--motion", type=int, help="Use specified motion value instead of weapon " +"average") 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("-x", "--monster-hunter-cross", action="store_true", default=False, help="Assume weapons are true attack, use MHX values") parser.add_argument("-g", "--monster-hunter-gen", action="store_true", default=False, help="Assume weapons are true attack, use MHGen values") parser.add_argument("--mhw", "--monster-hunter-world", action="store_true", default=False, help="Adjusted attack, use MHWorld values") parser.add_argument("--mhr", "--monster-hunter-rise", action="store_true", default=False, help="True attack, use MHRise values") parser.add_argument("-m", "--match", nargs="*", help="WEAPON_TYPE,ELEMENT_OR_STATUS_OR_RAW" +" Include all matching weapons in their final form." +" Supports abbreviations like LS for Long Sword" +" and Para for Paralysis or Blast for Blastblight." +" If just WEAPON_TYPE is given, include all final" +" weapons of that type." +" Examples: 'Great Sword,Raw'" +" 'Sword and Shield,Para'" +" 'HH,Blast' 'Hammer'", type=weapon_match_tuple, default=[], action="append") parser.add_argument("-w", "--weapon-custom", nargs="*", help="NAME,WEAPON_TYPE,TRUE_RAW,AFFINITY,SHARPNESS" +"ELEMENT_TYPE,ELEMENT_ATTACK" +" Add weapon based on stats." +" Examples: 'DinoSnS,SnS,190,0,Blue,Fire,30'" +" 'AkantorHam,Hammer,240,25,Green'", type=weapon_stats_tuple, default=[], action="append") parser.add_argument("-q", "--quest-level", help="village,guild[,permit[,arena]]", type=quest_level_tuple) parser.add_argument("-r", "--rarity", help="include weapons of given type with max rarity", type=int, nargs="?") parser.add_argument("--html-out", help="Write table of values as HTML and save to path") parser.add_argument("--html-site", help="Write entire site of all monster & quest levels") parser.add_argument("-n", "--monster", help="Full name of monster") parser.add_argument("weapon", nargs="*", help="One or more weapons of same class to compare," " full names") 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, end=' ') damage_map = weapon_damage_map[name] print("%0.2f" % avg_phial(damage_map, level=level), end=' ') for part in parts: part_damage = damage_map[part] #print "%0.2f" % sum(damage_map.cb_phial_damage[part][level]), print("%0.2f:%0.2f:%0.2f" % damage_map.cb_phial_damage[part][level], end=' ') 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 write_damage_html(path, monster, monster_damage, quest_level, names, damage_map_base, weapon_damage_map, parts, part_max_damage, monster_breaks, monster_stars): print(path) def uniform_average(weapon): return weapon_damage_map[weapon].averages["uniform"] names_sorted = list(names) names_sorted.sort(key=uniform_average, reverse=True) from mako.lookup import TemplateLookup from mako.runtime import Context tlookup = TemplateLookup(directories=["templates/damage"], output_encoding="utf-8", input_encoding="utf-8") damage_template = tlookup.get_template("/monster_damage.html") wtype = damage_map_base.weapon.wtype weapon_damage_type = WeaponType.damage_type(wtype) damage_types = list(DAMAGE_TYPES) weapon_types = list(WEAPON_TYPES) weapon_types.remove("Bow") weapon_types.remove("Light Bowgun") weapon_types.remove("Heavy Bowgun") with codecs.open(path, "w", "utf8") as f: template_args = dict( monster=monster.name, monster_damage=monster_damage, damage_types=DAMAGE_TYPES, weapon_types=weapon_types, weapon_type=wtype, weapon_damage_type=weapon_damage_type, village_stars=quest_level[0], guild_stars=quest_level[1], part_names=parts, part_max_damage=part_max_damage, weapon_names=names_sorted, weapon_damage_map=weapon_damage_map, monster_breaks=set(monster_breaks), monster_stars=monster_stars ) ctx = Context(f, **template_args) damage_template.render_context(ctx) def write_damage_html_by_rarity(path, rarity, monster, monster_damage, names, damage_map_base, weapon_damage_map, parts, part_max_damage): print(path) def uniform_average(weapon): return weapon_damage_map[weapon].averages["uniform"] names_sorted = list(names) names_sorted.sort(key=uniform_average, reverse=True) from mako.lookup import TemplateLookup from mako.runtime import Context tlookup = TemplateLookup(directories=["templates/damage"], output_encoding="utf-8", input_encoding="utf-8") damage_template = tlookup.get_template("/monster_damage_by_rarity.html") wtype = damage_map_base.weapon.wtype weapon_damage_type = WeaponType.damage_type(wtype) damage_types = list(DAMAGE_TYPES) weapon_types = list(WEAPON_TYPES) weapon_types.remove("Bow") weapon_types.remove("Light Bowgun") weapon_types.remove("Heavy Bowgun") with codecs.open(path, "w", "utf8") as f: template_args = dict( monster=monster.name, monster_damage=monster_damage, rarity=rarity, damage_types=DAMAGE_TYPES, weapon_types=weapon_types, weapon_type=wtype, weapon_damage_type=weapon_damage_type, part_names=parts, part_max_damage=part_max_damage, weapon_names=names_sorted, weapon_damage_map=weapon_damage_map, ) ctx = Context(f, **template_args) damage_template.render_context(ctx) 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, end=' ') damage_map = weapon_damage_map[name] print("%0.2f" % damage_map.averages["uniform"], end=' ') for part in parts: part_damage = damage_map[part] print("% 2d" % part_damage.average(), end=' ') print() # this is super buggy if False and len(names) > 1: w1 = weapon_damage_map[names_sorted[0]] w2 = weapon_damage_map[names_sorted[1]] m, ratio = w1.compare_break_even(w2) print() print("Comparison of '%s' and '%s'" % ( names_sorted[0], names_sorted[1])) print("Hitbox ratio:", m, "%0.2f" % ratio) if w1.etype: re_ratios = w1.get_raw_element_ratios() else: re_ratios = w2.get_raw_element_ratios() for line in re_ratios: line = list(line) if m*line[3] > m*ratio: line.append(names_sorted[0]) else: line.append(names_sorted[1]) # (part, raw, element, ratio) print("%-22s %02d %02d %0.2f %s" % tuple(line)) 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, end=' ') for wname in names: wd = weapon_damage_map[wname] damage = wd.cb_phial_damage[part][level] print("(%0.f, %0.f, %0.f);" % damage, end=' ') 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)) def match_quest_level(match_level, weapon_level): #print match_level, weapon_level if match_level is ANY: return True if match_level is None: if weapon_level is not None: return False return True if weapon_level is None or weapon_level > match_level: return False return True def run_comparison(args, db, motiondb, game_uses_true_raw, item_stars=None): monster = db.get_monster_by_name(args.monster) if not monster: raise ValueError("Monster '%s' not found" % args.monster) monster_damage = db.get_monster_damage(monster.id) if not monster_damage.is_valid(): print("WARN: invalid damage data for monster '%s'" % args.monster) return if item_stars is None: item_stars = ItemStars(db) weapons = [] weapon_type = None names_set = set() skill_args_map = {} for name_skills in args.weapon: name, skill_args = parse_weapon_arg(name_skills, args) weapon = db.get_weapon_by_name(name) if not weapon: raise ValueError("Weapon '%s' not found" % name) names_set.add(name) weapons.append(weapon) if skill_args: skill_args_map[name] = skill_args #print("args match", args.match) for match_tuple in args.match: # TODO: better validation if isinstance(match_tuple, list): # TODO: is this a bug in argparse!!!???? match_tuple = match_tuple[0] wtype, element = match_tuple if args.quest_level or args.rarity: final=None else: final=1 match_weapons = db.get_weapons_by_query(wtype=wtype, element=element, final=final) 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) names_set.add(w.name) if args.weapon_custom: weapons.extend([w[0] for w in args.weapon_custom]) if not weapons: print("Err: no matching weapons") sys.exit(1) names = [w.name for w in weapons] monster_breaks = db.get_monster_breaks(monster.id) part_names = monster_damage.keys() for i in range(len(monster_breaks)): if monster_breaks[i] not in monster_damage: plural = monster_breaks[i] + "s" if plural in monster_damage: monster_breaks[i] = plural states = monster_damage.state_names() print("States:", states) print("%-20s" % monster.name, " | ".join(monster_damage.keys())) for dtype in DAMAGE_TYPES: print(dtype[:2], ":", end=" ") for part_name, part_damage in monster_damage.items(): if part_damage.state_diff(dtype): print("% 2d (% 2d)" % (part_damage[dtype], part_damage.get_alt_state(dtype)), end=" ") else: print("% 2d" % part_damage[dtype], end=" ") print() 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 print("Weapon Type: %s" % weapon_type) print("Average Motion: %0.1f" % motion) if args.motion: motion = args.motion print("Specified Motion: %0.1f" % motion) print("Monster Breaks: %s" % ", ".join(monster_breaks)) skill_names = get_skill_names(args) print("Common Skills:", ", ".join(skill for skill in skill_names if skill)) if args.parts: limit_parts = args.parts.split(",") else: limit_parts = None if args.quest_level: village, guild, permit, arena = args.quest_level print("Filter by Quest Levels:", args.quest_level) weapons2 = dict() for w in weapons: if "village_stars" in w: stars = dict(Village=w["village_stars"], Guild=w["guild_stars"], Permit=w["permit_stars"], Arena=w["arena_stars"]) else: stars = item_stars.get_weapon_stars(w) if (not match_quest_level(village, stars["Village"]) and not match_quest_level(guild, stars["Guild"])): continue if not match_quest_level(permit, stars["Permit"]): continue if not match_quest_level(arena, stars["Arena"]): continue weapons2[w.id] = w parent_ids = set(w.parent_id for w in weapons2.values()) for wid in list(weapons2.keys()): if wid in parent_ids: del weapons2[wid] weapons = list(weapons2.values()) names = [w.name for w in weapons] if args.rarity: print("Filter by max rarity:", args.rarity) weapons2 = dict() by_name = dict() for w in weapons: if w.rarity <= args.rarity: weapons2[w.id] = w by_name[w.name] = w # TODO: don't have parent ids for mhrise yet if False and args.mhr: # hack to remove most common dups for wname in list(by_name.keys()): if wname.endswith("+"): base = wname[:-1] suffix = "+" else: parts = wname.rsplit(" ", maxsplit=1) if len(parts) == 1: continue base, suffix = parts parent_name = None if suffix == "+" or base.endswith("+"): parent_name = base.rstrip("+") elif suffix in ("II", "III", "VI", "VII"): parent_name = wname[:-1] elif suffix == "IV": parent_name = base + " III" elif suffix == "V": parent_name = base + " IV" if parent_name: print("parent", parent_name) if parent_name in by_name: del weapons2[by_name[parent_name].id] else: parent_ids = set(w.parent_id for w in weapons2.values()) for wid in list(weapons2.keys()): if wid in parent_ids: del weapons2[wid] weapons = list(weapons2.values()) names = [w.name for w in weapons] part_max_damage = defaultdict(int) weapon_damage_map = dict() for row in weapons: name = row["name"] row_type = row["wtype"] if row_type != weapon_type: raise ValueError( "Weapon '%s' is different type, got '%s' expected '%s'" % (name, row_type, weapon_type)) #print(name, row) try: skill_args = skill_args_map.get(name, args) wd = WeaponMonsterDamage(row, monster, monster_damage, motion, skill_args.sharpness_plus, monster_breaks, attack_skill=skill_args.attack_up, critical_eye_skill=skill_args.critical_eye, element_skill=skill_args.element_up, awaken=skill_args.awaken, artillery_level=skill_args.artillery, limit_parts=args.parts, frenzy_bonus=skill_args.frenzy, is_true_attack=game_uses_true_raw, blunt_power=skill_args.blunt_power, game=db.game) print("%-20s: %4.0f %2.0f%%" % (name, wd.attack, wd.affinity), end=' ') if wd.etype: if wd.etype2: print("(%4.0f %s, %4.0f %s)" \ % (wd.eattack, wd.etype, wd.eattack2, wd.etype2), end=' ') else: print("(%4.0f %s)" % (wd.eattack, wd.etype), end=' ') print(SharpnessLevel.name(wd.sharpness), wd.sharpness_points, end=' ') if skill_args != args: print("{%s}" % ",".join(sn for sn in get_skill_names(skill_args) if sn)) else: print() for part in wd.parts: if wd[part].average() > part_max_damage[part]: part_max_damage[part] = wd[part].average() weapon_damage_map[name] = wd except ValueError as e: print(str(e)) sys.exit(1) damage_map_base = weapon_damage_map[names[0]] if limit_parts: parts = limit_parts else: parts = damage_map_base.parts if args.diff: print_damage_percent_diff(names, damage_map_base, weapon_damage_map, parts) elif args.phial: print_sorted_phial_damage(names, damage_map_base, weapon_damage_map, parts, level=args.phial) else: print_sorted_damage(names, damage_map_base, weapon_damage_map, parts) if args.html_out: if args.mhr: if not args.rarity: print("Error: --html-out with --mrh requires --rarity") sys.exit(1) write_damage_html_by_rarity(args.html_out, args.rarity, monster, monster_damage, names, damage_map_base, weapon_damage_map, parts, part_max_damage) else: if not args.quest_level: print("Error: --html-out requires quest level (-q)") sys.exit(1) monster_stars = item_stars.get_monster_stars(monster.id) write_damage_html(args.html_out, monster, monster_damage, args.quest_level, names, damage_map_base, weapon_damage_map, parts, part_max_damage, monster_breaks, monster_stars) def write_html_site(args, db, motiondb, game_uses_true_raw): if db.game == "4u": village_max = 5 guild_max = 2 else: raise ValueError("Not implemented") monsters = db.get_monsters("Boss") monster_names = [monster.name for monster in monsters] weapon_types = db.get_weapon_types() item_stars = ItemStars(db) monster_stars = {} for monster in monsters: monster_stars[monster.id] = item_stars.get_monster_stars(monster.id) n = 0 base_dir = args.html_site for monster in monsters: stars = monster_stars[monster.id] if stars["Village"] is None: vrange = [0] else: if stars["Village"] > 2: start = stars["Village"] - 1 else: start = stars["Village"] vrange = list(range(start, 11)) if start > 2: vrange = [0] + vrange if stars["Guild"] is None: grange = [0] else: if stars["Guild"] > 1: start = stars["Guild"] - 1 else: start = stars["Guild"] grange = list(range(start, 11)) if start > 1: grange = [0] + grange for v in vrange: for g in grange: if v == 0: if g == 0: continue v = 1 if g == 0: g = 1 quest_dir = "v{}g{}".format(v, g) quest_path = os.path.join(base_dir, monster.name, quest_dir) if not os.path.isdir(quest_path): os.makedirs(quest_path) for wtype in weapon_types: if "Bowgun" in wtype or wtype == "Bow": continue args.html_out = os.path.join(quest_path, wtype + ".html") if os.path.isfile(args.html_out): print(args.html_out, " exists, skipping") continue args.html_site = None n += 1 args.monster = monster.name args.quest_level = (v if v else 1, g if g else 1, None, None) args.match = [(wtype, None)] run_comparison(args, db, motiondb, game_uses_true_raw, item_stars=item_stars) print("n =", n) def write_html_site_rise(args, db, motiondb, game_uses_true_raw=True): monsters = db.get_monsters() weapon_types = db.get_weapon_types() n = 0 base_dir = args.html_site for monster in monsters: for rarity in range(1, 11): args.rarity = rarity rarity_dir = "r{}".format(rarity) mpath = os.path.join(base_dir, monster.name, rarity_dir) if not os.path.isdir(mpath): os.makedirs(mpath) for wtype in weapon_types: if "Bowgun" in wtype or wtype == "Bow": continue args.html_out = os.path.join(mpath, wtype + ".html") if os.path.isfile(args.html_out): print(args.html_out, " exists, skipping") continue args.html_site = None n += 1 args.monster = monster.name args.match = [(wtype, None)] print(rarity, wtype) run_comparison(args, db, motiondb, game_uses_true_raw) print("n =", n) def main(): args = parse_args(None) game_uses_true_raw = False if args.quest_level or args.html_site: comps = True else: comps = False if args.monster_hunter_cross: db = MHDBX() game_uses_true_raw = True elif args.monster_hunter_gen: db = MHDB(game="gu", include_item_components=comps) game_uses_true_raw = True elif args.mhw: db = MHDBX(game="mhw") game_uses_true_raw = False SharpnessLevel._modifier = SharpnessLevel._modifier_mhw elif args.mhr: db = MHDBX(game="mhr") game_uses_true_raw = True SharpnessLevel._modifier = SharpnessLevel._modifier_mhw else: db = MHDB(game="4u", include_item_components=comps) motiondb = MotionValueDB(_pathfix.motion_values_path) if args.html_site: if args.mhr: write_html_site_rise(args, db, motiondb, game_uses_true_raw) else: write_html_site(args, db, motiondb, game_uses_true_raw) else: run_comparison(args, db, motiondb, game_uses_true_raw) if __name__ == '__main__': main()