Пример #1
0
class Buff(object):
    MAXHP_CAP = 1.30
    _static = Static({
        'all_buffs': [],
        'adv': None
    })

    def __init__(self, name='<buff_noname>', value=0, duration=0, mtype='att', morder=None, modifier=None, hidden=False):
        self.name = name
        self.__value = value
        self.duration = duration
        self.mod_type = mtype
        self.mod_order = morder or ('chance' if self.mod_type == 'crit' else 'buff')
        self.bufftype = 'misc' if hidden else 'self'

        self.bufftime = self._bufftime if self.duration > 0 else self._no_bufftime
        self.buff_end_timer = Timer(self.buff_end_proc)
        if modifier:
            self.modifier = modifier
            self.get = self.modifier.get
        elif mtype != 'effect':
            self.modifier = Modifier('mod_' + self.name, self.mod_type, self.mod_order, 0)
            self.modifier.get = self.get
        else:
            self.modifier = None
        self.dmg_test_event = Event('dmg_formula')
        self.dmg_test_event.dmg_coef = 1
        self.dmg_test_event.dname = 'test'

        self.hidden = hidden

        self.__stored = 0
        self.__active = 0
        # self.on()

    def logwrapper(self, *args):
        if not self.hidden:
            log('buff', *args)

    def _no_bufftime(self):
        return 1

    def _ex_bufftime(self):
        return 1 + self._static.adv.sub_mod('buff', 'ex')

    def _bufftime(self):
        return self._static.adv.mod('buff', operator=operator.add)

    def _debufftime(self):
        return self._static.adv.mod('debuff', operator=operator.add)

    def no_bufftime(self):
        self.bufftime = self._no_bufftime
        return self

    def ex_bufftime(self):
        self.bufftime = self._ex_bufftime
        return self

    def value(self, newvalue=None):
        if newvalue:
            self.logwrapper(self.name, f'{self.mod_type}({self.mod_order}): {newvalue:.02f}', 'buff value change')
            return self.set(newvalue)
        else:
            return self.get()

    def get(self):
        if self.__active:
            return self.__value
        else:
            return 0

    def set(self, v, d=None):
        self.__value = v
        if d != None:
            self.duration = d
        return self
        

    def stack(self):
        stack = 0
        for i in self._static.all_buffs:
            if i.name == self.name:
                if i.__active != 0:
                    stack += 1
        return stack

    def valuestack(self):
        stack = 0
        value = 0
        for i in self._static.all_buffs:
            if i.name == self.name:
                if i.__active != 0:
                    stack += 1
                    value += i.__value
        return value, stack

    def effect_on(self):
        return self.modifier and self.modifier.on()

    def effect_off(self):
        return self.modifier and self.modifier.off()

    def buff_end_proc(self, e):
        self.logwrapper(self.name, f'{self.mod_type}({self.mod_order}): {self.value():.02f}', 'buff end <timeout>')
        self.__active = 0

        if self.__stored:
            idx = len(self._static.all_buffs)
            while 1:
                idx -= 1
                if idx < 0:
                    break
                if self == self._static.all_buffs[idx]:
                    self._static.all_buffs.pop(idx)
                    break
            self.__stored = 0
        value, stack = self.valuestack()
        if stack > 0:
            self.logwrapper(self.name, f'{self.mod_type}({self.mod_order}): {value:.02f}', f'buff stack <{stack}>')
        self.effect_off()

    def count_team_buff(self):
        base_mods = [
            Modifier('base_cc', 'crit', 'chance', 0.12),
            Modifier('base_killer', 'killer','passive', 0.30)
        ]
        self.dmg_test_event.modifiers = ModifierDict()
        for mod in base_mods:
            self.dmg_test_event.modifiers.append(mod)
        for b in filter(lambda b: b.get() and b.bufftype == 'simulated_def', self._static.all_buffs):
            self.dmg_test_event.modifiers.append(b.modifier)

        self.dmg_test_event()
        no_team_buff_dmg = self.dmg_test_event.dmg

        placeholders = []
        for b in filter(lambda b: b.get() and b.bufftype in ('team', 'debuff'), self._static.all_buffs):
            placehold = None
            if b.modifier.mod_type == 's':
                placehold = Modifier('placehold_sd', 'att', 'sd', b.modifier.get() / 2)
            elif b.modifier.mod_type == 'spd':
                placehold = Modifier('placehold_spd', 'att', 'spd', b.modifier.get())
            elif b.modifier.mod_type.endswith('_killer'):
                placehold = Modifier('placehold_k', 'killer', 'passive', b.modifier.get())
            if placehold:
                self.dmg_test_event.modifiers.append(placehold)
                placeholders.append(placehold)
            else:
                self.dmg_test_event.modifiers.append(b.modifier)

        self.dmg_test_event()
        team_buff_dmg = self.dmg_test_event.dmg
        log('buff', 'team', team_buff_dmg / no_team_buff_dmg - 1)

        for mod in chain(base_mods, placeholders):
            mod.off()


    def on(self, duration=None):
        if self.mod_type == 'maxhp':
            max_hp = self._static.adv.mod('maxhp')
            if max_hp >= Buff.MAXHP_CAP:
                return self
            value = self.__value
            mod_val = min(value, max(Buff.MAXHP_CAP-max_hp, 0))
            self._static.adv.set_hp((self._static.adv.hp*max_hp+value*100)/(max_hp+mod_val))

        d = (duration or self.duration) * self.bufftime()
        if self.__active == 0:
            self.__active = 1
            if self.__stored == 0:
                self._static.all_buffs.append(self)
                self.__stored = 1
            if d >= 0:
                self.buff_end_timer.on(d)
            proc_type = 'start'
        else:
            if d >= 0:
                self.buff_end_timer.on(d)
            proc_type = 'refresh'
            
        self.logwrapper(self.name, f'{self.mod_type}({self.mod_order}): {self.value():.02f}', f'buff {proc_type} <{d:.02f}s>')
        value, stack = self.valuestack()
        if stack > 1:
            log('buff', self.name, f'{self.mod_type}({self.mod_order}): {value:.02f}', f'buff stack <{stack}>')

        if self.mod_type == 'defense':
            Event('defchain').on()
            if self.bufftype == 'team':
                log('buff', 'team_defense', 'proc team doublebuffs')

        if self.mod_type == 'regen':
            # may need to make this part global since game always regen all stacks at same ticks
            self.set_hp_event = Event('set_hp')
            self.set_hp_event.delta = self.get()
            self.regen_timer = Timer(self.hp_regen, 3.9, True)
        else:
            self.effect_on()
        return self

    def hp_regen(self, t):
        self.set_hp_event()

    def off(self):
        if self.__active == 0:
            return
        self.logwrapper(self.name, f'{self.mod_type}({self.mod_order}): {self.value():.02f}', f'buff end <turn off>')
        self.__active = 0
        self.effect_off()
        self.buff_end_timer.off()
        return self

    def timeleft(self):
        return -1 if self.duration == -1 else (self.buff_end_timer.timing-now())

    def add_time(self, delta):
        self.buff_end_timer.add(delta)
