class AliasController: def inject(self, registry): self.command_alias_service = registry.get_instance("command_alias_service") self.text = registry.get_instance("text") @command(command="alias", params=[Const("list")], access_level="all", description="List command aliases") def alias_list_cmd(self, request, _): data = self.command_alias_service.get_enabled_aliases() count = len(data) padded_rows = self.text.pad_table(list(map(lambda row: [row.alias, row.command], data))) blob = "" for cols in padded_rows: blob += " ".join(cols) + "\n" return ChatBlob(f"Aliases ({count})", blob) @command(command="alias", params=[Const("add"), Any("alias"), Any("command")], access_level="admin", description="Add a command alias", sub_command="modify") def alias_add_cmd(self, request, _, alias, command_str): if self.command_alias_service.add_alias(alias, command_str, force_enable=True): return f"Alias <highlight>{alias}</highlight> for command <highlight>{command_str}</highlight> added successfully." else: return f"Cannot add alias <highlight>{alias}</highlight> since there is already an active alias with that name." @command(command="alias", params=[Options(["rem", "remove"]), Any("alias")], access_level="admin", description="Remove a command alias", sub_command="modify") def alias_remove_cmd(self, request, _, alias): if self.command_alias_service.remove_alias(alias): return f"Alias <highlight>{alias}</highlight> has been removed successfully." else: return f"Could not find alias <highlight>{alias}</highlight>."
class SqlController: def inject(self, registry): self.bot = registry.get_instance("bot") self.db = registry.get_instance("db") self.command_alias_service = registry.get_instance("command_alias_service") self.getresp = registry.get_instance("translation_service").get_response def start(self): self.command_alias_service.add_alias("querysql", "sql query") self.command_alias_service.add_alias("executesql", "sql exec") @command(command="sql", params=[Const("query"), Any("sql_statement")], access_level="superadmin", description="Execute a SQL query and return the results") def sql_query_cmd(self, request, _, sql): try: results = self.db.query(sql) return ChatBlob(self.getresp("module/system", "sql_blob_title", {"count": len(results)}), json.dumps(results, indent=4, sort_keys=True)) except Exception as e: return self.getresp("module/system", "sql_fail", {"error": str(e)}) @command(command="sql", params=[Const("exec"), Any("sql_statement")], access_level="superadmin", description="Execute a SQL query and return number of affected rows") def sql_exec_cmd(self, request, _, sql): try: row_count = self.db.exec(sql) return self.getresp("module/system", "sql_exec_success", {"count": row_count}) except Exception as e: return self.getresp("module/system", "sql_fail", {"error": str(e)})
class SqlController: def inject(self, registry): self.bot = registry.get_instance("bot") self.db = registry.get_instance("db") self.command_alias_service = registry.get_instance( "command_alias_service") def start(self): self.command_alias_service.add_alias("querysql", "sql query") self.command_alias_service.add_alias("executesql", "sql exec") @command(command="sql", params=[Const("query"), Any("sql_statement")], access_level="superadmin", description="Execute a SQL query and return the results") def sql_query_cmd(self, request, _, sql): try: results = self.db.query(sql) return ChatBlob("Results (%d)" % len(results), json.dumps(results, indent=4, sort_keys=True)) except Exception as e: return "There was an error executing your query: %s" % str(e) @command( command="sql", params=[Const("exec"), Any("sql_statement")], access_level="superadmin", description="Execute a SQL query and return number of affected rows") def sql_exec_cmd(self, request, _, sql): try: row_count = self.db.exec(sql) return "%d row(s) affected." % row_count except Exception as e: return "There was an error executing your query: %s" % str(e)
class BosslootController: def inject(self, registry): self.db: DB = registry.get_instance("db") self.text: Text = registry.get_instance("text") def pre_start(self): self.db.load_sql_file(self.module_dir + "/" + "boss.sql") self.db.load_sql_file(self.module_dir + "/" + "boss_loot.sql") @command(command="boss", params=[Any("search")], access_level="all", description="Show loot for a boss") def boss_cmd(self, request, search): sql = "SELECT b.id, b.name, w.answer FROM boss b LEFT JOIN whereis w ON b.name = w.name WHERE b.name <EXTENDED_LIKE=0> ?" data = self.db.query(sql, [search], extended_like=True) cnt = len(data) blob = "" for row in data: blob += self.format_boss(row) blob += "\n\n" return ChatBlob("Boss Search Results for '%s' (%d)" % (search, cnt), blob) @command(command="bossloot", params=[Any("search")], access_level="all", description="Show loot for a boss") def bossloot_cmd(self, request, search): sql = "SELECT DISTINCT b2.id, b2.name, w.answer " \ "FROM boss_loot b1 JOIN boss b2 ON b2.id = b1.boss_id LEFT JOIN whereis w ON w.name = b2.name " \ "WHERE b1.item_name <EXTENDED_LIKE=0> ?" data = self.db.query(sql, [search], extended_like=True) cnt = len(data) blob = "" for row in data: blob += self.format_boss(row) blob += "\n\n" return ChatBlob( "Bossloot Search Results for '%s' (%d)" % (search, cnt), blob) def format_boss(self, row): data = self.db.query( "SELECT * FROM boss_loot b LEFT JOIN aodb a ON b.item_name = a.name WHERE b.boss_id = ? ORDER BY b.item_name ASC", [row.id]) blob = "<pagebreak>" blob += "<header2>%s</header2>\n" % row.name blob += "Location: <highlight>%s</highlight>\n" % row.answer blob += "Loot: " + ", ".join( map( lambda x: self.text.make_item(x.lowid, x.highid, x.highql, x. name), data)) return blob
class AliasController: def __init__(self): pass def inject(self, registry): self.command_alias_manager = registry.get_instance( "command_alias_manager") def start(self): pass @command(command="alias", params=[Const("list")], access_level="all", description="List command aliases") def alias_list_cmd(self, channel, sender, reply, args): blob = "" data = self.command_alias_manager.get_enabled_aliases() count = len(data) for row in data: blob += row.alias + " - " + row.command + "\n" reply(ChatBlob("Aliases (%d)" % count, blob)) @command(command="alias", params=[Const("add"), Any("alias"), Any("command")], access_level="superadmin", description="Add a command alias", sub_command="modify") def alias_add_cmd(self, channel, sender, reply, args): alias = args[1] command = args[2] if self.command_alias_manager.add_alias(alias, command): reply( "Alias <highlight>%s<end> for command <highlight>%s<end> added successfully." % (alias, command)) else: reply( "Cannot add alias <highlight>%s<end> since there is already an active alias with that name." % alias) @command(command="alias", params=[Options(["rem", "remove"]), Any("alias")], access_level="superadmin", description="Remove a command alias", sub_command="modify") def alias_remove_cmd(self, channel, sender, reply, args): alias = args[1] if self.command_alias_manager.remove_alias(alias): reply("Alias <highlight>%s<end> has been removed successfully." % alias) else: reply("Could not find alias <highlight>%s<end>." % alias)
class AliasController: def inject(self, registry): self.command_alias_service = registry.get_instance( "command_alias_service") self.ts: TranslationService = registry.get_instance( "translation_service") self.getresp = self.ts.get_response @command(command="alias", params=[Const("list")], access_level="all", description="List command aliases") def alias_list_cmd(self, request, _): blob = "" data = self.command_alias_service.get_enabled_aliases() count = len(data) for row in data: blob += row.alias + " - " + row.command + "\n" return ChatBlob( self.getresp("module/config", "alias_blob_title", {"amount": count}), blob) @command(command="alias", params=[Const("add"), Any("alias"), Any("command")], access_level="admin", description="Add a command alias", sub_command="modify") def alias_add_cmd(self, request, _, alias, command_str): if self.command_alias_service.add_alias(alias, command_str, force_enable=True): return self.getresp("module/config", "alias_add_success", { "alias": alias, "cmd": command_str }) else: return self.getresp("module/config", "alias_add_fail", {"alias": alias}) @command(command="alias", params=[Options(["rem", "remove"]), Any("alias")], access_level="admin", description="Remove a command alias", sub_command="modify") def alias_remove_cmd(self, request, _, alias): if self.command_alias_service.remove_alias(alias): return self.getresp("module/config", "alias_rem_success", {"alias": alias}) else: return self.getresp("module/config", "alias_rem_fail", {"alias": alias})
class CalculatorController: def __init__(self): self.allow_chars_regex = re.compile(r"^[0123456789.+\-*%()/ &|^~<>]+$") def inject(self, registry): self.discord_controller = registry.get_instance("discord_controller") def start(self): self.discord_controller.register_discord_command_handler( self.calc_discord_cmd, "calc", [Any("formula")]) @command( command="calc", params=[Any("formula")], access_level="all", description="Perform a calculation", extended_description= "Supported operators:\n\n+ (addition)\n- (subtraction)\n* (multiplication)\n/ (division)\n" "% (modulus)\n** (exponent)\n// (floor/integer division)\n< (less than)\n> (greater than)\n" "() (parenthesis)\n& (binary AND)\n| (binary OR)\n^ (binary exclusive OR)\n~ (binary ones complement)\n" "<< (binary left shift)\n>> (binary right shift)") def calc_cmd(self, request, formula): # this may be problematic if this bot is running on a system with a different locale formula = formula.replace(",", ".") if self.allow_chars_regex.match(formula): try: return "%s = %s" % (formula, round(eval(formula), 4)) except SyntaxError: return "Error! Invalid formula supplied." else: return "Error! Invalid character detected." def calc_discord_cmd(self, ctx, reply, args): reply(self.calc_cmd(None, *args))
class CountdownController: def inject(self, registry): self.job_scheduler = registry.get_instance("job_scheduler") @command(command="countdown", params=[Any("message", is_optional=True)], access_level="all", description="Start a 5-second countdown", aliases=["cd"]) def whois_cmd(self, request, message): message = message or "GO GO GO" message_format = "%s-------> %s <-------<end>" self.job_scheduler.delayed_job(self.show_countdown, 1, request.reply, message_format, "<red>", "5") self.job_scheduler.delayed_job(self.show_countdown, 2, request.reply, message_format, "<red>", "4") self.job_scheduler.delayed_job(self.show_countdown, 3, request.reply, message_format, "<orange>", "3") self.job_scheduler.delayed_job(self.show_countdown, 4, request.reply, message_format, "<orange>", "2") self.job_scheduler.delayed_job(self.show_countdown, 5, request.reply, message_format, "<orange>", "1") self.job_scheduler.delayed_job(self.show_countdown, 6, request.reply, message_format, "<green>", message) def show_countdown(self, timestamp, reply, message_format, color, message): reply(message_format % (color, message))
class CalculatorController: def __init__(self): self.allow_chars_regex = re.compile("^[0123456789.,+\-*%()/ &|^~<>]+$") def inject(self, registry): self.discord_controller = registry.get_instance("discord_controller") def start(self): self.discord_controller.register_discord_command_handler( self.calc_discord_cmd, "calc", [Any("formula")]) @command(command="calc", params=[Any("formula")], access_level="all", description="Perform a calculation") def calc_cmd(self, request, formula): if self.allow_chars_regex.match(formula): try: return "%s = %s" % (formula, round(eval(formula), 4)) except SyntaxError: return "Invalid formula supplied." else: return "Invalid character detected." def calc_discord_cmd(self, reply, args): reply(self.calc_cmd(None, *args))
def test_any(self): param = Any("test") self.assertEqual("10", self.param_test(param, "10")) self.assertEqual("ten", self.param_test(param, "ten")) self.assertEqual("?this is a test.", self.param_test(param, "?this is a test.")) self.assertIsNone(self.param_test(param, ""))
class RunasController: def inject(self, registry): self.bot = registry.get_instance("bot") self.command_service = registry.get_instance("command_service") self.setting_service = registry.get_instance("setting_service") self.access_service = registry.get_instance("access_service") self.getresp = registry.get_instance( "translation_service").get_response @command(command="runas", params=[Character("character"), Any("command")], access_level="superadmin", description="Run a command as another character") def shutdown_cmd(self, request, char, command_str): if command_str[0] == self.setting_service.get("symbol").get_value(): command_str = command_str[1:] if not char.char_id: return self.getresp("global", "char_not_found", {"char": char.name}) elif not self.access_service.has_sufficient_access_level( request.sender.char_id, char.char_id): return self.getresp("module/system", "runas_fail", {"char": char.name}) else: self.command_service.process_command(command_str, request.channel, char.char_id, request.reply)
class GuideController: GUIDE_FILE_EXT = ".txt" def __init__(self): pass def inject(self, registry): self.text = registry.get_instance("text") @command(command="guides", params=[], access_level="all", description="Show the list of guides") def guide_list_cmd(self, request): dir_path = self.get_base_path() guides = [f[:-len(self.GUIDE_FILE_EXT)] for f in os.listdir(dir_path) if f.endswith(self.GUIDE_FILE_EXT)] blob = "" for guide in guides: blob += self.text.make_chatcmd(guide, "/tell <myname> guides " + guide) + "\n" return ChatBlob("Guides (%d)" % len(guides), blob) @command(command="guides", params=[Any("guide")], access_level="all", description="Show the guide details") def guide_show_cmd(self, request, guide): guide = guide.lower() file_path = self.get_base_path() + os.sep + guide + self.GUIDE_FILE_EXT try: with open(file_path, "r") as f: return ChatBlob(guide.capitalize(), f.read()) except FileNotFoundError: return "Could not find guide <highlight>%s<end>." % guide def get_base_path(self): return os.path.dirname(os.path.realpath(__file__)) + os.sep + "guides"
class LeProcsController: def inject(self, registry): self.db = registry.get_instance("db") self.text: Text = registry.get_instance("text") self.util = registry.get_instance("util") self.command_alias_service = registry.get_instance( "command_alias_service") def pre_start(self): self.db.load_sql_file(self.module_dir + "/" + "leprocs.sql") def start(self): self.command_alias_service.add_alias("leproc", "leprocs") @command(command="leprocs", params=[], access_level="all", description="Show a list of professions with LE procs") def leprocs_list_command(self, request): data = self.db.query( "SELECT DISTINCT profession FROM leprocs ORDER BY profession ASC") blob = "" for row in data: blob += "<pagebreak>%s\n" % self.text.make_tellcmd( row.profession, "leprocs %s" % row.profession) blob += "\nProc info provided by Wolfbiter (RK1), Gatester (RK2), DrUrban" return ChatBlob("LE Procs", blob) @command(command="leprocs", params=[Any("profession")], access_level="all", description="Show LE proc information for a specific profession") def leprocs_show_command(self, request, prof_name): profession = self.util.get_profession(prof_name) if not profession: return "Could not find profession <highlight>%s</highlight>." % prof_name data = self.db.query( "SELECT * FROM leprocs WHERE profession LIKE ? ORDER BY proc_type ASC, research_lvl DESC", [profession]) proc_type = "" blob = "" for row in data: if proc_type != row.proc_type: proc_type = row.proc_type blob += "\n<highlight>%s</highlight>\n" % proc_type blob += "<pagebreak>[%d] %s <orange>%s</orange> %s <green>%s</green>\n" % ( row.research_lvl, row.name, row.modifiers, row.duration, row.proc_trigger) blob += "\n\nNote: Offensive procs have a 5% chance of firing every time you attack; Defensive procs have a 10% chance of firing every time something attacks you." blob += "\n\nProc info provided by Wolfbiter (RK1), Gatester (RK2)" return ChatBlob("%s LE Procs" % profession, blob)
class TopicController: def inject(self, registry): self.db: DB = registry.get_instance("db") self.text: Text = registry.get_instance("text") self.util = registry.get_instance("util") self.command_alias_service = registry.get_instance( "command_alias_service") def start(self): self.command_alias_service.add_alias("motd", "topic") @setting(name="topic", value="", description="The bot topic") def topic(self): return DictionarySettingType() @command(command="topic", params=[], access_level="all", description="Show the current topic") def topic_show_command(self, request): topic = self.topic().get_value() if topic: time_string = self.util.time_to_readable( int(time.time()) - topic["created_at"]) return "Topic: <highlight>%s<end> [set by <highlight>%s<end>][%s ago]" % ( topic["topic_message"], topic["created_by"]["name"], time_string) else: return "There is no current topic." @command(command="topic", params=[Options(["clear", "unset"])], access_level="all", description="Clears the current topic") def topic_clear_command(self, request, _): self.topic().set_value("") return "The topic has been cleared." @command(command="topic", params=[Const("set", is_optional=True), Any("topic_message")], access_level="all", description="Set the current topic") def topic_set_command(self, request, _, topic_message): sender = DictObject({ "name": request.sender.name, "char_id": request.sender.char_id }) topic = { "topic_message": topic_message, "created_by": sender, "created_at": int(time.time()) } self.topic().set_value(topic) return "The topic has been set."
class PrivateChannelController: def __init__(self): pass def inject(self, registry): self.bot = registry.get_instance("bot") self.private_channel_manager = registry.get_instance( "private_channel_manager") self.character_manager = registry.get_instance("character_manager") @command(command="join", params=[], access_level="all", description="Join the private channel") def join_cmd(self, channel, sender, reply, args): self.private_channel_manager.invite(sender.char_id) @command(command="leave", params=[], access_level="all", description="Leave the private channel") def leave_cmd(self, channel, sender, reply, args): self.private_channel_manager.kick(sender.char_id) @command(command="invite", params=[Any("character")], access_level="all", description="Invite a character to the private channel") def invite_cmd(self, channel, sender, reply, args): char = args[0].capitalize() char_id = self.character_manager.resolve_char_to_id(char) if sender.char_id == char_id: self.private_channel_manager.invite(sender.char_id) elif char_id: self.bot.send_private_message( char_id, "You have been invited to the private channel by <highlight>%s<end>." % sender.name) self.private_channel_manager.invite(char_id) reply( "You have invited <highlight>%s<end> to the private channel." % char) else: reply("Could not find character <highlight>%s<end>." % char) @event(PrivateChannelManager.JOINED_PRIVATE_CHANNEL_EVENT, "Notify private channel when someone joins") def private_channel_joined_event(self, event_type, event_data): char_name = self.character_manager.get_char_name(event_data.char_id) self.bot.send_private_channel_message( "<highlight>%s<end> has joined the private channel." % char_name) @event(PrivateChannelManager.LEFT_PRIVATE_CHANNEL_EVENT, "Notify private channel when someone leaves") def private_channel_left_event(self, event_type, event_data): char_name = self.character_manager.get_char_name(event_data.char_id) self.bot.send_private_channel_message( "<highlight>%s<end> has left the private channel." % char_name)
class PerksController: def __init__(self): self.grades = ["shiny", "bright", "faded"] def inject(self, registry): self.db = registry.get_instance("db") self.util = registry.get_instance("util") def pre_start(self): self.db.load_sql_file(self.module_dir + "/" + "perks.sql") @command(command="perks", params=[Int("level"), Any("profession")], access_level="all", description= "Show what perks are available for specified level and profession" ) def perks_cmd(self, request, level, profession): if level < 1 or level > 220: return "Level must be between <highlight>1</highlight> and <highlight>220</highlight>." prof = self.util.get_profession(profession) if not prof: return "Could not find profession <highlight>%s</highlight>" % profession sql = """ SELECT p.name AS perk_name, MAX(pl.number) AS max_perk_level, SUM(plb.amount) AS buff_amount, plb.skill FROM perk p JOIN perk_prof pp ON p.id = pp.perk_id JOIN perk_level pl ON p.id = pl.perk_id JOIN perk_level_buffs plb ON pl.id = plb.perk_level_id WHERE pp.profession = ? AND pl.min_level <= ? GROUP BY p.name, plb.skill ORDER BY p.name""" data = self.db.query(sql, [prof, level]) blob = "" current_perk = "" for row in data: if row.perk_name != current_perk: blob += "\n<header2>%s %s</header2>\n" % (row.perk_name, row.max_perk_level) current_perk = row.perk_name blob += "%s <highlight>%d</highlight>\n" % (row.skill, row.buff_amount) return ChatBlob("Buff Perks for %d %s" % (level, prof), blob)
class LinksController: def inject(self, registry): self.db = registry.get_instance("db") self.text = registry.get_instance("text") def start(self): self.db.exec("CREATE TABLE IF NOT EXISTS links (" "id INT PRIMARY KEY AUTO_INCREMENT," "char_id INT NOT NULL," "website VARCHAR(255) NOT NULL," "comments VARCHAR(255) NOT NULL," "created_at INT NOT NULL);") @command(command="links", params=[], access_level="all", description="Show links") def links_list_cmd(self, request): data = self.db.query("SELECT l.*, p.name FROM links l LEFT JOIN player p ON l.char_id = p.char_id ORDER BY name ASC") blob = "" for row in data: blob += "%s <highlight>%s<end> [%s] %s" % (self.text.make_chatcmd("[Link]", "/start %s" % row.website), row.comments, row.name, self.text.make_chatcmd("Remove", "/tell <myname> links remove %d" % row.id)) return ChatBlob("Links (%d)" % len(data), blob) @command(command="links", params=[Const("add"), Any("website"), Any("comment")], access_level="moderator", description="Add a link") def links_add_cmd(self, request, _, website, comment): if not website.startswith("https://") and not website.startswith("http://"): return "Website must start with 'http://' or 'https://'." self.db.exec("INSERT INTO links (char_id, website, comments, created_at) VALUES (?, ?, ?, ?)", [request.sender.char_id, website, comment, int(time.time())]) return "Link added successfully." @command(command="links", params=[Options(["rem", "remove"]), Int("link_id")], access_level="moderator", description="Remove a link") def links_remove_cmd(self, request, _, link_id): link = self.db.query_single("SELECT * FROM links WHERE id = ?", [link_id]) if not link: return "Could not find link with ID <highlight>%d<end>." % link_id self.db.exec("DELETE FROM links WHERE id = ?", [link_id]) return "Link has been deleted"
class PocketbossController: def __init__(self): pass def inject(self, registry): self.db = registry.get_instance("db") self.text = registry.get_instance("text") self.command_alias_service = registry.get_instance( "command_alias_service") def start(self): self.command_alias_service.add_alias("pb", "pocketboss") @command(command="pocketboss", params=[Any("search")], access_level="all", description="Show information about a pocketboss") def pocketboss_cmd(self, request, search): data = self.search_for_pocketboss(search) num = len(data) if num == 1: row = data[0] blob = "Location: <highlight>%s, %s<end>\n" % (row.long_name, row.location) blob += "Found on: <highlight>%s, Level %d<end>\n\n" % ( row.mob_type, row.level) symbs = self.db.query( "SELECT a.* FROM pocketboss_loot p " "LEFT JOIN aodb a ON p.item_id = a.highid WHERE pocketboss_id = ? " "ORDER BY a.highql DESC, a.name ASC", [row.id]) for symb in symbs: blob += "%s (%d)\n" % (self.text.make_item( symb.lowid, symb.highid, symb.highql, symb.name), symb.highql) return ChatBlob("Remains of %s" % row.name, blob) else: blob = "" for row in data: blob += self.text.make_chatcmd( row.name, "/tell <myname> pocketboss %s" % row.name) + "\n" return ChatBlob("Pocketboss Search Results (%d)" % num, blob) def search_for_pocketboss(self, search): row = self.db.query_single( "SELECT p1.*, p2.long_name FROM pocketboss p1 LEFT JOIN playfields p2 ON p1.playfield_id = p2.id WHERE name LIKE ?", [search]) if row: return [row] return self.db.query( "SELECT p1.*, p2.long_name FROM pocketboss p1 LEFT JOIN playfields p2 ON p1.playfield_id = p2.id " "WHERE name <EXTENDED_LIKE=0> ? ORDER BY name ASC", [search], extended_like=True)
class AliasController: def inject(self, registry): self.command_alias_service = registry.get_instance( "command_alias_service") @command(command="alias", params=[Const("list")], access_level="all", description="List command aliases") def alias_list_cmd(self, request, _): blob = "" data = self.command_alias_service.get_enabled_aliases() count = len(data) for row in data: blob += row.alias + " - " + row.command + "\n" return ChatBlob("Aliases (%d)" % count, blob) @command(command="alias", params=[Const("add"), Any("alias"), Any("command")], access_level="admin", description="Add a command alias", sub_command="modify") def alias_add_cmd(self, request, _, alias, command_str): if self.command_alias_service.add_alias(alias, command_str, force_enable=True): return "Alias <highlight>%s<end> for command <highlight>%s<end> added successfully." % ( alias, command_str) else: return "Cannot add alias <highlight>%s<end> since there is already an active alias with that name." % alias @command(command="alias", params=[Options(["rem", "remove"]), Any("alias")], access_level="admin", description="Remove a command alias", sub_command="modify") def alias_remove_cmd(self, request, _, alias): if self.command_alias_service.remove_alias(alias): return "Alias <highlight>%s<end> has been removed successfully." % alias else: return "Could not find alias <highlight>%s<end>." % alias
class TellRelayController: MESSAGE_SOURCE = "tell_relay" def inject(self, registry): self.bot = registry.get_instance("bot") self.text = registry.get_instance("text") self.pork_service = registry.get_instance("pork_service") self.setting_service = registry.get_instance("setting_service") self.character_service = registry.get_instance("character_service") self.public_channel_service = registry.get_instance("public_channel_service") self.message_hub_service = registry.get_instance("message_hub_service") self.ban_service = registry.get_instance("ban_service") def pre_start(self): self.message_hub_service.register_message_source(self.MESSAGE_SOURCE) def start(self): self.message_hub_service.register_message_destination(self.MESSAGE_SOURCE, self.handle_incoming_relay_message, ["private_channel", "private_channel_update", "org_channel", "org_channel_update", "discord", "websocket_relay", "shutdown_notice"], [self.MESSAGE_SOURCE]) self.setting_service.register(self.module_name, "relay_bot", "", TextSettingType(allow_empty=True), "Name of bot character for chat relay") def relay_bot(self): return self.setting_service.get("relay_bot") def relay_prefix(self): return self.setting_service.get("relay_prefix") @command(command="grc", params=[Any("message")], access_level="all", description="Accept incoming messages from relay bot") def grc_cmd(self, request, message): self.process_incoming_relay_message(request.sender, message) def process_incoming_relay_message(self, sender, message): relay_bot = self.relay_bot().get_value() if relay_bot and sender.name.lower() == relay_bot.lower(): self.message_hub_service.send_message(self.MESSAGE_SOURCE, None, None, message) def handle_incoming_relay_message(self, ctx): message = ctx.formatted_message self.send_message_to_relay(message) def send_message_to_relay(self, message): relay_bot = self.relay_bot().get_value() if relay_bot: # if setting, then use setting, else if org, then use org name, else use botname prefix = self.get_org_channel_prefix() char_id = self.character_service.resolve_char_to_id(relay_bot) self.bot.send_private_message(char_id, "grc [%s] %s" % (prefix, message), add_color=False, conn=self.bot.get_primary_conn()) def get_org_channel_prefix(self): conn = self.bot.get_primary_conn() return self.relay_prefix().get_value() or conn.get_org_name() or conn.get_char_name()
class SymbiantController: def __init__(self): pass def inject(self, registry): self.db = registry.get_instance("db") self.text = registry.get_instance("text") self.command_alias_service = registry.get_instance("command_alias_service") def start(self): self.command_alias_service.add_alias("symb", "symbiant") self.command_alias_service.add_alias("symbs", "symbiant") self.command_alias_service.add_alias("symbiants", "symbiant") @command(command="symbiant", params=[Any("search")], access_level="all", description="Show information about symbiants") def symbiant_cmd(self, request, search): data = self.search_for_symbiant(search) blob = "" for row in data: blob += "%s (%d)\n" % (self.text.make_item(row.lowid, row.highid, row.highql, row.name), row.highql) blob += "Found on %s\n\n" % self.text.make_tellcmd(row.pocketboss_name, "pocketboss %s" % row.pocketboss_name) return ChatBlob("Symbiant Search Results (%d)" % len(data), blob) def search_for_symbiant(self, search): parts = " ".join((map(self.replacements, search.split(" ")))) return self.db.query("SELECT a.*, p2.name AS pocketboss_name FROM pocketboss_loot p " "LEFT JOIN aodb a ON p.item_id = a.highid " "LEFT JOIN pocketboss p2 ON p.pocketboss_id = p2.id " "WHERE a.name <EXTENDED_LIKE=0> ? " "ORDER BY a.highql DESC, a.name ASC", [parts], extended_like=True) def replacements(self, part): if part == "eye": return "ocular" elif part == "head": return "brain" elif part == "rarm": return "right arm" elif part == "larm": return "left arm" elif part == "rwrist": return "right wrist" elif part == "lwrist": return "left wrist" elif part == "rhand": return "right hand" elif part == "lhand": return "left hand" elif part == "leg" or part == "legs": return "thigh" else: return part
class RunasController: def __init__(self): pass def inject(self, registry): self.bot = registry.get_instance("bot") self.character_manager = registry.get_instance("character_manager") self.command_manager = registry.get_instance("command_manager") def start(self): pass @command(command="runas", params=[Any("character"), Any("command")], access_level="superadmin", description="Run a command as another character") def shutdown_cmd(self, channel, sender, reply, args): char_name = args[0].capitalize() command_str = args[1] char_id = self.character_manager.resolve_char_to_id(char_name) self.command_manager.process_command(command_str, channel, char_id, reply)
class SendMessageController: def inject(self, registry): self.bot = registry.get_instance("bot") self.command_service = registry.get_instance("command_service") self.getresp = registry.get_instance( "translation_service").get_response @command(command="send", params=[Const("tell"), Character("character"), Any("message")], access_level="superadmin", description="Send a message to a character from the bot") def send_tell_cmd(self, request, _, char, message): if char.char_id: self.bot.send_private_message(char.char_id, message, add_color=False, conn=request.conn) return self.getresp("module/system", "msg_sent") else: return self.getresp("global", "char_not_found", {"char": char.name}) @command(command="send", params=[Const("org"), Any("message")], access_level="superadmin", description="Send a message to the org channel from the bot") def send_org_cmd(self, request, _, message): for _id, conn in self.bot.get_conns(lambda x: x.is_main): self.bot.send_org_message(message, add_color=False, conn=conn) return self.getresp("module/system", "msg_sent") @command(command="send", params=[Const("priv"), Any("message")], access_level="superadmin", description="Send a message to the private channel from the bot") def send_priv_cmd(self, request, _, message): self.bot.send_private_channel_message(message, add_color=False, conn=self.bot.get_primary_conn()) return self.getresp("module/system", "msg_sent")
class NotesController: def inject(self, registry): self.db = registry.get_instance("db") self.text = registry.get_instance("text") self.alts_service = registry.get_instance("alts_service") def start(self): self.db.exec("CREATE TABLE IF NOT EXISTS notes (" "id INT PRIMARY KEY AUTO_INCREMENT, " "char_id INT NOT NULL, " "note TEXT NOT NULL," "created_at INT NOT NULL)") @command(command="notes", params=[], access_level="all", description="Show your notes") def notes_list_cmd(self, request): alts = self.alts_service.get_alts(request.sender.char_id) cnt = 0 blob = "" for alt in alts: data = self.db.query("SELECT * FROM notes WHERE char_id = ? ORDER BY created_at DESC", [alt.char_id]) alt_cnt = len(data) cnt += alt_cnt if alt_cnt: blob += "\n<header2>%s<end>\n" % alt.name for row in data: blob += "%s %s\n\n" % (row.note, self.text.make_chatcmd("Remove", "/tell <myname> notes remove %d" % row.id)) return ChatBlob("Notes for %s (%d)" % (alts[0].name, cnt), blob) @command(command="notes", params=[Const("add"), Any("note")], access_level="all", description="Add a note") def notes_add_cmd(self, request, _, note): self.db.exec("INSERT INTO notes (char_id, note, created_at) VALUES (?, ?, ?)", [request.sender.char_id, note, int(time.time())]) return "Note added successfully." @command(command="notes", params=[Options(["rem", "remove"]), Int("note_id")], access_level="all", description="Remove a note") def notes_remove_cmd(self, request, _, note_id): note = self.db.query_single("SELECT n.*, p.name FROM notes n LEFT JOIN player p ON n.char_id = p.char_id WHERE n.id = ?", [note_id]) if not note: return "Could not find note with ID <highlight>%d<end>." % note_id if self.alts_service.get_main(request.sender.char_id).char_id != self.alts_service.get_main(note.char_id).char_id: return "You must be a confirmed alt of <highlight>%s<end> to remove this note." % note.name self.db.exec("DELETE FROM notes WHERE id = ?", [note_id]) return "Note with ID <highlight>%d<end> deleted successfully." % note_id
class ClusterController: def inject(self, registry): self.db: DB = registry.get_instance("db") self.text = registry.get_instance("text") @command(command="cluster", params=[], access_level="all", description= "Show a list of skills that can be buffed with an implant cluster" ) def cluster_list_cmd(self, request): data = self.db.query( "SELECT ClusterID, LongName FROM Cluster ORDER BY LongName ASC") blob = "" for row in data: blob += self.text.make_chatcmd( row["LongName"], "/tell <myname> cluster %s" % row["LongName"]) + "\n" return ChatBlob("Cluster List (%d)" % len(data), blob) @command(command="cluster", params=[Any("skill")], access_level="all", description="Show which clusters buff a particular skill") def cluster_show_cmd(self, request, skill): data = self.db.query(*self.db.handle_extended_like( "SELECT ClusterID, LongName FROM Cluster WHERE LongNAme <EXTENDED_LIKE=0> ?", [skill])) count = len(data) if count == 0: return "No skills found that match <highlight>%s<end>." % skill else: blob = "" for row in data: data2 = self.db.query( "SELECT i.ShortName as Slot, c2.Name AS ClusterType " "FROM ClusterImplantMap c1 " "JOIN ClusterType c2 ON c1.ClusterTypeID = c2.ClusterTypeID " "JOIN ImplantType i ON c1.ImplantTypeID = i.ImplantTypeID " "WHERE c1.ClusterID = ? " "ORDER BY c2.ClusterTypeID DESC", [row["ClusterID"]]) blob += "<pagebreak><header2>%s<end>\n" % row["LongName"] for row2 in data2: blob += "%s: <highlight>%s<end><tab>" % ( row2["ClusterType"].capitalize(), row2["Slot"]) blob += "\n\n" return ChatBlob("Cluster Search Results (%d)" % count, blob)
class CacheController: invalid_chars = ["/", "\\", ".."] def inject(self, registry): self.bot = registry.get_instance("bot") self.db = registry.get_instance("db") self.text = registry.get_instance("text") @command(command="cache", params=[Const("delete"), Any("category"), Any("filename")], access_level="superadmin", description="Manually remove a cache entry") def cache_remove_cmd(self, request, _, category, filename): full_file_path = os.sep.join([".", "data", "cache", category, filename]) full_file_path = os.path.normpath(full_file_path) if not full_file_path.startswith(os.path.normpath(os.sep.join([".", "data", "cache"]))): return f"<highlight>{full_file_path}</highlight> is not a valid cache entry." if os.path.isfile(full_file_path): os.remove(full_file_path) return f"Cache entry <highlight>{full_file_path}</highlight> has been removed." else: return f"Cache entry <highlight>{full_file_path}</highlight> does not exist or is not a file."
class AssistController: def __init__(self): self.assist = [] def inject(self, registry): self.leader_controller = registry.get_instance("leader_controller") @command(command="assist", params=[], access_level="all", description="Show current assist targets") def assist_command(self, request): return self.get_assist_output() @command(command="assist", params=[Const("clear")], access_level="all", description="Clear all assist targets", sub_command="modify") def assist_clear_command(self, request, _): if not self.assist: return "No assist targets set." if not self.leader_controller.can_use_command(request.sender.char_id): return LeaderController.NOT_LEADER_MSG else: self.assist = [] return "Assist targets have been cleared." @command( command="assist", params=[Any("assist_targets")], access_level="all", description="Set one or more assist targets", sub_command="modify", extended_description="Multiple assist targets should be space-delimited" ) def assist_set_command(self, request, assist_targets): targets = assist_targets.split(" ") if not self.leader_controller.can_use_command(request.sender.char_id): return LeaderController.NOT_LEADER_MSG else: self.assist = targets return self.get_assist_output() def get_assist_output(self): if not self.assist: return "No assist targets set." return "/macro assist " + " \\n ".join( map(lambda x: "/assist " + x.capitalize(), reversed(self.assist)))
class PlayfieldController: def inject(self, registry): self.db: DB = registry.get_instance("db") self.text: Text = registry.get_instance("text") @command(command="playfield", params=[], access_level="all", description="Show a list of playfields", aliases=["playfields"]) def playfield_list_command(self, request): data = self.db.query("SELECT * FROM playfields ORDER BY long_name") blob = "" for row in data: blob += "[<highlight>%d<end>] %s (%s)\n" % (row.id, row.long_name, row.short_name) return ChatBlob("Playfields", blob) @command(command="waypoint", params=[Regex("waypoint_data", "\s+.*?Pos: ([0-9.]+), ([0-9.]+), ([0-9.]+), Area: ([a-zA-Z ]+).*", num_groups=4)], access_level="all", description="Create a waypoint link from F9 output") def waypoint1_command(self, request, regex): x_coords, y_coords, _, playfield_arg = regex return self.create_waypoint_blob(x_coords, y_coords, playfield_arg) @command(command="waypoint", params=[Regex("waypoint_data", "\s+.*?([0-9.]+) ([0-9.]+) y ([0-9.]+) ([0-9]+).*", num_groups=4)], access_level="all", description="Create a waypoint link from Shift + F9 output") def waypoint2_command(self, request, regex): x_coords, y_coords, _, playfield_arg = regex return self.create_waypoint_blob(x_coords, y_coords, playfield_arg) @command(command="waypoint", params=[Int("x_coords"), Int("y_coords"), Any("playfield")], access_level="all", description="Manually create a waypoint link") def waypoint3_command(self, request, x_coords, y_coords, playfield_arg): return self.create_waypoint_blob(x_coords, y_coords, playfield_arg) def create_waypoint_blob(self, x_coords, y_coords, playfield_arg): playfield = self.get_playfield_by_name(playfield_arg) or self.get_playfield_by_id(playfield_arg) if not playfield: return "Could not find playfield <highlight>%s<end>." % playfield_arg else: title = "waypoint: %sx%s %s" % (x_coords, y_coords, playfield.long_name) blob = "Click here to use waypoint: " blob += self.text.make_chatcmd(title, "/waypoint %s %s %d" % (x_coords, y_coords, playfield.id)) return ChatBlob(title, blob) def get_playfield_by_name(self, name): return self.db.query_single("SELECT * FROM playfields WHERE long_name LIKE ? OR short_name LIKE ? LIMIT 1", [name, name]) def get_playfield_by_id(self, playfield_id): return self.db.query_single("SELECT * FROM playfields WHERE id = ?", [playfield_id])
class ChatController: def inject(self, registry): self.db: DB = registry.get_instance("db") self.text: Text = registry.get_instance("text") @command(command="loud", params=[Any("message")], access_level="all", description="Show a highly visible message", extended_description= "This command is similar to <symbol>cmd in Budabot", aliases=["cmd"]) def loud_command(self, request, message): return "\n<yellow>---------------------\n<red>%s<end>\n<yellow>---------------------" % message
class SendMessageController: def inject(self, registry): self.bot = registry.get_instance("bot") self.command_service = registry.get_instance("command_service") self.getresp = registry.get_instance("translation_service").get_response @command(command="sendtell", params=[Character("character"), Any("message")], access_level="superadmin", description="Send a tell to another character from the bot") def sendtell_cmd(self, request, char, message): if char.char_id: self.bot.send_private_message(char.char_id, message, add_color=False, conn=request.conn) return self.getresp("module/system", "msg_sent") else: return self.getresp("global", "char_not_found", {"char": char.name})