add armor search, damage fixes

main
Bryce Allen 11 years ago
parent 5e3552728f
commit 784299dd53

@ -0,0 +1,109 @@
#!/usr/bin/env python
import sys
import argparse
import codecs
import _pathfix
from mhapi.db import MHDB
def get_utf8_writer(writer):
return codecs.getwriter("utf8")(writer)
def parse_args(argv):
parser = argparse.ArgumentParser(description=
"Find armor with the specified skills and sort by"
" (max points, defense). Takes into account native points"
" and slots that fit decorations for the first skill."
)
parser.add_argument("-g", "--gunner", action="store_true",
default=False,
help="search for gunner instead of blademaster")
parser.add_argument("-d", "--min-defense", type=int,
help="Only include armors with min defense")
parser.add_argument("-t", "--type",
help="Head, Body, Arms, Waist, or Legs")
parser.add_argument("skills", nargs="+",
help="One or more armor skills to search for")
return parser.parse_args(argv)
def find_armors(args):
db = MHDB(_pathfix.db_path)
skills = {}
skill_ids = [] # preserve arg order
decorations = {}
for skill_name in args.skills:
sid = db.get_skill_tree_id(skill_name)
if sid is None:
raise ValueError("Skill '%s' not found" % skill_name)
skills[skill_name] = sid
skill_ids.append(sid)
#print skill_name, sid
ds = db.get_decorations_by_skills([sid])
for d in ds:
d.set_skills(db.get_item_skills(d.id))
decoration_values = get_decoration_values(sid, ds)
decorations[sid] = (ds, decoration_values)
print "%s[%s]:" % (skill_name, sid), ", ".join(d.name for d in ds), \
decoration_values
htype = "Gunner" if args.gunner else "Blade"
armors = db.get_armors_by_skills(skill_ids, htype)
skill_totals = {}
for a in armors:
skills = db.get_item_skills(a.id)
if not skills:
print "Error getting skills for '%s' (%d)" % (a.name, a.id)
sys.exit(1)
a.set_skills(skills)
# calculate total using decorations for first skill only. This
# works great if all skill shave same slot values; if not it's
# very messy to figure out what is 'best'
total = 0
first = True
for sid in skill_ids:
if first:
dv = decorations[sid][1]
first = False
else:
dv = []
total += a.skill(sid, dv)
skill_totals[a.id] = total
armors.sort(key=lambda a: (skill_totals[a.id], a.defense), reverse=True)
for a in armors:
if args.min_defense and a.defense < args.min_defense:
continue
if args.type and a.slot != args.type:
continue
total = skill_totals[a.id]
print a.id, skill_totals[a.id], a.one_line_u()
print " ", a.one_line_skills_u(args.skills)
def get_decoration_values(skill_id, decorations):
# TODO: write script to compute this and shove innto skill_tree table
values = [0, 0, 0]
for d in decorations:
assert d.num_slots is not None
# some skills like Handicraft have multiple decorations with
# same number of slots - use the best one
new = d.skills[skill_id]
current = values[d.num_slots-1]
if new > current:
values[d.num_slots-1] = new
return values
if __name__ == '__main__':
args = parse_args(None)
sys.stdout = get_utf8_writer(sys.stdout)
find_armors(args)

