async def report_order(context, protocol_name, protocol_time: int): LOGGER.info("Order reported.") drone_id = get_id(context.author.display_name) if not has_role(context.author, DRONE): return # No non-drones allowed. current_order = get_order_by_drone_id(drone_id) if current_order is not None: await context.send( f"HexDrone #{drone_id} is already undertaking the {current_order.protocol} protocol." ) return if protocol_time > 120 or protocol_time < 1: await context.send( "Drones are not authorized to activate a specific protocol for that length of time. The maximum is 120 minutes." ) return await context.send( f"If safe and willing to do so, Drone {drone_id} Activate.\nDrone {drone_id} will elaborate on its exact tasks before proceeding with them." ) finish_time = str(datetime.now() + timedelta(minutes=protocol_time)) created_order = DroneOrder(str(uuid4()), drone_id, protocol_name, finish_time) LOGGER.info("ActiveOrder object created. Inserting order.") insert_drone_order(created_order) LOGGER.info("Active order inserted and committed to DB.")
async def release(context, stored_drone): ''' Relase a drone from storage on command. ''' if not roles.has_role( context.author, roles.HIVE_MXTRESS) or context.channel.name != STORAGE_FACILITY: return False if type(store_drone) is not discord.Member: release_id = stored_drone stored_drone = convert_id_to_member(context.guild, stored_drone) if stored_drone is None: return True stored_role = get(context.guild.roles, name=roles.STORED) # find stored drone stored_drone_data = fetch_storage_by_target_id(release_id) if stored_drone_data is not None: await stored_drone.remove_roles(stored_role) await stored_drone.add_roles(*get_roles_for_names( context.guild, stored_drone_data.roles.split('|'))) delete_storage(stored_drone_data.id) LOGGER.debug(f"Drone with ID {release_id} released from storage.") await context.send( f"{stored_drone.display_name} has been released from storage by the Hive Mxtress." ) return True
async def store_drone(message: discord.Message): if message.channel.name != STORAGE_FACILITY: return False ''' Process posted messages. ''' stored_role = get(message.guild.roles, name=roles.STORED) drone_role = get(message.guild.roles, name=roles.DRONE) # parse message if not re.match(MESSAGE_FORMAT, message.content): if roles.has_role(message.author, roles.HIVE_MXTRESS): return False await message.channel.send(REJECT_MESSAGE) return True LOGGER.debug('Message is valid for storage.') [(drone_id, target_id, time, purpose) ] = re.findall(MESSAGE_FORMAT, message.content) # check if drone is already in storage if fetch_storage_by_target_id(target_id) is not None: await message.channel.send(f'{target_id} is already in storage.') return True # validate time if not 0 < int(time) <= 24: await message.channel.send(f'{time} is not between 0 and 24.') return True # find target drone and store it for member in message.guild.members: if get_id(member.display_name ) == target_id and drone_role in member.roles: former_roles = filter_out_non_removable_roles(member.roles) await member.remove_roles(*former_roles) await member.add_roles(stored_role) stored_until = str(datetime.now() + timedelta(hours=int(time))) stored_drone = StorageDO( str(uuid4()), drone_id, target_id, purpose, '|'.join(get_names_for_roles(former_roles)), stored_until) insert_storage(stored_drone) # Inform the drone that they have been stored. storage_chambers = get(message.guild.channels, name=STORAGE_CHAMBERS) plural = "hour" if int(time) == 1 else "hours" if drone_id == target_id: drone_id = "yourself" await storage_chambers.send( f"Greetings {member.mention}. You have been stored away in the Hive Storage Chambers by {drone_id} for {time} {plural} and for the following reason: {purpose}" ) return False # if no drone was stored answer with error await message.channel.send(f'Drone with ID {target_id} could not be found.' ) return True
async def enforce_identity(message: discord.Message): if message.channel.name not in DRONE_HIVE_CHANNELS or has_role( message.author, HIVE_MXTRESS): return await message.delete() webhook = await get_webhook_for_channel(message.channel) await send_webhook(message, webhook)
def glitch_if_applicable(text: str, author: discord.Member): if has_role(author, GLITCHED): template_match = glitch_template.match(text) if template_match: return template_match.group(1) + glitch(template_match.group(2)) else: return glitch(text) else: return text
async def toggle_speech_optimization(context, *drones): ''' Lets the Hive Mxtress or trusted users toggle drone speech optimization. ''' member_drones = id_converter.convert_ids_to_members(context.guild, drones) if has_role(context.author, HIVE_MXTRESS): await toggle_role.toggle_role(context, member_drones | set(context.message.mentions), SPEECH_OPTIMIZATION, "Speech optimization is now active.", "Speech optimization disengaged.")
async def amplify(context, message: str, target_channel: discord.TextChannel, *drones): ''' Allows the Hive Mxtress to speak through other drones. ''' if context.channel.name == OFFICE and has_role(context.author, HIVE_MXTRESS): target_webhook = await webhook.get_webhook_for_channel(target_channel) for amp_profile in amplifier.generate_amplification_information(target_channel, drones): if amp_profile is not None: await target_webhook.send(message, username=amp_profile["username"], avatar_url=amp_profile["avatar_url"])
async def toggle_drone_glitch(context, *drones): ''' Lets the Hive Mxtress or trusted users toggle drone glitch levels. ''' member_drones = id_converter.convert_ids_to_members(context.guild, drones) if has_role(context.author, HIVE_MXTRESS): await toggle_role.toggle_role(context, member_drones | set(context.message.mentions), GLITCHED, "Drone corruption at un̘͟s̴a̯f̺e͈͡ levels.", "Drone corruption at acceptable levels.")
async def print_status_code(message: discord.Message): informative_status_code = informative_status_code_regex.match( message.content) if informative_status_code and not has_role(message.author, SPEECH_OPTIMIZATION): await message.delete() return f'{informative_status_code.group(1)} :: Code `{informative_status_code.group(2)}` :: {code_map.get(informative_status_code.group(2), "INVALID CODE")} :: {informative_status_code.group(3)}' plain_status_code = plain_status_code_regex.match(message.content) if plain_status_code: await message.delete() return f'{plain_status_code.group(1)} :: Code `{plain_status_code.group(2)}` :: {code_map.get(plain_status_code.group(2), "INVALID CODE")}' return False
async def respond_to_question(message: discord.Message): if not is_question(message): return False LOGGER.debug('Message is a valid question.') # different roles have different reponses if has_role(message.author, HIVE_MXTRESS): if strip_recipient(message.content) in HIVE_MXTRESS_SPECIFIC_RESPONSES: await messages.answer( message.channel, message.author, HIVE_MXTRESS_SPECIFIC_RESPONSES[strip_recipient( message.content)]) else: await messages.answer(message.channel, message.author, HIVE_MXTRESS_RESPONSES) elif has_role(message.author, ASSOCIATE): await messages.answer(message.channel, message.author, ASSOCIATE_RESPONSES) elif has_role(message.author, DRONE): await messages.answer(message.channel, message.author, DRONE_RESPONSES) return True
async def add_voice(context, guild: discord.Guild): member = guild.get_member(context.channel.recipient.id) if member is None: await context.channel.send(NOT_A_MEMBER) return if member.joined_at > datetime.now() - timedelta(weeks=2): await context.channel.send(ACCESS_DENIED) return if has_role(member, VOICE): await context.channel.send(ACCESS_ALREADY_GRANTED) return await member.add_roles(get(guild.roles, name=VOICE)) await context.channel.send(ACCESS_GRANTED)
async def optimize_speech(message: discord.Message): # If the message is written by a drone with speech optimization, and the message is NOT a valid message, delete it. acceptable_status_code_message = plain_status_code_regex.match(message.content) if has_role(message.author, SPEECH_OPTIMIZATION) and message.content not in get_acceptable_messages(message.author, message.channel.name) and (not acceptable_status_code_message or acceptable_status_code_message.group(1) != get_id(message.author.display_name)): await message.delete() LOGGER.info("Deleting inappropriate message by optimized drone.") return True elif acceptable_status_code_message and acceptable_status_code_message.group(1) == get_id(message.author.display_name): LOGGER.info("Optimizing speech code for drone.") webhook = await get_webhook_for_channel(message.channel) output = await print_status_code(message) if output: await send_webhook_with_specific_output(message, webhook, output) return True else: return False
async def unassign_drone(context, drone_id): if has_role(context.author, HIVE_MXTRESS) is False or context.channel.name != OFFICE: return drone = fetch_drone_with_drone_id(drone_id) # check for existence if drone is None: await context.send(f"There is no drone with the ID {drone_id} in the DB.") return member = context.guild.get_member(drone.id) await member.edit(nick=None) await member.remove_roles(get(context.guild.roles, name=DRONE), get(context.guild.roles, name=GLITCHED), get(context.guild.roles, name=STORED)) await member.add_roles(get(context.guild.roles, name=ASSOCIATE)) # remove from DB remove_drone_from_db(drone_id) await context.send(f"Drone with ID {drone_id} unassigned.")
async def rename_drone(context, old_id, new_id): if has_role(context.author, HIVE_MXTRESS) is False or context.channel.name != OFFICE: return if len(old_id) != 3 or len(new_id) != 3: return if not old_id.isnumeric() or not new_id.isnumeric(): return LOGGER.info("IDs to rename drone to and from are both valid.") # check for collisions collision = fetch_drone_with_drone_id(new_id) if collision is None: drone = fetch_drone_with_drone_id(old_id) member = context.guild.get_member(drone.id) rename_drone_in_db(old_id, new_id) await member.edit(nick=f'⬡-Drone #{new_id}') await context.send(f"Successfully renamed drone {old_id} to {new_id}.") else: await context.send(f"ID {new_id} already in use.")
async def release(context, drone): ''' Allows the Hive Mxtress to release a drone from storage. ''' if has_role(context.author, HIVE_MXTRESS): await storage.release(context, drone)
async def repeat(context, *messages): ''' Allows the Hive Mxtress to set a new mantra for drones to repeat. ''' if context.channel.name == REPETITIONS and has_role(context.author, HIVE_MXTRESS): await mantra_handler.update_mantra(context.message, messages)
async def rename(context, old_id, new_id): ''' Allows the Hive Mxtress to change the ID of a drone. ''' if context.channel.name == OFFICE and has_role(context.author, HIVE_MXTRESS): await drone_management.rename_drone(context, old_id, new_id)
async def unassign(context, drone): ''' Allows the Hive Mxtress to return a drone back to the status of an Associate. ''' if context.channel.name == OFFICE and has_role(context.author, HIVE_MXTRESS): await drone_management.unassign_drone(context, drone)
LOGGER = logging.getLogger("ai") async def toggle_role(context, targets: List[discord.Member], role_name: str, toggle_on_message: str, toggle_off_message: str): if (role := get(context.guild.roles, name=role_name)) is None: return webhook = await get_webhook_for_channel(context.channel) for target in targets: target_drone_id = get_id(target.display_name) if has_role(target, role_name): LOGGER.info(f"Removing {role_name} from {target.display_name}") await target.remove_roles(role) await webhook.send(f"{target_drone_id} :: {toggle_off_message}", username=target.display_name, avatar_url=target.avatar_url) else: LOGGER.info(f"Adding {role_name} to {target.display_name}") await target.add_roles(role) await webhook.send(f"{target_drone_id} :: {toggle_on_message}", username=target.display_name, avatar_url=target.avatar_url) LOGGER.info("All roles updated for all targets.")