Esempio n. 1
0
class EVENT:
    # Executes when loaded
    def __init__(self):
        self.RUNNING = False
        self.param = {"TIME_ORDER": 1}

    # Executes when activated
    def start(self, SERVER):  # Set the parameters
        self.RUNNING = True
        self.MESSAGES = []
        self.db = Database()
        self.SERVER = SERVER
        self.CHANNEL = ""
        self.ANNOUNCE = ""

    # Executes when deactivated
    def end(self):  # Reset the parameters
        self.param = {"TIME_ORDER": 1}
        self.RUNNING = False

    # Exclusive to this event, updates the list of TWOWs in signups
    async def update_list(self,
                          hour=False,
                          announce=True,
                          update_channel=False):
        if len(self.MESSAGES) == 0 or update_channel:
            msgs = [
                int(x)
                for x in self.db.get_entries("signupmessages")[0][0].split(" ")
            ]
            self.CHANNEL = discord.utils.get(self.SERVER["MAIN"].channels,
                                             id=msgs[0])
            self.MESSAGES = [""] * (len(msgs) - 2)
            self.ANNOUNCE = ""

            async for msg in self.CHANNEL.history(limit=100):
                if msg.id in msgs:
                    if msgs.index(msg.id) != len(msgs) - 1:
                        self.MESSAGES[msgs.index(msg.id) - 1] = msg
                    else:
                        self.ANNOUNCE = msg

        twow_list = self.db.get_entries("signuptwows")
        twow_list = sorted(twow_list,
                           key=lambda m: self.param["TIME_ORDER"] * m[4])

        for ind, twow in enumerate(twow_list):
            if twow[4] <= time.time():
                twow_list[ind] = ""

        twow_list = [x for x in twow_list if x != ""]

        self.db.remove_entry("signuptwows")
        for twow in twow_list:
            self.db.add_entry("signuptwows", list(twow))

        if announce:
            try:
                new_twow_names = list(zip(*twow_list))[0]
            except IndexError:
                new_twow_names = []
            old_twow_names = [
                x.content[x.content.find("πŸ“–  **__") +
                          7:x.content.find("__** - Hosted by")]
                for x in self.MESSAGES if x.content != "\u200b"
            ]

            just_added = [x for x in new_twow_names if x not in old_twow_names]
            just_removed = [
                x for x in old_twow_names if x not in new_twow_names
            ]

            new_announcement_list = []
            for x in just_added:
                new_announcement_list.append(
                    f"`(<1 hour ago)` : Added **{x}** to the signup list")
            for x in just_removed:
                new_announcement_list.append(
                    f"`(<1 hour ago)` : Removed **{x}** from the signup list")

            if self.ANNOUNCE.content != "\u200b":
                old_announcement_list = self.ANNOUNCE.content.split("\n")[2:]

                if hour:
                    for z in range(len(old_announcement_list)):
                        halves = old_announcement_list[z].split(" : ")
                        halves[0] = halves[0].split(" ")
                        if halves[0][0][2:] == "<1":
                            halves[0] = "`(1 hour ago)`"
                            old_announcement_list[z] = " : ".join(halves)
                        elif halves[0][0][2:] != "23":
                            halves[
                                0] = f"`({int(halves[0][0][2:])+1} hours ago)`"
                            old_announcement_list[z] = " : ".join(halves)
                        else:
                            old_announcement_list[z] = ""

                old_announcement_list = [
                    x for x in old_announcement_list if x != ""
                ]

                if new_announcement_list != []:
                    old_announcement_list += new_announcement_list

                announce_msg = f"__**Recent list changes:**__\n\n" + "\n".join(
                    old_announcement_list)
                await self.ANNOUNCE.edit(content=announce_msg)

            else:
                announce_msg = f"__**Recent list changes:**__\n\n" + "\n".join(
                    new_announcement_list)
                await self.ANNOUNCE.edit(content=announce_msg)

            for x in just_added:
                verif = twow_list[new_twow_names.index(x)][-1]
                if verif == 1:
                    msg = await self.CHANNEL.send(
                        "<@&488451010319220766> <@&723946317839073370>")
                else:
                    msg = await self.CHANNEL.send("<@&723946317839073370>")

                await msg.delete()

        formatted_list = []
        for twow in twow_list:
            time_left = twow[4] - time.time()

            signup_warning = ""
            time_emoji = "πŸ•›πŸ•πŸ•‘πŸ•’πŸ•“πŸ•”πŸ••πŸ•–πŸ•—πŸ•˜πŸ•™πŸ•š"

            if time_left <= 0:
                t_l_string = "SIGNUPS ARE OVER!"
            else:
                abs_delta = [
                    np.ceil(time_left / 3600),  # Hours
                    int(np.ceil(time_left / 3600) / 24)
                ]  # Days

                hr = int(abs_delta[0] % 24)
                dy = int(abs_delta[1])

                t_l_string = f"Less than"
                if dy != 0:
                    t_l_string += f" {dy} day{'s' if dy!=1 else ''}"
                else:
                    signup_warning = "\n⏰  **SIGNUPS ARE ALMOST OVER! JOIN SOON!**"
                if hr != 0:
                    if dy != 0:
                        t_l_string += ","

                    t_l_string += f" {hr} hour{'s' if hr!=1 else ''}"

            datetime_dl = datetime.datetime.utcfromtimestamp(twow[4])
            deadline_string = datetime_dl.strftime("%B %d %Y %H:%M UTC")

            try:
                chosen_emoji = time_emoji[datetime_dl.hour % 12]
            except Exception:
                chosen_emoji = time_emoji[0]

            verified_string = ""
            if twow[5] > 0:
                verified_string = "\n⭐  **FEATURED TWOW!** (<@&488451010319220766>)"

            descrip = twow[3].replace('\n', '\n> ')

            message = f"""\u200b
			\u200b{verified_string}
			πŸ“–  **__{twow[0]}__** - Hosted by **{twow[1]}**
			> {descrip}
			{signup_warning}
			{chosen_emoji}  **Signup Deadline** : **{t_l_string}** `({deadline_string})`
			πŸ“₯  **Server Link** : {twow[2]}""".replace("\t", "")

            formatted_list.append(message)

        for t in range(len(self.MESSAGES)):
            if t < len(formatted_list):
                await self.MESSAGES[-t - 1].edit(content=formatted_list[t])
            elif self.MESSAGES[-t - 1].content != "\u200b":
                await self.MESSAGES[-t - 1].edit(content="\u200b")

    # Function that runs every hour
    async def on_one_hour(self):
        await self.update_list(hour=True)

    # Change a parameter of the event
    async def edit_event(self, message, new_params):
        incorrect = []
        correct = []
        for parameter in new_params.keys():
            try:
                self.param[parameter] = new_params[parameter]
                correct.append(parameter)
            except KeyError:
                incorrect.append(parameter)

        if len(correct) > 0:
            await message.channel.send(
                f"Successfully changed the parameters: {grammar_list(correct)}"
            )
        if len(incorrect) > 0:
            await message.channel.send(
                f"The following parameters are invalid: {grammar_list(incorrect)}"
            )

        return
Esempio n. 2
0
async def MAIN(message, args, level, perms):
	db = Database()

	if perms < 2: # Direct database viewing is staff-only
		await message.channel.send("You don't have permission to run this subcommand.")
		return


	if level == 2: # If it's just `tc/db main`, list the tables using the get_tables() function.
		table_list = db.get_tables()
		table_list = [f'**{table.upper()}**' for table in table_list]
		await message.channel.send(f"Here's a list of Brain Database's tables: {grammar_list(table_list)}")
		return
	

	if args[1].lower() == "add": # `tc/db main add` creates a table

		if level == 2:
			await message.channel.send("Include a name for the new table!")
			return
		
		if level == 3:
			await message.channel.send("Include the table's columns!")
			return
		
		# I expect columns to be in the format `name-datatype name-datatype` and so on for each column.
		name = args[2].lower()
		columns = [x.lower().split("-") for x in args[3:]]

		db.add_table(name, columns)
		
		# Turn the `name-datatype` into `name datatype`, just for readability in the confirmation message
		columns = [" ".join(x) for x in columns]
		await message.channel.send(f"Table **{name.upper()}** created with columns {', '.join(columns)}")
		return


	if args[1].lower() == "remove": # `tc/db main remove` deletes (a.k.a. drops) a table

		if level == 2:
			await message.channel.send("Include the table you want to remove!")
			return

		name = args[2].lower()

		db.remove_table(name)
		
		await message.channel.send(f"Successfully deleted table **{name.upper()}**.")
		return
	

	if args[1].lower() == "layout": # `tc/db main layout` displays all columns and datatypes of a table

		if level == 2:
			await message.channel.send("Include the table you want to see the layout of!")
			return
	
		name = args[2].lower()

		columns = db.get_columns(name, include_type=True)

		# Make them bold, in the format `name - datatype` and with arrows
		formatted = "\n> ".join([f"**{r}**" for r in [" - ".join(c) for c in columns]])

		await message.channel.send(
			f"Here are the colums and datatypes from the table **{name.upper()}**.\n> {formatted}")
		return
	

	if args[1].lower() == "entries": # `tc/db main entries` Displays, adds or removes entries of a table

		if level == 2:
			await message.channel.send("Include the table you want to see the layout of!")
			return
		
		name = args[2].lower()
		get_entries = False

		# args[4] is the number of entries you want to see
		if level == 3: # If it's not specified, assume 10
			limit = 10
			get_entries = True

		elif args[3].lower() == "all": # If it's "all", just go with 99999. Better safe than sorry
			limit = 99999
			get_entries = True

		elif args[3].lower() not in ["add", "remove", "edit"]:
			# If it's not a further subcommand, interpret it as a number
			try:
				limit = int(args[3])
			except: # If it's not actually a number, just go with 10
				limit = 10
			get_entries = True
		
		# If get_entries is switched to true, that means the section above was able to extrapolate a number
		# from the command - meaning the user wants to see the table's entries, not add or remove them
		if get_entries:
			entries = db.get_entries(name, limit=limit)

			# "\t".join([str(h) for h in e]) returns a single entry, with all its columns joined by tabs
			# ["\t".join([str(h) for h in e]) for e in entries] returns a list of those entry strings
			# `formatted` is set to all those entries together, separated by newlines and in arrow text
			formatted = "\n> ".join(["\t".join([str(h) for h in e]) for e in entries])

			# Gotta have correct grammar
			reported_limit = 'all' if limit >= 99999 else limit
			plural = 'ies' if limit != 1 else 'y'

			to_send = [f"Here are {reported_limit} entr{plural} of **{name.upper()}**.\n> {formatted}"]

			# Limit messages to 1950 characters at most. Cut them off if bigger. Getting any closer to 2000
			# can cause errors regardless for some reason, so I try to avoid it
			if len(to_send[0]) > 1950:
				to_send.append(f"> {to_send[0][1947:3900]}")
				to_send[0] = to_send[0][:1947] + "..."

			for z in to_send:
				await message.channel.send(z)
			return
		
		
		if args[3].lower() == "add":
			# I expect arguments for this to be `value1 // value2 // value3` and so on
			arguments = " ".join(args[4:]).split(" // ")

			db.add_entry(name, arguments)
			
			await message.channel.send(f"Successfully added entry to table **{name.upper()}**!")
			return
		

		if args[3].lower() == "remove":

			if level == 4:
				await message.channel.send("Include a search column!")
				return

			if level == 5 and args[4].lower() == "all": # Delete all entries in the table
				await message.channel.send(f"""Are you sure you want to delete all entries in **{name.upper()}**? 
				Send `confirm` to transfer.""".replace("\n", "").replace("\t", ""))
				
				# Check for the next message by the same person in the same channel
				msg = await BRAIN.wait_for('message', 
				check=lambda m: (m.author == message.author and m.channel == message.channel))

				if msg.content.lower() != "confirm": # If it's not `confirm`, cancel the command
					await message.channel.send("Database command cancelled.")
					return

				db.remove_entry(name)

				await message.channel.send(f"Successfully cleared all entries from table **{name.upper()}**!")
				return
			

			# Arguments for this should be `column // value`, as a key to determine what should be deleted
			arguments = " ".join(args[4:]).split(" // ")
			
			if len(arguments) % 2 == 1: # Odd number of arguments means one key has no value
				await message.channel.send("Include a value for every updating column!")
				return
			
			conditions = {}
			for z in range(int(len(arguments) / 2)):
				conditions[arguments[z*2]] = arguments[z*2+1]
			
			db.remove_entry(name, conditions)

			await message.channel.send(f"Successfully deleted entries from table **{name.upper()}**!")
			return
		
		
		if args[3].lower() == "edit":

			if level < 7: # Requires at least 3 extra args: `upd_column // upd_key`
				await message.channel.send("Make sure to include the columns to update!")
				return
			
			if len(" ".join(args[4:]).split(" -> ")) == 2: # Split arguments into searching and updating
				searching_arguments = " ".join(args[4:]).split(" -> ")[0].split(" // ")
				updating_arguments = " ".join(args[4:]).split(" -> ")[1].split(" // ")
			else:
				searching_arguments = []
				updating_arguments = " ".join(args[4:]).split(" // ")

			if len(searching_arguments) % 2 == 1:
				await message.channel.send("Include a value for every search column!")
				return
			
			if len(updating_arguments) % 2 == 1:
				await message.channel.send("Include a value for every updating column!")
				return
			
			conditions = {}
			for z in range(int(len(searching_arguments) / 2)):
				conditions[searching_arguments[z*2]] = searching_arguments[z*2+1]
			
			entry = {}
			for z in range(int(len(updating_arguments) / 2)):
				entry[updating_arguments[z*2]] = updating_arguments[z*2+1]
			
			db.edit_entry(name, entry=entry, conditions=conditions)
			
			await message.channel.send(f"Successfully edited entries in **{name.upper()}**!")
			return
