diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..3007d9f --- /dev/null +++ b/COPYING @@ -0,0 +1,20 @@ +Copyright (c) 2015 Bryce Allen + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/db/COPYING.mh4udb b/db/COPYING.mh4udb new file mode 100644 index 0000000..7e4a21f --- /dev/null +++ b/db/COPYING.mh4udb @@ -0,0 +1,23 @@ +The monster hunter db is taken from MonsterHUnter4UDatabase by DavianCorp, +which is also MIT licensed. Thanks to everyone who helped build the db and +the DavianCorp developers! License below: + +Copyright (c) 2014 DavianCorp + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/db/mh4u.db b/db/mh4u.db new file mode 100644 index 0000000..260a398 Binary files /dev/null and b/db/mh4u.db differ diff --git a/mhdb.py b/mhdb.py index 36f6a74..ebd1495 100755 --- a/mhdb.py +++ b/mhdb.py @@ -1,3 +1,9 @@ +""" +Module for accessing the sqlite monster hunter db from +""" + +import string + import sqlite3 @@ -6,15 +12,22 @@ class Quest(object): self._row = quest_row self._rewards = quest_rewards + self._template = string.Template( + "$name ($hub $stars* $rank)" + + "\n Goal: $goal" + + "\n Sub : $sub_goal" + ) + self.id = quest_row["_id"] self.name = quest_row["name"] self.stars = quest_row["stars"] self.hub = quest_row["hub"] self.goal = quest_row["goal"] + self.sub_goal = quest_row["sub_goal"] self.rank = get_rank(self.hub, self.stars) - def __str__(self): - return "%s (%s %s* %s)" % (self.name, self.hub, self.stars, self.rank) + def __unicode__(self): + return self._template.substitute(self.__dict__) def get_rank(hub, stars): @@ -54,35 +67,49 @@ class MHDB(object): SELECT * FROM items WHERE _id=? """, item_id) - return v[0] + return v[0] if v else None def get_item_by_name(self, name): v = self._get_memoized("item", """ SELECT * FROM items WHERE name=? """, name) - return v[0] + return v[0] if v else None + + def search_item_name(self, term, item_type): + """ + Search for items containing @term somewhere in the name. Returns + list of matching items. + + Not memoized. + """ + cursor = self.conn.execute(""" + SELECT * FROM items + WHERE name LIKE ? + AND type = ? + """, ("%%%s%%" % term, item_type)) + return cursor.fetchall() def get_monster_by_name(self, name): v = self._get_memoized("monster", """ SELECT * FROM monsters WHERE name=? """, name) - return v[0] + return v[0] if v else None def get_monster(self, monster_id): v = self._get_memoized("monster", """ SELECT * FROM monsters WHERE _id=? """, monster_id) - return v[0] + return v[0] if v else None def get_quest(self, quest_id): v = self._get_memoized("quest", """ SELECT * FROM quests WHERE _id=? """, quest_id) - return v[0] + return v[0] if v else None def get_quest_rewards(self, quest_id): v = self._get_memoized("quest_rewards", """ @@ -105,7 +132,12 @@ class MHDB(object): """, quest_id) return v - def get_item_quests(self, item_id): + def get_item_quest_objects(self, item_id): + """ + Get a list of quests that provide the specified item in quest + reqards. Returns a list of quest objects, which encapsulate the + quest details and the list of rewards. + """ cursor = self.conn.execute(""" SELECT DISTINCT quest_id FROM quest_rewards WHERE item_id=? diff --git a/mhrewards.py b/mhrewards.py index f2419d7..924ac36 100755 --- a/mhrewards.py +++ b/mhrewards.py @@ -1,9 +1,14 @@ #!/usr/bin/env python +from __future__ import print_function +import codecs + import mhdb import mhprob -db = mhdb.MHDB("mh4u.db") + +def get_utf8_writer(writer): + return codecs.getwriter("utf8")(writer) def _format_range(min_v, max_v): @@ -13,17 +18,35 @@ def _format_range(min_v, max_v): return "%5.2f%% to %5.2f%%" % (min_v, max_v) -def get_quests(item_name): +def find_item(db, item_name, out): + item_row = db.get_item_by_name(item_name) + if item_row is None: + print("Item '%s' not found. Listing partial matches:" % item_name, + file=out) + terms = item_name.split() + for term in terms: + if len(term) < 2: + # single char terms aren't very useful, too many results + continue + print("= Matching term '%s'" % term, file=out) + rows = db.search_item_name(term, "Flesh") + for row in rows: + print(" ", row["name"], file=out) + return None + return item_row + + +def print_quests_and_rewards(db, item_name, out): """ 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. """ item_row = db.get_item_by_name(item_name) item_id = item_row["_id"] - quests = db.get_item_quests(item_id) + quests = db.get_item_quest_objects(item_id) for q in quests: - print q - print " %20s" % "= Quest" + out.write(unicode(q) + "\n") + out.write(" %20s" % "= Quest\n") quest_ev = 0 sub_used = False @@ -42,8 +65,8 @@ def get_quests(item_name): # sanity check values from the db for slot in total_reward_p.keys(): if total_reward_p[slot] not in (0, 100): - print "WARNING: bad total p for %s = %d" \ - % (slot, total_reward_p[slot]) + print("WARNING: bad total p for %s = %d" + % (slot, total_reward_p[slot]), file=sys.stderr) for reward in q._rewards: slot = reward["reward_slot"] @@ -59,13 +82,13 @@ def get_quests(item_name): * reward["stack_size"] * reward["percentage"]) for i in totals] - print " %20s %d %5.2f%%" % (reward["reward_slot"], - reward["stack_size"], - evs[0]), - print " (%2d%% each)" % reward["percentage"], + out.write(" %20s %d %5.2f%%" % (reward["reward_slot"], + reward["stack_size"], + evs[0])) + out.write(" (%2d%% each)" % reward["percentage"]) if len(totals) > 1: - print " %s" % " ".join("%0.2f" % i for i in evs[1:]), - print + out.write(" %s" % " ".join("%0.2f" % i for i in evs[1:])) + out.write("\n") quest_ev += evs[0] if reward["reward_slot"] == "Sub": @@ -78,7 +101,7 @@ def get_quests(item_name): for m in monsters: mid = m["monster_id"] monster = db.get_monster(mid) - print " %20s" % ("= " + monster["name"] + " " + q.rank) + out.write(" %20s\n" % ("= " + monster["name"] + " " + q.rank)) rewards = db.get_monster_rewards(mid, q.rank) for reward in rewards: cap = kill = shiny = False @@ -129,23 +152,37 @@ def get_quests(item_name): if shiny: shiny_ev += evs[0] - print " %20s %d %5.2f%%" % (reward["condition"], - reward["stack_size"], - evs[0]), - print " (%2d%% each)" % reward["percentage"], + out.write(" %20s %d %5.2f%%" % (reward["condition"], + reward["stack_size"], + evs[0])) + out.write(" (%2d%% each)" % reward["percentage"]) if len(totals) > 1: - print " %s" % " ".join("%0.2f" % i for i in evs[1:]), - print - print " %20s" % "= Totals" - print " %20s %s" % \ - ("Kill", _format_range(*kill_ev)) - print " %20s %s" % \ - ("Cap", _format_range(*cap_ev)) - print " %20s %5.2f%%" % ("Shiny", shiny_ev) - print + out.write(" " + " ".join("%0.2f" % i for i in evs[1:])) + out.write("\n") + out.write(" %20s\n" % "= Totals") + out.write(" %20s %s\n" % ("Kill", _format_range(*kill_ev))) + out.write(" %20s %s\n" % ("Cap", _format_range(*cap_ev))) + out.write(" %20s %5.2f%%\n" % ("Shiny", shiny_ev)) + out.write("\n") if __name__ == '__main__': import sys + import os.path + + if len(sys.argv) != 2: + print("Usage: %s 'item name'" % sys.argv[0]) + sys.exit(1) + + item_name = sys.argv[1] + + out = get_utf8_writer(sys.stdout) + + # TODO: doesn't work if script is symlinked + db_path = os.path.dirname(sys.argv[0]) + db_path = os.path.join(db_path, "db", "mh4u.db") + db = mhdb.MHDB(db_path) - get_quests(sys.argv[1]) + item_row = find_item(db, item_name, out) + if item_row is not None: + print_quests_and_rewards(db, item_name, out)