add mhx damage

main
Bryce Allen 10 years ago
parent ec8e52b99d
commit f33dcf5985

@ -7,8 +7,8 @@ import copy
import _pathfix import _pathfix
from mhapi.db import MHDB from mhapi.db import MHDB, MHDBX
from mhapi.damage import MotionValueDB, WeaponMonsterDamage, WeaponType from mhapi.damage import MotionValueDB, WeaponMonsterDamage
from mhapi.model import SharpnessLevel, Weapon from mhapi.model import SharpnessLevel, Weapon
from mhapi import skills from mhapi import skills
from mhapi.util import ELEMENTS, WEAPON_TYPES, WTYPE_ABBR from mhapi.util import ELEMENTS, WEAPON_TYPES, WTYPE_ABBR
@ -31,30 +31,29 @@ def weapon_match_tuple(arg):
def _make_db_sharpness_string(level_string): def _make_db_sharpness_string(level_string):
print "level string", level_string #print "level string", level_string
level_value = SharpnessLevel.__dict__[level_string.upper()] level_value = SharpnessLevel.__dict__[level_string.upper()]
print "level value", level_value #print "level value", level_value
values = [] values = []
for i in xrange(SharpnessLevel.PURPLE+1): for i in xrange(SharpnessLevel.PURPLE+1):
if i <= level_value: if i <= level_value:
values.append("1") values.append("1")
else: else:
values.append("0") values.append("0")
print "sharp values %r" % values #print "sharp values %r" % values
return " ".join([".".join(values)] * 2) return " ".join([".".join(values)] * 2)
def weapon_stats_tuple(arg): def weapon_stats_tuple(arg):
parts = arg.split(",") parts = arg.split(",")
print "parts %r" % parts #print "parts %r" % parts
if len(parts) < 4: if len(parts) < 4:
print "not enough parts" print "not enough parts"
raise ValueError("Bad arg, use 'name,weapon_type,sharpness,raw'") raise ValueError("Bad arg, use 'name,weapon_type,sharpness,raw'")
weapon = {} weapon = {}
weapon["name"] = parts[0] weapon["name"] = parts[0]
weapon["wtype"] = get_wtype_match(parts[1]) weapon["wtype"] = get_wtype_match(parts[1])
multiplier = WeaponType.multiplier(weapon["wtype"]) weapon["attack"] = int(parts[2])
weapon["attack"] = multiplier * int(parts[2])
weapon["affinity"] = parts[3] weapon["affinity"] = parts[3]
weapon["sharpness"] = _make_db_sharpness_string(parts[4]) weapon["sharpness"] = _make_db_sharpness_string(parts[4])
if len(parts) == 5: if len(parts) == 5:
@ -64,13 +63,13 @@ def weapon_stats_tuple(arg):
weapon["element"] = get_element_match(parts[5]) weapon["element"] = get_element_match(parts[5])
weapon["element_attack"] = int(parts[6]) weapon["element_attack"] = int(parts[6])
else: else:
print "bad part number" #print "bad part number"
raise ValueError("Bad arg, use 'name,weapon_type,sharpness,raw'") raise ValueError("Bad arg, use 'name,weapon_type,sharpness,raw'")
weapon["element_2"] = None weapon["element_2"] = None
weapon["awaken"] = None weapon["awaken"] = None
weapon["element_2_attack"] = None weapon["element_2_attack"] = None
weapon["_id"] = -1 weapon["_id"] = -1
print "making model" #print "making model"
return Weapon(weapon) return Weapon(weapon)
@ -118,7 +117,8 @@ def get_skill_names(args):
"Awaken" if args.awaken else "", "Awaken" if args.awaken else "",
skills.AttackUp.name(args.attack_up), skills.AttackUp.name(args.attack_up),
skills.CriticalEye.name(args.critical_eye), skills.CriticalEye.name(args.critical_eye),
skills.ElementAttackUp.name(args.element_up)] skills.ElementAttackUp.name(args.element_up),
"Blunt Power" if args.blunt_power else ""]
def percent_change(a, b): def percent_change(a, b):
@ -151,6 +151,9 @@ def _add_skill_args(parser):
help="With virus affinity boost, must be either" help="With virus affinity boost, must be either"
+" 15 (normal) or 30 (with Frenzy Res skill)", +" 15 (normal) or 30 (with Frenzy Res skill)",
type=int, choices=[0, 15, 30], default=0) 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): def parse_args(argv):
@ -172,6 +175,9 @@ def parse_args(argv):
parser.add_argument("-d", "--diff", action="store_true", default=False, parser.add_argument("-d", "--diff", action="store_true", default=False,
help="Show percent difference in damage to each part" help="Show percent difference in damage to each part"
+" from first weapon in list.") +" 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("-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."
@ -318,7 +324,10 @@ def print_damage_percent_diff(names, damage_map_base, weapon_damage_map, parts):
if __name__ == '__main__': if __name__ == '__main__':
args = parse_args(None) args = parse_args(None)
db = MHDB(_pathfix.db_path) if args.monster_hunter_cross:
db = MHDBX()
else:
db = MHDB()
motiondb = MotionValueDB(_pathfix.motion_values_path) motiondb = MotionValueDB(_pathfix.motion_values_path)
monster = db.get_monster_by_name(args.monster) monster = db.get_monster_by_name(args.monster)
@ -399,7 +408,9 @@ if __name__ == '__main__':
awaken=skill_args.awaken, awaken=skill_args.awaken,
artillery_level=skill_args.artillery, artillery_level=skill_args.artillery,
limit_parts=args.parts, limit_parts=args.parts,
frenzy_bonus=skill_args.frenzy) frenzy_bonus=skill_args.frenzy,
is_true_attack=args.monster_hunter_cross,
blunt_power=skill_args.blunt_power)
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:

@ -28,13 +28,13 @@ def raw_damage(true_raw, sharpness, affinity, monster_hitbox, motion):
* monster_hitbox / 100.0) * monster_hitbox / 100.0)
def element_damage(element, sharpness, monster_ehitbox): def element_damage(raw_element, sharpness, monster_ehitbox):
""" """
Calculate elemental damage to a monster part with the given elemental Calculate elemental damage to a monster part with the given elemental
attack, the given sharpness, and the given monster elemental weakness. attack, the given sharpness, and the given monster elemental weakness.
Note that this is independent of the motion value of the attack. Note that this is independent of the motion value of the attack.
""" """
return floor(element / 10.0 return floor(raw_element
* SharpnessLevel.element_modifier(sharpness) * SharpnessLevel.element_modifier(sharpness)
* monster_ehitbox / 100.0) * monster_ehitbox / 100.0)
@ -171,7 +171,7 @@ class WeaponMonsterDamage(object):
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): frenzy_bonus=0, blunt_power=False, is_true_attack=False):
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
@ -183,6 +183,8 @@ class WeaponMonsterDamage(object):
self.element_skill = element_skill self.element_skill = element_skill
self.awaken = awaken self.awaken = awaken
self.artillery_level = artillery_level self.artillery_level = artillery_level
self.blunt_power = blunt_power
self.is_true_attack = is_true_attack
self.limit_parts = limit_parts self.limit_parts = limit_parts
# 15 normaly for overcoming the virus, 30 with frenzy res skill # 15 normaly for overcoming the virus, 30 with frenzy res skill
assert frenzy_bonus in (0, 15, 30) assert frenzy_bonus in (0, 15, 30)
@ -199,6 +201,9 @@ class WeaponMonsterDamage(object):
self.cb_phial_damage = defaultdict(dict) self.cb_phial_damage = defaultdict(dict)
self.weapon_type = self.weapon["wtype"] self.weapon_type = self.weapon["wtype"]
if is_true_attack:
self.true_raw = self.weapon["attack"]
else:
self.true_raw = (self.weapon["attack"] self.true_raw = (self.weapon["attack"]
/ WeaponType.multiplier(self.weapon_type)) / WeaponType.multiplier(self.weapon_type))
if sharp_plus: if sharp_plus:
@ -207,7 +212,8 @@ 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"]:
if "/" in self.weapon["affinity"]: if (isinstance(self.weapon["affinity"], str)
and "/" in self.weapon["affinity"]):
self.chaotic = True self.chaotic = True
# Handle chaotic gore affinity, e.g. -35/10. This means that # Handle chaotic gore affinity, e.g. -35/10. This means that
# 35% of the time it does a negative critical (75% damage) # 35% of the time it does a negative critical (75% damage)
@ -241,6 +247,11 @@ class WeaponMonsterDamage(object):
else: else:
self.eattack2 = 0 self.eattack2 = 0
if not self.is_true_attack and self.eattack:
self.eattack /= 10
if self.eattack2:
self.eattack2 /= 10
self.true_raw = skills.AttackUp.modified(attack_skill, self.true_raw = skills.AttackUp.modified(attack_skill,
self.true_raw) self.true_raw)
self.affinity = skills.CriticalEye.modified(critical_eye_skill, self.affinity = skills.CriticalEye.modified(critical_eye_skill,
@ -250,6 +261,14 @@ class WeaponMonsterDamage(object):
self.eattack2 = skills.ElementAttackUp.modified(element_skill, self.eattack2 = skills.ElementAttackUp.modified(element_skill,
self.eattack2) self.eattack2)
if self.blunt_power:
if self.sharpness in (SharpnessLevel.RED, SharpnessLevel.ORANGE):
self.true_raw += 30
elif self.sharpness == SharpnessLevel.YELLOW:
self.true_raw += 25
elif self.sharpness == SharpnessLevel.GREEN:
self.true_raw += 15
self.parts = [] self.parts = []
self.break_count = 0 self.break_count = 0
@ -266,6 +285,8 @@ class WeaponMonsterDamage(object):
@property @property
def attack(self): def attack(self):
if self.is_true_attack:
return self.true_raw
return self.true_raw * WeaponType.multiplier(self.weapon_type) return self.true_raw * WeaponType.multiplier(self.weapon_type)
def _calculate_damage(self): def _calculate_damage(self):

@ -4,6 +4,7 @@ Module for accessing the sqlite monster hunter db from
import os.path import os.path
import sqlite3 import sqlite3
import json
from mhapi import model from mhapi import model
@ -528,3 +529,67 @@ class MHDB(object):
else: else:
ucomps = None ucomps = None
item_data.set_components(ccomps, ucomps) item_data.set_components(ccomps, ucomps)
class MHDBX(object):
"""
Wrapper around Monster Hunter Cross (X) JSON data. Attempts limited
compatibility with original 4U MHDB class.
Uses MHDB object, as temporariy hack for MHX data that is not yet
available or integrated.
"""
def __init__(self):
"""
Loads JSON data, keeps in memory.
"""
module_path = os.path.dirname(__file__)
mhx_db_path = os.path.abspath(os.path.join(module_path, "..",
"db", "mhx"))
self._4udb = MHDB()
self._weapon_list = []
self._weapons_by_name = {}
with open(os.path.join(mhx_db_path, "weapon_list.json")) as f:
wlist = json.load(f)
for i, wdata in enumerate(wlist):
wdata["_id"] = i
weapon = model.Weapon(wdata)
self._weapon_list.append(weapon)
self._weapons_by_name[weapon.name_jp] = weapon
def get_weapon_by_name(self, name):
return self._weapons_by_name.get(name)
def get_monster_by_name(self, *args, **kwargs):
return self._4udb.get_monster_by_name(*args, **kwargs)
def get_monster_damage(self, *args, **kwargs):
return self._4udb.get_monster_damage(*args, **kwargs)
def get_monster_breaks(self, *args, **kwargs):
return self._4udb.get_monster_breaks(*args, **kwargs)
def get_weapons_by_query(self, wtype=None, element=None,
final=None):
"""
@element can have the special value 'Raw' to search for weapons
with no element. Otherwise @element is searched for in both
awaken and native, and can be a status or an element.
@final should be string '1' or '0'
"""
final = int(final)
results = []
for w in self._weapon_list:
if wtype is not None and w.wtype != wtype:
continue
if (element is not None
and element not in (w.element, w.element_2)
and not (element == "Raw" and not w.element)):
continue
if final is not None and w.final != final:
continue
results.append(w)
return results

@ -162,6 +162,16 @@ class SharpnessLevel(EnumBase):
PURPLE: (1.44, 1.20), PURPLE: (1.44, 1.20),
} }
_modifier_mhx = {
RED: (0.50, 0.25),
ORANGE: (0.75, 0.50),
YELLOW: (1.00, 0.75),
GREEN: (1.05, 1.00),
BLUE: (1.20, 1.0625),
WHITE: (1.32, 1.125),
}
@classmethod @classmethod
def raw_modifier(cls, sharpness): def raw_modifier(cls, sharpness):
return cls._modifier[sharpness][0] return cls._modifier[sharpness][0]
@ -177,8 +187,11 @@ class WeaponSharpness(ModelBase):
points at each level. E.g. the 0th item in the list is the amount of points at each level. E.g. the 0th item in the list is the amount of
RED sharpness, the 1st item is ORANGE, etc. RED sharpness, the 1st item is ORANGE, etc.
""" """
def __init__(self, db_string): def __init__(self, db_string_or_list):
self.value_list = [int(s) for s in db_string.split(".")] if isinstance(db_string_or_list, list):
self.value_list = db_string_or_list
else:
self.value_list = [int(s) for s in db_string_or_list.split(".")]
self._max = None self._max = None
@property @property
@ -364,6 +377,14 @@ class Weapon(ItemCraftable):
if self.wtype in ("Light Bowgun", "Heavy Bowgun", "Bow"): if self.wtype in ("Light Bowgun", "Heavy Bowgun", "Bow"):
self._data["sharpness"] = self._data["sharpness_plus"] = None self._data["sharpness"] = self._data["sharpness_plus"] = None
return return
if isinstance(self._row["sharpness"], list):
# MHX JSON data, already desired format, but doesn't have
# purple so we append 0
self.sharpness = WeaponSharpness(self._row["sharpness"] + [0])
self.sharpness_plus = WeaponSharpness(
self._row["sharpness_plus"] + [0])
else:
# 4U data from db
parts = self._row["sharpness"].split(" ") parts = self._row["sharpness"].split(" ")
if len(parts) != 2: if len(parts) != 2:
raise ValueError("Bad sharpness value in db: '%s'" raise ValueError("Bad sharpness value in db: '%s'"

Loading…
Cancel
Save