Esempio n. 3
0
async def MAIN(message, args, level, perms, TWOW_CENTRAL):
    db = Database()

    months = [
        "January", "February", "March", "April", "May", "June", "July",
        "August", "September", "October", "November", "December"
    ]

    if level == 1:  # If just tc/bd, return info on their birthday
        found = db.get_entries("birthday",
                               conditions={"id": str(message.author.id)})

        if found == []:
            await message.channel.send(
                f"""You are yet to register your birthday!
			You can register by using **{PREFIX}birthday register `DD/MM` `timezone`**"""
                .replace("\t", ""))
            return

        birthday, tz = found[0][1:]
        birthday = birthday.split("/")

        birthday_format = months[int(birthday[1]) - 1] + " " + str(birthday[0])
        timezone_f = ("+" if tz > 0 else "") + str(tz)

        await message.channel.send(
            f"""**{message.author.name}**'s birthday is set as **{birthday_format}** in **UTC {timezone_f}**."""
        )
        return

    if args[1].lower() == "view":
        if level == 2:
            found = db.get_entries("birthday")
            found = sorted(found, key=lambda k: int(k[1].split("/")[0]))
            found = sorted(found, key=lambda k: int(k[1].split("/")[1]))

            day, month = datetime.now(timezone.utc).day, datetime.now(
                timezone.utc).month

            for bd in found:
                if int(bd[1].split("/")[1]) > month:
                    next_bd = bd
                    break
                elif int(bd[1].split("/")[1]) == month and int(
                        bd[1].split("/")[0]) > day:
                    next_bd = bd
                    break
            else:
                next_bd = found[0]

            next_id, birthday, tz = next_bd
            birthday = birthday.split("/")
            birthday_format = months[int(birthday[1]) - 1] + " " + str(
                int(birthday[0]))
            timezone_f = ("+" if tz > 0 else "") + str(tz)

            try:
                username = TWOW_CENTRAL.get_member(int(next_id)).name
            except AttributeError:
                username = next_id

            await message.channel.send(
                f"The next birthday is **{username}**'s, on **{birthday_format}** in **UTC {timezone_f}**."
            )
            return

        rest = " ".join(args[2:])

        if rest.startswith("<@") and rest.endswith(">"):
            rest = rest[2:-1]

        if is_whole(rest):
            found = db.get_entries("birthday", conditions={"id": rest})

            try:
                username = TWOW_CENTRAL.get_member(int(rest)).name
            except:
                username = rest

            if found == []:
                await message.channel.send(
                    f"**{username}** has not registered a birthday yet!")
                return

            user_bd = found[0]
            birthday, tz = user_bd[1:]
            birthday = birthday.split("/")
            birthday_format = months[int(birthday[1]) - 1] + " " + str(
                int(birthday[0]))
            timezone_f = ("+" if tz > 0 else "") + str(tz)

            await message.channel.send(
                f"**{username}**'s birthday is on **{birthday_format}** in **UTC {timezone_f}**."
            )
            return

        else:
            user = discord.utils.get(TWOW_CENTRAL.members, name=rest)

            if user is None:
                await message.channel.send("That user is not in the server!")
                return

            found = db.get_entries("birthday", conditions={"id": str(user.id)})

            if found == []:
                await message.channel.send(
                    f"**{rest}** has not registered a birthday yet!")
                return

            user_bd = found[0]
            birthday, tz = user_bd[1:]
            birthday = birthday.split("/")
            birthday_format = months[int(birthday[1]) - 1] + " " + str(
                int(birthday[0]))
            timezone_f = ("+" if tz > 0 else "") + str(tz)

            await message.channel.send(
                f"**{rest}**'s birthday is on **{birthday_format}** in **UTC {timezone_f}**."
            )
            return

    if args[1].lower() == "register":
        if level == 2:
            await message.channel.send(
                "Include your birthday in `DD/MM` to register!")
            return

        # Check if the person is in the birthday database or not
        found = db.get_entries("birthday",
                               conditions={"id": str(message.author.id)})
        print(found)

        birthday = args[2].split("/")

        if level == 3:
            tz = 0

        elif not is_whole(args[3]):
            await message.channel.send(
                "Invalid timezone! Make sure it's a whole number from -12 to 14!"
            )
            return

        elif not -12 <= int(args[3]) <= 14:
            await message.channel.send(
                "Invalid timezone! Make sure it's a whole number from -12 to 14!"
            )
            return

        else:
            tz = int(args[3])

        if len(birthday) != 2:  # If it's not `n/n`
            await message.channel.send(
                "Invalid birthday! Make sure it's in the `DD/MM` format!")
            return

        if not is_whole(birthday[0]) or not is_whole(
                birthday[1]):  # If day and month aren't numbers
            await message.channel.send(
                "Invalid birthday! Make sure the day and month are both numbers!"
            )
            return

        # Transform into integers for these next two checks
        birthday[0] = int(birthday[0])
        birthday[1] = int(birthday[1])

        if not 1 <= birthday[1] <= 12:  # If month is invalid
            await message.channel.send(
                "Invalid month! Make sure it's between 1 and 12.")
            return

        if not 1 <= birthday[0] <= monthrange(
                2020, birthday[1])[1]:  # monthrange checks days in the month
            await message.channel.send(  # 2020 months because it's a leap year, and 29/02 should be available
                f"Invalid day! Make sure it's between 1 and {monthrange(2020, birthday[1])[1]} for that month."
            )
            return

        birthday_format = months[birthday[1] - 1] + " " + str(birthday[0])
        birthday = "/".join([str(x) for x in birthday
                             ])  # Join the list again for the next few lines
        timezone_f = ("+" if tz > 0 else "") + str(tz)

        # This confirmation message cannot be bypassed
        await message.channel.send(
            f"""Are you sure you want to record your birthday as {birthday_format} and your 
		timezone as UTC {timezone_f}? Send `confirm` in this channel to confirm.
		""".replace("\n", "").replace("\t", ""))

        # Wait for a message by the same author in the same channel
        msg = await BRAIN.wait_for(
            'message',
            check=(lambda m: m.channel == message.channel and m.author ==
                   message.author))

        if msg.content.lower(
        ) != "confirm":  # If it's not `confirm`, cancel command
            await message.channel.send("Birthday registering cancelled.")
            return

        # If confirmation passed, record the birthday
        if found == []:
            is_new = ""
            db.add_entry("birthday", [message.author.id, birthday, tz])
        else:
            is_new = "new "
            db.edit_entry("birthday",
                          entry={
                              "birthday": birthday,
                              "timezone": tz
                          },
                          conditions={"id": str(message.author.id)})

        await message.channel.send(
            f"Successfully recorded your {is_new}birthday as **{birthday} UTC {timezone_f}**!"
        )
        return
Esempio n. 4
0
async def MAIN(message, args, level, perms, SERVER):
	if level == 1:
		await message.channel.send("Include a subcommand!")
		return
	
	db = Database()
	
	if args[1].lower() == "info":
		tag_list = db.get_entries("b++2programs", columns=["name", "program", "author", "uses", "created", "lastused"])
		tag_list = sorted(tag_list, reverse=True, key=lambda m: m[3])

		tag_leaderboard = False
		if level == 2: # If it's not specified, assume it's the first page
			tag_list = tag_list[:10]
			page = 1
			tag_leaderboard = True
		
		elif is_whole(args[2]):
			if (int(args[2]) - 1) * 10 >= len(tag_list): # Detect if the page number is too big
				await message.channel.send(f"There is no page {args[2]} on the New B++ program list!")
				return
		
			else: # This means the user specified a valid page number
				lower = (int(args[2]) - 1) * 10
				upper = int(args[2]) * 10
				tag_list = tag_list[lower:upper]
				page = int(args[2])
				tag_leaderboard = True
	
		if tag_leaderboard:
			beginning = f"```diff\nB++ Programs Page {page}\n\n"

			for program in tag_list:
				r = tag_list.index(program) + 1 + (page - 1) * 10
				
				line = f"{r}{' '*(2-len(str(r)))}: {program[0]} :: {program[3]} use{'s' if program[3] != 1 else ''}"

				member_id = program[2]
				try: # Try to gather a username from the ID
					member = SERVER["MAIN"].get_member(int(member_id)).name
				except: # If you can't, just display the ID
					member = str(member_id)

				created_on = dt.utcfromtimestamp(program[4]).strftime('%Y-%m-%d %H:%M:%S UTC')
				line += f" (written by {member} at {created_on})\n"
			
				beginning += line # Add this line to the final message
			
			beginning += "```" # Close off code block

			await message.channel.send(beginning)
			return

		tag_name = args[2]

		if tag_name not in [x[0] for x in tag_list]:
			await message.channel.send("That tag does not exist.")
			return
		
		program = tag_list[[x[0] for x in tag_list].index(tag_name)]

		member_id = program[2]
		try: # Try to gather a username from the ID
			member = SERVER["MAIN"].get_member(int(member_id)).name
		except: # If you can't, just display the ID
			member = str(member_id)
		
		created_on = dt.utcfromtimestamp(program[4]).strftime('%Y-%m-%d %H:%M:%S UTC')
		c_d = dt.now() - dt.utcfromtimestamp(program[4])

		d = c_d.days
		h, rm = divmod(c_d.seconds, 3600)
		m, s = divmod(rm, 60)

		c_d = (('' if d==0 else f'{d} day{"s" if d!=1 else ""}, ') +
		('' if h==0 else f'{h} hour{"s" if h!=1 else ""}, ') +
		('' if m==0 else f'{m} minute{"s" if m!=1 else ""}, ') +
		(f'{s} second{"s" if s!=1 else ""}'))
		
		msg = f"**{program[0]}** -- by {member} -- {program[3]} use{'s' if program[3]!=1 else ''}\n"
		msg += f"Created on {created_on} `({c_d} ago)`\n"

		if program[5] != 0:
			last_used = dt.utcfromtimestamp(program[5]).strftime('%Y-%m-%d %H:%M:%S UTC')
			u_d = dt.now() - dt.utcfromtimestamp(program[5])
			
			d = u_d.days
			h, rm = divmod(u_d.seconds, 3600)
			m, s = divmod(rm, 60)

			u_d = (('' if d==0 else f'{d} day{"s" if d!=1 else ""}, ') +
			('' if h==0 else f'{h} hour{"s" if h!=1 else ""}, ') +
			('' if m==0 else f'{m} minute{"s" if m!=1 else ""}, ') +
			(f'{s} second{"s" if s!=1 else ""}'))

			msg += f"Last used on {last_used} `({u_d} ago)`\n"

		if len(program[1]) > 1700:
			msg += f"The program is too long to be included in the message, so it's in the file below:"
			open(f'program_{program[0]}.txt', 'w', encoding="utf-8").write(program[1])
			await message.channel.send(msg, file=discord.File(f'program_{program[0]}.txt'))
			os.remove(f'program_{program[0]}.txt')
		else:
			msg += f"```{program[1]}```"
			await message.channel.send(msg)
		
		return


	if args[1].lower() == "create":
		if level == 2:
			await message.channel.send("Include the name of your new program!")
			return
	
		tag_name = args[2]

		if re.search(r"[^0-9A-Za-z_]", tag_name) or re.search(r"[0-9]", tag_name[0]):
			await message.channel.send(
			"Tag name can only contain letters, numbers and underscores, and cannot start with a number!")
			return
		
		if tag_name in ["create", "edit", "delete", "info", "run", "help"]:
			await message.channel.send("The tag name must not be a reserved keyword!")
			return

		if len(tag_name) > 30:
			await message.channel.send("That tag name is too long. 30 characters maximum.")
			return
		
		if level > 3:
			program = " ".join(args[3:])

		elif len(message.attachments) != 0:
			try:
				if message.attachments[0].size >= 20000:
					await message.channel.send("Your program must be under **20KB**.")
					return
				
				await message.attachments[0].save(f"Config/{message.id}.txt")
				
			except Exception:
				await message.channel.send("Include a valid program to save!")
				return
			
			program = open(f"Config/{message.id}.txt", "r", encoding="utf-8").read()
			os.remove(f"Config/{message.id}.txt")
		
		else:
			await message.channel.send("Include a valid program to save!")
			return
		
		while program.startswith("`") and program.endswith("`"):
			program = program[1:-1]
		program.replace("{}", "\t")

		if (tag_name,) in db.get_entries("b++2programs", columns=["name"]):
			await message.channel.send("There's already a program with that name!")
			return
		
		db.add_entry("b++2programs", [tag_name, program, message.author.id, 0, time.time(), 0])
		await message.channel.send(f"Successfully created program `{tag_name}`!")
		return


	if args[1].lower() == "edit":
		if level == 2:
			await message.channel.send("Include the name of the program you want to edit!")
			return
		
		tag_name = args[2]

		tag_list = db.get_entries("b++2programs", columns=["name", "author"])

		if tag_name not in [x[0] for x in tag_list]:
			await message.channel.send(f"There's no program under the name `{tag_name}`!")
			return

		ind = [x[0] for x in tag_list].index(tag_name)
		if tag_list[ind][1] != str(message.author.id) and perms < 2:
			await message.channel.send(f"You can only edit a program if you created it or if you're a staff member!")
			return
		
		if level > 3:
			program = " ".join(args[3:])

		elif len(message.attachments) != 0:
			try:
				if message.attachments[0].size >= 20000:
					await message.channel.send("Your program must be under **20KB**.")
					return
				
				await message.attachments[0].save(f"Config/{message.id}.txt")

			except Exception:
				await message.channel.send("Include a valid program to run!")
				return
			
			program = open(f"Config/{message.id}.txt", "r", encoding="utf-8").read()
			os.remove(f"Config/{message.id}.txt")
		
		else:
			await message.channel.send("Include a valid program to run!")
			return
		
		while program.startswith("`") and program.endswith("`"):
			program = program[1:-1]
		
		program = program.replace("{}", "\v")
		
		db.edit_entry("b++2programs", entry={"program": program}, conditions={"name": tag_name})
		await message.channel.send(f"Succesfully edited program {tag_name}!")
		return


	if args[1].lower() == "delete":
		if level == 2:
			await message.channel.send("Include the name of the program you want to delete!")
			return
		
		tag_name = args[2]

		tag_list = db.get_entries("b++2programs", columns=["name", "author"])

		if tag_name not in [x[0] for x in tag_list]:
			await message.channel.send(f"There's no program under the name `{tag_name}`!")
			return

		ind = [x[0] for x in tag_list].index(tag_name)
		if tag_list[ind][1] != str(message.author.id) and perms < 2:
			await message.channel.send(f"You can only edit a program if you created it or if you're a staff member!")
			return
			
		db.remove_entry("b++2programs", conditions={"name": tag_name})
		await message.channel.send(f"Succesfully deleted program {tag_name}!")
		return


	if args[1].lower() == "run":
		if level > 2:
			program = " ".join(args[2:])

		elif len(message.attachments) != 0:
			try:
				if message.attachments[0].size >= 20000:
					await message.channel.send("Your program must be under **20KB**.")
					return

				await message.attachments[0].save(f"Config/{message.id}.txt")

			except Exception:
				await message.channel.send("Include a valid program to run!")
				return
			
			program = open(f"Config/{message.id}.txt", "r", encoding="utf-8").read()
			os.remove(f"Config/{message.id}.txt")
		
		else:
			await message.channel.send("Include a valid program to run!")
			return

		while program.startswith("`") and program.endswith("`"):
			program = program[1:-1]
		
		program = program.replace("{}", "\v")

		program_args = []

		author = message.author.id
	
	else:
		tag_name = args[1]

		tag_list = db.get_entries("b++2programs", columns=["name", "program", "author", "uses"])

		if tag_name not in [x[0] for x in tag_list]:
			await message.channel.send(f"There's no program under the name `{tag_name}`!")
			return
		
		tag_info = [x for x in tag_list if x[0] == tag_name][0]
		program = tag_info[1]

		uses = tag_info[3] + 1
		db.edit_entry("b++2programs", entry={"uses": uses, "lastused": time.time()}, conditions={"name": tag_name})

		program_args = args[2:]

		author = tag_info[2]
		
	try:
		program_output = run_bpp_program(program, program_args, author)
		program_output = program_output.replace("<@", "<\\@")
	except Exception as e:
		await message.channel.send(f'{type(e).__name__}:\n```{e}```')
		return

	if len(program_output) > 1950:
		program_output = "⚠️ `Output too long! First 1900 characters:`\n\n" + program_output[:1900]
	
	if len(program_output.strip()) == 0: program_output = "\u200b"
	
	await message.channel.send(program_output)
	return