Пример #2
0
class Modifier(object):
    _static = Static({
        'all_modifiers': ModifierDict(),
        'g_condition': None,
        'damage_sources': set()
    })

    def __init__(self, name, mtype, order, value, condition=None, get=None):
        self.mod_name = name
        self.mod_type = mtype
        self.mod_order = order
        self.mod_value = value
        self.mod_condition = condition
        self.mod_get = get
        self._mod_active = 0
        self.on()
        # self._static.all_modifiers.append(self)
        # self.__active = 1

    # @classmethod
    # def mod(cls, mtype, all_modifiers=None, morder=None):
    #     if not all_modifiers:
    #         all_modifiers = cls._static.all_modifiers
    #     if morder:
    #         return 1 + sum([modifier.get() for modifier in all_modifiers[mtype][morder]])
    #     m = defaultdict(lambda: 1)
    #     for order, modifiers in all_modifiers[mtype].items():
    #         m[order] += sum([modifier.get() for modifier in modifiers])
    #     ret = 1.0
    #     for i in m:
    #         ret *= m[i]
    #     return ret

    def get(self):
        if callable(self.mod_get) and not self.mod_get():
            return 0
        if self.mod_condition is not None and not self._static.g_condition(self.mod_condition):
            return 0
        return self.mod_value

    def on(self, modifier=None):
        if self._mod_active == 1:
            return self
        if modifier == None:
            modifier = self
        # if modifier.mod_condition:
        #     if not m_condition.on(modifier.mod_condition):
        #         return self
        # if modifier.mod_condition is not None:
        #     if not self._static.g_condition(modifier.mod_condition):
        #         return self

        self._static.all_modifiers.append(self)
        self._mod_active = 1
        return self

    def off(self, modifier=None):
        if self._mod_active == 0:
            return self
        self._mod_active = 0
        if modifier == None:
            modifier = self
        self._static.all_modifiers.remove(self)
        return self

    def __enter__(self):
        self.on()

    def __exit__(self, exc_type, exc_val, exc_tb):
        self.off()

    def __repr__(self):
        return '<%s %s %s %s>' % (self.mod_name, self.mod_type, self.mod_order, self.get())
