First commit
This commit is contained in:
@@ -0,0 +1,250 @@
|
||||
import json
|
||||
import random
|
||||
|
||||
import nextcord
|
||||
from nextcord.ext import commands
|
||||
import re
|
||||
from PIL import Image
|
||||
import textrace
|
||||
import asyncio
|
||||
|
||||
ongoing_races = {}
|
||||
|
||||
bot = commands.Bot(intents=nextcord.Intents.all())
|
||||
|
||||
class TokenError(Exception):
|
||||
pass
|
||||
|
||||
with open("db.json") as f:
|
||||
db = json.load(f)
|
||||
|
||||
tag_db = db["tag_servers"]
|
||||
|
||||
# Valid tokens
|
||||
condition_tokens = {
|
||||
"&",
|
||||
"|",
|
||||
"^"
|
||||
}
|
||||
variable_tokens = {
|
||||
"msg"
|
||||
}
|
||||
match_tokens = {
|
||||
"has",
|
||||
"HAS",
|
||||
"startswith",
|
||||
"STARTSWITH",
|
||||
"hasword",
|
||||
"HASWORD",
|
||||
"regex",
|
||||
"=",
|
||||
"=="
|
||||
}
|
||||
action_tokens = {
|
||||
"say": 2,
|
||||
"reply": 2,
|
||||
"react": 2
|
||||
}
|
||||
setting_tokens = {
|
||||
"check_self": 2
|
||||
}
|
||||
|
||||
def tokenize(multimod: str):
|
||||
tokenized = {}
|
||||
regex_output = re.findall(r"^\s*(.+?)\s*{\s*(.+)\s*}\s*$", multimod)
|
||||
if not regex_output:
|
||||
raise TokenError("condition-action structure not found")
|
||||
tokenized["condition"] = regex_output[0][0]
|
||||
tokenized["action"] = regex_output[0][1]
|
||||
if tokenized["condition"].count("\"") % 2 or tokenized["condition"].count("'") % 2:
|
||||
raise TokenError("condition contains unclosed quotes")
|
||||
tokenized["condition"] = re.findall(r"\"[^\"]*\"|'[^\"]*'|[|&^]|[^\s|&^\"]+", tokenized["condition"])
|
||||
for i, condition_token in enumerate(tokenized["condition"]):
|
||||
tokenized["condition"][i] = condition_token.strip("\"").strip("'")
|
||||
grouped = []
|
||||
current_group = []
|
||||
for token in tokenized["condition"]:
|
||||
if token in condition_tokens:
|
||||
if current_group:
|
||||
grouped.append(current_group)
|
||||
current_group = []
|
||||
grouped.append(token)
|
||||
else:
|
||||
current_group.append(token)
|
||||
if current_group:
|
||||
grouped.append(current_group)
|
||||
tokenized["condition"] = grouped
|
||||
|
||||
if tokenized["action"].count("\"") % 2 or tokenized["action"].count("'") % 2:
|
||||
raise TokenError("action contains unclosed quotes")
|
||||
tokenized["action"] = re.split(r";\s*", tokenized["action"])
|
||||
for i, action in enumerate(tokenized["action"]):
|
||||
tokenized["action"][i] = re.findall(r"\"[^\"]*\"|'[^\"]*'|[^\s\"]+", action)
|
||||
for i2, action_token in enumerate(tokenized["action"][i]):
|
||||
tokenized["action"][i][i2] = action_token.strip("\"").strip("'")
|
||||
|
||||
# Check that everything is valid
|
||||
if type(tokenized["condition"][0]) == str or type(tokenized["condition"][len(tokenized["condition"]) - 1]) == str:
|
||||
raise TokenError("unexpected condition token at start or end of condition")
|
||||
|
||||
for condition_group in tokenized["condition"]:
|
||||
if type(condition_group) == list:
|
||||
if len(condition_group) != 3:
|
||||
raise TokenError(f"3 tokens expected in condition group, got {len(condition_group)}")
|
||||
if condition_group[0] not in variable_tokens:
|
||||
raise TokenError(f"unknown token where variable token expected: {condition_group[0]}")
|
||||
if condition_group[1] not in match_tokens:
|
||||
raise TokenError(f"unknown token where match token expected: {condition_group[1]}")
|
||||
elif type(condition_group) == str:
|
||||
if condition_group not in condition_tokens:
|
||||
raise TokenError(f"unknown token where condition token expected: {condition_group}")
|
||||
|
||||
for action in tokenized["action"]:
|
||||
if action[0] not in action_tokens and action[0] not in setting_tokens:
|
||||
raise TokenError(f"unknown token where action or setting token expected: {action[0]}")
|
||||
if len(action) != action_tokens[action[0]] and len(action) != setting_tokens[action[0]]:
|
||||
raise TokenError(f"{action_tokens[action[0]] or setting_tokens[action[0]]} tokens expected in action group, got {len(action)}")
|
||||
return tokenized
|
||||
|
||||
@bot.event
|
||||
async def on_ready():
|
||||
print(f'We have logged in as {bot.user}')
|
||||
await bot.get_channel(1359151976994308219).send("It seems I have woken up in a 2008 Dacia Sandero.")
|
||||
|
||||
@bot.slash_command()
|
||||
async def tag(interaction: nextcord.Interaction):
|
||||
pass
|
||||
|
||||
@tag.subcommand(description="Add a tag")
|
||||
async def add(interaction: nextcord.Interaction, tag: str):
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
try:
|
||||
tokenized = tokenize(tag)
|
||||
except TokenError as e:
|
||||
await interaction.send(f"Malformed tag: {e}")
|
||||
else:
|
||||
await interaction.send(f"Tag added!\n`{tokenized}`")
|
||||
if not str(interaction.guild_id) in tag_db:
|
||||
tag_db[str(interaction.guild_id)] = []
|
||||
tag_db[str(interaction.guild_id)].append(tokenized)
|
||||
with open("db.json", "w") as f:
|
||||
json.dump(db, f)
|
||||
|
||||
@tag.subcommand(description="Remove a tag")
|
||||
async def remove(interaction: nextcord.Interaction, tag: int):
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
if not interaction.user.guild_permissions.manage_guild:
|
||||
await interaction.send("You need the Manage Server permission to manage tags")
|
||||
return
|
||||
if tag_db[str(interaction.guild_id)] and tag_db[str(interaction.guild_id)][tag]:
|
||||
await interaction.send(f"Tag removed!\n")
|
||||
else:
|
||||
await interaction.send(f"No such tag ")
|
||||
|
||||
@tag.subcommand(name="list", description="List tags")
|
||||
async def list_(interaction: nextcord.Interaction):
|
||||
await interaction.response.defer(ephemeral=True)
|
||||
string = ""
|
||||
if tag_db[str(interaction.guild_id)]:
|
||||
for i, tag in enumerate(tag_db[str(interaction.guild_id)]):
|
||||
string += f"{i}. `{tag}`\n"
|
||||
else:
|
||||
string = "No tags for this server."
|
||||
await interaction.send(embed=nextcord.Embed(color=nextcord.Color.blue(), title="Tag list", description=string))
|
||||
|
||||
@tag.subcommand(description="Export tags to a txt file")
|
||||
async def export(interaction: nextcord.Interaction):
|
||||
await interaction.send("Maybe in 2027")
|
||||
|
||||
@tag.subcommand(name="import", description="Import tags from a txt file")
|
||||
async def import_(interaction: nextcord.Interaction, file: nextcord.Attachment):
|
||||
await interaction.send("Maybe in 2027")
|
||||
|
||||
@bot.event
|
||||
async def on_message(message: nextcord.Message):
|
||||
if message.author != bot.user:
|
||||
for guild in tag_db:
|
||||
if str(message.guild.id) == guild:
|
||||
tags = tag_db[guild]
|
||||
for tag in tags:
|
||||
for condition_group in tag["condition"]:
|
||||
last_operator = None
|
||||
condition = None
|
||||
if type(condition_group) == list:
|
||||
if condition_group[0] == "msg":
|
||||
comparing_var = message.content
|
||||
|
||||
previous_condition = condition
|
||||
|
||||
if condition_group[1] == "has":
|
||||
condition = condition_group[2].lower() in comparing_var.lower()
|
||||
if condition_group[1] == "HAS":
|
||||
condition = condition_group[2] in comparing_var
|
||||
if condition_group[1] == "startswith":
|
||||
condition = comparing_var.lower().startswith(condition_group[2].lower())
|
||||
if condition_group[1] == "STARTSWITH":
|
||||
condition = comparing_var.startswith(condition_group[2])
|
||||
if condition_group[1] == "hasword":
|
||||
condition = all(elem in comparing_var.lower().split() for elem in condition_group[2].lower().split())
|
||||
if condition_group[1] == "HASWORD":
|
||||
condition = all(elem in comparing_var.lower().split() for elem in condition_group[2].split())
|
||||
if condition_group[1] == "regex":
|
||||
condition = bool(re.search(condition_group[2], comparing_var, re.IGNORECASE))
|
||||
if condition_group[1] == "REGEX":
|
||||
condition = bool(re.search(condition_group[2], comparing_var))
|
||||
if condition_group[1] == "=":
|
||||
condition = comparing_var.lower() == condition_group[2].lower()
|
||||
if condition_group[1] == "==":
|
||||
condition = comparing_var == condition_group[2]
|
||||
|
||||
if last_operator == "|":
|
||||
condition = previous_condition or condition
|
||||
if last_operator == "&":
|
||||
condition = previous_condition and condition
|
||||
if last_operator == "^":
|
||||
condition = bool(previous_condition) ^ condition
|
||||
|
||||
elif type(condition_group) == str:
|
||||
last_operator = condition_group
|
||||
|
||||
if condition:
|
||||
for action in tag["action"]:
|
||||
if action[0] == "say":
|
||||
await message.channel.send(action[1])
|
||||
if action[0] == "reply":
|
||||
await message.reply(action[1])
|
||||
if action[0] == "react":
|
||||
await message.add_reaction(action[1])
|
||||
|
||||
if message.channel.id in ongoing_races:
|
||||
for race in ongoing_races[message.channel.id]:
|
||||
if message.content.lower() == race["answer"].lower():
|
||||
ongoing_races.pop(message.channel.id)
|
||||
if not "users" in db:
|
||||
db["users"] = {}
|
||||
if str(message.author.id) not in db["users"]:
|
||||
db["users"][str(message.author.id)] = {}
|
||||
if "balance" not in db["users"][str(message.author.id)]:
|
||||
db["users"][str(message.author.id)]["balance"] = 0
|
||||
db["users"][str(message.author.id)]["balance"] = round(db["users"][str(message.author.id)]["balance"] + race["prize"], 2)
|
||||
with open("db.json", "w") as f:
|
||||
json.dump(db, f)
|
||||
|
||||
await message.channel.send(f"**{message.author.name}** has won the race! {race["prize"]} internet points have been deposited into **{message.author.name}**'s account.")
|
||||
elif random.randint(1, 20) == 1:
|
||||
# Start text race
|
||||
internet_value, text, image_buffer = textrace.generate_image()
|
||||
await message.channel.send(f"**TEXT RACE!**\nType this text in 60 seconds to get {internet_value} internet points!", file=nextcord.File(image_buffer, filename="bumbler.png"))
|
||||
if message.channel.id not in ongoing_races:
|
||||
ongoing_races[message.channel.id] = []
|
||||
ongoing_races[message.channel.id].append({"answer": text, "prize": internet_value})
|
||||
await asyncio.sleep(60)
|
||||
race_still_going = False
|
||||
if message.channel.id in ongoing_races and {"answer": text, "prize": internet_value} in ongoing_races[message.channel.id]:
|
||||
ongoing_races.pop(message.channel.id)
|
||||
await message.channel.send(f"**Time's up!**\nThe answer was **{text}**.")
|
||||
|
||||
with open("token.txt") as f:
|
||||
token = f.read()
|
||||
|
||||
bot.run(token)
|
||||
Reference in New Issue
Block a user