Exemplo n.º 1
0
    def start(self):
        self.command_alias_service.add_alias("lvl", "level")
        self.command_alias_service.add_alias("pvp", "level")
        self.command_alias_service.add_alias("team", "level")
        self.command_alias_service.add_alias("missions", "mission")
        self.command_alias_service.add_alias("mish", "mission")
        self.command_alias_service.add_alias("ailevel", "axp")

        self.discord_controller.register_discord_command_handler(
            self.level_discord_cmd, "level", [Int("level")])
        self.discord_controller.register_discord_command_handler(
            self.mission_discord_cmd, "mission", [Int("mission_level")])
Exemplo n.º 2
0
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])
Exemplo n.º 3
0
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)
Exemplo n.º 4
0
class OverequippedController:
    def inject(self, registry):
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.discord_controller = registry.get_instance("discord_controller")

    def start(self):
        self.discord_controller.register_discord_command_handler(
            self.oe_discord_cmd, "oe", [Int("skill_level")])

    @command(command="oe",
             params=[Int("skill_level")],
             access_level="all",
             description="Show the current time in every timezone")
    def oe_command(self, request, skill_level):
        oe = self.get_oe_vals(skill_level)

        blob = "With a skill requirement of <highlight>%s<end>, you will be\n" % skill_level
        blob += "Out of OE: <highlight>%d<end> or higher\n" % oe.oe100low
        blob += "75%%: <highlight>%d<end> to <highlight>%d<end>\n" % (
            oe.oe75low, oe.oe100low - 1)
        blob += "50%%: <highlight>%d<end> to <highlight>%d<end>\n" % (
            oe.oe50low, oe.oe75low - 1)
        blob += "25%%: <highlight>%d<end> to <highlight>%d<end>\n" % (
            oe.oe25low, oe.oe50low - 1)
        blob += "0%%: <highlight>%d<end> or lower\n\n" % (oe.oe25low - 1)

        blob += "With a personal skill of <highlight>%s<end>, you can use up to\n" % skill_level
        blob += "Out of OE: <highlight>%d<end> or lower\n" % oe.oe100
        blob += "75%%: <highlight>%d<end> to <highlight>%d<end>\n" % (
            oe.oe100 + 1, oe.oe75)
        blob += "50%%: <highlight>%d<end> to <highlight>%d<end>\n" % (
            oe.oe75 + 1, oe.oe50)
        blob += "25%%: <highlight>%d<end> to <highlight>%d<end>\n" % (
            oe.oe50 + 1, oe.oe25)
        blob += "0%%: <highlight>%d<end> or higher\n" % (oe.oe25 - 1)

        return ChatBlob("%d - %d - %d" % (oe.oe100low, skill_level, oe.oe100),
                        blob)

    def get_oe_vals(self, skill_level):
        return DictObject({
            "oe100": int(math.floor(skill_level / 0.8)),
            "oe100low": int(math.floor(skill_level * 0.8)),
            "oe75": int(math.floor(skill_level / 0.6)),
            "oe75low": int(math.floor(skill_level * 0.6)),
            "oe50": int(math.floor(skill_level / 0.4)),
            "oe50low": int(math.floor(skill_level * 0.4)),
            "oe25": int(math.floor(skill_level / 0.2)),
            "oe25low": int(math.floor(skill_level * 0.2))
        })

    def oe_discord_cmd(self, reply, args):
        skill_level, = args
        oe = self.get_oe_vals(skill_level)

        reply("%d - %d - %d" % (oe.oe100low, skill_level, oe.oe100), "OE")
Exemplo n.º 5
0
class ResearchController:
    def inject(self, registry):
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.util = registry.get_instance("util")

    @command(command="research", params=[Int("research_level")], access_level="all",
             description="Show information about a specific research level")
    def research_command(self, request, research_level):
        if research_level > 10 or research_level < 1:
            return "Research level must be between 1 and 10."

        row = self.db.query_single("SELECT * FROM research WHERE level = ?", [research_level])

        capsk = int(row.sk * 0.1)

        blob = "You must be level <highlight>%d<end> to research <highlight>Research Level %d<end>.\n" % (row.levelcap, research_level)
        blob += "You need <highlight>%s SK<end> to reach <highlight>Research Level %d<end> per research line.\n\n" % (self.util.format_number(row.sk), research_level)
        blob += "This equals <highlight>%s XP<end>.\n\n" % (self.util.format_number(row.sk * 1000))
        blob += "Your research will cap at <highlight>%s XP<end> or <highlight>%s SK<end>." % (self.util.format_number(capsk * 1000), self.util.format_number(capsk))

        return ChatBlob("Research Level %d" % research_level, blob)

    @command(command="research", params=[Int("research_level"), Int("research_level")], access_level="all",
             description="Show the amount of SK needed from one research level to another")
    def research_span_command(self, request, research_level1, research_level2):
        if research_level1 > 10 or research_level1 < 1 or research_level2 > 10 or research_level2 < 1:
            return "Research level must be between 1 and 10."
        elif research_level1 == research_level2:
            return "You must specify different research levels."

        if research_level1 > research_level2:
            # swap researches so the lower is research_level1 and higher is research_level2
            research_level1, research_level2 = research_level2, research_level1

        row = self.db.query_single("SELECT SUM(sk) AS total_sk, MAX(levelcap) AS levelcap FROM research WHERE level > ? AND level <= ?", [research_level1, research_level2])

        blob = "You must be <highlight>Level %d<end> to reach Research Level <highlight>%d.<end>\n" % (row.levelcap, research_level2)
        blob += "It takes <highlight>%s SK<end> to go from Research Level <highlight>%d<end> to Research Level <highlight>%d<end> per research line.\n\n" \
                % (self.util.format_number(row.total_sk), research_level1, research_level2)
        blob += "This equals <highlight>%s XP<end>." % self.util.format_number(row.total_sk * 1000)

        return ChatBlob("Research Levels %d - %d" % (research_level1, research_level2), blob)
Exemplo n.º 6
0
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
Exemplo n.º 7
0
class CharacterHistoryController:
    def __init__(self):
        pass

    def inject(self, registry):
        self.bot = registry.get_instance("bot")
        self.util = registry.get_instance("util")
        self.character_history_service = registry.get_instance(
            "character_history_service")
        self.command_alias_service = registry.get_instance(
            "command_alias_service")

    def start(self):
        self.command_alias_service.add_alias("h", "history")

    @command(
        command="history",
        params=[Character("character"),
                Int("server_num", is_optional=True)],
        access_level="all",
        description="Get history of character")
    def handle_history_cmd1(self, request, char, server_num):
        server_num = server_num or self.bot.dimension

        data = self.character_history_service.get_character_history(
            char.name, server_num)
        if not data:
            return "Could not find history for <highlight>%s<end> on server <highlight>%d<end>." % (
                char.name, server_num)

        return ChatBlob("History of %s (RK%d)" % (char.name, server_num),
                        self.format_character_history(char.name, data))

    def format_character_history(self, name, history):
        blob = "Date           Level    AI     Faction    Breed        Guild (rank)\n"
        blob += "________________________________________________ \n"
        for row in history:
            if row.guild_name:
                org = "%s (%s)" % (row.guild_name, row.guild_rank_name)
            else:
                org = ""

            last_changed = self.util.format_date(int(float(row.last_changed)))

            blob += "%s |  %s  | <green>%s<end> | %s | %s | %s\n" % \
                    (last_changed, row.level, row.defender_rank or 0, row.faction, row.breed, org)

        blob += "\nHistory provided by Auno.org, Chrisax, and Athen Paladins"

        return blob
Exemplo n.º 8
0
class OfabWeaponsController:
    def inject(self, registry):
        self.db = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.items_controller = registry.get_instance("items_controller")
        self.command_alias_service = registry.get_instance("command_alias_service")

    def start(self):
        self.command_alias_service.add_alias("ofabweapon", "ofabweapons")

    @command(command="ofabweapons", params=[], access_level="all",
             description="Show ofab weapons")
    def ofabweapons_list_command(self, request):
        data = self.db.query("SELECT type, name FROM ofab_weapons ORDER BY name ASC")

        blob = ""
        for row in data:
            blob += "<pagebreak>%s - Type %d\n" % (self.text.make_tellcmd(row.name, "ofabweapons %s" % row.name), row.type)

        return ChatBlob("Ofab Weapons", blob)

    @command(command="ofabweapons", params=[Int("ql", is_optional=True), Any("weapon"), Int("ql", is_optional=True)], access_level="all",
             description="Show info about an ofab weapon", extended_description="QL is optional and can come before or after the weapon")
    def ofabweapons_show_command(self, request, ql1, weapon_name, ql2):
        weapon_name = weapon_name.capitalize()
        ql = ql1 or ql2 or 300

        weapon = self.db.query_single("SELECT type, vp FROM ofab_weapons w, ofab_weapons_cost c WHERE w.name LIKE ? AND c.ql = ?", [weapon_name, ql])

        if not weapon:
            return "Could not find Ofab Weapon <highlight>%s</highlight> for QL <highlight>%d</highlight>." % (weapon_name, ql)

        type_ql = round(ql * 0.8)
        type_link = self.text.make_tellcmd("Kyr'Ozch Bio-Material - Type %d" % weapon.type, "bioinfo %d %d" % (weapon.type, type_ql))

        blob = "Upgrade with %s (minimum QL %d)\n\n" % (type_link, type_ql)

        data = self.db.query("SELECT ql FROM ofab_weapons_cost ORDER BY ql ASC")
        for row in data:
            blob += self.text.make_tellcmd(row.ql, "ofabweapons %s %d" % (weapon_name, row.ql)) + " "
        blob += "\n\n"

        for i in range(1, 7):
            item = self.items_controller.find_by_name("Ofab %s Mk %d" % (weapon_name, i))
            blob += "<pagebreak>" + self.text.format_item(item)
            if i == 1:
                blob += "  (<highlight>%d</highlight> VP)" % weapon.vp
            blob += "\n"

        return ChatBlob("Ofab %s (QL %d)" % (weapon_name, ql), blob)
Exemplo n.º 9
0
    def test_multiple(self):
        param1 = Multiple(Int("num"))
        self.assertEqual([1], self.param_test_helper(param1, "1"))
        self.assertEqual([1, 2, 3], self.param_test_helper(param1, "1 2 3"))

        param2 = Multiple(Const("something"))
        self.assertEqual(["something"], self.param_test_helper(param2, "something"))
        self.assertEqual(["something", "something", "something"],
                         self.param_test_helper(param2, "something something something"))

        param3 = Multiple(Time("time"))
        self.assertEqual([60], self.param_test_helper(param3, "1m"))
        self.assertEqual([304], self.param_test_helper(param3, "5M4S"))
        self.assertEqual([60, 304, 14521], self.param_test_helper(param3, "1m 5M4S 4h2m1s"))

        param4 = Multiple(Item("item"))
        self.assertEqual([{'low_id': 246817, 'high_id': 246817, 'ql': 200, 'name': 'Novictum Seed'}],
                         self.param_test_helper(param4, "<a href=\"itemref://246817/246817/200\">Novictum Seed</a>"))

        self.assertEqual([{'low_id': 246817, 'high_id': 246817, 'ql': 200, 'name': 'Novictum Seed'},
                          {'low_id': 100, 'high_id': 101, 'ql': 300, 'name': 'It\'s cool'}],
                         self.param_test_helper(param4, "<a href=\"itemref://246817/246817/200\">Novictum Seed</a> "
                                                        "<a href=\"itemref://100/101/300\">It's cool</a>"))

        self.assertEqual([{'low_id': 246817, 'high_id': 246817, 'ql': 200, 'name': 'Novictum Seed'},
                          {'low_id': 100, 'high_id': 101, 'ql': 300, 'name': 'It\'s cool'},
                          {'low_id': 12345, 'high_id': 54321, 'ql': 123, 'name': 'It Works!'}],
                         self.param_test_helper(param4,
                                                "<a href=\"itemref://246817/246817/200\">Novictum Seed</a> "
                                                "<a href=\"itemref://100/101/300\">It's cool</a> "
                                                "<a href=\"itemref://12345/54321/123\">It Works!</a>"))

        # no spaces
        self.assertEqual([{'low_id': 246817, 'high_id': 246817, 'ql': 200, 'name': 'Novictum Seed'},
                          {'low_id': 100, 'high_id': 101, 'ql': 300, 'name': 'It\'s cool'},
                          {'low_id': 12345, 'high_id': 54321, 'ql': 123, 'name': 'It Works!'}],
                         self.param_test_helper(param4,
                                                "<a href=\"itemref://246817/246817/200\">Novictum Seed</a>"
                                                "<a href=\"itemref://100/101/300\">It's cool</a>"
                                                "<a href=\"itemref://12345/54321/123\">It Works!</a>"))

        param5 = Multiple(Any("time"))
        self.assertEqual(["test"], self.param_test_helper(param5, "test"))
        self.assertEqual(["test1", "test2"], self.param_test_helper(param5, "test1 test2"))
        self.assertEqual(["test1", "test2", "test3"], self.param_test_helper(param5, "test1 test2 test3"))
Exemplo n.º 10
0
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 CharacterHistoryController:
    def __init__(self):
        pass

    def inject(self, registry):
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.pork_manager = registry.get_instance("pork_manager")

    @command(command="history",
             params=[Any("character"),
                     Int("server_num", is_optional=True)],
             access_level="all",
             description="Get history of character")
    def handle_history_cmd1(self, channel, sender, reply, args):
        name = args[0].capitalize()
        server_num = args[1] if args[1] else 5
        reply(self.get_character_history(name, server_num))

    def get_character_history(self, name, server_num):
        return "<header>" + name + " (" + str(server_num) + ")<end>"
Exemplo n.º 12
0
class OverequippedController:
    def inject(self, registry):
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")

    @command(command="oe",
             params=[Int("skill_level")],
             access_level="all",
             description="Show the current time in every timezone")
    def oe_command(self, request, skill_level):
        oe100 = int(math.floor(skill_level / 0.8))
        oe100low = int(math.floor(skill_level * 0.8))
        oe75 = int(math.floor(skill_level / 0.6))
        oe75low = int(math.floor(skill_level * 0.6))
        oe50 = int(math.floor(skill_level / 0.4))
        oe50low = int(math.floor(skill_level * 0.4))
        oe25 = int(math.floor(skill_level / 0.2))
        oe25low = int(math.floor(skill_level * 0.2))

        blob = "With a skill requirement of <highlight>%s<end>, you will be\n" % skill_level
        blob += "Out of OE: <highlight>%d<end> or higher\n" % oe100low
        blob += "75%%: <highlight>%d<end> to <highlight>%d<end>\n" % (
            oe75low, oe100low - 1)
        blob += "50%%: <highlight>%d<end> to <highlight>%d<end>\n" % (
            oe50low, oe75low - 1)
        blob += "25%%: <highlight>%d<end> to <highlight>%d<end>\n" % (
            oe25low, oe50low - 1)
        blob += "0%%: <highlight>%d<end> or lower\n\n" % (oe25low - 1)

        blob += "With a personal skill of <highlight>%s<end>, you can use up to\n" % skill_level
        blob += "Out of OE: <highlight>%d<end> or lower\n" % oe100
        blob += "75%%: <highlight>%d<end> to <highlight>%d<end>\n" % (oe100 +
                                                                      1, oe75)
        blob += "50%%: <highlight>%d<end> to <highlight>%d<end>\n" % (oe75 + 1,
                                                                      oe50)
        blob += "25%%: <highlight>%d<end> to <highlight>%d<end>\n" % (oe50 + 1,
                                                                      oe25)
        blob += "0%%: <highlight>%d<end> or higher\n" % (oe25 - 1)

        return ChatBlob("%d - %d - %d" % (oe100low, skill_level, oe100), blob)
Exemplo n.º 13
0
class RandomController:
    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.character_service = registry.get_instance("character_service")
        self.command_alias_service = registry.get_instance(
            "command_alias_service")

    def start(self):
        self.command_alias_service.add_alias("verify", "roll verify")

    @command(
        command="random",
        params=[Any("items")],
        access_level="all",
        description="Randomly order a list of elements",
        extended_description="Enter a space-delimited list of items to randomize"
    )
    def random_command(self, request, items):
        items = items.split(" ")
        random.shuffle(items)
        return " ".join(items)

    @command(command="roll",
             params=[Int("start_value", is_optional=True),
                     Int("end_value")],
             access_level="all",
             description="Roll a number between 1 and a number")
    def roll_command(self, request, start_value, end_value):
        start_value = start_value or 1

        if start_value > end_value:
            start_value, end = end_value, start_value

        result = random.randint(start_value, end_value)

        self.db.exec(
            "INSERT INTO roll (char_id, min_value, max_value, result, created_at) VALUES (?, ?, ?, ?, ?)",
            [
                request.sender.char_id, start_value, end_value, result,
                int(time.time())
            ])

        return "Rolling between %d and %d: <highlight>%d<end>. /tell <myname> roll verify %d" % (
            start_value, end_value, result, self.db.last_insert_id())

    @command(command="roll",
             params=[Const("verify"), Int("roll_id")],
             access_level="all",
             description="Verify a roll that happened")
    def roll_verify_command(self, request, _, roll_id):
        row = self.db.query_single("SELECT * FROM roll WHERE id = ?",
                                   [roll_id])

        if not row:
            return "Could not find roll with id <highlight>%d<end>." % roll_id
        else:
            time_string = self.util.time_to_readable(
                int(time.time()) - row.created_at)
            name = self.character_service.resolve_char_to_name(row.char_id)
            return "Rolling between %d and %d: <highlight>%d<end>. %s ago for %s." % (
                row.min_value, row.max_value, row.result, time_string, name)
Exemplo n.º 14
0
class DynaController:
    def inject(self, registry):
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")

    @command(command="dyna",
             params=[],
             access_level="all",
             description="Show a list of dyna mob types")
    def dyna_mob_types_command(self, request):
        data = self.db.query(
            "SELECT mob, MIN(minQl) AS minQl, MAX(maxQl) AS maxQl FROM dynadb GROUP BY mob ORDER BY mob ASC"
        )

        blob = ""
        for row in data:
            blob += "%s (%d - %d)\n" % (self.text.make_chatcmd(
                row.mob,
                "/tell <myname> dyna %s" % row.mob), row.minQl, row.maxQl)

        return ChatBlob("Dyna Mobs (%d)" % len(data), blob)

    @command(command="dyna",
             params=[Int("level")],
             access_level="all",
             description="Show a list of dyna camps +/- 25 of QL")
    def dyna_level_command(self, request, level):
        min_level = level - 25
        max_level = level + 25

        data = self.db.query(
            "SELECT * FROM dynadb d JOIN playfields p ON d.playfield_id = p.id WHERE d.minQl >= ? AND d.maxQl <= ? ORDER BY minQl",
            [min_level, max_level])

        blob = "Results of dyna camps between QL <highlight>%d<end> and <highlight>%d<end>\n\n" % (
            min_level, max_level)
        blob += self.format_results(data)
        url = "http://creativestudent.com/ao/files-helpfiles.html"
        blob += "Dyna camp information taken from CSP help files: " + self.text.make_chatcmd(
            url, "/start " + url)

        return ChatBlob("Dyna Camps (%d)" % len(data), blob)

    @command(command="dyna",
             params=[Any("search")],
             access_level="all",
             description="Search for dyna camps based on playfield or mob type"
             )
    def dyna_search_command(self, request, search):
        search_param = "%" + search + "%"
        data = self.db.query(
            "SELECT * FROM dynadb d JOIN playfields p ON d.playfield_id = p.id "
            "WHERE p.long_name LIKE ? OR p.short_name LIKE ? OR d.mob LIKE ? ORDER BY d.minQl",
            [search_param, search_param, search_param])

        blob = "Results of dyna camps search for <highlight>%s<end>\n\n" % search
        blob += self.format_results(data)
        url = "http://creativestudent.com/ao/files-helpfiles.html"
        blob += "Dyna camp information taken from CSP help files: " + self.text.make_chatcmd(
            url, "/start " + url)

        return ChatBlob("Dyna Camps (%d)" % len(data), blob)

    def format_results(self, data):
        blob = ""
        for row in data:
            coordinates = self.text.make_chatcmd(
                "%s %dx%d" % (row.long_name, row.cX, row.cY),
                "/waypoint %d %d %d" % (row.cX, row.cY, row.playfield_id))
            blob += "<pagebreak>" + coordinates + "\n"
            blob += "%s - Level <highlight>%d-%d<end>\n\n" % (
                row.mob, row.minQl, row.maxQl)
        return blob