Esempio n. 5
0
async def MAIN(message, args, level, perms, SERVER):
	if level == 1:
		await message.channel.send("Include a subcommand!")
		return
	
	VARIABLES = {}

	db = Database()

	if args[1].lower() == "info":
		tag_list = db.get_entries("b++programs", columns=["name", "program", "author", "uses"])
		tag_list = sorted(tag_list, reverse=True, key=lambda m: m[3])

		tag_leaderboard = False
		if level == 2: # If it's not specified, assume it's the first page
			tag_list = tag_list[:10]
			page = 1
			tag_leaderboard = True
		
		elif is_whole(args[2]):
			if (int(args[2]) - 1) * 10 >= len(tag_list): # Detect if the page number is too big
				await message.channel.send(f"There is no page {args[2]} on the B++ program list!")
				return
		
			else: # This means the user specified a valid page number
				lower = (int(args[2]) - 1) * 10
				upper = int(args[2]) * 10
				tag_list = tag_list[lower:upper]
				page = int(args[2])
				tag_leaderboard = True
		
		if tag_leaderboard:
			beginning = f"```diff\nOld B++ Programs Page {page}\n\n"

			for program in tag_list:
				r = tag_list.index(program) + 1 + (page - 1) * 10
				
				line = f"{r}{' '*(2-len(str(r)))}: {program[0]} :: {program[3]} use{'s' if program[3] != 1 else ''}"

				member_id = program[2]
				try: # Try to gather a username from the ID
					member = SERVER["MAIN"].get_member(int(member_id)).name
				except: # If you can't, just display the ID
					member = str(member_id)

				line += f" (written by {member})\n"
			
				beginning += line # Add this line to the final message
			
			beginning += "```" # Close off code block

			await message.channel.send(beginning)
			return

		tag_name = args[2]

		if tag_name not in [x[0] for x in tag_list]:
			await message.channel.send("That tag does not exist.")
			return
		
		program = tag_list[[x[0] for x in tag_list].index(tag_name)]

		member_id = program[2]
		try: # Try to gather a username from the ID
			member = SERVER["MAIN"].get_member(int(member_id)).name
		except: # If you can't, just display the ID
			member = str(member_id)
		
		if len(program[1]) + 6 >= 1900:
			program_code_msg = program[1]
			if len(program_code_msg) >= 1990:
				await message.channel.send(f"**{program[0]}** (written by {member})")
				await message.channel.send(f"```{program_code_msg[:1000]}```")
				await message.channel.send(f"```{program_code_msg[1000:]}```")
				await message.channel.send(f"Used {program[3]} time{'s' if program[3] != 1 else ''}")
			else:
				await message.channel.send(f"**{program[0]}** (written by {member})")
				await message.channel.send(f"```{program_code_msg}```")
				await message.channel.send(f"Used {program[3]} time{'s' if program[3] != 1 else ''}")
		else:
			await message.channel.send(f"""**{program[0]}** (written by {member})
			```{program[1]}```
			Used {program[3]} time{'s' if program[3] != 1 else ''}""".replace("\n", "").replace("\t", ""))
		return

	if args[1].lower() == "delete":
		if level == 2:
			await message.channel.send("Include the name of the program you want to delete!")
			return
		
		tag_name = args[2]

		tag_list = db.get_entries("b++programs", columns=["name", "author"])
		if tag_name in [x[0] for x in tag_list]:

			ind = [x[0] for x in tag_list].index(tag_name)
			if tag_list[ind][1] != str(message.author.id) and perms != 2:
				await message.channel.send(f"You can only delete a program you created!")
				return
			
			db.remove_entry("b++programs", conditions={"name": tag_name})
			await message.channel.send(f"Succesfully deleted program {tag_name}!")

		else:
			await message.channel.send(f"There's no program under the name `{tag_name}`!")

		return

	if args[1].lower() == "edit":
		if level == 2:
			await message.channel.send("Include the name of the program you want to edit!")
			return
		
		if level == 3:
			await message.channel.send("Include the new code for the program you want to edit!")
			return
		
		tag_name = args[2]

		program = " ".join(args[3:])

		if program.startswith("```") and program.endswith("```"):
			program = program[3:-3]
		if program.startswith("``") and program.endswith("``"):
			program = program[2:-2]
		if program.startswith("`") and program.endswith("`"):
			program = program[1:-1]

		tag_list = db.get_entries("b++programs", columns=["name", "author"])
		if tag_name in [x[0] for x in tag_list]:

			ind = [x[0] for x in tag_list].index(tag_name)
			if tag_list[ind][1] != str(message.author.id) and perms != 2:
				await message.channel.send(f"You can only edit a program you created!")
				return
			
			db.edit_entry("b++programs", entry={"program": program}, conditions={"name": tag_name})
			await message.channel.send(f"Succesfully edited program {tag_name}!")

		else:
			await message.channel.send(f"There's no program under the name `{tag_name}`!")

		return


	if args[1].lower() not in ["run", "create"]:
		tag_name = args[1]
		if (tag_name,) in db.get_entries("b++programs", columns=["name"]):
			program, uses = db.get_entries(
				"b++programs", columns=["program", "uses"], conditions={"name": tag_name})[0]
			
			uses += 1
			db.edit_entry("b++programs", entry={"uses": uses}, conditions={"name": tag_name})
		
		else:
			await message.channel.send(f"There's no tag under the name `{args[1]}`!")
			return

	else:
		if args[1].lower() == "run":
			if level == 2:
				await message.channel.send("Include a program to run!")
				return
			
			program = " ".join(args[2:])
		

		if args[1].lower() == "create":
			if level == 2:
				await message.channel.send("Include the name of your new program!")
				return
			
			if level == 3:
				await message.channel.send("Include the code for your program!")
				return
		
			tag_name = args[2]

			if len(tag_name) > 30:
				await message.channel.send("That tag name is too long. 30 characters maximum.")
				return
			
			program = " ".join(args[3:])

		if program.startswith("```") and program.endswith("```"):
			program = program[3:-3]
		if program.startswith("``") and program.endswith("``"):
			program = program[2:-2]
		if program.startswith("`") and program.endswith("`"):
			program = program[1:-1]

		if args[1].lower() == "create":
			if (tag_name,) in db.get_entries("b++programs", columns=["name"]):
				await message.channel.send("There's already a program with that name!")
				return
			
			db.add_entry("b++programs", [tag_name, program, message.author.id, 0])
			await message.channel.send(f"Successfully created program `{tag_name}`!")
			return

	semicolon_inds = find_all(program, ";")
	semicolon_inds = [x for x in semicolon_inds if program[x-1] != "\\"]

	program_chars = list(program)
	for ind in semicolon_inds:
		program_chars[ind] = "\n"
	program = ''.join(program_chars).replace("\t", "")

	lines = program.split("\n")

	context = []
	OUTPUT = ""
	try:
		try:
			tag_vars = db.get_entries("b++variables", columns=["name", "value"], conditions={"tag": tag_name})
			for var in tag_vars:
				value = var[1]
				if value.startswith("[") and value.endswith("]"):
					value = array_to_list(value)
				VARIABLES[var[0]] = value
		except:
			pass

		for line in lines:
			c_line = line

			if len(context) == 0:
				declaration = " = " in c_line
				array_context = "[" in c_line.replace("\[", "") and "]" not in c_line.replace("\]", "")

				if array_context:
					context.append(["array", c_line, c_line[c_line.find("["):]])
					continue
			else:
				context_list = [x[0] for x in context]
				if "array" in context_list:
					this_context = context[context_list.index("array")]

					this_context[1] += "\t" + c_line
					if "]" not in line.replace("\]", ""):
						this_context[2] += "\t" + c_line
						continue
					else:
						this_context[2] += c_line[:c_line.find("]")+1]
						c_line = this_context[1]
						del context[context_list.index("array")]
						declaration = " = " in c_line

			if declaration: # Deal with variable declaration
				c_line = c_line.replace("\\=", "\n")
				c_line = c_line.replace("==", "\t\t")
				
				sides = c_line.split("=")
				sides[1] = "=".join(sides[1:])

				sides = [x.replace("\n", "\=") for x in sides]
				sides = [x.replace("\t\t", "==") for x in sides]
				c_line = c_line.replace("\n", "=")
				c_line = c_line.replace("\t\t", "==")

				sides[0] = parenthesis_parser(sides[0].strip(), VARIABLES, OUTPUT)[0]
				sides[1] = parenthesis_parser(strip_front(sides[1]), VARIABLES, OUTPUT, var=True)[0]

				VARIABLES[sides[0]] = sides[1]
				continue

			line_info, OUTPUT = parenthesis_parser(c_line.strip(), VARIABLES, OUTPUT)
		
	except Exception as e:
		await message.channel.send(f'{type(e).__name__} in line `{c_line}`:\n\t{e}')
		return

	try:
		await message.channel.send(
		OUTPUT.replace("<@", "<\@").replace("\\\\", "\t\t").replace("\\", "").replace("\t\t", "\\").replace(u"\uF000","\n",50)[:1950])
	except discord.errors.HTTPException:
		pass
	
	try:
		tag_name
		tag_vars = db.get_entries("b++variables", columns=["name"], conditions={"tag": tag_name})

		for var in VARIABLES.keys():
			if var.startswith("__"):
				if type(VARIABLES[var]) == list:
					VARIABLES[var] = list_to_array(VARIABLES[var])

				if (var,) in tag_vars:
					db.edit_entry("b++variables", entry={"value": str(VARIABLES[var])}, conditions={"name": var})
					continue
				
				db.add_entry("b++variables", entry=[var, str(VARIABLES[var]), tag_name])
	except:
		pass
	return
