Post pug.py
This cog is a port of Pugbot (https://github.com/reznok/PugBot), so that it can work with Red-DiscordBot as a plugin.
This commit is contained in:
258
pug/pug.py
Normal file
258
pug/pug.py
Normal file
@@ -0,0 +1,258 @@
|
||||
import json
|
||||
import os
|
||||
import requests
|
||||
from .utils.dataIO import dataIO
|
||||
from __main__ import send_cmd_help
|
||||
from discord.ext import commands
|
||||
from .utils import checks
|
||||
|
||||
class Pug:
|
||||
|
||||
def __init__(self, bot):
|
||||
self.bot = bot
|
||||
self.settings = dataIO.load_json("data/pug/config.json")
|
||||
self.fp = "data/pug/config.json"
|
||||
API_KEY = self.settings["blizzard_api_key"]
|
||||
default_region = self.settings["default_region"]
|
||||
|
||||
LEG_WITH_SOCKET = [
|
||||
132369, 132410, 137044, 132444, 132449, 132452, 132460, 133973, 133974, 137037, 137038, 137039, 137040,
|
||||
137041, 137042, 137043, 132378, 137045, 137046, 137047, 137048, 137049, 137050, 137051, 137052, 137054, 137055,
|
||||
137220, 137223, 137276, 137382, 138854
|
||||
]
|
||||
|
||||
ENCHANTABLE_SLOTS = ["neck", "back", "finger1", "finger2"]
|
||||
|
||||
region_locale = {
|
||||
'us': ['us', 'en_US', 'en'],
|
||||
# 'kr': ['kr', 'ko_KR', 'ko'],
|
||||
# 'tw': ['tw', 'zh_TW', 'zh'],
|
||||
'eu': ['eu', 'en_GB', 'en']
|
||||
}
|
||||
|
||||
def get_sockets(self, player_dictionary):
|
||||
"""
|
||||
Return dict with total sockets and count of equipped gems and slots that are missing
|
||||
|
||||
:param player_dictionary: Retrieved player dict from API
|
||||
:return: dict()
|
||||
"""
|
||||
sockets = 0
|
||||
equipped_gems = 0
|
||||
|
||||
for item in player_dictionary["items"]:
|
||||
if item in "averageItemLevel" or item in "averageItemLevelEquipped":
|
||||
continue
|
||||
|
||||
if int(player_dictionary["items"][item]["id"]) in self.LEG_WITH_SOCKET:
|
||||
sockets += 1
|
||||
|
||||
for bonus in player_dictionary["items"][item]["bonusLists"]:
|
||||
if bonus == 1808: # 1808 is Legion prismatic socket bonus
|
||||
sockets += 1
|
||||
|
||||
for ttip in player_dictionary["items"][item]["tooltipParams"]:
|
||||
if item in "mainHand" or item in "offHand": # Ignore Relic
|
||||
continue
|
||||
if "gem" in ttip: # Equipped gems are listed as gem0, gem1, etc...
|
||||
equipped_gems += 1
|
||||
|
||||
return {"total_sockets": sockets,
|
||||
"equipped_gems": equipped_gems}
|
||||
|
||||
|
||||
def get_enchants(self, player_dictionary):
|
||||
"""
|
||||
Get count of enchants missing and slots that are missing
|
||||
:param player_dictionary:
|
||||
:return: dict()
|
||||
"""
|
||||
self.missing_enchant_slots = []
|
||||
for slot in self.ENCHANTABLE_SLOTS:
|
||||
if "enchant" not in player_dictionary["items"][slot]["tooltipParams"]:
|
||||
self.missing_enchant_slots.append(slot)
|
||||
|
||||
return {
|
||||
"enchantable_slots": len(self.ENCHANTABLE_SLOTS),
|
||||
"missing_slots": self.missing_enchant_slots,
|
||||
"total_missing": len(self.missing_enchant_slots)
|
||||
}
|
||||
|
||||
|
||||
def get_raid_progression(self, player_dictionary, raid):
|
||||
r = [x for x in player_dictionary["progression"]
|
||||
["raids"] if x["name"] in raid][0]
|
||||
normal = 0
|
||||
heroic = 0
|
||||
mythic = 0
|
||||
|
||||
for boss in r["bosses"]:
|
||||
if boss["normalKills"] > 0:
|
||||
normal += 1
|
||||
if boss["heroicKills"] > 0:
|
||||
heroic += 1
|
||||
if boss["mythicKills"] > 0:
|
||||
mythic += 1
|
||||
|
||||
return {"normal": normal,
|
||||
"heroic": heroic,
|
||||
"mythic": mythic,
|
||||
"total_bosses": len(r["bosses"])}
|
||||
|
||||
|
||||
def get_mythic_progression(self, player_dictionary):
|
||||
achievements = player_dictionary["achievements"]
|
||||
plus_two = 0
|
||||
plus_five = 0
|
||||
plus_ten = 0
|
||||
|
||||
if 33096 in achievements["criteria"]:
|
||||
index = achievements["criteria"].index(33096)
|
||||
plus_two = achievements["criteriaQuantity"][index]
|
||||
|
||||
if 33097 in achievements["criteria"]:
|
||||
index = achievements["criteria"].index(33097)
|
||||
plus_five = achievements["criteriaQuantity"][index]
|
||||
|
||||
if 33098 in achievements["criteria"]:
|
||||
index = achievements["criteria"].index(33098)
|
||||
plus_ten = achievements["criteriaQuantity"][index]
|
||||
|
||||
return {
|
||||
"plus_two": plus_two,
|
||||
"plus_five": plus_five,
|
||||
"plus_ten": plus_ten
|
||||
}
|
||||
|
||||
def get_char(self, name, server, target_region):
|
||||
self.settings = dataIO.load_json("data/pug/config.json") # Load Configs
|
||||
API_KEY = self.settings["blizzard_api_key"]
|
||||
r = requests.get("https://%s.api.battle.net/wow/character/%s/%s?fields=items+progression+achievements&locale=%s&apikey=%s" % (
|
||||
self.region_locale[target_region][0], server, name, self.region_locale[target_region][1], API_KEY))
|
||||
|
||||
if r.status_code != 200:
|
||||
raise Exception("Could not find character (No 200 from API).")
|
||||
|
||||
player_dict = json.loads(r.text)
|
||||
|
||||
r = requests.get(
|
||||
"https://%s.api.battle.net/wow/data/character/classes?locale=%s&apikey=%s" % (
|
||||
self.region_locale[target_region][0], self.region_locale[target_region][1], API_KEY))
|
||||
if r.status_code != 200:
|
||||
raise Exception("Could Not Find Character Classes (No 200 From API)")
|
||||
class_dict = json.loads(r.text)
|
||||
class_dict = {c['id']: c['name'] for c in class_dict["classes"]}
|
||||
|
||||
equipped_ivl = player_dict["items"]["averageItemLevelEquipped"]
|
||||
sockets = self.get_sockets(player_dict)
|
||||
enchants = self.get_enchants(player_dict)
|
||||
tov_progress = self.get_raid_progression(player_dict, "Trial of Valor")
|
||||
en_progress = self.get_raid_progression(player_dict, "The Emerald Nightmare")
|
||||
mythic_progress = self.get_mythic_progression(player_dict)
|
||||
|
||||
armory_url = 'http://{}.battle.net/wow/{}/character/{}/{}/advanced'.format(
|
||||
self.region_locale[target_region][0], self.region_locale[target_region][2], server, name)
|
||||
|
||||
return_string = ''
|
||||
return_string += "**%s** - **%s** - **%s %s**\n" % (
|
||||
name.title(), server.title(), player_dict['level'], class_dict[player_dict['class']])
|
||||
return_string += '<{}>\n'.format(armory_url)
|
||||
return_string += '```prolog\n' # start Markdown
|
||||
|
||||
# iLvL
|
||||
return_string += "Equipped Item Level: %s\n" % equipped_ivl
|
||||
|
||||
# Mythic Progression
|
||||
return_string += "Mythics: +2: %s, +5: %s, +10: %s\n" % (mythic_progress["plus_two"],
|
||||
mythic_progress["plus_five"],
|
||||
mythic_progress["plus_ten"])
|
||||
|
||||
# Raid Progression
|
||||
return_string += "EN: {1}/{0} (N), {2}/{0} (H), {3}/{0} (M)\n".format(en_progress["total_bosses"],
|
||||
en_progress["normal"],
|
||||
en_progress["heroic"],
|
||||
en_progress["mythic"])
|
||||
return_string += "TOV: {1}/{0} (N), {2}/{0} (H), {3}/{0} (M)\n".format(tov_progress["total_bosses"],
|
||||
tov_progress["normal"],
|
||||
tov_progress["heroic"],
|
||||
tov_progress["mythic"])
|
||||
|
||||
# Gems
|
||||
return_string += "Gems Equipped: %s/%s\n" % (
|
||||
sockets["equipped_gems"], sockets["total_sockets"])
|
||||
|
||||
# Enchants
|
||||
return_string += "Enchants: %s/%s\n" % (enchants["enchantable_slots"] - enchants["total_missing"],
|
||||
enchants["enchantable_slots"])
|
||||
if enchants["total_missing"] > 0:
|
||||
return_string += "Missing Enchants: {0}".format(
|
||||
", ".join(enchants["missing_slots"]))
|
||||
|
||||
return_string += '```' # end Markdown
|
||||
return return_string
|
||||
|
||||
@commands.command(name="pug", pass_context=True, no_pm=True)
|
||||
async def _pug(self, ctx, *, message):
|
||||
"""A Warcraft Armory character lookup tool.
|
||||
Use: !pug <name> <server> <region>
|
||||
Hyphenate two-word servers (Ex: Twisting-Nether)."""
|
||||
self.settings = dataIO.load_json("data/pug/config.json") # Load Configs
|
||||
default_region = self.settings["default_region"]
|
||||
target_region = default_region
|
||||
channel = ctx.message.channel
|
||||
try:
|
||||
i = str(ctx.message.content).split(' ')
|
||||
name = i[1]
|
||||
server = i[2]
|
||||
if len(i) == 4 and i[3].lower() in self.region_locale.keys():
|
||||
target_region = i[3].lower()
|
||||
character_info = self.get_char(name, server, target_region)
|
||||
await self.bot.send_message(ctx.message.channel, character_info)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
await self.bot.send_message(ctx.message.channel, "Error with character name or server.\n"
|
||||
"Use: !pug <name> <server> <region>\n"
|
||||
"Hyphenate two-word servers (Ex: Wyrmrest-Accord).")
|
||||
|
||||
@commands.command(pass_context=True, name='pugtoken')
|
||||
@checks.is_owner()
|
||||
async def _pugtoken(self, context, key: str):
|
||||
"""Sets the token for the Blizzard API.
|
||||
You can use this command in a private message to the bot.
|
||||
|
||||
Get an API token at: https://dev.battle.net/member/register"""
|
||||
settings = dataIO.load_json(self.fp)
|
||||
settings['blizzard_api_key'] = key
|
||||
dataIO.save_json(self.fp, settings)
|
||||
await self.bot.say("API key set.")
|
||||
|
||||
@commands.command()
|
||||
async def pugcredits(self):
|
||||
"""Code credits."""
|
||||
message = await self._credit()
|
||||
await self.bot.say(message)
|
||||
|
||||
async def _credit(self):
|
||||
message = "```This cog is made possible by Pugbot.\n"
|
||||
message+= "Please visit https://github.com/reznok/PugBot for more information.\n"
|
||||
message+= "```"
|
||||
return message
|
||||
|
||||
def check_folders():
|
||||
if not os.path.exists("data/pug"):
|
||||
print("Creating data/pug folder...")
|
||||
os.mkdir("data/pug")
|
||||
|
||||
|
||||
def check_files():
|
||||
fp = "data/pug/config.json"
|
||||
if not dataIO.is_valid_json(fp):
|
||||
print("Creating config.json...")
|
||||
dataIO.save_json(fp, {"blizzard_api_key": "", "default_region": "us"})
|
||||
|
||||
|
||||
def setup(bot):
|
||||
check_folders()
|
||||
check_files()
|
||||
n = Pug(bot)
|
||||
bot.add_cog(n)
|
||||
Reference in New Issue
Block a user