Exemplo n.º 15
0
class SpecialsController:
    def __init__(self):
        pass

    def inject(self, registry):
        self.db = registry.get_instance("db")
        self.text = registry.get_instance("text")
        self.util = registry.get_instance("util")
        self.items_controller = registry.get_instance("items_controller")
        self.command_alias_service = registry.get_instance(
            "command_alias_service")

    def pre_start(self):
        self.db.load_sql_file(self.module_dir + "/" + "weapon_attributes.sql")

    def start(self):
        self.command_alias_service.add_alias("aimshot", "aimedshot")
        self.command_alias_service.add_alias("as", "aimedshot")
        self.command_alias_service.add_alias("inits", "weapon")
        self.command_alias_service.add_alias("init", "weapon")
        self.command_alias_service.add_alias("specials", "weapon")
        self.command_alias_service.add_alias("fling", "flingshot")

    @command(command="aggdef",
             params=[
                 Decimal("weapon_attack"),
                 Decimal("weapon_recharge"),
                 Int("init_skill")
             ],
             access_level="all",
             description="Show agg/def information")
    def aggdef_cmd(self, request, weapon_attack, weapon_recharge, init_skill):
        init_result = self.get_init_result(weapon_attack, weapon_recharge,
                                           init_skill)

        inits_full_agg = self.get_inits_needed(100, weapon_attack,
                                               weapon_recharge)
        inits_neutral = self.get_inits_needed(87.5, weapon_attack,
                                              weapon_recharge)
        inits_full_def = self.get_inits_needed(0, weapon_attack,
                                               weapon_recharge)

        blob = "Attack: <highlight>%.2f secs</highlight>\n" % weapon_attack
        blob += "Recharge: <highlight>%.2f secs</highlight>\n" % weapon_recharge
        blob += "Init Skill: <highlight>%d</highlight>\n\n" % init_skill

        blob += "You must set your AGG/DEF bar at <highlight>%d%%</highlight> to wield your weapon at 1/1.\n\n" % int(
            init_result)

        blob += "Init needed for max speed at Full Agg (100%%): <highlight>%d</highlight>\n" % inits_full_agg
        blob += "Init needed for max speed at Neutral (87.5%%): <highlight>%d</highlight>\n" % inits_neutral
        blob += "Init needed for max speed at Full Def (0%%): <highlight>%d</highlight>\n\n" % inits_full_def

        blob += self.get_inits_display(weapon_attack, weapon_recharge) + "\n\n"

        blob += "Note that at the neutral position (87.5%), your attack and recharge time will match that of the weapon you are using.\n\n\n"

        blob += "Based on the !aggdef command from Budabot, which was based upon a RINGBOT module made by NoGoal(RK2) and modified for Budabot by Healnjoo(RK2)"

        return ChatBlob("Agg/Def Results", blob)

    @command(command="aimedshot",
             params=[
                 Decimal("weapon_attack"),
                 Decimal("weapon_recharge"),
                 Int("aimed_shot_skill")
             ],
             access_level="all",
             description="Show aimed shot information")
    def aimedshot_cmd(self, request, weapon_attack, weapon_recharge,
                      aimed_shot_skill):
        as_info = self.get_aimed_shot_info(weapon_attack, weapon_recharge,
                                           aimed_shot_skill)

        blob = "Attack: <highlight>%.2f secs</highlight>\n" % weapon_attack
        blob += "Recharge: <highlight>%.2f secs</highlight>\n" % weapon_recharge
        blob += "Aimed Shot Skill: <highlight>%d</highlight>\n\n" % aimed_shot_skill

        blob += "Aimed Shot Multiplier: <highlight>1 - %dx</highlight>\n" % as_info.multiplier
        blob += "Aimed Shot Recharge: <highlight>%d secs</highlight>\n\n" % as_info.recharge

        blob += "You need <highlight>%d</highlight> Aimed Shot Skill to cap your recharge at <highlight>%d</highlight> seconds." % (
            as_info.skill_cap, as_info.hard_cap)

        return ChatBlob("Aimed Shot Results", blob)

    @command(command="brawl",
             params=[Int("brawl_skill")],
             access_level="all",
             description="Show brawl information")
    def brawl_cmd(self, request, brawl_skill):
        brawl_info = self.get_brawl_info(brawl_skill)

        blob = "Brawl Skill: <highlight>%d</highlight>\n\n" % brawl_skill

        blob += "Brawl Recharge: <highlight>15 secs</highlight> (constant)\n"
        blob += "Brawl Damage: <highlight> %d - %d (%d)</highlight>\n" % (
            brawl_info.min_dmg, brawl_info.max_dmg, brawl_info.crit_dmg)
        blob += "Stun Change: <highlight>%d%%</highlight>\n" % brawl_info.stun_chance
        blob += "Stun Duration: <highlight>%d secs</highlight>\n\n" % brawl_info.stun_duration

        blob += "Stun chance is 10% for brawl skill less than 1000 and 20% for brawl skill 1000 or greater.\n"
        blob += "Stun duration is 3 seconds for brawl skill less than 2001 and 4 seconds for brawl skill 2001 or greater.\n\n\n"

        blob += "Based on the !brawl command from Budabot by Imoutochan (RK1)"

        return ChatBlob("Brawl Results", blob)

    @command(command="burst",
             params=[
                 Decimal("weapon_attack"),
                 Decimal("weapon_recharge"),
                 Int("burst_recharge"),
                 Int("burst_skill")
             ],
             access_level="all",
             description="Show burst information")
    def burst_cmd(self, request, weapon_attack, weapon_recharge,
                  burst_recharge, burst_skill):
        burst_info = self.get_burst_info(weapon_attack, weapon_recharge,
                                         burst_recharge, burst_skill)

        blob = "Attack: <highlight>%.2f secs</highlight>\n" % weapon_attack
        blob += "Recharge: <highlight>%.2f secs</highlight>\n" % weapon_recharge
        blob += "Burst Recharge: <highlight>%d</highlight>\n" % burst_recharge
        blob += "Burst Skill: <highlight>%d</highlight>\n\n" % burst_skill

        blob += "Burst Recharge: <highlight>%d secs</highlight>\n\n" % burst_info.recharge

        blob += "You need <highlight>%d</highlight> Burst Skill to cap your recharge at <highlight>%d secs</highlight>." % (
            burst_info.skill_cap, burst_info.hard_cap)

        return ChatBlob("Burst Results", blob)

    @command(command="dimach",
             params=[Int("dimach_skill")],
             access_level="all",
             description="Show dimach information")
    def dimach_cmd(self, request, dimach_skill):
        dimach_info = self.get_dimach_info(dimach_skill)

        blob = "Dimach Skill: <highlight>%d</highlight>\n\n" % dimach_skill

        blob += "<header2>Martial Artist</header2>\n"
        blob += "Damage: <highlight>%d</highlight>\n" % dimach_info.ma_dmg
        blob += "Recharge: <highlight>%s</highlight>\n\n" % self.util.time_to_readable(
            dimach_info.ma_recharge)

        blob += "<header2>Keeper</header2>\n"
        blob += "Self Heal: <highlight>%d</highlight>\n" % dimach_info.keeper_heal
        blob += "Recharge: <highlight>5 mins</highlight> (constant)\n\n"

        blob += "<header2>Shade</header2>\n"
        blob += "Damage: <highlight>%d</highlight>\n" % dimach_info.shade_dmg
        blob += "Self Heal: <highlight>%d%%</highlight> * <highlight>%d</highlight> = <highlight>%d</highlight>\n" % \
                (dimach_info.shade_heal_percentage, dimach_info.shade_dmg, round(dimach_info.shade_heal_percentage * dimach_info.shade_dmg / 100))
        blob += "Recharge: <highlight>%s</highlight>\n\n" % self.util.time_to_readable(
            dimach_info.shade_recharge)

        blob += "<header2>All other professions</header2>\n"
        blob += "Damage: <highlight>%d</highlight>\n" % dimach_info.general_dmg
        blob += "Recharge: <highlight>30 mins</highlight> (constant)\n\n\n"

        blob += "Based on the !dimach command from Budabot by Imoutochan (RK1)"

        return ChatBlob("Dimach Results", blob)

    @command(command="fastattack",
             params=[Decimal("weapon_attack"),
                     Int("fast_attack_skill")],
             access_level="all",
             description="Show fast attack information")
    def fastattack_cmd(self, request, weapon_attack, fast_attack_skill):
        fast_attack_info = self.get_fast_attack_info(weapon_attack,
                                                     fast_attack_skill)

        blob = "Attack: <highlight>%.2f secs</highlight>\n" % weapon_attack
        blob += "Fast Attack Skill: <highlight>%d</highlight>\n\n" % fast_attack_skill

        blob += "Fast Attack Recharge: <highlight>%.2f secs</highlight>\n\n" % fast_attack_info.recharge

        blob += "You need <highlight>%d</highlight> Fast Attack Skill to cap your recharge at <highlight>%.2f secs</highlight>." % (
            fast_attack_info.skill_cap, fast_attack_info.hard_cap)

        return ChatBlob("Fast Attack Results", blob)

    @command(command="flingshot",
             params=[Decimal("weapon_attack"),
                     Int("fling_shot_skill")],
             access_level="all",
             description="Show fling shot information")
    def flingshot_cmd(self, request, weapon_attack, fling_shot_skill):
        fling_shot_info = self.get_fling_shot_info(weapon_attack,
                                                   fling_shot_skill)

        blob = "Attack: <highlight>%.2f secs</highlight>\n" % weapon_attack
        blob += "Fling Shot Skill: <highlight>%d</highlight>\n\n" % fling_shot_skill

        blob += "Fling Shot Recharge: <highlight>%.2f secs</highlight>\n\n" % fling_shot_info.recharge

        blob += "You need <highlight>%d</highlight> Fling Shot Skill to cap your recharge at <highlight>%.2f secs</highlight>." % (
            fling_shot_info.skill_cap, fling_shot_info.hard_cap)

        return ChatBlob("Fling Shot Results", blob)

    @command(command="fullauto",
             params=[
                 Decimal("weapon_attack"),
                 Decimal("weapon_recharge"),
                 Int("full_auto_recharge"),
                 Int("full_auto_skill")
             ],
             access_level="all",
             description="Show full auto information")
    def fullauto_cmd(self, request, weapon_attack, weapon_recharge,
                     full_auto_recharge, full_auto_skill):
        full_auto_info = self.get_full_auto_info(weapon_attack,
                                                 weapon_recharge,
                                                 full_auto_recharge,
                                                 full_auto_skill)

        blob = "Attack: <highlight>%.2f secs</highlight>\n" % weapon_attack
        blob += "Recharge: <highlight>%.2f secs</highlight>\n" % weapon_recharge
        blob += "Full Auto Recharge: <highlight>%d</highlight>\n" % full_auto_recharge
        blob += "Full Auto Skill: <highlight>%d</highlight>\n\n" % full_auto_skill

        blob += "Full Auto Recharge: <highlight>%d secs</highlight>\n" % full_auto_info.recharge
        blob += "Max Number of Bullets: <highlight>%d</highlight>\n\n" % full_auto_info.max_bullets

        blob += "You need <highlight>%d</highlight> Full Auto Skill to cap your recharge at <highlight>%d secs</highlight>.\n\n" % (
            full_auto_info.skill_cap, full_auto_info.hard_cap)

        blob += "From <highlight>0 to 10K</highlight> damage, the bullet damage is unchanged.\n"
        blob += "From <highlight>10K to 11.5K</highlight> damage, each bullet damage is halved.\n"
        blob += "From <highlight>11K to 15K</highlight> damage, each bullet damage is halved again.\n"
        blob += "<highlight>15K</highlight> is the damage cap."

        return ChatBlob("Full Auto Results", blob)

    @command(command="mafist",
             params=[Int("ma_skill")],
             access_level="all",
             description="Show martial arts information")
    def mafist_cmd(self, request, ma_skill):
        ma_info = self.get_martial_arts_info(ma_skill)

        blob = "Martial Arts Skill: <highlight>%d</highlight>\n\n" % ma_skill

        blob += "<header2>Martial Artist</header2>\n"
        blob += "Speed: <highlight>%.2f / %.2f secs</highlight>\n" % (
            ma_info.ma_speed, ma_info.ma_speed)
        blob += "Damage: <highlight>%d - %d (%d)</highlight>\n\n" % (
            ma_info.ma_min_dmg, ma_info.ma_max_dmg, ma_info.ma_crit_dmg)

        blob += "<header2>Shade</header2>\n"
        blob += "Speed: <highlight>%.2f / %.2f secs</highlight>\n" % (
            ma_info.shade_speed, ma_info.shade_speed)
        blob += "Damage: <highlight>%d - %d (%d)</highlight>\n\n" % (
            ma_info.shade_min_dmg, ma_info.shade_max_dmg,
            ma_info.shade_crit_dmg)

        blob += "<header2>All other professions</header2>\n"
        blob += "Speed: <highlight>%.2f / %.2f secs</highlight>\n" % (
            ma_info.gen_speed, ma_info.gen_speed)
        blob += "Damage: <highlight>%d - %d (%d)</highlight>\n\n" % (
            ma_info.gen_min_dmg, ma_info.gen_max_dmg, ma_info.gen_crit_dmg)

        return ChatBlob("Martial Arts Results", blob)

    @command(command="nanoinit",
             params=[Decimal("nano_attack_time"),
                     Int("nano_cast_init")],
             access_level="all",
             description="Show nano cast init information")
    def nanoinit_cmd(self, request, nano_attack_time, nano_cast_init):
        nano_cast_info = self.get_nano_cast_info(nano_cast_init,
                                                 nano_attack_time)

        blob = "Attack: <highlight>%.2f secs</highlight>\n" % nano_attack_time
        blob += "Nano Cast Init: <highlight>%d</highlight>\n\n" % nano_cast_init

        blob += "Cast Time Reduction: <highlight>%.2f</highlight>\n" % nano_cast_info.cast_time_reduction
        blob += "Effective Cast Time: <highlight>%.2f</highlight>\n\n" % nano_cast_info.effective_cast_time

        if nano_cast_info.bar_setting > 100:
            blob += "You cannot instacast this nano at any AGG/DEF setting.\n\n"
        else:
            blob += "You must set your AGG/DEF bar to <highlight>%d%%</highlight> to instacast this nano.\n\n" % nano_cast_info.bar_setting

        blob += "NanoC. Init needed to instacast at Full Agg (100%%): <highlight>%d</highlight>\n" % nano_cast_info.instacast_full_agg
        blob += "NanoC. Init needed to instacast at Neutral (87.5%%): <highlight>%d</highlight>\n" % nano_cast_info.instacast_neutral
        blob += "NanoC. Init needed to instacast at Half (50%%): <highlight>%d</highlight>\n" % nano_cast_info.instacast_half
        blob += "NanoC. Init needed to instacast at Full Def (0%%): <highlight>%d</highlight>\n\n" % nano_cast_info.instacast_full_def

        blob += "Cast time at Full Agg (100%%): <highlight>%.2f</highlight>\n" % nano_cast_info.cast_time_full_agg
        blob += "Cast time at Neutral (87.5%%): <highlight>%.2f</highlight>\n" % nano_cast_info.cast_time_neutral
        blob += "Cast time at Half (50%%): <highlight>%.2f</highlight>\n" % nano_cast_info.cast_time_half
        blob += "Cast time at Full Def (0%%): <highlight>%.2f</highlight>" % nano_cast_info.cast_time_full_def

        return ChatBlob("Nano Cast Init Results", blob)

    @command(command="weapon",
             params=[Int("item_id"),
                     Int("ql", is_optional=True)],
             access_level="all",
             description="Show weapon information")
    def weapon_cmd(self, request, item_id, ql):
        return self.get_weapon_info(item_id, ql)

    @command(command="weapon",
             params=[Item("weapon_link")],
             access_level="all",
             description="Show weapon information")
    def weapon_cmd(self, request, item):
        return self.get_weapon_info(item.high_id, item.ql)

    @command(command="weapon",
             params=[Int("item_id"),
                     Int("ql", is_optional=True)],
             access_level="all",
             description="Show weapon information")
    def weapon_manual_cmd(self, request, item_id, ql):
        if not ql:
            item = self.items_controller.get_by_item_id(item_id)
            if item:
                ql = item.highql
            else:
                return "Could not find item with id <highlight>%d</highlight>." % item_id

        return self.get_weapon_info(item_id, ql)

    def get_weapon_info(self, item_id, ql):
        if ql:
            item = self.db.query_single(
                "SELECT * FROM aodb WHERE highid = ? AND lowql <= ? AND highql >= ? "
                "UNION "
                "SELECT * FROM aodb WHERE lowid = ? AND lowql <= ? AND highql >= ? "
                "LIMIT 1", [item_id, ql, ql, item_id, ql, ql])
        else:
            item = self.db.query_single(
                "SELECT * FROM aodb WHERE highid = ? UNION SELECT * FROM aodb WHERE lowid = ? LIMIT 1",
                [item_id, item_id])

        if not item:
            return "Could not find item with ID <highlight>%d</highlight>." % item_id

        ql = ql or item.highql

        low_attributes = self.db.query_single(
            "SELECT * FROM weapon_attributes WHERE id = ?", [item.lowid])
        high_attributes = self.db.query_single(
            "SELECT * FROM weapon_attributes WHERE id = ?", [item.highid])

        if not low_attributes or not high_attributes:
            return "Could not find weapon information or item is not a weapon for ID <highlight>%d</highlight>." % item_id

        weapon_attack = self.util.interpolate_value(
            ql, {
                item.lowql: low_attributes.attack_time,
                item.highql: high_attributes.attack_time
            }) / 100
        weapon_recharge = self.util.interpolate_value(
            ql, {
                item.lowql: low_attributes.recharge_time,
                item.highql: high_attributes.recharge_time
            }) / 100

        blob = "%s (QL %d)\n\n" % (self.text.make_item(item.lowid, item.highid,
                                                       ql, item.name), ql)
        blob += "Attack: <highlight>%.2f</highlight>\n" % weapon_attack
        blob += "Recharge: <highlight>%.2f</highlight>\n\n" % weapon_recharge

        blob += self.get_inits_display(weapon_attack, weapon_recharge) + "\n"

        blob += "<header2>Specials</header2>\n"

        if high_attributes.aimed_shot:
            as_info = self.get_aimed_shot_info(weapon_attack, weapon_recharge,
                                               1)
            blob += "Aimed Shot\n<highlight>%d</highlight> skill needed to cap Aimed Shot recharge at <highlight>%d secs</highlight>\n\n" % \
                    (as_info.skill_cap, as_info.hard_cap)

        if high_attributes.burst:
            burst_recharge = self.util.interpolate_value(
                ql, {
                    item.lowql: low_attributes.burst,
                    item.highql: high_attributes.burst
                })
            burst_info = self.get_burst_info(weapon_attack, weapon_recharge,
                                             burst_recharge, 1)
            blob += "Burst Recharge: <highlight>%d</highlight>\n<highlight>%d</highlight> skill needed to cap Burst recharge at <highlight>%d secs</highlight>\n\n" % \
                    (burst_recharge, burst_info.skill_cap, burst_info.hard_cap)

        if high_attributes.fast_attack:
            fast_attack_info = self.get_fast_attack_info(weapon_attack, 1)
            blob += "Fast Attack\n<highlight>%d</highlight> skill needed to cap Fast Attack recharge at <highlight>%.2f secs</highlight>\n\n" % \
                    (fast_attack_info.skill_cap, fast_attack_info.hard_cap)

        if high_attributes.fling_shot:
            fling_shot_info = self.get_fling_shot_info(weapon_attack, 1)
            blob += "Fling Shot\n<highlight>%d</highlight> skill needed to cap Fling Shot recharge at <highlight>%.2f secs</highlight>\n\n" % \
                    (fling_shot_info.skill_cap, fling_shot_info.hard_cap)

        if high_attributes.full_auto:
            full_auto_recharge = self.util.interpolate_value(
                ql, {
                    item.lowql: low_attributes.full_auto,
                    item.highql: high_attributes.full_auto
                })
            full_auto_info = self.get_full_auto_info(weapon_attack,
                                                     weapon_recharge,
                                                     full_auto_recharge, 1)
            blob += "Full Auto Recharge: <highlight>%d</highlight>\n<highlight>%d</highlight> skill needed to cap Full Auto recharge at <highlight>%d secs</highlight>\n\n" % \
                    (full_auto_recharge, full_auto_info.skill_cap, full_auto_info.hard_cap)

        return ChatBlob("Weapon Info for %s (QL %d)" % (item.name, ql), blob)

    def get_init_result(self, weapon_attack, weapon_recharge, init_skill):
        if init_skill < 1200:
            attack_calc = (((weapon_attack -
                             (init_skill / 600)) - 1) / 0.02) + 87.5
            recharge_calc = (((weapon_recharge -
                               (init_skill / 300)) - 1) / 0.02) + 87.5
        else:
            attack_calc = (((weapon_attack - (1200 / 600) - (
                (init_skill - 1200) / 600 / 3)) - 1) / 0.02) + 87.5
            recharge_calc = (((weapon_recharge - (1200 / 300) - (
                (init_skill - 1200) / 300 / 3)) - 1) / 0.02) + 87.5

        if attack_calc < recharge_calc:
            init_result = recharge_calc
        else:
            init_result = attack_calc

        init_result = min(init_result, 100)  # max of 100
        init_result = max(init_result, 0)  # min of 0

        return init_result

    def get_inits_needed(self, init_result, weapon_attack, weapon_recharge):
        inits_attack = ((
            (init_result - 87.5) * 0.02) + 1 - weapon_attack) * -600
        inits_recharge = ((
            (init_result - 87.5) * 0.02) + 1 - weapon_recharge) * -300

        if inits_attack > 1200:
            inits_attack = (((
                (init_result - 87.5) * 0.02) + 1 - weapon_attack + 2) *
                            -1800) + 1200

        if inits_recharge > 1200:
            inits_recharge = (((
                (init_result - 87.5) * 0.02) + 1 - weapon_attack + 4) *
                              -900) + 1200

        if inits_attack < inits_recharge:
            return inits_recharge
        else:
            return inits_attack

    def get_aimed_shot_info(self, weapon_attack, weapon_recharge,
                            aimed_shot_skill):
        result = DictObject()
        result.multiplier = round(aimed_shot_skill / 95)
        result.hard_cap = math.floor(weapon_attack + 10)
        result.skill_cap = math.ceil((4000 * weapon_recharge - 1100) / 3)

        as_recharge = math.ceil((weapon_recharge * 40) -
                                (aimed_shot_skill * 3 / 100) + weapon_attack -
                                1)
        if as_recharge < result.hard_cap:
            as_recharge = result.hard_cap

        result.recharge = as_recharge

        return result

    def get_brawl_info(self, brawl_skill):
        min_values = {
            1: 1,
            1000: 100,
            1001: 101,
            2000: 170,
            2001: 171,
            3000: 235
        }
        max_values = {
            1: 2,
            1000: 500,
            1001: 501,
            2000: 850,
            2001: 851,
            3000: 1145
        }
        crit_values = {
            1: 3,
            1000: 500,
            1001: 501,
            2000: 600,
            2001: 601,
            3000: 725
        }

        brawl_info = DictObject()
        brawl_info.min_dmg = self.util.interpolate_value(
            brawl_skill, min_values)
        brawl_info.max_dmg = self.util.interpolate_value(
            brawl_skill, max_values)
        brawl_info.crit_dmg = self.util.interpolate_value(
            brawl_skill, crit_values)
        brawl_info.stun_chance = 10 if brawl_skill < 1000 else 20
        brawl_info.stun_duration = 3 if brawl_skill < 2001 else 4

        return brawl_info

    def get_burst_info(self, weapon_attack, weapon_recharge, burst_recharge,
                       burst_skill):
        result = DictObject()
        result.hard_cap = round(weapon_attack + 8)
        result.skill_cap = math.floor(
            ((weapon_recharge * 20) + (burst_recharge / 100) - 8) * 25)

        recharge = math.floor((weapon_recharge * 20) + (burst_recharge / 100) -
                              (burst_skill / 25) + weapon_attack)
        if recharge < result.hard_cap:
            recharge = result.hard_cap

        result.recharge = recharge

        return result

    def get_dimach_info(self, dimach_skill):
        # item ids: 42033, 42032, 213260, 213261, 213262, 213263
        general_dmg = {
            1: 1,
            1000: 2000,
            1001: 2001,
            2000: 2500,
            2001: 2501,
            3000: 2850
        }

        # item ids: 42033, 42032, 213264, 213265, 213266, 213267
        ma_recharge = {
            1: 1800,
            1000: 1800,
            1001: 1188,
            2000: 600,
            2001: 600,
            3000: 300
        }
        ma_dmg = {
            1: 1,
            1000: 2000,
            1001: 2001,
            2000: 2340,
            2001: 2341,
            3000: 2550
        }

        # item ids: 213269, 213270, 213271, 213272, 213273, 213274
        shade_recharge = {
            1: 300,
            1000: 300,
            1001: 300,
            2000: 300,
            2001: 240,
            3000: 200
        }
        shade_dmg = {
            1: 1,
            1000: 920,
            1001: 921,
            2000: 1872,
            2001: 1873,
            3000: 2750
        }
        shade_heal_percentage = {
            1: 70,
            1000: 70,
            1001: 70,
            2000: 75,
            2001: 75,
            3000: 80
        }

        # item ids: 211399, 211400, 213275, 213276, 213277, 213278
        keeper_heal = {
            1: 1,
            1000: 3000,
            1001: 3001,
            2000: 10500,
            2001: 10501,
            3000: 15000
        }

        result = DictObject()
        result.general_dmg = self.util.interpolate_value(
            dimach_skill, general_dmg)
        result.ma_recharge = self.util.interpolate_value(
            dimach_skill, ma_recharge)
        result.ma_dmg = self.util.interpolate_value(dimach_skill, ma_dmg)
        result.shade_recharge = self.util.interpolate_value(
            dimach_skill, shade_recharge)
        result.shade_dmg = self.util.interpolate_value(dimach_skill, shade_dmg)
        result.shade_heal_percentage = self.util.interpolate_value(
            dimach_skill, shade_heal_percentage)
        result.keeper_heal = self.util.interpolate_value(
            dimach_skill, keeper_heal)

        return result

    def get_fast_attack_info(self, weapon_attack, fast_attack_skill):
        result = DictObject()
        result.hard_cap = weapon_attack + 5
        result.skill_cap = ((weapon_attack * 16) - result.hard_cap) * 100

        recharge = (weapon_attack * 16) - (fast_attack_skill / 100)
        if recharge < result.hard_cap:
            recharge = result.hard_cap

        result.recharge = recharge

        return result

    def get_fling_shot_info(self, weapon_attack, fling_shot_skill):
        result = DictObject()
        result.hard_cap = weapon_attack + 5
        result.skill_cap = ((weapon_attack * 16) - result.hard_cap) * 100

        recharge = (weapon_attack * 16) - (fling_shot_skill / 100)
        if recharge < result.hard_cap:
            recharge = result.hard_cap

        result.recharge = recharge

        return result

    def get_full_auto_info(self, weapon_attack, weapon_recharge,
                           full_auto_recharge, full_auto_skill):
        result = DictObject()
        result.hard_cap = math.floor(weapon_attack + 10)
        result.skill_cap = ((weapon_recharge * 40) +
                            (full_auto_recharge / 100) - 11) * 25
        result.max_bullets = 5 + math.floor(full_auto_skill / 100)

        recharge = round((weapon_recharge * 40) + (full_auto_recharge / 100) -
                         (full_auto_skill / 25) + round(weapon_attack - 1))
        if recharge < result.hard_cap:
            recharge = result.hard_cap

        result.recharge = recharge

        return result

    def get_martial_arts_info(self, ma_skill):
        result = DictObject()

        # ma items: http://budabot.com/forum/viewtopic.php?f=7&t=1264&p=5739#p5739
        #  QL    1       100     500     1      500      1      500
        #     211349, 211350, 211351, 211359, 211360, 211365, 211366    // Shade
        #     211352, 211353, 211354, 211357, 211358, 211363, 211364    // MA
        #      43712, 144745,  43713, 211355, 211356, 211361, 211362    // Gen/other

        ma_min_dmg = {
            1: 4,
            200: 45,
            1000: 125,
            1001: 130,
            2000: 220,
            2001: 225,
            3000: 450
        }
        ma_max_dmg = {
            1: 8,
            200: 75,
            1000: 400,
            1001: 405,
            2000: 830,
            2001: 831,
            3000: 1300
        }
        ma_crit_dmg = {
            1: 3,
            200: 50,
            1000: 500,
            1001: 501,
            2000: 560,
            2001: 561,
            3000: 800
        }
        ma_speed = {
            1: 1.15,
            200: 1.20,
            1000: 1.25,
            1001: 1.30,
            2000: 1.35,
            2001: 1.45,
            3000: 1.50
        }

        shade_min_dmg = {
            1: 3,
            200: 25,
            1000: 55,
            1001: 56,
            2000: 130,
            2001: 131,
            3000: 280
        }
        shade_max_dmg = {
            1: 5,
            200: 60,
            1000: 258,
            1001: 259,
            2000: 682,
            2001: 683,
            3000: 890
        }
        shade_crit_dmg = {
            1: 3,
            200: 50,
            1000: 250,
            1001: 251,
            2000: 275,
            2001: 276,
            3000: 300
        }
        shade_speed = {
            1: 1.25,
            200: 1.25,
            1000: 1.45,
            1001: 1.45,
            2000: 1.65,
            2001: 1.65,
            3000: 1.85
        }

        gen_min_dmg = {
            1: 3,
            200: 25,
            1000: 65,
            1001: 66,
            2000: 140,
            2001: 204,
            3000: 300
        }
        gen_max_dmg = {
            1: 5,
            200: 60,
            1000: 280,
            1001: 281,
            2000: 715,
            2001: 831,
            3000: 990
        }
        gen_crit_dmg = {
            1: 3,
            200: 50,
            1000: 500,
            1001: 501,
            2000: 605,
            2001: 605,
            3000: 630
        }
        gen_speed = {
            1: 1.25,
            200: 1.25,
            1000: 1.45,
            1001: 1.45,
            2000: 1.65,
            2001: 1.65,
            3000: 1.85
        }

        result.ma_min_dmg = self.util.interpolate_value(ma_skill, ma_min_dmg)
        result.ma_max_dmg = self.util.interpolate_value(ma_skill, ma_max_dmg)
        result.ma_crit_dmg = self.util.interpolate_value(ma_skill, ma_crit_dmg)
        result.ma_speed = self.util.interpolate_value(ma_skill, ma_speed, 2)

        result.shade_min_dmg = self.util.interpolate_value(
            ma_skill, shade_min_dmg)
        result.shade_max_dmg = self.util.interpolate_value(
            ma_skill, shade_max_dmg)
        result.shade_crit_dmg = self.util.interpolate_value(
            ma_skill, shade_crit_dmg)
        result.shade_speed = self.util.interpolate_value(
            ma_skill, shade_speed, 2)

        result.gen_min_dmg = self.util.interpolate_value(ma_skill, gen_min_dmg)
        result.gen_max_dmg = self.util.interpolate_value(ma_skill, gen_max_dmg)
        result.gen_crit_dmg = self.util.interpolate_value(
            ma_skill, gen_crit_dmg)
        result.gen_speed = self.util.interpolate_value(ma_skill, gen_speed, 2)

        return result

    def get_nano_cast_info(self, nano_cast_init, nano_attack_time):
        if nano_cast_init > 1200:
            nano_cast_reduction = (nano_cast_init - 1200) / 600 + 6
        else:
            nano_cast_reduction = nano_cast_init / 200

        result = DictObject()
        result.cast_time_reduction = nano_cast_reduction
        result.effective_cast_time = nano_attack_time - nano_cast_reduction
        result.instacast_full_agg = self.get_nano_init_for_instacast(
            nano_attack_time - 1)
        result.instacast_neutral = self.get_nano_init_for_instacast(
            nano_attack_time - 0.75)
        result.instacast_half = self.get_nano_init_for_instacast(
            nano_attack_time)
        result.instacast_full_def = self.get_nano_init_for_instacast(
            nano_attack_time + 1)
        result.cast_time_full_agg = result.effective_cast_time - 1
        result.cast_time_neutral = result.effective_cast_time - 0.75
        result.cast_time_half = result.effective_cast_time
        result.cast_time_full_def = result.effective_cast_time + 1

        bar_setting = round(result.effective_cast_time / 0.02 + 50)
        if bar_setting < 0:
            bar_setting = 0
        result.bar_setting = bar_setting

        return result

    def get_nano_init_for_instacast(self, nano_attack_time):
        if nano_attack_time < 6:
            return nano_attack_time * 200
        else:
            return 1200 + (nano_attack_time - 6) * 600

    def get_inits_display(self, weapon_attack, weapon_recharge):
        num_steps = 9
        step_size = 100 / (num_steps - 1)
        blob = ""
        for i in reversed(range(0, num_steps)):
            inits_needed = self.get_inits_needed(i * step_size, weapon_attack,
                                                 weapon_recharge)
            blob += "DEF >%s%s%s< AGG %d%% %d init \n" % (
                "=" * i, "][", "=" *
                (num_steps - 1 - i), i * step_size, inits_needed)

        return blob