Пример #3
0
class Buff(object):
    MAXHP_BUFF_CAP = 0.30
    _static = Static({"all_buffs": [], "adv": None})
    DB_DURATION = 15  # usual doublebuff effect duration for offensive buffs, note that regen lasts 20s

    def __init__(
        self,
        name="<buff_noname>",
        value=0,
        duration=0,
        mtype="att",
        morder=None,
        modifier=None,
        hidden=False,
        source=None,
    ):
        self.name = name
        self.__value = value
        self.duration = duration
        self.mod_type = mtype
        self.mod_order = morder or ("chance"
                                    if self.mod_type == "crit" else "buff")
        self.bufftype = "misc" if hidden else "self"

        self.source = source
        if self.source is not None and source[0] != "s" and source[0:2] != "ds":
            self.bufftime = self._ex_bufftime
        else:
            self.bufftime = self._bufftime
        self.buff_end_timer = Timer(self.buff_end_proc)
        if modifier:
            self.modifier = modifier
            self.get = self.modifier.get
        elif mtype != "effect":
            self.modifier = Modifier("mod_" + self.name, self.mod_type,
                                     self.mod_order, 0)
            self.modifier.get = self.get
        else:
            self.modifier = None
        self.dmg_test_event = Event("dmg_formula")
        self.dmg_test_event.dmg_coef = 1
        self.dmg_test_event.dname = "test"

        self.hidden = hidden

        self.__stored = 0
        self.__active = 0

        self.buffevent = Event("buff")
        self.pause_time = -1
        self.refresh_time = -1
        # self.on()

    def logwrapper(self, *args):
        if not self.hidden:
            log("buff", *args)

    def _no_bufftime(self):
        return 1

    def _ex_bufftime(self):
        return 1 + self._static.adv.sub_mod("buff", "ex")

    def _bufftime(self):
        return self._static.adv.mod("buff", operator=operator.add)

    def _debufftime(self):
        return self._static.adv.mod("debuff", operator=operator.add)

    def any_bufftime(self):
        self.bufftime = self._bufftime
        return self

    def no_bufftime(self):
        self.bufftime = self._no_bufftime
        return self

    def ex_bufftime(self):
        self.bufftime = self._ex_bufftime
        return self

    def value(self, newvalue=None):
        if newvalue is not None:
            self.logwrapper(
                self.name,
                f"{self.mod_type}({self.mod_order}): {newvalue:.02f}",
                "buff value change",
            )
            return self.set(newvalue)
        else:
            return self.__value

    @allow_acl
    def get(self):
        if self.__active:
            return self.__value
        else:
            return 0

    def set(self, v, d=None):
        self.__value = v
        if d != None:
            self.duration = d
        return self

    def stack(self):
        stack = 0
        for i in self._static.all_buffs:
            if i.name == self.name:
                if i.__active != 0:
                    stack += 1
        return stack

    def valuestack(self):
        stack = 0
        value = 0
        for i in self._static.all_buffs:
            if i.name == self.name:
                if i.__active != 0:
                    stack += 1
                    value += i.__value
        return value, stack

    def effect_on(self):
        value = self.get()
        if self.mod_type == "defense" and value > 0:
            db = Event("defchain")
            db.source = self.source
            db.on()
            if self.bufftype == "team":
                log("buff", "doublebuff", 15 * self.bufftime())
                if self.bufftime == self._bufftime:
                    self._static.adv.slots.c.set_need_bufftime()
        elif self.mod_type == "maxhp":
            if self._static.adv.sub_mod("maxhp", "buff") < Buff.MAXHP_BUFF_CAP:
                self.modifier.on()
            percent = value * 100
            log("heal", self.name, self._static.adv.max_hp * value,
                "team" if self.bufftype == "team" else "self")
            self._static.adv.add_hp(percent)
        # FIXME: heal formula 1day twust
        elif self.mod_type == "regen" and value != 0:
            self.set_hp_event = Event("set_hp")
            self.set_hp_event.delta = value
            self.regen_timer = Timer(self.hp_regen, 3.9, True).on()
        elif self.mod_type == "heal" and value != 0:
            self.set_hp_event = Event("heal_make")
            self.set_hp_event.name = self.name
            self.set_hp_event.delta = self._static.adv.heal_formula(
                self.source, value)
            self.set_hp_event.target = "team" if self.bufftype == "team" else "self"
            self.regen_timer = Timer(self.hp_regen, 2.9, True).on()
        else:
            return self.modifier and self.modifier.on()

    def effect_off(self):
        if self.mod_type in ("regen", "heal"):
            self.regen_timer.off()
        else:
            return self.modifier and self.modifier.off()

    def buff_end_proc(self, e):
        self.logwrapper(
            self.name,
            f"{self.mod_type}({self.mod_order}): {self.value():.02f}",
            "buff end <timeout>",
        )
        self.__active = 0

        if self.__stored:
            self._static.all_buffs.remove(self)
            self.__stored = 0
        value, stack = self.valuestack()
        if stack > 0:
            self.logwrapper(
                self.name,
                f"{self.mod_type}({self.mod_order}): {value:.02f}",
                f"buff stack <{stack}>",
            )
        self.effect_off()

    def count_team_buff(self):
        if self.bufftype == "self":
            return
        base_mods = [
            Modifier("base_cc", "crit", "chance", 0.12),
            Modifier("base_killer", "killer", "passive", 0.30),
        ]
        self.dmg_test_event.modifiers = ModifierDict()
        for mod in base_mods:
            self.dmg_test_event.modifiers.append(mod)
        for b in filter(lambda b: b.get() and b.bufftype == "simulated_def",
                        self._static.all_buffs):
            self.dmg_test_event.modifiers.append(b.modifier)

        self.dmg_test_event()
        no_team_buff_dmg = self.dmg_test_event.dmg

        placeholders = []
        for b in filter(
                lambda b: b.get() and b.bufftype in ("team", "debuff"),
                self._static.all_buffs,
        ):
            placehold = None
            if b.modifier.mod_type == "s":
                placehold = Modifier("placehold_sd", "att", "sd",
                                     b.modifier.get() / 2)
            elif b.modifier.mod_type == "spd":
                placehold = Modifier("placehold_spd", "att", "spd",
                                     b.modifier.get())
            elif b.modifier.mod_type.endswith("_killer"):
                placehold = Modifier("placehold_k", "killer", "passive",
                                     b.modifier.get())
            if placehold:
                self.dmg_test_event.modifiers.append(placehold)
                placeholders.append(placehold)
            else:
                self.dmg_test_event.modifiers.append(b.modifier)

        self.dmg_test_event()
        team_buff_dmg = self.dmg_test_event.dmg
        log("buff", "team", team_buff_dmg / no_team_buff_dmg - 1)

        for mod in chain(base_mods, placeholders):
            mod.off()

    def on(self, duration=None):
        d = max(-1, (duration or self.duration) * self.bufftime())
        if d != -1 and self.bufftime == self._bufftime:
            self._static.adv.slots.c.set_need_bufftime()
        if self.__active == 0:
            self.__active = 1
            if self.__stored == 0:
                self._static.all_buffs.append(self)
                self.__stored = 1
            if d >= 0:
                self.buff_end_timer.on(d)
            proc_type = "start"
        else:
            if d >= 0:
                if self.buff_end_timer.online:
                    self.buff_end_timer.on(d)
                else:
                    self.refresh_time = d
            else:
                return self
            proc_type = "refresh"

        self.logwrapper(
            self.name,
            f"{self.mod_type}({self.mod_order}): {self.value():.02f}",
            f"buff {proc_type} <{d:.02f}s>",
        )
        value, stack = self.valuestack()
        if stack > 1:
            log(
                "buff",
                self.name,
                f"{self.mod_type}({self.mod_order}): {value:.02f}",
                f"buff stack <{stack}>",
            )

        self.effect_on()

        self.buffevent.buff = self
        self.buffevent.on()

        return self

    def hp_regen(self, t):
        self.set_hp_event.on()

    def off(self):
        if self.__active == 0:
            return
        self.logwrapper(
            self.name,
            f"{self.mod_type}({self.mod_order}): {self.value():.02f}",
            f"buff end <turn off>",
        )
        self.__active = 0
        self.buff_end_timer.off()
        self.effect_off()
        return self

    @property
    def adv(self):
        return self._static.adv

    @allow_acl
    def timeleft(self):
        return -1 if self.duration == -1 else (self.buff_end_timer.timing -
                                               now())

    def add_time(self, delta):
        self.buff_end_timer.add(delta)

    def pause(self):
        self.pause_time = self.timeleft()
        if self.pause_time > 0:
            log("pause", self.name, self.pause_time)
            self.buff_end_timer.off()

    def resume(self):
        self.pause_time = max(self.pause_time, self.refresh_time)
        if self.pause_time > 0:
            log("resume", self.name, self.pause_time, now() + self.pause_time)
            self.buff_end_timer.on(self.pause_time)
        self.pause_time = -1