Source code for samurai

import pandas as pd
import string

# potency modifiers for each buff
JINPU_MOD = 1.15
SHIFU_MOD = 1.0
YUKIKAZE_MOD = 1.11
KAITEN_MOD = 1.5


[docs]class Samurai(): """ Far across the rolling waves, towards the rising sun, there lies the island nation of Hingashi. In the distant past, the realm's great lords vied for supremacy over its sea-girt confines in a long and bloody conflict. And taking to battle in their lieges' names were noble swordsmen whose art was forged in the crucible of war: the samurai. Eventually, the nation was unified under one banner, and these warriors came to wield their katana not upon fields as part of an army, but upon streets as protectors of the peace. But as a neglected blade grows dull with rust, so too do men forget their purpose. Amidst waning memories of the old ways, a determined few hold fast to their convictions, hands by katana grips, awaiting the moment for steel to sing. """ def __init__(self, base_gcd=2.40, kenki_mastery=0, kenki_gauge=0): """ Constructor for an instance of the Samurai class. """ self._base_gcd = base_gcd self._current_gcd = self._base_gcd self._kenki_mastery = kenki_mastery self._potency_mod = 1.0 self._kenki_gauge = kenki_gauge self._has_jinpu = False self._has_shifu = False self._applied_yukikaze = False self._applied_higanbana = 0 self._has_meikyo_shisui = False self._has_hissatsu_kaiten = False self._has_getsu = False self._has_ka = False self._has_setsu = False self._combo_act_gekko = False self._combo_act_mangetsu = False self._combo_act_kasha = False self._combo_act_shifu = False self._combo_act_jinpu = False self._combo_act_oka = False self._combo_act_yukikaze = False self._enhanced_enpi = False self._open_eyes = False
[docs] def parse_rotation(self, rotation, n_targets=1): """ Creates a dataframe describing the given rotation. :param rotation: A list of tuples describing each GCD with strings. Each tuple takes the format (weaponskill, ability). If no ability is used, a 1-tuple may be supplied: ('weaponskill). :param n_targets: Number of targets available in the encounter. Defaults to 1. :return: df: A Pandas DataFrame object describing the rotation :return: average_potency: The average potency per GCD of the rotation :return: pps: The average potency per second of the rotation """ parsed_gcds = [] snapshot_dot_modifier = 0 dot_mod = 1.0 n_applied_higanbana = 0 meikyo_shisui_counter = 3 higanbana_timer = 0 shifu_timer = 0 jinpu_timer = 0 if not self.applied_yukikaze: yukikaze_timer = 0 else: yukikaze_timer = 30 current_time = 0 # string translator for text parsing translator = str.maketrans(' ', '_', string.punctuation) for k in range(len(rotation)): gcd = rotation[k] if type(gcd) != tuple: weaponskill = gcd abilities = [] else: weaponskill = gcd[0] abilities = gcd[1:] # convert input text to lowercase, replace punctuation, and replace spaces with underscores parsed_ws = weaponskill.lower().translate(translator) # record buff status at beginning of GCD buff_status = (self.has_jinpu, self.has_shifu, self.applied_yukikaze, self.applied_higanbana, self.kenki_gauge) # compute potency of weaponskill ws_mod = 1.0 ws_mod = KAITEN_MOD if self.has_hissatsu_kaiten else 1.0 if parsed_ws != 'higanbana': ws_potency = ws_mod*getattr(self, parsed_ws)(n_targets) else: # add a target afflicted by Higanbana DoT n_applied_higanbana += 1 # Hissatsu: Kaiten applies to the DoT modifier dot_mod = ws_mod*JINPU_MOD if self.has_jinpu else ws_mod if n_targets >= n_applied_higanbana: # in this case, there are more total targets than those afflicted with Higanbana DoT # snapshot buffs at time of DoT application and add to current DoT tick multiplier snapshot_dot_modifier += dot_mod # update the number of targets afflicted by Higanbana DoT self.applied_higanbana = n_applied_higanbana else: # in this case, all targets have been afflicted with Higanbana DoT # overwrite a DoT modifier due to clipping snapshot_dot_modifier = min(dot_mod*n_targets, # upper limit snapshot_dot_modifier+dot_mod-1.0, # overwrite unbuffed DoT snapshot_dot_modifier+dot_mod-1.0*JINPU_MOD, # overwrite buffed DoTs snapshot_dot_modifier+dot_mod-1.0*JINPU_MOD*KAITEN_MOD) # max out the number of afflicted targets self.applied_higanbana = n_targets # remove Hissatsu: Kaiten buff self.has_hissatsu_kaiten = False # parse abilities if not abilities: # no abilities used, use empty string to fill the ability value parsed_gcds.append((current_time, weaponskill, '', ws_potency + snapshot_dot_modifier*self.higanbana_dot()) + buff_status) else: # parse abilities used parsed_gcds.append((current_time, weaponskill, abilities, ws_potency + sum([getattr(self, ability.lower().translate(translator))(n_targets) for ability in abilities]) + snapshot_dot_modifier*self.higanbana_dot()) + buff_status) if any([ability == 'Meikyo Shisui' for ability in abilities]): # allocate three weaponskills for Meikyo Shisui buff meikyo_shisui_counter = 3 # update counters if parsed_ws not in set(['higanbana', 'tenka goken', 'midare setsugekka']): # Iaijutsu does not consume a Meikyo Shisui charge meikyo_shisui_counter -= 1 # expended one Meikyo Shisui charge if meikyo_shisui_counter <= 0: # deactivate Meikyo Shisui if all charges expended self.has_meikyo_shisui = False if parsed_ws == 'higanbana': # start Higanbana DoT timer # accounts for cast time higanbana_timer = 60 + 1.8/2.5*self.current_gcd if parsed_ws == 'shifu': # start Shifu buff timer shifu_timer = 30 if parsed_ws == 'jinpu': # start Jinpu buff timer jinpu_timer = 30 if parsed_ws == 'yukikaze': # start slashing resistance down timer yukikaze_timer = 30 # update time and timers if self.has_shifu: # Shifu haste buff reduces recast time/GCD self.current_gcd = 0.90*self.base_gcd current_time += self.current_gcd higanbana_timer -= self.current_gcd shifu_timer -= self.current_gcd jinpu_timer -= self.current_gcd yukikaze_timer -= self.current_gcd if higanbana_timer <= 0: # DoT has fallen off n_applied_higanbana = 0 self.applied_higanbana = 0 snapshot_dot_modifier = 0 if shifu_timer <= 0: # Shifu has fallen off self.has_shifu = False if jinpu_timer <= 0: # Jinpu has fallen off self.has_jinpu = False if yukikaze_timer <= 0: # Slashing resistance down has fallen off self.applied_yukikaze = False # form output DataFrame and metrics df = pd.DataFrame(parsed_gcds, columns=['Time', 'Weaponskill', 'Abilities', 'Potency', 'Jinpu', 'Shifu', 'Yukikaze', 'Higanbana', 'Kenki']) df['Total Potency'] = df['Potency'].cumsum(axis=0) average_potency = df['Potency'].mean() potency_ps = df['Total Potency'].max()/current_time print('average potency per GCD = %s' % average_potency) print('average potency per second = %s' % potency_ps) return df, average_potency, potency_ps
@property def base_gcd(self): """The base GCD length in seconds.""" return self._base_gcd @base_gcd.setter def base_gcd(self, value): raise NotImplementedError('The base GCD may only be set in the constructor!') @property def current_gcd(self): """The current GCD length in seconds.""" return self._current_gcd @current_gcd.setter def current_gcd(self, value): if type(value) == float: self._current_gcd = value @property def kenki_mastery(self): """Kenki Mastery trait. 0 if none, 1 if I, 2 if II.""" return self._kenki_mastery @kenki_mastery.setter def kenki_mastery(self, value): raise NotImplementedError('Kenki Mastery may only be set in the constructor!') @property def potency_mod(self): """Potency modifier based on Jinpu buff and slashing resistance down debuff.""" return self._potency_mod @potency_mod.setter def potency_mod(self, value): if type(value) == bool: self._potency_mod = value
[docs] def potency_mod_update(self): """Method to update the potency modifier when weaponskills are used.""" self._potency_mod = 1.0 if self.has_jinpu: self._potency_mod = 1.0*JINPU_MOD if self.applied_yukikaze: self._potency_mod = YUKIKAZE_MOD*self._potency_mod
@property def kenki_gauge(self): """The current Kenki gauge reading.""" return self._kenki_gauge @kenki_gauge.setter def kenki_gauge(self, value): self._kenki_gauge = value
[docs] def inc_kenki_gauge(self, inc_amt): """Changes the Kenki gauge amount by inc_amt.""" if type(inc_amt) == int: self.kenki_gauge += inc_amt if self.kenki_gauge < 0: self.kenki_gauge = 0 elif self.kenki_gauge > 100: self.kenki_gauge = 100 else: raise TypeError('Must provide int to change Kenki gauge by!')
@property def has_jinpu(self): """If the Jinpu buff is active.""" return self._has_jinpu @has_jinpu.setter def has_jinpu(self, value): if type(value) == bool: self._has_jinpu = value @property def has_shifu(self): """If the Shifu buff is active.""" return self._has_shifu @has_shifu.setter def has_shifu(self, value): if type(value) == bool: self._has_shifu = value @property def applied_yukikaze(self): """If the slashing resistance down debuff from Yukikaze is applied.""" return self._applied_yukikaze @applied_yukikaze.setter def applied_yukikaze(self, value): if type(value) == bool: self._applied_yukikaze = value @property def applied_higanbana(self): """Number of targets afflicted with the Higanbana DoT.""" return self._applied_higanbana @applied_higanbana.setter def applied_higanbana(self, n_applied): if type(n_applied) == int: self._applied_higanbana = n_applied @property def has_meikyo_shisui(self): """If the Meikyo Shisui buff is active.""" return self._has_meikyo_shisui @has_meikyo_shisui.setter def has_meikyo_shisui(self, value): if type(value) == bool: self._has_meikyo_shisui = value
[docs] def meikyo_shisui_active(self): """The Meikyo Shisui buff allows combo bonuses without executing combos for up to three weaponskills.""" if self.has_meikyo_shisui: self.combo_act_gekko = True self.combo_act_mangetsu = True self.combo_act_kasha = True self.combo_act_shifu = True self.combo_act_jinpu = True self.combo_act_oka = True self.combo_act_yukikaze = True else: self.combo_act_gekko = False self.combo_act_mangetsu = False self.combo_act_kasha = False self.combo_act_shifu = False self.combo_act_jinpu = False self.combo_act_oka = False self.combo_act_yukikaze = False
@property def has_hissatsu_kaiten(self): """If the Hissatsu: Kaiten buff is active.""" return self._has_hissatsu_kaiten @has_hissatsu_kaiten.setter def has_hissatsu_kaiten(self, value): if type(value) == bool: self._has_hissatsu_kaiten = value @property def has_getsu(self): """If the Getsu Sen is opened.""" return self._has_getsu @has_getsu.setter def has_getsu(self, value): if type(value) == bool: self._has_getsu = value @property def has_ka(self): """If the Ka Sen is opened.""" return self._has_ka @has_ka.setter def has_ka(self, value): if type(value) == bool: self._has_ka = value @property def has_setsu(self): """If the Setsu Sen is opened.""" return self._has_setsu @has_setsu.setter def has_setsu(self, value): if type(value) == bool: self._has_setsu = value @property def combo_act_gekko(self): """If the Gekko combo bonus is applicable.""" return self._combo_act_gekko @combo_act_gekko.setter def combo_act_gekko(self, value): if type(value) == bool: self._combo_act_gekko = value @property def combo_act_mangetsu(self): """If the Mangetsu combo bonus is applicable.""" return self._combo_act_mangetsu @combo_act_mangetsu.setter def combo_act_mangetsu(self, value): if type(value) == bool: self._combo_act_mangetsu = value @property def combo_act_kasha(self): """If the Kasha combo bonus is applicable.""" return self._combo_act_kasha @combo_act_kasha.setter def combo_act_kasha(self, value): if type(value) == bool: self._combo_act_kasha = value @property def combo_act_jinpu(self): """If the Jinpu combo bonus is available.""" return self._combo_act_jinpu @combo_act_jinpu.setter def combo_act_jinpu(self, value): if type(value) == bool: self._combo_act_jinpu = value @property def combo_act_shifu(self): """If the Shifu combo bonus is available.""" return self._combo_act_shifu @combo_act_shifu.setter def combo_act_shifu(self, value): if type(value) == bool: self._combo_act_shifu = value @property def combo_act_oka(self): """If the Oka combo bonus is available.""" return self._combo_act_oka @combo_act_oka.setter def combo_act_oka(self, value): if type(value) == bool: self._combo_act_oka = value @property def combo_act_yukikaze(self): """If the Yukikaze combo bonus is available.""" return self._combo_act_yukikaze @combo_act_yukikaze.setter def combo_act_yukikaze(self, value): if type(value) == bool: self._combo_act_yukikaze = value @property def enhanced_enpi(self): """If the Enhanced Enpi status is active.""" return self._enhanced_enbi @enhanced_enpi.setter def enhanced_enpi(self, value): if type(value) == bool: self._enhanced_enbi = value @property def open_eyes(self): """If the Open Eyes status from Third Eye is active.""" return self._open_eyes @open_eyes.setter def open_eyes(self, value): if type(value) == bool: self._open_eyes = value
[docs] def hakaze(self, n_targets=1): """ lvl 1 Delivers an attack with a potency of 150. **Additional Effect**: Increases Kenki Gauge by 5 """ potency = 150 self.combo_act_yukikaze = True self.combo_act_shifu = True self.combo_act_jinpu = True if self.kenki_mastery == 2: self.inc_kenki_gauge(5) return self.potency_mod*potency
[docs] def jinpu(self, n_targets=1): """ lvl 4 Delivers an attack with a potency of 100. **Combo Action**: Hakaze **Combo Potency**: 280 **Combo Bonus**: Increases damage dealt by 15% **Duration**: 30s **Combo Bonus**: Increases Kenki Gauge by 5 """ if self.combo_act_jinpu: potency = 280 self.has_jinpu = True self.combo_act_gekko = True if self.kenki_mastery == 2: self.inc_kenki_gauge(5) else: potency = 100 potency = self.potency_mod*potency # don't want buff before effect is applied self.combo_act_jinpu = False self.potency_mod_update() return potency
[docs] def gekko(self, n_targets=1): """ lvl 30 Delivers an attack with a potency of 100. **Combo Action**: Jinpu **Combo Potency**: 400 **Rear Combo Bonus**: Increases Kenki Gauge by 10 **Combo Bonus**: Grants Getsu """ if self.combo_act_gekko: potency = 400 self.has_getsu = True if self.kenki_mastery > 0: self.inc_kenki_gauge(5) if self.kenki_mastery > 1: self.inc_kenki_gauge(5) else: potency = 100 self.combo_act_gekko = False return self.potency_mod*potency
[docs] def shifu(self, n_targets=1): """ lvl 18 Delivers an attack with a potency of 100. **Combo Action**: Hakaze **Combo Potency**: 280 **Combo Bonus**: Reduces weaponskill cast time and recast time, spell cast time and recast time, and auto-attack delay by 10% **Duration**: 30s **Combo Bonus**: Increases Kenki Gauge by 5 """ if self.combo_act_shifu: potency = 280 self.has_shifu = True self.combo_act_kasha = True if self.kenki_mastery == 2: self.inc_kenki_gauge(5) else: potency = 100 potency = self.potency_mod*potency # don't want updated potency before effect is applied self.combo_act_shifu = False self.potency_mod_update() return potency
[docs] def kasha(self, n_targets=1): """ lvl 40 Delivers an attack with a potency of 100. **Combo Action**: Shifu **Combo Potency**: 400 **Side Combo Bonus**: Increases Kenki Gauge by 10 **Combo Bonus**: Grants Ka """ if self.combo_act_kasha: potency = 400 self.has_ka = True if self.kenki_mastery > 0: self.inc_kenki_gauge(5) if self.kenki_mastery > 1: self.inc_kenki_gauge(5) else: potency = 100 self.combo_act_kasha = False return self.potency_mod*potency
[docs] def yukikaze(self, n_targets=1): """ lvl 50 Delivers an attack with a potency of 100. **Combo Action**: Hakaze **Combo Potency**: 340 **Combo Bonus**: Reduces target's slashing resistance by 10% **Duration**: 30s **Combo Bonus**: Increases Kenki Gauge by 10 **Combo Bonus**: Grants Setsu """ if self.combo_act_yukikaze: potency = 340 self.applied_yukikaze = True self.has_setsu = True if self.kenki_mastery > 0: self.inc_kenki_gauge(5) if self.kenki_mastery > 1: self.inc_kenki_gauge(5) else: potency = 100 potency = self.potency_mod*potency # don't want updated potency before effect is applied self.combo_act_yukikaze = False self.potency_mod_update() return potency
[docs] def fuga(self, n_targets): """ lvl 26 Delivers an attack with a potency of 100 to all enemies in a cone before you. **Additional Effect**: Increases Kenki Gauge by 5 """ potency = 100 self.combo_act_mangetsu = True self.combo_act_oka = True if self.kenki_mastery == 2: self.inc_kenki_gauge(5) return self.potency_mod*potency*n_targets
[docs] def oka(self, n_targets): """ lvl 45 Delivers an attack with a potency of 100 to all nearby enemies. **Combo Action**: Fuga **Combo Potency**: 200 for the first enemy, 10% less for the second, 20% less for the third, 30% less for the fourth, 40% less for the fifth, and 50% less for all remaining enemies **Combo Bonus**: Increases Kenki Gauge by 10 **Combo Bonus**: Grants Ka """ base_potency = 200 if self.combo_act_oka: if n_targets > 5: potency = base_potency*(1 + 0.9 + 0.8 + 0.7 + 0.6 + 0.5*(n_targets-5)) elif n_targets > 4: potency = base_potency * (1 + 0.9 + 0.8 + 0.7 + 0.6) elif n_targets > 3: potency = base_potency * (1 + 0.9 + 0.8 + 0.7) elif n_targets > 2: potency = base_potency * (1 + 0.9 + 0.8) elif n_targets > 1: potency = base_potency * (1 + 0.9) else: potency = base_potency self.has_ka = True if self.kenki_mastery > 0: self.inc_kenki_gauge(5) if self.kenki_mastery > 1: self.inc_kenki_gauge(5) else: potency = 100 self.combo_act_oka = False return self.potency_mod*potency
[docs] def mangetsu(self, n_targets): """ lvl 35 Delivers an attack with a potency of 100 to all nearby enemies. **Combo Action**: Fuga **Combo Potency**: 200 for the first enemy, 10% less for the second, 20% less for the third, 30% less for the fourth, 40% less for the fifth, and 50% less for all remaining enemies **Combo Bonus**: Increases Kenki Gauge by 10 **Combo Bonus**: Grants Getsu """ base_potency = 200 if self.combo_act_mangetsu: if n_targets > 5: potency = base_potency*(1 + 0.9 + 0.8 + 0.7 + 0.6 + 0.5*(n_targets-5)) elif n_targets > 4: potency = base_potency * (1 + 0.9 + 0.8 + 0.7 + 0.6) elif n_targets > 3: potency = base_potency * (1 + 0.9 + 0.8 + 0.7) elif n_targets > 2: potency = base_potency * (1 + 0.9 + 0.8) elif n_targets > 1: potency = base_potency * (1 + 0.9) else: potency = base_potency self.has_getsu = True if self.kenki_mastery > 0: self.inc_kenki_gauge(5) if self.kenki_mastery > 1: self.inc_kenki_gauge(5) else: potency = 100 self.combo_act_mangetsu = False return self.potency_mod*potency
[docs] def enpi(self, n_targets=1): """ lvl 15 Delivers a ranged attack with a potency of 100. **Yaten Bonus Potency**: 300 **Additional Effect**: Increases Kenki Gauge by 10 """ if self.enhanced_enpi: potency = 300 else: potency = 100 self.enhanced_enpi = False if self.kenki_mastery > 0: self.inc_kenki_gauge(5) if self.kenki_mastery > 1: self.inc_kenki_gauge(5) return self.potency_mod*potency
[docs] def higanbana(self, n_targets=1): """ Delivers an attack with a potency of 240. **Additional Effect**: Damage over time **Potency**: 35 **Duration**: 60s """ if self.has_getsu or self.has_setsu or self.has_ka: potency = 240*self.potency_mod self.has_getsu = False self.has_setsu = False self.has_ka = False else: raise ValueError('No Sen opened!') return potency
[docs] def higanbana_dot(self, n_targets=1): """ DoT component of Higanbana. """ avg_mod = self.current_gcd/3.0 # this averages the DoT potency per GCD (3 second ticks) potency = 35*avg_mod return potency
[docs] def tenka_goken(self, n_targets): """ Delivers an attack to all nearby enemies with a potency of 360 for the first enemy, 10% less for the second, 20% less for the third, 30% less for the fourth, 40% less for the fifth, and 50% less for all remaining enemies. """ base_potency = 360 if sum([self.has_getsu, self.has_setsu, self.has_ka]) == 2: if n_targets > 5: potency = base_potency*(1 + 0.9 + 0.8 + 0.7 + 0.6 + 0.5*(n_targets-5)) elif n_targets > 4: potency = base_potency * (1 + 0.9 + 0.8 + 0.7 + 0.6) elif n_targets > 3: potency = base_potency * (1 + 0.9 + 0.8 + 0.7) elif n_targets > 2: potency = base_potency * (1 + 0.9 + 0.8) elif n_targets > 1: potency = base_potency * (1 + 0.9) else: potency = base_potency else: raise ValueError('Not enough Sen opened!') return self.potency_mod*potency
[docs] def midare_setsugekka(self, n_targets=1): """ Delivers an attack with a potency of 720. """ if sum([self.has_getsu, self.has_setsu, self.has_ka]) == 3: potency = 720 else: raise ValueError('Not enough Sen opened!') return self.potency_mod*potency
[docs] def hissatsu_seigan(self, n_targets=1): """ lvl 66 Delivers an attack with a potency of 200. **Kenki Gauge Cost**: 15 Can only be executed while under the effect of Open Eyes. Shares a recast timer with Merciful Eyes. """ potency = 200 kenki_cost = 25 if self.kenki_gauge >= kenki_cost: if self.open_eyes: return potency*self.potency_mod else: raise ValueError('Open Eyes status not active!') else: raise ValueError('Not enough Kenki available!')
[docs] def third_eye(self): """ lvl 6 **Recast**: 15s Grants the Open Eyes status, reducing the amount of damage taken by the next attack by 20%. **Duration**: 3s """ self.open_eyes = True return 0
[docs] def meditate(self): """ lvl 60 **Recast**: 60s Gradually increases your Kenki Gauge. **Duration**: 15s Kenki Gauge not affected when used outside battle. Cancels auto-attack upon execution. """ self.inc_kenki_gauge(50) return 0
[docs] def merciful_eyes(self): """ lvl 58 **Recast**: 1s Instantly restores own HP. **Cure Potency**: 500 Cure potency varies with current attack power. Can only be executed while under the effect of Open Eyes. Shares a recast timer with Starry Eyes. """ return 0
[docs] def meikyo_shisui(self, n_targets=1): """ lvl 50 **Recast**: 80s Execute up to 3 combos without meeting combo prerequisites. **Duration**: 10s """ self.has_meikyo_shisui = True self.meikyo_shisui_active() return 0
[docs] def ageha(self, n_targets=1): """ lvl 10 **Recast**: 60s Delivers an attack with a potency of 250. **Additional Effect**: Increases Kenki Gauge by 10 If target's HP is 20% or less and killing blow is dealt, Kenki Gauge will increase by 20. *Only available if target's HP is 20% or less* """ potency = 250 self.inc_kenki_gauge(10) return potency*self.potency_mod
[docs] def hagakure(self, n_targets=1): """ lvl 68 **Recast**: 40s Converts Setsu, Getsu, and Ka into Kenki. Each Sen converted increases your Kenki Gauge by 20. Can only be executed if under the effect of at least one of the three statuses. """ sen_total = sum([self.has_setsu + self.has_getsu + self.has_ka]) if sen_total > 0: self.inc_kenki_gauge(sen_total*20) self.has_setsu = False self.has_getsu = False self.has_ka = False else: raise ValueError('No Sen open to convert!') return 0
[docs] def hissatsu_kaiten(self, n_targets=1): """ lvl 52 **Recast**: 5s Increases potency of next weaponskill by 50%. **Duration**: 10s **Kenki Gauge Cost**: 20 """ kenki_cost = 20 if self.kenki_gauge >= kenki_cost: self.has_hissatsu_kaiten = True self.inc_kenki_gauge(-kenki_cost) return 0 else: raise ValueError('Not enough Kenki available!')
[docs] def hissatsu_gyoten(self, n_targets=1): """ lvl 54 **Recast**: 10s Rushes target and delivers an attack with a potency of 100. **Kenki Gauge Cost**: 10 Cannot be executed while bound. """ potency = 100 kenki_cost = 10 if self.kenki_gauge >= kenki_cost: self.inc_kenki_gauge(-kenki_cost) return potency*self.potency_mod else: raise ValueError('Not enough Kenki available!')
[docs] def hissatsu_yaten(self, n_targets=1): """ lvl 56 **Recast**: 10s Delivers an attack with a potency of 100. **Additional Effect**: 10-yalm backstep **Additional Effect**: Grants Enhanced Enpi **Kenki Gauge Cost**: 10 Cannot be executed while bound. """ potency = 100 kenki_cost = 10 if self.kenki_gauge >= kenki_cost: self.inc_kenki_gauge(-kenki_cost) self.enhanced_enbi = True return potency * self.potency_mod else: raise ValueError('Not enough Kenki available!')
[docs] def hissatsu_shinten(self, n_targets=1): """ lvl 62 **Recast**: 1s Delivers an attack with a potency of 300. **Kenki Gauge Cost**: 25 """ potency = 300 kenki_cost = 25 if self.kenki_gauge >= kenki_cost: self.inc_kenki_gauge(-kenki_cost) return potency * self.potency_mod else: raise ValueError('Not enough Kenki available!')
[docs] def hissatsu_kyuten(self, n_targets): """ lvl 64 **Recast**: 1s Delivers an attack with a potency of 150 to all nearby enemies. **Kenki Gauge Cost**: 25 """ potency = n_targets*150 kenki_cost = 25 if self.kenki_gauge >= kenki_cost: self.inc_kenki_gauge(-kenki_cost) return potency * self.potency_mod else: raise ValueError('Not enough Kenki available!')
[docs] def hissatsu_guren(self, n_targets): """ lvl 70 **Recast**: 120s Delivers an attack to all enemies in a straight line before you with a potency of 800 for the first enemy, 25% less for the second, and 50% less for all remaining enemies. **Kenki Gauge Cost**: 50 """ base_potency = 800 kenki_cost = 50 if self.kenki_gauge >= kenki_cost: self.inc_kenki_gauge(-kenki_cost) if n_targets > 2: potency = base_potency*(1+0.75+0.50*(n_targets-2)) elif n_targets > 1: potency = base_potency*(1+0.75) else: potency = base_potency return potency * self.potency_mod else: raise ValueError('Not enough Kenki available!')