Exemplo n.º 16
0
class CharacterHistoryController:
    def __init__(self):
        pass

    def inject(self, registry):
        self.bot = registry.get_instance("bot")
        self.text = registry.get_instance("text")
        self.util = registry.get_instance("util")
        self.character_history_service = registry.get_instance(
            "character_history_service")
        self.command_alias_service = registry.get_instance(
            "command_alias_service")

    def start(self):
        self.command_alias_service.add_alias("h", "history")

    @command(
        command="history",
        params=[Character("character"),
                Int("server_num", is_optional=True)],
        access_level="guest",
        description="Get history of character",
        extended_description=
        "Use server_num 6 for RK2019 and server_num 5 for live")
    def handle_history_cmd1(self, request, char, server_num):
        server_num = server_num or self.bot.dimension

        data = self.character_history_service.get_character_history(
            char.name, server_num)
        if not data:
            return "Could not find history for <highlight>%s</highlight> on server <highlight>%d</highlight>." % (
                char.name, server_num)

        return ChatBlob(
            "History of %s (RK%d)" % (char.name, server_num),
            self.format_character_history(char.name, server_num, data))

    def format_character_history(self, name, server_num, history):
        col_separator = " | "

        rows = [[
            "Name", "Date", "Lvl", "AI", "Side", "Breed", "CharId",
            "Org (Rank)"
        ]]
        uniques = set()
        for row in history:
            if row.nickname and row.nickname != name:
                uniques.add(row.nickname)
            if row.char_id and row.char_id != name:
                uniques.add(row.char_id)

            if row.guild_name:
                org = "%s (%s)" % (row.guild_name, row.guild_rank_name)
            else:
                org = ""

            last_changed = self.util.format_date(int(float(row.last_changed)))
            current_row = [row.nickname, last_changed]

            if row.deleted == "1":  # This value is output as string
                current_row.append("<red>DELETED</red>")
            else:
                current_row.extend([
                    row.level,
                    "<green>%s</green>" % (row.defender_rank or "0"),
                    row.faction, row.breed, row.char_id, org
                ])

            rows.append(current_row)

        rows = self.text.pad_table(rows)
        blob = "  ".join(
            map(
                lambda x: "[" + self.text.make_tellcmd(
                    f"History {x}", f"history {x} {server_num}") + "]",
                uniques)) + "\n\n"

        blob += col_separator.join(rows[0]) + "\n"
        blob += "__________________________________________________________\n"
        for columns in rows[1:]:
            blob += col_separator.join(columns) + "\n"

        blob += "\nHistory provided by Auno.org, Chrisax, and Athen Paladins"
        return blob
Exemplo n.º 17
0
class PointsController:
    def __init__(self):
        pass

    def inject(self, registry):
        self.bot: Tyrbot = registry.get_instance("bot")
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.character_service: CharacterService = registry.get_instance(
            "character_service")
        self.util: Util = registry.get_instance("util")
        self.setting_service: SettingService = registry.get_instance(
            "setting_service")
        self.alts_service: AltsService = registry.get_instance("alts_service")

    def start(self):
        if self.db.query_single(
                "SELECT COUNT(*) AS count FROM points_presets").count < 1:
            # Populate with pre-made presets if empty
            presets = [
                "s13", "s28", "s35", "s42", "zodiac", "zod", "tnh", "beast",
                "12m", "tara", "pvp", "towers", "wipe", "clanwipe", "clan",
                "omniwipe", "omni", "bonus", "early"
            ]
            sql = "INSERT INTO points_presets (name) VALUES (?)"
            for preset in presets:
                self.db.exec(sql, [preset])

    @setting(name="initial_points_value",
             value="0",
             description="How many points new accounts start with")
    def initial_points_value(self):
        return NumberSettingType()

    @command(command="account",
             params=[Const("create"), Character("char")],
             access_level="moderator",
             description="Create a new account for given character name",
             sub_command="modify")
    def bank_create_cmd(self, request, _, char: SenderObj):
        alts_info = self.alts_service.get_alts(char.char_id)

        for alt in alts_info:
            sql = "SELECT char_id, disabled FROM points WHERE char_id = ? LIMIT 1"
            count = self.db.query_single(sql, [alt.char_id])

            if count:
                was_disabled = False

                if count.disabled == 1:
                    if self.db.exec(
                            "UPDATE points SET disabled = 0 WHERE char_id = ?",
                        [alt.char_id]):
                        was_disabled = True

                if alt.char_id == char.char_id:
                    if was_disabled:
                        if self.add_log_entry(
                                alt.char_id, request.sender.char_id,
                                "Account was re-enabled by %s" %
                                self.character_service.resolve_char_to_name(
                                    request.sender.char_id)):
                            return "<highlight>%s<end>'s account has been re-enabled." % char.name
                        else:
                            return "<highlight>%s<end> has an account, but failed to re-enable it." % char.name
                    else:
                        return "<highlight>%s<end> already has an account." % char.name
                else:
                    if was_disabled:
                        if self.add_log_entry(
                                alt.char_id, request.sender.char_id,
                                "Account was re-enabled by %s" %
                                self.character_service.resolve_char_to_name(
                                    request.sender.char_id)):
                            return "<highlight>%s<end>'s (%s) account has been re-enabled." % (
                                char.name,
                                self.character_service.resolve_char_to_name(
                                    alt.char_id))
                        else:
                            return "<highlight>%s<end> (%s) has an account, but failed to re-enable it." % (
                                char.name,
                                self.character_service.resolve_char_to_name(
                                    alt.char_id))
                    else:
                        return "<highlight>%s<end> (%s) already has an account." % (
                            char.name,
                            self.character_service.resolve_char_to_name(
                                alt.char_id))

        main_info = alts_info.pop(0)
        changed_to_main = main_info.char_id == char.char_id

        initial_points = self.setting_service.get(
            "initial_points_value").get_value()

        sql = "INSERT INTO points (char_id, points, created) VALUES (?,?,?)"
        if self.db.exec(sql,
                        [main_info.char_id, initial_points,
                         int(time.time())]) < 1:
            return "Failed to create an account for <highlight>%s<end>." % char.name

        if not self.add_log_entry(
                main_info.char_id, request.sender.char_id,
                "Account opened by %s" % request.sender.name):
            sql = "DELETE FROM points WHERE char_id = ?"
            self.db.exec(sql, [main_info.char_id])
            return "Failed to create an account for <highlight>%s<end>." % char.name

        name_reference = "%s (%s)" % (
            char.name,
            self.character_service.resolve_char_to_name(
                main_info.char_id)) if changed_to_main else char.name
        return "A new account has been created for <highlight>%s<end>." % name_reference

    @command(command="account",
             params=[Const("close"), Character("char")],
             access_level="moderator",
             description="Close the account for given character name",
             sub_command="modify")
    def close_account_cmd(self, request, _, char: SenderObj):
        main_id = self.alts_service.get_main(char.char_id)

        sql = "UPDATE points SET disabled = 1 WHERE char_id = ?"
        if self.db.exec(sql, [main_id.char_id]) > 0:
            reason = "Account was closed by %s" % self.character_service.resolve_char_to_name(
                request.sender.char_id)
            if self.add_log_entry(main_id.char_id, request.sender.char_id,
                                  reason):
                name_reference = "%s (%s)" % (
                    char.name,
                    self.character_service.resolve_char_to_name(
                        main_id.char_id)
                ) if main_id.char_id != char.char_id else char.name
                return "<highlight>%s<end> has had their account disabled. Logs have been preserved." % name_reference

        return "<highlight>%s<end> does not have an open account." % char.name

    @command(command="account",
             params=[],
             access_level="all",
             description="Look up your account")
    def account_self_cmd(self, request):
        return self.get_account_display(request.sender)

    @command(command="account",
             params=[Const("logentry"), Int("log_id")],
             access_level="moderator",
             description="Look up specific log entry",
             sub_command="modify")
    def account_log_entry_cmd(self, _1, _2, log_id: int):
        log_entry = self.db.query_single(
            "SELECT * FROM points_log WHERE log_id = ?", [log_id])

        if log_entry:
            char_name = self.character_service.resolve_char_to_name(
                log_entry.char_id)
            leader_name = self.character_service.resolve_char_to_name(
                log_entry.leader_id)

            blob = "Log entry ID: <highlight>%d<end>\n" % log_id
            blob += "Affecting account: <highlight>%s<end>\n" % char_name
            blob += "Action by: <highlight>%s<end>\n" % leader_name
            blob += "Type: <highlight>%s<end>\n" % (
                "Management" if log_entry.audit == 0 else "Altering of points")
            blob += "Reason: <highlight>%s<end>\n" % log_entry.reason
            action_links = None
            if log_entry.audit == 0:
                if "closed" in log_entry.reason:
                    action_links = self.text.make_chatcmd(
                        "Open the account",
                        "/tell <myname> account create %s" % char_name)
                elif "re-enabled" in log_entry.reason:
                    action_links = self.text.make_chatcmd(
                        "Close the account",
                        "/tell <myname> account close %s" % char_name)
            else:
                if log_entry.audit < 0:
                    reason = "Points from event (%d) has been retracted, %d points have been added." \
                             % (log_id, (-1*log_entry.audit))
                    action_links = self.text.make_chatcmd(
                        "Retract", "/tell <myname> bank give %d %s %s" %
                        ((-1 * log_entry.audit), char_name, reason))
                else:
                    reason = "Points from event (%d) has been retracted, %d points have been deducted." \
                             % (log_id, log_entry.audit)
                    action_links = self.text.make_chatcmd(
                        "Retract", "/tell <myname> bank take %d %s %s" %
                        (log_entry.audit, char_name, reason))

            blob += "Actions available: [%s]\n" % (action_links
                                                   if action_links is not None
                                                   else "No actions available")

            return ChatBlob("Log entry (%d)" % log_id, blob)

        return "No log entry with given ID <highlight>%d<end>." % log_id

    @command(command="account",
             params=[
                 Options(["give", "take"]),
                 Int("amount"),
                 Character("char"),
                 Any("reason")
             ],
             access_level="moderator",
             description="Give or take points from character account",
             sub_command="modify")
    def account_give_take_cmd(self, request, action: str, amount: int,
                              char: SenderObj, reason: str):
        main_id = self.alts_service.get_main(char.char_id)

        sql = "SELECT * FROM points WHERE char_id = ?"
        points = self.db.query_single(sql, [main_id.char_id])

        if points:
            if points.disabled == 1:
                return "<highlight>%s<end>'s account is disabled, altering the account is not possible." % char.name

            if points.points == 0 and action == "take":
                return "<highlight>%s<end> has 0 points - can't have less than 0 points." % char.name

            if amount > points.points and action == "take":
                amount = points.points

            new_points = amount if action == "give" else 0 - amount

            if not self.alter_points(points.points, main_id.char_id,
                                     new_points, request.sender.char_id,
                                     reason):
                return "Failed to alter <highlight>%s<end>'s account." % char.name

            action = "taken from" if action == "take" else "added to"
            return "<highlight>%s<end> has had <highlight>%d<end> points %s their account." % (
                char.name, amount, action)

        return "<highlight>%s<end> does not have an account." % char.name

    @command(command="account",
             params=[Character("char")],
             access_level="moderator",
             description="Look up account of another char",
             sub_command="modify")
    def account_other_cmd(self, request, char: SenderObj):
        return self.get_account_display(char)

    @command(command="presets",
             params=[Const("add"), Any("name"),
                     Int("points")],
             access_level="admin",
             description="Add new points preset")
    def presets_add_cmd(self, _1, _2, name: str, points: int):
        count = self.db.query_single(
            "SELECT COUNT(*) AS count FROM points_presets WHERE name = ?",
            [name]).count

        if count > 0:
            return "A preset already exists with the name <highlight>%s<end>." % name

        sql = "INSERT INTO points_presets (name, points) VALUES (?,?)"
        if self.db.exec(sql, [name, points]) > 0:
            return "A preset with the name <highlight>%s<end> was added, worth <green>%d<end> points." % (
                name, points)

        return "Failed to insert new preset in DB."

    @command(command="presets",
             params=[Const("rem"), Int("preset_id")],
             access_level="admin",
             description="Delete preset")
    def presets_rem_cmd(self, _1, _2, preset_id: int):
        if self.db.exec("DELETE FROM points_presets WHERE preset_id = ?",
                        [preset_id]) > 0:
            return "Successfully removed preset with ID <highlight>%d<end>." % preset_id

        return "No preset with given ID <highlight>%d<end>." % preset_id

    @command(command="presets",
             params=[Const("alter"),
                     Int("preset_id"),
                     Int("new_points")],
             access_level="admin",
             description="Alter the points dished out by given preset")
    def presets_alter_cmd(self, _1, _2, preset_id: int, new_points: int):
        preset = self.db.query_single(
            "SELECT * FROM points_presets WHERE preset_id = ?", [preset_id])

        if preset:
            if self.db.exec(
                    "UPDATE points_presets SET points = ? WHERE preset_id = ?",
                [new_points, preset_id]) > 0:
                return "Successfully updated the preset, <highlight>%s<end>, to dish out " \
                       "<green>%d<end> points instead of <red>%d<end>." % (preset.name, new_points, preset.points)

            return "Failed to update preset with ID <highlight>%d<end>." % preset_id

    @command(command="presets",
             params=[],
             access_level="admin",
             description="See list of points presets")
    def presets_cmd(self, _):
        return ChatBlob("Points presets", self.build_preset_list())

    def build_preset_list(self):
        presets = self.db.query(
            "SELECT * FROM points_presets ORDER BY name ASC, points DESC")

        if presets:
            blob = ""

            for preset in presets:
                add_points_link = self.text.make_chatcmd(
                    "Add pts", "/tell <myname> raid addpts %s" % preset.name)
                delete_link = self.text.make_chatcmd(
                    "Delete",
                    "/tell <myname> presets rem %d" % preset.preset_id)
                blob += "<highlight>%s<end> worth <green>%d<end> points [id: %d]\n | [%s] [%s]\n\n" \
                        % (preset.name, preset.points, preset.preset_id, add_points_link, delete_link)

            return blob

        return "No presets available. To add new presets use <highlight><symbol>presets add preset_name preset_points<end>."

    def add_log_entry(self,
                      char_id: int,
                      leader_id: int,
                      reason: str,
                      amount=0):
        sql = "INSERT INTO points_log (char_id, audit, leader_id, reason, time) VALUES (?,?,?,?,?)"
        return self.db.exec(
            sql, [char_id, amount, leader_id, reason,
                  int(time.time())]) > 0

    def alter_points(self, current_points: int, char_id: int, amount: int,
                     leader_id: int, reason: str):
        sql = "UPDATE points SET points = points + ? WHERE char_id = ?"
        if self.db.exec(sql, [amount, char_id]) < 1:
            return False

        if not self.add_log_entry(char_id, leader_id, reason, amount):
            sql = "UPDATE points p SET p.points = ? WHERE p.char_id = ?"
            self.db.exec(sql, [current_points, char_id])
            return False

        return True

    def get_account(self, main_id):
        sql = "SELECT p.char_id, p.points, p.disabled FROM points p WHERE p.char_id = ?"
        return self.db.query_single(sql, [main_id])

    def get_account_display(self, char: SenderObj):
        main = self.alts_service.get_main(char.char_id)
        if not main:
            return "Could not find character <highlight>%s<end>." % char.name

        points_log = self.db.query(
            "SELECT * FROM points_log WHERE char_id = ? ORDER BY time DESC LIMIT 50",
            [main.char_id])
        points = self.db.query_single(
            "SELECT points, disabled FROM points WHERE char_id = ?",
            [main.char_id])
        if not points:
            return "Could not find raid account for <highlight>%s<end>." % char.name

        alts_link = self.text.make_chatcmd(
            "Alts", "/tell <myname> alts %s" % main.name)
        blob = ""
        blob += "Holder of account: %s [%s]\n" % (main.name, alts_link)
        blob += "Points: %d\n" % points.points
        blob += "Status: %s\n\n" % ("<green>Open<end>" if points.disabled == 0
                                    else "<red>Disabled<end>")

        blob += "<header2>Account log<end>\n"
        if points_log is None:
            blob += "No entries in log."
        else:
            for entry in points_log:
                name_reference = "<highlight>%s<end>" % char.name

                if entry.audit == 0:
                    # If points is 0, then it's a general case log
                    blob += "<grey>[%s]<end> <orange>\"%s\"<end>" % (
                        self.util.format_datetime(entry.time), entry.reason)
                elif entry.audit > 0:
                    pts = "<green>%d<end>" % entry.audit
                    blob += "<grey>[%s]<end> %s points were added to %s account " \
                            "by <highlight>%s<end> with reason <orange>%s<end>" \
                            % (self.util.format_datetime(entry.time),
                               pts, name_reference,
                               self.character_service.resolve_char_to_name(entry.leader_id), entry.reason)
                elif entry.audit < 0:
                    pts = "<red>%d<end>" % (-1 * entry.audit)
                    blob += "<grey>[%s]<end> %s points were taken from %s account " \
                            "by <highlight>%s<end> with reason <orange>%s<end>" \
                            % (self.util.format_datetime(entry.time),
                               pts, name_reference,
                               self.character_service.resolve_char_to_name(entry.leader_id),
                               entry.reason)

                log_entry_link = self.text.make_chatcmd(
                    "%d" % entry.log_id,
                    "/tell <myname> account logentry %d" % entry.log_id)
                blob += " [%s]\n" % log_entry_link

        return ChatBlob("%s Account" % char.name, blob)
