This commit is contained in:
Raatty 2018-08-26 11:00:22 +12:00
commit e5ab9245d6
8 changed files with 682 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.vscode
__pycache__
.vscode
.env
venv

1
Procfile Normal file
View File

@ -0,0 +1 @@
worker: python bot.py

132
bot.py Normal file
View File

@ -0,0 +1,132 @@
import logging
import discord
from discord.ext import commands
import datetime
import psycopg2
import os
import requests
logging.basicConfig(level=logging.INFO, style='{', datefmt="%d.%m.%Y %H:%M:%S",
format="\n{asctime} [{levelname:<8}] {name}:\n{message}")
def get_pre(bot, msg):
if msg.server.id in bot.prefixes.keys():
return bot.prefixes[msg.server.id]
else:
return '#!'
bot = commands.Bot(description="drpg warden", command_prefix=get_pre)
if 'DATABASE_URL' in os.environ:
bot.db_conn = psycopg2.connect(os.getenv('DATABASE_URL'))
else:
import heroku3
heroku_conn = heroku3.from_key(os.getenv('HEROKUAPI'))
db_url = heroku_conn.app('drpg-warden').config()['DATABASE_URL']
bot.db_conn = psycopg2.connect(db_url)
bot.prefixes = {}
with bot.db_conn:
with bot.db_conn.cursor() as cur:
cur.execute("SELECT * FROM prefixes;")
pref = cur.fetchall()
for i in pref:
bot.prefixes[i[0]] = i[1]
bot.remove_command('help')
@bot.command(pass_context=True)
async def help(ctx):
await bot.say("__**DRPG Warden: Help**__\n"
"I am a simple bot with only one real function and that is "
"to remind you about the various cooldowns of the bot "
"'DiscordRPG' and I am mostly fuctionless without it.\n"
"For the common DiscordRPG commands I will begin counting "
"and once the cooldown for that command has expired I will "
"mention you to remind you that you can do the command "
"again.\n"
"Also I will scan all the adventure messages from "
"DiscordRPG and if your HP is below 20% I'll remind you to "
"heal. Stats messages will also be scanned currently you "
"will only get info about your weapon.\n\n"
"**Currently implemented cooldowns:**\n"
" __14 seconds:__ {0}adv\n"
" __300 seconds:__ {0}mine, {0}chop, {0}fish, {0}forage\n"
" __600 seconds:__ {0}search\n"
" __various:__ {0}travel (you must of done {0}location "
"in the same channel within the last 30s, you will get "
"pinged when you arive)\n\n"
"My commands:\n"
" **{0}help** shows this message\n"
" **{0}links** shows a message with links to add me to "
"your server or join my server.\n"
" **{0}setprefix** allows you to change my prefix to "
"what ever you want, if you forget what you set as the "
"prefix and message that mentions me and contains the word "
"prefix I will reply with your current prefix\n\n"
"If you have any questions or sugestion contact my master "
"**raatty#3522**"
.format(ctx.prefix))
@bot.command()
async def links():
await bot.say('```Link to join my server:```\n'
'<https://discord.gg/SeGrSUP>\n'
'```Link to add me to your own server:```\n'
'<https://discordapp.com/oauth2/authorize?client_id='
'410356358836256768&permissions=0&scope=bot>')
@bot.command(pass_context=True)
async def announce(ctx, *, something):
if ctx.message.author.id == '140652945032216576':
for s in bot.servers:
for c in s.channels:
if c.permissions_for(s.me).send_messages \
and str(c.type) == 'text':
await bot.send_message(c, something)
break
@bot.command(pass_context=True)
async def setprefix(ctx, prefix):
if len(prefix) == 1 or len(prefix) == 2 and isinstance(prefix, str):
if ctx.message.server.id in bot.prefixes:
with bot.db_conn:
with bot.db_conn.cursor() as cur:
cur.execute("UPDATE prefixes SET prefix='{}' WHERE "
"serverid='{}';".format(prefix,
ctx.message.server.id))
bot.prefixes[ctx.message.server.id] = prefix
await bot.say('Prefix updated')
else:
with bot.db_conn:
with bot.db_conn.cursor() as cur:
cur.execute("INSERT INTO prefixes (serverid, prefix) "
"VALUES (%s, %s)", (ctx.message.server.id,
prefix))
bot.prefixes[ctx.message.server.id] = prefix
await bot.say('Prefix updated')
else:
await bot.say('Prefix must be between 1 and 2 charactors long')
@bot.event
async def on_ready():
bot.load_extension("drpg")
await bot.change_presence(game=discord.Game(name='#!adv', type=2))
await bot.send_message(discord.Object(id="408902143119196161"),
"**Im ready!** " + str(datetime.datetime.now()))
requests.post('https://bots.discord.pw/api/bots/410356358836256768/stats',
headers={"Authorization": os.getenv('BOTS_PW_AUTH')},
json={"server_count": len(bot.servers)})
await bot.send_message(discord.Object(id="408902143119196161"),
f'**Connected to {len(bot.servers)} servers**')
bot.run(os.getenv('TOKEN'))

