def __init__(self, name=None, group=None, buffs=None, duration=-1, **kwargs): buffs = buffs or [] self.group = group self.alt = {} pause = kwargs.get('pause') timed_mode = bool(duration != -1 and pause) for k, buffclass in ModeManager.ALT_CLASS.items(): if kwargs.get(k, False): if k in ('s1', 's2'): self.alt[k] = buffclass(group=group, duration=duration, base=k, timed_mode=timed_mode) elif k in ('x'): self.alt[k] = buffclass(group=group, duration=duration, deferred=(kwargs.get('deferred', False))) else: self.alt[k] = buffclass(group=group, duration=duration) buffs.extend(self.alt.values()) super().__init__(name, buffs, duration, timed_mode=timed_mode) if timed_mode: self.pause_by = group if 's' in pause: self.l_s = Listener('s', self.pause, order=0).on() self.l_s_end = Listener('s_end', self.resume, order=0).on() if 'dragon' in pause: self.l_dragon = Listener('dragon', self.pause, order=0).on() self.l_dragon_end = Listener('dragon_end', self.resume, order=0).on() for b in self.buffs: b.no_bufftime()
def __init__(self, name=None, group=None, duration=-1, uses=-1, hidden=False, source=None): self.default_fs = self.adv.current_fs self.group = group pattern = r'^fs\d+$' if group is None else f'^fs\d*_{group}$' self.fs_list = [fsn for fsn, _ in self.adv.conf.find(pattern)] if not self.fs_list: if group is None: raise ValueError(f'fs[n] not found in conf') raise ValueError(f'{self.group} is not an FS') super().__init__(self.group or 'fs[n]', duration=duration, hidden=hidden, source=source) self.enable_fs(False) self.base_uses = uses self.uses = 0 self.l_fs = Listener('fs', self.l_off, order=2) self.managed = False
def __init__(self, name=None, group=None, buffs=None, duration=-1, **kwargs): buffs = buffs or [] self.group = group self.alt = {} pause = kwargs.get("pause") timed_mode = bool(duration != -1 and pause) for k, buffclass in ModeManager.ALT_CLASS.items(): if kwargs.get(k, False): if k in ("s1", "s2"): self.alt[k] = buffclass(group=group, duration=duration, base=k, timed_mode=timed_mode, hidden=True) elif k in ("x"): self.alt[k] = buffclass(group=group, duration=duration, deferred=(kwargs.get("deferred", False)), hidden=True) else: self.alt[k] = buffclass(group=group, duration=duration, hidden=True) buffs.extend(self.alt.values()) super().__init__(name, buffs, duration, timed_mode=timed_mode) if timed_mode: self.pause_by = group if "s" in pause: self.l_s = Listener("s", self.pause, order=0).on() self.l_s_end = Listener("s_end", self.resume, order=0).on() if "dragon" in pause: self.l_dragon = Listener("dragon", self.pause, order=0).on() self.l_dragon_end = Listener("dragon_end", self.resume, order=0).on() if not kwargs.get("source"): for b in self.buffs: b.no_bufftime() else: for b in self.buffs: b.source = kwargs.get("source")
def __init__( self, name=None, group=None, base=None, duration=-1, uses=-1, hidden=False, source=None, timed_mode=False, ): if base not in ("s1", "s2", "s3", "s4"): raise ValueError(f"{base} is not a skill") if group not in self.adv.a_s_dict[base].act_dict.keys(): raise ValueError(f"{base}-{group} is not a skill") super().__init__(f"{base}_{group}", duration=duration, hidden=hidden, source=source) self.base = base self.group = group self.default_s = self.adv.current_s[base] if group == "ddrive": self.l_s = Listener("s", self.l_add_ddrive, order=0).on() elif duration != -1 and not timed_mode: self.l_s = Listener("s", self.l_pause, order=0).on() self.l_s_end = Listener("s_end", self.l_resume, order=0).on() self.enable_s(True) self.base_uses = uses self.uses = 0 self.l_end = Listener("s", self.l_off, order=2)
def __init__(self, name=None, group=None, duration=-1, uses=-1, hidden=False, source=None): self.default_fs = self.adv.current_fs self.group = group pattern = r"^fs\d+$" if group is None else f"^fs\d*_{group}$" self.fs_list = [fsn for fsn, _ in self.adv.conf.find(pattern)] if not self.fs_list: if group is None: raise ValueError(f"fs[n] not found in conf") raise ValueError(f"{self.group} is not an FS") super().__init__( f"fs_{self.group}" if self.group else "fs[n]", duration=duration, hidden=hidden, source=source, ) self.enable_fs(False) self.base_uses = uses self.uses = 0 self.l_fs = Listener("fs", self.l_off, order=2) self.managed = False
def __init__(self, adv, name, conf, x_proc=None, no_fs=False, no_dodge=False): self.conf = Conf(conf) self.adv = adv self.name = name self.x_og = adv.x self.a_x_alt = {} self.x_proc = x_proc or self.x_proc_default self.l_x_alt = Listener("x", self.l_x).off() self.no_fs = no_fs self.no_dodge = no_dodge self.fs_og = adv.fs self.dodge_og = adv.dodge self.xmax = 1 n = "x{}".format(self.xmax) while n in self.conf: self.a_x_alt[self.xmax] = X((n, self.xmax), self.conf[n]) self.xmax += 1 n = "x{}".format(self.xmax) self.xmax -= 1 self.active = False self.xstart = None self.zeroed = None
def __init__(self, name, conf, adv, dragon): utp_params = adv.conf.c.utp # dform_modes # 0: ddrive as adventurer # 1: ddrive as dragon # 2: ddrive as adventurer, with servant super().__init__(name, conf, adv, dragon, dform_mode=utp_params[0], unique_dform=True) self.shift_mods = [] self.shift_cost = 0 self.utp_gauge = 0 self.ds_final = None self.max_utp_gauge = utp_params[1] self.utp_shift_req = utp_params[2] self.utp_drain = utp_params[3] self.utp_infinte = False self.utp_event = Event("utp") self.log_utp = True if self.dform_mode == 1: g_logs.log_dact_as_act = True for ds in self.shift_skills: try: del self.adv.conf[ds]["uses"] except KeyError: pass else: self.ddrive_fs_list = [fsn for fsn, _ in self.adv.conf.find(f"^fs\d*_{DDRIVE}$")] self.shift_skills = [sn.split("_")[0] for sn, _ in self.adv.conf.find(f"^s\d*_{DDRIVE}$")] self.l_ddrive_end = Listener("act_end", self.d_dragondrive_end, order=0) self.l_ddrive_end.off() self.ddrive_end_reason = None
class X_alt: def __init__(self, adv, name, conf, x_proc=None, no_fs=False): self.conf = Conf(conf) self.adv = adv self.name = name self.x_og = adv.x self.a_x_alt = {} if x_proc: self.x_proc = x_proc self.l_x_alt = Listener('x', self.l_x).off() else: self.l_x_alt = None self.no_fs = no_fs self.fs_og = adv.fs self.xmax = 1 n = 'x{}'.format(self.xmax) while n in self.conf: self.a_x_alt[n] = X((n, self.xmax), self.conf[n]) self.xmax += 1 n = 'x{}'.format(self.xmax) self.xmax -= 1 self.active = False def x_alt(self): x_prev = self.adv.action.getprev() if x_prev.name in self.a_x_alt and x_prev.index < self.xmax: x_next = self.a_x_alt['x{}'.format(x_prev.index + 1)] else: x_next = self.a_x_alt['x{}'.format(1)] return x_next() def l_x(self, e): self.x_proc(e) self.adv.think_pin('x') def fs_off(self): return False def on(self): log('debug', '{} x_alt on'.format(self.name)) self.active = True self.adv.x = self.x_alt if self.l_x_alt: self.adv.l_x.off() self.l_x_alt.on() if self.no_fs: self.adv.fs = self.fs_off def off(self): log('debug', '{} x_alt off'.format(self.name)) self.active = False self.adv.x = self.x_og if self.l_x_alt: self.l_x_alt.off() self.adv.l_x.on() if self.no_fs: self.adv.fs = self.fs_og
class FSAltBuff(ModeAltBuff): def __init__(self, name=None, group=None, duration=-1, uses=-1, hidden=False, source=None): self.default_fs = self.adv.current_fs self.group = group pattern = r'^fs\d+$' if group is None else f'^fs\d*_{group}$' self.fs_list = [fsn for fsn, _ in self.adv.conf.find(pattern)] if not self.fs_list: if group is None: raise ValueError(f'fs[n] not found in conf') raise ValueError(f'{self.group} is not an FS') super().__init__(self.group or 'fs[n]', duration=duration, hidden=hidden, source=source) self.enable_fs(False) self.base_uses = uses self.uses = 0 self.l_fs = Listener('fs', self.l_off, order=2) self.managed = False def enable_fs(self, enabled): for fsn in self.fs_list: self.adv.a_fs_dict[fsn].set_enabled(enabled) def effect_on(self): # self.logwrapper(f'fs-{self.name} on', self.uses) self.enable_fs(True) self.adv.current_fs = self.group self.adv.alt_fs_buff = self self.l_fs.on() def effect_off(self): # self.logwrapper(f'fs-{self.name} off', self.uses) self.enable_fs(False) self.adv.current_fs = self.default_fs self.adv.alt_fs_buff = None self.l_fs.off() def on(self, duration=None): self.uses = self.base_uses return super().on(duration) def l_off(self, e): if e.group == self.group and self.uses > 0: self.uses -= 1 if self.uses <= 0: super().off()
class SAltBuff(ModeAltBuff): def __init__(self, name=None, group=None, base=None, duration=-1, uses=-1, hidden=False, source=None, timed_mode=False): if base not in ('s1', 's2', 's3', 's4'): raise ValueError(f'{base} is not a skill') if group not in self.adv.a_s_dict[base].act_dict.keys(): raise ValueError(f'{base}-{group} is not a skill') super().__init__(f'{base}_{group}', duration=duration, hidden=hidden, source=source) self.base = base self.group = group self.default_s = self.adv.current_s[base] if group == 'ddrive': self.l_s = Listener('s', self.l_add_ddrive, order=0).on() elif duration != -1 and not timed_mode: self.l_s = Listener('s', self.l_pause, order=0).on() self.l_s_end = Listener('s_end', self.l_resume, order=0).on() self.enable_s(True) self.base_uses = uses self.uses = 0 self.l_end = Listener('s', self.l_off, order=2) def enable_s(self, enabled): for s in self.adv.a_s_dict.values(): s.enabled = enabled def effect_on(self): # self.logwrapper(f'{self.name} on') self.adv.current_s[self.base] = self.group self.uses = self.base_uses self.l_end.on() def effect_off(self): # self.logwrapper(f'{self.name} off', self.default_s) self.adv.current_s[self.base] = self.default_s self.l_end.off() def l_extend_time(self, e): if self.get() and e.name != 'ds' and e.base == self.base and e.group == self.group: skill = self.adv.a_s_dict[self.base] delta = (skill.ac.getstartup() + skill.ac.getrecovery()) / self.adv.speed() self.add_time(delta) log('debug', e.name, 'extend', delta) def l_pause(self, e): if self.get() and e.base == self.base and e.group == self.group: self.pause() def l_resume(self, e): if self.get() and e.act.base == self.base and e.act.group == self.group: self.resume() def l_add_ddrive(self, e): if self.get() and e.base == self.base and e.group == self.group: skill = self.adv.a_s_dict[self.base] self.adv.dragonform.add_drive_gauge_time(skill.ac.getstartup() + skill.ac.getrecovery(), skill_pause=True)
def __init__(self, name=None, group=None, base=None, duration=-1, hidden=False): if base not in ('s1', 's2', 's3', 's4'): raise ValueError(f'{base} is not a skill') if group not in self.adv.a_s_dict[base].act_dict.keys(): raise ValueError(f'{base}-{group} is not a skill') super().__init__(f'{base}_{group}', duration=duration, hidden=hidden) self.base = base self.group = group self.default_s = self.adv.current_s[base] if group == 'ddrive': self.l_s = Listener('s', self.l_add_ddrive, order=0).on() elif duration != -1: self.l_s = Listener('s', self.l_extend_time, order=0).on() self.enable_s(True)
class DrainBuff(Buff): def __init__(self, name, value=0, duration=0, source=None): super().__init__(name, 1, duration, "effect", source=source) self.drain = value self.drain_listener = Listener("dmg_made", self.l_drain) def effect_on(self): self.drain_listener.on() def effect_off(self): self.drain_listener.off() def l_drain(self, e): if e.name != "echo": self._static.adv.add_hp(self.drain * e.count, percent=False)
def do_config(self, conf): if self.l_fs: self.l_fs = Listener("fs", self.l_fs).off() # fsns = [n for n, c in conf.items() if self.pattern_fsn.match(n)] fsns = list(filter(self.pattern_fsn.match, conf.keys())) for fsn in fsns: self._set_attr_f(fsn, conf) if len(fsns) > 1: self.a_fs_alt = lambda before: None for pattern in self.patterns: self._back_up(pattern)
def __init__(self, adv, name, conf, x_proc=None, no_fs=False): self.conf = Conf(conf) self.adv = adv self.name = name self.x_og = adv.x self.a_x_alt = {} if x_proc: self.x_proc = x_proc self.l_x_alt = Listener('x', self.l_x).off() else: self.l_x_alt = None self.no_fs = no_fs self.fs_og = adv.fs self.xmax = 1 n = 'x{}'.format(self.xmax) while n in self.conf: self.a_x_alt[n] = X((n, self.xmax), self.conf[n]) self.xmax += 1 n = 'x{}'.format(self.xmax) self.xmax -= 1 self.active = False
def __init__(self, name, conf, adv, dragon, dform_mode=-1, unique_dform=False): self.name = name self.conf = conf self.adv = adv self.dragon = dragon self.dform_mode = dform_mode self.unique_dform = unique_dform self.shift_start_proc = None self.shift_end_proc = None self.config_actions() # events self.status = False self.disabled_reasons = set() self.dp_event = Event("dp") self.shift_end_timer = Timer(self.d_shift_end) self.shift_silence_timer = Timer(None, 10) self.can_end = True self.l_shift = Listener("dshift", self.d_shift_start, order=2) self.l_s = Listener("s", self.l_ds_pause, order=0) self.l_s_end = Listener("s_end", self.l_ds_resume, order=0) self.l_s_final_end = Listener("s_end", self.d_shift_end, order=0) self.l_s.off() self.l_s_end.off() self.l_s_final_end.off() self.shift_skills = ("ds1", "ds2") self.allow_end_cd = self.conf.allow_end + self.dstime() self.shift_end_reason = None # mods self.dracolith_mod = self.adv.Modifier("dracolith", "ex", "dragon", 0) self.dracolith_mod.get = self.ddamage self.dracolith_mod.off() self.shift_mods = [self.dracolith_mod] self.shift_spd_mod = None self.off_ele = self.adv.slots.c.ele != self.conf.d.ele self.previous_x = DEFAULT # gauge self.auto_gauge_val = 0.1 # percent self.auto_gauge_iv = min(int(self.adv.duration / 12), 15) self.dragon_gauge_timer = Timer(self.auto_gauge, timeout=max(1, self.auto_gauge_iv), repeat=1).on() self.dragon_gauge_pause_timer = None self.dragon_gauge_timer_diff = 0 self.dragon_gauge = 0 self.max_dragon_gauge = 1000 self.shift_cost = 500 self.log_utp = False # dragonbattle self.is_dragonbattle = False
class X_alt: def __init__(self, adv, name, conf, x_proc=None, no_fs=False, no_dodge=False): self.conf = Conf(conf) self.adv = adv self.name = name self.x_og = adv.x self.a_x_alt = {} if x_proc: self.x_proc = x_proc self.l_x_alt = Listener('x', self.l_x).off() else: self.l_x_alt = None self.no_fs = no_fs self.no_dodge = no_dodge self.fs_og = adv.fs self.dodge_og = adv.dodge self.xmax = 1 n = 'x{}'.format(self.xmax) while n in self.conf: self.a_x_alt[self.xmax] = X((n, self.xmax), self.conf[n]) self.xmax += 1 n = 'x{}'.format(self.xmax) self.xmax -= 1 self.active = False self.xstart = None self.zeroed = None def x_alt(self): x_prev = self.adv.action.getprev() if x_prev in self.a_x_alt.values() and x_prev.index < self.xmax: x_seq = x_prev.index + 1 else: x_seq = 1 return self.a_x_alt[x_seq]() def l_x(self, e): self.x_proc(e) self.adv.think_pin('x') def act_off(self): return False def on(self): if not self.active: if self.zeroed is not None: self.zeroed[0].index = self.zeroed[1] self.zeroed = None act = self.a_x_alt[1] doing = act._static.doing if not doing.idle and doing.status == -1: doing.startup_timer.off() doing._setprev() doing._static.doing = doing.nop act() log('debug', '{} x_alt on'.format(self.name)) self.active = True self.adv.x = self.x_alt if self.l_x_alt: self.adv.l_x.off() self.l_x_alt.on() if self.no_fs: self.adv.fs = self.act_off if self.no_dodge: self.adv.dodge = self.act_off def off(self): if self.active: log('debug', '{} x_alt off'.format(self.name)) self.active = False self.adv.x = self.x_og if self.l_x_alt: self.l_x_alt.off() self.adv.l_x.on() if self.no_fs: self.adv.fs = self.fs_og if self.no_dodge: self.adv.dodge = self.dodge_og doing = self.a_x_alt[1]._static.doing self.zeroed = (doing, doing.index) doing.index = 0
class DragonForm: def __init__(self, name, conf, adv, dragon, dform_mode=-1, unique_dform=False): self.name = name self.conf = conf self.adv = adv self.dragon = dragon self.dform_mode = dform_mode self.unique_dform = unique_dform self.shift_start_proc = None self.shift_end_proc = None self.config_actions() # events self.status = False self.disabled_reasons = set() self.dp_event = Event("dp") self.shift_end_timer = Timer(self.d_shift_end) self.shift_silence_timer = Timer(None, 10) self.can_end = True self.l_shift = Listener("dshift", self.d_shift_start, order=2) self.l_s = Listener("s", self.l_ds_pause, order=0) self.l_s_end = Listener("s_end", self.l_ds_resume, order=0) self.l_s_final_end = Listener("s_end", self.d_shift_end, order=0) self.l_s.off() self.l_s_end.off() self.l_s_final_end.off() self.shift_skills = ("ds1", "ds2") self.allow_end_cd = self.conf.allow_end + self.dstime() self.shift_end_reason = None # mods self.dracolith_mod = self.adv.Modifier("dracolith", "ex", "dragon", 0) self.dracolith_mod.get = self.ddamage self.dracolith_mod.off() self.shift_mods = [self.dracolith_mod] self.shift_spd_mod = None self.off_ele = self.adv.slots.c.ele != self.conf.d.ele self.previous_x = DEFAULT # gauge self.auto_gauge_val = 0.1 # percent self.auto_gauge_iv = min(int(self.adv.duration / 12), 15) self.dragon_gauge_timer = Timer(self.auto_gauge, timeout=max(1, self.auto_gauge_iv), repeat=1).on() self.dragon_gauge_pause_timer = None self.dragon_gauge_timer_diff = 0 self.dragon_gauge = 0 self.max_dragon_gauge = 1000 self.shift_cost = 500 self.log_utp = False # dragonbattle self.is_dragonbattle = False def set_dragonbattle(self): self.is_dragonbattle = True if self.dform_mode == 0: # ddrive chara cant do dragon battle self.adv.stop() return for skey in self.shift_skills: self.adv.a_s_dict[skey].dragonbattle_skill = True self.dragon_gauge += self.shift_cost g_logs.log_dact_as_act = True def config_actions(self): # merge confs into adv conf self.dx_max = 0 for dx, dxconf in self.conf.find(r"^dx\d+$"): self.adv.conf[dx] = dxconf self.dx_max = max(self.dx_max, int(dx[2:])) self.default_x_loop = self.conf["default_x_loop"] or self.dx_max # the default combo idx to end combo on for fs, fsconf in self.conf.find(r"^dfs\d*(_[A-Za-z0-9]+)?$"): self.adv.conf[fs] = fsconf if not self.unique_dform: for sfn in ("before", "proc"): self.adv.rebind_function(self.dragon, f"{fs}_{sfn}", f"{fs}_{sfn}", overwrite=False) self.ds_final = None for ds, dsconf in self.conf.find(r"^ds\d*(_[A-Za-z0-9]+)?$"): self.adv.conf[ds] = dsconf ds_base = ds.split("_")[0] if not self.unique_dform: for sfn in ("before", "proc"): self.adv.rebind_function(self.dragon, f"{ds_base}_{sfn}", f"{ds_base}_{sfn}", overwrite=False) if ds.startswith("ds99") or dsconf.get("final"): self.ds_final = ds.split("_")[0] # make separate dodge action, may want to handle forward/backward later self.d_dodge = Dodge("dodge", self.conf.dodge) self.d_shift = Shift("dshift", self.name, self.conf.dshift) self.d_end = Shift("dend", self.name, self.conf.dend) self.shift_event = Event("dragon") self.end_event = Event("dragon_end") if abs(self.dform_mode) == 1: try: self.shift_start_proc = self.dragon.shift_start_proc except AttributeError: pass try: self.shift_end_proc = self.dragon.shift_end_proc except AttributeError: pass def in_dform(self): return self.status def in_ddrive(self): return False @property def shift_silence(self): return bool(self.shift_silence_timer.online) def set_disabled(self, reason): if self.disabled_reasons is not None: self.disabled_reasons.add(reason) def unset_disabled(self, reason): if self.disabled_reasons is not None: self.disabled_reasons.discard(reason) @property def disabled(self): return bool(self.disabled_reasons) def set_dacts_enabled(self, enabled): for xact in self.adv.a_x_dict[DRG].values(): xact.enabled = enabled fsact = self.adv.a_fs_dict.get("dfs") if fsact: fsact.set_enabled(enabled) for skey in self.shift_skills: self.adv.a_s_dict[skey].set_enabled(enabled) def auto_dodge(self, index=None): index = index or self.dx_max d_combo = self.adv.a_x_dict[DRG][index] if "dodge" not in d_combo.conf.cancel: return False dodge_t = d_combo.conf.cancel["dodge"] + self.d_dodge.getstartup() + self.d_dodge.getrecovery() if d_combo.conf.cancel["dx1"]: combo_t = d_combo.conf.cancel["dx1"] / d_combo.speed() else: combo_t = d_combo.getrecovery() return dodge_t < combo_t def dx_dodge_or_wait(self, index): # log("dx_dodge_or_skill", "x{}: c on {}, s on {}".format(index, self.default_ds_x, self.default_x_loop), self.adv.ds1.check()) if index == self.default_x_loop: return self.d_dodge if self.auto_dodge(index=index) else False return False def pause_auto_gauge(self): if self.is_dragonbattle: return if self.dragon_gauge_pause_timer is None: self.dragon_gauge_timer_diff = self.dragon_gauge_timer.timing - now() else: self.dragon_gauge_timer_diff = self.dragon_gauge_pause_timer.timing - now() self.dragon_gauge_timer.off() def resume_auto_gauge(self, t): self.dragon_gauge_pause_timer = None self.auto_gauge(t) self.dragon_gauge_timer.on() def l_ds_pause(self, e): if self.status and e.base in self.shift_skills: self.shift_end_timer.pause() log("shift_end_timer", "pause", self.shift_end_timer.timing, self.shift_end_timer.pause_time) def l_ds_resume(self, e): if self.status and e.act.base in self.shift_skills: self.shift_end_timer.resume() log("shift_end_timer", "resume", self.shift_end_timer.timing, self.shift_end_timer.timing - now()) @allow_acl def dtime(self): return self.conf.duration * self.adv.mod("dt") + self.conf.exhilaration * int(not self.off_ele) def dstime(self): try: return (self.conf.ds.startup + self.conf.ds.recovery) / self.d_shift.speed() except TypeError: return 0 def reset_allow_end(self): self.allow_force_end_timer = Timer(None, timeout=self.allow_end_cd) self.allow_force_end_timer.on() self.allow_end_cd = min(self.allow_end_cd + self.conf.allow_end_step, self.dtime()) @property def allow_end(self): return not bool(self.allow_force_end_timer.online) def dhaste(self): return self.adv.mod("dh", operator=operator.add) def _charge_dp(self, name, value): gauge_before = self.dragon_gauge self.dragon_gauge = max(0, min(self.max_dragon_gauge, self.dragon_gauge + value)) delta = self.dragon_gauge - gauge_before if delta != 0 and not self.log_utp: log( "dgauge", name, f"{int(delta):+}", f"{int(self.dragon_gauge)}/{int(self.max_dragon_gauge)} [{self.dragon_gauge//self.shift_cost}]", ) self.dp_event.name = name self.dp_event.value = value self.dp_event.delta = delta self.dp_event.gauge = self.dragon_gauge self.dp_event() return value def charge_dprep(self, value): return self._charge_dp("dprep", float_ceil(self.max_dragon_gauge, value / 100)) def charge_dp(self, name, value): return self._charge_dp(name, float_ceil(value, self.dhaste())) def auto_gauge(self, t): self._charge_dp("auto", float_ceil(self.max_dragon_gauge * self.auto_gauge_val, self.dhaste())) @allow_acl def ddamage(self): return self.conf.dracolith + self.adv.mod("da", operator=operator.add, initial=0) def extend_shift_time(self, value, percent=True): max_d = self.dtime() - self.conf.dshift.startup cur_d = self.shift_end_timer.timeleft() delta_t = value if percent: delta_t *= max_d delta_t = min(max_d, cur_d + delta_t) - cur_d if cur_d + delta_t > 0: self.shift_end_timer.add(delta_t) log("shift_time", f"{delta_t:+2.4}", f"{cur_d+delta_t:2.4}") elif self.can_end: self.d_shift_end() self.shift_end_timer.off() def d_shift_start(self, _=None): self.status = True self.dragon_gauge -= self.shift_cost g_logs.set_log_shift(shift_name=self.name) if self.shift_start_proc: self.shift_start_proc() if self.off_ele: self.adv.element = self.adv.slots.d.ele if self.shift_spd_mod is not None: self.shift_spd_mod.on() self.pause_auto_gauge() for s in self.adv.dskills: s.reset_uses() self.adv.set_dacl(True) self.l_s.on() self.l_s_end.on() self.set_dacts_enabled(True) self.adv.charge_p("dshift", 1.0, dragon_sp=True) log("shift_end_timer", "on", self.dtime()) self.shift_end_timer.on(self.dtime()) self.reset_allow_end() self.shift_event() def d_shift_end(self, e=None, reason="timeout"): if not self.status or self.is_dragonbattle: return False doing = self.d_shift.getdoing() if self.ds_final and not (isinstance(doing, S) and doing.base in self.shift_skills) and not self.l_s_final_end.get(): ds_final = self.adv.a_s_dict[self.ds_final] if ds_final.ac.conf.final and ds_final.ac.enabled: self.shift_end_reason = reason self.l_s_final_end.on() ds_final.reset_uses() ds_final.charged = ds_final.sp ds_final() self.set_dacts_enabled(False) return False if self.off_ele: self.adv.element = self.adv.slots.c.ele if self.shift_spd_mod is not None: self.shift_spd_mod.off() self.shift_silence_timer.on() if self.dragon_gauge_timer_diff > 0: self.dragon_gauge_pause_timer = Timer(self.resume_auto_gauge).on(self.dragon_gauge_timer_diff) self.l_s.off() self.l_s_end.off() self.l_s_final_end.off() self.set_dacts_enabled(False) self.adv.set_dacl(False) self.end_event() self.d_end() self.status = False g_logs.set_log_shift(end_reason=self.shift_end_reason or reason) self.shift_end_reason = None if self.shift_end_proc: self.shift_end_proc() return True def d_shift_partial_end(self): if self.status and abs(self.dform_mode) == 1: g_logs.set_log_shift(end_reason="partial") @allow_acl def check(self): if self.disabled_reasons or self.shift_silence: return False if self.dragon_gauge < self.shift_cost: return False if self.status: return False doing = self.d_shift.getdoing() if not doing.idle: if isinstance(doing, S): return False return True def shift(self): if not self.check(): return False return self.d_shift() def sack(self): if self.status and not self.l_s_final_end.get() and self.allow_end: self.d_shift_end(reason="forced") self.shift_end_timer.off() return True return False
class DragonFormUTP(DragonForm): def __init__(self, name, conf, adv, dragon): utp_params = adv.conf.c.utp # dform_modes # 0: ddrive as adventurer # 1: ddrive as dragon # 2: ddrive as adventurer, with servant super().__init__(name, conf, adv, dragon, dform_mode=utp_params[0], unique_dform=True) self.shift_mods = [] self.shift_cost = 0 self.utp_gauge = 0 self.ds_final = None self.max_utp_gauge = utp_params[1] self.utp_shift_req = utp_params[2] self.utp_drain = utp_params[3] self.utp_infinte = False self.utp_event = Event("utp") self.log_utp = True if self.dform_mode == 1: g_logs.log_dact_as_act = True for ds in self.shift_skills: try: del self.adv.conf[ds]["uses"] except KeyError: pass else: self.ddrive_fs_list = [fsn for fsn, _ in self.adv.conf.find(f"^fs\d*_{DDRIVE}$")] self.shift_skills = [sn.split("_")[0] for sn, _ in self.adv.conf.find(f"^s\d*_{DDRIVE}$")] self.l_ddrive_end = Listener("act_end", self.d_dragondrive_end, order=0) self.l_ddrive_end.off() self.ddrive_end_reason = None def in_dform(self): return self.dform_mode == 1 and self.status def in_ddrive(self): return self.status def set_utp_infinite(self): self.utp_infinte = True self.utp_gauge = self.max_utp_gauge def utphaste(self): return self.dhaste() + self.adv.mod("utph", operator=operator.add, initial=0) def _charge_utp(self, name, value): # sync with timer value if self.utp_infinte: self.utp_gauge = self.max_utp_gauge if self.status: self.utp_gauge = self.shift_end_timer.timeleft() * self.utp_drain gauge_before = self.utp_gauge # use utp_gauge from here on self.utp_gauge = max(0, min(self.max_utp_gauge, gauge_before + value)) delta = self.utp_gauge - gauge_before if delta != 0: if self.log_utp: log( "utpgauge", name, f"{int(delta):+} ({delta/self.utp_drain:+2.4}s)", f"{int(self.utp_gauge)}/{int(self.max_utp_gauge)} ({self.dtime():2.4}s)", ) if self.utp_gauge <= 0: self.utp_gauge = 0 self.d_shift_end(reason="gauge deplete") else: self.shift_end_timer.add(delta / self.utp_drain) self.utp_event.name = name self.utp_event.value = value self.utp_event.delta = delta self.utp_event.gauge = self.utp_gauge self.utp_event() return value def charge_dprep(self, value): return self._charge_utp("dprep", super().charge_dprep(value)) def charge_dp(self, name, value): return self._charge_utp(name, super().charge_dp(name, value)) def charge_utp(self, name, value): if value > 0: value = float_ceil(value, self.utphaste()) return self._charge_utp(name, value) def charge_utprep(self, name, value): return self._charge_utp(name, float_ceil(self.max_utp_gauge, value / 100)) def auto_gauge(self, t): super().auto_gauge(t) self._charge_utp("auto", float_ceil(self.max_dragon_gauge * self.auto_gauge_val, self.utphaste())) def config_actions(self): if self.dform_mode == 1: return super().config_actions() # should maybe take the actual shift action from the modes self.name = "Dragondrive" self.d_shift = Shift("dshift", self.name, self.conf.dshift) self.shift_event = Event("dragondrive") self.end_event = Event("dragondrive_end") def set_dacts_enabled(self, enabled): if self.dform_mode == 1: return super().set_dacts_enabled(enabled) # ddrive try: for _, xact in self.adv.a_x_dict[DDRIVE].items(): xact.enabled = enabled if enabled: self.previous_x = self.adv.current_x self.adv.current_x = DDRIVE else: self.adv.current_x = self.previous_x except KeyError: pass if self.ddrive_fs_list: for fsn in self.ddrive_fs_list: self.adv.a_fs_dict[fsn].set_enabled(enabled) self.adv.current_fs = DDRIVE if enabled else DEFAULT if self.shift_skills: for sn in self.shift_skills: if DDRIVE in self.adv.a_s_dict[sn].act_dict: self.adv.current_s[sn] = DDRIVE if enabled else DEFAULT def dtime(self): return self.utp_gauge / self.utp_drain @allow_acl def check(self): if self.utp_gauge < self.utp_shift_req: return False return super().check() def d_dragondrive_start(self): self.status = True self.set_dacts_enabled(True) self.adv.set_dacl(True) self.l_s.on() self.l_s_end.on() self.l_ddrive_end.on() self.shift_end_timer.on(self.dtime()) self.shift_event() log("dragondrive", "start", self.dtime()) def d_shift_start(self, _=None): if self.dform_mode == 1: super().d_shift_start() else: self.d_dragondrive_start() if self.utp_infinte: self.shift_end_timer.off() self.l_s.off() self.l_s_end.off() def d_dragondrive_end(self, _=None): if self.ddrive_end_reason is not None: self.l_s.off() self.l_s_end.off() self.l_ddrive_end.off() self.shift_silence_timer.on() self.set_dacts_enabled(False) self.adv.set_dacl(False) self.status = False log("dragondrive", "end", self.ddrive_end_reason) self.end_event() self.ddrive_end_reason = None return True return False def pause_auto_gauge(self): pass def reset_allow_end(self): pass def d_shift_end(self, e=None, reason="timeout"): if not self.status: return False if reason == "timeout": self.utp_gauge = 0 if self.dform_mode == 1: return super().d_shift_end(e=e, reason=reason) self.ddrive_end_reason = reason return False
def __init__(self, name, value=0, duration=0, source=None): super().__init__(name, 1, duration, "effect", source=source) self.drain = value self.drain_listener = Listener("dmg_made", self.l_drain)
class X_alt: def __init__(self, adv, name, conf, x_proc=None, no_fs=False, no_dodge=False): self.conf = Conf(conf) self.adv = adv self.name = name self.x_og = adv.x self.a_x_alt = {} self.x_proc = x_proc or self.x_proc_default self.l_x_alt = Listener("x", self.l_x).off() self.no_fs = no_fs self.no_dodge = no_dodge self.fs_og = adv.fs self.dodge_og = adv.dodge self.xmax = 1 n = "x{}".format(self.xmax) while n in self.conf: self.a_x_alt[self.xmax] = X((n, self.xmax), self.conf[n]) self.xmax += 1 n = "x{}".format(self.xmax) self.xmax -= 1 self.active = False self.xstart = None self.zeroed = None def x_alt(self): x_prev = self.adv.action.getprev() if x_prev in self.a_x_alt.values() and x_prev.index < self.xmax: x_seq = x_prev.index + 1 else: x_seq = 1 return self.a_x_alt[x_seq]() def x_proc_default(self, e): xseq = e.name dmg_coef = self.conf[xseq].dmg sp = self.conf[xseq].sp hit = self.conf[xseq].hit log("x", xseq, self.name) self.adv.hits += hit self.adv.dmg_make(xseq, dmg_coef) self.adv.charge(xseq, sp) def l_x(self, e): self.x_proc(e) self.adv.think_pin("x") def act_off(self): return False def on_t(self, t): log("debug", "{} x_alt on".format(self.name)) self.active = True self.adv.x = self.x_alt if self.l_x_alt: self.adv.l_x.off() self.l_x_alt.on() if self.no_fs: self.adv.fs = self.act_off if self.no_dodge: self.adv.dodge = self.act_off def on(self): if not self.active: if self.zeroed is not None: self.zeroed[0].index = self.zeroed[1] self.zeroed = None act = self.a_x_alt[1] doing = act._static.doing delay = 0 if not doing.idle: try: if doing.status == -1: delay = doing.startup_timer.timing - now() elif doing.status == 0: delay = doing.getrecovery() elif doing.status == 1: delay = doing.recovery_timer.timing - now() except: pass Timer(self.on_t).on(delay) def off(self): if self.active: log("debug", "{} x_alt off".format(self.name)) self.active = False self.adv.x = self.x_og if self.l_x_alt: self.l_x_alt.off() self.adv.l_x.on() if self.no_fs: self.adv.fs = self.fs_og if self.no_dodge: self.adv.dodge = self.dodge_og doing = self.a_x_alt[1]._static.doing self.zeroed = (doing, doing.index) doing.index = 0 def switch_t(self, t): prev_x = t.prev_x_alt log("debug", "{} x_alt off".format(prev_x.name)) if prev_x.active: doing = prev_x.a_x_alt[1]._static.doing prev_x.zeroed = (doing, doing.index) doing.index = 0 prev_x.active = False if prev_x.l_x_alt: prev_x.l_x_alt.off() prev_x.adv.l_x.on() if prev_x.no_fs: prev_x.adv.fs = prev_x.fs_og if prev_x.no_dodge: prev_x.adv.dodge = prev_x.dodge_og log("debug", "{} x_alt on".format(self.name)) self.active = True self.adv.x = self.x_alt if self.l_x_alt: self.adv.l_x.off() self.l_x_alt.on() if self.no_fs: self.adv.fs = self.act_off if self.no_dodge: self.adv.dodge = self.act_off def switch(self, prev_x_alt): if not self.active: if self.zeroed is not None: self.zeroed[0].index = self.zeroed[1] self.zeroed = None act = self.a_x_alt[1] doing = act._static.doing delay = 0 if not doing.idle and isinstance(doing, X): try: if doing.status == -1: delay = doing.startup_timer.timing - now() elif doing.status == 0: delay = doing.getrecovery() elif doing.status == 1: delay = doing.recovery_timer.timing - now() except: pass t = Timer(self.switch_t) t.prev_x_alt = prev_x_alt t.on(delay)