Exemplo n.º 18
0
class rulesController:
    def inject(self, registry):
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.bot: Tyrbot = registry.get_instance("bot")
        self.access_service: AccessService = registry.get_instance(
            "access_service")
        self.buddy_service = registry.get_instance("buddy_service")
        self.character_service: CharacterService = registry.get_instance(
            "character_service")
        self.setting_service: SettingService = registry.get_instance(
            "setting_service")
        self.alts_service: AltsService = registry.get_instance("alts_service")

    @command(command="rules",
             params=[],
             access_level="all",
             description="Displays the rules")
    def rules_command(self, request):
        rules = self.get_rules()
        self.bot.send_private_message(request.sender.char_id,
                                      ChatBlob("Rules", rules))

    def get_rules(self):
        blob = ""
        rules = self.db.query(
            "SELECT * FROM rules ORDER BY priority, indent, identifier, rule ASC"
        )
        admin_link = self.text.make_chatcmd("admin", "/tell <myname> admins")

        blob += "<header>:: Disclaimer :: <end>\n"
        blob += "The leaders of this bot are free to interpretate the rules in their own way.\n\n"
        blob += "If you feel like one of the leaders is abusing the status, feel free to message an %s.\n\n" % admin_link

        blob += "<header>:: Rules ::<end>\n"

        for rule in rules:
            entry = rule.rule
            priority = rule.priority
            indent = rule.indent
            identifier = rule.identifier

            if indent >= 0:

                blob += "<highlight>%s%s<end> <white>%s<end>\n" % (
                    rule.priority, rule.identifier, rule.rule)

        if rules:
            return blob
        else:
            return "No rules have been set yet."

    @command(command="addrule",
             params=[Any("rule")],
             access_level="moderator",
             description="Adds a rule")
    def rules_add_command(self, request, rule: str):
        sql = "INSERT INTO rules (rule, priority, indent) VALUES (?,?,?)"
        count = self.db.exec(sql, [rule, 0, 0])

        layoutlink = self.text.make_chatcmd("ruleslayout",
                                            "/tell <myname> ruleslayout")

        if count > 0:
            return "Successfully added the new rules entry. Use %s to see an editorial overview of rules." % layoutlink
        else:
            return "Failed to add the new rules entry (DB insertion error)."

    @command(command="remrule",
             params=[Int("rule_id")],
             access_level="moderator",
             description="Removes a rule")
    def rules_rem_command(self, request, rule_id):
        sql = "DELETE FROM rules WHERE id = ?"
        count = self.db.exec(sql, [rule_id])

        layoutlink = self.text.make_chatcmd("ruleslayout",
                                            "/tell <myname> ruleslayout")

        if count > 0:
            return "Successfully removed the rules entry. Use %s to see an editorial overview of rules." % layoutlink
        else:
            return "Failed to remove the new rules entry (DB insertion error)."

    @command(command="rulepinc",
             params=[Int("rule_id")],
             access_level="moderator",
             description="Changes the priority of the rule")
    def rules_pinc_command(self, request, rule_id):
        sql = "UPDATE rules  SET priority = (priority + 1) WHERE id = ?"
        count = self.db.exec(sql, [rule_id])

        layoutlink = self.text.make_chatcmd("ruleslayout",
                                            "/tell <myname> ruleslayout")

        if count > 0:
            return "Successfully changed the priority of rule entry %s. Use %s to see an editorial overview of rules." % (
                rule_id, layoutlink)
        else:
            return "Failed to change priority of the rule entry (DB update error)."

    @command(command="rulepdec",
             params=[Int("rule_id")],
             access_level="moderator",
             description="Changes the priority of the rule")
    def rules_pdec_command(self, request, rule_id):
        sql = "UPDATE rules SET priority = (priority - 1) WHERE id = ?"
        count = self.db.exec(sql, [rule_id])

        layoutlink = self.text.make_chatcmd("ruleslayout",
                                            "/tell <myname> ruleslayout")

        if count > 0:
            return "Successfully changed the priority of rule entry %s. Use %s to see an editorial overview of rules." % (
                rule_id, layoutlink)
        else:
            return "Failed to change priority of the rule entry (DB update error)."

    @command(command="ruleindinc",
             params=[Int("rule_id")],
             access_level="moderator",
             description="Changes the indent of the rule")
    def rules_indic_command(self, request, rule_id):
        sql = "UPDATE rules SET indent = (indent + 1) WHERE id = ?"
        count = self.db.exec(sql, [rule_id])

        layoutlink = self.text.make_chatcmd("ruleslayout",
                                            "/tell <myname> ruleslayout")

        if count > 0:
            return "Successfully changed the indent of rule entry %s. Use %s to see an editorial overview of rules." % (
                rule_id, layoutlink)
        else:
            return "Failed to change indent of the rule entry (DB update error)."

    @command(command="ruleinddec",
             params=[Int("rule_id")],
             access_level="moderator",
             description="Changes the indent of the rule")
    def rules_inddec_command(self, request, rule_id):
        sql = "UPDATE rules SET indent = (indent - 1) WHERE id = ?"
        count = self.db.exec(sql, [rule_id])

        layoutlink = self.text.make_chatcmd("ruleslayout",
                                            "/tell <myname> ruleslayout")

        if count > 0:
            return "Successfully changed the indent of rule entry %s. Use %s to see an editorial overview of rules." % (
                rule_id, layoutlink)
        else:
            return "Failed to change indent of the rule entry (DB update error)."

    @command(command="rulealteridentifier",
             params=[Int("rule_id"), Any("identifier")],
             access_level="moderator",
             description="Changes the identifier of the rule")
    def rules_alteridentifier_command(self, request, rule_id, word: str):
        sql = "UPDATE rules SET identifier ? WHERE id = ?"
        count = self.db.exec(sql, [identifier, rule_id])

        layoutlink = self.text.make_chatcmd("ruleslayout",
                                            "/tell <myname> ruleslayout")

        if count > 0:
            return "Successfully changed the identifier of rule entry %s. Use %s to see an editorial overview of rules." % (
                rule_id, layoutlink)
        else:
            return "Failed to change identifier of the rule entry (DB update error)."

    @command(command="ruleslayout",
             params=[],
             access_level="moderator",
             description="Displays the ruleslayout")
    def rules_layout_command(self, request):
        ruleslayout = self.get_rules_layout()
        self.bot.send_private_message(request.sender.char_id,
                                      ChatBlob("Ruleslayout", ruleslayout))

    def get_rules_layout(self):
        blob = ""
        sql = "SELECT * FROM rules ORDER BY priority, indent, identifier, rule ASC"
        rules = self.db.query(sql)

        admin_link = self.text.make_chatcmd("admin", "/tell <myname> admins")

        blob += "<header>:: Disclaimer :: <end>\n"
        blob += "The leaders of this bot are free to interpretate the rules in their own way.\n\n"
        blob += "If you feel like one of the leaders is abusing the status, feel free to message an %s.\n\n" % admin_link
        blob += "<header>:: Ruleslayout ::<end>\n"

        for rule in rules:
            entry = rule.rule
            priority = rule.priority
            indent = rule.indent
            identifier = rule.identifier

            if indent >= 0:

                incp = self.text.make_chatcmd(
                    "p+", "/tell <myname> rulepinc %s") % rule.id
                decp = self.text.make_chatcmd(
                    "p-", "/tell <myname> rulepdec %s") % rule.id
                inci = self.text.make_chatcmd(
                    "i+", "/tell <myname> ruleindinc %s") % rule.id
                deci = self.text.make_chatcmd(
                    "i-", "/tell <myname> ruleinddec %s") % rule.id

                blob += "%s%s <highlight>%s<end>" % (priority, identifier,
                                                     entry)
                blob += " (p: %s || i: %s || id: %s)" % (priority, indent,
                                                         rule.id)
                blob += " [%s] [%s] [%s] [%s]\n" % (incp, decp, inci, deci)

        return blob
Exemplo n.º 19
0
class AlienBioController:
    def __init__(self):
        self.ofab_armor_types = ["64", "295", "468", "935"]
        self.ofab_weapon_types = ["18", "34", "687", "812"]
        self.alien_armor_types = ["mutated", "pristine"]
        self.alien_weapon_types = [
            "1", "2", "3", "4", "5", "12", "13", "48", "76", "112", "240",
            "880", "992"
        ]

    def inject(self, registry):
        self.db = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.util = registry.get_instance("util")
        self.items_controller = registry.get_instance("items_controller")
        self.command_alias_service = registry.get_instance(
            "command_alias_service")

    def start(self):
        self.command_alias_service.add_alias("clump", "bio")

    @command(command="bio",
             params=[Item("bio_material")],
             access_level="all",
             description="Show info about Kyr'Ozch Bio-Material")
    def bio_command(self, request, item):
        high_id = item.high_id
        ql = item.ql

        if high_id == 247707 or high_id == 247708:
            bio_type = "1"
        elif high_id == 247709 or high_id == 247710:
            bio_type = "2"
        elif high_id == 247717 or high_id == 247718:
            bio_type = "3"
        elif high_id == 247711 or high_id == 247712:
            bio_type = "4"
        elif high_id == 247713 or high_id == 247714:
            bio_type = "5"
        elif high_id == 247715 or high_id == 247716:
            bio_type = "12"
        elif high_id == 247719 or high_id == 247720:
            bio_type = "13"
        elif high_id == 288699 or high_id == 288700:
            bio_type = "48"
        elif high_id == 247697 or high_id == 247698:
            bio_type = "76"
        elif high_id == 247699 or high_id == 247700:
            bio_type = "112"
        elif high_id == 247701 or high_id == 247702:
            bio_type = "240"
        elif high_id == 247703 or high_id == 247704:
            bio_type = "880"
        elif high_id == 247705 or high_id == 247706:
            bio_type = "992"
        elif high_id == 247102 or high_id == 247103:
            bio_type = "pristine"
        elif high_id == 247104 or high_id == 247105:
            bio_type = "mutated"
        elif high_id == 247764 or high_id == 254804:
            bio_type = "serum"
        else:
            bio_type = "unknown"

        bio_info = self.get_bio_info(bio_type, ql)
        if bio_info:
            return bio_info
        else:
            return "Bio-Material type unknown or not a bio-material."

    @command(command="bioinfo",
             params=[],
             access_level="all",
             description="Show list of Kyr'Ozch Bio-Material types")
    def bioinfo_list_command(self, request):
        blob = "<header2>OFAB Armor Types<end>\n"
        blob += self.get_type_blob(self.ofab_armor_types)

        blob += "\n<header2>OFAB Weapon Types<end>\n"
        blob += self.get_type_blob(self.ofab_weapon_types)

        blob += "\n<header2>AI Armor Types<end>\n"
        blob += self.get_type_blob(self.alien_armor_types)

        blob += "\n<header2>AI Weapon Types<end>\n"
        blob += self.get_type_blob(self.alien_weapon_types)

        blob += "\n<header2>Serum<end>\n"
        blob += self.get_type_blob(["serum"])

        return ChatBlob("Bio-Material Types", blob)

    def get_type_blob(self, bio_types):
        blob = ""
        for bio_type in bio_types:
            blob += self.text.make_chatcmd(
                bio_type, "/tell <myname> bioinfo %s" % bio_type) + "\n"
        return blob

    @command(command="bioinfo",
             params=[Any("bio_type"),
                     Int("ql", is_optional=True)],
             access_level="all",
             description="Show info about a bio-material type")
    def bioinfo_show_command(self, request, bio_type, ql):
        ql = ql or 300

        bio_info = self.get_bio_info(bio_type, ql)
        if bio_info:
            return bio_info
        else:
            return "Unknown bio-material type <highlight>%s<end>." % bio_type

    def get_bio_info(self, bio_type, ql):
        if bio_type in self.ofab_armor_types:
            return self.ofab_armor_bio(bio_type, ql)
        elif bio_type in self.ofab_weapon_types:
            return self.ofab_weapon_bio(bio_type, ql)
        elif bio_type in self.alien_armor_types:
            return self.alien_armor_bio(bio_type, ql)
        elif bio_type in self.alien_weapon_types:
            return self.alien_weapon_bio(bio_type, ql)
        elif bio_type == "serum":
            return self.serum_bio(ql)
        else:
            return None

    def ofab_armor_bio(self, bio_type, ql):
        name = "Kyr'Ozch Bio-Material - Type %s" % bio_type

        data = self.db.query("SELECT * FROM ofab_armor_type WHERE type = ?",
                             [bio_type])

        blob = self.display_item(name, ql) + "\n\n"
        blob += "<highlight>Upgrades Ofab Armor for:<end>\n"
        for row in data:
            blob += self.text.make_chatcmd(
                row.profession,
                "/tell <myname> ofabarmor %s" % row.profession) + "\n"

        return ChatBlob("%s (QL %d)" % (name, ql), blob)

    def ofab_weapon_bio(self, bio_type, ql):
        name = "Kyr'Ozch Bio-Material - Type %s" % bio_type

        data = self.db.query("SELECT * FROM ofab_weapons WHERE type = ?",
                             [bio_type])

        blob = self.display_item(name, ql) + "\n\n"
        blob += "<highlight>Upgrades Ofab Weapons for:<end>\n"
        for row in data:
            blob += self.text.make_chatcmd(
                "Ofab %s Mk 1" % row.name,
                "/tell <myname> ofabweapons %s" % row.name) + "\n"

        return ChatBlob("%s (QL %d)" % (name, ql), blob)

    def alien_armor_bio(self, bio_type, ql):
        min_ql = math.floor(ql * 0.8)
        if ql <= 240:
            max_ql = math.floor(ql / 0.8)
        else:
            max_ql = 300

        cl = math.floor(min_ql * 4.5)
        pharma = math.floor(ql * 6)
        nano_prog = math.floor(min_ql * 6)
        psyco = math.floor(ql * 6)
        max_psyco = math.floor(max_ql * 6)
        ts_bio = math.floor(ql * 4.5)
        if bio_type == "mutated":
            name = "Mutated Kyr'Ozch Bio-Material"
            chem = math.floor(ql * 7)
            chem_msg = "7 * QL"
            extra_info = "more tradeskill requirements then pristine"
        elif bio_type == "pristine":
            name = "Pristine Kyr'Ozch Bio-Material"
            chem = math.floor(ql * 4.5)
            chem_msg = "4.5 * QL"
            extra_info = "less tradeskill requirements then mutated"
        else:
            return None

        blob = self.display_item(name, ql) + "\n\n"
        blob += "It will take <highlight>%d EE & CL<end> (<highlight>4.5 * QL<end>) to analyze the Bio-Material.\n\n" % ts_bio

        blob += "Used to build Alien Armor\n\n"
        blob += "The following tradeskill amounts are required to make <highlight>QL %d<end>\n" % ql
        blob += "strong/arithmetic/enduring/spiritual/supple/observant armor:\n\n"
        blob += "Computer Literacy - <highlight>%d<end> (<highlight>4.5 * QL<end>)\n" % cl
        blob += "Chemistry - <highlight>%d<end> (<highlight>%s<end>) %s\n" % (
            chem, chem_msg, extra_info)
        blob += "Nano Programming - <highlight>%d<end> (<highlight>6 * QL<end>)\n" % nano_prog
        blob += "Pharma Tech - <highlight>%d<end> (<highlight>6 * QL<end>)\n" % pharma
        blob += "Psychology - <highlight>%d<end> (<highlight>6 * QL<end>)\n\n" % psyco
        blob += "Note: Tradeskill requirements are based off the lowest QL items needed throughout the entire process."

        blob += "\n\nFor Supple, Arithmetic, or Enduring:\n\n"
        blob += "When completed, the armor piece can have as low as <highlight>QL %d<end> combined into it, depending on available tradeskill options.\n\n" % min_ql
        blob += "Does not change QL's, therefore takes <highlight>%d Psychology<end> for available combinations.<end>\n\n" % psyco
        blob += "For Spiritual, Strong, or Observant:\n\n"
        blob += "When completed, the armor piece can combine up to <highlight>QL %d<end>, depending on available tradeskill options.\n\n" % max_ql
        blob += "Changes QL depending on targets QL. "
        blob += "The max combination is: (<highlight>QL %d<end>) (<highlight>%d Psychology<end> required for this combination)" % (
            max_ql, max_psyco)

        blob += "\n\n<yellow>Tradeskilling info added by Mdkdoc420 (RK2)<end>"

        return ChatBlob("%s (QL %d)" % (name, ql), blob)

    def alien_weapon_bio(self, bio_type, ql):
        name = "Kyr'Ozch Bio-Material - Type %s" % bio_type

        # Ensures that the maximum AI weapon that combines into doesn't go over QL 300 when the user presents a QL 271+ bio-material
        max_ai_type = math.floor(ql / 0.9)
        if max_ai_type > 300 or max_ai_type < 1:
            max_ai_type = 300

        ts_bio = math.floor(ql * 4.5)

        blob = self.display_item(name, ql) + "\n\n"
        blob += "It will take <highlight>%d<end> EE & CL (<highlight>4.5 * QL<end>) to analyze the Bio-Material.\n\n" % ts_bio

        row = self.db.query_single(
            "SELECT specials FROM alien_weapon_specials WHERE type = ?",
            [bio_type])
        blob += "<highlight>Adds %s to:<end>\n" % row.specials

        data = self.db.query("SELECT * FROM alien_weapons WHERE type = ?",
                             [bio_type])
        for row in data:
            blob += self.display_item(row.name, max_ai_type) + "\n"

        blob += self.get_weapon_info(max_ai_type)
        blob += "\n\n<yellow>Tradeskilling info added by Mdkdoc420<end>"

        return ChatBlob("%s (QL %d)" % (name, ql), blob)

    def serum_bio(self, ql):
        name = "Kyr'Ozch Viral Serum"
        item = self.display_item(name, ql)

        pharma_ts = math.floor(ql * 3.5)
        chem_me_ts = math.floor(ql * 4)
        ee_ts = math.floor(ql * 4.5)
        cl_ts = math.floor(ql * 5)
        ts_bio = math.floor(ql * 4.5)

        if pharma_ts < 400:
            pharma_ts = 400

        if chem_me_ts < 400:
            chem_me_ts = 400

        blob = item + "\n\n"
        blob += "It will take <highlight>%d EE & CL<end> (<highlight>4.5 * QL<end>) to analyze the Bio-Material.\n\n" % ts_bio

        blob += "Used to build city buildings\n\n"
        blob += "The following are the required skills throughout the process of making a building:\n\n"
        blob += "Quantum FT - <highlight>400<end> (<highlight>Static<end>)\n"
        blob += "Pharma Tech - <highlight>%d<end> (<highlight>3.5 * QL<end>) 400 is minimum requirement\n" % pharma_ts
        blob += "Chemistry - <highlight>%d<end> (<highlight>4 * QL<end>) 400 is minimum requirement\n" % chem_me_ts
        blob += "Mechanical Engineering - <highlight>%d<end> (<highlight>4 * QL<end>)\n" % chem_me_ts
        blob += "Electrical Engineering - <highlight>%d<end> (<highlight>4.5 * QL<end>)\n" % ee_ts
        blob += "Comp Liter - <highlight>%d<end> (<highlight>5 * QL<end>)" % cl_ts

        blob += "\n\n<yellow>Tradeskilling info added by Mdkdoc420 (RK2)<end>"

        return ChatBlob("%s (QL %d)" % (name, ql), blob)

    def get_weapon_info(self, ql):
        ts_wep = math.floor(ql * 6)
        text = "\n\n<highlight>QL %d<end> is the highest weapon this type will combine into." % ql
        if ql != 300:
            text += "\nNote: <highlight>The weapon can bump several QL's.<end>"

        text += "\n\nIt will take <highlight>%d<end> ME & WS (<highlight>6 * QL<end>) to combine with a <highlight>QL %d<end> Kyr'ozch Weapon." % (
            ts_wep, ql)

        return text

    def display_item(self, name, ql):
        return self.text.format_item(
            self.items_controller.find_by_name(name, ql), ql)