93
drpg.py Normal file
View File

@ -0,0 +1,93 @@
import discord
from discord.ext import commands
import asyncio
from utils import read_adv, read_stats, read_travel, DEST_RE
class drpg:
def __init__(self, bot):
self.bot = bot
@commands.command(pass_context=True)
async def adv(self, ctx):
await asyncio.sleep(14)
await self.bot.say(f'🗺️ {ctx.message.author.mention} you can '
f'**{ctx.prefix}adv** again')
@commands.command(pass_context=True)
async def mine(self, ctx):
await asyncio.sleep(300)
await self.bot.say(f'⛏️ {ctx.message.author.mention} you can '
f'**{ctx.prefix}mine** again')
@commands.command(pass_context=True)
async def chop(self, ctx):
await asyncio.sleep(300)
await self.bot.say(f'🌲 {ctx.message.author.mention} you can '
f'**{ctx.prefix}chop** again')
@commands.command(pass_context=True)
async def fish(self, ctx):
await asyncio.sleep(300)
await self.bot.say(f'🎣 {ctx.message.author.mention} you can '
f'**{ctx.prefix}fish** again')
@commands.command(pass_context=True)
async def forage(self, ctx):
await asyncio.sleep(300)
await self.bot.say(f'🍋 {ctx.message.author.mention} you can '
f'**{ctx.prefix}forage** again')
@commands.command(pass_context=True)
async def search(self, ctx):
await asyncio.sleep(600)
await self.bot.say(f'🔍 {ctx.message.author.mention} you can '
f'**{ctx.prefix}search** again')
async def on_message(self, message: discord.Message):
if message.author.id == '170915625722576896':
if message.content.startswith('```diff\n!========['):
try:
usr, hp = read_adv(message.content)
if hp <= 50:
usr = message.server.get_member_named(usr)
msg = f"❤️ **Heal up!** {usr.mention} you only have "\
f"{hp:.2f}% HP left."
await self.bot.send_message(message.channel, msg)
except Exception as e:
raise
elif message.content.startswith('```diff\n!======== ['):
try:
out = read_stats(message.content)
if out is not None:
await self.bot.send_message(message.channel, out)
except Exception:
pass
elif message.embeds != []:
try:
user, destinations = read_travel(**message.embeds[0])
print(user)
def travel_check(message):
return message.author.id == '170915625722576896' and \
message.content.startswith(user)
travel = await self.bot.wait_for_message(timeout=30,
check=travel_check,
channel=message.channel)
user = message.server.get_member_named(user)
if travel is not None:
destination = DEST_RE.search(travel.content) \
.groups(0)[0]
await asyncio.sleep(destinations[destination])
m = f'{user.mention} you have arived at {destination}'
await self.bot.send_message(message.channel, m)
except Exception:
raise
elif message.server.me in message.mentions and \
'prefix' in message.content.lower():
m1 = '**The prefix for this server is currently set to:** {}'
m2 = m1.format(str(self.bot.command_prefix(self.bot, message)))
await self.bot.send_message(message.channel, m2)
def setup(bot):
bot.add_cog(drpg(bot))

373
items/weapons.json Normal file
View File