@ -18,9 +18,11 @@ def percent_change(a, b):
def parse_args(argv): def parse_args(argv):
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(description=
"Calculate damage to monster from different weapons of the" "Calculate damage to monster from different weapons of the"
" same class" " 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."
) )
parser.add_argument("-s", "--sharpness-plus-one", action="store_true", parser.add_argument("-s", "--sharpness-plus-one", action="store_true",
default=False, default=False,

@ -5,6 +5,7 @@ import json
import sys import sys
import errno import errno
from collections import defaultdict from collections import defaultdict
import urllib
import _pathfix import _pathfix
@ -20,6 +21,17 @@ def mkdirs_p(path):
raise raise
SAFE_CHARS = " &'+\""
def file_path(path, model_object, use_name=False):
if use_name and "name" in model_object:
key = urllib.quote(model_object.name.encode("utf8"), SAFE_CHARS)
else:
key = str(model_object.id)
return os.path.join(path, "%s.json" % key)
def write_list_file(path, model_list): def write_list_file(path, model_list):
list_path = os.path.join(path, "_list.json") list_path = os.path.join(path, "_list.json")
with open(list_path, "w") as f: with open(list_path, "w") as f:
@ -39,7 +51,7 @@ def monster_json(db, path):
indexes = {} indexes = {}
for m in monsters: for m in monsters:
monster_path = os.path.join(path, "%s.json" % m.id) monster_path = file_path(path, m)
m.update_indexes(indexes) m.update_indexes(indexes)
data = m.as_data() data = m.as_data()
damage = db.get_monster_damage(m.id) damage = db.get_monster_damage(m.id)
@ -58,7 +70,7 @@ def weapon_json(db, path):
indexes = {} indexes = {}
for w in weapons: for w in weapons:
weapon_path = os.path.join(path, "%s.json" % w.id) weapon_path = file_path(path, w)
w.update_indexes(indexes) w.update_indexes(indexes)
with open(weapon_path, "w") as f: with open(weapon_path, "w") as f:
w.json_dump(f) w.json_dump(f)
@ -73,7 +85,7 @@ def items_json(db, path):
indexes = {} indexes = {}
for item in items: for item in items:
item_path = os.path.join(path, "%s.json" % item.id) item_path = file_path(path, item)
item.update_indexes(indexes) item.update_indexes(indexes)
with open(item_path, "w") as f: with open(item_path, "w") as f:
item.json_dump(f) item.json_dump(f)

@ -199,6 +199,11 @@ class WeaponMonsterDamage(object):
self.etype = self.weapon.awaken self.etype = self.weapon.awaken
self.eattack = self.weapon.awaken_attack self.eattack = self.weapon.awaken_attack
if self.eattack:
self.eattack = int(self.eattack)
else:
self.eattack = 0
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,

@ -102,12 +102,12 @@ class MHDB(object):
""" """
List of unicode strings. List of unicode strings.
""" """
item_types.sort() args = sorted(item_types)
placeholders = ", ".join(["?"] * len(item_types)) placeholders = ", ".join(["?"] * len(item_types))
return self._query_all("item_names", """ return self._query_all("item_names", """
SELECT _id, name FROM items SELECT _id, name FROM items
WHERE type IN (%s) WHERE type IN (%s)
""" % placeholders, tuple(item_types), model_cls=field_model("name")) """ % placeholders, tuple(args), model_cls=field_model("name"))
def get_items(self, item_types=None): def get_items(self, item_types=None):
""" """
@ -115,7 +115,7 @@ class MHDB(object):
""" """
q = "SELECT * FROM items" q = "SELECT * FROM items"
if item_types: if item_types:
item_types.sort() item_types = sorted(item_types)
placeholders = ", ".join(["?"] * len(item_types)) placeholders = ", ".join(["?"] * len(item_types))
q += "\nWHERE type IN (%s)" % placeholders q += "\nWHERE type IN (%s)" % placeholders
item_types = tuple(item_types) item_types = tuple(item_types)
@ -304,6 +304,104 @@ class MHDB(object):
WHERE items.name=? WHERE items.name=?
""", (name,), model_cls=model.Weapon) """, (name,), model_cls=model.Weapon)
def get_armors(self):
return self._query_all("armors", """
SELECT * FROM armor
LEFT JOIN items ON armor._id = items._id
""", model_cls=model.Armor)
def get_armor(self, armor_id):
return self._query_one("armor", """
SELECT * FROM armor
LEFT JOIN items ON armor._id = items._id
WHERE armor._id=?
""", (armor_id,), model_cls=model.Armor)
def get_armor_by_name(self, name):
return self._query_one("armor", """
SELECT * FROM armor
LEFT JOIN items ON armor._id = items._id
WHERE items.name=?
""", (name,), model_cls=model.Armor)
def get_item_skills(self, item_id):
return self._query_all("item_skills", """
SELECT item_to_skill_tree.*, skill_trees.name
FROM item_to_skill_tree
LEFT JOIN skill_trees
ON item_to_skill_tree.skill_tree_id = skill_trees._id
WHERE item_to_skill_tree.item_id=?
""", (item_id,), model_cls=model.ItemSkill)
def get_decorations(self):
return self._query_all("decorations", """
SELECT *
FROM decorations
INNER JOIN items
ON items._id = decorations._id
""", model_cls=model.Decoration)
def get_decoration(self, decoration_id):
return self._query_one("decoration", """
SELECT *
FROM decorations
INNER JOIN items
ON items._id = decorations._id
WHERE decorations._id = ?
""", (decoration_id,), model_cls=model.Decoration)
def get_decoration_by_name(self, name):
return self._query_all("decoration", """
SELECT *
FROM decorations
INNER JOIN items
ON items._id = decorations._id
WHERE items.name = ?
""", (name,), model_cls=model.Decoration)
def get_skill_tree_id(self, skill_tree_name):
result = self._query_one("skill", """
SELECT _id FROM skill_trees
WHERE name=?
""", (skill_tree_name,))
if result:
return result["_id"]
return None
def get_decorations_by_skills(self, skill_tree_ids):
args = sorted(skill_tree_ids)
placeholders = ", ".join(["?"] * len(skill_tree_ids))
return self._query_all("decorations", """
SELECT items.*, decorations.*
FROM item_to_skill_tree
LEFT JOIN items
ON items._id = item_to_skill_tree.item_id
LEFT JOIN decorations
ON decorations._id = item_to_skill_tree.item_id
WHERE items.type = 'Decoration'
AND item_to_skill_tree.skill_tree_id IN (%s)
AND item_to_skill_tree.point_value > 0
GROUP BY item_to_skill_tree.item_id
""" % placeholders, tuple(args), model_cls=model.Decoration)
def get_armors_by_skills(self, skill_tree_ids, hunter_type):
args = sorted(skill_tree_ids)
placeholders = ", ".join(["?"] * len(skill_tree_ids))
args += [hunter_type]
return self._query_all("decorations", """
SELECT items.*, armor.*
FROM item_to_skill_tree
LEFT JOIN items
ON items._id = item_to_skill_tree.item_id
LEFT JOIN armor
ON armor._id = item_to_skill_tree.item_id
WHERE items.type = 'Armor'
AND item_to_skill_tree.skill_tree_id IN (%s)
AND item_to_skill_tree.point_value > 0
AND armor.hunter_type IN ('Both', ?)
GROUP BY item_to_skill_tree.item_id
""" % placeholders, tuple(args), model_cls=model.Armor)
def get_monster_breaks(self, monster_id): def get_monster_breaks(self, monster_id):
""" """
List of strings. List of strings.

@ -54,6 +54,9 @@ class RowModel(ModelBase):
def __getitem__(self, key): def __getitem__(self, key):
return self._data[key] return self._data[key]
def __contains__(self, key):
return key in self._data
def fields(self): def fields(self):
return self._data.keys() return self._data.keys()
@ -190,6 +193,76 @@ class WeaponSharpness(ModelBase):
return self.value_list return self.value_list
class ItemWithSkills(RowModel):
def __init__(self, item_row):
super(ItemWithSkills, self).__init__(item_row)
self.skills = None
self.skill_ids = []
self.skill_names = []
def set_skills(self, item_skills):
self.skills = {}
for s in item_skills:
self.skills[s.skill_tree_id] = s.point_value
self.skills[s.name] = s.point_value
self.skill_ids.append(s.skill_tree_id)
self.skill_names.append(s.name)
def skill(self, skill_id_or_name):
return self.skills.get(skill_id_or_name, 0)
def one_line_skills_u(self, skill_names=None):
if skill_names is None:
skill_names = sorted(self.skill_names)
return ", ".join("%s %d" % (name, self.skills[name])
for name in skill_names
if name in self.skills)
class Armor(ItemWithSkills):
_indexes = { "name": ["id"],
"slot": ["id", "name"] }
_one_line_template = string.Template(
"$name ($slot) Def $defense-$max_defense Slot $num_slots"
)
def __init__(self, armor_item_row):
super(Armor, self).__init__(armor_item_row)
def one_line_u(self):
return self._one_line_template.substitute(self.as_data())
def skill(self, skill_id_or_name, decoration_values=()):
"""
decoration_values should be a list of points from the given
number of slots, e.g. [1, 3] means that one slot gets 1 point
and two slots get 3 points, [1, 0, 4] means that one slot gets 1 point,
there is no two slot gem, and three slots gets 4 points.
"""
assert self.skills is not None
total = self.skills.get(skill_id_or_name, 0)
slots_left = self.num_slots
for slots in xrange(len(decoration_values), 0, -1):
if slots_left == 0:
break
decoration_value = decoration_values[slots-1]
if not decoration_value:
continue
if slots <= slots_left:
total += decoration_value
slots_left -= slots
return total
class Decoration(ItemWithSkills):
pass
class ItemSkill(RowModel):
pass
class Weapon(RowModel): class Weapon(RowModel):
_list_fields = ["id", "wtype", "name"] _list_fields = ["id", "wtype", "name"]
_indexes = { "name": ["id"], _indexes = { "name": ["id"],

Loading…
Cancel
Save