Exemplo n.º 20
0
class AlienBioController:
    def __init__(self):
        self.ofab_armor_types = ["64", "295", "468", "935"]
        self.ofab_weapon_types = ["18", "34", "687", "812"]
        self.alien_armor_types = ["mutated", "pristine"]
        self.alien_weapon_types = [
            "1", "2", "3", "4", "5", "12", "13", "48", "76", "112", "240",
            "880", "992"
        ]

    def inject(self, registry):
        self.db = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.util = registry.get_instance("util")
        self.items_controller = registry.get_instance("items_controller")
        self.command_alias_service = registry.get_instance(
            "command_alias_service")
        self.ts: TranslationService = registry.get_instance(
            "translation_service")
        self.getresp = self.ts.get_response

    def pre_start(self):
        self.db.load_sql_file(self.module_dir + "/" + "alien_weapons.sql")

    def start(self):
        self.command_alias_service.add_alias("clump", "bio")

    @command(command="bio",
             params=[Item("bio_material")],
             access_level="all",
             description="Show info about Kyr'Ozch Bio-Material")
    def bio_command(self, request, item):
        high_id = item.high_id
        ql = item.ql

        if high_id == 247707 or high_id == 247708:
            bio_type = "1"
        elif high_id == 247709 or high_id == 247710:
            bio_type = "2"
        elif high_id == 247717 or high_id == 247718:
            bio_type = "3"
        elif high_id == 247711 or high_id == 247712:
            bio_type = "4"
        elif high_id == 247713 or high_id == 247714:
            bio_type = "5"
        elif high_id == 247715 or high_id == 247716:
            bio_type = "12"
        elif high_id == 247719 or high_id == 247720:
            bio_type = "13"
        elif high_id == 288699 or high_id == 288700:
            bio_type = "48"
        elif high_id == 247697 or high_id == 247698:
            bio_type = "76"
        elif high_id == 247699 or high_id == 247700:
            bio_type = "112"
        elif high_id == 247701 or high_id == 247702:
            bio_type = "240"
        elif high_id == 247703 or high_id == 247704:
            bio_type = "880"
        elif high_id == 247705 or high_id == 247706:
            bio_type = "992"
        elif high_id == 247102 or high_id == 247103:
            bio_type = "pristine"
        elif high_id == 247104 or high_id == 247105:
            bio_type = "mutated"
        elif high_id == 247764 or high_id == 254804:
            bio_type = "serum"
        else:
            bio_type = "unknown"

        bio_info = self.get_bio_info(bio_type, ql)
        if bio_info:
            return bio_info
        else:
            return "Bio-Material type unknown or not a bio-material."

    @command(command="bioinfo",
             params=[],
             access_level="all",
             description="Show list of Kyr'Ozch Bio-Material types")
    def bioinfo_list_command(self, request):
        return ChatBlob(
            self.getresp("module/alien", "bioinfo_list_title"),
            self.getresp(
                "module/alien", "bioinfo_list", {
                    "ofab_armor": self.get_type_blob(self.ofab_armor_types),
                    "ofab_weap": self.get_type_blob(self.ofab_weapon_types),
                    "ai_armor": self.get_type_blob(self.alien_armor_types),
                    "ai_weap": self.get_type_blob(self.alien_weapon_types),
                    "serum": self.get_type_blob(["serum"]),
                }))

    def get_type_blob(self, bio_types):
        blob = ""
        for bio_type in bio_types:
            blob += self.text.make_tellcmd(bio_type,
                                           "bioinfo %s" % bio_type) + "\n"
        return blob

    @command(command="bioinfo",
             params=[Any("bio_type"),
                     Int("ql", is_optional=True)],
             access_level="all",
             description="Show info about a bio-material type")
    def bioinfo_show_command(self, request, bio_type, ql):
        ql = ql or 300

        bio_info = self.get_bio_info(bio_type, ql)
        if bio_info:
            return bio_info
        else:
            return self.getresp("module/alien", "bioinfo_unknown_type",
                                {"type": bio_type})

    def get_bio_info(self, bio_type, ql):
        if bio_type in self.ofab_armor_types:
            return self.ofab_armor_bio(bio_type, ql)
        elif bio_type in self.ofab_weapon_types:
            return self.ofab_weapon_bio(bio_type, ql)
        elif bio_type in self.alien_armor_types:
            return self.alien_armor_bio(bio_type, ql)
        elif bio_type in self.alien_weapon_types:
            return self.alien_weapon_bio(bio_type, ql)
        elif bio_type == "serum":
            return self.serum_bio(ql)
        else:
            return None

    def ofab_armor_bio(self, bio_type, ql):
        name = "Kyr'Ozch Bio-Material - Type %s" % bio_type

        data = self.db.query("SELECT * FROM ofab_armor_type WHERE type = ?",
                             [bio_type])
        item = self.items_controller.find_by_name(name, ql)
        upgrades = ""
        for row in data:
            upgrades += self.text.make_tellcmd(
                row.profession, "ofabarmor %s" % row.profession) + "\n"

        return ChatBlob(
            self.getresp("module/alien", "bioinfo_unknown_type", {
                "type": bio_type,
                "ql": ql
            }),
            self.getresp(
                "module/alien", "ofab_armor_bio", {
                    "type": bio_type,
                    **self.text.generate_item(item, ql), "upgrades": upgrades
                }))

    def ofab_weapon_bio(self, bio_type, ql):
        name = "Kyr'Ozch Bio-Material - Type %s" % bio_type

        data = self.db.query("SELECT * FROM ofab_weapons WHERE type = ?",
                             [bio_type])

        blob = self.display_item(name, ql) + "\n\n"
        blob += "<highlight>Upgrades Ofab Weapons for:</highlight>\n"
        for row in data:
            blob += self.text.make_tellcmd("Ofab %s Mk 1" % row.name,
                                           "ofabweapons %s" % row.name) + "\n"

        return ChatBlob("%s (QL %d)" % (name, ql), blob)

    def alien_armor_bio(self, bio_type, ql):
        min_ql = math.floor(ql * 0.8)
        if ql <= 240:
            max_ql = math.floor(ql / 0.8)
        else:
            max_ql = 300

        cl = math.floor(min_ql * 4.5)
        pharma = math.floor(ql * 6)
        nano_prog = math.floor(min_ql * 6)
        psyco = math.floor(ql * 6)
        max_psyco = math.floor(max_ql * 6)
        ts_bio = math.floor(ql * 4.5)
        if bio_type == "mutated":
            name = "Mutated Kyr'Ozch Bio-Material"
            chem = math.floor(ql * 7)
            chem_msg = "7 * QL"
            extra_info = self.getresp("module/alien",
                                      "alien_armor_bio_extra_info_mutated")
        elif bio_type == "pristine":
            name = "Pristine Kyr'Ozch Bio-Material"
            chem = math.floor(ql * 4.5)
            chem_msg = "4.5 * QL"
            extra_info = self.getresp("module/alien",
                                      "alien_armor_bio_extra_info_pristine")
        else:
            return None
        return ChatBlob(
            "%s (QL %d)" % (name, ql),
            self.getresp(
                "module/alien", "alien_armor_bio", {
                    "item": self.display_item(name, ql),
                    "ee_cl_req": ts_bio,
                    "ql": ql,
                    "cl_req": cl,
                    "chem_req": chem,
                    "chem_info": chem_msg,
                    "chem_extra_info": extra_info,
                    "nano_prog_req": nano_prog,
                    "pt_req": pharma,
                    "psyco_req": psyco,
                    "min_ql": min_ql,
                    "max_ql": max_ql,
                    "max_psyco": max_psyco
                }))

    def alien_weapon_bio(self, bio_type, ql):
        name = "Kyr'Ozch Bio-Material - Type %s" % bio_type

        # Ensures that the maximum AI weapon that combines into doesn't go over QL 300 when the user presents a QL 271+ bio-material
        max_ai_type = math.floor(ql / 0.9)
        if max_ai_type > 300 or max_ai_type < 1:
            max_ai_type = 300

        specials = self.db.query_single(
            "SELECT specials FROM alien_weapon_specials WHERE type = ?",
            [bio_type]).specials
        data = self.db.query("SELECT * FROM alien_weapons WHERE type = ?",
                             [bio_type])
        display_blob = ""
        for row in data:
            display_blob += self.display_item(row.name, max_ai_type) + "\n"

        return ChatBlob(
            "%s (QL %d)" % (name, ql),
            self.getresp(
                "module/alien", "alien_weapon_bio", {
                    "item_display": self.display_item(name, ql),
                    "ee_cl_req": math.floor(ql * 4.5),
                    "specials": specials,
                    "display_blob": display_blob,
                    "weapon_info": self.get_weapon_info(max_ai_type)
                }))

    def serum_bio(self, ql):
        name = "Kyr'Ozch Viral Serum"

        return ChatBlob(
            "%s (QL %d)" % (name, ql),
            self.getresp(
                "module/alien", "serum_bio", {
                    "item_display":
                    self.display_item(name, ql),
                    "ee_cl_req":
                    math.floor(ql * 4.5),
                    "pt_req":
                    (math.floor(ql *
                                3.5) if math.floor(ql * 3.5) > 400 else 400),
                    "chem_me_req":
                    (math.floor(ql * 4) if math.floor(ql * 4) > 400 else 400),
                    "cl_req":
                    math.floor(ql * 5)
                }))

    def get_weapon_info(self, ql):
        return self.getresp(
            "module/alien", "weapon_info", {
                "ql":
                ql,
                "bump": ("" if ql == 300 else self.getresp(
                    "module/alien", "weapon_bump")),
                "me_ws_req":
                math.floor(ql * 6)
            })

    def display_item(self, name, ql):
        return self.text.format_item(
            self.items_controller.find_by_name(name, ql), ql)
Exemplo n.º 21
0
class NanoController:
    def inject(self, registry):
        self.db = registry.get_instance("db")
        self.util = registry.get_instance("util")
        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("nl", "nanolines")
        self.command_alias_service.add_alias("nanoline", "nanolines")

    @command(command="nano",
             params=[Any("search"), NamedParameters(["page"])],
             access_level="all",
             description="Search for a nano")
    def nano_cmd(self, request, search, named_params):
        page = int(named_params.page or "1")
        page_size = 30
        offset = (page - 1) * page_size

        sql = "SELECT n1.lowid, n1.lowql, n1.name, n1.location, n1.profession, n3.id AS nanoline_id, n3.name AS nanoline_name " \
              "FROM nanos n1 " \
              "LEFT JOIN nanos_nanolines_ref n2 ON n1.lowid = n2.lowid " \
              "LEFT JOIN nanolines n3 ON n2.nanolines_id = n3.id " \
              "WHERE n1.name <EXTENDED_LIKE=0> ? " \
              "ORDER BY n1.profession, n3.name, n1.lowql DESC, n1.name ASC"
        data = self.db.query(sql, [search], extended_like=True)
        count = len(data)
        paged_data = data[offset:offset + page_size]

        blob = ""

        if count > page_size:
            if page > 1 and len(paged_data) > 0:
                blob += "   " + self.text.make_chatcmd(
                    "<< Page %d" %
                    (page - 1), self.get_chat_command(search, page - 1))
            if offset + page_size < len(data):
                blob += "   Page " + str(page)
                blob += "   " + self.text.make_chatcmd(
                    "Page %d >>" %
                    (page + 1), self.get_chat_command(search, page + 1))
            blob += "\n\n"

        current_nanoline = -1
        for row in paged_data:
            if current_nanoline != row.nanoline_id:
                if row.nanoline_name:
                    blob += "\n<header2>%s<end> - %s\n" % (
                        row.profession,
                        self.text.make_chatcmd(
                            row.nanoline_name,
                            "/tell <myname> nanolines %d" % row.nanoline_id))
                else:
                    blob += "\n<header2>Unknown/General<end>\n"
                current_nanoline = row.nanoline_id

            blob += "%s [%d] %s\n" % (self.text.make_item(
                row.lowid, row.lowid, row.lowql,
                row.name), row.lowql, row.location)
        blob += self.get_footer()

        return ChatBlob(
            "Nano Search Results for '%s' (%d - %d of %d)" %
            (search, offset + 1, min(offset + page_size, count), count), blob)

    @command(command="nanoloc",
             params=[],
             access_level="all",
             description="Show all nano locations")
    def nanoloc_list_cmd(self, request):
        data = self.db.query(
            "SELECT location, COUNT(location) AS cnt FROM nanos GROUP BY location ORDER BY location ASC"
        )

        blob = ""
        for row in data:
            blob += "%s (%d)\n" % (self.text.make_chatcmd(
                row.location,
                "/tell <myname> nanoloc %s" % row.location), row.cnt)
        blob += self.get_footer()

        return ChatBlob("Nano Locations", blob)

    @command(command="nanoloc",
             params=[Any("location")],
             access_level="all",
             description="Show nanos by location")
    def nanoloc_show_cmd(self, request, location):
        sql = "SELECT n1.lowid, n1.lowql, n1.name, n1.location, n3.profession " \
              "FROM nanos n1 LEFT JOIN nanos_nanolines_ref n2 ON n1.lowid = n2.lowid LEFT JOIN nanolines n3 ON n2.nanolines_id = n3.id " \
              "WHERE n1.location LIKE ? " \
              "ORDER BY n1.profession ASC, n1.name ASC"
        data = self.db.query(sql, [location])
        cnt = len(data)

        blob = ""
        for row in data:
            blob += "%s [%d] %s" % (self.text.make_item(
                row.lowid, row.lowid, row.lowql,
                row.name), row.lowql, row.location)
            if row.profession:
                blob += " - <highight>%s<end>" % row.profession
            blob += "\n"

        return ChatBlob("Nanos for Location '%s' (%d)" % (location, cnt), blob)

    @command(command="nanolines",
             params=[],
             access_level="all",
             description="Show nanos by nanoline")
    def nanolines_list_cmd(self, request):
        data = self.db.query(
            "SELECT DISTINCT profession FROM nanolines ORDER BY profession ASC"
        )

        blob = ""
        for row in data:
            blob += self.text.make_chatcmd(
                row.profession,
                "/tell <myname> nanolines %s" % row.profession) + "\n"
        blob += self.get_footer()

        return ChatBlob("Nanolines", blob)

    @command(command="nanolines",
             params=[Int("nanoline_id")],
             access_level="all",
             description="Show nanos by nanoline id")
    def nanolines_id_cmd(self, request, nanoline_id):
        nanoline = self.db.query_single("SELECT * FROM nanolines WHERE id = ?",
                                        [nanoline_id])

        if not nanoline:
            return "Could not find nanoline with ID <highlight>%d<end>." % nanoline_id

        data = self.db.query(
            "SELECT n1.lowid, n1.lowql, n1.name, n1.location "
            "FROM nanos n1 JOIN nanos_nanolines_ref n2 ON n1.lowid = n2.lowid "
            "WHERE n2.nanolines_id = ? "
            "ORDER BY n1.lowql DESC, n1.name ASC", [nanoline_id])

        blob = ""
        for row in data:
            blob += "%s [%d] %s\n" % (self.text.make_item(
                row.lowid, row.lowid, row.lowql,
                row.name), row.lowql, row.location)
        blob += self.get_footer()

        return ChatBlob("%s %s Nanos" % (nanoline.profession, nanoline.name),
                        blob)

    @command(command="nanolines",
             params=[Any("profession")],
             access_level="all",
             description="Show nanolines by profession")
    def nanolines_profession_cmd(self, request, prof_name):
        profession = self.util.get_profession(prof_name)
        if not profession:
            return "Could not find profession <highlight>%s<end>." % prof_name

        data = self.db.query(
            "SELECT * FROM nanolines WHERE profession = ? ORDER BY name ASC",
            [profession])

        blob = ""
        for row in data:
            blob += self.text.make_chatcmd(
                row.name, "/tell <myname> nanolines %d" % row.id) + "\n"
        blob += self.get_footer()

        return ChatBlob("%s Nanolines" % profession, blob)

    def get_footer(self):
        return "\n\nNanos DB provided by Saavick & Lucier"

    def get_chat_command(self, search, page):
        return "/tell <myname> nano %s --page=%d" % (search, page)
Exemplo n.º 22
0
class OfabArmorController:
    def inject(self, registry):
        self.db = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.util = registry.get_instance("util")

    @command(command="ofabarmor",
             params=[],
             access_level="all",
             description="Show ofab armor")
    def ofabarmor_list_command(self, request):
        data = self.db.query(
            "SELECT type, profession FROM ofab_armor_type ORDER BY profession ASC"
        )

        blob = ""
        for row in data:
            blob += "<pagebreak>%s - Type %d\n" % (self.text.make_chatcmd(
                row.profession,
                "/tell <myname> ofabarmor %s" % row.profession), row.type)

        return ChatBlob("Ofab Armor", blob)

    @command(command="ofabarmor",
             params=[
                 Int("ql", is_optional=True),
                 Any("profession"),
                 Int("ql", is_optional=True)
             ],
             access_level="all",
             description="Show info about ofab armor",
             extended_description=
             "QL is optional and can come before or after the profession")
    def ofabarmor_show_command(self, request, ql1, prof_name, ql2):
        profession = self.util.get_profession(prof_name)
        ql = ql1 or ql2 or 300

        if not profession:
            return "Could not find Ofab Armor for profession <highlight>%s<end>." % prof_name

        data = self.db.query(
            "SELECT * FROM ofab_armor o1 LEFT JOIN ofab_armor_cost o2 ON o1.slot = o2.slot WHERE o1.profession = ? AND o2.ql = ? ORDER BY upgrade ASC, name ASC",
            [profession, ql])
        if not data:
            return "Could not find Ofab Armor for QL <highlight>%d<end>." % ql

        upgrade_type = self.db.query_single(
            "SELECT type FROM ofab_armor_type WHERE profession = ?",
            [profession]).type

        type_ql = round(ql * 0.8)
        type_link = self.text.make_chatcmd(
            "Kyr'Ozch Bio-Material - Type %d" % upgrade_type,
            "/tell <myname> bioinfo %d %d" % (upgrade_type, type_ql))

        blob = "Upgrade with %s (minimum QL %d)\n\n" % (type_link, type_ql)

        cost_data = self.db.query(
            "SELECT DISTINCT ql FROM ofab_weapons_cost ORDER BY ql ASC")
        for row in cost_data:
            blob += self.text.make_chatcmd(
                row.ql, "/tell <myname> ofabarmor %s %d" %
                (profession, row.ql)) + " "
        blob += "\n\n"

        current_upgrade = ""
        total_vp = 0
        for row in data:
            if current_upgrade != row.upgrade:
                current_upgrade = row.upgrade
                blob += "\n"

            blob += "<pagebreak>" + self.text.make_item(
                row.lowid, row.highid, ql, row.name)

            if row.upgrade == 0 or row.upgrade == 3:
                blob += "  (<highlight>%d<end> VP)" % row.vp
                total_vp += row.vp
            blob += "\n"

        blob += "\nVP cost for full set: <highlight>%d<end>" % total_vp

        return ChatBlob("%s Ofab Armor (QL %d)" % (profession, ql), blob)
