Skip to content
This repository has been archived by the owner on Jun 27, 2019. It is now read-only.

Commit

Permalink
Merge pull request #114 from Galarzaa90/dev
Browse files Browse the repository at this point in the history
Version 1.4
  • Loading branch information
Galarzaa90 authored Jul 24, 2018
2 parents 1f577b5 + 82973be commit 296a14c
Show file tree
Hide file tree
Showing 65 changed files with 820 additions and 880 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ loot/
token.txt

/data/*
!/data/loot_template.db
!/data/loot.db
!/data/tibia_database.db
!/data/tibia_worlds.json
!/data/config_template.yml
Expand All @@ -21,4 +21,4 @@ extra/*.py
!/extra/tibiammo.py

# Mkdocs built site
site/
site/
29 changes: 29 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,33 @@
# Changelog
## Version 1.4.0 (2018-07-24)
- `/loot` has been rewritten:
- Loot database remade from scratch with images extracted directly from the client, all images should now be pixel perfect matches to those taken from in-game screenshots
- Priority values for items were removed so database can be updated directly (no longer requires template database)
- Quality checks removed, now expects pixel perfect images (compressed images or screenshots taken using the software renderer won't be scanned at all).
- Number scan updated to properly handle stacks higher than three digits (mostly to be able to scan images taken from the stash, also recognizes the letter K in stack numbers)
- Now properly scans slots even if a few pixels at the bottom were cut off or blocked by the window border.
- Massive performance improvements.
- Minimum announce level is now configurable per server (`/settings minlevel`).
- Event channel is now disabled by default.
- New configurable emoji: `loading_emoji`
- By default ⏳ is used.
- Removed restart scripts as they were outdated, very platform specific and bad practice.
- Improved world scanning speed to not be heavily affected by the number of tracked worlds.
- New `/sql` command, executes a sql query and shows the results, only for the bot owner.
- New `/wikistats` command, shows you information about the TibiaWiki database used.
- `/removechar` now only lets you remove chars from users that are only in servers you are an admin in.
- Fixed bug in `/event make` showing failure icon on success.
- Fixed bug in `/addchar`, it was not working at all.
- Fixed bug in `/world` when query included spaces.
- Fixed bug in `/monster` failing if it was missing some bestiary data.
- Fixed bug in `/event addplayer` failing when the character was not registered.
- Fixed error when using `/share` with no parameters.
- Fixed bug in commands that offer you choices not working in commands channel.
- Fixed bug in `/choose` when the command was used with no parameters.
- `/stamina` now considers the 10 minutes you have to be logged off to start regenerating stamina.
- Removed `/restart` command as it was really system specific and not an universal solution, along with the autorestarting launchers.
- Command error now contains a link to the support server.

## Version 1.3.2 (2018-07-15)
- Monster's occurence was being displayed incorrectly.
- Updated database to show better update information.
Expand Down
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# NabBot
Nab Bot is a discord bot that uses [Rapptz's discord.py](https://github.com/Rapptz/discord.py). It features commands related to the MMORPG [Tibia](http://www.tibia.com/news/?subtopic=latestnews).

Expand All @@ -7,7 +6,15 @@ Nab Bot is a discord bot that uses [Rapptz's discord.py](https://github.com/Rapp
[![GitHub release](https://img.shields.io/github/release/Galarzaa90/NabBot.svg)](https://github.com/Galarzaa90/NabBot/releases)
[![Discord](https://img.shields.io/discord/441991938200305674.svg)](https://discord.gg/NmDvhpY)

## Requirements
[![Discord Bots](https://discordbots.org/api/widget/178966653982212096.svg)](https://discordbots.org/bot/178966653982212096)

## Adding NabBot
To add NabBot to your server, check out its page at [Discord Bots](https://discordbots.org/bot/178966653982212096)
and click the **Invite** button. Also remember to **Vote**.

## Hosting NabBot
You can also host your own instance of NabBot.
### Requirements
- Python 3.6
- Python modules:
- [discord.py (rewrite branch)](https://github.com/Rapptz/discord.py/tree/rewrite)
Expand All @@ -17,19 +24,9 @@ Nab Bot is a discord bot that uses [Rapptz's discord.py](https://github.com/Rapp
- pyYAML
- git

## Installing and running
### Installing and running
Follow the [install guide](https://galarzaa90.github.io/NabBot/install/) on the official documentation site.

## Current features
- Characters and guilds lookup.
- Linking characters to discord users.
- Level up and deaths announcements.
- Event management, create timed events with announcements.
- Keeps track of registered character's deaths and level ups as a log.
- Watched list, add characters or guilds to check their online status all the time.
- Information commands, based on TibiaWiki articles. Items, monsters, NPCs, houses and more.
- Joinable roles, create roles that any member can join or leave.
- Autoroles, create roles that are assigned to users automatically based on their registered characters.

## Documentation
See https://galarzaa90.github.io/NabBot/
Expand All @@ -40,7 +37,11 @@ Visit our support server
[![Support Server](https://discordapp.com/api/guilds/441991938200305674/embed.png)](https://discord.gg/NmDvhpY)

## Donate
If you like Nab Bot, you can donate to this project. NabBot and the developers will appreciate it :)
If you like NabBot, you can donate to this project. NabBot and the developers will appreciate it :)


[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=B33DCPZ9D3GMJ)



*[Tibia](http://tibia.com) is made by [CipSoft](https://www.cipsoft.com/), all game related images are copyrighted by [CipSoft GmbH](https://www.cipsoft.com/).*
76 changes: 43 additions & 33 deletions cogs/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,6 @@ async def add_account(self, ctx: NabCtx, *, params):
conn.execute("UPDATE users SET name = ? WHERE id = ?", (target.display_name, target.id,))

await ctx.send(reply)
print(log_reply)
for server_id, message in log_reply.items():
if message:
message = f"{target.mention} registered:" + message
Expand All @@ -176,18 +175,17 @@ async def add_account(self, ctx: NabCtx, *, params):
@checks.is_tracking_world()
@commands.command(name="addchar", aliases=["registerchar"], usage="<user>,<character>")
async def add_char(self, ctx: NabCtx, *, params):
"""Registers a character to a user."""
"""Registers a character to a user.
The character must be in the world you're tracking.
If the desired character is already assigned to someone else, the user must use `claim`."""
params = params.split(",")
if len(params) != 2:
raise commands.BadArgument()

if ctx.world is None:
await ctx.send("This server is not tracking any worlds.")
return

user = self.bot.get_member(params[0], ctx.guild)
if user is None:
await ctx.send("I don't see any user named **{0}** in this server.".format(params[0]))
return await ctx.send(f"{ctx.tick(False)} I don't see any user named **{params[0]}** in this server.")
user_servers = self.bot.get_user_guilds(user.id)

with ctx.typing():
Expand Down Expand Up @@ -295,48 +293,60 @@ async def checkchannel(self, ctx: NabCtx, *, channel: discord.TextChannel = None
content += f"\n{ctx.tick(True)} All permissions are correct!"
await ctx.send(content)


@checks.is_admin()
@checks.is_tracking_world()
@commands.command(name="removechar", aliases=["deletechar", "unregisterchar"])
async def remove_char(self, ctx: NabCtx, *, name):
"""Removes a registered character."""
"""Removes a registered character.
Note that you can only remove chars if they are from users exclusively in your server.
You can't remove any characters that would alter other servers NabBot is in."""
# This could be used to remove deleted chars so we don't need to check anything
# Except if the char exists in the database...
c = userDatabase.cursor()
try:
c.execute("SELECT name, user_id, world, ABS(level) as level, vocation, guild "
c.execute("SELECT name, user_id, world, guild, abs(level) as level, vocation "
"FROM chars WHERE name LIKE ?", (name,))
result = c.fetchone()
if result is None or result["user_id"] == 0:
await ctx.send("There's no character with that name registered.")
return
return await ctx.send("There's no character with that name registered.")
if result["world"] != ctx.world:
return await ctx.send(f"{ctx.tick(False)} The character **{result['name']}** is in a different world.")

user = self.bot.get_member(result["user_id"])
user_guilds: List[discord.Guild] = []
if user is not None:
# User is in another server
if ctx.guild.get_member(user.id) is None:
await ctx.send("The character is assigned to someone on another server.")
return
user_guilds = self.bot.get_user_guilds(user.id)
for guild in user_guilds:
if guild == ctx.guild:
continue
if self.bot.tracked_worlds.get(guild.id, None) != ctx.world:
continue
member: discord.Member = guild.get_member(ctx.author.id)
if member is None or member.guild_permissions.administrator:
await ctx.send(f"{ctx.tick(False)} The user of this server is also in another server tracking "
f"**{ctx.world}**, where you are not an admin. You can't alter other servers.")
return
username = "unknown" if user is None else user.display_name
c.execute("UPDATE chars SET user_id = 0 WHERE name LIKE ?", (name,))
await ctx.send("**{0}** was removed successfully from **@{1}**.".format(result["name"], username))
if user is not None:
for server in self.bot.get_user_guilds(user.id):
world = self.bot.tracked_worlds.get(server.id, None)
if world != result["world"]:
continue
if result["guild"] is None:
result["guild"] = "No guild"
log_msg = "{0.mention} unregistered:\n\u2023 {1} - Level {2} {3} - **{4}**". \
format(user, result["name"], result["level"], get_voc_abb_and_emoji(result["vocation"]),
result["guild"])
embed = discord.Embed(description=log_msg)
embed.set_author(name=f"{user.name}#{user.discriminator}", icon_url=get_user_avatar(user))
embed.set_footer(text="{0.name}#{0.discriminator}".format(ctx.author),
icon_url=get_user_avatar(ctx.author))
embed.colour = discord.Colour.dark_teal()
await self.bot.send_log_message(server, embed=embed)
return
for server in user_guilds:
world = self.bot.tracked_worlds.get(server.id, None)
if world != result["world"]:
continue
if result["guild"] is None:
result["guild"] = "No guild"
log_msg = "{0.mention} unregistered:\n\u2023 {1} - Level {2} {3} - **{4}**". \
format(user, result["name"], result["level"], get_voc_abb_and_emoji(result["vocation"]),
result["guild"])

embed = discord.Embed(description=log_msg)
embed.set_author(name=f"{user.name}#{user.discriminator}", icon_url=get_user_avatar(user))
embed.set_footer(text="{0.name}#{0.discriminator}".format(ctx.author),
icon_url=get_user_avatar(ctx.author))
embed.colour = discord.Colour.dark_teal()

await self.bot.send_log_message(server, embed=embed)
finally:
c.close()
userDatabase.commit()
Expand Down
42 changes: 27 additions & 15 deletions cogs/general.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ async def game_update(self):
"League of Dota", "my cards right", "out your death in my head"]
await self.bot.wait_until_ready()
while not self.bot.is_closed():
await self.bot.change_presence(activity=discord.Game(name=random.choice(game_list)))
if random.randint(0, 9) >= 7:
await self.bot.change_presence(activity=discord.Game(name=f"in {len(self.bot.guilds)} servers"))
else:
await self.bot.change_presence(activity=discord.Game(name=random.choice(game_list)))
await asyncio.sleep(60*20) # Change game every 20 minutes

async def events_announce(self):
Expand Down Expand Up @@ -106,7 +109,7 @@ async def events_announce(self):
event["start"] = 'now'
message = "**{name}** (by **@{author}**,*ID:{id}*) - Is starting {start}!".format(**event)
c.execute("UPDATE events SET status = ? WHERE id = ?", (new_status, event["id"],))
announce_channel_id = get_server_property(guild.id, "events_channel", is_int=True)
announce_channel_id = get_server_property(guild.id, "events_channel", is_int=True, default=0)
if announce_channel_id == 0:
continue
announce_channel = self.bot.get_channel_or_top(guild, announce_channel_id)
Expand Down Expand Up @@ -198,15 +201,18 @@ def ram(value):
embed.description = f"🔰 Version: **{self.bot.__version__}**\n" \
f"⏱ ️Uptime **{parse_uptime(self.bot.start_time)}**\n" \
f"🖥️ OS: **{platform.system()} {platform.release()}**\n" \
f"📉 RAM: **{ram(used_ram)}/{ram(total_ram)} ({percentage_ram:.2f}%)**\n" \
f"⚙️ CPU: **{psutil.cpu_count()} @ {psutil.cpu_freq().max} MHz**\n" \
f"🏓 Ping: **{ping} ms**\n" \
f"👾 Servers: **{len(self.bot.guilds):,}**\n" \
f"💬 Channels: **{len(list(self.bot.get_all_channels())):,}**\n"\
f"👨 Users: **{len(self.bot.users):,}** \n" \
f"👤 Characters: **{char_count:,}**\n" \
f"{config.levelup_emoji} Level ups: **{levels_count:,}**\n" \
f"{config.death_emoji} Deaths: **{deaths_count:,}**"
f"📉 RAM: **{ram(used_ram)}/{ram(total_ram)} ({percentage_ram:.2f}%)**\n"
try:
embed.description += f"⚙️ CPU: **{psutil.cpu_count()} @ {psutil.cpu_freq().max} MHz**\n"
except AttributeError:
pass
embed.description += f"🏓 Ping: **{ping} ms**\n" \
f"👾 Servers: **{len(self.bot.guilds):,}**\n" \
f"💬 Channels: **{len(list(self.bot.get_all_channels())):,}**\n"\
f"👨 Users: **{len(self.bot.users):,}** \n" \
f"👤 Characters: **{char_count:,}**\n" \
f"{config.levelup_emoji} Level ups: **{levels_count:,}**\n" \
f"{config.death_emoji} Deaths: **{deaths_count:,}**"
await ctx.send(embed=embed)

@commands.command(usage="<choices...>")
Expand All @@ -216,6 +222,9 @@ async def choose(self, ctx, *choices: str):
Each choice is separated by spaces. For choices that contain spaces surround it with quotes.
e.g. "Choice A" ChoiceB "Choice C"
"""
if not choices:
await ctx.send(f"{ctx.tick(False)} I can't tell you what to choose if you don't give me choices")
return
user = ctx.author
await ctx.send('Alright, **@{0}**, I choose: "{1}"'.format(user.display_name, random.choice(choices)))

Expand Down Expand Up @@ -453,17 +462,20 @@ async def event_addplayer(self, ctx, event_id: int, *, character):
await ctx.send(f"{ctx.tick(False)} You can only add people to your own events.")
return
with closing(userDatabase.cursor()) as c:
c.execute("SELECT * FROM chars WHERE name LIKE ?", (character,))
c.execute("SELECT * FROM chars WHERE name LIKE ? AND user_id != 0", (character,))
char = c.fetchone()
if event["slots"] != 0 and len(event["participants"]) >= event["slots"]:
await ctx.send(f"{ctx.tick(False)} All the slots for this event has been filled. "
f"You can change them by using `/event edit slots {event_id} newSlots`.")
return

if char is None:
await ctx.send(f"{ctx.tick(False)} That character is not registered.")
return
owner = self.bot.get_member(char["user_id"], ctx.guild)
if char is None or owner is None:
if owner is None:
await ctx.send(f"{ctx.tick(False)} That character is not registered.")
return

world = self.bot.tracked_worlds.get(event["server"])
if world != char["world"]:
await ctx.send(f"{ctx.tick(False)} You can't add a character from another world.")
Expand Down Expand Up @@ -1014,7 +1026,7 @@ async def event_make(self, ctx: NabCtx):
(ctx.author.id, ctx.guild.id, start_time, name, description))
event_id = c.lastrowid
userDatabase.commit()
await ctx.send(f"{ctx.tick(False)} Event registered successfully.\n\t**{name}** in *{starts_in.original}*.\n"
await ctx.send(f"{ctx.tick()} Event registered successfully.\n\t**{name}** in *{starts_in.original}*.\n"
f"*To edit this event use ID {event_id}*")

@commands.guild_only()
Expand Down
Loading

0 comments on commit 296a14c

Please sign in to comment.