@ -0,0 +1,373 @@
[
{
"item": "Small Dagger",
"level": 1,
"price": "N/A",
"min dmg": 1,
"max dmg": 5
},
{
"item": " Iron Sword",
"level": 2,
"price": 100,
"min dmg": 2,
"max dmg": 6
},
{
"item": "Iron Mace",
"level": 3,
"price": 500,
"min dmg": 5,
"max dmg": 10
},
{
"item": "Iron Flail",
"level": 4,
"price": 750,
"min dmg": 7,
"max dmg": 12
},
{
"item": "Iron Battleaxe",
"level": 7,
"price": 2500,
"min dmg": 10,
"max dmg": 15
},
{
"item": "Golden Hammer",
"level": 10,
"price": 4500,
"min dmg": 13,
"max dmg": 18
},
{
"item": "Hammer of Gaia",
"level": 11,
"price": 7000,
"min dmg": 14,
"max dmg": 21
},
{
"item": "Enhanced Bow",
"level": 12,
"price": 9500,
"min dmg": 16,
"max dmg": 25
},
{
"item": "Claws",
"level": 12,
"price": 11000,
"min dmg": 18,
"max dmg": 25
},
{
"item": "Burning Super-Death Sword",
"level": 13,
"price": 13000,
"min dmg": 20,
"max dmg": 26
},
{
"item": "Sharpened Sickle",
"level": 14,
"price": 15500,
"min dmg": 27,
"max dmg": 31
},
{
"item": "Fancy Wand",
"level": 15,
"price": 19000,
"min dmg": 32,
"max dmg": 36
},
{
"item": "Damp Trident",
"level": 16,
"price": 22500,
"min dmg": 38,
"max dmg": 41
},
{
"item": "Bronze Gauntlets",
"level": 17,
"price": 26000,
"min dmg": 43,
"max dmg": 46
},
{
"item": "Scissorgloves",
"level": 18,
"price": 29500,
"min dmg": 48,
"max dmg": 52
},
{
"item": "Family Cutlass",
"level": 19,
"price": 32000,
"min dmg": 53,
"max dmg": 56
},
{
"item": "Magy's Scythe",
"level": 20,
"price": 35500,
"min dmg": 56,
"max dmg": 62
},
{
"item": "Ghostly Scimitar",
"level": 25,
"price": 49500,
"min dmg": 78,
"max dmg": 87
},
{
"item": "Hunters Sorrow",
"level": 30,
"price": 63500,
"min dmg": 100,
"max dmg": 112
},
{
"item": "Citrus Blade",
"level": 30,
"price": 66500,
"min dmg": 99,
"max dmg": 106
},
{
"item": "Peacemaker",
"level": 35,
"price": 79000,
"min dmg": 115,
"max dmg": 130
},
{
"item": "Orchid Sword",
"level": 40,
"price": 100000,
"min dmg": 132,
"max dmg": 144
},
{
"item": "Light Longbow of Mourning",
"level": 45,
"price": 121875,
"min dmg": 153,
"max dmg": 167
},
{
"item": "Conjurer's Foresight",
"level": 50,
"price": 143750,
"min dmg": 175,
"max dmg": 190
},
{
"item": "Fearsome Rust Axe of Hunting",
"level": 55,
"price": 165625,
"min dmg": 192,
"max dmg": 213
},
{
"item": "Beserk Stone Axe of Hunting",
"level": 60,
"price": 187500,
"min dmg": 209,
"max dmg": 236
},
{
"item": "Chivalic Rapier",
"level": 75,
"price": 200000,
"min dmg": 200,
"max dmg": 222
},
{
"item": "Flintlock Pistol",
"level": 80,
"price": 230000,
"min dmg": 245,
"max dmg": 270
},
{
"item": "Zangetsu",
"level": 90,
"price": 432432,
"min dmg": 119,
"max dmg": 461
},
{
"item": "Die",
"level": 91,
"price": 654321,
"min dmg": 0,
"max dmg": 600
},
{
"item": "Schwarz Sieben Prototype Mk III",
"level": 95,
"price": 255000,
"min dmg": 260,
"max dmg": 290
},
{
"item": "Force Mithril Greatsword",
"level": 120,
"price": 350000,
"min dmg": 310,
"max dmg": 360
},
{
"item": "Astral Rod",
"level": 142,
"price": 555555,
"min dmg": 377,
"max dmg": 433
},
{
"item": "Sadist's Scythe's Return",
"level": 156,
"price": 666666,
"min dmg": 449,
"max dmg": 541
},
{
"item": "Spear of Indra",
"level": 200,
"price": 1000000,
"min dmg": 600,
"max dmg": 666
},
{
"item": "Z-Saber",
"level": 250,
"price": 1600000,
"min dmg": 740,
"max dmg": 830
},
{
"item": "Iron Tomahawk",
"level": 300,
"price": 3050000,
"min dmg": 895,
"max dmg": 1019
},
{
"item": "Polished Obsidian Battle-axe",
"level": 350,
"price": 4500000,
"min dmg": 1050,
"max dmg": 1208
},
{
"item": "Engraved Silver Musket",
"level": 400,
"price": 6000000,
"min dmg": 1200,
"max dmg": 1389
},
{
"item": "Toast",
"level": 420,
"price": 8888888,
"min dmg": 855,
"max dmg": 1666
},
{
"item": "Menacing Bardiche of Bloodletting",
"level": 450,
"price": 7800000,
"min dmg": 1350,
"max dmg": 1550
},
{
"item": "Purple Blade Return",
"level": 500,
"price": 10000000,
"min dmg": 1500,
"max dmg": 1750
},
{
"item": "Elegant Spiked War Mace",
"level": 550,
"price": 12000000,
"min dmg": 1700,
"max dmg": 1981
},
{
"item": "Massive Greatsword of Striking",
"level": 600,
"price": 16000000,
"min dmg": 1950,
"max dmg": 2262
},
{
"item": "Crystal Flail",
"level": 650,
"price": 22222222,
"min dmg": 2222,
"max dmg": 2499
},
{
"item": "Titanium Axe",
"level": 700,
"price": 29876543,
"min dmg": 2444,
"max dmg": 2753
},
{
"item": "Crystalline Musket",
"level": 750,
"price": 37373737,
"min dmg": 2666,
"max dmg": 2963
},
{
"item": "Pitchfork",
"level": 800,
"price": 47777777,
"min dmg": 2888,
"max dmg": 3222
},
{
"item": "Machete",
"level": 850,
"price": 58642085,
"min dmg": 3111,
"max dmg": 3444
},
{
"item": "Claymore",
"level": 900,
"price": 70123456,
"min dmg": 3333,
"max dmg": 3693
},
{
"item": "Halberd",
"level": 950,
"price": 83333333,
"min dmg": 3555,
"max dmg": 3939
},
{
"item": "War Hammer",
"level": 1000,
"price": 100010001,
"min dmg": 3842,
"max dmg": 4242
},
{
"item": "Crystal Cutlass",
"level": 1500,
"price": 266776681,
"min dmg": 6712,
"max dmg": 7272
}
]