Exemplo n.º 23
0
class TowerController:
    def __init__(self):
        self.logger = Logger(__name__)

    def inject(self, registry):
        self.bot: Tyrbot = registry.get_instance("bot")
        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")
        self.setting_service = registry.get_instance("setting_service")
        self.playfield_controller: PlayfieldController = registry.get_instance(
            "playfield_controller")
        self.level_controller = registry.get_instance("level_controller")

    def pre_start(self):
        self.db.load_sql_file(self.module_dir + "/" + "tower_site.sql")
        self.db.load_sql_file(self.module_dir + "/" + "tower_site_bounds.sql")

    def start(self):
        self.command_alias_service.add_alias("hot", "lc open")

        self.setting_service.register(
            self.module_name, "tower_api_address",
            "https://tower-api.jkbff.com/v1/api/towers",
            TextSettingType(["https://tower-api.jkbff.com/v1/api/towers"]),
            "The address of the Tower API")
        self.setting_service.register(self.module_name,
                                      "tower_api_custom_headers", "",
                                      DictionarySettingType(),
                                      "Custom headers for the Tower API")

    @command(command="lc",
             params=[],
             access_level="guest",
             description=
             "See a list of playfields containing land control tower sites")
    def lc_list_cmd(self, request):
        data = self.db.query(
            "SELECT id, long_name, short_name FROM playfields WHERE id IN (SELECT DISTINCT playfield_id FROM tower_site) ORDER BY short_name"
        )

        blob = ""
        for row in data:
            blob += "[%d] %s <highlight>%s</highlight>\n" % (
                row.id,
                self.text.make_tellcmd(
                    row.long_name, "lc %s" % row.short_name), row.short_name)

        blob += "\n" + self.get_lc_blob_footer()

        return ChatBlob("Land Control Playfields (%d)" % len(data), blob)

    if FeatureFlags.USE_TOWER_API:

        @command(command="lc",
                 params=[Const("org"),
                         Any("org", is_optional=True)],
                 access_level="guest",
                 description="See a list of land control tower sites by org")
        def lc_org_cmd(self, request, _, org):
            params = list()
            params.append(("enabled", "true"))
            if not org:
                org = str(request.conn.org_id)
                if not org:
                    return "Bot does not belong to an org so an org name or org id must be specified."

            if org.isdigit():
                params.append(("org_id", org))
            else:
                for org_name_piece in org.split(" "):
                    params.append(("org_name", "%" + org_name_piece + "%"))

            data = self.lookup_tower_info(params).results

            t = int(time.time())
            grouped_data = self.util.group_by(data, lambda x:
                                              (x.org_id, x.org_name))
            blob = ""
            for k, v in grouped_data.items():
                v = sorted(v, key=lambda x: x.ql)

                org_blob = ""
                ct_types = []
                ql_total = 0
                for ct in v:
                    ct_types.append(self.get_ct_type(ct.ql))
                    ql_total += ct.ql
                    org_blob += self.format_site_info(ct, t) + "\n"

                blob += f"<pagebreak><header2>{k[1]} ({k[0]})</header2>"
                blob += " Types: <highlight>" + ", ".join(
                    ct_types
                ) + f"</highlight> Total CT QL: <highlight>{ql_total}</highlight>\n\n"
                blob += org_blob + "\n"

            return ChatBlob(f"Org Info for '{org}' ({len(data)})", blob)

        @command(
            command="lc",
            params=[
                Options([
                    "all", "open", "closed", "penalty", "unplanted", "disabled"
                ]),
                Options(["omni", "clan", "neutral", "all"], is_optional=True),
                Int("pvp_level", is_optional=True),
                Time("time", is_optional=True)
            ],
            access_level="guest",
            description=
            "See a list of land control tower sites by QL, faction, and open status",
            extended_description=
            "The time param only applies when the first param is either 'open' or 'closed'"
        )
        def lc_search_cmd(self, request, site_status, faction, pvp_level,
                          time_offset):
            t = int(time.time())
            relative_time = t + (time_offset or 0)

            min_ql = 1
            max_ql = 300
            if pvp_level:
                level_info = self.level_controller.get_level_info(pvp_level)
                if not level_info:
                    return "PVP level must be between 1 and 220."
                min_ql = level_info.pvp_min
                max_ql = level_info.pvp_max

            params = list()

            if site_status.lower() == "disabled":
                params.append(("enabled", "false"))
            else:
                params.append(("enabled", "true"))

            if min_ql > 1:
                params.append(("min_ql", min_ql))

            if max_ql < 300:
                params.append(("max_ql", max_ql))

            if faction and faction != "all":
                params.append(("faction", faction))

            if site_status.lower() == "open":
                params.append(("min_close_time", relative_time))
                params.append(("max_close_time", relative_time + (3600 * 6)))
            elif site_status.lower() == "closed":
                params.append(("min_close_time", relative_time + (3600 * 6)))
                params.append(("max_close_time", relative_time + (3600 * 24)))
            elif site_status.lower() == "penalty":
                params.append(("penalty", "true"))
            elif site_status.lower() == "unplanted":
                params.append(("planted", "false"))

            data = self.lookup_tower_info(params).results

            blob = ""
            for row in data:
                blob += "<pagebreak>" + self.format_site_info(row, t) + "\n"

            if blob:
                blob += self.get_lc_blob_footer()

            title = "Tower Info: %s" % site_status.capitalize()
            if min_ql > 1 or max_ql < 300:
                title += " QL %d - %d" % (min_ql, max_ql)
            if faction:
                title += " [%s]" % faction.capitalize()
            if time_offset:
                title += " in " + self.util.time_to_readable(time_offset)
            title += " (%d)" % len(data)

            return ChatBlob(title, blob)

    @command(command="lc",
             params=[Any("playfield"),
                     Int("site_number", is_optional=True)],
             access_level="guest",
             description=
             "See a list of land control tower sites in a particular playfield"
             )
    def lc_playfield_cmd(self, request, playfield_name, site_number):
        playfield = self.playfield_controller.get_playfield_by_name_or_id(
            playfield_name)
        if not playfield:
            return f"Could not find playfield <highlight>{playfield_name}</highlight>."

        data = self.get_tower_site_info(playfield.id, site_number)

        blob = ""
        t = int(time.time())
        for row in data:
            blob += "<pagebreak>" + self.format_site_info(row, t) + "\n"

        blob += self.get_lc_blob_footer()

        if site_number:
            title = "Tower Info: %s %d" % (playfield.long_name, site_number)
        else:
            title = "Tower Info: %s (%d)" % (playfield.long_name, len(data))

        return ChatBlob(title, blob)

    def format_site_info(self, row, t):
        blob = "<highlight>%s %d</highlight> (QL %d-%d) %s\n" % (
            row.playfield_short_name, row.site_number, row.min_ql, row.max_ql,
            row.site_name)

        if row.get("org_name"):
            current_day_time = t % 86400
            value = datetime.fromtimestamp(row.close_time, tz=pytz.UTC)
            current_status_time = row.close_time - current_day_time
            if current_status_time < 0:
                current_status_time += 86400

            status = ""
            if current_status_time <= 3600:
                status += "<red>5%%</red> (closes in %s)" % self.util.time_to_readable(
                    current_status_time)
            elif current_status_time <= (3600 * 6):
                status += "<orange>25%%</orange> (closes in %s)" % self.util.time_to_readable(
                    current_status_time)
            else:
                status += "<green>75%%</green> (opens in %s)" % self.util.time_to_readable(
                    current_status_time - (3600 * 6))

            if row.penalty_until > t:
                status += " <red>Penalty</red> (for %s)" % self.util.time_to_readable(
                    row.penalty_until - t)

            blob += "%s (%d) [%s] <highlight>QL %d</highlight> %s %s\n" % (
                row.org_name, row.org_id,
                self.text.get_formatted_faction(row.faction), row.ql,
                self.text.make_chatcmd(
                    "%dx%d" %
                    (row.x_coord, row.y_coord), "/waypoint %d %d %d" %
                    (row.x_coord, row.y_coord, row.playfield_id)),
                self.util.time_to_readable(t - row.created_at))
            blob += "Close Time: <highlight>%s</highlight> %s\n" % (
                value.strftime("%H:%M:%S %Z"), status)
        else:
            blob += "%s\n" % self.text.make_chatcmd(
                "%dx%d" % (row.x_coord, row.y_coord), "/waypoint %d %d %d" %
                (row.x_coord, row.y_coord, row.playfield_id))
            if not row.enabled:
                blob += "<red>Disabled</red>\n"

        return blob

    def get_tower_site_info(self, playfield_id, site_number):
        if FeatureFlags.USE_TOWER_API:
            params = list()
            params.append(("playfield_id", playfield_id))
            if site_number:
                params.append(("site_number", site_number))

            data = self.lookup_tower_info(params).results
        else:
            if site_number:
                data = self.db.query(
                    "SELECT t.*, p.short_name AS playfield_short_name, p.long_name AS playfield_long_name "
                    "FROM tower_site t JOIN playfields p ON t.playfield_id = p.id WHERE t.playfield_id = ? AND site_number = ?",
                    [playfield_id, site_number])
            else:
                data = self.db.query(
                    "SELECT t.*, p.short_name AS playfield_short_name, p.long_name AS playfield_long_name "
                    "FROM tower_site t JOIN playfields p ON t.playfield_id = p.id WHERE t.playfield_id = ?",
                    [playfield_id])

        return data

    def lookup_tower_info(self, params):
        url = self.setting_service.get("tower_api_address").get_value()

        headers = self.setting_service.get(
            "tower_api_custom_headers").get_value() or {}
        headers.update({"User-Agent": f"Tyrbot {self.bot.version}"})
        r = requests.get(url, params, headers=headers, timeout=5)
        result = DictObject(r.json())

        return result

    def get_lc_blob_footer(self):
        return "Thanks to Draex and Unk for providing the tower information. And a special thanks to Trey."

    def get_ct_type(self, ql):
        if ql < 34:
            return "I"
        elif ql < 82:
            return "II"
        elif ql < 129:
            return "III"
        elif ql < 177:
            return "IV"
        elif ql < 201:
            return "V"
        elif ql < 226:
            return "VI"
        else:
            return "VII"
Exemplo n.º 24
0
class ImplantController:
    def __init__(self):
        self.grades = ["shiny", "bright", "faded"]

        self.normal_ability_req = {1: 6, 200: 404, 201: 426, 300: 1095}
        self.normal_treatment_req = {1: 11, 200: 951, 201: 1001, 300: 2051}

        self.jobe_ability_req = {1: 6, 200: 464, 201: 476, 300: 1231}
        self.jobe_treatment_req = {1: 11, 200: 1005, 201: 1001, 300: 2051}

        self.ability_shiny_bonus = {1: 5, 200: 55, 201: 55, 300: 73}
        self.ability_bright_bonus = {1: 3, 200: 33, 201: 33, 300: 44}
        self.ability_faded_bonus = {1: 2, 200: 22, 201: 22, 300: 29}

        self.skill_shiny_bonus = {1: 6, 200: 105, 201: 106, 300: 141}
        self.skill_bright_bonus = {1: 3, 200: 63, 201: 63, 300: 85}
        self.skill_faded_bonus = {1: 2, 200: 42, 201: 42, 300: 57}

        self.normal_build_shiny = {1: 4, 200: 800, 201: 994, 300: 1575}
        self.normal_build_bright = {1: 3, 200: 600, 201: 753, 300: 1125}
        self.normal_build_faded = {1: 2, 200: 400, 201: 552, 300: 825}

        self.jobe_build_shiny = {1: 6, 200: 1250, 201: 1356, 300: 2025}
        self.jobe_build_bright = {1: 4, 200: 950, 201: 1055, 300: 1575}
        self.jobe_build_faded = {1: 3, 200: 650, 201: 753, 300: 1125}

        self.clean_np = {1: 1, 200: 200}
        self.clean_be = {1: 4, 200: 950}

    def inject(self, registry):
        self.db = registry.get_instance("db")
        self.util = registry.get_instance("util")
        self.text = registry.get_instance("text")
        self.command_alias_service = registry.get_instance(
            "command_alias_service")

    def pre_start(self):
        self.db.load_sql_file(self.module_dir + "/sql/" + "Ability.sql")
        self.db.load_sql_file(self.module_dir + "/sql/" + "Cluster.sql")
        self.db.load_sql_file(self.module_dir + "/sql/" +
                              "ClusterImplantMap.sql")
        self.db.load_sql_file(self.module_dir + "/sql/" + "ClusterType.sql")
        self.db.load_sql_file(self.module_dir + "/sql/" +
                              "EffectTypeMatrix.sql")
        self.db.load_sql_file(self.module_dir + "/sql/" + "EffectValue.sql")
        self.db.load_sql_file(self.module_dir + "/sql/" + "ImplantMatrix.sql")
        self.db.load_sql_file(self.module_dir + "/sql/" + "ImplantType.sql")
        self.db.load_sql_file(self.module_dir + "/sql/" + "Profession.sql")
        self.db.load_sql_file(self.module_dir + "/sql/" + "Symbiant.sql")
        self.db.load_sql_file(self.module_dir + "/sql/" +
                              "SymbiantAbilityMatrix.sql")
        self.db.load_sql_file(self.module_dir + "/sql/" +
                              "SymbiantClusterMatrix.sql")
        self.db.load_sql_file(self.module_dir + "/sql/" +
                              "SymbiantProfessionMatrix.sql")

        self.db.load_sql_file(self.module_dir + "/sql/" +
                              "implant_requirements.sql")

    def start(self):
        self.command_alias_service.add_alias("implants", "implant")

    @command(command="implant",
             params=[Int("ql")],
             access_level="all",
             description="Shows information about an implant at given QL")
    def implant_cmd(self, request, ql):
        if ql > 300 or ql < 1:
            return "Implant QL must be between <highlight>1</highlight> and <highlight>300</highlight>."

        implant = self.get_implant_by_ql(ql)
        blob = self.format_implant(implant)

        return ChatBlob(
            f"Implant QL {implant.ql} ({implant.ability} Ability, {implant.treatment} Treatment)",
            blob)

    @command(
        command="implant",
        params=[Int("ability"), Int("treatment")],
        access_level="all",
        description="Shows highest QL implant for a given ability and treatment"
    )
    def implant_requirement_cmd(self, request, ability, treatment):
        implant = self.get_implant_by_requirements(ability, treatment)
        if not implant:
            return "You do not have enough ability or treatment to wear an implant."

        blob = self.format_implant(implant)

        return ChatBlob(
            f"Implant QL {implant.ql} ({implant.ability} Ability, {implant.treatment} Treatment)",
            blob)

    def get_implant_by_requirements(self, ability, treatment):
        row = self.db.query_single(
            "SELECT ql FROM implant_requirement WHERE ability <= ? AND treatment <= ? ORDER BY ql DESC LIMIT 1",
            [ability, treatment])

        if row:
            return self.get_implant_by_ql(row.ql)
        else:
            return None

    def format_implant(self, implant):
        blob = "<header2>Requirements to Wear</header2>\n"
        blob += "<highlight>%d</highlight> Treatment\n" % implant.treatment
        blob += "<highlight>%d</highlight> Ability\n" % implant.ability

        blob += "\n<header2>Ability Cluster Bonuses</header2>\n"
        blob += "<highlight>%d</highlight> Shiny (%d - %d)\n" % (
            implant.ability_shiny, implant.ability_shiny_min,
            implant.ability_shiny_max)
        blob += "<highlight>%d</highlight> Bright (%d - %d)\n" % (
            implant.ability_bright, implant.ability_bright_min,
            implant.ability_bright_max)
        blob += "<highlight>%d</highlight> Faded (%d - %d)\n" % (
            implant.ability_faded, implant.ability_faded_min,
            implant.ability_faded_max)

        blob += "\n<header2>Skill Cluster Bonuses</header2>\n"
        blob += "<highlight>%d</highlight> Shiny (%d - %d)\n" % (
            implant.skill_shiny, implant.skill_shiny_min,
            implant.skill_shiny_max)
        blob += "<highlight>%d</highlight> Bright (%d - %d)\n" % (
            implant.skill_bright, implant.skill_bright_min,
            implant.skill_bright_max)
        blob += "<highlight>%d</highlight> Faded (%d - %d)\n" % (
            implant.skill_faded, implant.skill_faded_min,
            implant.skill_faded_max)

        if implant.ql <= 200:
            blob += "\n<header2>Requirements to Clean</header2>\n"
            blob += "<highlight>%d</highlight> Break&Entry\n" % implant.clean_break_and_entry
            blob += "<highlight>%d</highlight> NanoProgramming\n" % implant.clean_nano_programming
        else:
            blob += "\nRefined implants cannot be cleaned\n"

        blob += "\n<header2>Max Requirements to Build</header2> (actual requirements may be lower)\n"
        blob += "<highlight>%d</highlight> NanoProgramming for Shiny\n" % implant.build_shiny
        blob += "<highlight>%d</highlight> NanoProgramming for Bright\n" % implant.build_bright
        blob += "<highlight>%d</highlight> NanoProgramming for Faded\n" % implant.build_faded

        blob += "\n<header2>Min Cluster QL</header2>\n"
        blob += "<highlight>%d</highlight> Shiny\n" % implant.minimum_cluster_shiny
        blob += "<highlight>%d</highlight> Bright\n" % implant.minimum_cluster_bright
        blob += "<highlight>%d</highlight> Faded\n" % implant.minimum_cluster_faded

        if implant.ql >= 99:
            blob += "\n<header2>Requirements to Wear Jobe Implants</header2>\n"
            blob += "<highlight>%d</highlight> Treatment\n" % implant.jobe_treatment
            blob += "<highlight>%d</highlight> Ability\n" % implant.jobe_ability

            blob += "\n<header2>Max Requirements to Build Jobe Implants</header2> (actual requirements may be lower)\n"
            blob += "<highlight>%d</highlight> NanoProgramming for Shiny\n" % implant.jobe_build_shiny
            blob += "<highlight>%d</highlight> NanoProgramming for Bright\n" % implant.jobe_build_bright
            blob += "<highlight>%d</highlight> NanoProgramming for Faded\n" % implant.jobe_build_faded

            blob += "\nJobe implants cannot be cleaned\n"

        blob += "\n\nBased on the !impql command written for %s by <highlight>Lucier</highlight>" % self.text.make_chatcmd(
            "Ttst", "/tell ttst help")

        return blob

    def get_implant_by_ql(self, ql):
        implant = DictObject({})

        implant.ql = ql

        implant.treatment = int(
            self.util.interpolate_value(ql, self.normal_treatment_req))
        implant.ability = int(
            self.util.interpolate_value(ql, self.normal_ability_req))

        implant.jobe_treatment = self.util.interpolate_value(
            ql, self.jobe_treatment_req)
        implant.jobe_ability = self.util.interpolate_value(
            ql, self.jobe_ability_req)

        implant.ability_shiny = self.util.interpolate_value(
            ql, self.ability_shiny_bonus)
        implant.ability_shiny_min, implant.ability_shiny_max = self.get_range(
            ql, implant.ability_shiny, self.ability_shiny_bonus)
        implant.ability_bright = self.util.interpolate_value(
            ql, self.ability_bright_bonus)
        implant.ability_bright_min, implant.ability_bright_max = self.get_range(
            ql, implant.ability_bright, self.ability_bright_bonus)
        implant.ability_faded = self.util.interpolate_value(
            ql, self.ability_faded_bonus)
        implant.ability_faded_min, implant.ability_faded_max = self.get_range(
            ql, implant.ability_faded, self.ability_faded_bonus)

        implant.skill_shiny = self.util.interpolate_value(
            ql, self.skill_shiny_bonus)
        implant.skill_shiny_min, implant.skill_shiny_max = self.get_range(
            ql, implant.skill_shiny, self.skill_shiny_bonus)
        implant.skill_bright = self.util.interpolate_value(
            ql, self.skill_bright_bonus)
        implant.skill_bright_min, implant.skill_bright_max = self.get_range(
            ql, implant.skill_bright, self.skill_bright_bonus)
        implant.skill_faded = self.util.interpolate_value(
            ql, self.skill_faded_bonus)
        implant.skill_faded_min, implant.skill_faded_max = self.get_range(
            ql, implant.skill_faded, self.skill_faded_bonus)

        implant.clean_break_and_entry = self.util.interpolate_value(
            ql, self.clean_be)
        implant.clean_nano_programming = self.util.interpolate_value(
            ql, self.clean_np)

        implant.build_shiny = self.util.interpolate_value(
            ql, self.normal_build_shiny)
        implant.build_bright = self.util.interpolate_value(
            ql, self.normal_build_bright)
        implant.build_faded = self.util.interpolate_value(
            ql, self.normal_build_faded)

        implant.jobe_build_shiny = self.util.interpolate_value(
            ql, self.jobe_build_shiny)
        implant.jobe_build_bright = self.util.interpolate_value(
            ql, self.jobe_build_bright)
        implant.jobe_build_faded = self.util.interpolate_value(
            ql, self.jobe_build_faded)

        if ql >= 201:
            implant.minimum_cluster_shiny = max(201, math.floor(ql * 0.86))
            implant.minimum_cluster_bright = max(201, math.floor(ql * 0.84))
            implant.minimum_cluster_faded = max(201, math.floor(ql * 0.82))
        else:
            implant.minimum_cluster_shiny = math.floor(ql * 0.86)
            implant.minimum_cluster_bright = math.floor(ql * 0.84)
            implant.minimum_cluster_faded = math.floor(ql * 0.82)

        return implant

    def get_range(self, ql, value, interpolation):
        min_ql = ql
        max_ql = ql

        while self.util.interpolate_value(min_ql - 1, interpolation) == value:
            min_ql -= 1

        while self.util.interpolate_value(max_ql + 1, interpolation) == value:
            max_ql += 1

        return [min_ql, max_ql]