async def MAIN(message, args, level, perms, SERVER):

    if isinstance(message.channel, discord.DMChannel
                  ):  # Everyone should be able to see button presses
        await message.channel.send("This command cannot be used in DMs!")
        return

    db = Database()

    if level == 1:  # `tc/button` will check the current button

        try:
            # "public.bigredbutton" always has a single entry unless there has never been a button. If len(button_info)
            # is 0, that's the case, and this will throw an error caught by the try except block.
            button_info = db.get_entries("bigredbutton",
                                         columns=["button", "info"])[0]
        except IndexError:
            button_info = db.get_entries("bigredbutton",
                                         columns=["button", "info"])

        if len(button_info) == 0:  # If there is no button, create one
            button_number = 1  # It'd be the first ever button
            serial_number = key_generator(random.randrange(
                8, 15))  # Generate serial
            exploding_chance = random.randrange(
                15, 51)  # 15 to 50% chance of exploding
            inspector = number_key(3)  # Factory inspector code

            db.add_entry(
                "bigredbutton",
                [1, f"{serial_number} {exploding_chance} {inspector}", "", ""])
            # Insert the new button info. Now there is a button, so skip to [*]

        elif button_info[
                1] == "PRESSED":  # This is the 3 second interval after a button is pressed and before
            return  # the outcome is announced. Ignore button checks for this period

        elif len(button_info[1].split(" ")) == 1:  # [#]
            # Button, when in cooldown, has a single code for its info column, representing when it was pressed and
            # if it blew up or not. This code, unlike the normal `serial exp_chance` information, has no space in
            # it. This section detects that code

            pressing_time = int(
                button_info[1][2:])  # Time at which the button was pressed

            if button_info[1].startswith(
                    "0-"):  # `0-time` means button didn't blow up
                left = int((pressing_time + 15) -
                           time.time())  # Time left for button to come back

                if left < 0:  # If it's negative, the button should've returned by now but didn't
                    # So generate the button on the spot
                    button_number = button_info[
                        0] + 1  # Increment button number
                    serial_number = key_generator(random.randrange(
                        8, 15))  # Generate serial
                    exploding_chance = random.randrange(
                        15, 51)  # 15 to 50% chance of exploding
                    inspector = number_key(3)  # Factory inspector code

                    n_info = f"{serial_number} {exploding_chance} {inspector}"
                    db.edit_entry("bigredbutton",
                                  entry={
                                      "button": button_number,
                                      "info": n_info
                                  })
                    # Update with the new button

                else:  # If it's not negative, and the timer hasn't ended, report the amount of time remaining
                    await message.channel.send(
                        f"The new button is currently being prepared! {left}s remain!"
                    )
                    return

            if button_info[1].startswith(
                    "1-"):  # `1-time` means the button blew up
                left = int((pressing_time + 300) -
                           time.time())  # Time left for button to come back

                if left < 0:  # Read above about the timer being negative
                    button_number = button_info[0] + 1
                    serial_number = key_generator(random.randrange(8, 15))
                    exploding_chance = random.randrange(15, 51)
                    inspector = number_key(3)

                    n_info = f"{serial_number} {exploding_chance} {inspector}"
                    db.edit_entry("bigredbutton",
                                  entry={
                                      "button": button_number,
                                      "info": n_info
                                  })
                    # Update with new button

                else:  # Report the actual timer if it hasn't ended yet
                    mn = int(left / 60)  # Extract minutes
                    sc = left % 60  # Extract seconds
                    await message.channel.send(
                        f"The new button is being reconstructed. {mn}min {sc}s remain!"
                    )
                    return

        else:  # If there's a button and that's it
            button_number = button_info[0]  # Report the button number...
            serial_number = button_info[1].split(" ")[0]  # Its serial...
            exploding_chance = button_info[1].split(" ")[
                1]  # ...Its explosion chance
            inspector = button_info[1].split(" ")[2]  # And its inspector

        # [*] Report the current button
        await message.channel.send(
            f"""<:bigredbutton:654042578617892893> This is **Big Red Button #{button_number}**
			
			It has a **{exploding_chance}%** chance of exploding. The serial number is `{serial_number}`.
			It was inspected and approved by Factory Inspector #{inspector}.
			Use `tc/bigredbutton press` to press this button!""".replace("\t", ""))

        return

    if args[1].lower() == "top":  # Points leaderboard

        unformatted_points = db.get_entries("bigredbutton",
                                            columns=["points"])[0]
        unformatted_points = [
            x.split("-") for x in unformatted_points[0].split(" ")
        ]
        # unformatted_points might include empty strings from how the points value is formatted
        points = []  # This variable will be the clean version

        for x in unformatted_points:
            try:
                x[0] = int(x[0])
                x[1] = int(x[1])
                points.append(
                    x)  # If it passed the int tests, append it to points
            except ValueError:  # If it fails to convert to integers, it's an empty string and is ignored
                continue

        points = sorted(points, reverse=True,
                        key=lambda x: x[1])  # Sort the leaderboard

        player_info = [x for x in points if x[0] == message.author.id][0]
        player_ind = points.index(player_info)

        # args[2] is the page number.
        if level == 2:  # If it's not specified, assume it's the first page
            points = points[:10]
            page = 1

        elif not is_whole(
                args[2]
        ):  # If it's not a valid integer, assume it's first page also
            points = points[:10]
            page = 1

        elif (int(args[2]) -
              1) * 10 >= len(points):  # Detect if the page number is too big
            await message.channel.send(
                f"There is no page {args[2]} on Big Red Button!")
            return

        else:  # This means the user specified a valid page number
            lower = (int(args[2]) - 1) * 10
            upper = int(args[2]) * 10
            points = points[lower:upper]
            page = int(args[2])

        # Top of the message
        beginning = f"```diff\n---⭐ Big Red Button Points Leaderboard Page {page} ⭐---\n"
        beginning += "\n Rank |  Name                  |  Points\n"

        for person in points:
            r = points.index(person) + 1 + (page - 1) * 10
            if r == 1:  # + if the person is first
                line = f"+ {r}{' ' * (4 - len(str(r)))}|  "
            else:  # - otherwise
                line = f"- {r}{' ' * (4 - len(str(r)))}|  "

            try:  # Try to gather a username from the ID
                member = SERVER["MAIN"].get_member(int(person[0])).name
            except:  # If you can't, just display the ID
                member = str(person[0])

            line += f"{member[:20]}{' ' * (22 - len(member[:20]))}|  "  # Trim usernames to 20 characters long
            line += str(person[1]) + "\n"  # Add points value and newline

            beginning += line  # Add this line to the final message

        beginning += f"\nYour rank is {player_ind+1}, with {player_info[1]} points."
        beginning += "```"  # Close off code block

        await message.channel.send(beginning)
        return

    if args[1].lower() == "press":  # Press the button!

        button_info = db.get_entries("bigredbutton")[0]

        # This segment is almost an exact repeat of [#] up above
        if len(button_info[1].split(" ")) == 1 and button_info[1] != "PRESSED":
            pressing_time = int(button_info[1][2:])

            if button_info[1].startswith("0-"):
                left = int((pressing_time + 15) - time.time())

                if left < 0:
                    button_number = button_info[0] + 1
                    serial_number = key_generator(random.randrange(8, 15))
                    exploding_chance = random.randrange(15, 51)
                    inspector = number_key(3)

                    n_info = f"{serial_number} {exploding_chance} {inspector}"
                    db.edit_entry("bigredbutton",
                                  entry={
                                      "button": button_number,
                                      "info": n_info
                                  })

                    await message.channel.send(
                        f"""Big Red Button #{button_number} has arrived from inspection 
					by Factory Inspector #{inspector}, now with a {exploding_chance}% chance to explode and a 
					serial number of `{serial_number}`!""".replace("\n",
                                                    "").replace("\t", ""))
                    return

                else:
                    await message.channel.send(
                        f"The new button is currently being prepared! {left}s remain!"
                    )
                    return

            if button_info[1].startswith("1-"):
                left = int((pressing_time + 300) - time.time())

                if left < 0:
                    button_number = button_info[0] + 1
                    serial_number = key_generator(random.randrange(8, 15))
                    exploding_chance = random.randrange(15, 51)
                    inspector = number_key(3)

                    n_info = f"{serial_number} {exploding_chance} {inspector}"
                    db.edit_entry("bigredbutton",
                                  entry={
                                      "button": button_number,
                                      "info": n_info
                                  })

                    await message.channel.send(
                        f"""Big Red Button #{button_number} has arrived from inspection 
					by Factory Inspector #{inspector}, now with a {exploding_chance}% chance to explode and a 
					serial number of `{serial_number}`!""".replace("\n",
                                                    "").replace("\t", ""))
                    return

                else:
                    mn = int(left / 60)
                    sc = left % 60
                    await message.channel.send(
                        f"The new button is being reconstructed. {mn}min {sc}s remain!"
                    )
                    return

        # We already checked button_info[1], check two others now
        button_number = button_info[0]
        incapacitated = button_info[2]

        if str(message.author.id) in incapacitated:  # If you're incapacitated
            incapacitated = incapacitated.split(" ")

            ind = 0  # Find the author in the incapacitated list and extract their explosion time
            for incap in incapacitated:
                if incap.split("-")[0] == str(message.author.id):
                    ind = incapacitated.index(incap)
                    explosion_t = int(incap.split("-")[1])
                    break

            # Calculate how long it'll be before they can recover
            delta = (explosion_t + 21600) - time.time()

            if delta < 0:  # If it's negative, then they already recovered and can go on
                del incapacitated[ind]  # Delete the entry for this person

                incapacitated = " ".join(incapacitated)  # Join the list

                # Update with the new incapacitated list
                db.edit_entry("bigredbutton",
                              entry={"incapacitated": incapacitated})

            else:  # If it's not negative, they still have to wait a little
                abs_delta = [
                    int(delta),  # Seconds
                    int(delta / 60),  # Minutes
                    int(delta / (60 * 60))
                ]  # Hours

                sc = abs_delta[0] % 60
                mn = abs_delta[1] % 60
                hr = abs_delta[2]

                await message.channel.send(
                    f"You are still incapacitated! Wait {hr}h {mn}min {sc}s to press again."
                )
                return

        if strip_alpha(message.author.name) == "":
            return  # Don't try to cheese it by having no letters

        if button_info[
                1] == "PRESSED":  # If it's currently being pressed, ignore this press
            return
        else:  # Mark this button as being pressed so nobody else presses it during the 3 second interval
            db.edit_entry("bigredbutton", entry={"info": "PRESSED"})

        # Gather serial_number and exploding_chance for calculations
        serial_number = button_info[1].split(" ")[0]
        exploding_chance = int(button_info[1].split(" ")[1])
        inspector = list(button_info[1].split(" ")[2])

        new_chance = exploding_chance  # Clean slate variable
        if str(message.author.id)[-1] in serial_number:
            new_chance *= 0.67  # If last digit of ID is in serial...

        if strip_alpha(message.author.name)[0].upper() in serial_number:
            new_chance *= 2  # If first letter of username is in serial...

        point_retention = 0.5
        share_count = 0
        disc = list(str(message.author.discriminator))
        for x in range(len(list(inspector))):
            if inspector[x] in disc:
                share_count += 1
                disc.remove(inspector[x])
                inspector[x] = "-"

        if share_count == 2:
            point_retention = 0.75
        if share_count == 3:
            point_retention = 0.9

        seed = random.uniform(
            0,
            100)  # Has to be above the explosion chance otherwise it explodes

        await message.channel.send(
            f"**{message.author.name}** presses the button, and...")
        await asyncio.sleep(3)  # Suspense!

        if seed <= new_chance:  # If it's under the explosion chance, it blows up
            n_button_info = f"1-{int(time.time())}"  # Remember, `1-time` is the explosion flag
            new_inc = f" {message.author.id}-{n_button_info[2:]}"  # Add this person to the incapacitated list
            points = button_info[3].split(" ")  # Get the points list

            new_points = 0

            ind = -1  # Find the player in the points list and halve their point count
            for player in points:
                if player.split("-")[0] == str(message.author.id):
                    ind = points.index(player)
                    new_points = int(
                        int(player.split("-")[1]) * point_retention)
                    points[ind] = f"{message.author.id}-{new_points}"

            if ind == -1:  # If ind is still -1, then the player wasn't found in the points list so create a new
                points.append(f"{message.author.id}-{new_points}"
                              )  # entry for them with 0 points

            points = " ".join(points)

            db.edit_entry("bigredbutton",
                          entry={
                              "info": n_button_info,
                              "points": points,
                              "incapacitated": incapacitated + new_inc
                          })
            # Update with the explosion info, the new incapacitated list, and the new points list

            await message.channel.send(
                f"""<:bigredbutton:654042578617892893> ***The #{button_number} Big Red Button blew up!***

			<@{message.author.id}> has been incapacitated. Their point total is now **{new_points}**.
			They cannot press any more buttons for 6 hours.
			The button is broken. It'll take **5 minutes** to rebuild it.""".replace(
                    "\t", ""))

            await asyncio.sleep(300)  # Five minutes until the button is back

        else:  # If seed > new_chance, it doesn't blow up
            points = button_info[3].split(" ")  # Get points list to add points
            n_button_info = f"0-{int(time.time())}"  # `0-time` means no explosion

            ind = -1  # Find player in points list and add the new points
            for player in points:
                if player.split("-")[0] == str(message.author.id):
                    ind = points.index(player)
                    # Note: the points they gain is ALWAYS the nominal value for the exploding chance, not the
                    # modified serial number chance that was used to calculate explosions
                    new_points = int(player.split("-")[1]) + exploding_chance
                    points[ind] = f"{message.author.id}-{new_points}"

            if ind == -1:  # If they're not in the points list, add them with the new point value
                points.append(f"{message.author.id}-{exploding_chance}")

            points = " ".join(points)

            db.edit_entry("bigredbutton",
                          entry={
                              "info": n_button_info,
                              "points": points
                          })
            # Update with the pressing info and the new points list

            await message.channel.send(f"""
			<:bigredbutton:654042578617892893> The #{button_number} Big Red Button did nothing.

			<@{message.author.id}> gained {exploding_chance} points. Another button arrives in **15 seconds**.
			""".replace("\t", ""))

            await asyncio.sleep(15)  # Fifteen seconds until the button is back

        # Generate new serial_number and exploding_chance
        button_number += 1
        serial_number = key_generator(random.randrange(8, 15))
        exploding_chance = random.randrange(15, 51)
        inspector = number_key(3)

        n_info = f"{serial_number} {exploding_chance} {inspector}"
        db.edit_entry("bigredbutton",
                      entry={
                          "button": button_number,
                          "info": n_info
                      })
        # Update table with the new button

        # Announce the new button
        await message.channel.send(
            f"""Big Red Button #{button_number} has arrived from inspection 
		by Factory Inspector #{inspector}, now with a {exploding_chance}% chance to explode and a 
		serial number of `{serial_number}`!""".replace("\n", "").replace("\t", ""))
        return
