import math from core.chat_blob import ChatBlob from core.command_param_types import Int, Decimal, Item from core.decorators import instance, command from core.dict_object import DictObject @instance() 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", pre_optimized=True) self.db.create_view("weapon_attributes") 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="member", description="Show agg/def information") def aggdef_cmd(self, _, 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 = f"Attack: {weapon_attack:.2f} secs\n" blob += f"Recharge: {weapon_recharge:.2f} secs\n" blob += f"Init Skill: {init_skill:d}\n\n" blob += "You must set your AGG/DEF bar at %d%% to wield your weapon at 1/1.\n\n" % int( init_result) blob += f"Init needed for max speed at Full Agg (100%): {inits_full_agg:d}\n" blob += f"Init needed for max speed at Neutral (87.5%): {inits_neutral:d}\n" blob += f"Init needed for max speed at Full Def (0%): {inits_full_def:d}\n\n" 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="member", description="Show aimed shot information") def aimedshot_cmd(self, _, weapon_attack, weapon_recharge, aimed_shot_skill): as_info = self.get_aimed_shot_info(weapon_attack, weapon_recharge, aimed_shot_skill) blob = f"Attack: {weapon_attack:.2f} secs\n" blob += f"Recharge: {weapon_recharge:.2f} secs\n" blob += f"Aimed Shot Skill: {aimed_shot_skill:d}\n\n" blob += f"Aimed Shot Multiplier: 1 - {as_info.multiplier:d}x\n" blob += f"Aimed Shot Recharge: {as_info.recharge:d} secs\n\n" blob += f"You need {as_info.skill_cap:d} Aimed Shot Skill " \ f"to cap your recharge at {as_info.hard_cap:d} seconds." return ChatBlob("Aimed Shot Results", blob) @command(command="brawl", params=[Int("brawl_skill")], access_level="member", description="Show brawl information") def brawl_cmd(self, _, brawl_skill): brawl_info = self.get_brawl_info(brawl_skill) blob = f"Brawl Skill: {brawl_skill:d}\n\n" blob += "Brawl Recharge: 15 secs (constant)\n" blob += f"Brawl Damage: {brawl_info.min_dmg:d} - {brawl_info.max_dmg:d} " \ f"({brawl_info.crit_dmg:d})\n" blob += f"Stun Change: {brawl_info.stun_chance:d}%\n" blob += f"Stun Duration: {brawl_info.stun_duration:d} secs\n\n" 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="member", description="Show burst information") def burst_cmd(self, _, weapon_attack, weapon_recharge, burst_recharge, burst_skill): burst_info = self.get_burst_info(weapon_attack, weapon_recharge, burst_recharge, burst_skill) blob = f"Attack: {weapon_attack:.2f} secs\n" blob += f"Recharge: {weapon_recharge:.2f} secs\n" blob += f"Burst Recharge: {burst_recharge:d}\n" blob += f"Burst Skill: {burst_skill:d}\n\n" blob += f"Burst Recharge: {burst_info.recharge:d} secs\n\n" blob += f"You need {burst_info.skill_cap:d} Burst Skill " \ f"to cap your recharge at {burst_info.hard_cap:d} secs." return ChatBlob("Burst Results", blob) @command(command="dimach", params=[Int("dimach_skill")], access_level="member", description="Show dimach information") def dimach_cmd(self, _, dimach_skill): dimach_info = self.get_dimach_info(dimach_skill) blob = f"Dimach Skill: {dimach_skill:d}\n\n" blob += "Martial Artist\n" blob += f"Damage: {dimach_info.ma_dmg:d}\n" blob += f"Recharge: {self.util.time_to_readable(dimach_info.ma_recharge)}\n\n" blob += "Keeper\n" blob += f"Self Heal: {dimach_info.keeper_heal:d}\n" blob += "Recharge: 5 mins (constant)\n\n" blob += "Shade\n" blob += f"Damage: {dimach_info.shade_dmg:d}\n" blob += f"Self Heal: {dimach_info.shade_heal_percentage:d}% " \ f"* {dimach_info.shade_dmg:d} " \ f"= {round(dimach_info.shade_heal_percentage * dimach_info.shade_dmg / 100):d}\n" blob += f"Recharge: {self.util.time_to_readable(dimach_info.shade_recharge)}\n\n" blob += "All other professions\n" blob += f"Damage: {dimach_info.general_dmg:d}\n" blob += "Recharge: 30 mins (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="member", description="Show fast attack information") def fastattack_cmd(self, _, weapon_attack, fast_attack_skill): fast_attack_info = self.get_fast_attack_info(weapon_attack, fast_attack_skill) blob = f"Attack: {weapon_attack:.2f} secs\n" blob += f"Fast Attack Skill: {fast_attack_skill:d}\n\n" blob += f"Fast Attack Recharge: {fast_attack_info.recharge:.2f} secs\n\n" blob += f"You need {fast_attack_info.skill_cap:d} Fast Attack Skill " \ f"to cap your recharge at {fast_attack_info.hard_cap:.2f} secs." return ChatBlob("Fast Attack Results", blob) @command(command="flingshot", params=[Decimal("weapon_attack"), Int("fling_shot_skill")], access_level="member", description="Show fling shot information") def flingshot_cmd(self, _, weapon_attack, fling_shot_skill): fling_shot_info = self.get_fling_shot_info(weapon_attack, fling_shot_skill) blob = f"Attack: {weapon_attack:.2f} secs\n" blob += f"Fling Shot Skill: {fling_shot_skill:d}\n\n" blob += f"Fling Shot Recharge: {fling_shot_info.recharge:.2f} secs\n\n" blob += f"You need {fling_shot_info.skill_cap:d} Fling Shot Skill " \ f"to cap your recharge at {fling_shot_info.hard_cap:.2f} secs." 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="member", description="Show full auto information") def fullauto_cmd(self, _, 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 = f"Attack: {weapon_attack:.2f} secs\n" blob += f"Recharge: {weapon_recharge:.2f} secs\n" blob += f"Full Auto Recharge: {full_auto_recharge:d}\n" blob += f"Full Auto Skill: {full_auto_skill:d}\n\n" blob += f"Full Auto Recharge: {full_auto_info.recharge:d} secs\n" blob += f"Max Number of Bullets: {full_auto_info.max_bullets:d}\n\n" blob += f"You need {full_auto_info.skill_cap:d} Full Auto Skill " \ f"to cap your recharge at {full_auto_info.hard_cap:d} secs.\n\n" blob += "From 0 to 10K damage, the bullet damage is unchanged.\n" blob += "From 10K to 11.5K damage, each bullet damage is halved.\n" blob += "From 11K to 15K damage, each bullet damage is halved again.\n" blob += "15K is the damage cap." return ChatBlob("Full Auto Results", blob) @command(command="mafist", params=[Int("ma_skill")], access_level="member", description="Show martial arts information") def mafist_cmd(self, _, ma_skill): ma_info = self.get_martial_arts_info(ma_skill) blob = f"Martial Arts Skill: {ma_skill:d}\n\n" blob += "Martial Artist\n" blob += f"Speed: {ma_info.ma_speed:.2f} / {ma_info.ma_speed:.2f} secs\n" blob += f"Damage: {ma_info.ma_min_dmg:d} - {ma_info.ma_max_dmg:d} " \ f"({ma_info.ma_crit_dmg:d})\n\n" blob += "Shade\n" blob += f"Speed: {ma_info.shade_speed:.2f} / {ma_info.shade_speed:.2f} secs\n" blob += f"Damage: {ma_info.shade_min_dmg:d} - {ma_info.shade_max_dmg:d} " \ f"({ma_info.shade_crit_dmg:d})\n\n" blob += "All other professions\n" blob += f"Speed: {ma_info.gen_speed:.2f} / {ma_info.gen_speed:.2f} secs\n" blob += f"Damage: {ma_info.gen_min_dmg:d} - {ma_info.gen_max_dmg:d} " \ f"({ma_info.gen_crit_dmg:d})\n\n" return ChatBlob("Martial Arts Results", blob) @command(command="nanoinit", params=[Decimal("nano_attack_time"), Int("nano_cast_init")], access_level="member", description="Show nano cast init information") def nanoinit_cmd(self, _, nano_attack_time, nano_cast_init): nano_cast_info = self.get_nano_cast_info(nano_cast_init, nano_attack_time) blob = f"Attack: {nano_attack_time:.2f} secs\n" blob += f"Nano Cast Init: {nano_cast_init:d}\n\n" blob += f"Cast Time Reduction: {nano_cast_info.cast_time_reduction:.2f}\n" blob += f"Effective Cast Time: {nano_cast_info.effective_cast_time:.2f}\n\n" if nano_cast_info.bar_setting > 100: blob += "You cannot instacast this nano at any AGG/DEF setting.\n\n" else: blob += f"You must set your AGG/DEF bar to {nano_cast_info.bar_setting:d}% " \ f"to instacast this nano.\n\n" blob += f"NanoC. Init needed to instacast at Full Agg (100%): " \ f"{nano_cast_info.instacast_full_agg:d}\n" blob += f"NanoC. Init needed to instacast at Neutral (87.5%): " \ f"{nano_cast_info.instacast_neutral:d}\n" blob += f"NanoC. Init needed to instacast at Half (50%): " \ f"{nano_cast_info.instacast_half:d}\n" blob += f"NanoC. Init needed to instacast at Full Def (0%): " \ f"{nano_cast_info.instacast_full_def:d}\n\n" blob += f"Cast time at Full Agg (100%): {nano_cast_info.cast_time_full_agg:.2f}\n" blob += f"Cast time at Neutral (87.5%): {nano_cast_info.cast_time_neutral:.2f}\n" blob += f"Cast time at Half (50%): {nano_cast_info.cast_time_half:.2f}\n" blob += f"Cast time at Full Def (0%): {nano_cast_info.cast_time_full_def:.2f}" return ChatBlob("Nano Cast Init Results", blob) @command(command="weapon", params=[Int("item_id"), Int("ql", is_optional=True)], access_level="member", description="Show weapon information") def weapon_cmd(self, _, item_id, ql): return self.get_weapon_info(item_id, ql) @command(command="deflect", params=[Int("deflect_skill")], access_level="member", description="Show deflect information") def deflect_cmd(self, _, deflect_skill): if deflect_skill > 3000 or deflect_skill < 1: return "Your deflect skill can only be between 1 and 3000" return f"With {deflect_skill} skill you will deflect {round(deflect_skill / 300, 2)}% of attacks" @command(command="weapon", params=[Item("weapon_link")], access_level="member", description="Show weapon information") def weapon_cmd(self, _, 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="member", description="Show weapon information") def weapon_manual_cmd(self, _, item_id, ql): if not ql: item = self.items_controller.get_by_item_id(item_id) if item: ql = item.highql else: return f"Could not find item with id {item_id:d}." 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 f"Could not find item with ID {item_id:d}." 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 f"Could not find weapon information or item is not a weapon for " \ f"ID {item_id:d}." 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 = f"{self.text.make_item(item.lowid, item.highid, ql, item.name)} (QL {ql:d})\n\n" blob += f"Attack: {weapon_attack:.2f}\n" blob += f"Recharge: {weapon_recharge:.2f}\n\n" blob += self.get_inits_display(weapon_attack, weapon_recharge) + "\n" blob += "Specials\n" if high_attributes.aimed_shot: as_info = self.get_aimed_shot_info(weapon_attack, weapon_recharge, 1) blob += f"Aimed Shot\n{as_info.skill_cap:d} skill needed to cap " \ f"Aimed Shot recharge at {as_info.hard_cap:d} secs\n\n" 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 += f"Burst Recharge: {burst_recharge:d}\n" \ f"{burst_info.skill_cap:d} skill needed " \ f"to cap Burst recharge at {burst_info.hard_cap:d} secs\n\n" if high_attributes.fast_attack: fast_attack_info = self.get_fast_attack_info(weapon_attack, 1) blob += f"Fast Attack\n{fast_attack_info.skill_cap:d} skill needed " \ f"to cap Fast Attack recharge at {fast_attack_info.hard_cap:.2f} secs\n\n" if high_attributes.fling_shot: fling_shot_info = self.get_fling_shot_info(weapon_attack, 1) blob += f"Fling Shot\n{fling_shot_info.skill_cap:d} skill needed " \ f"to cap Fling Shot recharge at {fling_shot_info.hard_cap:.2f} secs\n\n" 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 += f"Full Auto Recharge: {full_auto_recharge:d}\n" \ f"{full_auto_info.skill_cap:d} skill needed " \ f"to cap Full Auto recharge at {full_auto_info.hard_cap:d} secs\n\n" return ChatBlob(f"Weapon Info for {item.name} (QL {ql:d})", 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 += f"DEF >{'=' * i}{']['}{'=' * (num_steps - 1 - i)}< AGG {i * step_size:d}% {inits_needed:d} init \n" return blob