Exemplo n.º 25
0
class CloakController:
    MESSAGE_SOURCE = "cloak_reminder"
    CLOAK_EVENT = "cloak"

    CLOAK_STATUS_OFF = "off"
    CLOAK_STATUS_ON = "on"
    CLOAK_STATUS_MANUAL = "on*"

    def inject(self, registry):
        self.bot = registry.get_instance("bot")
        self.db = registry.get_instance("db")
        self.util = registry.get_instance("util")
        self.text = registry.get_instance("text")
        self.character_service = registry.get_instance("character_service")
        self.command_alias_service = registry.get_instance("command_alias_service")
        self.timer_controller = registry.get_instance("timer_controller", is_optional=True)
        self.event_service = registry.get_instance("event_service")
        self.access_service = registry.get_instance("access_service")
        self.message_hub_service = registry.get_instance("message_hub_service")

    def pre_start(self):
        self.bot.register_packet_handler(PublicChannelMessage.id, self.handle_public_message)
        self.event_service.register_event_type(self.CLOAK_EVENT)
        self.message_hub_service.register_message_source(self.MESSAGE_SOURCE)

    def start(self):
        self.db.exec("CREATE TABLE IF NOT EXISTS cloak_status (char_id INT NOT NULL, action VARCHAR(10) NOT NULL, created_at INT NOT NULL, org_id INT NOT NULL)")
        self.command_alias_service.add_alias("city", "cloak")

    @command(command="cloak", params=[Const("history"), Int("org_id")], access_level="org_member",
             description="Shows the cloak history")
    def cloak_history_command(self, request, _, org_id):
        data = self.db.query("SELECT c.*, p.name FROM cloak_status c LEFT JOIN player p ON c.char_id = p.char_id "
                             "WHERE c.org_id = ? ORDER BY created_at DESC LIMIT 20", [org_id])

        blob = ""
        for row in data:
            action = self.get_cloak_status_display(row.action)
            blob += "%s turned the device %s at %s.\n" % (row.name, action, self.util.format_datetime(row.created_at))

        conn = self.bot.get_conn_by_org_id(org_id)
        org_name = conn.get_org_name()
        return ChatBlob(f"Cloak History for {org_name}", blob)

    @command(command="cloak", params=[NamedFlagParameters(["all"])], access_level="org_member",
             description="Shows the cloak status")
    def cloak_command(self, request, flag_params):
        t = int(time.time())

        if flag_params.all:
            blob = ""
            for _id, conn in self.bot.get_conns(lambda x: x.is_main and x.org_id):
                row = self.db.query_single("SELECT c.char_id, c.action, c.created_at, p.name FROM cloak_status c LEFT JOIN player p ON c.char_id = p.char_id "
                                           "WHERE c.org_id = ? ORDER BY created_at DESC LIMIT 1", [conn.org_id])

                org_name = conn.get_org_name()
                if row:
                    action = self.get_cloak_status_display(row.action)
                    time_str = self.util.time_to_readable(t - row.created_at)
                    history_link = self.text.make_tellcmd("History", f"cloak history {conn.org_id}")
                    blob += f"{org_name} - {action} [{time_str} ago] {history_link}\n"
                else:
                    blob += f"{org_name} - Unknown\n"

            title = "Cloak Status"

            return ChatBlob(title, blob)
        else:
            conn = request.conn
            if not conn.org_id:
                return "This bot is not a member of an org."

            row = self.db.query_single("SELECT c.char_id, c.action, c.created_at, p.name FROM cloak_status c LEFT JOIN player p ON c.char_id = p.char_id "
                                       "WHERE c.org_id = ? ORDER BY created_at DESC LIMIT 1", [conn.org_id])

            org_name = conn.get_org_name()
            if row:
                action = self.get_cloak_status_display(row.action)
                time_str = self.util.time_to_readable(t - row.created_at)
                return f"{org_name} - {action} [{time_str} ago]"
            else:
                return f"{org_name} - Unknown cloak status"

    @command(command="cloak", params=[Options(["raise", "on"]), Int("org_id", is_optional=True)], access_level="org_member",
             description="Manually raises the cloak status on the bot")
    def cloak_raise_command(self, request, _, org_id):
        org_id = org_id or request.conn.org_id

        if not org_id:
            return "This bot is not a member of an org."

        row = self.db.query_single("SELECT action FROM cloak_status WHERE org_id = ?", [org_id])
        if row and (row.action == self.CLOAK_STATUS_ON or row.action == self.CLOAK_STATUS_MANUAL):
            return "The cloaking device is already <green>enabled</green>."

        self.db.exec("INSERT INTO cloak_status (char_id, action, created_at, org_id) VALUES (?, ?, ?, ?)",
                     [request.sender.char_id, self.CLOAK_STATUS_MANUAL, int(time.time()), org_id])
        return "The cloaking device has been set to enabled in the bot (you must still enable the cloak if it is disabled)."

    @event(event_type=CLOAK_EVENT, description="Record when the city cloak is turned off and on", is_system=True)
    def city_cloak_event(self, event_type, event_data):
        self.db.exec("INSERT INTO cloak_status (char_id, action, created_at, org_id) VALUES (?, ?, ?, ?)",
                     [event_data.char_id, event_data.action, int(time.time()), event_data.conn.org_id])

    @timerevent(budatime="15m", description="Reminds the players when cloak can be raised")
    def cloak_reminder_event(self, event_type, event_data):
        messages = []
        for _id, conn in self.bot.get_conns(lambda x: x.is_main and x.org_id):
            row = self.db.query_single("SELECT c.*, p.name FROM cloak_status c LEFT JOIN player p ON c.char_id = p.char_id "
                                       "WHERE c.org_id = ? ORDER BY created_at DESC LIMIT 1", [conn.org_id])
            if row:
                one_hour = 3600
                t = int(time.time())
                time_until_change = row.created_at + one_hour - t
                if row.action == self.CLOAK_STATUS_OFF and 0 >= time_until_change > (one_hour * 6 * -1):
                    time_str = self.util.time_to_readable(t - row.created_at)
                    org_name = conn.get_org_name()
                    messages.append(f"The cloaking device for org <highlight>{org_name}</highlight> is <orange>disabled</orange> but can be enabled. "
                                    f"<highlight>{row.name}</highlight> disabled it {time_str} ago.")

        if messages:
            self.message_hub_service.send_message(self.MESSAGE_SOURCE, None, None, "\n".join(messages))

    @event(event_type=CLOAK_EVENT, description="Set a timer for when cloak can be raised and lowered")
    def city_cloak_timer_event(self, event_type, event_data):
        if event_data.action == self.CLOAK_STATUS_OFF:
            timer_name = f"Raise City Cloak ({event_data.conn.get_org_name()})"
        elif event_data.action == self.CLOAK_STATUS_ON:
            timer_name = f"Lower City Cloak ({event_data.conn.get_org_name()})"
        else:
            raise Exception(f"Unknown cloak action '{event_data.action}'")

        timer_name = self.timer_controller.get_timer_name(timer_name)

        self.timer_controller.add_timer(timer_name, event_data.char_id, PublicChannelService.ORG_CHANNEL_COMMAND, int(time.time()), 3600)

    def handle_public_message(self, conn: Conn, packet: PublicChannelMessage):
        if not conn.is_main:
            return

        ext_msg = packet.extended_message
        if ext_msg and ext_msg.category_id == 1001 and ext_msg.instance_id == 1:
            char_name = ext_msg.params[0]
            char_id = self.character_service.resolve_char_to_id(char_name)
            action = ext_msg.params[1]
            self.event_service.fire_event(self.CLOAK_EVENT, DictObject({"char_id": char_id, "name": char_name, "action": action, "conn": conn}))

    def get_cloak_status_display(self, status):
        if status == self.CLOAK_STATUS_ON:
            return "<green>on</green>"
        elif status == self.CLOAK_STATUS_MANUAL:
            return "<green>on*</green>"
        elif status == self.CLOAK_STATUS_OFF:
            return "<orange>off</orange>"
        else:
            return "<highlight>Unknown</highlight>"
Exemplo n.º 26
0
class PointsController:
    def __init__(self):
        pass

    def inject(self, registry):
        self.bot = registry.get_instance("bot")
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.character_service: CharacterService = registry.get_instance("character_service")
        self.util: Util = registry.get_instance("util")
        self.setting_service: SettingService = registry.get_instance("setting_service")
        self.alts_service: AltsService = registry.get_instance("alts_service")

    def start(self):
        self.db.exec("CREATE TABLE IF NOT EXISTS points (char_id BIGINT PRIMARY KEY, points INT DEFAULT 0, created_at INT NOT NULL, "
                     "disabled SMALLINT DEFAULT 0)")
        self.db.exec("CREATE TABLE IF NOT EXISTS points_log (log_id INT PRIMARY KEY, char_id BIGINT NOT NULL, audit INT NOT NULL, "
                     "leader_id BIGINT NOT NULL, reason VARCHAR(255), created_at INT NOT NULL)")
        self.db.exec("CREATE TABLE IF NOT EXISTS points_presets (preset_id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50) NOT NULL, "
                     "points INT DEFAULT 1, UNIQUE(name))")

        if self.db.query_single("SELECT COUNT(*) AS count FROM points_presets").count < 1:
            # Populate with pre-made presets if empty
            presets = ["s13", "s28", "s35", "s42", "zodiac", "zod",
                       "tnh", "beast", "12m", "tara", "pvp", "towers",
                       "wipe", "clanwipe", "clan", "omniwipe", "omni",
                       "bonus", "early"]
            sql = "INSERT INTO points_presets (name) VALUES (?)"
            for preset in presets:
                self.db.exec(sql, [preset])

    @command(command="account", params=[Const("create"), Character("char")], access_level="moderator",
             description="Create a new account for given character name", sub_command="modify")
    def bank_create_cmd(self, request, _, char: SenderObj):
        alts_info = self.alts_service.get_alts(char.char_id)

        for alt in alts_info:
            sql = "SELECT char_id, disabled FROM points WHERE char_id = ? LIMIT 1"
            row = self.db.query_single(sql, [alt.char_id])

            if row:
                was_disabled = False

                if row.disabled == 1:
                    if self.db.exec("UPDATE points SET disabled = 0 WHERE char_id = ?", [alt.char_id]):
                        was_disabled = True

                if alt.char_id == char.char_id:
                    if was_disabled:
                        self.add_log_entry(alt.char_id, request.sender.char_id, "Account was re-enabled by %s" % request.sender.name)
                        return "<highlight>%s</highlight>'s account has been re-enabled." % char.name
                    else:
                        return "<highlight>%s</highlight> already has an account." % char.name
                else:
                    if was_disabled:
                        self.add_log_entry(alt.char_id, request.sender.char_id, "Account was re-enabled by %s" % request.sender.name)
                        return "<highlight>%s</highlight>'s (%s) account has been re-enabled." % (char.name, alt.name)
                    else:
                        return "<highlight>%s</highlight> (%s) already has an account." % (char.name, alt.name)

        main_info = alts_info[0]
        changed_to_main = main_info.char_id == char.char_id

        self.create_account(main_info.char_id, request.sender)

        name_reference = "%s (%s)" % (char.name, main_info.name) if changed_to_main else char.name
        return "A new account has been created for <highlight>%s</highlight>." % name_reference

    @command(command="account", params=[Const("close"), Character("char")], access_level="moderator",
             description="Close the account for given character name", sub_command="modify")
    def close_account_cmd(self, request, _, char: SenderObj):
        main = self.alts_service.get_main(char.char_id)

        sql = "UPDATE points SET disabled = 1 WHERE char_id = ?"
        if self.db.exec(sql, [main.char_id]) > 0:
            reason = f"Account was closed by {request.sender.name}"
            self.add_log_entry(main.char_id, request.sender.char_id, reason)
            name_reference = "%s (%s)" % (char.name, main.name) if main.char_id != char.char_id else char.name
            return f"<highlight>{name_reference}</highlight> has had their account disabled. Logs have been preserved."
        else:
            return "<highlight>%s</highlight> does not have an open account." % char.name

    @command(command="account", params=[Const("history"), Int("log_id")], access_level="moderator",
             description="Look up specific account history record", sub_command="modify")
    def account_history_cmd(self, request, _, log_id: int):
        log_entry = self.db.query_single("SELECT log_id, char_id, audit, leader_id, reason, created_at FROM points_log WHERE log_id = ?", [log_id])

        if not log_entry:
            return "No account history record with given ID <highlight>%d</highlight>." % log_id

        char_name = self.character_service.resolve_char_to_name(log_entry.char_id)
        leader_name = self.character_service.resolve_char_to_name(log_entry.leader_id)

        blob = f"ID: <highlight>{log_entry.log_id}</highlight>\n"
        blob += f"Account: <highlight>{char_name}</highlight>\n"
        blob += f"Action by: <highlight>{leader_name}</highlight>\n"
        blob += "Type: <highlight>%s</highlight>\n" % ("Management" if log_entry.audit == 0 else "Altering of points")
        blob += f"Reason: <highlight>{log_entry.reason}</highlight>\n"
        blob += f"Audit: <highlight>{log_entry.audit}</highlight>\n"
        action_links = None
        if log_entry.audit == 0:
            if "closed" in log_entry.reason:
                action_links = self.text.make_tellcmd("Open the account", "account create %s" % char_name)
            elif "re-enabled" in log_entry.reason:
                action_links = self.text.make_tellcmd("Close the account", "account close %s" % char_name)
        else:
            reason = f"Points from event ({log_id}) have been retracted"
            if log_entry.audit < 0:
                action_links = self.text.make_tellcmd("Retract", f"account add {char_name} {-log_entry.audit} {reason}")
            else:
                action_links = self.text.make_tellcmd("Retract", f"account rem {char_name} {log_entry.audit} {reason}")

        blob += "Actions available: [%s]\n" % (action_links if action_links is not None else "No actions available")

        return ChatBlob(f"Account History Record ({log_id})", blob)

    @command(command="account", params=[Const("add"), Character("char"), Int("amount"), Any("reason")], access_level="moderator",
             description="Add points to an account", sub_command="modify")
    def account_add_cmd(self, request, _, char: SenderObj, amount: int, reason: str):
        main = self.alts_service.get_main(char.char_id)
        row = self.get_account(main.char_id, request.conn)

        if not row:
            return f"<highlight>{char.name}</highlight> does not have an account."

        if row.disabled == 1:
            return f"Account for <highlight>{char.name}</highlight> is disabled and cannot be altered."

        self.alter_points(main.char_id, request.sender.char_id, reason, amount)

        return f"<highlight>{char.name}</highlight> has had <highlight>{amount}</highlight> points added to their account."

    @command(command="account", params=[Options(["rem", "remove"]), Character("char"), Int("amount"), Any("reason")], access_level="moderator",
             description="Remove points from an account", sub_command="modify")
    def account_remove_cmd(self, request, _, char: SenderObj, amount: int, reason: str):
        main = self.alts_service.get_main(char.char_id)
        row = self.get_account(main.char_id, request.conn)

        if not row:
            return f"<highlight>{char.name}</highlight> does not have an account."

        if row.disabled == 1:
            return f"Account for <highlight>{char.name}</highlight> is disabled and cannot be altered."

        if amount > row.points:
            return f"<highlight>{char.name}</highlight> only has <highlight>{row.points}</highlight> points."

        self.alter_points(main.char_id, request.sender.char_id, reason, -amount)

        return f"<highlight>{char.name}</highlight> has had <highlight>{amount}</highlight> points removed from their account."

    @command(command="account", params=[NamedParameters(["page"])], access_level="all",
             description="Look up your account")
    def account_self_cmd(self, request, named_params):
        return self.get_account_display(request.sender, named_params.page)

    @command(command="account", params=[Character("char"), NamedParameters(["page"])], access_level="moderator",
             description="Look up account of another char", sub_command="modify")
    def account_other_cmd(self, request, char: SenderObj, named_params):
        return self.get_account_display(char, named_params.page)

    @command(command="raid", params=[Const("presets"), Const("add"), Any("name"), Int("points")], access_level="admin",
             description="Add new points preset", sub_command="manage_points")
    def presets_add_cmd(self, request, _1, _2, name: str, points: int):
        count = self.db.query_single("SELECT COUNT(*) AS count FROM points_presets WHERE name = ?", [name]).count

        if count > 0:
            return "A preset already exists with the name <highlight>%s</highlight>." % name

        sql = "INSERT INTO points_presets (name, points) VALUES (?,?)"
        self.db.exec(sql, [name, points])
        return "A preset with the name <highlight>%s</highlight> was added, worth <green>%d</green> points." % (name, points)

    @command(command="raid", params=[Const("presets"), Const("rem"), Int("preset_id")], access_level="admin",
             description="Delete preset", sub_command="manage_points")
    def presets_rem_cmd(self, request, _1, _2, preset_id: int):
        if self.db.exec("DELETE FROM points_presets WHERE preset_id = ?", [preset_id]) > 0:
            return "Successfully removed preset with ID <highlight>%d</highlight>." % preset_id
        else:
            return "No preset with given ID <highlight>%d</highlight>." % preset_id

    @command(command="raid", params=[Const("presets"), Const("alter"), Int("preset_id"), Int("new_points")], access_level="admin",
             description="Alter the points dished out by given preset", sub_command="manage_points")
    def presets_alter_cmd(self, request, _1, _2, preset_id: int, new_points: int):
        preset = self.db.query_single("SELECT * FROM points_presets WHERE preset_id = ?", [preset_id])

        if not preset:
            return f"Preset with ID <highlight>{preset_id}</highlight> does not exist."

        self.db.exec("UPDATE points_presets SET points = ? WHERE preset_id = ?", [new_points, preset_id])
        return "Successfully updated the preset, <highlight>%s</highlight>, to dish out " \
               "<green>%d</green> points instead of <red>%d</red>." % (preset.name, new_points, preset.points)

    @command(command="raid", params=[Options(["presets", "addpts"])], access_level="member",
             description="See list of points presets")
    def presets_cmd(self, request, _):
        return ChatBlob("Raid Points Presets", self.build_preset_list())

    def build_preset_list(self):
        presets = self.db.query("SELECT * FROM points_presets ORDER BY name ASC, points DESC")

        if presets:
            blob = ""

            for preset in presets:
                add_points_link = self.text.make_tellcmd("Add pts", "raid addpts %s" % preset.name)
                blob += "<highlight>%s</highlight> worth <green>%d</green> points %s [id: %d]\n\n" \
                        % (preset.name, preset.points, add_points_link, preset.preset_id)

            return blob

        return "No presets available. To add new presets use <highlight><symbol>presets add preset_name preset_points</highlight>."

    def add_log_entry(self, char_id: int, leader_id: int, reason: str, amount=0):
        sql = "INSERT INTO points_log (char_id, audit, leader_id, reason, created_at) VALUES (?,?,?,?,?)"
        return self.db.exec(sql, [char_id, amount, leader_id, reason, int(time.time())])

    def alter_points(self, char_id: int, leader_id: int, reason: str, amount: int):
        sql = "UPDATE points SET points = points + ? WHERE char_id = ?"
        self.db.exec(sql, [amount, char_id])

        self.add_log_entry(char_id, leader_id, reason, amount)

    def get_account(self, main_id, conn):
        sql = "SELECT p.char_id, p.points, p.disabled FROM points p WHERE p.char_id = ?"
        row = self.db.query_single(sql, [main_id])
        if not row:
            self.create_account(main_id, SenderObj(conn.get_char_id(),
                                                   conn.get_char_name(),
                                                   None))
            row = self.db.query_single(sql, [main_id])

        return row

    def create_account(self, main_id, sender):
        sql = "INSERT INTO points (char_id, points, created_at) VALUES (?,?,?)"
        self.db.exec(sql, [main_id, 0, int(time.time())])

        self.add_log_entry(main_id, sender.char_id, "Account opened by %s" % sender.name)

    def get_account_display(self, char: SenderObj, page):
        main = self.alts_service.get_main(char.char_id)
        if not main:
            return "Could not find character <highlight>%s</highlight>." % char.name

        page = int(page) if page else 1
        page_size = 20
        offset = (page - 1) * page_size

        points = self.db.query_single("SELECT points, disabled FROM points WHERE char_id = ?", [main.char_id])
        if not points:
            return "Could not find raid account for <highlight>%s</highlight>." % char.name

        alts_link = self.text.make_tellcmd("Alts", "alts %s" % main.name)
        blob = ""
        blob += "Account: %s [%s]\n" % (main.name, alts_link)
        blob += "Points: %d\n" % points.points
        blob += "Status: %s\n\n" % ("<green>Open</green>" if points.disabled == 0 else "<red>Disabled</red>")

        points_log = self.db.query("SELECT * FROM points_log WHERE char_id = ? ORDER BY created_at DESC LIMIT ?, ?",
                                   [main.char_id, offset, page_size])
        blob += "<header2>Account log</header2>\n"
        if points_log is None:
            blob += "No entries in log."
        else:
            for entry in points_log:
                if entry.audit > 0:
                    pts = "<green>+%d</green>" % entry.audit
                    blob += "<grey>[%s]</grey> %s points by <highlight>%s</highlight>; <orange>%s</orange>" \
                            % (self.util.format_datetime(entry.created_at), pts,
                               self.character_service.resolve_char_to_name(entry.leader_id), entry.reason)
                elif entry.audit < 0:
                    pts = "<red>-%d</red>" % (-1 * entry.audit)
                    blob += "<grey>[%s]</grey> %s points by <highlight>%s</highlight>; <orange>%s</orange>" \
                            % (self.util.format_datetime(entry.created_at), pts,
                               self.character_service.resolve_char_to_name(entry.leader_id),
                               entry.reason)
                else:
                    # If points is 0, then it's a general case log
                    blob += "<grey>[%s]</grey> <orange>%s</orange>" % (self.util.format_datetime(entry.created_at), entry.reason)

                log_entry_link = self.text.make_tellcmd(entry.log_id, f"account history {entry.log_id}")
                blob += " [%s]\n" % log_entry_link

        return ChatBlob("%s Account" % char.name, blob)
Exemplo n.º 27
0
class AuctionController:
    def __init__(self):
        self.auction: AuctionStrategy = None

    @setting(name="auction_length",
             value="90s",
             description="Regular auction length in seconds")
    def auction_length(self):
        return TimeSettingType()

    @setting(name="auction_announce_interval",
             value="15s",
             description="Auction announce interval")
    def auction_announce_interval(self):
        return TimeSettingType()

    @setting(name="auction_late_bid_extension",
             value="10s",
             description="How much to extend auction in case of late bid")
    def auction_late_bid_extension(self):
        return TimeSettingType()

    @setting(name="auction_late_bid_threshold",
             value="10s",
             description="Threshold for a bid to be considered late")
    def auction_late_bid_threshold(self):
        return TimeSettingType()

    @command(command="auction",
             params=[],
             description="Show auction status",
             access_level="member")
    def auction_cmd(self, request):
        if not self.is_auction_running():
            return "No auction running."

        return self.auction.get_auction_list()

    @command(command="auction",
             params=[Const("start"), Any("items")],
             description="Start an auction, with one or more items",
             access_level="moderator",
             sub_command="modify")
    def auction_start_cmd(self, request, _, items):
        if self.is_auction_running():
            return "Auction already running."

        items = re.findall(
            r"(([^<]+)?<a href=[\"\']itemref://(\d+)/(\d+)/(\d+)[\"\']>([^<]+)</a>([^<]+)?)",
            items)
        # TODO choose auction strategy impl
        self.auction = AuctionStrategy()
        for item in items:
            self.auction.add_item(item[0])

        auction_length = self.auction_length().get_value()
        announce_interval = self.auction_announce_interval().get_value()
        late_bid_threshold = self.auction_late_bid_threshold().get_value()
        late_bid_extension = self.auction_late_bid_extension().get_value()

        return self.auction.start(request.sender, auction_length,
                                  announce_interval, late_bid_threshold,
                                  late_bid_extension)

    @command(command="auction",
             params=[Options(["cancel", "end"])],
             description="Cancel ongoing auction",
             access_level="moderator",
             sub_command="modify")
    def auction_cancel_cmd(self, request, _):
        if not self.is_auction_running():
            return "No auction running."

        result = self.auction.cancel(request.sender)
        self.auction = None
        return result

    @command(command="auction",
             params=[
                 Const("bid"),
                 Int("amount", is_optional=True),
                 Const("all", is_optional=True),
                 Int("item_index", is_optional=True)
             ],
             description="Bid on an item",
             access_level="member")
    def auction_bid_cmd(self, request, _, amount, all_amount, item_index):
        if not self.is_auction_running():
            return "No auction running."

        return self.auction.add_bid(request.sender, all_amount or amount,
                                    item_index)

    def is_auction_running(self):
        return self.auction and self.auction.is_running