Esempio n. 7
0
async def MAIN(message, args, level, perms, SERVER):
    db = Database()

    months = [
        "January", "February", "March", "April", "May", "June", "July",
        "August", "September", "October", "November", "December"
    ]

    if level == 1:  # If just tc/bd, return info on their birthday
        found = db.get_entries("birthday",
                               conditions={"id": str(message.author.id)})

        if found == []:
            await message.channel.send(
                f"""You are yet to register your birthday!
			You can register by using **{SERVER["PREFIX"]}birthday register `DD/MM` `timezone`**"""
                .replace("\t", ""))
            return

        birthday, tz = found[0][1:]
        birthday = birthday.split("/")

        birthday_format = months[int(birthday[1]) - 1] + " " + str(birthday[0])
        timezone_f = ("+" if tz > 0 else "") + str(tz)

        await message.channel.send(
            f"""**{message.author.name}**'s birthday is set as **{birthday_format}** in **UTC {timezone_f}**."""
        )
        return

    if args[1].lower() == "month":
        if level == 2:
            chosen_month = datetime.now(timezone.utc).month

        elif is_whole(args[2]):
            if int(args[2]) > 12 or int(args[2]) < 1:
                await message.channel.send(
                    "Invalid month number. If you're picking a month number, choose one between 1 and 12!"
                )
                return

            chosen_month = int(args[2])

        else:
            possible_months = [
                x for x in months if x.lower().startswith(args[2].lower())
            ]

            if len(possible_months) == 0:
                new_possible = [
                    x for x in months if args[2].lower() in x.lower()
                ]

                if len(new_possible) == 0:
                    await message.channel.send(
                        "There's no valid month with that name!")
                    return

                if len(new_possible) > 1:
                    await message.channel.send(
                        f"""There are multiple months fitting that search key. Please specify which one you mean!
						`({', '.join(new_possible)})`""".replace("\t", ""))
                    return

                possible_months = new_possible

            if len(possible_months) > 1:
                await message.channel.send(
                    f"""There are multiple months fitting that search key. Please specify which one you mean!
					`({', '.join(possible_months)})`""".replace("\t", ""))
                return

            chosen_month = months.index(possible_months[0]) + 1

        found = db.get_entries("birthday")
        found = [k for k in found if int(k[1].split("/")[1]) == chosen_month]
        month_name = months[chosen_month - 1]

        if len(found) == 0:
            await message.channel.send(
                f"There are no registered birthdays in {month_name}!")
            return

        found = sorted(found, key=lambda k: int(k[1].split("/")[0]))

        messages = [
            f"Here are all the birthdays registered in {month_name}:\n\n"
        ]

        for bd in found:
            try:
                username = f"**{SERVER['MAIN'].get_member(int(bd[0])).name}**"
            except Exception:
                username = f"**`[{bd[0]}]`**"

            day = bd[1].split("/")[0]
            tz = ("+" if bd[2] > 0 else "") + str(bd[2])

            line = f"> {username} - {month_name} {day}, UTC {tz}\n"

            if len(messages[-1]) + len(line) > 1900:
                messages.append("")

            messages[-1] += line

        for m in messages:
            await message.channel.send(m)

        return

    if args[1].lower() == "next":
        found = db.get_entries("birthday")
        found = sorted(found, key=lambda k: int(k[1].split("/")[0]))
        found = sorted(found, key=lambda k: int(k[1].split("/")[1]))

        day, month = datetime.now(timezone.utc).day, datetime.now(
            timezone.utc).month

        for bd in found:
            if int(bd[1].split("/")[1]) > month:
                next_bd = bd
                break
            elif int(bd[1].split("/")[1]) == month and int(
                    bd[1].split("/")[0]) > day:
                next_bd = bd
                break
        else:
            next_bd = found[0]

        next_id, birthday, tz = next_bd
        birthday = birthday.split("/")
        birthday_format = months[int(birthday[1]) - 1] + " " + str(
            int(birthday[0]))
        timezone_f = ("+" if tz > 0 else "") + str(tz)

        try:
            username = SERVER["MAIN"].get_member(int(next_id)).name
        except AttributeError:
            username = next_id

        await message.channel.send(
            f"The next birthday is **{username}**'s, on **{birthday_format}** in **UTC {timezone_f}**."
        )
        return

    if args[1].lower() == "user":
        if level == 2:
            await message.channel.send(
                "Include the username or ID of the person whose birthday you want to check."
            )
            return

        rest = " ".join(args[2:])

        if rest.startswith("<@") and rest.endswith(">"):
            rest = rest[2:-1]

        if is_whole(rest):
            found = db.get_entries("birthday", conditions={"id": rest})

            try:
                username = SERVER["MAIN"].get_member(int(rest)).name
            except:
                username = rest

            if found == []:
                await message.channel.send(
                    f"**{username}** has not registered a birthday yet!")
                return

            user_bd = found[0]
            birthday, tz = user_bd[1:]
            birthday = birthday.split("/")
            birthday_format = months[int(birthday[1]) - 1] + " " + str(
                int(birthday[0]))
            timezone_f = ("+" if tz > 0 else "") + str(tz)

            await message.channel.send(
                f"**{username}**'s birthday is on **{birthday_format}** in **UTC {timezone_f}**."
            )
            return

        else:
            user = discord.utils.get(SERVER["MAIN"].members, name=rest)

            if user is None:
                await message.channel.send("That user is not in the server!")
                return

            found = db.get_entries("birthday", conditions={"id": str(user.id)})

            if found == []:
                await message.channel.send(
                    f"**{rest}** has not registered a birthday yet!")
                return

            user_bd = found[0]
            birthday, tz = user_bd[1:]
            birthday = birthday.split("/")
            birthday_format = months[int(birthday[1]) - 1] + " " + str(
                int(birthday[0]))
            timezone_f = ("+" if tz > 0 else "") + str(tz)

            await message.channel.send(
                f"**{rest}**'s birthday is on **{birthday_format}** in **UTC {timezone_f}**."
            )
            return

    if args[1].lower() == "remove":
        found = db.get_entries("birthday",
                               conditions={"id": str(message.author.id)})

        if found == []:
            await message.channel.send(
                "You haven't registered a birthday yet to remove it!")
            return

        await message.channel.send(
            f"""Are you sure you want to remove your birthday from the database? Send `confirm` 
		in this channel to confirm. Send anything else to cancel.""".replace(
                "\n", "").replace("\t", ""))

        # Wait for a message by the same author in the same channel
        msg = await BRAIN.wait_for(
            'message',
            check=(lambda m: m.channel == message.channel and m.author ==
                   message.author))

        if msg.content.lower(
        ) != "confirm":  # If it's not `confirm`, cancel command
            await message.channel.send("Birthday registering cancelled.")
            return

        db.remove_entry("birthday", conditions={"id": str(message.author.id)})
        await message.channel.send(
            "Your birthday has been removed from the database.")
        return

    if args[1].lower() == "register":
        if level == 2:
            await message.channel.send(
                "Include your birthday in `DD/MM` to register!")
            return

        # Check if the person is in the birthday database or not
        found = db.get_entries("birthday",
                               conditions={"id": str(message.author.id)})

        birthday = args[2].split("/")

        if level == 3:
            tz = 0

        elif not is_whole(args[3]):
            await message.channel.send(
                "Invalid timezone! Make sure it's a whole number from -12 to 14!"
            )
            return

        elif not -12 <= int(args[3]) <= 14:
            await message.channel.send(
                "Invalid timezone! Make sure it's a whole number from -12 to 14!"
            )
            return

        else:
            tz = int(args[3])

        if len(birthday) != 2:  # If it's not `n/n`
            await message.channel.send(
                "Invalid birthday! Make sure it's in the `DD/MM` format!")
            return

        if not is_whole(birthday[0]) or not is_whole(
                birthday[1]):  # If day and month aren't numbers
            await message.channel.send(
                "Invalid birthday! Make sure the day and month are both numbers!"
            )
            return

        # Transform into integers for these next two checks
        birthday[0] = int(birthday[0])
        birthday[1] = int(birthday[1])

        if not 1 <= birthday[1] <= 12:  # If month is invalid
            await message.channel.send(
                "Invalid month! Make sure it's between 1 and 12.")
            return

        if not 1 <= birthday[0] <= monthrange(
                2020, birthday[1])[1]:  # monthrange checks days in the month
            await message.channel.send(  # 2020 months because it's a leap year, and 29/02 should be available
                f"Invalid day! Make sure it's between 1 and {monthrange(2020, birthday[1])[1]} for that month."
            )
            return

        birthday_format = months[birthday[1] - 1] + " " + str(birthday[0])
        birthday = "/".join([str(x) for x in birthday
                             ])  # Join the list again for the next few lines
        timezone_f = ("+" if tz > 0 else "") + str(tz)

        # This confirmation message cannot be bypassed
        await message.channel.send(
            f"""Are you sure you want to record your birthday as {birthday_format} and your 
		timezone as UTC {timezone_f}? Send `confirm` in this channel to confirm.
		""".replace("\n", "").replace("\t", ""))

        # Wait for a message by the same author in the same channel
        msg = await BRAIN.wait_for(
            'message',
            check=(lambda m: m.channel == message.channel and m.author ==
                   message.author))

        if msg.content.lower(
        ) != "confirm":  # If it's not `confirm`, cancel command
            await message.channel.send("Birthday registering cancelled.")
            return

        # If confirmation passed, record the birthday
        if found == []:
            is_new = ""
            db.add_entry("birthday", [message.author.id, birthday, tz])
        else:
            is_new = "new "
            db.edit_entry("birthday",
                          entry={
                              "birthday": birthday,
                              "timezone": tz
                          },
                          conditions={"id": str(message.author.id)})

        await message.channel.send(
            f"Successfully recorded your {is_new}birthday as **{birthday} UTC {timezone_f}**!"
        )
        return