3
requirements.txt Normal file
View File

@ -0,0 +1,3 @@
discord.py
psycopg2-binary
requests

1
runtime.txt Normal file
View File

@ -0,0 +1 @@
python-3.6.6

74
utils.py Normal file
View File

@ -0,0 +1,74 @@
import re
import json
USERREGEX = re.compile(r'!(=)+\[ (.+)\'s Adventure \](=)+!')
HPSREGEX = re.compile(r'[0-9,]+/[0-9,]+')
def read_adv(content):
try:
hps = HPSREGEX.findall(content)
hp = hps[1].replace(',', '').split("/")
hppercent = int(hp[0]) / int(hp[1]) * 100
usr = USERREGEX.search(content)
usr = usr.group(2)
return usr, hppercent
except Exception:
pass
STATSUSERRE = re.compile(r'!=+ \[(.+)\'s Stats\] =+!')
LEVELRE = re.compile(r'Level (\d+)')
WEAPRE = re.compile(r'Weapon: (.+)')
with open('items/weapons.json') as f:
WEAPONS = json.loads(f.read())
def read_stats(content):
try:
user = STATSUSERRE.search(content).groups(0)[0]
weap = WEAPRE.search(content).groups(0)[0]
for i in WEAPONS:
if i['item'] == weap:
weap = i
break
level = LEVELRE.search(content).groups(0)[0]
for i in WEAPONS[::-1]:
if i['level'] <= int(level):
if i['level'] != weap['level']:
new_weap = i
break
else:
new_weap = None
break
if new_weap is not None:
out = f'```{user}\'s Weapon\n' \
f'Name: {weap["item"]} Maxhit: '\
f'{weap["max dmg"]} Minhit: {weap["min dmg"]}\n'\
f'You should upgrade to {new_weap["item"]} ' \
f'costing {new_weap["price"]}gold with ' \
f'a max hit of {new_weap["max dmg"]} and a ' \
f'min hit of {new_weap["min dmg"]}```'
else:
out = f'```{user}\'s Weapon\n' \
f'Name: {weap["item"]} ' \
f'Maxhit: {weap["max dmg"]} ' \
f'Minhit: {weap["min dmg"]}\n' \
f'Your weapon seems correct for your level```'
return out
except Exception:
pass
LOC_USR_RE = re.compile(r'(.+)\'s location')
CLEAN_DEST_RE = re.compile(r'([A-Za-z \']+) - (\d+)s')
def read_travel(title, fields, **kwargs):
if title.endswith('location') and fields[0]["name"] == "Kingdom":
rawdestinations = fields[1]["value"].split('\n')
desetinations = {i[0]: int(i[1])
for i in [CLEAN_DEST_RE.search(i).groups()
for i in rawdestinations]}
user = LOC_USR_RE.search(title).groups(0)[0]
return user, desetinations
DEST_RE = re.compile(r'started their journey to ([A-Za-z \']+)!')