Exemplo n.º 28
0
class LadderController:
    def __init__(self):
        self.grades = ["shiny", "bright", "faded"]

    def inject(self, registry):
        self.db = registry.get_instance("db")
        self.util = registry.get_instance("util")
        self.text = registry.get_instance("text")

    @command(command="ladder", params=[Const("treatment"), Int("starting_amount")], access_level="all",
             description="Show sequence of laddering implants for treatment",
             extended_description="The base amount should be the treatment or ability you have with all nano buffs, perks, and items-buffing equipment equipped, "
                                  "but minus any implants you have equipped.")
    def ladder_treatment_cmd(self, request, _, treatment):
        if treatment < 11:
            return "Base treatment must be at least <highlight>11<end>."

        prefix = "skill_"
        result = self.optimized_steps(prefix, treatment, self.get_implant_by_max_treatment)

        blob = self.format_steps("treatment", result.steps, treatment, (treatment + self.calculate_total(result.slots, prefix)))

        return ChatBlob("Laddering Treatment", blob)

    @command(command="ladder", params=[Const("ability"), Int("starting_amount")], access_level="all",
             description="Show sequence of laddering implants for ability",
             extended_description="The base amount should be the treatment or ability you have with all nano buffs, perks, and items-buffing equipment equipped, "
                                  "but minus any implants you have equipped.")
    def ladder_ability_cmd(self, request, _, ability):
        if ability < 6:
            return "Base ability must be at least <highlight>6<end>."

        prefix = "ability_"
        result = self.optimized_steps(prefix, ability, self.get_implant_by_max_ability)

        blob = self.format_steps("ability", result.steps, ability, (ability + self.calculate_total(result.slots, prefix)))

        return ChatBlob("Laddering Ability", blob)

    def format_steps(self, label, steps, starting, ending):
        blob = "Starting %s: <highlight>%s<end>\n\n" % (label, starting)
        blob += "-------------------\n\n"
        for (action, grade, implant) in steps:
            blob += "%s %s QL <highlight>%d<end>\n\n" % (action.capitalize(), grade, implant.ql)

        blob += "-------------------\n\n"
        blob += "Ending %s: <highlight>%s<end>\n\n" % (label, ending)
        blob += "\nInspired by a command written by Lucier of the same name"

        return blob

    def optimized_steps(self, prefix, base_value, get_max_implant):
        grade_combinations = [self.grades,
                              ["shiny", "faded", "bright"],
                              ["bright", "shiny", "faded"],
                              ["bright", "faded", "shiny"],
                              ["faded", "shiny", "bright"],
                              ["faded", "bright", "shiny"]]

        best = None
        for grade_combo in grade_combinations:
            result = self.get_steps(prefix, base_value, get_max_implant, lambda current_grade: self.get_next_grade(current_grade, grade_combo))
            if not best:
                best = result
            else:
                result_value = self.calculate_total(result.slots, prefix)
                best_value = self.calculate_total(best.slots, prefix)
                if result_value > best_value:
                    # this is here as a sanity check, but it appears that the result is always the same no matter which order you insert the implants
                    best = result
                elif best_value == result_value and len(result.steps) < len(best.steps):
                    # this optimizes for the least amount of steps/implants
                    best = result

        return best

    def get_steps(self, prefix, base_value, get_max_implant, get_next_grade):
        slots = DictObject({"shiny": None,
                            "bright": None,
                            "faded": None})

        steps = []

        num_skipped = 0
        current_grade = None
        while num_skipped < 3:
            current_grade = get_next_grade(current_grade)

            # find next highest possible implant
            new_implant = get_max_implant(self.calculate_total(slots, prefix, current_grade) + base_value)

            if not slots.get(current_grade):
                steps.append(["add", current_grade, new_implant])
                slots[current_grade] = new_implant
            elif new_implant.get(prefix + current_grade) > slots.get(current_grade).get(prefix + current_grade):
                steps.append(["remove", current_grade, slots.get(current_grade)])
                steps.append(["add", current_grade, new_implant])
                slots[current_grade] = new_implant
            else:
                num_skipped += 1

        return DictObject({"slots": slots,
                           "steps": steps})

    def get_next_grade(self, current_grade, grades):
        if not current_grade:
            next_index = 0
        else:
            next_index = grades.index(current_grade) + 1
            if next_index >= len(grades):
                next_index = 0

        return grades[next_index]

    def get_implant_by_max_treatment(self, treatment):
        return self.db.query_single("SELECT * from implant_requirement WHERE treatment <= ? ORDER BY ql DESC LIMIT 1", [treatment])

    def get_implant_by_max_ability(self, ability):
        return self.db.query_single("SELECT * from implant_requirement WHERE ability <= ? ORDER BY ql DESC LIMIT 1", [ability])

    def get_cluser_min_ql(self, ql, grade):
        if grade == "shiny":
            result = math.floor(ql * 0.86)
        elif grade == "bright":
            result = math.floor(ql * 0.84)
        elif grade == "faded":
            result = math.floor(ql * 0.82)
        else:
            raise Exception("Unknown grade: '%s'" % grade)

        if ql >= 201:
            return max(201, result)
        else:
            return result

    def calculate_total(self, slots, prefix, skip_grade=None):
        value = 0
        for grade in self.grades:
            if grade != skip_grade:
                implant = slots.get(grade)
                if implant:
                    value += implant.get(prefix + grade)

        return value
Exemplo n.º 29
0
class TowerAttackController:
    def __init__(self):
        self.logger = Logger(__name__)

    def inject(self, registry):
        self.bot = registry.get_instance("bot")
        self.db = registry.get_instance("db")
        self.text = registry.get_instance("text")
        self.util = registry.get_instance("util")
        self.event_service = registry.get_instance("event_service")
        self.playfield_controller = registry.get_instance(
            "playfield_controller")
        self.command_alias_service = registry.get_instance(
            "command_alias_service")
        self.public_channel_service = registry.get_instance(
            "public_channel_service")

    def start(self):
        self.db.exec(
            "CREATE TABLE IF NOT EXISTS tower_attacker (id INT PRIMARY KEY AUTO_INCREMENT, att_org_name VARCHAR(50) NOT NULL, att_faction VARCHAR(10) NOT NULL, "
            "att_char_id INT, att_char_name VARCHAR(20) NOT NULL, att_level INT NOT NULL, att_ai_level INT NOT NULL, att_profession VARCHAR(15) NOT NULL, "
            "x_coord INT NOT NULL, y_coord INT NOT NULL, is_victory SMALLINT NOT NULL, "
            "tower_battle_id INT NOT NULL, created_at INT NOT NULL)")
        self.db.exec(
            "CREATE TABLE IF NOT EXISTS tower_battle (id INT PRIMARY KEY AUTO_INCREMENT, playfield_id INT NOT NULL, site_number INT NOT NULL, "
            "def_org_name VARCHAR(50) NOT NULL, def_faction VARCHAR(10) NOT NULL, is_finished INT NOT NULL, battle_type VARCHAR(20) NOT NULL, last_updated INT NOT NULL)"
        )

        self.command_alias_service.add_alias("victory", "attacks")

    @command(command="attacks",
             params=[NamedParameters(["page"])],
             access_level="all",
             description="Show recent tower attacks and victories")
    def attacks_cmd(self, request, named_params):
        page = int(named_params.page or "1")

        page_size = 30
        offset = (page - 1) * page_size

        sql = """
            SELECT
                b.*,
                a.*,
                COALESCE(a.att_level, 0) AS att_level,
                COALESCE(a.att_ai_level, 0) AS att_ai_level,
                p.short_name,
                b.id AS battle_id
            FROM
                tower_battle b
                LEFT JOIN tower_attacker a ON
                    a.tower_battle_id = b.id
                LEFT JOIN playfields p ON
                    p.id = b.playfield_id
            ORDER BY
                b.last_updated DESC,
                a.created_at DESC
            LIMIT %d, %d
        """ % (offset, page_size)

        data = self.db.query(sql)
        t = int(time.time())

        blob = self.check_for_all_towers_channel()

        if page > 1:
            blob += "   " + self.text.make_chatcmd(
                "<< Page %d" % (page - 1), self.get_chat_command(page - 1))
        if len(data) > 0:
            blob += "   Page " + str(page)
            blob += "   " + self.text.make_chatcmd(
                "Page %d >>" % (page + 1), self.get_chat_command(page + 1))
            blob += "\n"

        current_battle_id = -1
        for row in data:
            if current_battle_id != row.battle_id:
                blob += "\n<pagebreak>"
                current_battle_id = row.battle_id
                blob += self.format_battle_info(row, t)
                blob += self.text.make_chatcmd(
                    "More Info",
                    "/tell <myname> attacks battle %d" % row.battle_id) + "\n"
                blob += "<header2>Attackers:<end>\n"

            blob += "<tab>" + self.format_attacker(row) + "\n"

        return ChatBlob("Tower Attacks", blob)

    @command(command="attacks",
             params=[Const("battle"), Int("battle_id")],
             access_level="all",
             description="Show battle info for a specific battle")
    def attacks_battle_cmd(self, request, _, battle_id):
        battle = self.db.query_single(
            "SELECT b.*, p.short_name FROM tower_battle b LEFT JOIN playfields p ON p.id = b.playfield_id WHERE b.id = ?",
            [battle_id])
        if not battle:
            return "Could not find battle with ID <highlight>%d<end>." % battle_id

        t = int(time.time())

        attackers = self.db.query(
            "SELECT * FROM tower_attacker WHERE tower_battle_id = ? ORDER BY created_at DESC",
            [battle_id])

        first_activity = attackers[-1].created_at if len(
            attackers) > 0 else battle.last_updated

        blob = self.check_for_all_towers_channel()
        blob += self.format_battle_info(battle, t)
        blob += "Duration: <highlight>%s<end>\n\n" % self.util.time_to_readable(
            battle.last_updated - first_activity)
        blob += "<header2>Attackers:<end>\n"

        for row in attackers:
            blob += "<tab>" + self.format_attacker(row)
            blob += " " + self.format_timestamp(row.created_at, t)
            blob += "\n"

        return ChatBlob("Battle Info %d" % battle_id, blob)

    @event(event_type=TowerController.TOWER_ATTACK_EVENT,
           description="Record tower attacks",
           is_hidden=True)
    def tower_attack_event(self, event_type, event_data):
        t = int(time.time())
        site_number = self.find_closest_site_number(
            event_data.location.playfield.id, event_data.location.x_coord,
            event_data.location.y_coord)

        attacker = event_data.attacker or {}
        defender = event_data.defender

        battle = self.find_or_create_battle(event_data.location.playfield.id,
                                            site_number, defender.org_name,
                                            defender.faction, "attack", t)

        self.db.exec(
            "INSERT INTO tower_attacker (att_org_name, att_faction, att_char_id, att_char_name, att_level, att_ai_level, att_profession, "
            "x_coord, y_coord, is_victory, tower_battle_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
            [
                attacker.get("org_name", ""),
                attacker.get("faction", ""),
                attacker.get("char_id", 0),
                attacker.get("name", ""),
                attacker.get("level", 0),
                attacker.get("ai_level", 0),
                attacker.get("profession", ""), event_data.location.x_coord,
                event_data.location.y_coord, 0, battle.id, t
            ])

    @event(event_type=TowerController.TOWER_VICTORY_EVENT,
           description="Record tower victories",
           is_hidden=True)
    def tower_victory_event(self, event_type, event_data):
        t = int(time.time())

        if event_data.type == "attack":
            row = self.get_last_attack(event_data.winner.faction,
                                       event_data.winner.org_name,
                                       event_data.loser.faction,
                                       event_data.loser.org_name,
                                       event_data.location.playfield.id, t)

            if not row:
                site_number = 0
                is_finished = 1
                self.db.exec(
                    "INSERT INTO tower_battle (playfield_id, site_number, def_org_name, def_faction, is_finished, battle_type, last_updated) VALUES (?, ?, ?, ?, ?, ?, ?)",
                    [
                        event_data.location.playfield.id, site_number,
                        event_data.loser.org_name, event_data.loser.faction,
                        is_finished, event_data.type, t
                    ])
                battle_id = self.db.last_insert_id()

                attacker = event_data.winner or {}
                self.db.exec(
                    "INSERT INTO tower_attacker (att_org_name, att_faction, att_char_id, att_char_name, att_level, att_ai_level, att_profession, "
                    "x_coord, y_coord, is_victory, tower_battle_id, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
                    [
                        attacker.get("org_name", ""),
                        attacker.get("faction", ""),
                        attacker.get("char_id", 0),
                        attacker.get("name", ""),
                        attacker.get("level", 0),
                        attacker.get("ai_level", 0),
                        attacker.get("profession", ""), 0, 0, 0, battle_id, t
                    ])
            else:
                is_victory = 1
                self.db.exec(
                    "UPDATE tower_attacker SET is_victory = ? WHERE id = ?",
                    [is_victory, row.attack_id])

                is_finished = 1
                self.db.exec(
                    "UPDATE tower_battle SET is_finished = ?, last_updated = ? WHERE id = ?",
                    [is_finished, t, row.battle_id])
        elif event_data.type == "terminated":
            site_number = 0
            is_finished = 1
            self.db.exec(
                "INSERT INTO tower_battle (playfield_id, site_number, def_org_name, def_faction, is_finished, battle_type, last_updated) VALUES (?, ?, ?, ?, ?, ?, ?)",
                [
                    event_data.location.playfield.id, site_number,
                    event_data.loser.org_name, event_data.loser.faction,
                    is_finished, event_data.type, t
                ])
        else:
            raise Exception("Unknown victory event type: '%s'" %
                            event_data.type)

    def format_attacker(self, row):
        if row.att_char_name:
            level = ("%d/<green>%d<end>" % (row.att_level, row.att_ai_level)
                     ) if row.att_ai_level > 0 else "%d" % row.att_level
            org = row.att_org_name + " " if row.att_org_name else ""
            victor = " - <notice>Winner!<end>" if row.is_victory else ""
            return "%s (%s %s) %s(%s)%s" % (row.att_char_name, level,
                                            row.att_profession, org,
                                            row.att_faction, victor)
        else:
            return "Unknown attacker"

    def find_closest_site_number(self, playfield_id, x_coord, y_coord):
        sql = """
            SELECT
                site_number,
                ((x_distance * x_distance) + (y_distance * y_distance)) radius
            FROM
                (SELECT
                    playfield_id,
                    site_number,
                    min_ql,
                    max_ql,
                    x_coord,
                    y_coord,
                    site_name,
                    (x_coord - ?) as x_distance,
                    (y_coord - ?) as y_distance
                FROM
                    tower_site
                WHERE
                    playfield_id = ?) t
            ORDER BY
                radius ASC
            LIMIT 1"""

        row = self.db.query_single(sql, [x_coord, y_coord, playfield_id])
        if row:
            return row.site_number
        else:
            return 0

    def find_or_create_battle(self, playfield_id, site_number, org_name,
                              faction, battle_type, t):
        last_updated = t - (8 * 3600)
        is_finished = 0

        sql = """
            SELECT
                *
            FROM
                tower_battle
            WHERE
                playfield_id = ?
                AND site_number = ?
                AND is_finished = ?
                AND def_org_name = ?
                AND def_faction = ?
                AND last_updated >= ?
        """

        battle = self.db.query_single(sql, [
            playfield_id, site_number, is_finished, org_name, faction,
            last_updated
        ])

        if battle:
            self.db.exec(
                "UPDATE tower_battle SET last_updated = ? WHERE id = ?",
                [t, battle.id])
            return battle
        else:
            self.db.exec(
                "INSERT INTO tower_battle (playfield_id, site_number, def_org_name, def_faction, is_finished, battle_type, last_updated) VALUES (?, ?, ?, ?, ?, ?, ?)",
                [
                    playfield_id, site_number, org_name, faction, is_finished,
                    battle_type, t
                ])
            return self.db.query_single(
                "SELECT * FROM tower_battle WHERE id = ?",
                [self.db.last_insert_id()])

    def get_last_attack(self, att_faction, att_org_name, def_faction,
                        def_org_name, playfield_id, t):
        last_updated = t - (8 * 3600)
        is_finished = 0

        sql = """
            SELECT
                b.id AS battle_id,
                a.id AS attack_id
            FROM
                tower_battle b
                JOIN tower_attacker a ON
                    a.tower_battle_id = b.id 
            WHERE
                a.att_faction = ?
                AND a.att_org_name = ?
                AND b.def_faction = ?
                AND b.def_org_name = ?
                AND b.playfield_id = ?
                AND b.is_finished = ?
                AND b.last_updated >= ?
            ORDER BY
                last_updated DESC
            LIMIT 1"""

        return self.db.query_single(sql, [
            att_faction, att_org_name, def_faction, def_org_name, playfield_id,
            is_finished, last_updated
        ])

    def format_battle_info(self, row, t):
        blob = ""
        defeated = " - <notice>Defeated!<end>" if row.is_finished else ""
        blob += "Site: <highlight>%s %s<end>\n" % (row.short_name,
                                                   row.site_number or "?")
        blob += "Defender: <highlight>%s<end> (%s)%s\n" % (
            row.def_org_name, row.def_faction, defeated)
        blob += "Last Activity: %s\n" % self.format_timestamp(
            row.last_updated, t)
        return blob

    def format_timestamp(self, t, current_t):
        return "<highlight>%s<end> (%s ago)" % (self.util.format_datetime(
            t), self.util.time_to_readable(current_t - t))

    def get_chat_command(self, page):
        return "/tell <myname> attacks --page=%d" % page

    def check_for_all_towers_channel(self):
        if not self.public_channel_service.get_channel_name(
                TowerController.ALL_TOWERS_ID):
            return "Notice: The bot must belong to an org and be promoted to a rank that is high enough to have the All Towers channel (e.g., Squad Commander) in order for the <symbol>attacks command to work correctly.\n\n"
        else:
            return ""
Exemplo n.º 30
0
class ItemsController:
    PAGE_SIZE = 30

    def inject(self, registry):
        self.db: DB = registry.get_instance("db")
        self.text: Text = registry.get_instance("text")
        self.command_alias_service = registry.get_instance(
            "command_alias_service")

    def pre_start(self):
        self.db.load_sql_file(self.module_dir + "/" + "aodb.sql")

    def start(self):
        self.command_alias_service.add_alias("item", "items")
        self.command_alias_service.add_alias("i", "items")

    @command(command="items",
             params=[Int("item_id")],
             access_level="all",
             description="Search for an item by item id")
    def items_id_cmd(self, request, item_id):
        item = self.get_by_item_id(item_id)
        if item:
            return self.format_items_response(None, str(item_id), [item], 0, 1)
        else:
            return "Could not find item with ID <highlight>%d</highlight>." % item_id

    @command(command="items",
             params=[
                 Int("ql", is_optional=True),
                 Any("search"),
                 NamedParameters(["page"])
             ],
             access_level="all",
             description="Search for an item")
    def items_search_cmd(self, request, ql, search, named_params):
        page = int(named_params.page or "1")

        search = html.unescape(search)

        offset = (page - 1) * self.PAGE_SIZE

        all_items = self.find_items(search, ql)

        return self.format_items_response(ql, search, all_items, offset, page)

    def format_items_response(self, ql, search, all_items, offset,
                              page_number):
        items = self.sort_items(search,
                                all_items)[offset:offset + self.PAGE_SIZE]
        cnt = len(items)

        if cnt == 0:
            if ql:
                return "No QL <highlight>%d</highlight> items found matching <highlight>%s</highlight>." % (
                    ql, search)
            else:
                return "No items found matching <highlight>%s</highlight>." % search
        elif cnt == 1:
            item = items[0]
            return self.format_single_item([item], ql)
        else:
            blob = ""
            # blob += "Version: <highlight>%s</highlight>\n" % "unknown"
            if ql:
                blob += "Search: <highlight>QL %d %s</highlight>\n" % (ql,
                                                                       search)
            else:
                blob += "Search: <highlight>%s</highlight>\n" % search
            blob += "\n"

            blob += self.text.get_paging_links(
                self.get_chat_command(ql, search), page_number,
                (offset + self.PAGE_SIZE) < len(all_items))
            blob += "\n\n"

            blob += self.format_items(items, ql)
            blob += "\nItem DB rips created using the %s tool." % self.text.make_chatcmd(
                "Budabot Items Extractor",
                "/start https://github.com/Budabot/ItemsExtractor")

            return ChatBlob(
                "Item Search Results (%d - %d of %d)" %
                (offset + 1, min(offset + self.PAGE_SIZE,
                                 len(all_items)), len(all_items)), blob)

    def format_items(self, items, ql=None):
        blob = ""
        for item_group in ItemIter(items):
            blob += "<pagebreak>"
            blob += self.text.make_image(item_group[0].icon) + "\n"
            blob += self.format_single_item(item_group, ql)
            blob += "\n\n"

        return blob

    def format_single_item(self, item_group, ql):
        msg = ""
        msg += item_group[0].name

        for item in reversed(item_group):
            if ql:
                if item.lowql != item.highql:
                    msg += " %s" % self.text.make_item(item.lowid, item.highid,
                                                       ql, ql)
                    msg += " [%s - %s]" % (self.text.make_item(
                        item.lowid, item.highid, item.lowql, item.lowql),
                                           self.text.make_item(
                                               item.lowid, item.highid,
                                               item.highql, item.highql))
                elif item.lowql == item.highql:
                    msg += " [%s]" % self.text.make_item(
                        item.lowid, item.highid, item.highql, item.highql)
            elif item.lowql == item.highql:
                msg += " [%s]" % self.text.make_item(item.lowid, item.highid,
                                                     item.highql, item.highql)
            else:
                msg += " [%s - %s]" % (self.text.make_item(
                    item.lowid, item.highid, item.lowql, item.lowql),
                                       self.text.make_item(
                                           item.lowid, item.highid,
                                           item.highql, item.highql))

        return msg

    def find_items(self, name, ql=None):
        params = [name]
        sql = "SELECT * FROM aodb WHERE name LIKE ? "
        if ql:
            sql += " AND lowql <= ? AND highql >= ?"
            params.append(ql)
            params.append(ql)

        sql += " UNION SELECT * FROM aodb WHERE name <EXTENDED_LIKE=%d> ?" % len(
            params)
        params.append(name)

        if ql:
            sql += " AND lowql <= ? AND highql >= ?"
            params.append(ql)
            params.append(ql)

        sql += " ORDER BY name ASC, highql DESC"

        return self.db.query(sql, params, extended_like=True)

    def sort_items(self, search, items):
        search = search.lower()
        search_parts = search.split(" ")

        # if item name matches search exactly (case-insensitive) then priority = 0
        # if item name contains every whole word from search (case-insensitive) then priority = 1
        # +1 priority for each whole word from search that item name does not contain

        for row in items:
            row.priority = 0
            row_name = row.name.lower()
            if row_name != search:
                row.priority += 1
                row_parts = row_name.split(" ")
                for search_part in search_parts:
                    if search_part not in row_parts:
                        row.priority += 1

        items.sort(key=lambda x: x.priority, reverse=False)

        return items

    def get_by_item_id(self, item_id, ql=None):
        if ql:
            return self.db.query_single(
                "SELECT * FROM aodb WHERE (highid = ? OR lowid = ?) AND (lowql <= ? AND highql >= ?) ORDER BY highid = ? DESC LIMIT 1",
                [item_id, item_id, ql, ql, item_id])
        else:
            return self.db.query_single(
                "SELECT * FROM aodb WHERE highid = ? OR lowid = ? ORDER BY highid = ? DESC LIMIT 1",
                [item_id, item_id, item_id])

    def find_by_name(self, name, ql=None):
        if ql:
            return self.db.query_single(
                "SELECT * FROM aodb WHERE name = ? AND lowql <= ? AND highql >= ? ORDER BY highid DESC LIMIT 1",
                [name, ql, ql])
        else:
            return self.db.query_single(
                "SELECT * FROM aodb WHERE name = ? ORDER BY highql DESC, highid DESC LIMIT 1",
                [name])

    def get_chat_command(self, ql, search):
        if ql:
            return "items %d %s" % (ql, search)
        else:
            return "items %s" % search