Compare commits
7 Commits
8ce30489cf
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
58183d8791 | ||
|
|
ff29b205bd | ||
|
|
228c594ca9 | ||
|
|
6b57d498b6 | ||
|
|
e9c710ca99 | ||
|
|
57f7060794 | ||
|
|
c2d967b7f3 |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -2,3 +2,7 @@
|
|||||||
README.html
|
README.html
|
||||||
RECOMMENDATIONS.html
|
RECOMMENDATIONS.html
|
||||||
tmp/
|
tmp/
|
||||||
|
*.bak
|
||||||
|
web/jsonapi/
|
||||||
|
web/*/rewards/
|
||||||
|
web/*/damage/
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ link:https://github.com/kamegami13/MonsterHunter4UDatabase[MonsterHunter4UDataba
|
|||||||
Android app by DavianCorp, which is also MIT licensed. See
|
Android app by DavianCorp, which is also MIT licensed. See
|
||||||
link:db/COPYING.mh4udb[] for license details.
|
link:db/COPYING.mh4udb[] for license details.
|
||||||
|
|
||||||
|
Rise data is from link:https://mhrise.mhrice.info/about.html[MHRice].
|
||||||
|
|
||||||
== Example usage
|
== Example usage
|
||||||
|
|
||||||
For a list of quests and hunts providing the specified monster part:
|
For a list of quests and hunts providing the specified monster part:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
# Set PYTHONPATH in lighttpd or other server config.
|
# Set PYTHONPATH in lighttpd or other server config.
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Script to generate static rewards files for all items.
|
Script to generate static rewards files for all items.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import codecs
|
import codecs
|
||||||
import urllib
|
import urllib.request, urllib.parse, urllib.error
|
||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
import _pathfix
|
import _pathfix
|
||||||
@@ -27,7 +27,7 @@ if __name__ == '__main__':
|
|||||||
elif len(sys.argv) == 2:
|
elif len(sys.argv) == 2:
|
||||||
outdir = sys.argv[1]
|
outdir = sys.argv[1]
|
||||||
else:
|
else:
|
||||||
print("Usage: %s [outdir]" % sys.argv[0])
|
print(("Usage: %s [outdir]" % sys.argv[0]))
|
||||||
sys.exit(os.EX_USAGE)
|
sys.exit(os.EX_USAGE)
|
||||||
|
|
||||||
err_out = get_utf8_writer(sys.stderr)
|
err_out = get_utf8_writer(sys.stderr)
|
||||||
@@ -46,7 +46,7 @@ if __name__ == '__main__':
|
|||||||
|
|
||||||
# write all names json to /items.json
|
# write all names json to /items.json
|
||||||
items_file = os.path.join(outdir, "items.json")
|
items_file = os.path.join(outdir, "items.json")
|
||||||
print "Writing", items_file
|
print("Writing", items_file)
|
||||||
with open(items_file, "w") as f:
|
with open(items_file, "w") as f:
|
||||||
out = get_utf8_writer(f)
|
out = get_utf8_writer(f)
|
||||||
out.write("[")
|
out.write("[")
|
||||||
@@ -66,7 +66,7 @@ if __name__ == '__main__':
|
|||||||
item_id = item.id
|
item_id = item.id
|
||||||
encoded_name = name.encode("utf8")
|
encoded_name = name.encode("utf8")
|
||||||
item_file = os.path.join(outdir, encoded_name + ".txt")
|
item_file = os.path.join(outdir, encoded_name + ".txt")
|
||||||
print "Writing", item_id, item_file
|
print("Writing", item_id, item_file)
|
||||||
with open(item_file, "w") as f:
|
with open(item_file, "w") as f:
|
||||||
out = get_utf8_writer(f)
|
out = get_utf8_writer(f)
|
||||||
item_row = rewards.find_item(db, name, err_out)
|
item_row = rewards.find_item(db, name, err_out)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
@@ -57,7 +57,7 @@ def find_armors(args):
|
|||||||
matches = difflib.get_close_matches(skill_name, skill_tree_names,
|
matches = difflib.get_close_matches(skill_name, skill_tree_names,
|
||||||
1, 0.5)
|
1, 0.5)
|
||||||
if matches:
|
if matches:
|
||||||
print "Fuzzy Match:", matches[0]
|
print("Fuzzy Match:", matches[0])
|
||||||
sid = skill_tree_id_map.get(matches[0])
|
sid = skill_tree_id_map.get(matches[0])
|
||||||
skill_name = matches[0]
|
skill_name = matches[0]
|
||||||
args.skills[i] = skill_name
|
args.skills[i] = skill_name
|
||||||
@@ -71,8 +71,8 @@ def find_armors(args):
|
|||||||
d.set_skills(db.get_item_skills(d.id))
|
d.set_skills(db.get_item_skills(d.id))
|
||||||
decoration_values = get_decoration_values(sid, ds)[1]
|
decoration_values = get_decoration_values(sid, ds)[1]
|
||||||
decorations[sid] = (ds, decoration_values)
|
decorations[sid] = (ds, decoration_values)
|
||||||
print "%s[%s]:" % (skill_name, sid), ", ".join(d.name for d in ds), \
|
print("%s[%s]:" % (skill_name, sid), ", ".join(d.name for d in ds), \
|
||||||
decoration_values
|
decoration_values)
|
||||||
|
|
||||||
htype = "Gunner" if args.gunner else "Blade"
|
htype = "Gunner" if args.gunner else "Blade"
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ def find_armors(args):
|
|||||||
for a in armors:
|
for a in armors:
|
||||||
skills = db.get_item_skills(a.id)
|
skills = db.get_item_skills(a.id)
|
||||||
if not skills:
|
if not skills:
|
||||||
print "Error getting skills for '%s' (%d)" % (a.name, a.id)
|
print("Error getting skills for '%s' (%d)" % (a.name, a.id))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
a.set_skills(skills)
|
a.set_skills(skills)
|
||||||
# calculate total using decorations for first skill only. This
|
# calculate total using decorations for first skill only. This
|
||||||
@@ -113,12 +113,12 @@ def find_armors(args):
|
|||||||
if args.type and a.slot != args.type:
|
if args.type and a.slot != args.type:
|
||||||
continue
|
continue
|
||||||
total = skill_totals[a.id]
|
total = skill_totals[a.id]
|
||||||
print skill_totals[a.id], a.one_line_u(),
|
print(skill_totals[a.id], a.one_line_u(), end=' ')
|
||||||
if args.resist:
|
if args.resist:
|
||||||
print args.resist.title(), a[args.resist + "_res"]
|
print(args.resist.title(), a[args.resist + "_res"])
|
||||||
else:
|
else:
|
||||||
print
|
print()
|
||||||
print " ", a.one_line_skills_u(args.skills)
|
print(" ", a.one_line_skills_u(args.skills))
|
||||||
|
|
||||||
|
|
||||||
def str_lower(x):
|
def str_lower(x):
|
||||||
|
|||||||
507
bin/mhdamage.py
507
bin/mhdamage.py
@@ -1,17 +1,21 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
import shlex
|
import shlex
|
||||||
import copy
|
import copy
|
||||||
|
import codecs
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
from collections import defaultdict
|
||||||
|
|
||||||
import _pathfix
|
import _pathfix
|
||||||
|
|
||||||
from mhapi.db import MHDB, MHDBX
|
from mhapi.db import MHDB, MHDBX
|
||||||
from mhapi.damage import MotionValueDB, WeaponMonsterDamage
|
from mhapi.damage import MotionValueDB, WeaponMonsterDamage, WeaponType
|
||||||
from mhapi.model import SharpnessLevel, Weapon, ItemStars
|
from mhapi.model import SharpnessLevel, Weapon, ItemStars
|
||||||
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, DAMAGE_TYPES
|
||||||
|
|
||||||
|
|
||||||
def weapon_match_tuple(arg):
|
def weapon_match_tuple(arg):
|
||||||
@@ -54,7 +58,7 @@ def _make_db_sharpness_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 range(SharpnessLevel.PURPLE+1):
|
||||||
if i <= level_value:
|
if i <= level_value:
|
||||||
values.append("1")
|
values.append("1")
|
||||||
else:
|
else:
|
||||||
@@ -65,9 +69,9 @@ def _make_db_sharpness_string(level_string):
|
|||||||
|
|
||||||
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]
|
||||||
@@ -154,14 +158,14 @@ def _add_skill_args(parser):
|
|||||||
default=False,
|
default=False,
|
||||||
help="add Awaken (FreeElemnt), 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=list(range(0, 5)), default=0,
|
||||||
help="1-4 for AuS, M, L, XL")
|
help="1-4 for AuS, M, L, XL")
|
||||||
parser.add_argument("-c", "--critical-eye",
|
parser.add_argument("-c", "--critical-eye",
|
||||||
type=int, choices=range(0, 5), default=0,
|
type=int, choices=list(range(0, 5)), default=0,
|
||||||
help="1-4 for CE+1, +2, +3 and Critical God")
|
help="1-4 for CE+1, +2, +3 and Critical God")
|
||||||
parser.add_argument("-e", "--element-up",
|
parser.add_argument("-e", "--element-up",
|
||||||
type=int, choices=range(0, 5), default=0,
|
type=int, choices=list(range(0, 6)), default=0,
|
||||||
help="1-4 for (element) Atk +1, +2, +3 and"
|
help="1-5 for (element) Atk +1, +2, +3 and"
|
||||||
" Element Attack Up")
|
" Element Attack Up")
|
||||||
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,
|
||||||
@@ -206,6 +210,9 @@ def parse_args(argv):
|
|||||||
parser.add_argument("--mhw", "--monster-hunter-world", action="store_true",
|
parser.add_argument("--mhw", "--monster-hunter-world", action="store_true",
|
||||||
default=False,
|
default=False,
|
||||||
help="Adjusted attack, use MHWorld values")
|
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="*",
|
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."
|
||||||
@@ -216,19 +223,27 @@ def parse_args(argv):
|
|||||||
+" Examples: 'Great Sword,Raw'"
|
+" Examples: 'Great Sword,Raw'"
|
||||||
+" 'Sword and Shield,Para'"
|
+" 'Sword and Shield,Para'"
|
||||||
+" 'HH,Blast' 'Hammer'",
|
+" 'HH,Blast' 'Hammer'",
|
||||||
type=weapon_match_tuple, default=[])
|
type=weapon_match_tuple, default=[],
|
||||||
|
action="append")
|
||||||
parser.add_argument("-w", "--weapon-custom", nargs="*",
|
parser.add_argument("-w", "--weapon-custom", nargs="*",
|
||||||
help="NAME,WEAPON_TYPE,TRUE_RAW,AFFINITY,SHARPNESS"
|
help="NAME,WEAPON_TYPE,TRUE_RAW,AFFINITY,SHARPNESS"
|
||||||
+"ELEMENT_TYPE,ELEMENT_ATTACK"
|
+"ELEMENT_TYPE,ELEMENT_ATTACK"
|
||||||
+" Add weapon based on stats."
|
+" Add weapon based on stats."
|
||||||
+" Examples: 'DinoSnS,SnS,190,0,Blue,Fire,30'"
|
+" Examples: 'DinoSnS,SnS,190,0,Blue,Fire,30'"
|
||||||
+" 'AkantorHam,Hammer,240,25,Green'",
|
+" 'AkantorHam,Hammer,240,25,Green'",
|
||||||
type=weapon_stats_tuple, default=[])
|
type=weapon_stats_tuple, default=[],
|
||||||
|
action="append")
|
||||||
parser.add_argument("-q", "--quest-level",
|
parser.add_argument("-q", "--quest-level",
|
||||||
help="village,guild[,permit[,arena]]",
|
help="village,guild[,permit[,arena]]",
|
||||||
type=quest_level_tuple)
|
type=quest_level_tuple)
|
||||||
parser.add_argument("monster",
|
parser.add_argument("-r", "--rarity",
|
||||||
help="Full name of monster")
|
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="*",
|
parser.add_argument("weapon", nargs="*",
|
||||||
help="One or more weapons of same class to compare,"
|
help="One or more weapons of same class to compare,"
|
||||||
" full names")
|
" full names")
|
||||||
@@ -253,24 +268,117 @@ def print_sorted_phial_damage(names, damage_map_base, weapon_damage_map, parts,
|
|||||||
_print_headers(parts, damage_map_base)
|
_print_headers(parts, damage_map_base)
|
||||||
|
|
||||||
for name in names_sorted:
|
for name in names_sorted:
|
||||||
print "%-20s:" % name,
|
print("%-20s:" % name, end=' ')
|
||||||
damage_map = weapon_damage_map[name]
|
damage_map = weapon_damage_map[name]
|
||||||
print "%0.2f" % avg_phial(damage_map, level=level),
|
print("%0.2f" % avg_phial(damage_map, level=level), end=' ')
|
||||||
for part in parts:
|
for part in parts:
|
||||||
part_damage = damage_map[part]
|
part_damage = damage_map[part]
|
||||||
#print "%0.2f" % sum(damage_map.cb_phial_damage[part][level]),
|
#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],
|
print("%0.2f:%0.2f:%0.2f" % damage_map.cb_phial_damage[part][level], end=' ')
|
||||||
print
|
print()
|
||||||
|
|
||||||
|
|
||||||
def _print_headers(parts, damage_map_base):
|
def _print_headers(parts, damage_map_base):
|
||||||
print
|
print()
|
||||||
avg_hitbox = (sum(damage_map_base[part].hitbox for part in parts)
|
avg_hitbox = (sum(damage_map_base[part].hitbox for part in parts)
|
||||||
/ float(len(parts)))
|
/ float(len(parts)))
|
||||||
cols = ["%s (%d)" % (part, damage_map_base[part].hitbox)
|
cols = ["%s (%d)" % (part, damage_map_base[part].hitbox)
|
||||||
for part in parts]
|
for part in parts]
|
||||||
cols = ["%s (%d)" % ("Avg", avg_hitbox)] + cols
|
cols = ["%s (%d)" % ("Avg", avg_hitbox)] + cols
|
||||||
print " | ".join(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 print_sorted_damage(names, damage_map_base, weapon_damage_map, parts):
|
||||||
@@ -288,31 +396,36 @@ def print_sorted_damage(names, damage_map_base, weapon_damage_map, parts):
|
|||||||
# for part in parts])
|
# for part in parts])
|
||||||
|
|
||||||
for name in names_sorted:
|
for name in names_sorted:
|
||||||
print "%-20s:" % name,
|
print("%-20s:" % name, end=' ')
|
||||||
damage_map = weapon_damage_map[name]
|
damage_map = weapon_damage_map[name]
|
||||||
print "%0.2f" % damage_map.averages["uniform"],
|
print("%0.2f" % damage_map.averages["uniform"], end=' ')
|
||||||
for part in parts:
|
for part in parts:
|
||||||
part_damage = damage_map[part]
|
part_damage = damage_map[part]
|
||||||
print "% 2d" % part_damage.average(),
|
print("% 2d" % part_damage.average(), end=' ')
|
||||||
print
|
print()
|
||||||
|
|
||||||
if len(names) > 1:
|
# this is super buggy
|
||||||
|
if False and len(names) > 1:
|
||||||
w1 = weapon_damage_map[names_sorted[0]]
|
w1 = weapon_damage_map[names_sorted[0]]
|
||||||
w2 = weapon_damage_map[names_sorted[1]]
|
w2 = weapon_damage_map[names_sorted[1]]
|
||||||
m, ratio = w1.compare_break_even(w2)
|
m, ratio = w1.compare_break_even(w2)
|
||||||
print
|
print()
|
||||||
print "Comparison of '%s' and '%s'" % (
|
print("Comparison of '%s' and '%s'" % (
|
||||||
names_sorted[0], names_sorted[1])
|
names_sorted[0], names_sorted[1]))
|
||||||
print "Hitbox ratio:", m, "%0.2f" % ratio
|
print("Hitbox ratio:", m, "%0.2f" % ratio)
|
||||||
|
|
||||||
for line in w1.get_raw_element_ratios():
|
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)
|
line = list(line)
|
||||||
if m*line[3] > m*ratio:
|
if m*line[3] > m*ratio:
|
||||||
line.append(names_sorted[0])
|
line.append(names_sorted[0])
|
||||||
else:
|
else:
|
||||||
line.append(names_sorted[1])
|
line.append(names_sorted[1])
|
||||||
# (part, raw, element, ratio)
|
# (part, raw, element, ratio)
|
||||||
print "%-22s %02d %02d %0.2f %s" % tuple(line)
|
print("%-22s %02d %02d %0.2f %s" % tuple(line))
|
||||||
|
|
||||||
|
|
||||||
def print_damage_percent_diff(names, damage_map_base, weapon_damage_map, parts):
|
def print_damage_percent_diff(names, damage_map_base, weapon_damage_map, parts):
|
||||||
@@ -336,7 +449,7 @@ def print_damage_percent_diff(names, damage_map_base, weapon_damage_map, parts):
|
|||||||
ediff_s = ",".join("%+0.1f%%" % i for i in ediffs)
|
ediff_s = ",".join("%+0.1f%%" % i for i in ediffs)
|
||||||
bdiff_s = ",".join("%+0.1f%%" % i for i in bdiffs)
|
bdiff_s = ",".join("%+0.1f%%" % i for i in bdiffs)
|
||||||
damage = damage_map_base[part]
|
damage = damage_map_base[part]
|
||||||
print "%22s%s h%02d %0.2f (%s) h%02d %0.2f (%s) %+0.2f (%s)" \
|
print("%22s%s h%02d %0.2f (%s) h%02d %0.2f (%s) %+0.2f (%s)" \
|
||||||
% (part, "*" if damage.is_breakable() else " ",
|
% (part, "*" if damage.is_breakable() else " ",
|
||||||
damage.hitbox,
|
damage.hitbox,
|
||||||
damage.total,
|
damage.total,
|
||||||
@@ -345,17 +458,17 @@ def print_damage_percent_diff(names, damage_map_base, weapon_damage_map, parts):
|
|||||||
damage.element,
|
damage.element,
|
||||||
ediff_s,
|
ediff_s,
|
||||||
damage.break_diff(),
|
damage.break_diff(),
|
||||||
bdiff_s)
|
bdiff_s))
|
||||||
if weapon_type == "Charge Blade":
|
if weapon_type == "Charge Blade":
|
||||||
for level in (0, 1, 2, 3, 5):
|
for level in (0, 1, 2, 3, 5):
|
||||||
print " " * 20, level,
|
print(" " * 20, level, end=' ')
|
||||||
for wname in names:
|
for wname in names:
|
||||||
wd = weapon_damage_map[wname]
|
wd = weapon_damage_map[wname]
|
||||||
damage = wd.cb_phial_damage[part][level]
|
damage = wd.cb_phial_damage[part][level]
|
||||||
print "(%0.f, %0.f, %0.f);" % damage,
|
print("(%0.f, %0.f, %0.f);" % damage, end=' ')
|
||||||
print
|
print()
|
||||||
|
|
||||||
print " --------------------"
|
print(" --------------------")
|
||||||
|
|
||||||
for avg_type in "uniform raw weakpart_raw element weakpart_element break_raw break_element break_only".split():
|
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]
|
base = damage_map_base.averages[avg_type]
|
||||||
@@ -367,7 +480,7 @@ def print_damage_percent_diff(names, damage_map_base, weapon_damage_map, parts):
|
|||||||
|
|
||||||
diff_s = ",".join("%+0.1f%%" % i for i in diffs)
|
diff_s = ",".join("%+0.1f%%" % i for i in diffs)
|
||||||
|
|
||||||
print "%22s %0.2f (%s)" % (avg_type, base, diff_s)
|
print("%22s %0.2f (%s)" % (avg_type, base, diff_s))
|
||||||
|
|
||||||
|
|
||||||
def match_quest_level(match_level, weapon_level):
|
def match_quest_level(match_level, weapon_level):
|
||||||
@@ -383,32 +496,19 @@ def match_quest_level(match_level, weapon_level):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def run_comparison(args, db, motiondb, game_uses_true_raw, item_stars=None):
|
||||||
args = parse_args(None)
|
|
||||||
|
|
||||||
game_uses_true_raw = False
|
|
||||||
if args.monster_hunter_cross:
|
|
||||||
db = MHDBX()
|
|
||||||
game_uses_true_raw = True
|
|
||||||
elif args.monster_hunter_gen:
|
|
||||||
if args.quest_level:
|
|
||||||
comps = True
|
|
||||||
else:
|
|
||||||
comps = False
|
|
||||||
db = MHDB(game="gu", include_item_components=comps)
|
|
||||||
game_uses_true_raw = True
|
|
||||||
elif args.monster_hunter_world:
|
|
||||||
db = MHDBX(game="mhw")
|
|
||||||
game_uses_true_raw = False
|
|
||||||
else:
|
|
||||||
db = MHDB(game="4u")
|
|
||||||
motiondb = MotionValueDB(_pathfix.motion_values_path)
|
|
||||||
|
|
||||||
monster = db.get_monster_by_name(args.monster)
|
monster = db.get_monster_by_name(args.monster)
|
||||||
if not monster:
|
if not monster:
|
||||||
raise ValueError("Monster '%s' not found" % args.monster)
|
raise ValueError("Monster '%s' not found" % args.monster)
|
||||||
monster_damage = db.get_monster_damage(monster.id)
|
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 = []
|
weapons = []
|
||||||
weapon_type = None
|
weapon_type = None
|
||||||
names_set = set()
|
names_set = set()
|
||||||
@@ -425,10 +525,14 @@ def main():
|
|||||||
if skill_args:
|
if skill_args:
|
||||||
skill_args_map[name] = skill_args
|
skill_args_map[name] = skill_args
|
||||||
|
|
||||||
|
#print("args match", args.match)
|
||||||
for match_tuple in args.match:
|
for match_tuple in args.match:
|
||||||
# TODO: better validation
|
# TODO: better validation
|
||||||
|
if isinstance(match_tuple, list):
|
||||||
|
# TODO: is this a bug in argparse!!!????
|
||||||
|
match_tuple = match_tuple[0]
|
||||||
wtype, element = match_tuple
|
wtype, element = match_tuple
|
||||||
if args.quest_level:
|
if args.quest_level or args.rarity:
|
||||||
final=None
|
final=None
|
||||||
else:
|
else:
|
||||||
final=1
|
final=1
|
||||||
@@ -443,28 +547,51 @@ def main():
|
|||||||
names_set.add(w.name)
|
names_set.add(w.name)
|
||||||
|
|
||||||
if args.weapon_custom:
|
if args.weapon_custom:
|
||||||
weapons.extend(args.weapon_custom)
|
weapons.extend([w[0] for w in args.weapon_custom])
|
||||||
|
|
||||||
if not weapons:
|
if not weapons:
|
||||||
print "Err: no matching weapons"
|
print("Err: no matching weapons")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
names = [w.name for w in weapons]
|
names = [w.name for w in weapons]
|
||||||
|
|
||||||
monster_breaks = db.get_monster_breaks(monster.id)
|
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"]
|
weapon_type = weapons[0]["wtype"]
|
||||||
if args.phial and weapon_type != "Charge Blade":
|
if args.phial and weapon_type != "Charge Blade":
|
||||||
print "ERROR: phial option is only supported for Charge Blade"
|
print("ERROR: phial option is only supported for Charge Blade")
|
||||||
sys.exit(1)
|
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)
|
||||||
if args.motion:
|
if args.motion:
|
||||||
motion = args.motion
|
motion = args.motion
|
||||||
print "Specified Motion: %0.1f" % motion
|
print("Specified Motion: %0.1f" % motion)
|
||||||
print "Monster Breaks: %s" % ", ".join(monster_breaks)
|
print("Monster Breaks: %s" % ", ".join(monster_breaks))
|
||||||
skill_names = get_skill_names(args)
|
skill_names = get_skill_names(args)
|
||||||
print "Common Skills:", ", ".join(skill for skill in skill_names if skill)
|
print("Common Skills:", ", ".join(skill for skill in skill_names if skill))
|
||||||
|
|
||||||
if args.parts:
|
if args.parts:
|
||||||
limit_parts = args.parts.split(",")
|
limit_parts = args.parts.split(",")
|
||||||
@@ -473,24 +600,73 @@ def main():
|
|||||||
|
|
||||||
if args.quest_level:
|
if args.quest_level:
|
||||||
village, guild, permit, arena = args.quest_level
|
village, guild, permit, arena = args.quest_level
|
||||||
print "Filter by Quest Levels:", args.quest_level
|
print("Filter by Quest Levels:", args.quest_level)
|
||||||
weapons2 = dict()
|
weapons2 = dict()
|
||||||
for w in weapons:
|
for w in weapons:
|
||||||
if (not match_quest_level(village, w["village_stars"])
|
if "village_stars" in w:
|
||||||
and not match_quest_level(guild, w["guild_stars"])):
|
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
|
continue
|
||||||
if not match_quest_level(permit, w["permit_stars"]):
|
if not match_quest_level(permit, stars["Permit"]):
|
||||||
continue
|
continue
|
||||||
if not match_quest_level(arena, w["arena_stars"]):
|
if not match_quest_level(arena, stars["Arena"]):
|
||||||
continue
|
continue
|
||||||
weapons2[w.id] = w
|
weapons2[w.id] = w
|
||||||
parent_ids = set(w.parent_id for w in weapons2.values())
|
parent_ids = set(w.parent_id for w in weapons2.values())
|
||||||
for wid in weapons2.keys():
|
for wid in list(weapons2.keys()):
|
||||||
if wid in parent_ids:
|
if wid in parent_ids:
|
||||||
del weapons2[wid]
|
del weapons2[wid]
|
||||||
weapons = weapons2.values()
|
weapons = list(weapons2.values())
|
||||||
names = [w.name for w in weapons]
|
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()
|
weapon_damage_map = dict()
|
||||||
for row in weapons:
|
for row in weapons:
|
||||||
name = row["name"]
|
name = row["name"]
|
||||||
@@ -499,6 +675,7 @@ def main():
|
|||||||
raise ValueError(
|
raise ValueError(
|
||||||
"Weapon '%s' is different type, got '%s' expected '%s'"
|
"Weapon '%s' is different type, got '%s' expected '%s'"
|
||||||
% (name, row_type, weapon_type))
|
% (name, row_type, weapon_type))
|
||||||
|
#print(name, row)
|
||||||
try:
|
try:
|
||||||
skill_args = skill_args_map.get(name, args)
|
skill_args = skill_args_map.get(name, args)
|
||||||
wd = WeaponMonsterDamage(row,
|
wd = WeaponMonsterDamage(row,
|
||||||
@@ -513,24 +690,28 @@ def main():
|
|||||||
limit_parts=args.parts,
|
limit_parts=args.parts,
|
||||||
frenzy_bonus=skill_args.frenzy,
|
frenzy_bonus=skill_args.frenzy,
|
||||||
is_true_attack=game_uses_true_raw,
|
is_true_attack=game_uses_true_raw,
|
||||||
blunt_power=skill_args.blunt_power)
|
blunt_power=skill_args.blunt_power,
|
||||||
print "%-20s: %4.0f %2.0f%%" % (name, wd.attack, wd.affinity),
|
game=db.game)
|
||||||
|
print("%-20s: %4.0f %2.0f%%" % (name, wd.attack, wd.affinity), end=' ')
|
||||||
if wd.etype:
|
if wd.etype:
|
||||||
if wd.etype2:
|
if wd.etype2:
|
||||||
print "(%4.0f %s, %4.0f %s)" \
|
print("(%4.0f %s, %4.0f %s)" \
|
||||||
% (wd.eattack, wd.etype, wd.eattack2, wd.etype2),
|
% (wd.eattack, wd.etype, wd.eattack2, wd.etype2), end=' ')
|
||||||
else:
|
else:
|
||||||
print "(%4.0f %s)" % (wd.eattack, wd.etype),
|
print("(%4.0f %s)" % (wd.eattack, wd.etype), end=' ')
|
||||||
print SharpnessLevel.name(wd.sharpness),
|
print(SharpnessLevel.name(wd.sharpness), wd.sharpness_points, end=' ')
|
||||||
if skill_args != args:
|
if skill_args != args:
|
||||||
print "{%s}" % ",".join(sn
|
print("{%s}" % ",".join(sn
|
||||||
for sn in get_skill_names(skill_args)
|
for sn in get_skill_names(skill_args)
|
||||||
if sn)
|
if sn))
|
||||||
else:
|
else:
|
||||||
print
|
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
|
weapon_damage_map[name] = wd
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
print str(e)
|
print(str(e))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
damage_map_base = weapon_damage_map[names[0]]
|
damage_map_base = weapon_damage_map[names[0]]
|
||||||
@@ -551,6 +732,162 @@ def main():
|
|||||||
print_sorted_damage(names, damage_map_base,
|
print_sorted_damage(names, damage_map_base,
|
||||||
weapon_damage_map, parts)
|
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__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
Script to find the most lucrative monster parts to farm for money.
|
Script to find the most lucrative monster parts to farm for money.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import codecs
|
import codecs
|
||||||
import urllib
|
import urllib.request, urllib.parse, urllib.error
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
@@ -55,8 +55,8 @@ def print_top_items(db, rank="G"):
|
|||||||
value = item_value(item)
|
value = item_value(item)
|
||||||
if value < min_value:
|
if value < min_value:
|
||||||
break
|
break
|
||||||
print " %-20s % 7.f % 6d (% 5.f)" % \
|
print(" %-20s % 7.f % 6d (% 5.f)" % \
|
||||||
(item.name, value, int(item.sell), ev[item.id])
|
(item.name, value, int(item.sell), ev[item.id]))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Calculate probability of getting at least one of a monster part from one
|
Calculate probability of getting at least one of a monster part from one
|
||||||
@@ -71,22 +71,22 @@ if __name__ == '__main__':
|
|||||||
max_rewards = 8 - fixed_rewards
|
max_rewards = 8 - fixed_rewards
|
||||||
|
|
||||||
if min_rewards < 0:
|
if min_rewards < 0:
|
||||||
print "Error: fixed_rewards (%d) must be less than or equal to " \
|
print("Error: fixed_rewards (%d) must be less than or equal to " \
|
||||||
"guaranteeed_rewards (%d)" % (fixed_rewards, guarenteed_rewards)
|
"guaranteeed_rewards (%d)" % (fixed_rewards, guarenteed_rewards))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
total_p = 0.0
|
total_p = 0.0
|
||||||
expected_attempts = 0.0
|
expected_attempts = 0.0
|
||||||
for reward_count in xrange(min_rewards, max_rewards + 1):
|
for reward_count in range(min_rewards, max_rewards + 1):
|
||||||
p = stats._reward_count_p(reward_count, min_rewards, max_rewards,
|
p = stats._reward_count_p(reward_count, min_rewards, max_rewards,
|
||||||
extend_percent)
|
extend_percent)
|
||||||
expected_attempts += p * reward_count
|
expected_attempts += p * reward_count
|
||||||
# probability of getting @reward_count rewards that could be the
|
# probability of getting @reward_count rewards that could be the
|
||||||
# desired item
|
# desired item
|
||||||
print "P(C = %d) = %0.4f" % (reward_count, p)
|
print("P(C = %d) = %0.4f" % (reward_count, p))
|
||||||
total_p += p
|
total_p += p
|
||||||
# expected value for number of rewards that could be the desired item
|
# expected value for number of rewards that could be the desired item
|
||||||
print "E(C) = %0.2f" % expected_attempts
|
print("E(C) = %0.2f" % expected_attempts)
|
||||||
|
|
||||||
# math check, make sure all possibilities add up to 1, allowing for
|
# math check, make sure all possibilities add up to 1, allowing for
|
||||||
# some floating point precision loss.
|
# some floating point precision loss.
|
||||||
@@ -96,5 +96,5 @@ if __name__ == '__main__':
|
|||||||
max_rewards, extend_percent)
|
max_rewards, extend_percent)
|
||||||
expected = expected_attempts * reward_percent / 100.0
|
expected = expected_attempts * reward_percent / 100.0
|
||||||
|
|
||||||
print "P(N > 0) = %0.2f%%" % p_at_least_one
|
print("P(N > 0) = %0.2f%%" % p_at_least_one)
|
||||||
print "E(N) = %0.4f" % expected
|
print("E(N) = %0.4f" % expected)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import _pathfix
|
import _pathfix
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ if __name__ == '__main__':
|
|||||||
import os.path
|
import os.path
|
||||||
|
|
||||||
if len(sys.argv) != 2:
|
if len(sys.argv) != 2:
|
||||||
print("Usage: %s 'item name'" % sys.argv[0])
|
print(("Usage: %s 'item name'" % sys.argv[0]))
|
||||||
sys.exit(os.EX_USAGE)
|
sys.exit(os.EX_USAGE)
|
||||||
|
|
||||||
item_name = canonical_item_name(sys.argv[1])
|
item_name = canonical_item_name(sys.argv[1])
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
@@ -40,8 +40,8 @@ if __name__ == '__main__':
|
|||||||
else:
|
else:
|
||||||
for cost in costs:
|
for cost in costs:
|
||||||
components = cost["components"]
|
components = cost["components"]
|
||||||
print "=", ", ".join([w.name for w in cost["path"]])
|
print("=", ", ".join([w.name for w in cost["path"]]))
|
||||||
print " Zenny", cost["zenny"]
|
print(" Zenny", cost["zenny"])
|
||||||
for item_name in sorted(components.iterkeys()):
|
for item_name in sorted(components.keys()):
|
||||||
print "%20s %2d" % (item_name, components[item_name])
|
print("%20s %2d" % (item_name, components[item_name]))
|
||||||
print
|
print()
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
import errno
|
import errno
|
||||||
import urllib
|
import urllib.request, urllib.parse, urllib.error
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
import _pathfix
|
import _pathfix
|
||||||
|
|
||||||
from mhapi.db import MHDB
|
from mhapi.db import MHDB, MHDBX
|
||||||
from mhapi import model
|
from mhapi import model
|
||||||
|
|
||||||
ENTITIES = """item weapon monster armor
|
ENTITIES = """item weapon monster armor
|
||||||
@@ -42,7 +42,7 @@ SAFE_CHARS = " &'+\""
|
|||||||
|
|
||||||
def file_path(path, model_object, alt_name_field=None):
|
def file_path(path, model_object, alt_name_field=None):
|
||||||
if alt_name_field:
|
if alt_name_field:
|
||||||
key = urllib.quote(model_object[alt_name_field].encode("utf8"),
|
key = urllib.parse.quote(model_object[alt_name_field].encode("utf8"),
|
||||||
SAFE_CHARS)
|
SAFE_CHARS)
|
||||||
else:
|
else:
|
||||||
key = str(model_object.id)
|
key = str(model_object.id)
|
||||||
@@ -57,7 +57,7 @@ def write_list_file(path, model_list):
|
|||||||
|
|
||||||
|
|
||||||
def write_index_file(path, indexes):
|
def write_index_file(path, indexes):
|
||||||
for key, data in indexes.iteritems():
|
for key, data in indexes.items():
|
||||||
index_path = os.path.join(path, "_index_%s.json" % key)
|
index_path = os.path.join(path, "_index_%s.json" % key)
|
||||||
with open(index_path, "w") as f:
|
with open(index_path, "w") as f:
|
||||||
json.dump(data, f, cls=model.ModelJSONEncoder, indent=2)
|
json.dump(data, f, cls=model.ModelJSONEncoder, indent=2)
|
||||||
@@ -106,7 +106,7 @@ def armor_json(db, path):
|
|||||||
a.update_indexes(indexes)
|
a.update_indexes(indexes)
|
||||||
skills = db.get_item_skills(a.id)
|
skills = db.get_item_skills(a.id)
|
||||||
if not skills:
|
if not skills:
|
||||||
print "WARN: armor '%s' (%d) has no skills" % (a.name, a.id)
|
print("WARN: armor '%s' (%d) has no skills" % (a.name, a.id))
|
||||||
a.set_skills(skills)
|
a.set_skills(skills)
|
||||||
|
|
||||||
all_data.append(a.as_data())
|
all_data.append(a.as_data())
|
||||||
@@ -130,7 +130,7 @@ def decoration_json(db, path):
|
|||||||
a.update_indexes(indexes)
|
a.update_indexes(indexes)
|
||||||
skills = db.get_item_skills(a.id)
|
skills = db.get_item_skills(a.id)
|
||||||
if not skills:
|
if not skills:
|
||||||
print "WARN: decoration '%s' (%d) has no skills" % (a.name, a.id)
|
print("WARN: decoration '%s' (%d) has no skills" % (a.name, a.id))
|
||||||
a.set_skills(skills)
|
a.set_skills(skills)
|
||||||
|
|
||||||
all_data.append(a.as_data())
|
all_data.append(a.as_data())
|
||||||
@@ -202,11 +202,12 @@ def weapon_json(db, path):
|
|||||||
]
|
]
|
||||||
data["horn_melodies"] = melodies[w.horn_notes]
|
data["horn_melodies"] = melodies[w.horn_notes]
|
||||||
|
|
||||||
stars = item_stars.get_weapon_stars(w)
|
if db.game == "4u":
|
||||||
data["village_stars"] = stars["Village"]
|
stars = item_stars.get_weapon_stars(w)
|
||||||
data["guild_stars"] = stars["Guild"]
|
data["village_stars"] = stars["Village"]
|
||||||
data["permit_stars"] = stars["Permit"]
|
data["guild_stars"] = stars["Guild"]
|
||||||
data["arena_stars"] = stars["Arena"]
|
data["permit_stars"] = stars["Permit"]
|
||||||
|
data["arena_stars"] = stars["Arena"]
|
||||||
|
|
||||||
all_data.append(data)
|
all_data.append(data)
|
||||||
|
|
||||||
@@ -254,7 +255,7 @@ def wyporium_json(db, path):
|
|||||||
if not k.startswith("wyporium"):
|
if not k.startswith("wyporium"):
|
||||||
continue
|
continue
|
||||||
trade_map[item.id][k] = all_data[k]
|
trade_map[item.id][k] = all_data[k]
|
||||||
print trade_map
|
print(trade_map)
|
||||||
mkdirs_p(path)
|
mkdirs_p(path)
|
||||||
write_map_file(path, trade_map)
|
write_map_file(path, trade_map)
|
||||||
|
|
||||||
@@ -274,21 +275,27 @@ def horn_melody_json(db, path):
|
|||||||
def main():
|
def main():
|
||||||
args = parse_args()
|
args = parse_args()
|
||||||
|
|
||||||
db = MHDB(game=args.game, include_item_components=True)
|
if args.game in ("mhx", "mhr"):
|
||||||
|
db = MHDBX(game=args.game)
|
||||||
|
else:
|
||||||
|
db = MHDB(game=args.game, include_item_components=True)
|
||||||
|
|
||||||
if not args.outpath:
|
if not args.outpath:
|
||||||
args.outpath = os.path.join(_pathfix.web_path, "jsonapi")
|
args.outpath = os.path.join(_pathfix.web_path, "jsonapi", args.game)
|
||||||
|
|
||||||
if args.entities:
|
if args.entities:
|
||||||
for entity in args.entities:
|
for entity in args.entities:
|
||||||
if entity not in ENTITIES:
|
if entity not in ENTITIES:
|
||||||
print "Unknown entity: %s" % entity
|
print("Unknown entity: %s" % entity)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
else:
|
else:
|
||||||
args.entities = ENTITIES
|
args.entities = ENTITIES
|
||||||
|
|
||||||
if db.game != "4u":
|
if db.game != "4u":
|
||||||
args.entities.remove("wyporium")
|
try:
|
||||||
|
args.entities.remove("wyporium")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
for entity in args.entities:
|
for entity in args.entities:
|
||||||
fn = globals()["%s_json" % entity]
|
fn = globals()["%s_json" % entity]
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ from mhapi.util import get_utf8_writer
|
|||||||
|
|
||||||
|
|
||||||
def print_header_nav(title, pid):
|
def print_header_nav(title, pid):
|
||||||
print """
|
print("""
|
||||||
<div data-role="header" data-position="fixed">
|
<div data-role="header" data-position="fixed">
|
||||||
<a href="#page-menu" class="ui-btn-left ui-btn ui-btn-inline ui-mini ui-corner-all ui-btn-icon-left ui-icon-bars">Menu</a>
|
<a href="#page-menu" class="ui-btn-left ui-btn ui-btn-inline ui-mini ui-corner-all ui-btn-icon-left ui-icon-bars">Menu</a>
|
||||||
<h1>%s</h1>
|
<h1>%s</h1>
|
||||||
""".strip() % title
|
""".strip() % title)
|
||||||
|
|
||||||
alt_pid = None
|
alt_pid = None
|
||||||
if pid.endswith("-en"):
|
if pid.endswith("-en"):
|
||||||
@@ -27,11 +27,11 @@ def print_header_nav(title, pid):
|
|||||||
alt_title = "en"
|
alt_title = "en"
|
||||||
|
|
||||||
if alt_pid is not None:
|
if alt_pid is not None:
|
||||||
print """
|
print("""
|
||||||
<a href="#%s" class="ui-btn-right ui-btn ui-btn-inline ui-mini">%s</a>
|
<a href="#%s" class="ui-btn-right ui-btn ui-btn-inline ui-mini">%s</a>
|
||||||
""".strip() % (alt_pid, alt_title)
|
""".strip() % (alt_pid, alt_title))
|
||||||
|
|
||||||
print " </div>"
|
print(" </div>")
|
||||||
|
|
||||||
|
|
||||||
def mk_html_list(dict_list, keys, sort_keys, divider_fn="auto"):
|
def mk_html_list(dict_list, keys, sort_keys, divider_fn="auto"):
|
||||||
@@ -39,7 +39,7 @@ def mk_html_list(dict_list, keys, sort_keys, divider_fn="auto"):
|
|||||||
print ('<ul data-role="listview" data-filter="true"'
|
print ('<ul data-role="listview" data-filter="true"'
|
||||||
' data-autodividers="true">')
|
' data-autodividers="true">')
|
||||||
else:
|
else:
|
||||||
print '<ul data-role="listview" data-filter="true">'
|
print('<ul data-role="listview" data-filter="true">')
|
||||||
|
|
||||||
if isinstance(sort_keys, types.FunctionType):
|
if isinstance(sort_keys, types.FunctionType):
|
||||||
sort_fn = sort_keys
|
sort_fn = sort_keys
|
||||||
@@ -55,26 +55,26 @@ def mk_html_list(dict_list, keys, sort_keys, divider_fn="auto"):
|
|||||||
if divider_fn not in (None, "auto"):
|
if divider_fn not in (None, "auto"):
|
||||||
divider_text = divider_fn(d, prev_d)
|
divider_text = divider_fn(d, prev_d)
|
||||||
if divider_text is not None:
|
if divider_text is not None:
|
||||||
print ' <li data-role="list-divider">%s</li>' % divider_text
|
print(' <li data-role="list-divider">%s</li>' % divider_text)
|
||||||
print " <li>"
|
print(" <li>")
|
||||||
for i, k in enumerate(keys):
|
for i, k in enumerate(keys):
|
||||||
value = d[k]
|
value = d[k]
|
||||||
if k in ("section", "description"):
|
if k in ("section", "description"):
|
||||||
if value:
|
if value:
|
||||||
print ' <p class="ui-li-desc">%s</p>' % value
|
print(' <p class="ui-li-desc">%s</p>' % value)
|
||||||
continue
|
continue
|
||||||
elif k == "title_jp" and i != 0:
|
elif k == "title_jp" and i != 0:
|
||||||
# NB: for monster by title we want it to be a normal column
|
# NB: for monster by title we want it to be a normal column
|
||||||
if value:
|
if value:
|
||||||
print ' <p class="ui-li-desc">Title: %s</p>' % value
|
print(' <p class="ui-li-desc">Title: %s</p>' % value)
|
||||||
continue
|
continue
|
||||||
if value.endswith(".png"):
|
if value.endswith(".png"):
|
||||||
value = ('<img class="icon" src="../img/icons_items/%s" />'
|
value = ('<img class="icon" src="../img/icons_items/%s" />'
|
||||||
% value)
|
% value)
|
||||||
print ' <span class="%s">%s</span>' % (k, value)
|
print(' <span class="%s">%s</span>' % (k, value))
|
||||||
print " </li>"
|
print(" </li>")
|
||||||
prev_d = d
|
prev_d = d
|
||||||
print '</ul>'
|
print('</ul>')
|
||||||
|
|
||||||
|
|
||||||
def _main():
|
def _main():
|
||||||
@@ -87,7 +87,7 @@ def _main():
|
|||||||
carve_items = db.get_items(item_types=("Flesh",))
|
carve_items = db.get_items(item_types=("Flesh",))
|
||||||
|
|
||||||
|
|
||||||
print """<!DOCTYPE html>
|
print("""<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Poogie Translate</title>
|
<title>Poogie Translate</title>
|
||||||
@@ -133,26 +133,26 @@ def _main():
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
"""
|
""")
|
||||||
stree_path = os.path.join(_pathfix.project_path, "db",
|
stree_path = os.path.join(_pathfix.project_path, "db",
|
||||||
"mhx_skill_tree_list.json")
|
"mhx_skill_tree_list.json")
|
||||||
with open(stree_path) as f:
|
with open(stree_path) as f:
|
||||||
stree_list = json.load(f)
|
stree_list = json.load(f)
|
||||||
|
|
||||||
print '<div data-role="page" id="page-skilltrees-en">'
|
print('<div data-role="page" id="page-skilltrees-en">')
|
||||||
print_header_nav("Skill Trees (en)", "page-skilltrees-en")
|
print_header_nav("Skill Trees (en)", "page-skilltrees-en")
|
||||||
print '<div data-role="main" class="ui-content">'
|
print('<div data-role="main" class="ui-content">')
|
||||||
mk_html_list(stree_list, ("name", "name_jp"), ("name",))
|
mk_html_list(stree_list, ("name", "name_jp"), ("name",))
|
||||||
print '</div>'
|
print('</div>')
|
||||||
print '</div>'
|
print('</div>')
|
||||||
|
|
||||||
print '<div data-role="page" id="page-skilltrees-jp">'
|
print('<div data-role="page" id="page-skilltrees-jp">')
|
||||||
print_header_nav("Skill Trees (jp)", "page-skilltrees-jp")
|
print_header_nav("Skill Trees (jp)", "page-skilltrees-jp")
|
||||||
print '<div data-role="main" class="ui-content">'
|
print('<div data-role="main" class="ui-content">')
|
||||||
mk_html_list(stree_list, ("name_jp", "name"), jplen_sort_fn,
|
mk_html_list(stree_list, ("name_jp", "name"), jplen_sort_fn,
|
||||||
divider_fn=jplen_divider_fn)
|
divider_fn=jplen_divider_fn)
|
||||||
print '</div>'
|
print('</div>')
|
||||||
print '</div>'
|
print('</div>')
|
||||||
|
|
||||||
def item_divider_fn(d, prev_d):
|
def item_divider_fn(d, prev_d):
|
||||||
prefix = _icon_prefix(d)
|
prefix = _icon_prefix(d)
|
||||||
@@ -160,29 +160,29 @@ def _main():
|
|||||||
if prefix != prev_prefix:
|
if prefix != prev_prefix:
|
||||||
return prefix
|
return prefix
|
||||||
return None
|
return None
|
||||||
print '<div data-role="page" id="page-item-usable">'
|
print('<div data-role="page" id="page-item-usable">')
|
||||||
print_header_nav("Items: Usable", "page-item-usable")
|
print_header_nav("Items: Usable", "page-item-usable")
|
||||||
print '<div data-role="main" class="ui-content">'
|
print('<div data-role="main" class="ui-content">')
|
||||||
mk_html_list(items, ("icon_name", "name", "name_jp"),
|
mk_html_list(items, ("icon_name", "name", "name_jp"),
|
||||||
("icon_name", "name"), divider_fn=item_divider_fn)
|
("icon_name", "name"), divider_fn=item_divider_fn)
|
||||||
print '</div>'
|
print('</div>')
|
||||||
print '</div>'
|
print('</div>')
|
||||||
|
|
||||||
print '<div data-role="page" id="page-item-gather">'
|
print('<div data-role="page" id="page-item-gather">')
|
||||||
print_header_nav("Items: Gatherable", "page-item-gather")
|
print_header_nav("Items: Gatherable", "page-item-gather")
|
||||||
print '<div data-role="main" class="ui-content">'
|
print('<div data-role="main" class="ui-content">')
|
||||||
mk_html_list(gather_items, ("icon_name", "name", "name_jp"),
|
mk_html_list(gather_items, ("icon_name", "name", "name_jp"),
|
||||||
("icon_name", "name"), divider_fn=item_divider_fn)
|
("icon_name", "name"), divider_fn=item_divider_fn)
|
||||||
print '</div>'
|
print('</div>')
|
||||||
print '</div>'
|
print('</div>')
|
||||||
|
|
||||||
print '<div data-role="page" id="page-item-carve">'
|
print('<div data-role="page" id="page-item-carve">')
|
||||||
print_header_nav("Items: Carve", "page-item-carve")
|
print_header_nav("Items: Carve", "page-item-carve")
|
||||||
print '<div data-role="main" class="ui-content">'
|
print('<div data-role="main" class="ui-content">')
|
||||||
mk_html_list(carve_items, ("icon_name", "name", "name_jp"),
|
mk_html_list(carve_items, ("icon_name", "name", "name_jp"),
|
||||||
("icon_name", "name"), divider_fn=item_divider_fn)
|
("icon_name", "name"), divider_fn=item_divider_fn)
|
||||||
print '</div>'
|
print('</div>')
|
||||||
print '</div>'
|
print('</div>')
|
||||||
|
|
||||||
ha_path = os.path.join(_pathfix.project_path, "db", "hunter_arts.json")
|
ha_path = os.path.join(_pathfix.project_path, "db", "hunter_arts.json")
|
||||||
with open(ha_path) as f:
|
with open(ha_path) as f:
|
||||||
@@ -194,21 +194,21 @@ def _main():
|
|||||||
elif d["section"] != prev_d["section"]:
|
elif d["section"] != prev_d["section"]:
|
||||||
return d["section"]
|
return d["section"]
|
||||||
return None
|
return None
|
||||||
print '<div data-role="page" id="page-hunterarts-en">'
|
print('<div data-role="page" id="page-hunterarts-en">')
|
||||||
print_header_nav("Hunter Arts (en)", "page-hunterarts-en")
|
print_header_nav("Hunter Arts (en)", "page-hunterarts-en")
|
||||||
print '<div data-role="main" class="ui-content">'
|
print('<div data-role="main" class="ui-content">')
|
||||||
mk_html_list(ha_list, ("name", "name_jp", "description"), None,
|
mk_html_list(ha_list, ("name", "name_jp", "description"), None,
|
||||||
divider_fn=ha_divider_fn)
|
divider_fn=ha_divider_fn)
|
||||||
print '</div>'
|
print('</div>')
|
||||||
print '</div>'
|
print('</div>')
|
||||||
|
|
||||||
print '<div data-role="page" id="page-hunterarts-jp">'
|
print('<div data-role="page" id="page-hunterarts-jp">')
|
||||||
print_header_nav("Hunter Arts (jp)", "page-hunterarts-jp")
|
print_header_nav("Hunter Arts (jp)", "page-hunterarts-jp")
|
||||||
print '<div data-role="main" class="ui-content">'
|
print('<div data-role="main" class="ui-content">')
|
||||||
mk_html_list(ha_list, ("name_jp", "name", "section", "description"),
|
mk_html_list(ha_list, ("name_jp", "name", "section", "description"),
|
||||||
jplen_sort_fn, divider_fn=jplen_divider_fn)
|
jplen_sort_fn, divider_fn=jplen_divider_fn)
|
||||||
print '</div>'
|
print('</div>')
|
||||||
print '</div>'
|
print('</div>')
|
||||||
|
|
||||||
|
|
||||||
monster_path = os.path.join(_pathfix.project_path, "db",
|
monster_path = os.path.join(_pathfix.project_path, "db",
|
||||||
@@ -216,35 +216,35 @@ def _main():
|
|||||||
with open(monster_path) as f:
|
with open(monster_path) as f:
|
||||||
monster_list = json.load(f)
|
monster_list = json.load(f)
|
||||||
|
|
||||||
print '<div data-role="page" id="page-monsters-en">'
|
print('<div data-role="page" id="page-monsters-en">')
|
||||||
print_header_nav("Monsters (en)", "page-monsters-en")
|
print_header_nav("Monsters (en)", "page-monsters-en")
|
||||||
print '<div data-role="main" class="ui-content">'
|
print('<div data-role="main" class="ui-content">')
|
||||||
mk_html_list(monster_list, ("name", "name_jp", "title_jp"), ("name",))
|
mk_html_list(monster_list, ("name", "name_jp", "title_jp"), ("name",))
|
||||||
print '</div>'
|
print('</div>')
|
||||||
print '</div>'
|
print('</div>')
|
||||||
|
|
||||||
print '<div data-role="page" id="page-monsters-jp">'
|
print('<div data-role="page" id="page-monsters-jp">')
|
||||||
print_header_nav("Monsters (jp)", "page-monsters-jp")
|
print_header_nav("Monsters (jp)", "page-monsters-jp")
|
||||||
print '<div data-role="main" class="ui-content">'
|
print('<div data-role="main" class="ui-content">')
|
||||||
mk_html_list(monster_list, ("name_jp", "name", "title_jp"), ("name_jp",))
|
mk_html_list(monster_list, ("name_jp", "name", "title_jp"), ("name_jp",))
|
||||||
print '</div>'
|
print('</div>')
|
||||||
print '</div>'
|
print('</div>')
|
||||||
|
|
||||||
titled_monster_list = [m for m in monster_list if m["title_jp"]]
|
titled_monster_list = [m for m in monster_list if m["title_jp"]]
|
||||||
print '<div data-role="page" id="page-monsters-title">'
|
print('<div data-role="page" id="page-monsters-title">')
|
||||||
print_header_nav("Monster Titles", "page-monsters-title")
|
print_header_nav("Monster Titles", "page-monsters-title")
|
||||||
print '<div data-role="main" class="ui-content">'
|
print('<div data-role="main" class="ui-content">')
|
||||||
mk_html_list(titled_monster_list, ("title_jp", "name"), ("title_jp",),
|
mk_html_list(titled_monster_list, ("title_jp", "name"), ("title_jp",),
|
||||||
divider_fn=None)
|
divider_fn=None)
|
||||||
print '</div>'
|
print('</div>')
|
||||||
print '</div>'
|
print('</div>')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
print """
|
print("""
|
||||||
</body>
|
</body>
|
||||||
"""
|
""")
|
||||||
|
|
||||||
def _icon_prefix(d):
|
def _icon_prefix(d):
|
||||||
if d is None:
|
if d is None:
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import json
|
import json
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf8 -*-
|
# -*- coding: utf8 -*-
|
||||||
"""
|
"""
|
||||||
Parse hunter arts name, name_jp, and description from wikia:
|
Parse hunter arts name, name_jp, and description from wikia:
|
||||||
@@ -10,7 +10,7 @@ Returns list of dict, e.g.:
|
|||||||
"section": "Heavy Bowgun",
|
"section": "Heavy Bowgun",
|
||||||
"description": "",
|
"description": "",
|
||||||
"name": "Acceleration Shower I",
|
"name": "Acceleration Shower I",
|
||||||
"name_jp": "\u30a2\u30af\u30bb\u30eb\u30b7\u30e3\u30ef\u30fc I"
|
"name_jp": "\\u30a2\\u30af\\u30bb\\u30eb\\u30b7\\u30e3\\u30ef\\u30fc I"
|
||||||
},
|
},
|
||||||
...
|
...
|
||||||
]
|
]
|
||||||
@@ -62,7 +62,7 @@ def parse_wikia_hunter_arts(f):
|
|||||||
def _main():
|
def _main():
|
||||||
with open(sys.argv[1]) as f:
|
with open(sys.argv[1]) as f:
|
||||||
data = parse_wikia_hunter_arts(f)
|
data = parse_wikia_hunter_arts(f)
|
||||||
print json.dumps(data, indent=2)
|
print(json.dumps(data, indent=2))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf8 -*-
|
# -*- coding: utf8 -*-
|
||||||
"""
|
"""
|
||||||
Parse monster names and jp names for monster hunter X.
|
Parse monster names and jp names for monster hunter X.
|
||||||
@@ -18,6 +18,7 @@ Returns list of dict, e.g.:
|
|||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import json
|
import json
|
||||||
|
import lxml.etree
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
@@ -34,14 +35,27 @@ MONSTER_RE = re.compile(
|
|||||||
'(?:</td>)?<td style="[^"]*background-color:#EBEBEB;[^"]*">\s*'
|
'(?:</td>)?<td style="[^"]*background-color:#EBEBEB;[^"]*">\s*'
|
||||||
'<a href="([^"]*)" [^>]* title="([^"]*)"')
|
'<a href="([^"]*)" [^>]* title="([^"]*)"')
|
||||||
|
|
||||||
|
# Old, MHX
|
||||||
|
"""
|
||||||
MONSTER_LINK_RE = re.compile(
|
MONSTER_LINK_RE = re.compile(
|
||||||
'<a href="(/wiki/[^/"]*)"\s+class="image image-thumbnail link-internal"\s+'
|
'<a href="(/wiki/[^/"]*)"\s+class="image image-thumbnail link-internal"\s+'
|
||||||
'title="([^"]*)"\s+>')
|
'title="([^"]*)"\s+>')
|
||||||
|
|
||||||
|
|
||||||
JAPANESE_NAME_STR = '<h3 class="pi-data-label pi-secondary-font">Japanese:</h3>'
|
JAPANESE_NAME_STR = '<h3 class="pi-data-label pi-secondary-font">Japanese:</h3>'
|
||||||
JAPANESE_NAME_RE = re.compile(
|
JAPANESE_NAME_RE = re.compile(
|
||||||
'<div class="pi-data-value pi-font">(.*)</div>')
|
'<div class="pi-data-value pi-font">(.*)</div>')
|
||||||
|
"""
|
||||||
|
|
||||||
|
MONSTER_LINK_RE = re.compile(
|
||||||
|
'<a href="(/wiki/[^/"]*)" title="([^"]*)">([^<>]+)</a>')
|
||||||
|
|
||||||
|
"""
|
||||||
|
<h2 class="pi-item pi-item-spacing pi-title" data-source="Japanese Name"><ruby lang="ja"><rb lang="ja-Hani">ドスフロギィ<br/>(Dosufurogi)</rb></ruby></h2>
|
||||||
|
"""
|
||||||
|
JAPANESE_NAME_RE = re.compile('<h2 class="pi-item pi-item-spacing pi-title" data-source="Japanese Name"><ruby lang="ja"><rb lang="[^"]*">([^<>]*)<br/>.*</rb></ruby></h2>')
|
||||||
|
JAPANESE_TITLE_RE = re.compile(
|
||||||
|
'<div class="pi-data-value pi-font">([^<>]*)</div>')
|
||||||
|
|
||||||
def parse_wikia_monsters(f):
|
def parse_wikia_monsters(f):
|
||||||
section = None
|
section = None
|
||||||
@@ -55,7 +69,7 @@ def parse_wikia_monsters(f):
|
|||||||
m = SECTION_RE.match(line)
|
m = SECTION_RE.match(line)
|
||||||
if m:
|
if m:
|
||||||
section = m.group(1)
|
section = m.group(1)
|
||||||
print >>sys.stderr, "section", section
|
print("section", section, file=sys.stderr)
|
||||||
continue
|
continue
|
||||||
if section not in ["Large Monsters", "Small Monsters"]:
|
if section not in ["Large Monsters", "Small Monsters"]:
|
||||||
continue
|
continue
|
||||||
@@ -72,20 +86,17 @@ def parse_wikia_monsters(f):
|
|||||||
def get_jp_names(monster_path):
|
def get_jp_names(monster_path):
|
||||||
url = "http://monsterhunter.wikia.com" + monster_path
|
url = "http://monsterhunter.wikia.com" + monster_path
|
||||||
r = requests.get(url)
|
r = requests.get(url)
|
||||||
lines = r.text.split("\n")
|
root = lxml.etree.HTML(r.text)
|
||||||
|
|
||||||
names = []
|
names = []
|
||||||
while lines:
|
|
||||||
line = lines.pop(0).strip()
|
rbs = root.xpath('//h2[@data-source="Japanese Name"]//rb')
|
||||||
if JAPANESE_NAME_STR not in line:
|
names.append(rbs[0].text)
|
||||||
continue
|
|
||||||
line = lines.pop(0).strip()
|
divs = root.xpath('//div[@data-source="Japanese Title"]//div')
|
||||||
while line == "":
|
if divs:
|
||||||
line = lines.pop(0).strip()
|
names.append(divs[0].text)
|
||||||
m = JAPANESE_NAME_RE.match(line)
|
|
||||||
assert m, "No match: " + line
|
|
||||||
names.append(parse_japanese_name(m.group(1)))
|
|
||||||
if len(names) == 2:
|
|
||||||
break
|
|
||||||
return names
|
return names
|
||||||
|
|
||||||
|
|
||||||
@@ -108,16 +119,16 @@ def _main():
|
|||||||
name = m["name"]
|
name = m["name"]
|
||||||
names = get_jp_names(m["href"])
|
names = get_jp_names(m["href"])
|
||||||
if len(names) == 0:
|
if len(names) == 0:
|
||||||
print >>sys.stderr, "ERROR: no names for %s" % name
|
print("ERROR: no names for %s" % name, file=sys.stderr)
|
||||||
names = ["", ""]
|
names = ["", ""]
|
||||||
if len(names) == 1:
|
if len(names) == 1:
|
||||||
print >>sys.stderr, "ERROR: no title for %s" % name
|
print("ERROR: no title for %s" % name, file=sys.stderr)
|
||||||
names.append("")
|
names.append("")
|
||||||
m["name_jp"] = names[0]
|
m["name_jp"] = names[0]
|
||||||
m["title_jp"] = names[1]
|
m["title_jp"] = names[1]
|
||||||
if m["title_jp"] in ("None", "N/A", "(?)"):
|
if m["title_jp"] in ("None", "N/A", "(?)"):
|
||||||
m["title_jp"] = ""
|
m["title_jp"] = ""
|
||||||
print json.dumps(monster_list, indent=2)
|
print(json.dumps(monster_list, indent=2))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf8 -*-
|
# -*- coding: utf8 -*-
|
||||||
"""
|
"""
|
||||||
Parse skill tree names and jp names for monster hunter X.
|
Parse skill tree names and jp names for monster hunter X.
|
||||||
@@ -81,7 +81,7 @@ def parse_wikia_skill_trees(f):
|
|||||||
|
|
||||||
def _main():
|
def _main():
|
||||||
if len(sys.argv) != 4:
|
if len(sys.argv) != 4:
|
||||||
print "Usage: %s infile out_strees.json out_skills.json" % sys.argv[0]
|
print("Usage: %s infile out_strees.json out_skills.json" % sys.argv[0])
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
with open(sys.argv[1]) as f:
|
with open(sys.argv[1]) as f:
|
||||||
strees, skills = parse_wikia_skill_trees(f)
|
strees, skills = parse_wikia_skill_trees(f)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import _pathfix
|
import _pathfix
|
||||||
|
|
||||||
@@ -15,4 +15,4 @@ if __name__ == '__main__':
|
|||||||
try:
|
try:
|
||||||
httpd.serve_forever()
|
httpd.serve_forever()
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
print "^C"
|
print("^C")
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import argparse
|
import argparse
|
||||||
@@ -21,7 +21,7 @@ def main():
|
|||||||
if args.item:
|
if args.item:
|
||||||
item = db.get_item_by_name(args.item)
|
item = db.get_item_by_name(args.item)
|
||||||
if item is None:
|
if item is None:
|
||||||
print "Item '%s' not found" % args.item
|
print("Item '%s' not found" % args.item)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
if item.type == "Materials":
|
if item.type == "Materials":
|
||||||
stars = item_stars.get_material_stars(item.id)
|
stars = item_stars.get_material_stars(item.id)
|
||||||
@@ -30,15 +30,15 @@ def main():
|
|||||||
elif args.weapon:
|
elif args.weapon:
|
||||||
weapon = db.get_weapon_by_name(args.weapon)
|
weapon = db.get_weapon_by_name(args.weapon)
|
||||||
if weapon is None:
|
if weapon is None:
|
||||||
print "Weapon '%s' not found" % args.weapon
|
print("Weapon '%s' not found" % args.weapon)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
stars = item_stars.get_weapon_stars(weapon)
|
stars = item_stars.get_weapon_stars(weapon)
|
||||||
else:
|
else:
|
||||||
print "Specify -w or -i"
|
print("Specify -w or -i")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
for k, v in stars.iteritems():
|
for k, v in stars.items():
|
||||||
print k, v
|
print(k, v)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ from mhapi.db import MHDB
|
|||||||
def apply_update(db, row):
|
def apply_update(db, row):
|
||||||
quest = db.get_quest(row["id"])
|
quest = db.get_quest(row["id"])
|
||||||
if quest.goal == row["goal"]:
|
if quest.goal == row["goal"]:
|
||||||
print "quest", row["id"], row["name"], "already updated, skipping"
|
print("quest", row["id"], row["name"], "already updated, skipping")
|
||||||
return
|
return
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
cur.execute("""UPDATE quests SET
|
cur.execute("""UPDATE quests SET
|
||||||
@@ -21,9 +21,9 @@ def apply_update(db, row):
|
|||||||
AND name=?""",
|
AND name=?""",
|
||||||
(row["goal"], row["id"], row["name"]))
|
(row["goal"], row["id"], row["name"]))
|
||||||
if cur.rowcount == 1:
|
if cur.rowcount == 1:
|
||||||
print "quest", row["id"], row["name"], "goal updated:", row["goal"]
|
print("quest", row["id"], row["name"], "goal updated:", row["goal"])
|
||||||
else:
|
else:
|
||||||
print "ERROR", "quest", row["id"], row["name"], "update failed"
|
print("ERROR", "quest", row["id"], row["name"], "update failed")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -123,8 +123,8 @@ def _parse_monster(name):
|
|||||||
|
|
||||||
name = rstrip(name, "'s")
|
name = rstrip(name, "'s")
|
||||||
name = rstrip(name, "'")
|
name = rstrip(name, "'")
|
||||||
name = rstrip(name, u"’")
|
name = rstrip(name, "’")
|
||||||
name = rstrip(name, u"’s")
|
name = rstrip(name, "’s")
|
||||||
|
|
||||||
#print "=>", name
|
#print "=>", name
|
||||||
|
|
||||||
@@ -202,7 +202,7 @@ def fuzzy_find(name):
|
|||||||
|
|
||||||
|
|
||||||
def check_hunts(db, quest):
|
def check_hunts(db, quest):
|
||||||
print ">", quest.id, quest.name,
|
print(">", quest.id, quest.name, end=' ')
|
||||||
|
|
||||||
monsters_match = False
|
monsters_match = False
|
||||||
|
|
||||||
@@ -240,30 +240,30 @@ def check_hunts(db, quest):
|
|||||||
|
|
||||||
if monsters_match and not errors:
|
if monsters_match and not errors:
|
||||||
# useful for doing grep -v on output
|
# useful for doing grep -v on output
|
||||||
print " *OK*"
|
print(" *OK*")
|
||||||
elif monsters_match:
|
elif monsters_match:
|
||||||
print " *MISSPELLING*"
|
print(" *MISSPELLING*")
|
||||||
print " goal:", quest.goal
|
print(" goal:", quest.goal)
|
||||||
print " sub:", quest.sub_goal
|
print(" sub:", quest.sub_goal)
|
||||||
for err in errors:
|
for err in errors:
|
||||||
print " ", err
|
print(" ", err)
|
||||||
else:
|
else:
|
||||||
print " *MISMATCH*",
|
print(" *MISMATCH*", end=' ')
|
||||||
if errors:
|
if errors:
|
||||||
print " *MISSPELLING*",
|
print(" *MISSPELLING*", end=' ')
|
||||||
print
|
print()
|
||||||
for err in errors:
|
for err in errors:
|
||||||
print " ", err
|
print(" ", err)
|
||||||
print " goal:", quest.goal
|
print(" goal:", quest.goal)
|
||||||
print " sub:", quest.sub_goal
|
print(" sub:", quest.sub_goal)
|
||||||
print " parsed:", goal_expected
|
print(" parsed:", goal_expected)
|
||||||
if sub_expected and not sub_expected < goal_expected:
|
if sub_expected and not sub_expected < goal_expected:
|
||||||
# print if sub monster looks like it's not one of the
|
# print if sub monster looks like it's not one of the
|
||||||
# main monsters. This will false positive when main quest
|
# main monsters. This will false positive when main quest
|
||||||
# is hunt all large monsters.
|
# is hunt all large monsters.
|
||||||
print " sub prsd:", sub_expected
|
print(" sub prsd:", sub_expected)
|
||||||
print " db:", db_expected
|
print(" db:", db_expected)
|
||||||
print " db unstb:", db_expected_unstable
|
print(" db unstb:", db_expected_unstable)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ stdout = get_utf8_writer(sys.stdout)
|
|||||||
|
|
||||||
|
|
||||||
def set_weapon_final(db, weapon, value):
|
def set_weapon_final(db, weapon, value):
|
||||||
print >>stdout, "weapon_final", weapon.id, weapon.name, value
|
print("weapon_final", weapon.id, weapon.name, value, file=stdout)
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
cur.execute("""UPDATE weapons SET
|
cur.execute("""UPDATE weapons SET
|
||||||
final=? WHERE _id=?""",
|
final=? WHERE _id=?""",
|
||||||
|
|||||||
BIN
db/mh4u.db
BIN
db/mh4u.db
Binary file not shown.
38
db/mh4u/weapon_shop.csv
Normal file
38
db/mh4u/weapon_shop.csv
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
Iron Sword,1500
|
||||||
|
Buster Sword,2550
|
||||||
|
Giant Jawblade,5250
|
||||||
|
Ravager Blade,5250
|
||||||
|
Iron Katana,1500
|
||||||
|
Canine Katana,3300
|
||||||
|
Eager Cleaver,10950
|
||||||
|
Hunter's Knife,1500
|
||||||
|
Assassin's Dagger,3300
|
||||||
|
Chief Kris,4200
|
||||||
|
Matched Slicers,1500
|
||||||
|
Chief's Scythes,3300
|
||||||
|
Dual Hatchets,4200
|
||||||
|
War Hammer,1500
|
||||||
|
War Mace,2550
|
||||||
|
Bone Bludgeon+,4200
|
||||||
|
Iron Striker+,5250
|
||||||
|
Metal Bagpipe,1500
|
||||||
|
Hunter's Horn,4200
|
||||||
|
Heavy Bagpipe+,5250
|
||||||
|
Iron Lance,1500
|
||||||
|
Knight Lance,2550
|
||||||
|
Rampart,5250
|
||||||
|
Spiked Javelin,6450
|
||||||
|
Iron Gunlance,1500
|
||||||
|
Jaggid Gunlance,4200
|
||||||
|
Defender's Gunlance,6450
|
||||||
|
Bone Axe,1950
|
||||||
|
Wild Axe,4200
|
||||||
|
Power Gasher,5250
|
||||||
|
Elite Blad,1950
|
||||||
|
Bone Staff,3300
|
||||||
|
Cross Bowgun,2550
|
||||||
|
Cross Bowgun+,4200
|
||||||
|
Bone Shooter,2100
|
||||||
|
Bone Shooter+,5400
|
||||||
|
Hunter's Bow I,1500
|
||||||
|
Hunter's Stoutbow I,4200
|
||||||
|
4408
db/mhr/monster_hitboxes.json
Normal file
4408
db/mhr/monster_hitboxes.json
Normal file
File diff suppressed because it is too large
Load Diff
254
db/mhr/monster_list.json
Normal file
254
db/mhr/monster_list.json
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "Rathian",
|
||||||
|
"link": "/monster/001_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Apex Rathian",
|
||||||
|
"link": "/monster/001_07.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rathalos",
|
||||||
|
"link": "/monster/002_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Apex Rathalos",
|
||||||
|
"link": "/monster/002_07.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Khezu",
|
||||||
|
"link": "/monster/003_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Basarios",
|
||||||
|
"link": "/monster/004_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Diablos",
|
||||||
|
"link": "/monster/007_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Apex Diablos",
|
||||||
|
"link": "/monster/007_07.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Daimyo Hermitaur",
|
||||||
|
"link": "/monster/019_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Shogun Ceanataur",
|
||||||
|
"link": "/monster/020_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rajang",
|
||||||
|
"link": "/monster/023_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Furious Rajang",
|
||||||
|
"link": "/monster/023_05.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Kushala Daora",
|
||||||
|
"link": "/monster/024_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Chameleos",
|
||||||
|
"link": "/monster/025_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Teostra",
|
||||||
|
"link": "/monster/027_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tigrex",
|
||||||
|
"link": "/monster/032_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Nargacuga",
|
||||||
|
"link": "/monster/037_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Barioth",
|
||||||
|
"link": "/monster/042_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Barroth",
|
||||||
|
"link": "/monster/044_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Royal Ludroth",
|
||||||
|
"link": "/monster/047_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Great Baggi",
|
||||||
|
"link": "/monster/054_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Zinogre",
|
||||||
|
"link": "/monster/057_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Apex Zinogre",
|
||||||
|
"link": "/monster/057_07.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Great Wroggi",
|
||||||
|
"link": "/monster/059_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Arzuros",
|
||||||
|
"link": "/monster/060_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Apex Arzuros",
|
||||||
|
"link": "/monster/060_07.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lagombi",
|
||||||
|
"link": "/monster/061_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Volvidon",
|
||||||
|
"link": "/monster/062_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gore Magala",
|
||||||
|
"link": "/monster/071_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Shagaru Magala",
|
||||||
|
"link": "/monster/072_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Seregios",
|
||||||
|
"link": "/monster/077_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Astalos",
|
||||||
|
"link": "/monster/081_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mizutsune",
|
||||||
|
"link": "/monster/082_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Apex Mizutsune",
|
||||||
|
"link": "/monster/082_07.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Crimson Glow Valstrax",
|
||||||
|
"link": "/monster/086_05.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Magnamalo",
|
||||||
|
"link": "/monster/089_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Scorned Magnamalo",
|
||||||
|
"link": "/monster/089_05.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bishaten",
|
||||||
|
"link": "/monster/090_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Blood Orange Bishaten",
|
||||||
|
"link": "/monster/090_01.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Aknosom",
|
||||||
|
"link": "/monster/091_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tetranadon",
|
||||||
|
"link": "/monster/092_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Somnacanth",
|
||||||
|
"link": "/monster/093_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Aurora Somnacanth",
|
||||||
|
"link": "/monster/093_01.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Rakna-Kadaki",
|
||||||
|
"link": "/monster/094_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pyre Rakna-Kadaki",
|
||||||
|
"link": "/monster/094_01.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Almudron",
|
||||||
|
"link": "/monster/095_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Magma Almudron",
|
||||||
|
"link": "/monster/095_01.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Wind Serpent Ibushi",
|
||||||
|
"link": "/monster/096_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Goss Harag",
|
||||||
|
"link": "/monster/097_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Great Izuchi",
|
||||||
|
"link": "/monster/098_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Thunder Serpent Narwa",
|
||||||
|
"link": "/monster/099_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Narwa the Allmother",
|
||||||
|
"link": "/monster/099_05.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Anjanath",
|
||||||
|
"link": "/monster/100_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pukei-Pukei",
|
||||||
|
"link": "/monster/102_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Kulu-Ya-Ku",
|
||||||
|
"link": "/monster/107_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Jyuratodus",
|
||||||
|
"link": "/monster/108_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Tobi-Kadachi",
|
||||||
|
"link": "/monster/109_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Bazelgeuse",
|
||||||
|
"link": "/monster/118_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Malzeno",
|
||||||
|
"link": "/monster/132_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Lunagaron",
|
||||||
|
"link": "/monster/133_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Garangolm",
|
||||||
|
"link": "/monster/134_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Gaismagorm",
|
||||||
|
"link": "/monster/135_00.html"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Espinas",
|
||||||
|
"link": "/monster/136_00.html"
|
||||||
|
}
|
||||||
|
]
|
||||||
154311
db/mhr/weapon_list.json
Normal file
154311
db/mhr/weapon_list.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -19,7 +19,7 @@ def set_carve_counts(db, monster_carves):
|
|||||||
for m in monsters:
|
for m in monsters:
|
||||||
rewards = db.get_monster_rewards(m.id)
|
rewards = db.get_monster_rewards(m.id)
|
||||||
mc = monster_carves.get(m.name)
|
mc = monster_carves.get(m.name)
|
||||||
print "===", m.name
|
print("===", m.name)
|
||||||
for r in rewards:
|
for r in rewards:
|
||||||
condition = r["condition"]
|
condition = r["condition"]
|
||||||
if "Carve" not in condition:
|
if "Carve" not in condition:
|
||||||
@@ -34,13 +34,13 @@ def set_carve_counts(db, monster_carves):
|
|||||||
elif condition == "Tail Carve":
|
elif condition == "Tail Carve":
|
||||||
stack_size = 1
|
stack_size = 1
|
||||||
else:
|
else:
|
||||||
print "WARN: unknown condition %s.%s" \
|
print("WARN: unknown condition %s.%s" \
|
||||||
% (m.name, condition)
|
% (m.name, condition))
|
||||||
else:
|
else:
|
||||||
assert False, "Unknown monster class: %s" % m["class"]
|
assert False, "Unknown monster class: %s" % m["class"]
|
||||||
if r["stack_size"] == stack_size:
|
if r["stack_size"] == stack_size:
|
||||||
continue
|
continue
|
||||||
print " ", condition, r["stack_size"], "=>", stack_size
|
print(" ", condition, r["stack_size"], "=>", stack_size)
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
cur.execute("""UPDATE hunting_rewards
|
cur.execute("""UPDATE hunting_rewards
|
||||||
SET stack_size=? WHERE _id=?""",
|
SET stack_size=? WHERE _id=?""",
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ def _add_column(cursor, table, column_spec):
|
|||||||
|
|
||||||
|
|
||||||
def _set_stars(cursor, item_id, stars):
|
def _set_stars(cursor, item_id, stars):
|
||||||
for k in stars.keys():
|
for k in list(stars.keys()):
|
||||||
col = k.lower() + "_stars"
|
col = k.lower() + "_stars"
|
||||||
q = "UPDATE items SET %s=? WHERE _id=?" % col
|
q = "UPDATE items SET %s=? WHERE _id=?" % col
|
||||||
cursor.execute(q, (stars[k], item_id))
|
cursor.execute(q, (stars[k], item_id))
|
||||||
@@ -45,7 +45,7 @@ def main():
|
|||||||
items = db.get_items(exclude_types=["", "Armor", "Palico Weapon",
|
items = db.get_items(exclude_types=["", "Armor", "Palico Weapon",
|
||||||
"Decoration"])
|
"Decoration"])
|
||||||
for item in items:
|
for item in items:
|
||||||
print item.id, item.type, item.name
|
print(item.id, item.type, item.name)
|
||||||
if item.type == "Materials":
|
if item.type == "Materials":
|
||||||
stars = item_stars.get_material_stars(item.id)
|
stars = item_stars.get_material_stars(item.id)
|
||||||
elif item.type == "Weapon":
|
elif item.type == "Weapon":
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ def set_quest_ranks(db):
|
|||||||
for quest in quests:
|
for quest in quests:
|
||||||
if not quest["name"]:
|
if not quest["name"]:
|
||||||
assert quest["hub"] == "Event"
|
assert quest["hub"] == "Event"
|
||||||
print "WARN: skipping non localized event quest: %d" % quest.id
|
print("WARN: skipping non localized event quest: %d" % quest.id)
|
||||||
continue
|
continue
|
||||||
set_quest_rank(db, quest)
|
set_quest_rank(db, quest)
|
||||||
|
|
||||||
@@ -35,19 +35,19 @@ def set_quest_rank(db, quest):
|
|||||||
rewards = db.get_quest_rewards(quest_id)
|
rewards = db.get_quest_rewards(quest_id)
|
||||||
rank = guess_quest_rank_from_rewards(db, rewards)
|
rank = guess_quest_rank_from_rewards(db, rewards)
|
||||||
if rank is None:
|
if rank is None:
|
||||||
print "WARN: quest '%s' has no flesh rewards, assuming lower rank"\
|
print("WARN: quest '%s' has no flesh rewards, assuming lower rank"\
|
||||||
% (quest.name.encode("utf8"),)
|
% (quest.name.encode("utf8"),))
|
||||||
rank = rank_stars_guess[0]
|
rank = rank_stars_guess[0]
|
||||||
elif rank not in rank_stars_guess:
|
elif rank not in rank_stars_guess:
|
||||||
print "ERROR: quest '%s' reward guess '%s' not in stars guess '%s'"\
|
print("ERROR: quest '%s' reward guess '%s' not in stars guess '%s'"\
|
||||||
% (quest.name, rank, rank_stars_guess)
|
% (quest.name, rank, rank_stars_guess))
|
||||||
else:
|
else:
|
||||||
rank = rank_stars_guess
|
rank = rank_stars_guess
|
||||||
|
|
||||||
assert rank in "LR HR G".split()
|
assert rank in "LR HR G".split()
|
||||||
|
|
||||||
quest.rank = rank
|
quest.rank = rank
|
||||||
print quest.one_line_u()
|
print(quest.one_line_u())
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
cur.execute("UPDATE quests SET rank=? WHERE _id=?", (rank, quest_id))
|
cur.execute("UPDATE quests SET rank=? WHERE _id=?", (rank, quest_id))
|
||||||
|
|
||||||
|
|||||||
39
db/set_weapon_buy.py
Executable file
39
db/set_weapon_buy.py
Executable file
@@ -0,0 +1,39 @@
|
|||||||
|
#!/usr/bin/env python2
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
import codecs
|
||||||
|
import csv
|
||||||
|
|
||||||
|
import _pathfix
|
||||||
|
|
||||||
|
from mhapi.db import MHDB
|
||||||
|
|
||||||
|
|
||||||
|
def set_buy(db, item_id, buy):
|
||||||
|
print("buy", item_id, buy)
|
||||||
|
cur = db.cursor()
|
||||||
|
cur.execute("""UPDATE items SET
|
||||||
|
buy=? WHERE _id=?""",
|
||||||
|
(buy, item_id))
|
||||||
|
|
||||||
|
def set_buy_by_name(db, name, buy):
|
||||||
|
cur = db.cursor()
|
||||||
|
cur.execute("""UPDATE items SET
|
||||||
|
buy=? WHERE name=?""",
|
||||||
|
(buy, name))
|
||||||
|
rowid = cur.lastrowid
|
||||||
|
print("buy", rowid, name, buy)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
db = MHDB(game="4u")
|
||||||
|
delta_file_path = os.path.join(_pathfix.db_path, "mh4u", "weapon_shop.csv")
|
||||||
|
|
||||||
|
with open(delta_file_path) as f:
|
||||||
|
reader = csv.reader(f)
|
||||||
|
for row in reader:
|
||||||
|
name = row[0]
|
||||||
|
value = int(row[1])
|
||||||
|
set_buy_by_name(db, name, value)
|
||||||
|
|
||||||
|
db.commit()
|
||||||
|
db.close()
|
||||||
@@ -10,7 +10,7 @@ from mhapi.db import MHDB
|
|||||||
|
|
||||||
|
|
||||||
def set_upgrade_cost(db, item_id, upgrade_cost):
|
def set_upgrade_cost(db, item_id, upgrade_cost):
|
||||||
print "upgrade_cost", item_id, upgrade_cost
|
print("upgrade_cost", item_id, upgrade_cost)
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
cur.execute("""UPDATE weapons SET
|
cur.execute("""UPDATE weapons SET
|
||||||
upgrade_cost=? WHERE _id=?""",
|
upgrade_cost=? WHERE _id=?""",
|
||||||
@@ -18,7 +18,7 @@ def set_upgrade_cost(db, item_id, upgrade_cost):
|
|||||||
|
|
||||||
|
|
||||||
def set_creation_cost(db, item_id, creation_cost):
|
def set_creation_cost(db, item_id, creation_cost):
|
||||||
print "creation_cost", item_id, creation_cost
|
print("creation_cost", item_id, creation_cost)
|
||||||
cur = db.cursor()
|
cur = db.cursor()
|
||||||
cur.execute("""UPDATE weapons SET
|
cur.execute("""UPDATE weapons SET
|
||||||
creation_cost=? WHERE _id=?""",
|
creation_cost=? WHERE _id=?""",
|
||||||
|
|||||||
@@ -78,14 +78,14 @@ class WeaponTypeMotionValues(object):
|
|||||||
self.motion_values[name] = MotionValue(name, d["type"], d["power"])
|
self.motion_values[name] = MotionValue(name, d["type"], d["power"])
|
||||||
|
|
||||||
self.average = (sum(mv.average
|
self.average = (sum(mv.average
|
||||||
for mv in self.motion_values.itervalues())
|
for mv in self.motion_values.values())
|
||||||
/ len(self))
|
/ len(self))
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.motion_values)
|
return len(self.motion_values)
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self.motion_values.keys()
|
return list(self.motion_values.keys())
|
||||||
|
|
||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return self.motion_values[key]
|
return self.motion_values[key]
|
||||||
@@ -109,7 +109,7 @@ class MotionValueDB(object):
|
|||||||
return self.motion_values_map[weapon_type]
|
return self.motion_values_map[weapon_type]
|
||||||
|
|
||||||
def keys(self):
|
def keys(self):
|
||||||
return self.motion_values_map.keys()
|
return list(self.motion_values_map.keys())
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.motion_values_map)
|
return len(self.motion_values_map)
|
||||||
@@ -158,7 +158,7 @@ class WeaponType(object):
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def all(cls):
|
def all(cls):
|
||||||
return cls._multiplier.keys()
|
return list(cls._multiplier.keys())
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def damage_type(cls, weapon_type):
|
def damage_type(cls, weapon_type):
|
||||||
@@ -187,7 +187,8 @@ 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, blunt_power=False, is_true_attack=False):
|
frenzy_bonus=0, blunt_power=False, is_true_attack=False,
|
||||||
|
game="4u"):
|
||||||
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
|
||||||
@@ -222,15 +223,23 @@ class WeaponMonsterDamage(object):
|
|||||||
else:
|
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 == 1:
|
|
||||||
self.sharpness = self.weapon.sharpness_plus.max
|
if sharp_plus:
|
||||||
elif sharp_plus == 2:
|
if game == "mhr":
|
||||||
self.sharpness = self.weapon.sharpness_plus2.max
|
sharp_n = self.weapon.sharpness_plus.get_rise_handicraft(sharp_plus)
|
||||||
|
self.sharpness, self.sharpness_points = sharp_n.get_max_points()
|
||||||
|
else:
|
||||||
|
if sharp_plus == 1:
|
||||||
|
self.sharpness, self.sharpness_points = self.weapon.sharpness_plus.get_max_points()
|
||||||
|
elif sharp_plus == 2:
|
||||||
|
self.sharpness, self.sharpness_points = self.weapon.sharpness_plus2.get_max_points()
|
||||||
else:
|
else:
|
||||||
self.sharpness = self.weapon.sharpness.max
|
self.sharpness, self.sharpness_points = self.weapon.sharpness.get_max_points()
|
||||||
#print "sharpness=", self.sharpness
|
|
||||||
|
self.sharpness_name = SharpnessLevel.name(self.sharpness)
|
||||||
|
|
||||||
if self.weapon["affinity"]:
|
if self.weapon["affinity"]:
|
||||||
if (isinstance(self.weapon["affinity"], basestring)
|
if (isinstance(self.weapon["affinity"], str)
|
||||||
and "/" in self.weapon["affinity"]):
|
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
|
||||||
@@ -358,7 +367,7 @@ class WeaponMonsterDamage(object):
|
|||||||
part_damage.part = part
|
part_damage.part = part
|
||||||
if alt is None:
|
if alt is None:
|
||||||
if (self.breakable_parts
|
if (self.breakable_parts
|
||||||
and _break_find(part, self.monster_damage.parts.keys(),
|
and _break_find(part, list(self.monster_damage.parts.keys()),
|
||||||
self.breakable_parts)):
|
self.breakable_parts)):
|
||||||
part_damage.breakable = True
|
part_damage.breakable = True
|
||||||
if hitbox > self.max_raw_part[1]:
|
if hitbox > self.max_raw_part[1]:
|
||||||
@@ -366,15 +375,15 @@ class WeaponMonsterDamage(object):
|
|||||||
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 part in self.damage_map.keys():
|
for part in list(self.damage_map.keys()):
|
||||||
if None not in self.damage_map[part].states:
|
if None not in self.damage_map[part].states:
|
||||||
#print "Failed to parse part:", part
|
#print "Failed to parse part:", part
|
||||||
del self.damage_map[part]
|
del self.damage_map[part]
|
||||||
|
|
||||||
for part, d in self.damage_map.iteritems():
|
for part, d in self.damage_map.items():
|
||||||
if d.is_breakable():
|
if d.is_breakable():
|
||||||
self.break_count += 1
|
self.break_count += 1
|
||||||
self.parts = self.damage_map.keys()
|
self.parts = list(self.damage_map.keys())
|
||||||
self.averages["uniform"] = self.uniform()
|
self.averages["uniform"] = self.uniform()
|
||||||
self.averages["raw"] = self.weighted_raw()
|
self.averages["raw"] = self.weighted_raw()
|
||||||
self.averages["element"] = self.weighted_element()
|
self.averages["element"] = self.weighted_element()
|
||||||
@@ -403,10 +412,10 @@ class WeaponMonsterDamage(object):
|
|||||||
artillery_level=self.artillery_level)
|
artillery_level=self.artillery_level)
|
||||||
self.cb_phial_damage[part][level] = damage_tuple
|
self.cb_phial_damage[part][level] = damage_tuple
|
||||||
|
|
||||||
def uniform(self):
|
def uniform(self, break_weight=0.25):
|
||||||
average = 0.0
|
average = 0.0
|
||||||
for part, damage in self.damage_map.iteritems():
|
for part, damage in self.damage_map.items():
|
||||||
average += damage.average()
|
average += damage.average(break_weight)
|
||||||
return average / len(self.damage_map)
|
return average / len(self.damage_map)
|
||||||
|
|
||||||
def weighted_raw(self):
|
def weighted_raw(self):
|
||||||
@@ -417,7 +426,7 @@ class WeaponMonsterDamage(object):
|
|||||||
"""
|
"""
|
||||||
average = 0.0
|
average = 0.0
|
||||||
total_hitbox = 0.0
|
total_hitbox = 0.0
|
||||||
for part, damage in self.damage_map.iteritems():
|
for part, damage in self.damage_map.items():
|
||||||
average += damage.average() * damage.hitbox
|
average += damage.average() * damage.hitbox
|
||||||
total_hitbox += damage.hitbox
|
total_hitbox += damage.hitbox
|
||||||
if total_hitbox == 0:
|
if total_hitbox == 0:
|
||||||
@@ -430,7 +439,7 @@ class WeaponMonsterDamage(object):
|
|||||||
"""
|
"""
|
||||||
average = 0.0
|
average = 0.0
|
||||||
total_ehitbox = 0.0
|
total_ehitbox = 0.0
|
||||||
for part, damage in self.damage_map.iteritems():
|
for part, damage in self.damage_map.items():
|
||||||
average += damage.average() * damage.ehitbox
|
average += damage.average() * damage.ehitbox
|
||||||
total_ehitbox += damage.ehitbox
|
total_ehitbox += damage.ehitbox
|
||||||
if total_ehitbox == 0:
|
if total_ehitbox == 0:
|
||||||
@@ -444,7 +453,7 @@ class WeaponMonsterDamage(object):
|
|||||||
else:
|
else:
|
||||||
other_weight = (1 - weak_weight) / (len(self.parts) - 1)
|
other_weight = (1 - weak_weight) / (len(self.parts) - 1)
|
||||||
average = 0
|
average = 0
|
||||||
for part, damage in self.damage_map.iteritems():
|
for part, damage in self.damage_map.items():
|
||||||
if part == self.max_raw_part[0]:
|
if part == self.max_raw_part[0]:
|
||||||
weight = weak_weight
|
weight = weak_weight
|
||||||
else:
|
else:
|
||||||
@@ -459,7 +468,7 @@ class WeaponMonsterDamage(object):
|
|||||||
else:
|
else:
|
||||||
other_weight = (1 - weak_weight) / (len(self.parts) - 1)
|
other_weight = (1 - weak_weight) / (len(self.parts) - 1)
|
||||||
average = 0
|
average = 0
|
||||||
for part, damage in self.damage_map.iteritems():
|
for part, damage in self.damage_map.items():
|
||||||
if part == self.max_element_part[0]:
|
if part == self.max_element_part[0]:
|
||||||
weight = weak_weight
|
weight = weak_weight
|
||||||
else:
|
else:
|
||||||
@@ -475,7 +484,7 @@ class WeaponMonsterDamage(object):
|
|||||||
return 0
|
return 0
|
||||||
average = 0.0
|
average = 0.0
|
||||||
count = self.break_count + 1
|
count = self.break_count + 1
|
||||||
for part, damage in self.damage_map.iteritems():
|
for part, damage in self.damage_map.items():
|
||||||
if part == self.max_raw_part[0]:
|
if part == self.max_raw_part[0]:
|
||||||
average += damage.average()
|
average += damage.average()
|
||||||
if damage.is_breakable():
|
if damage.is_breakable():
|
||||||
@@ -494,7 +503,7 @@ class WeaponMonsterDamage(object):
|
|||||||
return 0
|
return 0
|
||||||
average = 0.0
|
average = 0.0
|
||||||
count = self.break_count + 1
|
count = self.break_count + 1
|
||||||
for part, damage in self.damage_map.iteritems():
|
for part, damage in self.damage_map.items():
|
||||||
if part == self.max_element_part[0]:
|
if part == self.max_element_part[0]:
|
||||||
# If weakpart is also a break, assume continue attacking
|
# If weakpart is also a break, assume continue attacking
|
||||||
# even after broken
|
# even after broken
|
||||||
@@ -516,7 +525,7 @@ class WeaponMonsterDamage(object):
|
|||||||
if not self.break_count:
|
if not self.break_count:
|
||||||
return 0
|
return 0
|
||||||
average = 0.0
|
average = 0.0
|
||||||
for part, damage in self.damage_map.iteritems():
|
for part, damage in self.damage_map.items():
|
||||||
if damage.is_breakable():
|
if damage.is_breakable():
|
||||||
# attack until broken, then move to next break
|
# attack until broken, then move to next break
|
||||||
average += damage.total
|
average += damage.total
|
||||||
@@ -553,8 +562,21 @@ class WeaponMonsterDamage(object):
|
|||||||
for row in self.monster_damage._rows:
|
for row in self.monster_damage._rows:
|
||||||
part = row["body_part"]
|
part = row["body_part"]
|
||||||
hitbox = int(row[raw_type])
|
hitbox = int(row[raw_type])
|
||||||
ehitbox = int(row[str(self.etype.lower())])
|
if self.etype:
|
||||||
hitboxes.append((part, hitbox, ehitbox, float(hitbox) / ehitbox))
|
try:
|
||||||
|
ehitbox = int(row[str(self.etype.lower())])
|
||||||
|
except IndexError:
|
||||||
|
ehitbox = 0
|
||||||
|
print("WARN: bad etype {}, row = {}".format(
|
||||||
|
self.etype, row))
|
||||||
|
else:
|
||||||
|
ehitbox = 0
|
||||||
|
|
||||||
|
if ehitbox > 0:
|
||||||
|
ratio = float(hitbox) / ehitbox
|
||||||
|
else:
|
||||||
|
ratio = 0
|
||||||
|
hitboxes.append((part, hitbox, ehitbox, ratio))
|
||||||
return hitboxes
|
return hitboxes
|
||||||
|
|
||||||
def nohitbox_damage(self, motion=None):
|
def nohitbox_damage(self, motion=None):
|
||||||
@@ -610,6 +632,20 @@ class PartDamage(object):
|
|||||||
def ehitbox(self):
|
def ehitbox(self):
|
||||||
return self.states[None].ehitbox
|
return self.states[None].ehitbox
|
||||||
|
|
||||||
|
@property
|
||||||
|
def break_hitbox(self):
|
||||||
|
if "Break Part" in self.states:
|
||||||
|
return self.states["Break Part"].hitbox
|
||||||
|
else:
|
||||||
|
return self.hitbox
|
||||||
|
|
||||||
|
@property
|
||||||
|
def break_ehitbox(self):
|
||||||
|
if "Break Part" in self.states:
|
||||||
|
return self.states["Break Part"].ehitbox
|
||||||
|
else:
|
||||||
|
return self.ehitbox
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def break_raw(self):
|
def break_raw(self):
|
||||||
if "Break Part" in self.states:
|
if "Break Part" in self.states:
|
||||||
@@ -660,7 +696,8 @@ class PartDamage(object):
|
|||||||
# If the part has a hitbox with different damage in the break
|
# If the part has a hitbox with different damage in the break
|
||||||
# rows from the db, or if it's explicitly marked as breakable
|
# rows from the db, or if it's explicitly marked as breakable
|
||||||
# (done by checking hunt rewards for breaks).
|
# (done by checking hunt rewards for breaks).
|
||||||
return self.break_diff() > 0 or self.breakable
|
return (self.breakable or self.raw != self.break_raw
|
||||||
|
or self.element != self.break_element)
|
||||||
|
|
||||||
def average(self, break_weight=0.25, rage_weight=0.5):
|
def average(self, break_weight=0.25, rage_weight=0.5):
|
||||||
if self.break_diff():
|
if self.break_diff():
|
||||||
@@ -680,7 +717,8 @@ class PartDamage(object):
|
|||||||
+ self.total * (1 - rage_weight))
|
+ self.total * (1 - rage_weight))
|
||||||
|
|
||||||
def set_damage(self, raw, element, hitbox, ehitbox, state=None):
|
def set_damage(self, raw, element, hitbox, ehitbox, state=None):
|
||||||
if state == "Without Hide":
|
if state in ("Without Hide", "Charged", "Tail Inflated", "Savaged",
|
||||||
|
"Enraged", "Ice Shield"):
|
||||||
state = "Break Part"
|
state = "Break Part"
|
||||||
self.states[state] = PartDamageState(raw, element,
|
self.states[state] = PartDamageState(raw, element,
|
||||||
hitbox, ehitbox, state)
|
hitbox, ehitbox, state)
|
||||||
|
|||||||
97
mhapi/db.py
97
mhapi/db.py
@@ -7,6 +7,7 @@ import sqlite3
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from mhapi import model
|
from mhapi import model
|
||||||
|
from mhapi.util import WEAPON_TYPES
|
||||||
|
|
||||||
|
|
||||||
def field_model(key):
|
def field_model(key):
|
||||||
@@ -257,10 +258,15 @@ class MHDB(object):
|
|||||||
return self._query_all("search_item", query, tuple(args),
|
return self._query_all("search_item", query, tuple(args),
|
||||||
no_cache=True, model_cls=model.Item)
|
no_cache=True, model_cls=model.Item)
|
||||||
|
|
||||||
def get_monsters(self):
|
def get_monsters(self, monster_class=None):
|
||||||
return self._query_all("monsters", """
|
args = []
|
||||||
SELECT * FROM monsters
|
where = []
|
||||||
""", model_cls=model.Monster)
|
if monster_class is not None:
|
||||||
|
where.append("WHERE class = ?")
|
||||||
|
args.append(monster_class)
|
||||||
|
args = tuple(args)
|
||||||
|
q = "SELECT * FROM monsters " + "\n".join(where)
|
||||||
|
return self._query_all("monsters", q, args, model_cls=model.Monster)
|
||||||
|
|
||||||
def get_monster_names(self):
|
def get_monster_names(self):
|
||||||
"""
|
"""
|
||||||
@@ -317,12 +323,17 @@ class MHDB(object):
|
|||||||
WHERE quest_id=?
|
WHERE quest_id=?
|
||||||
""", (quest_id,))
|
""", (quest_id,))
|
||||||
|
|
||||||
def get_monster_quests(self, monster_id, rank):
|
def get_monster_quests(self, monster_id, rank=None):
|
||||||
return self._query_all("monster_quests", """
|
|
||||||
SELECT DISTINCT quests.* FROM quests, monster_to_quest
|
query = """SELECT DISTINCT quests.* FROM quests, monster_to_quest
|
||||||
WHERE monster_to_quest.quest_id = quests._id
|
WHERE monster_to_quest.quest_id = quests._id
|
||||||
AND monster_to_quest.monster_id=? AND rank=?
|
AND monster_to_quest.monster_id=?"""
|
||||||
""", (monster_id, rank), model_cls=model.Quest)
|
args = [monster_id]
|
||||||
|
if rank is not None:
|
||||||
|
query += " AND rank=?"
|
||||||
|
args += [rank]
|
||||||
|
return self._query_all("monster_quests", query,
|
||||||
|
tuple(args), model_cls=model.Quest)
|
||||||
|
|
||||||
def get_item_quests(self, item_id):
|
def get_item_quests(self, item_id):
|
||||||
"""
|
"""
|
||||||
@@ -381,6 +392,14 @@ class MHDB(object):
|
|||||||
WHERE monster_id=?
|
WHERE monster_id=?
|
||||||
""", (monster_id,), collection_cls=model.MonsterDamage)
|
""", (monster_id,), collection_cls=model.MonsterDamage)
|
||||||
|
|
||||||
|
def get_weapon_types(self):
|
||||||
|
"""
|
||||||
|
List of strings.
|
||||||
|
"""
|
||||||
|
return self._query_all("weapon_types", """
|
||||||
|
SELECT DISTINCT wtype FROM weapons
|
||||||
|
""", model_cls=field_model("wtype"))
|
||||||
|
|
||||||
def get_weapons(self):
|
def get_weapons(self):
|
||||||
# Note: weapons only available via JP DLC have no localized
|
# Note: weapons only available via JP DLC have no localized
|
||||||
# name, filter them out.
|
# name, filter them out.
|
||||||
@@ -613,6 +632,13 @@ class MHDB(object):
|
|||||||
item_data.set_components(ccomps, ucomps)
|
item_data.set_components(ccomps, ucomps)
|
||||||
|
|
||||||
|
|
||||||
|
def _get_rise_num_slots(slot_list):
|
||||||
|
num_slots = 0
|
||||||
|
nslots = len(slot_list)
|
||||||
|
for i in range(nslots - 1, -1, -1):
|
||||||
|
num_slots += 10**(nslots - i - 1) * slot_list[i]
|
||||||
|
return num_slots
|
||||||
|
|
||||||
|
|
||||||
class MHDBX(object):
|
class MHDBX(object):
|
||||||
"""
|
"""
|
||||||
@@ -626,12 +652,14 @@ class MHDBX(object):
|
|||||||
"""
|
"""
|
||||||
Loads JSON data, keeps in memory.
|
Loads JSON data, keeps in memory.
|
||||||
"""
|
"""
|
||||||
|
self.game = game
|
||||||
module_path = os.path.dirname(__file__)
|
module_path = os.path.dirname(__file__)
|
||||||
self._mhx_db_path = os.path.abspath(os.path.join(module_path, "..",
|
self._mhx_db_path = os.path.abspath(os.path.join(module_path, "..",
|
||||||
"db", game))
|
"db", game))
|
||||||
self._4udb = MHDB()
|
self._4udb = MHDB(game="gu")
|
||||||
self._weapon_list = []
|
self._weapon_list = []
|
||||||
self._weapons_by_name = {}
|
self._weapons_by_name = {}
|
||||||
|
self._weapons_by_id = {}
|
||||||
|
|
||||||
self._monsters_by_name = {}
|
self._monsters_by_name = {}
|
||||||
self._monster_damage = {}
|
self._monster_damage = {}
|
||||||
@@ -644,10 +672,23 @@ class MHDBX(object):
|
|||||||
with open(os.path.join(self._mhx_db_path, "weapon_list.json")) as f:
|
with open(os.path.join(self._mhx_db_path, "weapon_list.json")) as f:
|
||||||
wlist = json.load(f)
|
wlist = json.load(f)
|
||||||
for i, wdata in enumerate(wlist):
|
for i, wdata in enumerate(wlist):
|
||||||
wdata["_id"] = i
|
if "_id" not in wdata:
|
||||||
|
wdata["_id"] = i
|
||||||
|
keys = ["awaken", "horn_notes",
|
||||||
|
"element", "element_attack",
|
||||||
|
"element_2", "element_2_attack",
|
||||||
|
"bug_level", "phial", "phial_value",
|
||||||
|
"shelling_type", "shelling_level",
|
||||||
|
"buy"]
|
||||||
|
for k in keys:
|
||||||
|
if k not in wdata:
|
||||||
|
wdata[k] = None
|
||||||
|
if self.game == "mhr":
|
||||||
|
wdata["num_slots"] = _get_rise_num_slots(wdata["slots"])
|
||||||
weapon = model.Weapon(wdata)
|
weapon = model.Weapon(wdata)
|
||||||
self._weapon_list.append(weapon)
|
self._weapon_list.append(weapon)
|
||||||
self._weapons_by_name[weapon.name_jp] = weapon
|
self._weapons_by_name[weapon.name_jp] = weapon
|
||||||
|
self._weapons_by_id[weapon.id] = weapon
|
||||||
|
|
||||||
def _load_monsters(self):
|
def _load_monsters(self):
|
||||||
names_path = os.path.join(self._mhx_db_path,
|
names_path = os.path.join(self._mhx_db_path,
|
||||||
@@ -662,20 +703,39 @@ class MHDBX(object):
|
|||||||
self._monsters_by_name[d["name"]] = model.Monster(d)
|
self._monsters_by_name[d["name"]] = model.Monster(d)
|
||||||
with open(hitboxes_path) as f:
|
with open(hitboxes_path) as f:
|
||||||
damage_map = json.load(f)
|
damage_map = json.load(f)
|
||||||
for name, damage in damage_map.iteritems():
|
for name, damage in damage_map.items():
|
||||||
mid = self._monsters_by_name[name].id
|
mid = self._monsters_by_name[name].id
|
||||||
damage_rows = []
|
damage_rows = []
|
||||||
for part, data in damage.iteritems():
|
for part, data in damage.items():
|
||||||
if part.startswith("_"):
|
if part.startswith("_"):
|
||||||
continue
|
continue
|
||||||
row = dict((k.lower(), v) for k, v in data.iteritems())
|
row = dict((k.lower(), v) for k, v in data.items())
|
||||||
row["body_part"] = part
|
row["body_part"] = part
|
||||||
row["ko"] = 100 if part == "Head" else 0
|
row["ko"] = 100 if part == "Head" else 0
|
||||||
row["_id"] = 0
|
row["_id"] = 0
|
||||||
row["monster_id"] = mid
|
row["monster_id"] = mid
|
||||||
damage_rows.append(row)
|
damage_rows.append(row)
|
||||||
self._monster_damage[mid] = model.MonsterDamage(damage_rows)
|
self._monster_damage[mid] = model.MonsterDamage(damage_rows)
|
||||||
self._monster_breaks[mid] = damage["_breaks"]
|
self._monster_breaks[mid] = damage.get("_breaks", [])
|
||||||
|
|
||||||
|
def get_monsters(self):
|
||||||
|
return list(self._monsters_by_name.values())
|
||||||
|
|
||||||
|
def get_weapons(self):
|
||||||
|
return list(self._weapon_list)
|
||||||
|
|
||||||
|
def get_weapon(self, weapon_id):
|
||||||
|
return self._weapons_by_id[weapon_id]
|
||||||
|
|
||||||
|
def get_weapons_by_parent(self, parent_id):
|
||||||
|
result = []
|
||||||
|
for w in self._weapon_list:
|
||||||
|
if w.parent_id == parent_id:
|
||||||
|
result.append(w)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def get_weapon_types(self):
|
||||||
|
return WEAPON_TYPES
|
||||||
|
|
||||||
def get_weapon_by_name(self, name):
|
def get_weapon_by_name(self, name):
|
||||||
return self._weapons_by_name.get(name)
|
return self._weapons_by_name.get(name)
|
||||||
@@ -705,9 +765,10 @@ class MHDBX(object):
|
|||||||
with no element. Otherwise @element is searched for in both
|
with no element. Otherwise @element is searched for in both
|
||||||
awaken and native, and can be a status or an element.
|
awaken and native, and can be a status or an element.
|
||||||
|
|
||||||
@final should be string '1' or '0'
|
@final None or string '1' or '0'
|
||||||
"""
|
"""
|
||||||
final = int(final)
|
if final is not None:
|
||||||
|
final = int(final)
|
||||||
results = []
|
results = []
|
||||||
for w in self._weapon_list:
|
for w in self._weapon_list:
|
||||||
if wtype is not None and w.wtype != wtype:
|
if wtype is not None and w.wtype != wtype:
|
||||||
|
|||||||
326
mhapi/model.py
326
mhapi/model.py
@@ -1,8 +1,11 @@
|
|||||||
|
import os
|
||||||
import string
|
import string
|
||||||
import json
|
import json
|
||||||
import urllib
|
from typing import NamedTuple
|
||||||
|
import urllib.request, urllib.parse, urllib.error
|
||||||
import re
|
import re
|
||||||
import difflib
|
import difflib
|
||||||
|
from collections import namedtuple
|
||||||
|
|
||||||
from mhapi.util import EnumBase
|
from mhapi.util import EnumBase
|
||||||
|
|
||||||
@@ -57,7 +60,7 @@ class RowModel(ModelBase):
|
|||||||
return key in self._data
|
return key in self._data
|
||||||
|
|
||||||
def fields(self):
|
def fields(self):
|
||||||
return self._data.keys()
|
return list(self._data.keys())
|
||||||
|
|
||||||
def as_data(self):
|
def as_data(self):
|
||||||
return self._data
|
return self._data
|
||||||
@@ -69,7 +72,7 @@ class RowModel(ModelBase):
|
|||||||
return list_data
|
return list_data
|
||||||
|
|
||||||
def update_indexes(self, data):
|
def update_indexes(self, data):
|
||||||
for key_field, value_fields in self._indexes.iteritems():
|
for key_field, value_fields in self._indexes.items():
|
||||||
if key_field not in data:
|
if key_field not in data:
|
||||||
data[key_field] = {}
|
data[key_field] = {}
|
||||||
self.update_index(key_field, value_fields, data[key_field])
|
self.update_index(key_field, value_fields, data[key_field])
|
||||||
@@ -86,7 +89,7 @@ class RowModel(ModelBase):
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
if "name" in self._data and self.name is not None:
|
if "name" in self._data and self.name is not None:
|
||||||
name = urllib.quote(self.name, safe=" ")
|
name = urllib.parse.quote(self.name, safe=" ")
|
||||||
else:
|
else:
|
||||||
name = str(self.id)
|
name = str(self.id)
|
||||||
return "%s '%s'" % (self.__class__.__name__, name)
|
return "%s '%s'" % (self.__class__.__name__, name)
|
||||||
@@ -139,7 +142,7 @@ class SharpnessLevel(EnumBase):
|
|||||||
WHITE = 5
|
WHITE = 5
|
||||||
PURPLE = 6
|
PURPLE = 6
|
||||||
|
|
||||||
ALL = range(0, PURPLE + 1)
|
ALL = list(range(0, PURPLE + 1))
|
||||||
|
|
||||||
_names = {
|
_names = {
|
||||||
RED: "Red",
|
RED: "Red",
|
||||||
@@ -162,7 +165,7 @@ class SharpnessLevel(EnumBase):
|
|||||||
PURPLE: (1.44, 1.20),
|
PURPLE: (1.44, 1.20),
|
||||||
}
|
}
|
||||||
|
|
||||||
# for mhx, mhgen, mhxx, and likely mhw
|
# for mhx, mhgen, mhxx
|
||||||
_modifier_mhx = {
|
_modifier_mhx = {
|
||||||
RED: (0.50, 0.25),
|
RED: (0.50, 0.25),
|
||||||
ORANGE: (0.75, 0.50),
|
ORANGE: (0.75, 0.50),
|
||||||
@@ -172,14 +175,48 @@ class SharpnessLevel(EnumBase):
|
|||||||
WHITE: (1.32, 1.125),
|
WHITE: (1.32, 1.125),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# world, rise
|
||||||
|
# https://twitter.com/AsteriskAmpers1/status/1372886666940137479
|
||||||
|
# https://monsterhunterworld.wiki.fextralife.com/Sharpness
|
||||||
|
# https://monsterhunterrise.wiki.fextralife.com/Sharpness
|
||||||
|
_modifier_mhw = {
|
||||||
|
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.15),
|
||||||
|
PURPLE: (1.39, 1.25),
|
||||||
|
}
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def raw_modifier(cls, sharpness):
|
def raw_modifier(cls, sharpness):
|
||||||
return cls._modifier[sharpness][0]
|
if _game() == "4u":
|
||||||
|
d = cls._modifier
|
||||||
|
elif _game() in ["gen", "gu", "mhx"]:
|
||||||
|
d = cls._modifier_mhx
|
||||||
|
else:
|
||||||
|
d = cls._modifier_mhw
|
||||||
|
return d[sharpness][0]
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def element_modifier(cls, sharpness):
|
def element_modifier(cls, sharpness):
|
||||||
return cls._modifier[sharpness][1]
|
if _game() == "4u":
|
||||||
|
d = cls._modifier
|
||||||
|
elif _game() in ["gen", "gu", "mhx"]:
|
||||||
|
d = cls._modifier_mhx
|
||||||
|
else:
|
||||||
|
d = cls._modifier_mhw
|
||||||
|
return d[sharpness][1]
|
||||||
|
|
||||||
|
_GAME = None
|
||||||
|
|
||||||
|
def _game():
|
||||||
|
global _GAME
|
||||||
|
if _GAME is None:
|
||||||
|
_GAME = os.environ.get("MHAPI_GAME", "4u")
|
||||||
|
assert _GAME in ("4u", "gen", "gu", "mhx", "mhw", "mhr")
|
||||||
|
return _GAME
|
||||||
|
|
||||||
|
|
||||||
class WeaponSharpness(ModelBase):
|
class WeaponSharpness(ModelBase):
|
||||||
@@ -195,32 +232,54 @@ class WeaponSharpness(ModelBase):
|
|||||||
self.value_list = [int(s) for s in db_string_or_list.split(".")]
|
self.value_list = [int(s) for s in db_string_or_list.split(".")]
|
||||||
# For MHX, Gen, no purple sharpness, but keep model the same for
|
# For MHX, Gen, no purple sharpness, but keep model the same for
|
||||||
# simplicity
|
# simplicity
|
||||||
if len(self.value_list) < SharpnessLevel.PURPLE + 1:
|
while len(self.value_list) < SharpnessLevel.PURPLE + 1:
|
||||||
self.value_list.append(0)
|
self.value_list.append(0)
|
||||||
self._max = None
|
self._max = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def max(self):
|
def max(self):
|
||||||
if self._max is None:
|
if self._max is None:
|
||||||
self._max = SharpnessLevel.RED
|
for i in range(SharpnessLevel.PURPLE, -1, -1):
|
||||||
for i in xrange(SharpnessLevel.PURPLE+1):
|
if self.value_list[i] > 0:
|
||||||
if self.value_list[i] == 0:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
self._max = i
|
self._max = i
|
||||||
|
break
|
||||||
return self._max
|
return self._max
|
||||||
|
|
||||||
|
def get_max_points(self):
|
||||||
|
return (self.max, self.value_list[self.max])
|
||||||
|
|
||||||
|
def get_rise_handicraft(self, n):
|
||||||
|
"""In Rise, there are 5 levels of Handicraft, each give 5 extra points; this
|
||||||
|
can be used to subtract off from sharpness_plus row"""
|
||||||
|
alt_values = list(self.value_list)
|
||||||
|
assert n >= 0 and n <= 5
|
||||||
|
minus_points = 25 - n * 5
|
||||||
|
for i in range(SharpnessLevel.PURPLE, -1, -1):
|
||||||
|
val = alt_values[i]
|
||||||
|
if minus_points <= val:
|
||||||
|
alt_values[i] -= minus_points
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
alt_values[i] = 0
|
||||||
|
minus_points -= val
|
||||||
|
return WeaponSharpness(alt_values)
|
||||||
|
|
||||||
def as_data(self):
|
def as_data(self):
|
||||||
return self.value_list
|
return self.value_list
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return ",".join(str(v) for v in self.value_list)
|
||||||
|
|
||||||
|
|
||||||
class ItemCraftable(RowModel):
|
class ItemCraftable(RowModel):
|
||||||
_list_fields = ["id", "name"]
|
_list_fields = ["id", "name"]
|
||||||
|
|
||||||
def __init__(self, item_row):
|
def __init__(self, item_row):
|
||||||
super(ItemCraftable, self).__init__(item_row)
|
super(ItemCraftable, self).__init__(item_row)
|
||||||
self.create_components = None
|
if "create_components" not in item_row:
|
||||||
self.upgrade_components = None
|
self.create_components = None
|
||||||
|
if "upgrade_components" not in item_row:
|
||||||
|
self.upgrade_components = None
|
||||||
|
|
||||||
def set_components(self, create_components, upgrade_components):
|
def set_components(self, create_components, upgrade_components):
|
||||||
self.create_components = create_components
|
self.create_components = create_components
|
||||||
@@ -230,10 +289,10 @@ class ItemCraftable(RowModel):
|
|||||||
data = super(ItemCraftable, self).as_data()
|
data = super(ItemCraftable, self).as_data()
|
||||||
if self.create_components is not None:
|
if self.create_components is not None:
|
||||||
data["create_components"] = dict((item.name, item.quantity)
|
data["create_components"] = dict((item.name, item.quantity)
|
||||||
for item in self.create_components)
|
for item in _item_list(self.create_components))
|
||||||
if self.upgrade_components is not None:
|
if self.upgrade_components is not None:
|
||||||
data["upgrade_components"] = dict((item.name, item.quantity)
|
data["upgrade_components"] = dict((item.name, item.quantity)
|
||||||
for item in self.upgrade_components)
|
for item in _item_list(self.upgrade_components))
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
|
||||||
@@ -304,7 +363,7 @@ class Armor(ItemWithSkills):
|
|||||||
assert self.skills is not None
|
assert self.skills is not None
|
||||||
total = self.skills.get(skill_id_or_name, 0)
|
total = self.skills.get(skill_id_or_name, 0)
|
||||||
slots_left = self.num_slots
|
slots_left = self.num_slots
|
||||||
for slots in xrange(len(decoration_values), 0, -1):
|
for slots in range(len(decoration_values), 0, -1):
|
||||||
if slots_left == 0:
|
if slots_left == 0:
|
||||||
break
|
break
|
||||||
decoration_value = decoration_values[slots-1]
|
decoration_value = decoration_values[slots-1]
|
||||||
@@ -373,6 +432,8 @@ class Weapon(ItemCraftable):
|
|||||||
def __init__(self, weapon_item_row):
|
def __init__(self, weapon_item_row):
|
||||||
super(Weapon, self).__init__(weapon_item_row)
|
super(Weapon, self).__init__(weapon_item_row)
|
||||||
self._parse_sharpness()
|
self._parse_sharpness()
|
||||||
|
if "name_jp" not in self._data:
|
||||||
|
self._data["name_jp"] = self._data["name"]
|
||||||
|
|
||||||
def _parse_sharpness(self):
|
def _parse_sharpness(self):
|
||||||
"""
|
"""
|
||||||
@@ -385,11 +446,12 @@ class Weapon(ItemCraftable):
|
|||||||
if isinstance(self._row["sharpness"], list):
|
if isinstance(self._row["sharpness"], list):
|
||||||
# MHX JSON data, already desired format, but doesn't have
|
# MHX JSON data, already desired format, but doesn't have
|
||||||
# purple so we append 0
|
# purple so we append 0
|
||||||
self.sharpness = WeaponSharpness(self._row["sharpness"] + [0])
|
row_sharpness = self._row["sharpness"]
|
||||||
self.sharpness_plus = WeaponSharpness(
|
row_sharpness_plus = self._row.get("sharpness_plus", row_sharpness)
|
||||||
self._row["sharpness_plus"] + [0])
|
row_sharpness_plus2 = self._row.get("sharpness_plus2", row_sharpness)
|
||||||
self.sharpness_plus2 = WeaponSharpness(
|
self.sharpness = WeaponSharpness(row_sharpness)
|
||||||
self._row["sharpness_plus2"] + [0])
|
self.sharpness_plus = WeaponSharpness(row_sharpness_plus)
|
||||||
|
self.sharpness_plus2 = WeaponSharpness(row_sharpness_plus2)
|
||||||
else:
|
else:
|
||||||
# 4U or gen data from db
|
# 4U or gen data from db
|
||||||
parts = self._row["sharpness"].split(" ")
|
parts = self._row["sharpness"].split(" ")
|
||||||
@@ -410,6 +472,10 @@ class Weapon(ItemCraftable):
|
|||||||
# english weapons, and not for Japanese DLC weapons.
|
# english weapons, and not for Japanese DLC weapons.
|
||||||
return ord(self.name[0]) < 128
|
return ord(self.name[0]) < 128
|
||||||
|
|
||||||
|
@property
|
||||||
|
def sharpness_name(self):
|
||||||
|
return SharpnessLevel.name(self.sharpness)
|
||||||
|
|
||||||
|
|
||||||
class Monster(RowModel):
|
class Monster(RowModel):
|
||||||
_list_fields = ["id", "class", "name"]
|
_list_fields = ["id", "class", "name"]
|
||||||
@@ -459,6 +525,12 @@ class MonsterPartStateDamage(RowModel):
|
|||||||
def __ne__(self, other):
|
def __ne__(self, other):
|
||||||
return not self.__eq__(other)
|
return not self.__eq__(other)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.as_data())
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return repr(self.as_data())
|
||||||
|
|
||||||
|
|
||||||
class MonsterPartDamage(ModelBase):
|
class MonsterPartDamage(ModelBase):
|
||||||
"""
|
"""
|
||||||
@@ -493,6 +565,49 @@ class MonsterPartDamage(ModelBase):
|
|||||||
damage=self.states
|
damage=self.states
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return str(self.as_data())
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return repr(self.as_data())
|
||||||
|
|
||||||
|
def state_names(self):
|
||||||
|
return list(self.states.keys())
|
||||||
|
|
||||||
|
def get(self, damage_type):
|
||||||
|
return self.get_state(damage_type)
|
||||||
|
|
||||||
|
def get_break(self, damage_type):
|
||||||
|
self.get_state(damage_type, "Break Part")
|
||||||
|
|
||||||
|
def get_alt_state(self, damage_type):
|
||||||
|
return self.get_state(damage_type, self.alt_state)
|
||||||
|
|
||||||
|
def get_state(self, damage_type, state="Default"):
|
||||||
|
if state not in self.states:
|
||||||
|
state = "Default"
|
||||||
|
return self.states[state][damage_type]
|
||||||
|
|
||||||
|
def __getitem__(self, damage_type):
|
||||||
|
return self.get(damage_type)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def alt_state(self):
|
||||||
|
if "Break Part" in self.states:
|
||||||
|
return "Break Part"
|
||||||
|
elif len(self.states) > 1:
|
||||||
|
alt_states = list(self.states.keys())
|
||||||
|
if "Default" in alt_states:
|
||||||
|
alt_states.remove("Default")
|
||||||
|
return alt_states[0]
|
||||||
|
else:
|
||||||
|
return "Default"
|
||||||
|
|
||||||
|
def state_diff(self, damage_type, state=None):
|
||||||
|
if state is None:
|
||||||
|
state = self.alt_state
|
||||||
|
return self.get_state(damage_type, state) - self.get(damage_type)
|
||||||
|
|
||||||
|
|
||||||
class MonsterDamage(ModelBase):
|
class MonsterDamage(ModelBase):
|
||||||
"""
|
"""
|
||||||
@@ -518,6 +633,10 @@ class MonsterDamage(ModelBase):
|
|||||||
self.parts[part] = MonsterPartDamage(part)
|
self.parts[part] = MonsterPartDamage(part)
|
||||||
self.parts[part].add_state(state, row)
|
self.parts[part].add_state(state, row)
|
||||||
|
|
||||||
|
def is_valid(self):
|
||||||
|
# TODO: more validation
|
||||||
|
return (len(self.states) > 0 and len(self.parts) > 0)
|
||||||
|
|
||||||
def as_data(self):
|
def as_data(self):
|
||||||
return dict(
|
return dict(
|
||||||
states=list(self.states),
|
states=list(self.states),
|
||||||
@@ -529,11 +648,54 @@ class MonsterDamage(ModelBase):
|
|||||||
Set breakable flag on parts based on the breakable list from
|
Set breakable flag on parts based on the breakable list from
|
||||||
rewards (use MHDB.get_monster_breaks).
|
rewards (use MHDB.get_monster_breaks).
|
||||||
"""
|
"""
|
||||||
for name, part_damage in self.parts.iteritems():
|
for name, part_damage in self.parts.items():
|
||||||
if _break_find(name, self.parts, breakable_list):
|
if _break_find(name, self.parts, breakable_list):
|
||||||
#print "part %s is breakable [by rewards]" % name
|
#print "part %s is breakable [by rewards]" % name
|
||||||
part_damage.breakable = True
|
part_damage.breakable = True
|
||||||
|
|
||||||
|
def state_names(self):
|
||||||
|
names = list(self.states)
|
||||||
|
names.sort()
|
||||||
|
if "Default" in names:
|
||||||
|
names.remove("Default")
|
||||||
|
names.insert(0, "Default")
|
||||||
|
return names
|
||||||
|
|
||||||
|
def keys(self):
|
||||||
|
return self.parts.keys()
|
||||||
|
|
||||||
|
def values(self):
|
||||||
|
return self.parts.values()
|
||||||
|
|
||||||
|
def items(self):
|
||||||
|
return self.parts.items()
|
||||||
|
|
||||||
|
def __len__(self):
|
||||||
|
return len(self.parts)
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return iter(self.parts)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def alt_state(self):
|
||||||
|
alt_states = set(self.states)
|
||||||
|
alt_states.remove("Default")
|
||||||
|
if alt_states:
|
||||||
|
return alt_states.pop()
|
||||||
|
return "Default"
|
||||||
|
|
||||||
|
def avg(self, damage_type, state="Default"):
|
||||||
|
return sum(part.get_state(damage_type, state)
|
||||||
|
for part in self.values()) / len(self)
|
||||||
|
|
||||||
|
def alt_avg(self, damage_type):
|
||||||
|
return sum(part.get_alt_state(damage_type)
|
||||||
|
for part in self.values()) / len(self)
|
||||||
|
|
||||||
|
def max(self, damage_type, state="Default"):
|
||||||
|
return max(part.get_state(damage_type, state)
|
||||||
|
for part in self.values())
|
||||||
|
|
||||||
|
|
||||||
def get_decoration_values(skill_id, decorations):
|
def get_decoration_values(skill_id, decorations):
|
||||||
"""
|
"""
|
||||||
@@ -610,19 +772,19 @@ def get_costs(db, weapon):
|
|||||||
upgrade_cost = int(weapon.upgrade_cost)
|
upgrade_cost = int(weapon.upgrade_cost)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
upgrade_cost = 0
|
upgrade_cost = 0
|
||||||
print "WARN: bad upgrade cost for '%s' (%s): '%s'" \
|
print("WARN: bad upgrade cost for '%s' (%s): '%s'" \
|
||||||
% (weapon.name, weapon.id, weapon.upgrade_cost)
|
% (weapon.name, weapon.id, weapon.upgrade_cost))
|
||||||
except UnicodeError:
|
except UnicodeError:
|
||||||
upgrade_cost = 0
|
upgrade_cost = 0
|
||||||
cost_display = urllib.quote(weapon.upgrade_cost)
|
cost_display = urllib.parse.quote(weapon.upgrade_cost)
|
||||||
print "WARN: bad upgrade cost for '%s' (%s): '%s'" \
|
print("WARN: bad upgrade cost for '%s' (%s): '%s'" \
|
||||||
% (weapon.name, weapon.id, cost_display)
|
% (weapon.name, weapon.id, cost_display))
|
||||||
parent_weapon = db.get_weapon(weapon.parent_id)
|
parent_weapon = db.get_weapon(weapon.parent_id)
|
||||||
costs = get_costs(db, parent_weapon)
|
costs = get_costs(db, parent_weapon)
|
||||||
for cost in costs:
|
for cost in costs:
|
||||||
cost["zenny"] += upgrade_cost
|
cost["zenny"] += upgrade_cost
|
||||||
cost["path"] += [weapon]
|
cost["path"] += [weapon]
|
||||||
for item in weapon.upgrade_components:
|
for item in _item_list(weapon.upgrade_components):
|
||||||
if item.type == "Weapon":
|
if item.type == "Weapon":
|
||||||
continue
|
continue
|
||||||
if item.name not in cost["components"]:
|
if item.name not in cost["components"]:
|
||||||
@@ -632,28 +794,65 @@ def get_costs(db, weapon):
|
|||||||
try:
|
try:
|
||||||
zenny = int(weapon.creation_cost)
|
zenny = int(weapon.creation_cost)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print "WARN: bad creation cost for '%s': '%s'" \
|
print("WARN: bad creation cost for '%s': '%s'" \
|
||||||
% (weapon.name, weapon.creation_cost)
|
% (weapon.name, weapon.creation_cost))
|
||||||
zenny = weapon.upgrade_cost or 0
|
zenny = weapon.upgrade_cost or 0
|
||||||
create_cost = dict(zenny=zenny,
|
create_cost = dict(zenny=zenny,
|
||||||
path=[weapon],
|
path=[weapon],
|
||||||
components={})
|
components={})
|
||||||
for item in weapon.create_components:
|
for item in _item_list(weapon.create_components):
|
||||||
create_cost["components"][item.name] = item.quantity
|
create_cost["components"][item.name] = item.quantity
|
||||||
costs = [create_cost] + costs
|
costs = [create_cost] + costs
|
||||||
|
if weapon.buy:
|
||||||
|
buy_cost = dict(zenny=int(weapon.buy),
|
||||||
|
path=[weapon],
|
||||||
|
components={})
|
||||||
|
costs = [buy_cost] + costs
|
||||||
return costs
|
return costs
|
||||||
|
|
||||||
|
|
||||||
|
CompItem = namedtuple("CompItem", "name quantity type")
|
||||||
|
def _item_list(comps):
|
||||||
|
if comps is None or isinstance(comps, list):
|
||||||
|
return comps
|
||||||
|
elif isinstance(comps, dict):
|
||||||
|
items = []
|
||||||
|
for k, v in comps.items():
|
||||||
|
items.append(CompItem(k, v, "material"))
|
||||||
|
return items
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown component type")
|
||||||
|
|
||||||
|
|
||||||
|
def rank_quest_level(game, hub, rank):
|
||||||
|
if game != "4u":
|
||||||
|
raise NotImplementedError()
|
||||||
|
if hub == "Village":
|
||||||
|
if rank == "G":
|
||||||
|
return 10
|
||||||
|
elif rank == "HR":
|
||||||
|
return 7
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
elif hub == "Guild":
|
||||||
|
if rank == "G":
|
||||||
|
return 8
|
||||||
|
elif rank == "HR":
|
||||||
|
return 4
|
||||||
|
else:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
|
||||||
class ItemStars(object):
|
class ItemStars(object):
|
||||||
"""
|
"""
|
||||||
Get the game progress (in hub stars) required to make an item. Caches
|
Get the game progress (in hub stars) required to make an item. Caches
|
||||||
values.
|
values.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, db):
|
def __init__(self, db):
|
||||||
self.db = db
|
self.db = db
|
||||||
self._item_stars = {} # item id -> stars dict
|
self._item_stars = {} # item id -> stars dict
|
||||||
self._weapon_stars = {} # weapon id -> stars dict
|
self._weapon_stars = {} # weapon id -> stars dict
|
||||||
|
self._monster_stars = {} # monster id -> stars dict
|
||||||
self._wyporium_trades = {}
|
self._wyporium_trades = {}
|
||||||
|
|
||||||
if self.db.game == "4u":
|
if self.db.game == "4u":
|
||||||
@@ -678,8 +877,12 @@ class ItemStars(object):
|
|||||||
costs = get_costs(self.db, weapon)
|
costs = get_costs(self.db, weapon)
|
||||||
# find least 'expensive' path
|
# find least 'expensive' path
|
||||||
for c in costs:
|
for c in costs:
|
||||||
|
# don't calculate stars from buy cost (buys aren't available
|
||||||
|
# until after item is craftable, sometimes much later)
|
||||||
|
if not c["components"]:
|
||||||
|
continue
|
||||||
current_stars = self._get_component_stars(c)
|
current_stars = self._get_component_stars(c)
|
||||||
for k, v in current_stars.iteritems():
|
for k, v in current_stars.items():
|
||||||
if v is None:
|
if v is None:
|
||||||
continue
|
continue
|
||||||
if stars[k] is None or v < stars[k]:
|
if stars[k] is None or v < stars[k]:
|
||||||
@@ -734,7 +937,7 @@ class ItemStars(object):
|
|||||||
if "Scrap" in item.name:
|
if "Scrap" in item.name:
|
||||||
continue
|
continue
|
||||||
istars = self.get_item_stars(item.id)
|
istars = self.get_item_stars(item.id)
|
||||||
for k, v in stars.items():
|
for k, v in list(stars.items()):
|
||||||
if istars[k] > v:
|
if istars[k] > v:
|
||||||
stars[k] = istars[k]
|
stars[k] = istars[k]
|
||||||
break
|
break
|
||||||
@@ -765,7 +968,7 @@ class ItemStars(object):
|
|||||||
gather_locations = set()
|
gather_locations = set()
|
||||||
for gather in gathering:
|
for gather in gathering:
|
||||||
gather_locations.add((gather["location_id"], gather["rank"]))
|
gather_locations.add((gather["location_id"], gather["rank"]))
|
||||||
for location_id, rank in list(gather_locations):
|
for location_id, rank in gather_locations:
|
||||||
gather_quests = self.db.get_location_quests(location_id, rank)
|
gather_quests = self.db.get_location_quests(location_id, rank)
|
||||||
quests.extend(gather_quests)
|
quests.extend(gather_quests)
|
||||||
|
|
||||||
@@ -773,7 +976,7 @@ class ItemStars(object):
|
|||||||
monster_ranks = set()
|
monster_ranks = set()
|
||||||
for monster in monsters:
|
for monster in monsters:
|
||||||
monster_ranks.add((monster["monster_id"], monster["rank"]))
|
monster_ranks.add((monster["monster_id"], monster["rank"]))
|
||||||
for monster_id, rank in list(monster_ranks):
|
for monster_id, rank in monster_ranks:
|
||||||
monster_quests = self.db.get_monster_quests(monster_id, rank)
|
monster_quests = self.db.get_monster_quests(monster_id, rank)
|
||||||
quests.extend(monster_quests)
|
quests.extend(monster_quests)
|
||||||
|
|
||||||
@@ -785,17 +988,36 @@ class ItemStars(object):
|
|||||||
if quest.stars == 0:
|
if quest.stars == 0:
|
||||||
# ignore training quests
|
# ignore training quests
|
||||||
if "Training" not in quest.name:
|
if "Training" not in quest.name:
|
||||||
print "Error: non training quest has 0 stars", \
|
print("Error: non training quest has 0 stars", \
|
||||||
quest.id, quest.name
|
quest.id, quest.name)
|
||||||
continue
|
continue
|
||||||
if quest.hub in stars:
|
if quest.hub in stars:
|
||||||
current = stars[quest.hub]
|
current = stars[quest.hub]
|
||||||
if current is None or quest.stars < current:
|
if current is None or quest.stars < current:
|
||||||
stars[quest.hub] = quest.stars
|
stars[quest.hub] = quest.stars
|
||||||
else:
|
else:
|
||||||
print "Error: unknown hub", quest.hub
|
print("Error: unknown hub", quest.hub)
|
||||||
|
|
||||||
# if available guild or village, then null out permit/arena values,
|
if stars["Village"] is None and stars["Guild"] is None:
|
||||||
|
# not available from quests or gathering, may be an
|
||||||
|
# Everwood only monster (4u). Set stars based on rank. Note
|
||||||
|
# that this is imperfect, because some monsters have special
|
||||||
|
# quests and unlock them appearing in the Everwood, but at least
|
||||||
|
# will prevent totally broken G-rank weapons showing up in
|
||||||
|
# low rank comparisons.
|
||||||
|
min_village = 10
|
||||||
|
min_guild = 10
|
||||||
|
for _, rank in monster_ranks:
|
||||||
|
v = rank_quest_level(self.db.game, "Village", rank)
|
||||||
|
if v < min_village:
|
||||||
|
min_village = v
|
||||||
|
g = rank_quest_level(self.db.game, "Guild", rank)
|
||||||
|
if g < min_guild:
|
||||||
|
min_guild = g
|
||||||
|
stars["Village"] = min_village
|
||||||
|
stars["Guild"] = min_guild
|
||||||
|
|
||||||
|
# If available guild or village, then null out permit/arena values,
|
||||||
# because they are more useful for filtering if limited to items
|
# because they are more useful for filtering if limited to items
|
||||||
# exclusively available from permit or arena. Allows matching
|
# exclusively available from permit or arena. Allows matching
|
||||||
# on based on meeting specified critera for
|
# on based on meeting specified critera for
|
||||||
@@ -807,3 +1029,21 @@ class ItemStars(object):
|
|||||||
self._item_stars[item_id] = stars
|
self._item_stars[item_id] = stars
|
||||||
return stars
|
return stars
|
||||||
|
|
||||||
|
def get_monster_stars(self, monster_id):
|
||||||
|
stars = self._monster_stars.get(monster_id)
|
||||||
|
if stars is not None:
|
||||||
|
return stars
|
||||||
|
|
||||||
|
stars = dict(Village=None, Guild=None, Permit=None, Arena=None,
|
||||||
|
Event=None)
|
||||||
|
|
||||||
|
quests = self.db.get_monster_quests(monster_id)
|
||||||
|
|
||||||
|
for quest in quests:
|
||||||
|
if quest.hub == "Caravan":
|
||||||
|
quest.hub = "Village"
|
||||||
|
if stars[quest.hub] is None or quest.stars < stars[quest.hub]:
|
||||||
|
stars[quest.hub] = quest.stars
|
||||||
|
|
||||||
|
self._monster_stars[monster_id] = stars
|
||||||
|
return stars
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ Calculate expected values for monster hunter items and find the best quests
|
|||||||
and hunts for getting an item with specified skills.
|
and hunts for getting an item with specified skills.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from __future__ import print_function
|
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from mhapi import stats
|
from mhapi import stats
|
||||||
@@ -105,7 +105,7 @@ class GatherLocation(object):
|
|||||||
for gr in self._rewards:
|
for gr in self._rewards:
|
||||||
gr.print(out, indent)
|
gr.print(out, indent)
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __bool__(self):
|
||||||
return bool(len(self._rewards))
|
return bool(len(self._rewards))
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
@@ -146,7 +146,7 @@ class QuestReward(object):
|
|||||||
* (LuckSkill.AMAZING - LuckSkill.NONE + 1))
|
* (LuckSkill.AMAZING - LuckSkill.NONE + 1))
|
||||||
else:
|
else:
|
||||||
counts = [stats.quest_reward_expected_c(self.slot, skill)
|
counts = [stats.quest_reward_expected_c(self.slot, skill)
|
||||||
for skill in xrange(LuckSkill.NONE,
|
for skill in range(LuckSkill.NONE,
|
||||||
LuckSkill.AMAZING+1)]
|
LuckSkill.AMAZING+1)]
|
||||||
|
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ class QuestItemExpectedValue(object):
|
|||||||
# chances there are to get other rewards.
|
# chances there are to get other rewards.
|
||||||
fixed_seen = dict(A=set(), B=set(), Sub=set())
|
fixed_seen = dict(A=set(), B=set(), Sub=set())
|
||||||
dups = dict()
|
dups = dict()
|
||||||
for i in xrange(len(rewards)):
|
for i in range(len(rewards)):
|
||||||
reward = rewards[i]
|
reward = rewards[i]
|
||||||
slot = reward["reward_slot"]
|
slot = reward["reward_slot"]
|
||||||
if reward["percentage"] == 100:
|
if reward["percentage"] == 100:
|
||||||
@@ -251,7 +251,7 @@ class QuestItemExpectedValue(object):
|
|||||||
|
|
||||||
self.slot_rewards[reward.slot].append(reward)
|
self.slot_rewards[reward.slot].append(reward)
|
||||||
evs = reward.expected_values()
|
evs = reward.expected_values()
|
||||||
for i in xrange(len(evs)):
|
for i in range(len(evs)):
|
||||||
self.total_expected_values[i] += evs[i]
|
self.total_expected_values[i] += evs[i]
|
||||||
|
|
||||||
def print(self, out, indent=2):
|
def print(self, out, indent=2):
|
||||||
@@ -320,10 +320,10 @@ class HuntReward(object):
|
|||||||
shiny=self.shiny)
|
shiny=self.shiny)
|
||||||
kill_ev = dict()
|
kill_ev = dict()
|
||||||
cap_ev = dict()
|
cap_ev = dict()
|
||||||
for skill in xrange(CarvingSkill.NONE, CarvingSkill.GOD+1):
|
for skill in range(CarvingSkill.NONE, CarvingSkill.GOD+1):
|
||||||
kill_ev[CarvingSkill.name(skill)] = \
|
kill_ev[CarvingSkill.name(skill)] = \
|
||||||
self.expected_value(STRAT_CAP, carving_skill=skill)
|
self.expected_value(STRAT_CAP, carving_skill=skill)
|
||||||
for skill in xrange(CapSkill.NONE, CapSkill.GOD+1):
|
for skill in range(CapSkill.NONE, CapSkill.GOD+1):
|
||||||
cap_ev[CapSkill.name(skill)] = self.expected_value(STRAT_CAP,
|
cap_ev[CapSkill.name(skill)] = self.expected_value(STRAT_CAP,
|
||||||
cap_skill=skill)
|
cap_skill=skill)
|
||||||
|
|
||||||
@@ -357,7 +357,7 @@ class HuntReward(object):
|
|||||||
self.kill = False
|
self.kill = False
|
||||||
counts = [
|
counts = [
|
||||||
stats.capture_reward_expected_c(skill)
|
stats.capture_reward_expected_c(skill)
|
||||||
for skill in xrange(CapSkill.NONE,
|
for skill in range(CapSkill.NONE,
|
||||||
CapSkill.GOD+1)
|
CapSkill.GOD+1)
|
||||||
]
|
]
|
||||||
elif self.condition == "Virus Reward":
|
elif self.condition == "Virus Reward":
|
||||||
@@ -393,7 +393,7 @@ class HuntReward(object):
|
|||||||
if self.skill == SKILL_CARVING:
|
if self.skill == SKILL_CARVING:
|
||||||
counts = [
|
counts = [
|
||||||
self.stack_size + stats.carve_delta_expected_c(skill)
|
self.stack_size + stats.carve_delta_expected_c(skill)
|
||||||
for skill in xrange(CarvingSkill.NONE,
|
for skill in range(CarvingSkill.NONE,
|
||||||
CarvingSkill.GOD+1)
|
CarvingSkill.GOD+1)
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -624,7 +624,7 @@ class HuntItemExpectedValue(object):
|
|||||||
carving_skill=carving_skill)
|
carving_skill=carving_skill)
|
||||||
return ev
|
return ev
|
||||||
|
|
||||||
def __nonzero__(self):
|
def __bool__(self):
|
||||||
return bool(len(self.matching_rewards))
|
return bool(len(self.matching_rewards))
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
@@ -640,10 +640,10 @@ class HuntItemExpectedValue(object):
|
|||||||
rewards=[r.as_data() for r in self.matching_rewards])
|
rewards=[r.as_data() for r in self.matching_rewards])
|
||||||
kill_ev = dict()
|
kill_ev = dict()
|
||||||
cap_ev = dict()
|
cap_ev = dict()
|
||||||
for skill in xrange(CarvingSkill.NONE, CarvingSkill.GOD+1):
|
for skill in range(CarvingSkill.NONE, CarvingSkill.GOD+1):
|
||||||
kill_ev[CarvingSkill.name(skill)] = \
|
kill_ev[CarvingSkill.name(skill)] = \
|
||||||
self.expected_value(STRAT_CAP, carving_skill=skill)
|
self.expected_value(STRAT_CAP, carving_skill=skill)
|
||||||
for skill in xrange(CapSkill.NONE, CapSkill.GOD+1):
|
for skill in range(CapSkill.NONE, CapSkill.GOD+1):
|
||||||
cap_ev[CapSkill.name(skill)] = self.expected_value(STRAT_CAP,
|
cap_ev[CapSkill.name(skill)] = self.expected_value(STRAT_CAP,
|
||||||
cap_skill=skill)
|
cap_skill=skill)
|
||||||
|
|
||||||
@@ -737,8 +737,8 @@ class ItemRewards(object):
|
|||||||
key = (mid, rank)
|
key = (mid, rank)
|
||||||
self._hunt_items[key] = hunt_item
|
self._hunt_items[key] = hunt_item
|
||||||
|
|
||||||
for rank, skill_sets in self.rank_skill_sets.iteritems():
|
for rank, skill_sets in self.rank_skill_sets.items():
|
||||||
for s in skill_sets.itervalues():
|
for s in skill_sets.values():
|
||||||
s.add_hunt_option(hunt_item)
|
s.add_hunt_option(hunt_item)
|
||||||
|
|
||||||
def get_hunt_item(self, monster_id, monster_rank):
|
def get_hunt_item(self, monster_id, monster_rank):
|
||||||
@@ -777,15 +777,15 @@ class ItemRewards(object):
|
|||||||
gather_key = (quest_item.quest.location_id, quest_item.quest.rank)
|
gather_key = (quest_item.quest.location_id, quest_item.quest.rank)
|
||||||
gather_location = self._gather_items.get(gather_key)
|
gather_location = self._gather_items.get(gather_key)
|
||||||
|
|
||||||
for rank, skill_sets in self.rank_skill_sets.iteritems():
|
for rank, skill_sets in self.rank_skill_sets.items():
|
||||||
for s in skill_sets.itervalues():
|
for s in skill_sets.values():
|
||||||
s.add_quest_option(quest_item, hunt_items, gather_location)
|
s.add_quest_option(quest_item, hunt_items, gather_location)
|
||||||
|
|
||||||
def print_gather_locations(self, out):
|
def print_gather_locations(self, out):
|
||||||
if not self._gather_items:
|
if not self._gather_items:
|
||||||
return
|
return
|
||||||
|
|
||||||
for gl in self._gather_items.itervalues():
|
for gl in self._gather_items.values():
|
||||||
out.write("(GATHER) %s %s\n"
|
out.write("(GATHER) %s %s\n"
|
||||||
% (gl.location_name, gl.rank))
|
% (gl.location_name, gl.rank))
|
||||||
gl.print(out, indent=2)
|
gl.print(out, indent=2)
|
||||||
@@ -798,7 +798,7 @@ class ItemRewards(object):
|
|||||||
if not self._hunt_items:
|
if not self._hunt_items:
|
||||||
return
|
return
|
||||||
|
|
||||||
for hunt_item in self._hunt_items.itervalues():
|
for hunt_item in self._hunt_items.values():
|
||||||
out.write("(HUNT) %s %s\n"
|
out.write("(HUNT) %s %s\n"
|
||||||
% (hunt_item.monster_name, hunt_item.monster_rank))
|
% (hunt_item.monster_name, hunt_item.monster_rank))
|
||||||
hunt_item.print(out, indent=2)
|
hunt_item.print(out, indent=2)
|
||||||
@@ -826,13 +826,13 @@ class ItemRewards(object):
|
|||||||
|
|
||||||
def print_recommended_hunts(self, out):
|
def print_recommended_hunts(self, out):
|
||||||
out.write("*** Poogie Recommends ***\n")
|
out.write("*** Poogie Recommends ***\n")
|
||||||
for rank, skill_sets in self.rank_skill_sets.iteritems():
|
for rank, skill_sets in self.rank_skill_sets.items():
|
||||||
no_skill_best = skill_sets["No skills"].best
|
no_skill_best = skill_sets["No skills"].best
|
||||||
if no_skill_best is None:
|
if no_skill_best is None:
|
||||||
# not available at this rank
|
# not available at this rank
|
||||||
continue
|
continue
|
||||||
out.write("> " + rank + "\n")
|
out.write("> " + rank + "\n")
|
||||||
for name, skill_set in skill_sets.iteritems():
|
for name, skill_set in skill_sets.items():
|
||||||
if skill_set.best is None:
|
if skill_set.best is None:
|
||||||
# Don't print out a rank with no options
|
# Don't print out a rank with no options
|
||||||
continue
|
continue
|
||||||
@@ -850,8 +850,8 @@ class ItemRewards(object):
|
|||||||
Get a list of the quests for acquiring a given item and the probability
|
Get a list of the quests for acquiring a given item and the probability
|
||||||
of getting the item, depending on cap or kill and luck skills.
|
of getting the item, depending on cap or kill and luck skills.
|
||||||
"""
|
"""
|
||||||
for quest_item in self._quest_items.itervalues():
|
for quest_item in self._quest_items.values():
|
||||||
out.write("(QUEST) " + unicode(quest_item.quest) + "\n")
|
out.write("(QUEST) " + str(quest_item.quest) + "\n")
|
||||||
out.write(" %20s" % "= Quest\n")
|
out.write(" %20s" % "= Quest\n")
|
||||||
|
|
||||||
quest_item.print(out, indent=2)
|
quest_item.print(out, indent=2)
|
||||||
@@ -921,7 +921,7 @@ class ItemRewards(object):
|
|||||||
item_name = self.item_row["name"]
|
item_name = self.item_row["name"]
|
||||||
out.write("*** Wyporium trade for '%s'\n" % item_name)
|
out.write("*** Wyporium trade for '%s'\n" % item_name)
|
||||||
out.write(" Unlocked by quest '%s'\n"
|
out.write(" Unlocked by quest '%s'\n"
|
||||||
% unicode(self.trade_unlock_quest).split("\n")[0])
|
% str(self.trade_unlock_quest).split("\n")[0])
|
||||||
out.write("\n")
|
out.write("\n")
|
||||||
|
|
||||||
self.print_recommended_hunts(out)
|
self.print_recommended_hunts(out)
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ def _reward_count_p(reward_count, min_rewards, max_rewards, extend_percent):
|
|||||||
p = 1.0
|
p = 1.0
|
||||||
extend_p = extend_percent / 100.0
|
extend_p = extend_percent / 100.0
|
||||||
stop_p = 1.0 - extend_p
|
stop_p = 1.0 - extend_p
|
||||||
for i in xrange(min_rewards+1, reward_count+1):
|
for i in range(min_rewards+1, reward_count+1):
|
||||||
p *= extend_p
|
p *= extend_p
|
||||||
if reward_count < max_rewards:
|
if reward_count < max_rewards:
|
||||||
p *= stop_p
|
p *= stop_p
|
||||||
@@ -56,7 +56,7 @@ def quest_reward_p(reward_percent, min_rewards, max_rewards, extend_percent=69):
|
|||||||
extra attempt.
|
extra attempt.
|
||||||
"""
|
"""
|
||||||
p = 0.0
|
p = 0.0
|
||||||
for reward_count in xrange(min_rewards, max_rewards + 1):
|
for reward_count in range(min_rewards, max_rewards + 1):
|
||||||
p += (_reward_count_p(reward_count, min_rewards, max_rewards,
|
p += (_reward_count_p(reward_count, min_rewards, max_rewards,
|
||||||
extend_percent)
|
extend_percent)
|
||||||
* _quest_reward_p(reward_percent, reward_count))
|
* _quest_reward_p(reward_percent, reward_count))
|
||||||
@@ -71,7 +71,7 @@ def reward_expected_c(min_rewards, max_rewards, extend_percent):
|
|||||||
"""
|
"""
|
||||||
total_p = 0.0
|
total_p = 0.0
|
||||||
expected_attempts = 0.0
|
expected_attempts = 0.0
|
||||||
for reward_count in xrange(min_rewards, max_rewards + 1):
|
for reward_count in range(min_rewards, max_rewards + 1):
|
||||||
p = _reward_count_p(reward_count, min_rewards, max_rewards,
|
p = _reward_count_p(reward_count, min_rewards, max_rewards,
|
||||||
extend_percent)
|
extend_percent)
|
||||||
expected_attempts += p * reward_count
|
expected_attempts += p * reward_count
|
||||||
|
|||||||
@@ -53,6 +53,18 @@ WTYPE_ABBR = dict(
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
DAMAGE_TYPES = """
|
||||||
|
cut
|
||||||
|
impact
|
||||||
|
shot
|
||||||
|
fire
|
||||||
|
water
|
||||||
|
thunder
|
||||||
|
ice
|
||||||
|
dragon
|
||||||
|
""".split()
|
||||||
|
|
||||||
|
|
||||||
class EnumBase(object):
|
class EnumBase(object):
|
||||||
_names = dict()
|
_names = dict()
|
||||||
|
|
||||||
|
|||||||
268
scrapers/fextralife-weapons.py
Executable file
268
scrapers/fextralife-weapons.py
Executable file
@@ -0,0 +1,268 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os.path
|
||||||
|
import sys
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
import lxml.etree
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
#WTYPES = ["Great Sword", "Long Sword", "Sword and Shield", "Dual Blades", "Lance", "Gunlance", "Hammer"]
|
||||||
|
WTYPES = ["Great Sword", "Lance", "Hammer"]
|
||||||
|
|
||||||
|
WIDTH_RE = re.compile(r'width: *(\d+)%;')
|
||||||
|
|
||||||
|
PART_RE = re.compile(r'(.*) x(\d+)( Points)?')
|
||||||
|
|
||||||
|
# MR Bone 20 pts.
|
||||||
|
PART_RE_MR = re.compile(r'(.*) (\d+) +pts\.?')
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
<div class="progress" style="max-width: 100%; min-width: 100px;">
|
||||||
|
<div class="progress-bar danger-color-dark" style="width: 11%;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="progress-bar warning-color-dark" style="width: 20%;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="progress-bar warning-color" style="width: 12%;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="progress-bar success-color" style="width: 0%;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="progress-bar primary-color-dark" style="width: 0%;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div class="progress-bar white" style="width: 0%;">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
def parse_sharpness(div):
|
||||||
|
values = []
|
||||||
|
divs = div.xpath('div')
|
||||||
|
for div in divs:
|
||||||
|
style = div.get("style")
|
||||||
|
m = WIDTH_RE.match(style)
|
||||||
|
if m:
|
||||||
|
values.append(int(m.group(1)))
|
||||||
|
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
|
def parse_rampage(td):
|
||||||
|
return td.xpath('ul/li/a/text()')
|
||||||
|
|
||||||
|
|
||||||
|
def parse_crafting(td):
|
||||||
|
materials = {}
|
||||||
|
for li in td.xpath('ul/li'):
|
||||||
|
atext = li.xpath('a/text()')
|
||||||
|
litext = li.xpath('text()')
|
||||||
|
if litext:
|
||||||
|
litext = litext[0].strip()
|
||||||
|
else:
|
||||||
|
print("Unknown format: ", lxml.etree.tostring(td))
|
||||||
|
return {}
|
||||||
|
|
||||||
|
if litext.endswith('\xa0'):
|
||||||
|
litext = litext.rstrip('\xa0')
|
||||||
|
if litext.endswith('.'):
|
||||||
|
litext = litext.rstrip('.')
|
||||||
|
|
||||||
|
if litext.endswith('l'):
|
||||||
|
litext = litext[:-1] + '1'
|
||||||
|
|
||||||
|
if litext.startswith('+ '):
|
||||||
|
atext += '+'
|
||||||
|
litext = litext[2:]
|
||||||
|
|
||||||
|
if litext.startswith('x'):
|
||||||
|
litext = litext[1:]
|
||||||
|
|
||||||
|
if atext:
|
||||||
|
atext = atext[0].strip()
|
||||||
|
if litext.endswith(" Points"):
|
||||||
|
litext = litext.rstrip(" Points")
|
||||||
|
atext += " Points"
|
||||||
|
#print("atext '" + atext + "' '" + litext + "'")
|
||||||
|
try:
|
||||||
|
materials[atext] = clean_int(litext)
|
||||||
|
except Exception as e:
|
||||||
|
print("WARN: failed parsing ", atext, litext)
|
||||||
|
if litext == 'l':
|
||||||
|
materials[atext] = 1
|
||||||
|
elif litext.isdigit():
|
||||||
|
materials['zenny'] = clean_int(litext)
|
||||||
|
else:
|
||||||
|
m = PART_RE.match(litext)
|
||||||
|
if not m:
|
||||||
|
m = PART_RE_MR.match(litext)
|
||||||
|
if m:
|
||||||
|
materials[m.group(1) + ' Points'] = int(m.group(2))
|
||||||
|
elif m.group(2):
|
||||||
|
materials[m.group(1) + ' Points'] = int(m.group(2))
|
||||||
|
else:
|
||||||
|
materials[m.group(1)] = int(m.group(2))
|
||||||
|
return materials
|
||||||
|
|
||||||
|
|
||||||
|
def clean_text(t):
|
||||||
|
t = t.strip()
|
||||||
|
t = t.rstrip('\xa0')
|
||||||
|
return t
|
||||||
|
|
||||||
|
|
||||||
|
def clean_int(s):
|
||||||
|
s = clean_text(s)
|
||||||
|
if not s:
|
||||||
|
return 0
|
||||||
|
return int(s)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_element(td):
|
||||||
|
#pp("td", td)
|
||||||
|
etype = td.xpath('a/text()')
|
||||||
|
if etype:
|
||||||
|
values = td.xpath('./text()')
|
||||||
|
if values:
|
||||||
|
value = clean_int(values[0].strip())
|
||||||
|
return dict(type=etype[0], attack=value)
|
||||||
|
return dict(type=None, attack=None)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_rarity(td):
|
||||||
|
text = td.xpath('.//text()')
|
||||||
|
if text:
|
||||||
|
parts = text[0].split()
|
||||||
|
if len(parts) > 1:
|
||||||
|
return clean_int(text[0].split()[1])
|
||||||
|
return 8
|
||||||
|
|
||||||
|
|
||||||
|
def parse_slots(td):
|
||||||
|
slots = []
|
||||||
|
for img in td.xpath('.//img'):
|
||||||
|
title = img.get("title")
|
||||||
|
if title and title.startswith('gem_'):
|
||||||
|
parts = title.split("_")
|
||||||
|
level = int(parts[2])
|
||||||
|
slots.append(level)
|
||||||
|
return slots
|
||||||
|
|
||||||
|
|
||||||
|
def adjust_slots_rampage(data):
|
||||||
|
if data['rarity'] >= 8:
|
||||||
|
data['rampage_slot'] = data['slots'][-1]
|
||||||
|
data['slots'] = data['slots'][:-1]
|
||||||
|
else:
|
||||||
|
data['rampage_slot'] = 0
|
||||||
|
|
||||||
|
|
||||||
|
def gl_parse_tr(tr):
|
||||||
|
data = {}
|
||||||
|
cells = tr.xpath('td')
|
||||||
|
#print(lxml.etree.tostring(cells[9]))
|
||||||
|
|
||||||
|
# Name
|
||||||
|
name = cells[0]
|
||||||
|
#print(name)
|
||||||
|
data['name'] = name.xpath('a/text()')[0]
|
||||||
|
data['slots'] = parse_slots(name)
|
||||||
|
data['sharpness'] = parse_sharpness(name.xpath('div')[0])
|
||||||
|
data['attack'] = clean_int(cells[1].text)
|
||||||
|
element = parse_element(cells[2])
|
||||||
|
data['element'] = element['type']
|
||||||
|
data['element_attack'] = element['attack']
|
||||||
|
data['element_2'] = None
|
||||||
|
data['element_2_attack'] = None
|
||||||
|
data['affinity'] = clean_int(cells[3].text.rstrip('%'))
|
||||||
|
data['defense'] = clean_int(cells[4].text)
|
||||||
|
data['shot_type'] = cells[5].text
|
||||||
|
data['level'] = clean_int(cells[6].text.split()[1])
|
||||||
|
data['rarity'] = parse_rarity(cells[7])
|
||||||
|
data['rampage_skills'] = parse_rampage(cells[8])
|
||||||
|
data['crafting'] = parse_crafting(cells[9])
|
||||||
|
|
||||||
|
adjust_slots_rampage(data)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def default_parse_tr(tr):
|
||||||
|
data = {}
|
||||||
|
cells = tr.xpath('td')
|
||||||
|
#print(lxml.etree.tostring(cells[9]))
|
||||||
|
|
||||||
|
if len(cells) == 10:
|
||||||
|
return gl_parse_tr(tr)
|
||||||
|
|
||||||
|
#print("cels", [c.text for c in cells])
|
||||||
|
|
||||||
|
# Name
|
||||||
|
name = cells[0]
|
||||||
|
data['name'] = name.xpath('a/text()')[0]
|
||||||
|
data['slots'] = parse_slots(name)
|
||||||
|
data['sharpness'] = parse_sharpness(name.xpath('div')[0])
|
||||||
|
data['attack'] = clean_int(cells[1].text)
|
||||||
|
element = parse_element(cells[2])
|
||||||
|
data['element'] = element['type']
|
||||||
|
data['element_attack'] = element['attack']
|
||||||
|
data['element_2'] = None
|
||||||
|
data['element_2_attack'] = None
|
||||||
|
data['affinity'] = clean_int(cells[3].text.rstrip('%'))
|
||||||
|
data['defense'] = clean_int(cells[4].text)
|
||||||
|
data['rarity'] = parse_rarity(cells[5])
|
||||||
|
data['rampage_skills'] = parse_rampage(cells[6])
|
||||||
|
data['crafting'] = parse_crafting(cells[7])
|
||||||
|
|
||||||
|
adjust_slots_rampage(data)
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def parse_fextralife_weapons(text):
|
||||||
|
root = lxml.etree.HTML(text)
|
||||||
|
weapons = []
|
||||||
|
|
||||||
|
table = root.xpath('//div[@id="wiki-content-block"]//table')[0]
|
||||||
|
rows = table.xpath('tbody/tr')
|
||||||
|
#print("nrows", len(rows))
|
||||||
|
for tr in rows:
|
||||||
|
data = default_parse_tr(tr)
|
||||||
|
weapons.append(data)
|
||||||
|
return weapons
|
||||||
|
|
||||||
|
|
||||||
|
def pp(name, e):
|
||||||
|
if isinstance(e, list):
|
||||||
|
for i, ei in enumerate(e):
|
||||||
|
pp(name + "[" + str(i) + "]", ei)
|
||||||
|
else:
|
||||||
|
print(name, e.tag)
|
||||||
|
print(lxml.etree.tostring(e, pretty_print=True))
|
||||||
|
|
||||||
|
|
||||||
|
def _main():
|
||||||
|
indir = sys.argv[1]
|
||||||
|
outpath = sys.argv[2]
|
||||||
|
weapon_list_all = []
|
||||||
|
for wtype in WTYPES:
|
||||||
|
print(wtype)
|
||||||
|
fpath = os.path.join(indir, wtype + ".html")
|
||||||
|
with open(fpath) as f:
|
||||||
|
text = f.read()
|
||||||
|
weapon_list = parse_fextralife_weapons(text)
|
||||||
|
for w in weapon_list:
|
||||||
|
w["wtype"] = wtype
|
||||||
|
weapon_list_all.extend(weapon_list)
|
||||||
|
with open(outpath, "w") as f:
|
||||||
|
json.dump(weapon_list_all, f, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
_main()
|
||||||
159
scrapers/mhrice_monsters.py
Executable file
159
scrapers/mhrice_monsters.py
Executable file
@@ -0,0 +1,159 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os.path
|
||||||
|
import time
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
import lxml.etree
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
PART_HEADER_MAP = dict(Slash="Cut",
|
||||||
|
Impact="Impact",
|
||||||
|
Shot="Shot",
|
||||||
|
Fire="Fire",
|
||||||
|
Water="Water",
|
||||||
|
Ice="Ice",
|
||||||
|
Thunder="Thunder",
|
||||||
|
Dragon="Dragon")
|
||||||
|
|
||||||
|
|
||||||
|
def _td_part_id(td):
|
||||||
|
s = td.xpath('.//text()')[0].strip()
|
||||||
|
if s.startswith("["):
|
||||||
|
s = s[1:2]
|
||||||
|
return int(s)
|
||||||
|
|
||||||
|
|
||||||
|
def _td_part_break(td):
|
||||||
|
text = td.text or ""
|
||||||
|
text = text.strip()
|
||||||
|
if text:
|
||||||
|
m = re.match(r"\(x(\d+)\) (\d+)", text)
|
||||||
|
print(text, m, m.group(1), m.group(2))
|
||||||
|
return dict(count=int(m.group(1)), damage=int(m.group(2)))
|
||||||
|
return dict(count=0, damage=0)
|
||||||
|
|
||||||
|
def _td_part_sever(td):
|
||||||
|
text = td.text or ""
|
||||||
|
text = text.strip()
|
||||||
|
if text:
|
||||||
|
m = re.match(r"\((\w+)\) (\d+)", text)
|
||||||
|
return dict(type=m.group(1), damage=int(m.group(2)))
|
||||||
|
return dict(type="", damage=0)
|
||||||
|
|
||||||
|
|
||||||
|
def get_monster_data(link):
|
||||||
|
hit_data = {}
|
||||||
|
base = "https://mhrise.mhrice.info"
|
||||||
|
url = base + link
|
||||||
|
result = requests.get(url)
|
||||||
|
root = lxml.etree.HTML(result.content)
|
||||||
|
sections = root.xpath("//section")
|
||||||
|
hit_table = None
|
||||||
|
parts_table = None
|
||||||
|
for section in sections:
|
||||||
|
h2 = section.xpath('h2')
|
||||||
|
if h2 and h2[0].text:
|
||||||
|
if hit_table is None and h2[0].text.lower().startswith("hitzone"):
|
||||||
|
hit_table = section.xpath('.//table')[0]
|
||||||
|
elif parts_table is None and h2[0].text.lower().startswith("parts"):
|
||||||
|
parts_table = section.xpath('.//table')[0]
|
||||||
|
#pp("hit_table", hit_table)
|
||||||
|
#pp("tr", hit_table.xpath('thead/tr'))
|
||||||
|
header_cells = hit_table.xpath('thead/tr/th')
|
||||||
|
header_names = [th.text for th in header_cells]
|
||||||
|
#print("names", header_names)
|
||||||
|
rows = hit_table.xpath('tbody/tr')
|
||||||
|
part_id_name_map = {}
|
||||||
|
for row in rows:
|
||||||
|
if 'invalid' in row.attrib.get('class', ""):
|
||||||
|
continue
|
||||||
|
#pp("tr", row)
|
||||||
|
cols = dict(zip(header_names, row.xpath('td')))
|
||||||
|
name_td = cols["Name"]
|
||||||
|
#pp("name_td", name_td)
|
||||||
|
name_en_span = name_td.xpath('.//span[@lang="en"]/span')
|
||||||
|
if not name_en_span:
|
||||||
|
continue
|
||||||
|
name = name_en_span[0].text
|
||||||
|
#pp("part", cols["Part"].xpath('.//text()'))
|
||||||
|
part_id = _td_part_id(cols["Part"])
|
||||||
|
part_id_name_map[part_id] = name
|
||||||
|
hit_data[name] = {}
|
||||||
|
for k in PART_HEADER_MAP.keys():
|
||||||
|
hit_data[name][PART_HEADER_MAP[k]] = int(cols[k].text)
|
||||||
|
#print(hit_data)
|
||||||
|
|
||||||
|
return hit_data
|
||||||
|
|
||||||
|
# add break/sever data
|
||||||
|
header_cells = parts_table.xpath('thead/tr/th')
|
||||||
|
header_names = [th.text for th in header_cells]
|
||||||
|
#print(header_names)
|
||||||
|
rows = parts_table.xpath('tbody/tr')
|
||||||
|
breaks = []
|
||||||
|
for row in rows:
|
||||||
|
if 'invalid' in row.attrib.get('class', ""):
|
||||||
|
continue
|
||||||
|
cols = dict(zip(header_names, row.xpath('td')))
|
||||||
|
part_id = _td_part_id(cols["Part"])
|
||||||
|
part_name = part_id_name_map[part_id]
|
||||||
|
hit_data[part_name]["_stagger"] = int(cols["Stagger"].text)
|
||||||
|
part_break = cols["Break"].text or ""
|
||||||
|
part_sever = cols["Sever"].text or ""
|
||||||
|
part_break = part_break.strip()
|
||||||
|
part_sever = part_sever.strip()
|
||||||
|
hit_data[part_name]["_break"] = _td_part_break(cols["Break"])
|
||||||
|
hit_data[part_name]["_sever"] = _td_part_sever(cols["Sever"])
|
||||||
|
if part_break or part_sever:
|
||||||
|
breaks.append(part_name)
|
||||||
|
|
||||||
|
hit_data["_breaks"] = breaks
|
||||||
|
return hit_data
|
||||||
|
|
||||||
|
|
||||||
|
def pp(name, e):
|
||||||
|
if isinstance(e, list):
|
||||||
|
for i, ei in enumerate(e):
|
||||||
|
pp(name + "[" + str(i) + "]", ei)
|
||||||
|
else:
|
||||||
|
print(name, e.tag)
|
||||||
|
print(lxml.etree.tostring(e, pretty_print=True))
|
||||||
|
|
||||||
|
|
||||||
|
def get_monster_list():
|
||||||
|
result = requests.get("https://mhrise.mhrice.info/monster.html")
|
||||||
|
root = lxml.etree.HTML(result.content)
|
||||||
|
monster_li = root.xpath('//ul[@id="slist-monster"]//li')
|
||||||
|
monsters = []
|
||||||
|
for li in monster_li:
|
||||||
|
name = li.xpath('.//span[@lang="en"]/span')[0].text
|
||||||
|
link = li.xpath('a')[0].attrib['href']
|
||||||
|
monsters.append(dict(name=name, link=link))
|
||||||
|
return monsters
|
||||||
|
|
||||||
|
|
||||||
|
def _main():
|
||||||
|
outdir = sys.argv[1]
|
||||||
|
monster_list = get_monster_list()
|
||||||
|
with open(os.path.join(outdir, "monster_list.json"), "w") as f:
|
||||||
|
json.dump(monster_list, f, indent=2)
|
||||||
|
|
||||||
|
monster_hitboxes = {}
|
||||||
|
for m in monster_list:
|
||||||
|
print(m["name"])
|
||||||
|
try:
|
||||||
|
monster_hitboxes[m["name"]] = get_monster_data(m["link"])
|
||||||
|
except Exception as e:
|
||||||
|
print("ERR: failed to parse hitzones for ", m["name"])
|
||||||
|
print(repr(e), str(e))
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
with open(os.path.join(outdir, "monster_hitboxes.json"), "w") as f:
|
||||||
|
json.dump(monster_hitboxes, f, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
_main()
|
||||||
352
scrapers/mhrice_weapons.py
Executable file
352
scrapers/mhrice_weapons.py
Executable file
@@ -0,0 +1,352 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import sys
|
||||||
|
import os.path
|
||||||
|
import time
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
from pprint import pprint
|
||||||
|
from collections import defaultdict
|
||||||
|
import lxml.etree
|
||||||
|
|
||||||
|
import requests
|
||||||
|
|
||||||
|
import _pathfix
|
||||||
|
|
||||||
|
from mhapi.util import WEAPON_TYPES
|
||||||
|
|
||||||
|
MAX_PER_TYPE = 100000
|
||||||
|
|
||||||
|
def pp(name, e):
|
||||||
|
if isinstance(e, list):
|
||||||
|
for i, ei in enumerate(e):
|
||||||
|
pp(name + "[" + str(i) + "]", ei)
|
||||||
|
else:
|
||||||
|
print(name, e.tag)
|
||||||
|
print(lxml.etree.tostring(e, pretty_print=True))
|
||||||
|
|
||||||
|
|
||||||
|
def parse_sharpness(value_span):
|
||||||
|
bar_span = value_span.xpath('.//span[@class="mh-sharpness-bar"]')[0]
|
||||||
|
sharp_spans = bar_span.xpath('.//span')
|
||||||
|
i = 0
|
||||||
|
last_color_num = -1
|
||||||
|
values = []
|
||||||
|
values_plus = []
|
||||||
|
for sharp_span in sharp_spans:
|
||||||
|
# <span class="mh-sharpness mh-sharpness-color-0" style="left:0%;width:47.5%;"></span>
|
||||||
|
attr_style = sharp_span.attrib["style"]
|
||||||
|
attr_class = sharp_span.attrib["class"]
|
||||||
|
classes = attr_class.split()
|
||||||
|
half = False
|
||||||
|
for class_name in classes:
|
||||||
|
if class_name.startswith("mh-sharpness-color-"):
|
||||||
|
color_num = int(class_name[-1])
|
||||||
|
if class_name == "mh-sharpness-half":
|
||||||
|
half = True
|
||||||
|
styles = attr_style.split(";")
|
||||||
|
for s in styles:
|
||||||
|
s = s.strip()
|
||||||
|
if not s:
|
||||||
|
continue
|
||||||
|
parts = s.split(":")
|
||||||
|
if parts[0] == "width":
|
||||||
|
value = int(2*float(parts[1].rstrip("%")))
|
||||||
|
break
|
||||||
|
if value == 0:
|
||||||
|
continue
|
||||||
|
if half:
|
||||||
|
if not values_plus:
|
||||||
|
values_plus = list(values)
|
||||||
|
if color_num == last_color_num:
|
||||||
|
values_plus[-1] += value
|
||||||
|
else:
|
||||||
|
values_plus.append(value)
|
||||||
|
else:
|
||||||
|
# fill in missing colors, if any
|
||||||
|
while i < color_num:
|
||||||
|
values.append(0)
|
||||||
|
i += 1
|
||||||
|
values.append(value)
|
||||||
|
i += 1
|
||||||
|
last_color_num = color_num
|
||||||
|
return values, values_plus
|
||||||
|
|
||||||
|
|
||||||
|
def _map_element(e):
|
||||||
|
if e == "Bomb":
|
||||||
|
return "Blast"
|
||||||
|
if e == "Paralyze":
|
||||||
|
return "Paralysis"
|
||||||
|
return e
|
||||||
|
|
||||||
|
|
||||||
|
def get_weapon_details(wtype, name, link):
|
||||||
|
data = dict(wtype=wtype, name=name)
|
||||||
|
url = "https://mhrise.mhrice.info" + link
|
||||||
|
result = requests.get(url)
|
||||||
|
root = lxml.etree.HTML(result.content)
|
||||||
|
|
||||||
|
icon_div = root.xpath('//div[@class="mh-title-icon"]/div[@class="mh-colored-icon"]/div')[0]
|
||||||
|
rarity_class = icon_div.attrib["class"]
|
||||||
|
data["rarity"] = int(rarity_class.split("-")[-1])
|
||||||
|
|
||||||
|
stat_div = root.xpath('//div[@class="mh-kvlist"]')[0]
|
||||||
|
kvlist = stat_div.xpath('.//p[@class="mh-kv"]')
|
||||||
|
for kv in kvlist:
|
||||||
|
spans = kv.xpath('span')
|
||||||
|
key = spans[0].text.strip().lower()
|
||||||
|
if key in set(["attack", "affinity", "defense"]):
|
||||||
|
value = spans[1].text
|
||||||
|
value = value.rstrip("%")
|
||||||
|
data[key.lower()] = int(value)
|
||||||
|
elif key == "element":
|
||||||
|
value_spans = spans[1].xpath("span")
|
||||||
|
value = value_spans[0].text.strip()
|
||||||
|
if value:
|
||||||
|
parts = value.split()
|
||||||
|
if parts[0] == "None":
|
||||||
|
data["element"] = None
|
||||||
|
data["element_attack"] = None
|
||||||
|
else:
|
||||||
|
data["element"] = _map_element(parts[0])
|
||||||
|
data["element_attack"] = int(parts[1])
|
||||||
|
if len(value_spans) > 1:
|
||||||
|
value = value_spans[1].text.strip()
|
||||||
|
parts = value.split()
|
||||||
|
data["element_2"] = _map_element(parts[0])
|
||||||
|
data["element_2_attack"] = int(parts[1])
|
||||||
|
else:
|
||||||
|
data["element_2"] = None
|
||||||
|
data["element_2_attack"] = None
|
||||||
|
elif key == "slot":
|
||||||
|
# <img alt="A level-2 slot" class="mh-slot" src="/resources/slot_1.png">
|
||||||
|
# <img alt="A level-4 slot" class="mh-slot-large" src="/resources/slot_3.png">
|
||||||
|
slots = []
|
||||||
|
value_span = spans[1]
|
||||||
|
slot_imgs = value_span.xpath('.//span[@class="mh-slot-outer"]/img')
|
||||||
|
for slot_img in slot_imgs:
|
||||||
|
src = slot_img.attrib["src"]
|
||||||
|
m = re.match(r".*/slot_(\d+)\.png", src)
|
||||||
|
if m:
|
||||||
|
svalue = int(m.group(1)) + 1
|
||||||
|
slots.append(svalue)
|
||||||
|
data["slots"] = slots
|
||||||
|
elif key == "rampage slot":
|
||||||
|
slots = []
|
||||||
|
value_span = spans[1]
|
||||||
|
slot_imgs = value_span.xpath('.//span[@class="mh-slot-outer"]/img')
|
||||||
|
for slot_img in slot_imgs:
|
||||||
|
src = slot_img.attrib["src"]
|
||||||
|
m = re.match(r".*/slot_(\d+).png", src)
|
||||||
|
if m:
|
||||||
|
svalue = int(m.group(1)) + 1
|
||||||
|
slots.append(svalue)
|
||||||
|
data["rampage_slots"] = slots
|
||||||
|
elif key == "sharpness":
|
||||||
|
value_span = spans[1]
|
||||||
|
sharp, sharp_plus = parse_sharpness(value_span)
|
||||||
|
data["sharpness"] = sharp
|
||||||
|
data["sharpness_plus"] = sharp_plus
|
||||||
|
elif key == "bottle":
|
||||||
|
value = spans[1].text.strip()
|
||||||
|
if wtype == "Charge Blade":
|
||||||
|
key = "phial"
|
||||||
|
if value == "Power":
|
||||||
|
value = "Impact"
|
||||||
|
if value == "StrongElement":
|
||||||
|
value = "Element"
|
||||||
|
if wtype == "Switch Axe":
|
||||||
|
key = "phial"
|
||||||
|
parts = value.split()
|
||||||
|
value = parts[0]
|
||||||
|
if value == "StrongElement":
|
||||||
|
value = "Element"
|
||||||
|
if value == "DownStamina":
|
||||||
|
value = "Exhaust"
|
||||||
|
phial_num = int(parts[1])
|
||||||
|
if phial_num > 0:
|
||||||
|
data["phial_value"] = phial_num
|
||||||
|
data[key] = value
|
||||||
|
elif key == "type":
|
||||||
|
value = spans[1].text.strip()
|
||||||
|
parts = value.split()
|
||||||
|
value = parts[0]
|
||||||
|
if len(parts) > 1:
|
||||||
|
level = int(parts[1])
|
||||||
|
data["shelling_level"] = level
|
||||||
|
if wtype == "Gunlance":
|
||||||
|
key = "shelling_type"
|
||||||
|
if value == "Radial":
|
||||||
|
value = "Long"
|
||||||
|
elif value == "Diffusion":
|
||||||
|
value = "Wide"
|
||||||
|
data[key] = value
|
||||||
|
elif key == "insect level":
|
||||||
|
value = spans[1].text.strip()
|
||||||
|
data["bug_level"] = int(value)
|
||||||
|
|
||||||
|
sections = root.xpath("//section")
|
||||||
|
craft_table = None
|
||||||
|
for section in sections:
|
||||||
|
h2 = section.xpath("h2/text()")
|
||||||
|
if h2 and h2[0] == "Crafting":
|
||||||
|
craft_table = section.xpath("div/table/tbody")[0]
|
||||||
|
break
|
||||||
|
if craft_table is not None:
|
||||||
|
rows = craft_table.xpath("tr")
|
||||||
|
for row in rows:
|
||||||
|
cells = row.findall("td")
|
||||||
|
craft_type = cells[0].text.strip()
|
||||||
|
if craft_type.startswith("Forge"):
|
||||||
|
zenny, comps = get_components(cells)
|
||||||
|
data["creation_cost"] = zenny
|
||||||
|
data["create_components"] = comps
|
||||||
|
elif craft_type.startswith("Upgrade"):
|
||||||
|
zenny, comps = get_components(cells)
|
||||||
|
data["upgrade_cost"] = zenny
|
||||||
|
data["upgrade_components"] = comps
|
||||||
|
|
||||||
|
return data
|
||||||
|
|
||||||
|
|
||||||
|
def get_components(cells):
|
||||||
|
zenny = int(cells[1].text)
|
||||||
|
cmat_text = cells[2].text
|
||||||
|
components = {}
|
||||||
|
if cmat_text != "-":
|
||||||
|
cmat_name = cells[2].xpath('.//span[@lang="en"]/span')[0].text
|
||||||
|
cmat_points_string = cells[2].xpath("span")[0].tail
|
||||||
|
cmat_points = int(cmat_points_string.split(" ")[0])
|
||||||
|
components[cmat_name] = cmat_points
|
||||||
|
li_mats = cells[3].xpath("ul/li")
|
||||||
|
for li in li_mats:
|
||||||
|
count = int(li.text.strip().rstrip("x"))
|
||||||
|
name = li.xpath('.//span[@lang="en"]/span')[0].text
|
||||||
|
components[name] = count
|
||||||
|
return (zenny, components)
|
||||||
|
|
||||||
|
|
||||||
|
def get_rice_id(link):
|
||||||
|
# /weapon/GreatSword_026.html
|
||||||
|
fname_base, _ = os.path.splitext(os.path.basename(link))
|
||||||
|
_, tail = fname_base.rsplit("_", maxsplit=1)
|
||||||
|
return int(tail)
|
||||||
|
|
||||||
|
|
||||||
|
def get_weapon_list(wtype, id_offset):
|
||||||
|
if wtype == "Sword and Shield":
|
||||||
|
ftype = "short_sword"
|
||||||
|
elif wtype == "Hunting Horn":
|
||||||
|
ftype = "horn"
|
||||||
|
elif wtype == "Gunlance":
|
||||||
|
ftype = "gun_lance"
|
||||||
|
elif wtype == "Switch Axe":
|
||||||
|
ftype = "slash_axe"
|
||||||
|
elif wtype == "Charge Blade":
|
||||||
|
ftype = "charge_axe"
|
||||||
|
else:
|
||||||
|
ftype = wtype.lower().replace(" ", "_")
|
||||||
|
list_fname = ftype + ".html"
|
||||||
|
result = requests.get("https://mhrise.mhrice.info/weapon/" + list_fname)
|
||||||
|
root = lxml.etree.HTML(result.content)
|
||||||
|
weapon_tree_li = root.xpath('//div[@class="mh-weapon-tree"]//li')
|
||||||
|
weapons = []
|
||||||
|
seen = set()
|
||||||
|
for li in weapon_tree_li:
|
||||||
|
listack = [li]
|
||||||
|
name_stack = [None]
|
||||||
|
while listack:
|
||||||
|
current_li = listack.pop()
|
||||||
|
parent_name = name_stack.pop()
|
||||||
|
|
||||||
|
a = current_li.xpath('a[@class="mh-icon-text"]')[0]
|
||||||
|
sublists = current_li.xpath('ul/li')
|
||||||
|
|
||||||
|
name = a.xpath('.//span[@lang="en"]/span')[0].text
|
||||||
|
link = a.attrib['href']
|
||||||
|
|
||||||
|
name_stack.extend([name] * len(sublists))
|
||||||
|
listack.extend(sublists)
|
||||||
|
|
||||||
|
if link in seen:
|
||||||
|
print("WARN: Duplicate ", name, link)
|
||||||
|
continue
|
||||||
|
seen.add(link)
|
||||||
|
|
||||||
|
id_ = get_rice_id(link) + id_offset
|
||||||
|
final = (len(sublists) == 0)
|
||||||
|
wdata = dict(name=name, link=link, _id=id_, parent_name=parent_name, final=final)
|
||||||
|
weapons.append(wdata)
|
||||||
|
|
||||||
|
return weapons
|
||||||
|
|
||||||
|
|
||||||
|
def test_details():
|
||||||
|
tests = [
|
||||||
|
("Great Sword", "Sinister Shadowblade+", "/weapon/GreatSword_403.html"),
|
||||||
|
("Great Sword", "Redwing Claymore I", "/weapon/GreatSword_068.html"),
|
||||||
|
("Great Sword", "Defender Great Sword I", "/weapon/GreatSword_132.html"),
|
||||||
|
("Great Sword", "Kamura Warrior Cleaver", "/weapon/GreatSword_300.html"),
|
||||||
|
("Dual Blades", "Blood Wind Skards+", "/weapon/DualBlades_319.html"),
|
||||||
|
("Switch Axe", "Arzuros Jubilax", "/weapon/SlashAxe_323.html"),
|
||||||
|
("Switch Axe", "Leave-Taker+", "/weapon/SlashAxe_307.html"),
|
||||||
|
("Insect Glaive", "Fine Kamura Glaive", "/weapon/InsectGlaive_302.html"),
|
||||||
|
]
|
||||||
|
for t in tests:
|
||||||
|
print(t)
|
||||||
|
d = get_weapon_details(*t)
|
||||||
|
pprint(d)
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def _main():
|
||||||
|
weapons_type_name_map = defaultdict(dict)
|
||||||
|
weapons_data = []
|
||||||
|
|
||||||
|
outdir = sys.argv[1]
|
||||||
|
outfile = os.path.join(outdir, "weapon_list.json")
|
||||||
|
if os.path.exists(outfile):
|
||||||
|
print("Loading existing data from ", outfile)
|
||||||
|
with open(outfile) as f:
|
||||||
|
old_data = json.load(f)
|
||||||
|
for d in old_data:
|
||||||
|
wtype_name_map = weapons_type_name_map[d["wtype"]]
|
||||||
|
if d["name"] in wtype_name_map:
|
||||||
|
print("Removing duplicate ", d["wtype"], d["name"])
|
||||||
|
continue
|
||||||
|
wtype_name_map[d["name"]] = d
|
||||||
|
|
||||||
|
for itype, wtype in enumerate(WEAPON_TYPES):
|
||||||
|
wtype_name_map = weapons_type_name_map[wtype]
|
||||||
|
weapons = get_weapon_list(wtype, (itype+1) * MAX_PER_TYPE)
|
||||||
|
if not weapons:
|
||||||
|
print("WARN: no weapons of type", wtype)
|
||||||
|
continue
|
||||||
|
name_id_map = {}
|
||||||
|
for w in weapons:
|
||||||
|
# always re-calculate IDs
|
||||||
|
name_id_map[w["name"]] = w["_id"]
|
||||||
|
if w["parent_name"]:
|
||||||
|
w["parent_id"] = name_id_map[w["parent_name"]]
|
||||||
|
else:
|
||||||
|
w["parent_id"] = None
|
||||||
|
data = wtype_name_map.get(w["name"])
|
||||||
|
if data is not None:
|
||||||
|
print("UP ", wtype, w["_id"], w["name"], w["link"])
|
||||||
|
data.update(w)
|
||||||
|
weapons_data.append(data)
|
||||||
|
continue
|
||||||
|
print("ADD", wtype, w["_id"], w["name"], w["link"])
|
||||||
|
data = get_weapon_details(wtype, w["name"], w["link"])
|
||||||
|
data.update(w)
|
||||||
|
weapons_data.append(data)
|
||||||
|
time.sleep(0.5)
|
||||||
|
|
||||||
|
with open(os.path.join(outdir, "weapon_list.json"), "w") as f:
|
||||||
|
json.dump(weapons_data, f, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
#test_details()
|
||||||
|
_main()
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python2
|
||||||
# vim: set fileencoding=utf8 :
|
# vim: set fileencoding=utf8 :
|
||||||
|
|
||||||
import urllib
|
import urllib.request, urllib.parse, urllib.error
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
@@ -34,74 +34,74 @@ _RANGED_TYPES = ["Bow", "Light Bowgun", "Heavy Bowgun"]
|
|||||||
|
|
||||||
|
|
||||||
_ELEMENT_MAP = {
|
_ELEMENT_MAP = {
|
||||||
u"火": "Fire",
|
"火": "Fire",
|
||||||
u"水": "Water",
|
"水": "Water",
|
||||||
u"雷": "Thunder",
|
"雷": "Thunder",
|
||||||
u"氷": "Ice",
|
"氷": "Ice",
|
||||||
u"龍": "Dragon",
|
"龍": "Dragon",
|
||||||
u"毒": "Poison",
|
"毒": "Poison",
|
||||||
u"麻痺": "Paralysis",
|
"麻痺": "Paralysis",
|
||||||
u"睡眠": "Sleep",
|
"睡眠": "Sleep",
|
||||||
u"爆破": "Blast",
|
"爆破": "Blast",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_GL_SHOT_TYPES = {
|
_GL_SHOT_TYPES = {
|
||||||
u"通常": "Normal",
|
"通常": "Normal",
|
||||||
u"放射": "Long",
|
"放射": "Long",
|
||||||
u"拡散": "Wide",
|
"拡散": "Wide",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_SA_PHIAL_TYPES = {
|
_SA_PHIAL_TYPES = {
|
||||||
u"強撃ビン": "Power",
|
"強撃ビン": "Power",
|
||||||
u"減気ビン": "Exhaust",
|
"減気ビン": "Exhaust",
|
||||||
u"滅龍ビン": "Dragon",
|
"滅龍ビン": "Dragon",
|
||||||
u"強属性ビン": "Element",
|
"強属性ビン": "Element",
|
||||||
u"毒ビン": "Poison",
|
"毒ビン": "Poison",
|
||||||
u"麻痺ビン": "Paralysis",
|
"麻痺ビン": "Paralysis",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_CB_PHIAL_TYPES = {
|
_CB_PHIAL_TYPES = {
|
||||||
u"榴弾ビン": "Impact",
|
"榴弾ビン": "Impact",
|
||||||
u"強属性ビン": "Element",
|
"強属性ビン": "Element",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_BUG_TYPES = {
|
_BUG_TYPES = {
|
||||||
u"切断": "Cutting",
|
"切断": "Cutting",
|
||||||
u"打撃": "Impact",
|
"打撃": "Impact",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_BOW_ARC_TYPES = {
|
_BOW_ARC_TYPES = {
|
||||||
u"集中型": "Focus",
|
"集中型": "Focus",
|
||||||
u"放散型": "Wide",
|
"放散型": "Wide",
|
||||||
u"爆裂型": "Blast",
|
"爆裂型": "Blast",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_BOW_SHOT_TYPES = {
|
_BOW_SHOT_TYPES = {
|
||||||
u"連射": "Rapid",
|
"連射": "Rapid",
|
||||||
u"拡散": "Spread",
|
"拡散": "Spread",
|
||||||
u"貫通": "Pierce",
|
"貫通": "Pierce",
|
||||||
u"重射": "Heavy",
|
"重射": "Heavy",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_BOW_COATINGS = {
|
_BOW_COATINGS = {
|
||||||
u"強1": "Power 1",
|
"強1": "Power 1",
|
||||||
u"強2": "Power 2",
|
"強2": "Power 2",
|
||||||
u"属1": "Element 1",
|
"属1": "Element 1",
|
||||||
u"属2": "Element 2",
|
"属2": "Element 2",
|
||||||
u"接": "C. Range",
|
"接": "C. Range",
|
||||||
u"ペ": "Paint",
|
"ペ": "Paint",
|
||||||
u"毒": "Poison",
|
"毒": "Poison",
|
||||||
u"麻": "Paralysis",
|
"麻": "Paralysis",
|
||||||
u"睡": "Sleep",
|
"睡": "Sleep",
|
||||||
u"減": "Exhaust",
|
"減": "Exhaust",
|
||||||
u"爆": "Blast",
|
"爆": "Blast",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -195,8 +195,8 @@ def _add_phial_or_shot_data(data, td_element):
|
|||||||
elif data["wtype"] == "Bow":
|
elif data["wtype"] == "Bow":
|
||||||
data["arc_type"] = _BOW_ARC_TYPES[text]
|
data["arc_type"] = _BOW_ARC_TYPES[text]
|
||||||
else:
|
else:
|
||||||
msg = u"Unexpected element for wtype '%s'" % data["wtype"]
|
msg = "Unexpected element for wtype '%s'" % data["wtype"]
|
||||||
print >>sys.stderr, msg, text
|
print(msg, text, file=sys.stderr)
|
||||||
raise ValueError(msg)
|
raise ValueError(msg)
|
||||||
|
|
||||||
|
|
||||||
@@ -223,7 +223,7 @@ def _get_detailed_sharpness(name, href, parser):
|
|||||||
weapon_level = 1
|
weapon_level = 1
|
||||||
tmp_path = os.path.join(_pathfix.project_path, "tmp")
|
tmp_path = os.path.join(_pathfix.project_path, "tmp")
|
||||||
fpath = os.path.join(tmp_path, "details-%s.html" % (base_name))
|
fpath = os.path.join(tmp_path, "details-%s.html" % (base_name))
|
||||||
urllib.urlretrieve(href, fpath)
|
urllib.request.urlretrieve(href, fpath)
|
||||||
with open(fpath) as f:
|
with open(fpath) as f:
|
||||||
tree = etree.parse(f, parser)
|
tree = etree.parse(f, parser)
|
||||||
data1 = tree.xpath('//*/div[@class="data1"]')
|
data1 = tree.xpath('//*/div[@class="data1"]')
|
||||||
@@ -252,7 +252,7 @@ def _get_detailed_sharpness(name, href, parser):
|
|||||||
heads = tr.xpath('./th')
|
heads = tr.xpath('./th')
|
||||||
if heads:
|
if heads:
|
||||||
for j, th in enumerate(heads):
|
for j, th in enumerate(heads):
|
||||||
if u"斬れ味" in th.text:
|
if "斬れ味" in th.text:
|
||||||
sharpness_col = j
|
sharpness_col = j
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -265,8 +265,8 @@ def _get_detailed_sharpness(name, href, parser):
|
|||||||
name = names[i]
|
name = names[i]
|
||||||
try:
|
try:
|
||||||
sharpness_levels = _parse_sharpness_td(sharpness_cell)
|
sharpness_levels = _parse_sharpness_td(sharpness_cell)
|
||||||
except KeyError, ValueError:
|
except KeyError as ValueError:
|
||||||
print >>sys.stderr, "bad sharpness:", href, name
|
print("bad sharpness:", href, name, file=sys.stderr)
|
||||||
raise
|
raise
|
||||||
SHARPNESS[name] = sharpness_levels
|
SHARPNESS[name] = sharpness_levels
|
||||||
#print name, sharpness_levels
|
#print name, sharpness_levels
|
||||||
@@ -322,11 +322,11 @@ def _parse_hh_attr_td(td_element):
|
|||||||
affinity = int(span.text.strip())
|
affinity = int(span.text.strip())
|
||||||
text_lines = td_element.text.strip().split("\n")
|
text_lines = td_element.text.strip().split("\n")
|
||||||
for line in text_lines:
|
for line in text_lines:
|
||||||
if line.startswith(u"防御+"):
|
if line.startswith("防御+"):
|
||||||
defense = int(line[3:])
|
defense = int(line[3:])
|
||||||
|
|
||||||
if td_element.tail:
|
if td_element.tail:
|
||||||
slots = td_element.tail.count(u"◯")
|
slots = td_element.tail.count("◯")
|
||||||
return attack, affinity, defense, elements, slots
|
return attack, affinity, defense, elements, slots
|
||||||
|
|
||||||
|
|
||||||
@@ -347,13 +347,13 @@ def _parse_elements_td(td_element):
|
|||||||
affinity = int(span.text.strip())
|
affinity = int(span.text.strip())
|
||||||
text_lines = td_element.text.strip().split("\n")
|
text_lines = td_element.text.strip().split("\n")
|
||||||
for line in text_lines:
|
for line in text_lines:
|
||||||
if line.startswith(u"防御+"):
|
if line.startswith("防御+"):
|
||||||
defense = int(line[3:])
|
defense = int(line[3:])
|
||||||
return affinity, defense, elements
|
return affinity, defense, elements
|
||||||
|
|
||||||
|
|
||||||
def _parse_element(text):
|
def _parse_element(text):
|
||||||
for jp_element in sorted(_ELEMENT_MAP.keys(), key=lambda s: len(s),
|
for jp_element in sorted(list(_ELEMENT_MAP.keys()), key=lambda s: len(s),
|
||||||
reverse=True):
|
reverse=True):
|
||||||
if text.startswith(jp_element):
|
if text.startswith(jp_element):
|
||||||
value = int(text[len(jp_element):])
|
value = int(text[len(jp_element):])
|
||||||
@@ -385,7 +385,7 @@ def _parse_name_td(td_element):
|
|||||||
def _parse_slots_td(td_element):
|
def _parse_slots_td(td_element):
|
||||||
text = td_element.text
|
text = td_element.text
|
||||||
if text:
|
if text:
|
||||||
return text.count(u"◯")
|
return text.count("◯")
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
||||||
@@ -406,9 +406,9 @@ def _parse_sharpness_td(td_element):
|
|||||||
if sub.text is None:
|
if sub.text is None:
|
||||||
continue
|
continue
|
||||||
current.append(sub.text.count("."))
|
current.append(sub.text.count("."))
|
||||||
for level in xrange(3):
|
for level in range(3):
|
||||||
sharpness = sharpness_levels[level]
|
sharpness = sharpness_levels[level]
|
||||||
for i in xrange(len(sharpness), 6):
|
for i in range(len(sharpness), 6):
|
||||||
sharpness.append(0)
|
sharpness.append(0)
|
||||||
return sharpness_levels
|
return sharpness_levels
|
||||||
|
|
||||||
@@ -422,27 +422,27 @@ def _main():
|
|||||||
raise
|
raise
|
||||||
weapon_list = []
|
weapon_list = []
|
||||||
parser = etree.HTMLParser()
|
parser = etree.HTMLParser()
|
||||||
for wtype, urls in _WEAPON_URLS.iteritems():
|
for wtype, urls in _WEAPON_URLS.items():
|
||||||
for i, url in enumerate(urls):
|
for i, url in enumerate(urls):
|
||||||
fpath = os.path.join(tmp_path, "%s-%d.html" % (wtype, i))
|
fpath = os.path.join(tmp_path, "%s-%d.html" % (wtype, i))
|
||||||
urllib.urlretrieve(_BASE_URL + url, fpath)
|
urllib.request.urlretrieve(_BASE_URL + url, fpath)
|
||||||
with open(fpath) as f:
|
with open(fpath) as f:
|
||||||
tree = etree.parse(f, parser)
|
tree = etree.parse(f, parser)
|
||||||
wlist = extract_weapon_list(wtype, tree, parser)
|
wlist = extract_weapon_list(wtype, tree, parser)
|
||||||
weapon_list.extend(wlist)
|
weapon_list.extend(wlist)
|
||||||
print json.dumps(weapon_list, indent=2)
|
print(json.dumps(weapon_list, indent=2))
|
||||||
|
|
||||||
|
|
||||||
def _test_details():
|
def _test_details():
|
||||||
parser = etree.HTMLParser()
|
parser = etree.HTMLParser()
|
||||||
# final level has same name
|
# final level has same name
|
||||||
_get_detailed_sharpness(u"ベルダーハンマー",
|
_get_detailed_sharpness("ベルダーハンマー",
|
||||||
"http://wiki.mhxg.org/ida/219225.html", parser)
|
"http://wiki.mhxg.org/ida/219225.html", parser)
|
||||||
# final level has different name
|
# final level has different name
|
||||||
_get_detailed_sharpness(u"テッケン",
|
_get_detailed_sharpness("テッケン",
|
||||||
"http://wiki.mhxg.org/ida/230575.html", parser)
|
"http://wiki.mhxg.org/ida/230575.html", parser)
|
||||||
# final level >= 10 (two chars)
|
# final level >= 10 (two chars)
|
||||||
_get_detailed_sharpness(u"ウィルガシェルプレス",
|
_get_detailed_sharpness("ウィルガシェルプレス",
|
||||||
"http://wiki.mhxg.org/ida/228545.html", parser)
|
"http://wiki.mhxg.org/ida/228545.html", parser)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python2
|
||||||
# vim: set fileencoding=utf8 :
|
# vim: set fileencoding=utf8 :
|
||||||
|
|
||||||
import urllib
|
import urllib.request, urllib.parse, urllib.error
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
@@ -17,7 +17,7 @@ _PAGES = {
|
|||||||
"items": "MHX:_Item_List",
|
"items": "MHX:_Item_List",
|
||||||
}
|
}
|
||||||
|
|
||||||
_CIRCLE = u"\u26ab"
|
_CIRCLE = "\u26ab"
|
||||||
|
|
||||||
|
|
||||||
def extract_names_and_icons(tree):
|
def extract_names_and_icons(tree):
|
||||||
@@ -90,11 +90,11 @@ def _translate_icon_name(s):
|
|||||||
def _main():
|
def _main():
|
||||||
tmp_path = os.path.join(_pathfix.project_path, "tmp")
|
tmp_path = os.path.join(_pathfix.project_path, "tmp")
|
||||||
outdir = os.path.join(_pathfix.project_path, "db", "mhx")
|
outdir = os.path.join(_pathfix.project_path, "db", "mhx")
|
||||||
for name, page in _PAGES.iteritems():
|
for name, page in _PAGES.items():
|
||||||
fpath = os.path.join(tmp_path, "wikia-%s.html" % name)
|
fpath = os.path.join(tmp_path, "wikia-%s.html" % name)
|
||||||
opath = os.path.join(outdir, name.replace("-", "_") + ".json")
|
opath = os.path.join(outdir, name.replace("-", "_") + ".json")
|
||||||
parser = etree.HTMLParser()
|
parser = etree.HTMLParser()
|
||||||
urllib.urlretrieve(_BASE_URL + page, fpath)
|
urllib.request.urlretrieve(_BASE_URL + page, fpath)
|
||||||
with open(fpath) as f:
|
with open(fpath) as f:
|
||||||
tree = etree.parse(f, parser)
|
tree = etree.parse(f, parser)
|
||||||
data = extract_names_and_icons(tree)
|
data = extract_names_and_icons(tree)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python2
|
#!/usr/bin/env python2
|
||||||
# vim: set fileencoding=utf8 :
|
# vim: set fileencoding=utf8 :
|
||||||
|
|
||||||
import urllib
|
import urllib.request, urllib.parse, urllib.error
|
||||||
import os
|
import os
|
||||||
import json
|
import json
|
||||||
import sys
|
import sys
|
||||||
@@ -14,7 +14,7 @@ _BASE_URL = "http://monsterhunter.wikia.com/wiki/"
|
|||||||
|
|
||||||
_PAGE = "MHX:_Palico_Skills"
|
_PAGE = "MHX:_Palico_Skills"
|
||||||
|
|
||||||
_CIRCLE = u"\u26ab"
|
_CIRCLE = "\u26ab"
|
||||||
|
|
||||||
|
|
||||||
def extract_arts_and_skills(tree):
|
def extract_arts_and_skills(tree):
|
||||||
@@ -29,7 +29,7 @@ def extract_arts_and_skills(tree):
|
|||||||
rows = list(table)
|
rows = list(table)
|
||||||
for row in rows:
|
for row in rows:
|
||||||
cols, is_header = _get_column_cells_texts(row)
|
cols, is_header = _get_column_cells_texts(row)
|
||||||
print is_header, cols
|
print(is_header, cols)
|
||||||
continue
|
continue
|
||||||
if is_header:
|
if is_header:
|
||||||
if len(cols) == 1:
|
if len(cols) == 1:
|
||||||
@@ -100,13 +100,13 @@ def _main():
|
|||||||
tmp_path = os.path.join(_pathfix.project_path, "tmp")
|
tmp_path = os.path.join(_pathfix.project_path, "tmp")
|
||||||
fpath = os.path.join(tmp_path, "wikia-palico-skills.html")
|
fpath = os.path.join(tmp_path, "wikia-palico-skills.html")
|
||||||
parser = etree.HTMLParser()
|
parser = etree.HTMLParser()
|
||||||
urllib.urlretrieve(_BASE_URL + _PAGE, fpath)
|
urllib.request.urlretrieve(_BASE_URL + _PAGE, fpath)
|
||||||
with open(fpath) as f:
|
with open(fpath) as f:
|
||||||
tree = etree.parse(f, parser)
|
tree = etree.parse(f, parser)
|
||||||
arts, skills = extract_arts_and_skills(tree)
|
arts, skills = extract_arts_and_skills(tree)
|
||||||
#print json.dumps(weapon_list, indent=2)
|
#print json.dumps(weapon_list, indent=2)
|
||||||
print json.dumps(arts, indent=2)
|
print(json.dumps(arts, indent=2))
|
||||||
print json.dumps(skills, indent=2)
|
print(json.dumps(skills, indent=2))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
36
templates/damage/base.html
Normal file
36
templates/damage/base.html
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
## -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Poogie's Calculator - ${self.title()}</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<!-- Include meta tag to ensure proper rendering and touch zooming -->
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<script src="/js/jquery.min.js"></script>
|
||||||
|
|
||||||
|
<!--link rel="stylesheet" href="/css/jquery-ui.min.css" /-->
|
||||||
|
<!--script src="/js/jquery-ui.min.js"></script-->
|
||||||
|
|
||||||
|
<script src="/js/common.js"></script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/css/poogie.css">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.icon { width: 20px; height: 20px; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<h1><%block name="title"/></h1>
|
||||||
|
${self.body()}
|
||||||
|
</body>
|
||||||
67
templates/damage/index.html
Normal file
67
templates/damage/index.html
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
<%inherit file="base.html" />
|
||||||
|
|
||||||
|
<div id="poogie-header">
|
||||||
|
<div class="poogie-header-content">
|
||||||
|
<div class="poogie-header-title">Menu</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="poogie-content">
|
||||||
|
<div class="pure-menu">
|
||||||
|
<ul class="pure-menu-list">
|
||||||
|
|
||||||
|
<li class="pure-menu-item poogie-menu-item">
|
||||||
|
<a class="pure-menu-link"
|
||||||
|
href="skilltrees-en.html">Skill Trees</a>
|
||||||
|
</li>
|
||||||
|
<li class="pure-menu-item poogie-menu-item">
|
||||||
|
<a class="pure-menu-link" href="hunterarts.html">Hunter Arts</a>
|
||||||
|
</li>
|
||||||
|
<li class="pure-menu-item poogie-menu-item">
|
||||||
|
<a class="pure-menu-link" href="monsters-en.html">Monsters</a>
|
||||||
|
</li>
|
||||||
|
<li class="pure-menu-item poogie-menu-item">
|
||||||
|
<a class="pure-menu-link"
|
||||||
|
href="monster-titles.html">Monster Titles</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="pure-menu-heading poogie-menu-heading">Items</li>
|
||||||
|
|
||||||
|
<li class="pure-menu-item poogie-menu-item">
|
||||||
|
<a class="pure-menu-link"
|
||||||
|
href="items-en.html">Items (Usable, Gatherable)</a>
|
||||||
|
</li>
|
||||||
|
<li class="pure-menu-item poogie-menu-item">
|
||||||
|
<a class="pure-menu-link"
|
||||||
|
href="items-carve-en.html">Monster Carves</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="pure-menu-heading poogie-menu-heading">Old Sites (searchable but slow load)</li>
|
||||||
|
|
||||||
|
<li class="pure-menu-item poogie-menu-item">
|
||||||
|
<a class="pure-menu-link"
|
||||||
|
href="site-jqueryui.html">Version 2 (home menu navigation)</a>
|
||||||
|
</li>
|
||||||
|
<li class="pure-menu-item poogie-menu-item">
|
||||||
|
<a class="pure-menu-link"
|
||||||
|
href="site-jqueryui-tabbed.html">Version 1 (tabbed navigation)</a>
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<li class="pure-menu-heading poogie-menu-heading">Acknowledgments / Sources</li>
|
||||||
|
|
||||||
|
<li class="pure-menu-item poogie-menu-item">
|
||||||
|
<a class="pure-menu-link"
|
||||||
|
href="http://monsterhunter.wikia.com/wiki/MHX"
|
||||||
|
>Monster Hunter X Wiki (Wikia)</a>
|
||||||
|
</li>
|
||||||
|
<li class="pure-menu-item poogie-menu-item">
|
||||||
|
<a class="pure-menu-link"
|
||||||
|
href="https://github.com/kamegami13/MonsterHunter4UDatabase">MonsterHunter4UDatabase</a>
|
||||||
|
</li>
|
||||||
|
<li class="pure-menu-item poogie-menu-item">
|
||||||
|
<a class="pure-menu-link"
|
||||||
|
href="http://creativecommons.org/licenses/by-sa/3.0/">License CC-BY-SA</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
312
templates/damage/monster_damage.html
Normal file
312
templates/damage/monster_damage.html
Normal file
@@ -0,0 +1,312 @@
|
|||||||
|
## -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Poogie's Calculator: ${monster} v${village_stars} g${guild_stars}</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<!-- Include meta tag to ensure proper rendering and touch zooming -->
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<script src="/js/jquery.min.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/css/jquery-ui.min.css" />
|
||||||
|
<script src="/js/jquery-ui.min.js"></script>
|
||||||
|
|
||||||
|
<script src="/js/common.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/css/poogie.css">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.icon { width: 20px; height: 20px; }
|
||||||
|
|
||||||
|
.sharpness-bar {
|
||||||
|
border: 1px #a9a9a9 solid;
|
||||||
|
min-width: 82px;
|
||||||
|
height: 10px;
|
||||||
|
background-color: #a9a9a9;
|
||||||
|
float: left;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar span {
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .red {
|
||||||
|
background-color: #C00C38 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .orange {
|
||||||
|
background-color: #E85018 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .yellow {
|
||||||
|
background-color: #F0C830 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .green {
|
||||||
|
background-color: #58D000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .blue {
|
||||||
|
background-color: #3068E8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .white {
|
||||||
|
background-color: #F0F0F0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .purple {
|
||||||
|
background-color: #c3c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sharpness_popup {
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
border: 1px solid;
|
||||||
|
background: rgba(204, 204, 204, 0.9);
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.sharpness-box {
|
||||||
|
float: left;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin: 1px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, .2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Red {
|
||||||
|
background-color: #C00C38 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Orange {
|
||||||
|
background-color: #E85018 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Yellow {
|
||||||
|
background-color: #F0C830 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Green {
|
||||||
|
background-color: #58D000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Blue {
|
||||||
|
background-color: #3068E8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.White {
|
||||||
|
background-color: #F0F0F0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Purple {
|
||||||
|
background-color: #c3c !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function load_monster_damage(form) {
|
||||||
|
var url = "/mh4u/damage/" + $("#monster").val()
|
||||||
|
+ "/v" + $("#village_stars").val()
|
||||||
|
+ "g" + $("#guild_stars").val()
|
||||||
|
+ "/" + $("#weapon_type").val() + ".html";
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
|
$(document).ready(function(){
|
||||||
|
setup_monster_autocomplete("mh4u", "#monster");
|
||||||
|
$( "#village_stars" ).spinner({
|
||||||
|
spin: function(event, ui) {
|
||||||
|
if (${monster_stars["Village"]} == 0) {
|
||||||
|
if (ui.value != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (ui.value < ${monster_stars["Village"]}) {
|
||||||
|
return false;
|
||||||
|
} else if (ui.value > 10) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$( "#guild_stars" ).spinner({
|
||||||
|
spin: function(event, ui) {
|
||||||
|
if (${monster_stars["Guild"]} == 0) {
|
||||||
|
if (ui.value != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (ui.value < ${monster_stars["Guild"]}) {
|
||||||
|
return false;
|
||||||
|
} else if (ui.value > 10) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<form action="javascript:void(0);" onsubmit="load_monster_damage(this)">
|
||||||
|
<span>
|
||||||
|
<input id="monster" name="monster" type="text" size="20"
|
||||||
|
value="${monster}" /></td>
|
||||||
|
<select id="weapon_type" name="weapon_type">
|
||||||
|
% for wname in weapon_types:
|
||||||
|
% if wname == weapon_type:
|
||||||
|
<option value="${wname}" selected="selected">${wname}</option>
|
||||||
|
% else:
|
||||||
|
<option value="${wname}">${wname}</option>
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<label for="village_stars">Village:</label>
|
||||||
|
<input id="village_stars" name="village_stars" value="${village_stars}"
|
||||||
|
style="width: 18px">
|
||||||
|
<label for="guild_stars">Guild:</label>
|
||||||
|
<input id="guild_stars" name="guild_stars" value="${guild_stars}"
|
||||||
|
style="width: 18px">
|
||||||
|
<input type="submit" value="Go" />
|
||||||
|
</span>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<p>Breaks: ${", ".join(monster_breaks)}</p>
|
||||||
|
|
||||||
|
% if monster_damage.alt_state != "Default":
|
||||||
|
<p>Alternate state: ${monster_damage.alt_state}</p>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
<table border="1" cellpadding="2" cellspacing="0">
|
||||||
|
<tr>
|
||||||
|
<th colspan="6">Weapon</th>
|
||||||
|
<th>Avg</th>
|
||||||
|
% for part in part_names:
|
||||||
|
% if part in monster_breaks:
|
||||||
|
<th style="background: pink;">${part}</th>
|
||||||
|
% else:
|
||||||
|
<th>${part}</th>
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
% for dtype in damage_types:
|
||||||
|
<% max_damage = monster_damage.max(dtype) %>
|
||||||
|
<% avg_damage = monster_damage.avg(dtype) %>
|
||||||
|
<% alt_avg_damage = monster_damage.alt_avg(dtype) %>
|
||||||
|
<tr style="border: 0px;">
|
||||||
|
<td colspan="6" align="left">
|
||||||
|
<img style="height:.8em"
|
||||||
|
title="dtype"
|
||||||
|
src="/img/${dtype.capitalize()}.png" />
|
||||||
|
${dtype}
|
||||||
|
</td>
|
||||||
|
<td align="right">
|
||||||
|
% if avg_damage > 0 or alt_avg_damage > 0:
|
||||||
|
${round(avg_damage, 1)}
|
||||||
|
% if alt_avg_damage != avg_damage:
|
||||||
|
(${round(alt_avg_damage, 1)})
|
||||||
|
% endif
|
||||||
|
<img style="height:.8em"
|
||||||
|
title="dtype"
|
||||||
|
src="/img/${dtype.capitalize()}.png" />
|
||||||
|
% else:
|
||||||
|
|
||||||
|
% endif
|
||||||
|
</td>
|
||||||
|
% for part_name, part in monster_damage.items():
|
||||||
|
<% bgcolor = "lightyellow" if (part[dtype] > 0 and part[dtype] == max_damage) else "white" %>
|
||||||
|
% if part.state_diff(dtype) != 0:
|
||||||
|
<td align="right" style="background: ${bgcolor}">
|
||||||
|
% if part[dtype] > 0 or part.get_alt_state(dtype) > 0:
|
||||||
|
${part[dtype]} (${part.get_alt_state(dtype)})
|
||||||
|
<img style="height:.8em"
|
||||||
|
title="dtype"
|
||||||
|
src="/img/${dtype.capitalize()}.png" />
|
||||||
|
% else:
|
||||||
|
|
||||||
|
% endif
|
||||||
|
</td>
|
||||||
|
% else:
|
||||||
|
<td align="right" style="background: ${bgcolor}">
|
||||||
|
% if part[dtype] > 0:
|
||||||
|
${part[dtype]}
|
||||||
|
<img style="height:.8em"
|
||||||
|
title="dtype"
|
||||||
|
src="/img/${dtype.capitalize()}.png" />
|
||||||
|
% else:
|
||||||
|
|
||||||
|
%endif
|
||||||
|
</td>
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
</tr>
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
% for weapon in weapon_names:
|
||||||
|
<% damage = weapon_damage_map[weapon] %>
|
||||||
|
<% affinity = str(int(damage.affinity)) + "%" if damage.affinity else " " %>
|
||||||
|
<% avg = damage.uniform(0.0) %>
|
||||||
|
<% avg_break = damage.uniform(1.0) %>
|
||||||
|
<tr style="border: 0px;">
|
||||||
|
<td align="left">
|
||||||
|
<a href="/mh4u/weaponplanner.html?weapon=${weapon | u}">${weapon}</a>
|
||||||
|
</td>
|
||||||
|
<td align="right">${int(damage.attack)}</td>
|
||||||
|
<td align="right">${affinity}</td>
|
||||||
|
<td align="center" title="${damage.weapon.sharpness}">
|
||||||
|
<div class="sharpness-box ${damage.sharpness_name}" />
|
||||||
|
</td>
|
||||||
|
% if damage.eattack > 0:
|
||||||
|
<td align="right">
|
||||||
|
${int(damage.eattack)}
|
||||||
|
<img style="height:.8em"
|
||||||
|
title="${damage.etype}"
|
||||||
|
src="/img/${damage.etype}.png" />
|
||||||
|
</td>
|
||||||
|
% else:
|
||||||
|
<td> </td>
|
||||||
|
% endif
|
||||||
|
% if damage.eattack2 > 0:
|
||||||
|
<td align="right">
|
||||||
|
${int(damage.eattack2)}
|
||||||
|
<img style="height:.8em"
|
||||||
|
title="${damage.etype2}"
|
||||||
|
src="/img/${damage.etype2}.png" />
|
||||||
|
</td>
|
||||||
|
% else:
|
||||||
|
<td> </td>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
<td align="right">
|
||||||
|
${round(avg, 1)}
|
||||||
|
% if avg != avg_break:
|
||||||
|
(${round(avg_break, 1)})
|
||||||
|
% endif
|
||||||
|
</td>
|
||||||
|
% for part in part_names:
|
||||||
|
<% bgcolor = "yellow" if damage[part].average() == part_max_damage[part] else "white" %>
|
||||||
|
<td align="right" style="background: ${bgcolor};">
|
||||||
|
${int(damage[part].total)}
|
||||||
|
% if damage[part].total_break != damage[part].total:
|
||||||
|
(${int(damage[part].total_break)})
|
||||||
|
% endif
|
||||||
|
</td>
|
||||||
|
% endfor
|
||||||
|
</tr>
|
||||||
|
% endfor
|
||||||
|
</table>
|
||||||
|
<div id="sharpness_popup"></div>
|
||||||
|
</body>
|
||||||
279
templates/damage/monster_damage_by_rarity.html
Normal file
279
templates/damage/monster_damage_by_rarity.html
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
## -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
|
||||||
|
<head>
|
||||||
|
<title>Poogie's Calculator: ${monster} r${rarity}</title>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<!-- Include meta tag to ensure proper rendering and touch zooming -->
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
|
||||||
|
<script src="/js/jquery.min.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/css/jquery-ui.min.css" />
|
||||||
|
<script src="/js/jquery-ui.min.js"></script>
|
||||||
|
|
||||||
|
<script src="/js/common.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="/css/poogie.css">
|
||||||
|
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-size: 1em;
|
||||||
|
line-height: 1.3;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.icon { width: 20px; height: 20px; }
|
||||||
|
|
||||||
|
.sharpness-bar {
|
||||||
|
border: 1px #a9a9a9 solid;
|
||||||
|
min-width: 82px;
|
||||||
|
height: 10px;
|
||||||
|
background-color: #a9a9a9;
|
||||||
|
float: left;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar span {
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .red {
|
||||||
|
background-color: #C00C38 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .orange {
|
||||||
|
background-color: #E85018 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .yellow {
|
||||||
|
background-color: #F0C830 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .green {
|
||||||
|
background-color: #58D000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .blue {
|
||||||
|
background-color: #3068E8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .white {
|
||||||
|
background-color: #F0F0F0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .purple {
|
||||||
|
background-color: #c3c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sharpness_popup {
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
border: 1px solid;
|
||||||
|
background: rgba(204, 204, 204, 0.9);
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.sharpness-box {
|
||||||
|
float: left;
|
||||||
|
width: 10px;
|
||||||
|
height: 10px;
|
||||||
|
margin: 1px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, .2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.Red {
|
||||||
|
background-color: #C00C38 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Orange {
|
||||||
|
background-color: #E85018 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Yellow {
|
||||||
|
background-color: #F0C830 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Green {
|
||||||
|
background-color: #58D000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Blue {
|
||||||
|
background-color: #3068E8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.White {
|
||||||
|
background-color: #F0F0F0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Purple {
|
||||||
|
background-color: #c3c !important;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
function load_monster_damage(form) {
|
||||||
|
var url = "/mhr/damage/" + $("#monster").val()
|
||||||
|
+ "/r" + $("#rarity").val()
|
||||||
|
+ "/" + $("#weapon_type").val() + ".html";
|
||||||
|
window.location.href = url;
|
||||||
|
}
|
||||||
|
$(document).ready(function(){
|
||||||
|
setup_monster_autocomplete("mhr", "#monster");
|
||||||
|
$( "#rarity" ).spinner({
|
||||||
|
spin: function(event, ui) {
|
||||||
|
if (ui.value > 10) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<form action="javascript:void(0);" onsubmit="load_monster_damage(this)">
|
||||||
|
<span>
|
||||||
|
<input id="monster" name="monster" type="text" size="20"
|
||||||
|
value="${monster}" /></td>
|
||||||
|
<select id="weapon_type" name="weapon_type">
|
||||||
|
% for wname in weapon_types:
|
||||||
|
% if wname == weapon_type:
|
||||||
|
<option value="${wname}" selected="selected">${wname}</option>
|
||||||
|
% else:
|
||||||
|
<option value="${wname}">${wname}</option>
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
<span>
|
||||||
|
<label for="rarity">Rarity:</label>
|
||||||
|
<input id="rarity" name="rarity" value="${rarity}"
|
||||||
|
style="width: 18px">
|
||||||
|
<input type="submit" value="Go" />
|
||||||
|
</span>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<table border="1" cellpadding="2" cellspacing="0">
|
||||||
|
<tr>
|
||||||
|
<th colspan="6">Weapon</th>
|
||||||
|
<th>Avg</th>
|
||||||
|
% for part in part_names:
|
||||||
|
<th>${part}</th>
|
||||||
|
% endfor
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
% for dtype in damage_types:
|
||||||
|
<% max_damage = monster_damage.max(dtype) %>
|
||||||
|
<% avg_damage = monster_damage.avg(dtype) %>
|
||||||
|
<% alt_avg_damage = monster_damage.alt_avg(dtype) %>
|
||||||
|
<tr style="border: 0px;">
|
||||||
|
<td colspan="6" align="left">
|
||||||
|
<img style="height:.8em"
|
||||||
|
title="dtype"
|
||||||
|
src="/img/${dtype.capitalize()}.png" />
|
||||||
|
${dtype}
|
||||||
|
</td>
|
||||||
|
<td align="right">
|
||||||
|
% if avg_damage > 0 or alt_avg_damage > 0:
|
||||||
|
${round(avg_damage, 1)}
|
||||||
|
% if alt_avg_damage != avg_damage:
|
||||||
|
(${round(alt_avg_damage, 1)})
|
||||||
|
% endif
|
||||||
|
<img style="height:.8em"
|
||||||
|
title="dtype"
|
||||||
|
src="/img/${dtype.capitalize()}.png" />
|
||||||
|
% else:
|
||||||
|
|
||||||
|
% endif
|
||||||
|
</td>
|
||||||
|
% for part_name, part in monster_damage.items():
|
||||||
|
<% bgcolor = "lightyellow" if (part[dtype] > 0 and part[dtype] == max_damage) else "white" %>
|
||||||
|
% if part.state_diff(dtype) != 0:
|
||||||
|
<td align="right" style="background: ${bgcolor}">
|
||||||
|
% if part[dtype] > 0 or part.get_alt_state(dtype) > 0:
|
||||||
|
${part[dtype]} (${part.get_alt_state(dtype)})
|
||||||
|
<img style="height:.8em"
|
||||||
|
title="dtype"
|
||||||
|
src="/img/${dtype.capitalize()}.png" />
|
||||||
|
% else:
|
||||||
|
|
||||||
|
% endif
|
||||||
|
</td>
|
||||||
|
% else:
|
||||||
|
<td align="right" style="background: ${bgcolor}">
|
||||||
|
% if part[dtype] > 0:
|
||||||
|
${part[dtype]}
|
||||||
|
<img style="height:.8em"
|
||||||
|
title="dtype"
|
||||||
|
src="/img/${dtype.capitalize()}.png" />
|
||||||
|
% else:
|
||||||
|
|
||||||
|
%endif
|
||||||
|
</td>
|
||||||
|
% endif
|
||||||
|
% endfor
|
||||||
|
</tr>
|
||||||
|
% endfor
|
||||||
|
|
||||||
|
% for weapon in weapon_names:
|
||||||
|
<% damage = weapon_damage_map[weapon] %>
|
||||||
|
<% affinity = str(int(damage.affinity)) + "%" if damage.affinity else " " %>
|
||||||
|
<% avg = damage.uniform(0.0) %>
|
||||||
|
<% avg_break = damage.uniform(1.0) %>
|
||||||
|
<tr style="border: 0px;">
|
||||||
|
<td align="left">
|
||||||
|
<a href="/mhr/weaponplanner.html?weapon=${weapon | u}">${weapon}</a>
|
||||||
|
</td>
|
||||||
|
<td align="right">${int(damage.attack)}</td>
|
||||||
|
<td align="right">${affinity}</td>
|
||||||
|
<td align="center" title="${damage.weapon.sharpness}">
|
||||||
|
<div class="sharpness-box ${damage.sharpness_name}" />
|
||||||
|
</td>
|
||||||
|
% if damage.eattack > 0:
|
||||||
|
<td align="right">
|
||||||
|
${int(damage.eattack)}
|
||||||
|
<img style="height:.8em"
|
||||||
|
title="${damage.etype}"
|
||||||
|
src="/img/${damage.etype}.png" />
|
||||||
|
</td>
|
||||||
|
% else:
|
||||||
|
<td> </td>
|
||||||
|
% endif
|
||||||
|
% if damage.eattack2 > 0:
|
||||||
|
<td align="right">
|
||||||
|
${int(damage.eattack2)}
|
||||||
|
<img style="height:.8em"
|
||||||
|
title="${damage.etype2}"
|
||||||
|
src="/img/${damage.etype2}.png" />
|
||||||
|
</td>
|
||||||
|
% else:
|
||||||
|
<td> </td>
|
||||||
|
% endif
|
||||||
|
|
||||||
|
<td align="right">
|
||||||
|
${round(avg, 1)}
|
||||||
|
% if avg != avg_break:
|
||||||
|
(${round(avg_break, 1)})
|
||||||
|
% endif
|
||||||
|
</td>
|
||||||
|
% for part in part_names:
|
||||||
|
<% bgcolor = "yellow" if damage[part].average() == part_max_damage[part] else "white" %>
|
||||||
|
<td align="right" style="background: ${bgcolor};">
|
||||||
|
${int(damage[part].total)}
|
||||||
|
% if damage[part].total_break != damage[part].total:
|
||||||
|
(${int(damage[part].total_break)})
|
||||||
|
% endif
|
||||||
|
</td>
|
||||||
|
% endfor
|
||||||
|
</tr>
|
||||||
|
% endfor
|
||||||
|
</table>
|
||||||
|
<div id="sharpness_popup"></div>
|
||||||
|
</body>
|
||||||
BIN
web/img/Cut.png
Normal file
BIN
web/img/Cut.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
web/img/Impact.png
Normal file
BIN
web/img/Impact.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.5 KiB |
BIN
web/img/Shot.png
Normal file
BIN
web/img/Shot.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.0 KiB |
@@ -88,7 +88,8 @@
|
|||||||
(<a href="mh4u/weaponlist.html">MH4U</a>,
|
(<a href="mh4u/weaponlist.html">MH4U</a>,
|
||||||
<a href="mhx/weaponlist.html">MHX</a>,
|
<a href="mhx/weaponlist.html">MHX</a>,
|
||||||
<a href="mhgen/weaponlist.html">MHGen</a>,
|
<a href="mhgen/weaponlist.html">MHGen</a>,
|
||||||
<a href="mhgu/weaponlist.html">MHGU</a>)</td></tr>
|
<a href="mhgu/weaponlist.html">MHGU</a>,
|
||||||
|
<a href="mhr/weaponlist.html">MHRise</a>)</td></tr>
|
||||||
</table>
|
</table>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
</form>
|
</form>
|
||||||
@@ -103,10 +104,12 @@
|
|||||||
</fieldset>
|
</fieldset>
|
||||||
|
|
||||||
<h2>Acknowledgements</h2>
|
<h2>Acknowledgements</h2>
|
||||||
Data is primary from the excellent 4U and Gen android apps:
|
Data is primarily from the 4U, Gen, and World android apps and from mhrice for Rise:
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://github.com/kamegami13/MonsterHunter4UDatabase">MonsterHunter4UDatabase</a></li>
|
<li><a href="https://github.com/kamegami13/MonsterHunter4UDatabase">MonsterHunter4UDatabase</a></li>
|
||||||
<li><a href="https://github.com/gatheringhallstudios/MHGenDatabase">MHGenDatabase</a></li>
|
<li><a href="https://github.com/gatheringhallstudios/MHGenDatabase">MHGenDatabase</a></li>
|
||||||
|
<li><a href="https://github.com/gatheringhallstudios/MHWorldDatabase">MHWorldDatabase</a></li>
|
||||||
|
<li><a href="https://github.com/wwylele/mhrice">mhrice</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
Also sourced for MHX translation and weapon data:
|
Also sourced for MHX translation and weapon data:
|
||||||
|
|||||||
@@ -135,7 +135,7 @@ function normalize_name(s) {
|
|||||||
|
|
||||||
|
|
||||||
function setup_item_autocomplete(selector) {
|
function setup_item_autocomplete(selector) {
|
||||||
var DATA_PATH = get_base_path() + "/rewards/";
|
var DATA_PATH = get_base_path() + "/mh4u/rewards/";
|
||||||
$.getJSON(DATA_PATH + "items.json",
|
$.getJSON(DATA_PATH + "items.json",
|
||||||
function(data) {
|
function(data) {
|
||||||
$(selector).autocomplete({ source: data });
|
$(selector).autocomplete({ source: data });
|
||||||
@@ -143,6 +143,16 @@ function setup_item_autocomplete(selector) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function setup_monster_autocomplete(game, selector) {
|
||||||
|
var DATA_PATH = "/jsonapi/" + game + "/";
|
||||||
|
$.getJSON(DATA_PATH + "monster/_list.json",
|
||||||
|
function(data) {
|
||||||
|
var boss = data.filter(a => (a["class"] == "Boss" || a["class"] == "Large"));
|
||||||
|
var boss_names = boss.map(a => a["name"]);
|
||||||
|
$(selector).autocomplete({ source: boss_names });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function load_weapon_data(ready_fn) {
|
function load_weapon_data(ready_fn) {
|
||||||
if (typeof DATA_PATH == "undefined") {
|
if (typeof DATA_PATH == "undefined") {
|
||||||
DATA_PATH = get_base_path() + "/jsonapi/";
|
DATA_PATH = get_base_path() + "/jsonapi/";
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/themes/smoothness/jquery-ui.css" />
|
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/themes/smoothness/jquery-ui.css" />
|
||||||
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js"></script>
|
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript" src="js/ejs_production.js"></script>
|
<script type="text/javascript" src="/js/ejs_production.js"></script>
|
||||||
|
|
||||||
<script src="js/common.js"></script>
|
<script src="/js/common.js"></script>
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
label {
|
label {
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
var DATA_PATH = get_base_path() + "/jsonapi/";
|
var DATA_PATH = "/jsonapi/mh4u/";
|
||||||
var TYPES = ["Head", "Body", "Arms", "Waist", "Legs"];
|
var TYPES = ["Head", "Body", "Arms", "Waist", "Legs"];
|
||||||
var GEAR = ["Weapon", "Head", "Body", "Arms", "Waist", "Legs", "Talisman"];
|
var GEAR = ["Weapon", "Head", "Body", "Arms", "Waist", "Legs", "Talisman"];
|
||||||
var ELEMENTS = ["fire", "water", "thunder", "ice", "dragon"];
|
var ELEMENTS = ["fire", "water", "thunder", "ice", "dragon"];
|
||||||
@@ -60,9 +60,9 @@
|
|||||||
"Waist": [], "Legs": [], "Weapon": [] };
|
"Waist": [], "Legs": [], "Weapon": [] };
|
||||||
var slots_left = {};
|
var slots_left = {};
|
||||||
|
|
||||||
var template_skills = new EJS({ url: "templates/skills.ejs" });
|
var template_skills = new EJS({ url: "/templates/skills.ejs" });
|
||||||
var template_resist = new EJS({ url: "templates/resistance.ejs" });
|
var template_resist = new EJS({ url: "/templates/resistance.ejs" });
|
||||||
var template_decorations = new EJS({ url: "templates/decorations.ejs" });
|
var template_decorations = new EJS({ url: "/templates/decorations.ejs" });
|
||||||
|
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
$.getJSON(DATA_PATH + "armor/_index_name.json",
|
$.getJSON(DATA_PATH + "armor/_index_name.json",
|
||||||
|
|||||||
345
web/mhr/weaponlist.html
Normal file
345
web/mhr/weaponlist.html
Normal file
@@ -0,0 +1,345 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Poogie's Weapon List (Rise)</title>
|
||||||
|
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/themes/smoothness/jquery-ui.css" />
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="../js/ejs_production.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="../js/common.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: sans, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.plus {
|
||||||
|
background-color: LightCyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.minus {
|
||||||
|
background-color: LightPink;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.num {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*@media (max-width: 600) {*/
|
||||||
|
.flexbox {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar {
|
||||||
|
border: 1px #a9a9a9 solid;
|
||||||
|
min-width: 90px;
|
||||||
|
height: 7px;
|
||||||
|
background-color: #a9a9a9;
|
||||||
|
float: left;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar span {
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .red {
|
||||||
|
background-color: #C00C38 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .orange {
|
||||||
|
background-color: #E85018 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .yellow {
|
||||||
|
background-color: #F0C830 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .green {
|
||||||
|
background-color: #58D000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .blue {
|
||||||
|
background-color: #3068E8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .white {
|
||||||
|
background-color: #F0F0F0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .purple {
|
||||||
|
background-color: #c3c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sharpness_popup {
|
||||||
|
position: absolute;
|
||||||
|
display: none;
|
||||||
|
border: 1px solid;
|
||||||
|
background: rgba(204, 204, 204, 0.9);
|
||||||
|
z-index: 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
#cp_div {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
var WEAPON_LIST = null;
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url: "../jsonapi/mhr/weapon/_all.json",
|
||||||
|
async: false,
|
||||||
|
dataType: "json",
|
||||||
|
success: function (data) {
|
||||||
|
WEAPON_LIST = data;
|
||||||
|
console.log("weapon count " + WEAPON_LIST.length);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var template_row = new EJS({ url: "/templates/weaponrow-rise.ejs" });
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
init_page();
|
||||||
|
|
||||||
|
$("#sharpness_popup").on("click", function(evt) {
|
||||||
|
$(this).html("").offset({top:0, left:0}).hide();
|
||||||
|
});
|
||||||
|
|
||||||
|
$("#weapon_table").on("click", "#sharpness_td", function(evt) {
|
||||||
|
var td_obj = $(evt.currentTarget);
|
||||||
|
var offset = td_obj.offset();
|
||||||
|
var sharpness = td_obj.data("sharpness");
|
||||||
|
$("#sharpness_popup").html(sharpness).offset(offset).show();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
function init_page() {
|
||||||
|
var qs = load_qs();
|
||||||
|
$(window).on("popstate", function(e) {
|
||||||
|
var oe = e.originalEvent;
|
||||||
|
if (oe.state !== null) {
|
||||||
|
console.log("popState:" + JSON.stringify(oe.state));
|
||||||
|
update_weapon_list(oe.state);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#search").click(function(evt) {
|
||||||
|
var state = get_ui_state();
|
||||||
|
save_state(state);
|
||||||
|
update_weapon_list(state);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (qs) {
|
||||||
|
update_weapon_list(qs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function load_qs() {
|
||||||
|
if ($.QueryString["weapon_type"]) {
|
||||||
|
load_state($.QueryString);
|
||||||
|
return $.QueryString;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_ui_state() {
|
||||||
|
return { "weapon_type": $("#weapon_type").val(),
|
||||||
|
"weapon_element": $("#weapon_element").val(),
|
||||||
|
"weapon_final": $("#weapon_final").is(":checked"),
|
||||||
|
"weapon_name_text": $("#weapon_name_text").val(),
|
||||||
|
"weapon_rarity": $("#weapon_rarity").val() };
|
||||||
|
}
|
||||||
|
|
||||||
|
function load_state(state) {
|
||||||
|
$("#weapon_type").val(state["weapon_type"]);
|
||||||
|
$("#weapon_element").val(state["weapon_element"]);
|
||||||
|
if (typeof final == "string") {
|
||||||
|
final = final.toLowerCase();
|
||||||
|
state["weapon_final"] = (final == "true" || final == "1");
|
||||||
|
}
|
||||||
|
$("#weapon_final").prop("checked", state["weapon_final"]);
|
||||||
|
$("#weapon_name_text").val(state["weapon_name_text"]);
|
||||||
|
$("#weapon_rarity").val(state["weapon_rarity"]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function save_state(state, replace) {
|
||||||
|
var url = "weaponlist.html?" + encode_qs(state);
|
||||||
|
if (replace) {
|
||||||
|
window.history.replaceState(state, "", url);
|
||||||
|
} else {
|
||||||
|
window.history.pushState(state, "", url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function weapon_predicate(state, weapon_data) {
|
||||||
|
var weapon_type = state["weapon_type"];
|
||||||
|
var weapon_element = state["weapon_element"];
|
||||||
|
var final_only = state["weapon_final"];
|
||||||
|
var rarity = state["weapon_rarity"];
|
||||||
|
var weapon_names = state["weapon_name_text"].split("|");
|
||||||
|
|
||||||
|
if (final_only && !Boolean(weapon_data["final"])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rarity != "Any" && weapon_data["rarity"] > rarity) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weapon_type != "All" && weapon_type != weapon_data["wtype"]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weapon_element != "All"
|
||||||
|
&& weapon_element != weapon_data["element"]
|
||||||
|
&& weapon_element != weapon_data["element_2"]
|
||||||
|
&& weapon_element != weapon_data["awaken"]
|
||||||
|
&& weapon_element != weapon_data["phial"]) {
|
||||||
|
if (weapon_element != "None"
|
||||||
|
|| weapon_data["element"] != null
|
||||||
|
|| weapon_data["awaken"] != null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (weapon_names && !list_match(weapon_names, [weapon_data["name"]])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function list_match(needles, string_list) {
|
||||||
|
var found = false;
|
||||||
|
for (var i=0; i<string_list.length; i++) {
|
||||||
|
for (var j=0; j<needles.length; j++) {
|
||||||
|
if (string_list[i].search(needles[j]) >= 0) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_weapon_list(state) {
|
||||||
|
var match_count = 0;
|
||||||
|
console.log("updating weapon list: " + JSON.stringify(state));
|
||||||
|
var results = [];
|
||||||
|
$.each(WEAPON_LIST, function(i, weapon_data) {
|
||||||
|
if (weapon_predicate(state, weapon_data)) {
|
||||||
|
weapon_data["id"] = i;
|
||||||
|
weapon_data["sharpness_width"] = 0.4;
|
||||||
|
match_count += 1;
|
||||||
|
set_sharpness_titles(weapon_data);
|
||||||
|
set_bow_values(weapon_data);
|
||||||
|
weapon_data["wtype_short"] =
|
||||||
|
WEAPON_TYPE_ABBR[weapon_data["wtype"]];
|
||||||
|
weapon_data["ELEMENT_ABBR"] = ELEMENT_ABBR;
|
||||||
|
var html = template_row.render(weapon_data);
|
||||||
|
results.push([weapon_data, html]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
results.sort(function (a, b) {
|
||||||
|
avals = get_weapon_sort_values(a[0]);
|
||||||
|
bvals = get_weapon_sort_values(b[0]);
|
||||||
|
return cmp_arrays(bvals, avals);
|
||||||
|
});
|
||||||
|
$("#weapon_table").empty();
|
||||||
|
$.each(results, function(i, pair) {
|
||||||
|
$("#weapon_table").append(pair[1]);
|
||||||
|
});
|
||||||
|
console.log("match count: " + match_count);
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><label for="weapon_type"
|
||||||
|
title="Only show weapons of this type"
|
||||||
|
>Type:</label></td>
|
||||||
|
<td><select id="weapon_type">
|
||||||
|
<option value="All">All</option>
|
||||||
|
<option value="Great Sword">Great Sword</option>
|
||||||
|
<option value="Long Sword">Long Sword</option>
|
||||||
|
<option value="Sword and Shield">Sword and Shield</option>
|
||||||
|
<option value="Dual Blades">Dual Blades</option>
|
||||||
|
<option value="Hammer">Hammer</option>
|
||||||
|
<option value="Hunting Horn">Hunting Horn</option>
|
||||||
|
<option value="Lance">Lance</option>
|
||||||
|
<option value="Gunlance">Gunlance</option>
|
||||||
|
<option value="Switch Axe">Switch Axe</option>
|
||||||
|
<option value="Charge Blade">Charge Blade</option>
|
||||||
|
<option value="Insect Glaive">Insect Glaive</option>
|
||||||
|
<!--option value="Light Bowgun">Light Bowgun</option-->
|
||||||
|
<!--option value="Heavy Bowgun">Heavy Bowgun</option-->
|
||||||
|
<option value="Bow">Bow</option>
|
||||||
|
</select></td>
|
||||||
|
<td><label for="weapon_element"
|
||||||
|
title="Only show weapons with this element (native or requiring awaken)"
|
||||||
|
>Element:</label></td>
|
||||||
|
<td><select id="weapon_element">
|
||||||
|
<option value="All">All</option>
|
||||||
|
<option value="None">None</option>
|
||||||
|
<option value="Fire">Fire</option>
|
||||||
|
<option value="Water">Water</option>
|
||||||
|
<option value="Thunder">Thunder</option>
|
||||||
|
<option value="Ice">Ice</option>
|
||||||
|
<option value="Dragon">Dragon</option>
|
||||||
|
<option value="Poison">Poison</option>
|
||||||
|
<option value="Paralysis">Paralysis</option>
|
||||||
|
<option value="Sleep">Sleep</option>
|
||||||
|
<option value="Blast">Blast</option>
|
||||||
|
</select></td>
|
||||||
|
<td><label>Rarity:</label>
|
||||||
|
<select id="weapon_rarity">
|
||||||
|
<option value="Any">*</option>
|
||||||
|
<option value="1">1</option>
|
||||||
|
<option value="2">2</option>
|
||||||
|
<option value="3">3</option>
|
||||||
|
<option value="4">4</option>
|
||||||
|
<option value="5">5</option>
|
||||||
|
<option value="6">6</option>
|
||||||
|
<option value="7">7</option>
|
||||||
|
<option value="8">8</option>
|
||||||
|
<option value="9">9</option>
|
||||||
|
<option value="10">10</option>
|
||||||
|
</select></td>
|
||||||
|
<td><label for="weapon_final"
|
||||||
|
title="Only show weapons with no furthur upgrades"
|
||||||
|
>Final?</label></td>
|
||||||
|
<td><input id="weapon_final" type="checkbox" /></td>
|
||||||
|
<td><button id="search">Search</button></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td colspan="8">
|
||||||
|
<label for="weapon_name_text"
|
||||||
|
title="Show only weapons with a match in the name. List of strings separated by '|' (vertical bar)."
|
||||||
|
>Name:</label>
|
||||||
|
<input id="weapon_name_text" size="15" />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<table id="weapon_table">
|
||||||
|
</table>
|
||||||
|
<div id="sharpness_popup"></div>
|
||||||
|
</body>
|
||||||
284
web/mhr/weaponplanner.html
Normal file
284
web/mhr/weaponplanner.html
Normal file
@@ -0,0 +1,284 @@
|
|||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Poogie's Weapon Planner (Rise)</title>
|
||||||
|
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
|
||||||
|
|
||||||
|
<link rel="stylesheet" href="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/themes/smoothness/jquery-ui.css" />
|
||||||
|
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.3/jquery-ui.min.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/js/ejs_production.js"></script>
|
||||||
|
|
||||||
|
<script type="text/javascript" src="/js/common.js"></script>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
label {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: sans, sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.plus {
|
||||||
|
background-color: LightCyan;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.minus {
|
||||||
|
background-color: LightPink;
|
||||||
|
}
|
||||||
|
|
||||||
|
td.num {
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*@media (max-width: 600) {*/
|
||||||
|
.flexbox {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar {
|
||||||
|
border: 1px #d3d3d3 solid;
|
||||||
|
min-width: 92px;
|
||||||
|
height: 10px;
|
||||||
|
background-color: #d3d3d3;
|
||||||
|
float: left;
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar span {
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .red {
|
||||||
|
background-color: #C00C38 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .orange {
|
||||||
|
background-color: #E85018 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .yellow {
|
||||||
|
background-color: #F0C830 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .green {
|
||||||
|
background-color: #58D000 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .blue {
|
||||||
|
background-color: #3068E8 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .white {
|
||||||
|
background-color: #F0F0F0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sharpness-bar .purple {
|
||||||
|
background-color: #c3c !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
var DATA_PATH = "/jsonapi/mhr/";
|
||||||
|
|
||||||
|
var template_path = new EJS({ url: "/templates/weaponpath.ejs" });
|
||||||
|
var template_stats = new EJS({ url: "/templates/weaponstats-rise.ejs" });
|
||||||
|
|
||||||
|
$(document).ready(function(){
|
||||||
|
setup_weapon_autocomplete("#weapon", autocomplete_predicate,
|
||||||
|
init_page, update_search);
|
||||||
|
});
|
||||||
|
|
||||||
|
function init_page() {
|
||||||
|
load_qs();
|
||||||
|
$("#search").click(update_search);
|
||||||
|
$(window).on("popstate", function(e) {
|
||||||
|
var oe = e.originalEvent;
|
||||||
|
if (oe.state !== null) {
|
||||||
|
console.log("popState:" + JSON.stringify(oe.state));
|
||||||
|
$("#weapon_type").val(oe.state["weapon_type"]);
|
||||||
|
$("#weapon_type").change();
|
||||||
|
show_trees(oe.state["weapon"]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$("#weapon_type").change(function(evt) {
|
||||||
|
update_weapon_autocomplete("#weapon", autocomplete_predicate,
|
||||||
|
update_search);
|
||||||
|
$("#weapon").val("");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function load_qs() {
|
||||||
|
var wtype = $.QueryString["weapon_type"];
|
||||||
|
var weapon = $.QueryString["weapon"];
|
||||||
|
if (!wtype) {
|
||||||
|
wtype = "All";
|
||||||
|
}
|
||||||
|
$("#weapon_type").val(wtype);
|
||||||
|
$("#weapon_type").change();
|
||||||
|
if (weapon) {
|
||||||
|
show_trees(weapon);
|
||||||
|
console.log("replaceState: " + weapon);
|
||||||
|
save_state(get_state(), true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_state() {
|
||||||
|
return { "weapon": $("#weapon").val(),
|
||||||
|
"weapon_type": $("#weapon_type").val() };
|
||||||
|
}
|
||||||
|
|
||||||
|
function save_state(state, replace) {
|
||||||
|
var url = "/mhr/weaponplanner.html?" + encode_qs(state);
|
||||||
|
if (replace) {
|
||||||
|
window.history.replaceState(state, "", url);
|
||||||
|
} else {
|
||||||
|
window.history.pushState(state, "", url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function autocomplete_predicate(weapon_data) {
|
||||||
|
var weapon_type = $("#weapon_type").val();
|
||||||
|
|
||||||
|
if (weapon_type != "All" && weapon_type != weapon_data["wtype"]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_search() {
|
||||||
|
var weapon_name = $("#weapon").val();
|
||||||
|
|
||||||
|
if (!weapon_name) return;
|
||||||
|
|
||||||
|
if (window.history.state
|
||||||
|
&& window.history.state["weapon"] == weapon_name) {
|
||||||
|
console.log("weapon not changed, skipping update");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
show_trees(weapon_name);
|
||||||
|
console.log("pushState: " + weapon_name);
|
||||||
|
save_state(get_state(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function show_trees(weapon_name) {
|
||||||
|
console.log("show_trees '" + weapon_name + "'");
|
||||||
|
if (!weapon_name) return;
|
||||||
|
weapon_id = WEAPON_NAME_IDX[weapon_name][0];
|
||||||
|
console.log("show_trees(" + weapon_name + "): " + weapon_id);
|
||||||
|
$("#weapon").val(weapon_name);
|
||||||
|
$("#results").html("");
|
||||||
|
$("#weapon_stats").html("");
|
||||||
|
$.getJSON(DATA_PATH + "weapon/" + weapon_id + ".json",
|
||||||
|
function(data) {
|
||||||
|
set_sharpness_titles(data);
|
||||||
|
//set_horn_melodies_title(data);
|
||||||
|
if (data["parent_id"]) {
|
||||||
|
var parent_obj = WEAPON_ID_IDX[data["parent_id"]][0];
|
||||||
|
data["parent_name"] = parent_obj["name"];
|
||||||
|
} else {
|
||||||
|
data["parent_name"] = null;
|
||||||
|
}
|
||||||
|
data["sharpness_width"] = 0.4;
|
||||||
|
data["sharpness_plus2"] = null;
|
||||||
|
data["village_stars"] = 0
|
||||||
|
data["guild_stars"] = 0
|
||||||
|
var html = template_stats.render(data);
|
||||||
|
$("#weapon_stats").html(html);
|
||||||
|
});
|
||||||
|
|
||||||
|
$.getJSON(DATA_PATH + "weapon/" + weapon_id + "_tree.json",
|
||||||
|
function(data) {
|
||||||
|
// first pass: collect all components and sort them
|
||||||
|
var all_dict = {};
|
||||||
|
for (i=0; i<data.length; i++) {
|
||||||
|
var components = Object.keys(data[i]["components"]);
|
||||||
|
for (j=0; j<components.length; j++) {
|
||||||
|
all_dict[components[j]] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var all_components = Object.keys(all_dict);
|
||||||
|
all_components.sort();
|
||||||
|
// second pass: generate the fieldset for each weapon
|
||||||
|
// path. Note that the template uses all components
|
||||||
|
// to order the components and make them line up
|
||||||
|
for (i=0; i<data.length; i++) {
|
||||||
|
delta = {};
|
||||||
|
path = data[i];
|
||||||
|
components = path["components"]
|
||||||
|
path_string = "";
|
||||||
|
for (j=0; j<path["path"].length; j++) {
|
||||||
|
if (j != 0) {
|
||||||
|
path_string += " -> ";
|
||||||
|
}
|
||||||
|
path_string += path["path"][j]["name"];
|
||||||
|
}
|
||||||
|
path["path_string"] = path_string.replace(/"/g,
|
||||||
|
'"');
|
||||||
|
path["all_components"] = all_components;
|
||||||
|
path["component_list"] = Object.keys(components);
|
||||||
|
if (i > 0) {
|
||||||
|
prev_comps = data[i-1]["components"];
|
||||||
|
$.each(components, function(name, quantity) {
|
||||||
|
if (name in prev_comps) {
|
||||||
|
delta[name] = components[name]
|
||||||
|
- prev_comps[name];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
path["delta"] = delta;
|
||||||
|
path["component_list"].sort();
|
||||||
|
path["trade_names"] = [];
|
||||||
|
for (j=0; j<all_components.length; j++) {
|
||||||
|
var name = all_components[j];
|
||||||
|
path["trade_names"][j] = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
var html = template_path.render(path);
|
||||||
|
$("#results").append(html);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td><label for="weapon_type">Type:</label></td>
|
||||||
|
<td><select id="weapon_type">
|
||||||
|
<option value="All">All</option>
|
||||||
|
<option value="Great Sword">Great Sword</option>
|
||||||
|
<option value="Long Sword">Long Sword</option>
|
||||||
|
<option value="Sword and Shield">Sword and Shield</option>
|
||||||
|
<option value="Dual Blades">Dual Blades</option>
|
||||||
|
<option value="Hammer">Hammer</option>
|
||||||
|
<option value="Hunting Horn">Hunting Horn</option>
|
||||||
|
<option value="Lance">Lance</option>
|
||||||
|
<option value="Gunlance">Gunlance</option>
|
||||||
|
<option value="Switch Axe">Switch Axe</option>
|
||||||
|
<option value="Charge Blade">Charge Blade</option>
|
||||||
|
<option value="Insect Glaive">Insect Glaive</option>
|
||||||
|
<option value="Light Bowgun">Light Bowgun</option>
|
||||||
|
<option value="Heavy Bowgun">Heavy Bowgun</option>
|
||||||
|
<option value="Bow">Bow</option>
|
||||||
|
</select></td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td><label for="weapon">Weapon:</label></td>
|
||||||
|
<td><input id="weapon" name="weapon" size="20" />
|
||||||
|
<button id="search">Ask Poogie</button></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div id="weapon_stats"></div>
|
||||||
|
<div id="results" class="flexbox"></div>
|
||||||
|
</body>
|
||||||
63
web/templates/weaponrow-rise.ejs
Normal file
63
web/templates/weaponrow-rise.ejs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
<tr title="id: <%= id %>">
|
||||||
|
<td><% if (final == 1) { %>
|
||||||
|
<strong>*</strong>
|
||||||
|
<% } else { %>
|
||||||
|
|
||||||
|
<% } %>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="weaponplanner.html?weapon=<%= encodeURIComponent(name) %>"><%= name %></a>
|
||||||
|
</td>
|
||||||
|
<td><%= wtype_short %></td>
|
||||||
|
<td style="text-align:right"><%= attack %></td>
|
||||||
|
<td style="text-align:right"><% if (affinity) { %><%= affinity %>%<% } %></td>
|
||||||
|
<td>
|
||||||
|
<% if (element) { %>
|
||||||
|
<img style="height:.8em" title="<%= element %>"
|
||||||
|
src="/img/<%= element %>.png" /> <%= element_attack %>
|
||||||
|
<%= ELEMENT_ABBR[element] %>
|
||||||
|
<% if (element_2) { %>
|
||||||
|
<img style="height:.8em" title="<%= element_2 %>"
|
||||||
|
src="/img/<%= element_2 %>.png" /> <%= element_2_attack %>
|
||||||
|
<%= ELEMENT_ABBR[element_2] %>
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
||||||
|
</td>
|
||||||
|
<td id="sharpness_td"
|
||||||
|
data-sharpness="<%= sharpness_all_title %>"
|
||||||
|
data-id="<%= id %>">
|
||||||
|
<% if (sharpness) { %>
|
||||||
|
<div class="sharpness-bar" title="<%= sharpness_all_title %>">
|
||||||
|
<span style="width:<%= sharpness[0] * sharpness_width %>px" class="red"></span>
|
||||||
|
<span style="width:<%= sharpness[1] * sharpness_width %>px" class="orange"></span>
|
||||||
|
<span style="width:<%= sharpness[2] * sharpness_width %>px" class="yellow"></span>
|
||||||
|
<span style="width:<%= sharpness[3] * sharpness_width %>px" class="green"></span>
|
||||||
|
<span style="width:<%= sharpness[4] * sharpness_width %>px" class="blue"></span>
|
||||||
|
<span style="width:<%= sharpness[5] * sharpness_width %>px" class="white"></span>
|
||||||
|
<% if (sharpness.length > 6) { %>
|
||||||
|
<span style="width:<%= sharpness[6] * sharpness_width %>px" class="purple"></span>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
<% if (sharpness_plus) { %>
|
||||||
|
<div class="sharpness-bar" title="<%= sharpness_all_title %>">
|
||||||
|
<span style="width:<%= sharpness_plus[0] * sharpness_width %>px" class="red"></span>
|
||||||
|
<span style="width:<%= sharpness_plus[1] * sharpness_width %>px" class="orange"></span>
|
||||||
|
<span style="width:<%= sharpness_plus[2] * sharpness_width %>px" class="yellow"></span>
|
||||||
|
<span style="width:<%= sharpness_plus[3] * sharpness_width %>px" class="green"></span>
|
||||||
|
<span style="width:<%= sharpness_plus[4] * sharpness_width %>px" class="blue"></span>
|
||||||
|
<span style="width:<%= sharpness_plus[5] * sharpness_width %>px" class="white"></span>
|
||||||
|
<% if (sharpness_plus.length > 6) { %>
|
||||||
|
<span style="width:<%= sharpness_plus[6] * sharpness_width %>px" class="purple"></span>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
</td>
|
||||||
|
<td style="text-align:right"><%= phial %>
|
||||||
|
<% if (phial_value) { %><%= phial_value %><% } %>
|
||||||
|
</td>
|
||||||
|
<td style="text-align:right"><%= shelling_type %>
|
||||||
|
<% if (shelling_level) { %><%= shelling_level %><% } %>
|
||||||
|
</td>
|
||||||
|
<td style="text-align:right"><%= bug_level %></td>
|
||||||
|
<td><%= defense ? "+" + defense + " Def" : "" %></td>
|
||||||
115
web/templates/weaponstats-rise.ejs
Normal file
115
web/templates/weaponstats-rise.ejs
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
<table>
|
||||||
|
<tr title="<%= id %>">
|
||||||
|
<td><%= name %></td>
|
||||||
|
<td>(<%= wtype %>)</td>
|
||||||
|
<td><% if (phial) {
|
||||||
|
%><<%= phial %> Phial><%
|
||||||
|
} else if (shelling_type) {
|
||||||
|
%><<%= shelling_type %> <%= shelling_level %>><%
|
||||||
|
} else if (horn_notes) {
|
||||||
|
%><span title="<%= horn_melodies_title %>"
|
||||||
|
>[<%= horn_notes %>]<%
|
||||||
|
} %></td>
|
||||||
|
<td>[<%= slots %>]</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>Atk: <%= attack %></td>
|
||||||
|
<td style="text-align:right"><% if (affinity) { %><%= affinity %>%<% } %></td>
|
||||||
|
<td>
|
||||||
|
<% if (awaken) { %>
|
||||||
|
(<img style="height:.8em" title="Awaken <%= awaken %>"
|
||||||
|
src="/img/<%= awaken %>.png" /><%= awaken_attack %> <%= awaken %>)
|
||||||
|
<% } else if (element) { %>
|
||||||
|
<img style="height:.8em" title="<%= element %>"
|
||||||
|
src="/img/<%= element %>.png" /> <%= element_attack %>
|
||||||
|
<%= element %>
|
||||||
|
<% if (element_2) { %>
|
||||||
|
<img style="height:.8em" title="<%= element_2 %>"
|
||||||
|
src="/img/<%= element_2 %>.png" /> <%= element_2_attack %>
|
||||||
|
<%= element_2 %>
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
||||||
|
</td>
|
||||||
|
<td id="sharpness_td"
|
||||||
|
data-sharpness="<%= sharpness_all_title %>"
|
||||||
|
data-id="<%= id %>">
|
||||||
|
<% if (sharpness) { %>
|
||||||
|
<div class="sharpness-bar" title="<%= sharpness_all_title %>">
|
||||||
|
<span style="width:<%= sharpness[0] * sharpness_width %>px" class="red"></span>
|
||||||
|
<span style="width:<%= sharpness[1] * sharpness_width %>px" class="orange"></span>
|
||||||
|
<span style="width:<%= sharpness[2] * sharpness_width %>px" class="yellow"></span>
|
||||||
|
<span style="width:<%= sharpness[3] * sharpness_width %>px" class="green"></span>
|
||||||
|
<span style="width:<%= sharpness[4] * sharpness_width %>px" class="blue"></span>
|
||||||
|
<span style="width:<%= sharpness[5] * sharpness_width %>px" class="white"></span>
|
||||||
|
<% if (sharpness.length > 6) { %>
|
||||||
|
<span style="width:<%= sharpness[6] * sharpness_width %>px" class="purple"></span>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<div class="sharpness-bar" title="<%= sharpness_all_title %>">
|
||||||
|
<span style="width:<%= sharpness_plus[0] * sharpness_width %>px" class="red"></span>
|
||||||
|
<span style="width:<%= sharpness_plus[1] * sharpness_width %>px" class="orange"></span>
|
||||||
|
<span style="width:<%= sharpness_plus[2] * sharpness_width %>px" class="yellow"></span>
|
||||||
|
<span style="width:<%= sharpness_plus[3] * sharpness_width %>px" class="green"></span>
|
||||||
|
<span style="width:<%= sharpness_plus[4] * sharpness_width %>px" class="blue"></span>
|
||||||
|
<span style="width:<%= sharpness_plus[5] * sharpness_width %>px" class="white"></span>
|
||||||
|
<% if (sharpness.length > 6) { %>
|
||||||
|
<span style="width:<%= sharpness_plus[6] * sharpness_width %>px" class="purple"></span>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<% if (sharpness_plus2) { %>
|
||||||
|
<div class="sharpness-bar" title="<%= sharpness_all_title %>">
|
||||||
|
<span style="width:<%= sharpness_plus2[0] * sharpness_width %>px" class="red"></span>
|
||||||
|
<span style="width:<%= sharpness_plus2[1] * sharpness_width %>px" class="orange"></span>
|
||||||
|
<span style="width:<%= sharpness_plus2[2] * sharpness_width %>px" class="yellow"></span>
|
||||||
|
<span style="width:<%= sharpness_plus2[3] * sharpness_width %>px" class="green"></span>
|
||||||
|
<span style="width:<%= sharpness_plus2[4] * sharpness_width %>px" class="blue"></span>
|
||||||
|
<span style="width:<%= sharpness_plus2[5] * sharpness_width %>px" class="white"></span>
|
||||||
|
<% if (sharpness.length > 6) { %>
|
||||||
|
<span style="width:<%= sharpness_plus2[6] * sharpness_width %>px" class="purple"></span>
|
||||||
|
<% } %>
|
||||||
|
</div>
|
||||||
|
<% } %>
|
||||||
|
<% } %>
|
||||||
|
</td>
|
||||||
|
<td style="text-align:right"><% if (defense) { %>+<%= defense %> Def<% } %>
|
||||||
|
<% if (parent_name) { %>
|
||||||
|
<a href="weaponplanner.html?weapon=<%= encodeURIComponent(parent_name) %>"
|
||||||
|
title="<%= parent_name %>">(parent)</a>
|
||||||
|
<% } %>
|
||||||
|
</td>
|
||||||
|
|
||||||
|
<% if (village_stars) { %>
|
||||||
|
<td>
|
||||||
|
Village <%= village_stars %>
|
||||||
|
</td>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (guild_stars) { %>
|
||||||
|
<td>
|
||||||
|
Guild <%= guild_stars %>
|
||||||
|
</td>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
<% if (rarity) { %>
|
||||||
|
<td>
|
||||||
|
Rarity <%= rarity %>
|
||||||
|
</td>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
<% if (children.length) { %>
|
||||||
|
<table>
|
||||||
|
<tr><td colspan="5"> ->
|
||||||
|
<% for(var i=0; i<children.length; i++) { %>
|
||||||
|
<a href="weaponplanner.html?weapon=<%= encodeURIComponent(children[i]['name']) %>"
|
||||||
|
><%= children[i]["name"] %></a>
|
||||||
|
<% if (i != children.length - 1) { %>|<% } %>
|
||||||
|
<% } %>
|
||||||
|
</td></tr>
|
||||||
|
</table>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
@@ -81,17 +81,25 @@
|
|||||||
title="<%= parent_name %>">(parent)</a>
|
title="<%= parent_name %>">(parent)</a>
|
||||||
<% } %>
|
<% } %>
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
<% if (village_stars) { %>
|
<% if (village_stars) { %>
|
||||||
<td>
|
<td>
|
||||||
Village <%= village_stars %>
|
Village <%= village_stars %>
|
||||||
</td>
|
</td>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
<% if (guild_stars) { %>
|
<% if (guild_stars) { %>
|
||||||
<td>
|
<td>
|
||||||
Guild <%= guild_stars %>
|
Guild <%= guild_stars %>
|
||||||
</td>
|
</td>
|
||||||
<% } %>
|
<% } %>
|
||||||
|
|
||||||
|
<% if (rarity) { %>
|
||||||
|
<td>
|
||||||
|
Rarity <%= rarity %>
|
||||||
|
</td>
|
||||||
|
<% } %>
|
||||||
|
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<% if (children.length) { %>
|
<% if (children.length) { %>
|
||||||
|
|||||||
Reference in New Issue
Block a user