Esempio n. 8
0
async def MAIN(message, args, level, perms, SERVER):
    if level == 1:
        await message.channel.send("Include a subcommand!")
        return

    if args[1].lower() == "setup":
        if level == 2:
            n = 10
        elif is_whole(args[2]):
            n = int(args[2])
        else:
            n = 10

        msg_ids = [str(message.channel.id)]
        for _ in range(n):
            msg = await message.channel.send("\u200b")
            msg_ids.append(str(msg.id))

        await message.channel.send(" ".join(msg_ids))
        return

    if args[1].lower() == "update":
        await message.channel.send("Updating list...")
        await SERVER["EVENTS"]["SIGNUPS"].update_list(update_channel=True)
        await message.channel.send("Updated list!")
        return

    if args[1].lower() == "edit":
        msg = message.content

        if "name:[" not in msg:
            await message.channel.send(
                "Include the name of the TWOW you want to edit!")
            return

        db = Database()

        starting_bound = msg[msg.find("name:[") + 6:]
        twow_name = starting_bound[:starting_bound.find("]")]

        twow_list = db.get_entries("signuptwows",
                                   conditions={"name": twow_name})

        if len(twow_list) == 0:
            await message.channel.send(
                f"There's no TWOW named **{twow_name}** in the signup list!")
            return

        old_entry = twow_list[0]
        old_entry = dict(
            zip(["name", "hosts", "link", "description", "time", "verified"],
                old_entry))

        entry = {
            "name": None,
            "hosts": None,
            "link": None,
            "description": None,
            "time": None,
            "verified": None
        }

        cond = {"name": twow_name}

        if "newname:[" in msg:
            starting_bound = msg[msg.find("newname:[") + 9:]
            new_name = starting_bound[:starting_bound.find("]")]
            entry["name"] = new_name

        if "host:[" in msg:
            starting_bound = msg[msg.find("host:[") + 6:]
            hosts = starting_bound[:starting_bound.find("]")]
            entry["hosts"] = hosts

        if "link:[" in msg:
            starting_bound = msg[msg.find("link:[") + 6:]
            link = starting_bound[:starting_bound.find("]")].replace(
                "<", "").replace(">", "")
            entry["link"] = link

        if "desc:[" in msg:
            starting_bound = msg[msg.find("desc:[") + 6:]
            desc = starting_bound[:starting_bound.find("]")]
            entry["description"] = desc

        if "deadline:[" in msg:
            starting_bound = msg[msg.find("deadline:[") + 10:]
            dl_string = starting_bound[:starting_bound.find("]")]
            deadline = datetime.datetime.strptime(dl_string, "%d/%m/%Y %H:%M")
            deadline = deadline.replace(
                tzinfo=datetime.timezone.utc).timestamp()
            entry["time"] = deadline

        if "verified:[" in msg:
            starting_bound = msg[msg.find("verified:[") + 10:]
            verified = starting_bound[:starting_bound.find("]")]
            if verified in ["0", ""]:
                vf = 0
            else:
                vf = 1
            entry["verified"] = vf

        entry = {k: d for k, d in entry.items() if d is not None}

        if len(entry.keys()) == 0:
            await message.channel.send("You've made no edits to this TWOW!")
            return

        db.edit_entry("signuptwows", entry=entry, conditions=cond)

        announce = "dont_announce" not in msg
        await SERVER["EVENTS"]["SIGNUPS"].update_list(announce=announce)

        old_info_string = ""
        for k, v in old_entry.items():
            if v != "":
                tag = k
                if k == "hosts":
                    tag = "host"
                if k == "time":
                    tag = "deadline"
                if k == "description":
                    tag = "desc"

                old_info_string += f"{tag}:[{v}] "

        for k, v in entry.items():
            old_entry[k] = v

        new_info_string = ""
        for k, v in old_entry.items():
            if v != "":
                tag = k
                if k == "hosts":
                    tag = "host"
                if k == "time":
                    tag = "deadline"
                if k == "description":
                    tag = "desc"

                if k == "link":
                    v = f"<{v}>"
                new_info_string += f"{tag}:[{v}] "

        await message.channel.send(
            f"""**{cond['name']}** has been edited in the signup list.
		
		**Old TWOW Info**:
		{old_info_string}

		**New TWOW Info**:
		{new_info_string}""".replace("\t", ""))

    if args[1].lower() == "remove":
        msg = message.content

        if level == 2:
            await message.channel.send(
                "Include the name of the TWOW you want to remove!")
            return

        db = Database()

        if "dont_announce" in msg:
            twow_name = " ".join(args[2:-1])
        else:
            twow_name = " ".join(args[2:])

        twow_list = db.get_entries("signuptwows",
                                   conditions={"name": twow_name})

        if len(twow_list) == 0:
            await message.channel.send(
                f"There's no TWOW named **{twow_name}** in the signup list!")
            return

        twow_info = twow_list[0]
        dl_format = datetime.datetime.utcfromtimestamp(
            twow_info[4]).strftime("%d/%m/%Y %H:%M")

        db.remove_entry("signuptwows", conditions={"name": twow_name})

        announce = "dont_announce" not in msg
        await SERVER["EVENTS"]["SIGNUPS"].update_list(announce=announce)

        await message.channel.send(
            f"""**{twow_info[0]}** has been removed from the signup list!
		
		**TWOW Info**:
		""".replace("\t", "") + f"""name:[{twow_info[0]}] 
		host:[{twow_info[1]}] 
		link:[{twow_info[2]}] 
		desc:[{twow_info[3]}] 
		deadline:[{dl_format}] 
		{'is_verified' if bool(twow_info[5]) else ''}""".replace("\n", "").replace(
                "\t", ""))

        return

    if args[1].lower() == "add":
        msg = message.content

        if "name:[" not in msg:
            await message.channel.send(
                "Include the name of the TWOW you want to add!")
            return

        db = Database()

        starting_bound = msg[msg.find("name:[") + 6:]
        twow_name = starting_bound[:starting_bound.find("]")]

        entry = [twow_name, "", "", "", 0, 0, ""]

        if "host:[" in msg:
            starting_bound = msg[msg.find("host:[") + 6:]
            hosts = starting_bound[:starting_bound.find("]")]
            entry[1] = hosts

        if "link:[" in msg:
            starting_bound = msg[msg.find("link:[") + 6:]
            link = starting_bound[:starting_bound.find("]")].replace(
                "<", "").replace(">", "")
            entry[2] = link

        if "desc:[":
            starting_bound = msg[msg.find("desc:[") + 6:]
            desc = starting_bound[:starting_bound.find("]")]
            entry[3] = desc

        if "deadline:[" in msg:
            starting_bound = msg[msg.find("deadline:[") + 10:]
            deadline = starting_bound[:starting_bound.find("]")]
            entry[6] = deadline
            deadline = datetime.datetime.strptime(deadline, "%d/%m/%Y %H:%M")
            deadline = deadline.replace(
                tzinfo=datetime.timezone.utc).timestamp()
            entry[4] = deadline

        vf = 0
        if "verified:[" in msg:
            starting_bound = msg[msg.find("verified:[") + 10:]
            verified = starting_bound[:starting_bound.find("]")]
            if verified not in ["0", ""]:
                vf = 1
        entry[5] = vf

        db.add_entry("signuptwows", entry[:6])

        announce = "dont_announce" not in msg
        await SERVER["EVENTS"]["SIGNUPS"].update_list(announce=announce)

        await message.channel.send(
            f"""**{entry[0]}** has been added to the list of TWOWs in signups!
		**Host:** {entry[1]}
		**Description:** {entry[3]}
		**Deadline:** {entry[6]}
		**Deadline Timestamp:** {entry[4]}
		**Link:** <{entry[2]}>""".replace("\t", ""))
Esempio n. 9
0
import discord
from Config._db import Database
from Config._const import BRAIN

db = Database()

columns = db.get_entries("serverdata")

MAIN_SERVER = {}
SERVERS = {}

MAIN_SERVER["ID"] = 481509601590771724
MAIN_SERVER["MAIN"] = discord.utils.get(BRAIN.guilds, id=MAIN_SERVER["ID"])
MAIN_SERVER["LOGS"] = discord.utils.get(MAIN_SERVER["MAIN"].channels,
                                        id=653677748832698378)
MAIN_SERVER["BIRTHDAY"] = discord.utils.get(MAIN_SERVER["MAIN"].roles,
                                            id=653630098813222943)
MAIN_SERVER["MEMES"] = discord.utils.get(MAIN_SERVER["MAIN"].channels,
                                         id=656639194415759371)
MAIN_SERVER["INTERESTED"] = discord.utils.get(MAIN_SERVER["MAIN"].roles,
                                              id=654072824318918677)
'''
MAIN_SERVER["ID"] = 653673010821201920
MAIN_SERVER["MAIN"] = discord.utils.get(BRAIN.guilds, id=MAIN_SERVER["ID"])
MAIN_SERVER["LOGS"] = discord.utils.get(MAIN_SERVER["MAIN"].channels, id=653673395954647095)
MAIN_SERVER["BIRTHDAY"] = discord.utils.get(MAIN_SERVER["MAIN"].roles, id=653771648616366103)
MAIN_SERVER["MEMES"] = discord.utils.get(MAIN_SERVER["MAIN"].channels, id=656641155869704205)
MAIN_SERVER["INTERESTED"] = discord.utils.get(MAIN_SERVER["MAIN"].roles, id=654094896562438154)
'''

for server in columns:
Esempio n. 10
0
async def MAIN(message, args, level, perms, SERVER):
	db = Database()

	id_search_key = str(SERVER["MAIN"].id)

	try:
		roles, contestants, contnames, emojis, limit = db.get_entries(
			"teamdata", columns=["roles", "contestants", "contname", "emojis", "teamlimit"],
			conditions={"server":id_search_key}
		)[0]
	except IndexError:
		await message.channel.send("There are no team flairs in this server!")
		return

	flair_list = False
	count = False
	if level == 1:
		flair_list = True
	elif args[1].lower() in ["teams", "list", "options"]:
		flair_list = True
	elif args[1].lower() == "count":
		flair_list = True
		count = True
	
	if flair_list:
		role_list = roles.split(" ")

		if contnames != "":
			cont_list = contnames.split(" / ")
		
		if emojis != "":
			emoji_list = emojis.split(" ")

		if count:
			output = [f"Here's the current team member standings.\n\n"]

			teams = []
			for t in range(len(role_list)):
				team_info = []
				
				try:
					team_info.append(emoji_list[t])
				except:
					pass

				try:
					team_info.append("**" + cont_list[t] + "** -")
				except:
					team_info.append("<@&" + role_list[t] + "> -")
				
				try:
					counter = len(discord.utils.get(SERVER["MAIN"].roles, id=int(role_list[t])).members)
				except:
					counter = 0
				
				team_info.append(counter)
				team_info.append("member" + ('' if counter == 1 else 's') + "\n")
			
				teams.append(team_info)
			
			teams = sorted(teams, reverse=True, key=lambda m: m[1])

			teams = [" ".join([str(a) for a in t]) for t in teams]

			for t in teams:
				if len(output[-1]) + len(t) > 1980:
					output.append("")
				
				output[-1] += t

		else:
			output = [f"Here's a list of available team flairs.\nYou can pick **{limit}** at most.\n\n"]

			for t in range(len(role_list)):
				line = ""

				try:
					line += emoji_list[t] + " - "
				except:
					pass

				try:
					line += "**" + cont_list[t] + "** - "
				except:
					pass

				line += "<@&" + role_list[t] + ">\n"

				if len(output[-1]) + len(line) > 1980:
					output.append("")
				
				output[-1] += line

		for m in output:
			await message.channel.send(m)
		return
	
	if args[1].lower() in ["get", "remove"]:
		if level == 2:
			await message.channel.send(f"Specify the team flair you want to {args[1].lower()}!")
			return
		
		cont_list = contnames.split(" / ")
		cont_id_list = contestants.split(" ")
		role_list = roles.split(" ")

		cont_list_l = [x.lower() for x in cont_list]

		key = " ".join(args[2:]).lower()

		found_first = False
		picked = []

		found_list = [x for x in cont_list_l if x.startswith(key)]

		if len(found_list) == 1:
			ind = cont_list_l.index(found_list[0])
			picked = [cont_list[ind], cont_id_list[ind], role_list[ind]]
		elif len(found_list) > 1:
			found_first = True
		
		if picked == []:
			role_name_list = [
				discord.utils.get(SERVER["MAIN"].roles, id=int(x)).name for x in role_list
				if discord.utils.get(SERVER["MAIN"].roles, id=int(x)) != None]

			found_list = [x for x in role_name_list if x.lower().startswith(key)]
			
			if len(found_list) == 1:
				ind = role_name_list.index(found_list[0])
				picked = [cont_list[ind], cont_id_list[ind], role_list[ind]]
			elif len(found_list) > 1:
				found_first = True
		
		if picked == []:
			if found_first:
				await message.channel.send(
					"There seem to be multiple flairs matching that search key. Please specify more!")
			else:
				await message.channel.send("I couldn't find a team flair matching that search key!")
			return

		author_member = SERVER["MAIN"].get_member(message.author.id)
		current_flair_list = [str(x.id) for x in author_member.roles if str(x.id) in role_list]

		if args[1].lower() == "get":
			if picked[1] == str(message.author.id):
				await message.channel.send("You can't pick your own team flair!")
				return
			
			if picked[2] in current_flair_list:
				await message.channel.send("You already have that team flair!")
				return
			
			if len(current_flair_list) >= limit:
				await message.channel.send(
					f"You already have {limit} flair{'' if limit==1 else 's'}. You can't get any more!")
				return
			
			team_role = discord.utils.get(SERVER["MAIN"].roles, id=int(picked[2]))
			await author_member.add_roles(team_role)
			await message.channel.send(f"You have been added to **{picked[0]}**'s team!")
			return
		
		if args[1].lower() == "remove":
			if picked[2] not in current_flair_list:
				await message.channel.send("You don't have that team flair!")
			
			team_role = discord.utils.get(SERVER["MAIN"].roles, id=int(picked[2]))
			await author_member.remove_roles(team_role)
			await message.channel.send(f"You are no longer on **{picked[0]}**'s team.")
			return
