add mhx damage
This commit is contained in:
@@ -7,8 +7,8 @@ import copy
|
||||
|
||||
import _pathfix
|
||||
|
||||
from mhapi.db import MHDB
|
||||
from mhapi.damage import MotionValueDB, WeaponMonsterDamage, WeaponType
|
||||
from mhapi.db import MHDB, MHDBX
|
||||
from mhapi.damage import MotionValueDB, WeaponMonsterDamage
|
||||
from mhapi.model import SharpnessLevel, Weapon
|
||||
from mhapi import skills
|
||||
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):
|
||||
print "level string", level_string
|
||||
#print "level string", level_string
|
||||
level_value = SharpnessLevel.__dict__[level_string.upper()]
|
||||
print "level value", level_value
|
||||
#print "level value", level_value
|
||||
values = []
|
||||
for i in xrange(SharpnessLevel.PURPLE+1):
|
||||
if i <= level_value:
|
||||
values.append("1")
|
||||
else:
|
||||
values.append("0")
|
||||
print "sharp values %r" % values
|
||||
#print "sharp values %r" % values
|
||||
return " ".join([".".join(values)] * 2)
|
||||
|
||||
|
||||
def weapon_stats_tuple(arg):
|
||||
parts = arg.split(",")
|
||||
print "parts %r" % parts
|
||||
#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])
|
||||
multiplier = WeaponType.multiplier(weapon["wtype"])
|
||||
weapon["attack"] = multiplier * int(parts[2])
|
||||
weapon["attack"] = int(parts[2])
|
||||
weapon["affinity"] = parts[3]
|
||||
weapon["sharpness"] = _make_db_sharpness_string(parts[4])
|
||||
if len(parts) == 5:
|
||||
@@ -64,13 +63,13 @@ def weapon_stats_tuple(arg):
|
||||
weapon["element"] = get_element_match(parts[5])
|
||||
weapon["element_attack"] = int(parts[6])
|
||||
else:
|
||||
print "bad part number"
|
||||
#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"
|
||||
#print "making model"
|
||||
return Weapon(weapon)
|
||||
|
||||
|
||||
@@ -118,7 +117,8 @@ def get_skill_names(args):
|
||||
"Awaken" if args.awaken else "",
|
||||
skills.AttackUp.name(args.attack_up),
|
||||
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):
|
||||
@@ -151,6 +151,9 @@ def _add_skill_args(parser):
|
||||
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):
|
||||
@@ -172,6 +175,9 @@ def parse_args(argv):
|
||||
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("-m", "--match", nargs="*",
|
||||
help="WEAPON_TYPE,ELEMENT_OR_STATUS_OR_RAW"
|
||||
+" 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__':
|
||||
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)
|
||||
|
||||
monster = db.get_monster_by_name(args.monster)
|
||||
@@ -399,7 +408,9 @@ if __name__ == '__main__':
|
||||
awaken=skill_args.awaken,
|
||||
artillery_level=skill_args.artillery,
|
||||
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),
|
||||
if wd.etype:
|
||||
if wd.etype2:
|
||||
|
||||
@@ -28,13 +28,13 @@ def raw_damage(true_raw, sharpness, affinity, monster_hitbox, motion):
|
||||
* 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
|
||||
attack, the given sharpness, and the given monster elemental weakness.
|
||||
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)
|
||||
* monster_ehitbox / 100.0)
|
||||
|
||||
@@ -171,7 +171,7 @@ class WeaponMonsterDamage(object):
|
||||
critical_eye_skill=skills.CriticalEye.NONE,
|
||||
element_skill=skills.ElementAttackUp.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.monster = monster_row
|
||||
self.monster_damage = monster_damage
|
||||
@@ -183,6 +183,8 @@ class WeaponMonsterDamage(object):
|
||||
self.element_skill = element_skill
|
||||
self.awaken = awaken
|
||||
self.artillery_level = artillery_level
|
||||
self.blunt_power = blunt_power
|
||||
self.is_true_attack = is_true_attack
|
||||
self.limit_parts = limit_parts
|
||||
# 15 normaly for overcoming the virus, 30 with frenzy res skill
|
||||
assert frenzy_bonus in (0, 15, 30)
|
||||
@@ -199,6 +201,9 @@ class WeaponMonsterDamage(object):
|
||||
self.cb_phial_damage = defaultdict(dict)
|
||||
|
||||
self.weapon_type = self.weapon["wtype"]
|
||||
if is_true_attack:
|
||||
self.true_raw = self.weapon["attack"]
|
||||
else:
|
||||
self.true_raw = (self.weapon["attack"]
|
||||
/ WeaponType.multiplier(self.weapon_type))
|
||||
if sharp_plus:
|
||||
@@ -207,7 +212,8 @@ class WeaponMonsterDamage(object):
|
||||
self.sharpness = self.weapon.sharpness.max
|
||||
#print "sharpness=", self.sharpness
|
||||
if self.weapon["affinity"]:
|
||||
if "/" in self.weapon["affinity"]:
|
||||
if (isinstance(self.weapon["affinity"], str)
|
||||
and "/" in self.weapon["affinity"]):
|
||||
self.chaotic = True
|
||||
# Handle chaotic gore affinity, e.g. -35/10. This means that
|
||||
# 35% of the time it does a negative critical (75% damage)
|
||||
@@ -241,6 +247,11 @@ class WeaponMonsterDamage(object):
|
||||
else:
|
||||
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)
|
||||
self.affinity = skills.CriticalEye.modified(critical_eye_skill,
|
||||
@@ -250,6 +261,14 @@ class WeaponMonsterDamage(object):
|
||||
self.eattack2 = skills.ElementAttackUp.modified(element_skill,
|
||||
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.break_count = 0
|
||||
|
||||
@@ -266,6 +285,8 @@ class WeaponMonsterDamage(object):
|
||||
|
||||
@property
|
||||
def attack(self):
|
||||
if self.is_true_attack:
|
||||
return self.true_raw
|
||||
return self.true_raw * WeaponType.multiplier(self.weapon_type)
|
||||
|
||||
def _calculate_damage(self):
|
||||
|
||||
65
mhapi/db.py
65
mhapi/db.py
@@ -4,6 +4,7 @@ Module for accessing the sqlite monster hunter db from
|
||||
|
||||
import os.path
|
||||
import sqlite3
|
||||
import json
|
||||
|
||||
from mhapi import model
|
||||
|
||||
@@ -528,3 +529,67 @@ class MHDB(object):
|
||||
else:
|
||||
ucomps = None
|
||||
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),
|
||||
}
|
||||
|
||||
_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
|
||||
def raw_modifier(cls, sharpness):
|
||||
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
|
||||
RED sharpness, the 1st item is ORANGE, etc.
|
||||
"""
|
||||
def __init__(self, db_string):
|
||||
self.value_list = [int(s) for s in db_string.split(".")]
|
||||
def __init__(self, db_string_or_list):
|
||||
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
|
||||
|
||||
@property
|
||||
@@ -364,6 +377,14 @@ class Weapon(ItemCraftable):
|
||||
if self.wtype in ("Light Bowgun", "Heavy Bowgun", "Bow"):
|
||||
self._data["sharpness"] = self._data["sharpness_plus"] = None
|
||||
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(" ")
|
||||
if len(parts) != 2:
|
||||
raise ValueError("Bad sharpness value in db: '%s'"
|
||||
|
||||
Reference in New Issue
Block a user