Esempio n. 11
0
async def MAIN(message, args, level, perms, TWOW_CENTRAL, EVENT, GAME_CHANNEL):
    if not isinstance(
            message.channel,
            discord.DMChannel) and message.channel.id != GAME_CHANNEL:
        await message.channel.send(
            f"MiniMiniTWOW commands can only be used in <#{GAME_CHANNEL}>!")
        return

    if level == 1:
        await message.channel.send("Include a subcommand!")
        return

    # Shorten the notation for convenience
    mmt = EVENT["MMT"]

    if args[1].lower() == "stats":

        if level == 2:
            await message.channel.send(
                "Include the type of stat you want to see!")
            return

        db = Database()

        # public.mmtstats contains ids, placements in each round, and MMT wins from everyone who's participated
        # in any MMT rounds so far
        data = db.get_entries("mmtstats")

        if len(data) == 0:  # Just in case it gets reset one day
            await message.channel.send("There's no data yet!")
            return

        leaderboard = []

        if args[2].lower() == "points":
            for person in data:  # `person` is a table entry, (id, placements, wins)
                try:  # Try to find that person's username through TWOW Central
                    member = TWOW_CENTRAL.get_member(int(person[0])).name
                    if member is None:
                        member = person[0]
                except Exception:  # If you can't find them, just use the ID instead
                    member = person[0]

                # MMT seasons are joined with tabs and MMT rounds are joined with spaces in the database
                ranks = [x.split(" ") for x in person[1].split("\t")]
                score = 0
                rounds = 0

                for twow in ranks:  # For each season...
                    for p_round in twow:  # For each placement in a round...
                        if p_round.strip() == "":
                            continue
                        numbers = p_round.split(
                            "/")  # Get a list of [rank, contestantcount]
                        # Points adds the amount of people you beat each round
                        score += int(numbers[1]) - int(numbers[0])
                        rounds += 1  # Keep track of the round count too

                leaderboard.append([member, score, rounds])

        elif args[2].lower() == "wins":
            for person in data:
                try:
                    member = TWOW_CENTRAL.get_member(int(person[0])).name
                    if member is None:
                        member = person[0]
                except Exception:
                    member = person[0]

                leaderboard.append([
                    member, person[2]
                ])  # person[2] is MMT season wins, so that's all we need

        elif args[2].lower() == "roundwins":
            for person in data:
                try:
                    member = TWOW_CENTRAL.get_member(int(person[0])).name
                    if member is None:
                        member = person[0]
                except Exception:
                    member = person[0]

                ranks = [x.split(" ") for x in person[1].split("\t")]
                wins = 0

                for twow in ranks:
                    for p_round in twow:
                        if p_round.strip() == "":
                            continue

                        numbers = p_round.split("/")
                        if int(numbers[0]
                               ) == 1:  # Count up for each `1` placement
                            wins += 1

                leaderboard.append(
                    [member, wins])  # wins is the total number of round wins

        elif args[2].lower() == "nr":
            for person in data:
                try:
                    member = TWOW_CENTRAL.get_member(int(person[0])).name
                    if member is None:
                        member = person[0]
                except Exception:
                    member = person[0]

                ranks = [x.split(" ") for x in person[1].split("\t")]
                total = 0
                rounds = 0

                for twow in ranks:
                    for p_round in twow:
                        if p_round.strip() == "":
                            continue

                        numbers = p_round.split("/")
                        # Add this round's NR to the total
                        total += (int(numbers[1]) -
                                  int(numbers[0])) / (int(numbers[1]) - 1)
                        rounds += 1

                if rounds == 0:
                    continue

                # Format those as percentage strings
                average = "{:.2%}".format(total / rounds)
                total = "{:.2%}".format(total)

                leaderboard.append([member, total, average])

        else:
            return

        player_count = len(leaderboard)

        if args[2].lower(
        ) == "points":  # Sort by points descending, then rounds ascending
            leaderboard = sorted(leaderboard, key=lambda c: c[2])
            leaderboard = sorted(leaderboard, reverse=True, key=lambda c: c[1])
        if args[2].lower(
        ) == "nr":  # Sort by total NR -- remove the percentage and convert to float first
            leaderboard = sorted(leaderboard,
                                 reverse=True,
                                 key=lambda c: float(c[1][:-1]))
        if args[2].lower() in [
                "wins", "roundwins"
        ]:  # Just sort by wins ascending. Remove people who have none
            leaderboard = sorted(leaderboard, reverse=True, key=lambda c: c[1])
            leaderboard = [x for x in leaderboard if x[1] != 0]

        for line in range(len(
                leaderboard)):  # Add the rank to each line of the leaderboard
            leaderboard[line] = [line + 1] + leaderboard[line]

        # args[3] is the page number.
        if level == 3:  # If it's not specified, assume it's the first page
            leaderboard = leaderboard[:10]
            page = 1

        elif not is_whole(
                args[3]
        ):  # If it's not a valid integer, assume it's first page also
            leaderboard = leaderboard[:10]
            page = 1

        elif (int(args[3]) - 1) * 10 >= len(
                leaderboard):  # Detect if the page number is too big
            await message.channel.send(
                f"There is no page {args[3]} of this stat!")
            return

        else:  # This means the user specified a valid page number
            lower = (int(args[3]) - 1) * 10
            upper = int(args[3]) * 10
            leaderboard = leaderboard[lower:upper]
            page = args[3]

        # Headers for each stat
        if args[2].lower() == "points":
            final_message = f"```diff\n---⭐ MiniMiniTWOW Point Leaderboard Page {page} ⭐---\n\n"
            final_message += " Rank |  Name                    |  Pts.  |  Rounds\n"
            spacing = 6
        if args[2].lower() == "nr":
            final_message = f"```diff\n---⭐ MiniMiniTWOW Normalized Rank Leaderboard Page {page} ⭐---\n\n"
            final_message += " Rank |  Name                    |   Total   |  Average\n"
            spacing = 9
        if args[2].lower() == "wins":
            final_message = f"```diff\n---⭐ MiniMiniTWOW Wins Leaderboard Page {page} ⭐---\n\n"
            final_message += " Rank |  Name                    |  Wins\n"
            spacing = 4
        if args[2].lower() == "roundwins":
            final_message = f"```diff\n---⭐ MiniMiniTWOW Round Wins Leaderboard Page {page} ⭐---\n\n"
            final_message += " Rank |  Name                    |  Round Wins\n"
            spacing = 5

        # Composition of each line of the leaderboard
        for line in leaderboard:
            symbol = "+" if line[0] == 1 else "-"
            spaced_rank = f"{line[0]}{' ' * (4 - len(str(line[0])))}"
            spaced_name = f"{line[1][:23]}{' '*(24 - len(str(line[1])))}"
            spaced_points = f"{line[2]}{' '*(spacing - len(str(line[2])))}"
            try:  # Some stats will have two number columns...
                formatted = f"{symbol} {spaced_rank}|  {spaced_name}|  {spaced_points}|  {line[3]}\n"
            except:  # ...but others will have one. This try except block detects each one.
                formatted = f"{symbol} {spaced_rank}|  {spaced_name}|  {spaced_points}\n"

            final_message += formatted  # Add the line to the message

        final_message += "```"  # Close off the code block

        await message.channel.send(final_message)
        return

    if args[1].lower() == "end":
        if not mmt.RUNNING:
            await message.channel.send(
                "There's no MiniMiniTWOW running right now!")
            return

        if message.author.id == mmt.info["GAME"][
                "HOST"]:  # Automatically end MMT if it's the host trying to end it
            await message.channel.send(
                "**The current MiniMiniTWOW has been ended by the host! The queue moves on.**"
            )
            mmt.force_skip()
            return

        if perms == 2:  # Do the same if it's a staff member
            await message.channel.send(
                "**The current MiniMiniTWOW has been ended by staff! The queue moves on.**"
            )
            mmt.force_skip()
            return

        if mmt.info["GAME"][
                "PERIOD"] == 1:  # Spectator votes have to wait until post-start, though
            await message.channel.send(
                "You can only vote to end a MiniMiniTWOW that has already started!"
            )
            return

        spect = len(mmt.info["SPECTATORS"])  # Number of spectators
        necessary = np.ceil(
            spect**(4 / 5) + 0.8
        )  # By the formula, the number of votes necessary to end the MMT

        # If there are less than 4 spectators, you can't end an MMT by spectator vote. As such, there's not much
        # reason to bother including the amount of votes necessary if necessary > spect, so include it only if
        # necessary <= spect instead
        nec_seg = ""
        if necessary <= spect:
            nec_seg = f"/{necessary}"

        if message.author.id in mmt.info["GAME"]["END_VOTES"]:
            # Filter the user's ID out of the list of end voters
            mmt.info["GAME"]["END_VOTES"] = [
                x for x in mmt.info["GAME"]["END_VOTES"]
                if x != message.author.id
            ]
            votes = len(mmt.info["GAME"]
                        ["END_VOTES"])  # Calculate the new number of votes
            await message.channel.send(
                f"""πŸšͺ {message.author.mention} removes their vote to end the MiniMiniTWOW. 
			There are now **{votes}{nec_seg}** votes.""")
            return

        mmt.info["GAME"]["END_VOTES"].append(
            message.author.id)  # Add user's ID to list of end votes
        votes = len(
            mmt.info["GAME"]["END_VOTES"])  # Calculate new number of votes
        await message.channel.send(
            f"""πŸšͺ **{message.author.mention} voted to end the MiniMiniTWOW!** 
		There are now **{votes}{nec_seg}** votes.""")

        if votes >= necessary:  # If the amount of votes reaches the required...
            await message.channel.send(
                """**The current MiniMiniTWOW has been ended 
			by public vote! The queue moves on.**""".replace("\n",
                                                    "").replace("\t", ""))
            mmt.force_skip(
            )  # Function to skip a host, also used in Events/mmt.py

        return

    if args[1].lower() == "transfer":
        if not mmt.RUNNING:
            await message.channel.send(
                "There's no MiniMiniTWOW running right now!")
            return

        if mmt.info["GAME"]["PERIOD"] == 0:
            await message.channel.send(
                "Host transfers can only occur with MiniMiniTWOWs that have been created."
            )
            return

        if mmt.info["GAME"]["HOST"] != message.author.id:
            await message.channel.send(
                "Only the host can transfer the MiniMiniTWOW to someone else!")
            return

        if level == 2:
            await message.channel.send("Choose a user to transfer it to!")
            return

        # You have to ping the person you wanna transfer it to
        mention = args[2]
        try:
            user_id = int(mention[2:-1])
        except:
            await message.channel.send(
                "Invalid user! Ping the user you want to transfer the MiniMiniTWOW to!"
            )
            return

        # Try to find the person in TWOW Central
        person = TWOW_CENTRAL.get_member(user_id)

        if person is None:  # If they're not in TWOW Central, they can't become the new host
            await message.channel.send(
                "Invalid user! Ping the user you want to transfer the MiniMiniTWOW to!"
            )
            return

        if 'confirm' not in [
                x.lower() for x in args
        ]:  # Confirmation can be bypassed by including `confirm`
            await message.channel.send(
                f"""Are you sure you want to transfer the MiniMiniTWOW to **{person.name}**? 
			Send `confirm` to transfer.""".replace("\n", "").replace("\t", ""))

            # Check for the next message by the same person in the same channel
            msg = await BRAIN.wait_for(
                'message',
                check=lambda m:
                (m.author == message.author and m.channel == message.channel))

            if msg.content.lower(
            ) != "confirm":  # If it's not `confirm`, cancel the command
                await message.channel.send("Transfer command cancelled.")
                return

        msg_send = f"Successfully transfered host position to **{person.name}**!"

        # Make the new person the host
        mmt.info["GAME"]["HOST"] = user_id

        # Reset the timers for host actions if necessary
        if mmt.info["GAME"][
                "PERIOD"] == 1 and mmt.info["GAME"]["PERIOD_START"] != 0:
            mmt.info["GAME"]["PERIOD_START"] = time.time()
            msg_send += f""" The timer to start the MiniMiniTWOW is reset. {mention} has {mmt.param["S_DEADLINE"]} 
			seconds to start it with `tc/mmt start`.""".replace("\n",
                                                       "").replace("\t", "")

        if mmt.info["GAME"]["PERIOD"] == 2:
            mmt.info["GAME"]["PERIOD_START"] = time.time()
            msg_send += f""" The timer to set the prompt is reset. {mention} has {mmt.param["P_DEADLINE"]} 
			seconds to decide on the prompt with `tc/mmt prompt`.""".replace(
                "\n", "").replace("\t", "")

        await message.channel.send(msg_send)
        return

    if args[1].lower() == "queue":
        if level == 2:  # If it's just `tc/mmt queue`
            if not mmt.RUNNING:  # The event is counted as off if there's nobody in queue. To check the queue, it needs
                # to be on, so being the first to join the queue will start up the event
                mmt.start(TWOW_CENTRAL)

            if message.author.id in mmt.info[
                    "HOST_QUEUE"]:  # If you're already in queue, leaves the queue
                mmt.info["HOST_QUEUE"] = [
                    x for x in mmt.info["HOST_QUEUE"] if x != message.author.id
                ]
                await mmt.MMT_C.send(
                    f"🎩 <@{message.author.id}> has been removed from queue.")
                return

            mmt.info["HOST_QUEUE"].append(
                message.author.id
            )  # If you're not in queue, you're added to queue
            await message.channel.send(
                f"🎩 <@{message.author.id}> has been added to queue at position **{len(mmt.info['HOST_QUEUE'])}**."
            )
            return

        if args[2].lower() == "list":
            if len(
                    mmt.info["HOST_QUEUE"]
            ) == 0:  # If the event is not running, the host queue's length is also 0
                await message.channel.send("The queue is empty!")
                return

            # Array I use to split the list into multiple messages if necessary
            init = ["**This is the current MiniMiniTWOW hosting queue:**\n\n"]

            for person in mmt.info["HOST_QUEUE"]:  # `person` is an ID
                member = TWOW_CENTRAL.get_member(
                    person)  # Try to find the user

                if member is None:  # If you can't find the user, just use their ID and format it
                    member = f"`{person}`"
                else:  # If you found the user, use their username
                    member = member.name

                # Define the line that's about to be added
                line = f"🎩 [{mmt.info['HOST_QUEUE'].index(person) + 1}] - **{member}**\n"

                # If adding this line steps over the character limit, add another string to the array
                # 1950 instead of 2000 because having over 1950 can cause issues for like no reason
                if len(init[-1] + line) > 1950:
                    line.append("")
                init[-1] += line  # Add the line to this new string

            for z in init:  # Send each of those strings as a separate message
                await message.channel.send(z)
            return

    if args[1].lower() == "create":
        if not mmt.RUNNING:  # If the event isn't running
            await message.channel.send(
                f"There's no host to create a MiniMiniTWOW! Join the queue with `{PREFIX}mmt queue` to host!"
            )
            return

        if mmt.info["GAME"]["PERIOD"] != 0:  # If it's not time to create one
            await message.channel.send(
                "There's already a MiniMiniTWOW running!")
            return

        if message.author.id != mmt.info["GAME"]["HOST"]:  # If you're not host
            await message.channel.send(
                "You can only create a MiniMiniTWOW if you're up on the queue!"
            )
            return

        # Switch the period to 1 (signups)
        mmt.info["GAME"]["PERIOD"] = 1
        mmt.info["GAME"]["PERIOD_START"] = 0

        await message.channel.send(
            f"🎩 <@{message.author.id}> has created a MiniMiniTWOW! Use `{PREFIX}mmt join` to join it!"
        )
        return

    if args[1].lower() == "spectate":
        if not mmt.RUNNING:  # If the event isn't running
            await message.channel.send(
                "There's no MiniMiniTWOW running right now!")
            return

        if mmt.info["GAME"][
                "PERIOD"] == 0:  # If `tc/mmt create` hasn't been run
            await message.channel.send(
                "You can only spectate a MiniMiniTWOW that has been created!")
            return

        if message.author.id in mmt.info[
                "SPECTATORS"]:  # If you're a spectator...
            # ...You're removed from the list of spectators
            mmt.info["SPECTATORS"] = [
                x for x in mmt.info["SPECTATORS"] if x != message.author.id
            ]
            await mmt.MMT_C.send(
                f"πŸ‘οΈ <@{message.author.id}> is no longer spectating.")
            return

        mmt.info["SPECTATORS"].append(
            message.author.id)  # Adds user to the list of spectators
        await mmt.MMT_C.send(
            f"""πŸ‘οΈ <@{message.author.id}> is now spectating, and will receive voting screens 
		for future rounds.""".replace("\n", "").replace("\t", ""))
        return

    if args[1].lower() == "join":
        if not mmt.RUNNING:  # If the event is not running
            await message.channel.send(
                "There's no MiniMiniTWOW running right now!")
            return

        if mmt.info["GAME"]["PERIOD"] != 1:  # If it's not signup period
            await message.channel.send(
                "You can only join the MiniMiniTWOW if it's in signups!")
            return

        if message.author.id in mmt.info[
                "PLAYERS"]:  # If you're already a player
            # Remove you both from the player list and the spectator list
            mmt.info["PLAYERS"] = [
                x for x in mmt.info["PLAYERS"] if x != message.author.id
            ]
            mmt.info["SPECTATORS"] = [
                x for x in mmt.info["SPECTATORS"] if x != message.author.id
            ]

            await mmt.MMT_C.send(
                f"🏁 <@{message.author.id}> left the MiniMiniTWOW. Our player count is {len(mmt.info['PLAYERS'])}."
            )

            if len(
                    mmt.info['PLAYERS']
            ) == 1:  # The timer is cancelled if there's no longer 2 players
                await mmt.MMT_C.send(
                    "🏁 We no longer have two players. The three minute start timer is now reset."
                )
            return

        mmt.info["PLAYERS"].append(message.author.id)  # Adds user as a player
        if message.author.id not in mmt.info["SPECTATORS"]:
            mmt.info["SPECTATORS"].append(
                message.author.id
            )  # And a spectator, if they're not already one

        await mmt.MMT_C.send(
            f"🏁 **<@{message.author.id}> joined the MiniMiniTWOW!** Our player count is now {len(mmt.info['PLAYERS'])}!"
        )
        if len(mmt.info['PLAYERS']
               ) == 2:  # If there are two players, the signup timer begins
            await mmt.MMT_C.send(
                f"""🏁 We have two players! <@{mmt.info["GAME"]["HOST"]}> has three minutes 
			to start the MiniMiniTWOW with `{PREFIX}mmt start`.""".replace(
                    "\n", "").replace("\t", ""))
            mmt.info["GAME"]["PERIOD_START"] = time.time()
        return

    if args[1].lower() == "start":
        if not mmt.RUNNING:  # If the event isn't running
            await message.channel.send(
                "There's no MiniMiniTWOW running right now!")
            return

        if mmt.info["GAME"]["PERIOD"] != 1:  # If it's not signup period
            await message.channel.send(
                "You can only start a MiniMiniTWOW if it's in signups!")
            return

        if message.author.id != mmt.info["GAME"]["HOST"]:  # If user isn't host
            await message.channel.send(
                "Only the host can start a MiniMiniTWOW!")
            return

        if len(mmt.info["PLAYERS"]) < 2:  # If there aren't two contestants
            await message.channel.send(
                "You need at least two contestants to start a MiniMiniTWOW!")
            return

        # Set it to round 1 with period 2 (prompt deciding)
        mmt.info["GAME"]["ROUND"] = 1
        mmt.info["GAME"]["PERIOD"] = 2
        mmt.info["GAME"]["PERIOD_START"] = time.time()

        await mmt.MMT_C.send(
            f"""🏁 <@{message.author.id}> has started the MiniMiniTWOW with 
		{len(mmt.info["PLAYERS"])} contestants. Nobody can sign up anymore.""".
            replace("\n", "").replace("\t", ""))

        return

    if args[1].lower() == "prompt":
        if not mmt.RUNNING:  # If the event isn't running
            await message.channel.send(
                "There's no MiniMiniTWOW running right now!")
            return

        if mmt.info["GAME"][
                "PERIOD"] != 2:  # If it's not prompt decision period
            await message.channel.send(
                "You can only set a prompt inbetween rounds!")
            return

        if message.author.id != mmt.info["GAME"]["HOST"]:  # If user isn't host
            await message.channel.send("Only the host can set a prompt!")
            return

        if level == 2:
            await message.channel.send("You need to include a prompt!")
            return

        # Remove formatting and characters that might cause errors
        prompt = " ".join(args[2:]).replace("`",
                                            "").replace("\t",
                                                        "").replace("\n", "")

        if len(prompt) > 200:
            await message.channel.send(
                "That prompt is too long! It must be 200 characters at most.")
            return

        # Switch to responding period, set the rpompt, prepare the responses array
        mmt.info["GAME"]["PERIOD"] = 3
        mmt.info["GAME"]["PERIOD_START"] = time.time()
        mmt.info["GAME"]["PROMPT"] = prompt
        mmt.info["RESPONSES"] = [""] * len(mmt.info["PLAYERS"])

        await mmt.MMT_C.send(
            f"""πŸ“ **Round {mmt.info["GAME"]["ROUND"]} Responding** has started! The prompt is:
		```{prompt}```
		Our contestants have {mmt.param["R_DEADLINE"]} seconds to respond to it.""".
            replace("\n", "").replace("\t", ""))

        for player in mmt.info["PLAYERS"]:
            try:  # DM everyone the prompt
                await TWOW_CENTRAL.get_member(player).send(f"""
				πŸ“ **Round {mmt.info["GAME"]["ROUND"]} Responding** has started! The prompt is:
				```{prompt}```
				You must respond in {mmt.param["R_DEADLINE"]} seconds using `{PREFIX}mmt respond`!
				""".replace("\n", "").replace("\t", ""))
            except Exception:  # If something goes wrong, skip the person
                pass
        return

    if args[1].lower() == "respond":
        if not isinstance(message.channel, discord.DMChannel):  # If not in DMs
            await mmt.MMT_C.send("This command can only be used in DMs!")
            return

        if not mmt.RUNNING:  # If event isn't running
            await message.channel.send(
                "There's no MiniMiniTWOW running right now!")
            return

        if mmt.info["GAME"]["PERIOD"] != 3:  # If it's not submission period
            await message.channel.send(
                "You can only respond during a submission period!")
            return

        if message.author.id not in mmt.info[
                "PLAYERS"]:  # If you're not a player
            await message.channel.send("Only alive contestants can respond!")
            return

        if level == 2:
            await message.channel.send("You need to include a response!")
            return

        # Run the formatting_fix function, remove characters that might cause issues and strip unnecessary whitespace
        response = formatting_fix(" ".join(args[2:]).replace("`", "").replace(
            "\t", "").replace("\n", "")).strip()

        if len(response) > 120:  # Too long
            await message.channel.send(
                "Your response is too long! It must be 120 characters at most."
            )
            return

        if len(response) == 0:  # Literally empty
            await message.channel.send(
                "Your response evaluates to an empty string.")
            return

        ind = mmt.info["PLAYERS"].index(
            message.author.id)  # Index of the user in the players array
        new = not mmt.info["RESPONSES"][
            ind] == ""  # Detects if this is a new response or an edit

        while response in mmt.info[
                "RESPONSES"]:  # If this response has already been submitted...
            response += "\u200b"  # ...distinguish between them by adding a zero-width space to the end of one
        # Keep doing so until it's unique (in the case there's more than two identical entries)

        mmt.info["RESPONSES"][
            ind] = response  # Set the response to the one submitted

        await message.channel.send(
            f"""Your {'new ' if new else ''}response to the prompt has been recorded as:
		```{response}```> **Word count:** {word_count(response)}""".replace(
                "\n", "").replace("\t", ""))
        return

    if args[1].lower() == "vote":
        if not isinstance(message.channel, discord.DMChannel):  # If not in DMs
            await mmt.MMT_C.send("This command can only be used in DMs!")
            return

        if not mmt.RUNNING:  # If event isn't running
            await message.channel.send(
                "There's no MiniMiniTWOW running right now!")
            return

        if message.author.id not in mmt.info["VOTES"][
                "ID"]:  # If you didn't receive a voting screen
            await message.channel.send(
                "You can only vote if you received a voting screen!")
            return

        if mmt.info["GAME"]["PERIOD"] != 4:  # If it's not voting period
            await message.channel.send(
                "You can only vote during a voting period!")
            return

        if level == 2:
            await message.channel.send("You need to include a vote!")
            return

        vote = args[2].upper()  # Always convert vote to uppercase
        ind = mmt.info["VOTES"]["ID"].index(
            message.author.id)  # Index of user in the votes arrays
        screen = mmt.info["VOTES"]["RESP"][
            ind]  # Check the screen the user received

        # The screen has `n` responses, so the vote should be composed of the first `n` letters of the alphabet
        # Otherwise, it's invalid
        if sorted(list(vote)) != sorted(list(ALPHABET[:len(screen)])):
            await message.channel.send(
                """Your vote is invalid. Make sure you're not missing or repeating any letters, 
			or including any invalid characters.""".replace("\n", "").replace("\n", ""))
            return

        # Instantly convert the vote to the score it'll give to each response
        parsed_vote = []
        for z in range(len(vote)):
            score = (len(vote) - 1 - vote.find(ALPHABET[z])) / (len(vote) - 1)
            parsed_vote.append(str(score))

        new = not mmt.info["VOTES"]["VOTE"][
            ind] == ""  # Detect if the vote is new or an edit
        mmt.info["VOTES"]["VOTE"][ind] = " ".join(
            parsed_vote)  # Join the list of values and record it

        # Display the vote back as the letters
        await message.channel.send(
            f"""Your {'new ' if new else ''}vote has been recorded as: 
		```{vote}```""".replace("\n", "").replace("\t", ""))
        return