Ejemplo n.º 1
0
    def test_next_to_expire(self):
        buffable = Buffable()

        buff = BuffSpec()
        buff.activation_triggers = []  # no triggers
        buff.conditions = []  # no conditions
        buff.duration_seconds = 10  # Only lasts for 10 seconds
        buff.max_stack = 3
        buff.modifiers = [Modifier("+", 50, Attributes.DEF)]

        with FixedTime(get_timestamp()):

            expiry_time = get_timestamp() + buff.duration_seconds

            # Add the buff
            add_buff(buffable, buff, CompleteBuildingEvent())
            add_buff(buffable, buff, CompleteBuildingEvent())
            add_buff(buffable, buff, CompleteBuildingEvent())

            assert _get_next_expiry_time(buffable) == expiry_time

            expired_buffs = list(get_expired_buffs(buffable))
            assert len(expired_buffs) == 0

            with FixedTime(expiry_time):

                expired_buffs = list(get_expired_buffs(buffable))
                assert len(expired_buffs) == 3

                # Calling expired buffs should have removed them from expiry list
                assert len(buffable.expiry_times) == 0
Ejemplo n.º 2
0
    def test_expiring_stacks(self):
        buffable = Buffable()

        buff = BuffSpec(1)
        buff.activation_triggers = []  # no triggers
        buff.conditions = []  # no conditions
        buff.duration_seconds = 10  # Only lasts for 10 seconds
        buff.max_stack = 2
        buff.modifiers = [Modifier("+", 50, Attributes.DEF)]

        # Add the buff 2 times, one in the future
        add_buff(buffable, buff, CompleteBuildingEvent())
        with FixedTime(get_timestamp() + 5):
            add_buff(buffable, buff, CompleteBuildingEvent())

        expiry_time_1 = get_timestamp() + buff.duration_seconds
        expiry_time_2 = expiry_time_1 + 5

        assert buffable.attributes[Attributes.DEF] == 100
        assert buffable.active_buffs[buff.buff_id].stack == 2
        assert len(buffable.expiry_times) == 2

        with FixedTime(expiry_time_1):
            assert buffable.attributes[Attributes.DEF] == 50
            assert buffable.active_buffs[buff.buff_id].stack == 1
            assert len(buffable.expiry_times) == 1

        with FixedTime(expiry_time_2):
            assert buffable.attributes[Attributes.DEF] == 0
            assert buff.buff_id not in buffable.active_buffs
            assert len(buffable.expiry_times) == 0
Ejemplo n.º 3
0
	def test_modification_history(self):
		buffable = Buffable()
		attributes = buffable.attributes

		# Create an event with fake event data
		source_event = CompleteBuildingEvent()

		apply_attributes_modification(attributes, BuffModification(Modifier("+", 25, Attributes.ATK), source_event))
		apply_attributes_modification(attributes, BuffModification(Modifier("%", 1.00, Attributes.ATK), source_event))
		apply_attributes_modification(attributes, BuffModification(Modifier("%", 1.00, Attributes.ATK), source_event))
		assert buffable.attributes[Attributes.ATK] == 75

		# Checking if we has history of those 3 modifications
		attribute_history = list(buffable.attributes.get_data(Attributes.ATK).history.values())

		assert attribute_history[0].modifier.operator == "+"
		assert attribute_history[0].modifier.value == 25
		assert attribute_history[0].modifier.attribute_id == Attributes.ATK
		assert attribute_history[0].source_event == source_event

		assert attribute_history[1].modifier.operator == "%"
		assert attribute_history[1].modifier.value == 1.00
		assert attribute_history[1].modifier.attribute_id == Attributes.ATK
		assert attribute_history[1].source_event == source_event

		assert attribute_history[2].modifier.operator == "%"
		assert attribute_history[2].modifier.value == 1.00
		assert attribute_history[2].modifier.attribute_id == Attributes.ATK
		assert attribute_history[2].source_event == source_event
Ejemplo n.º 4
0
    def test_condition_parameters(self):
        buffable = Buffable()
        buff = BuffSpec()
        buff.activation_triggers = ["DamageEvent"]
        buff.deactivation_triggers = ["DamageEvent"]
        buff.conditions = ["is_damage_higher_then 10"
                           ]  # condition parameters after condition name
        buff.buff_id = 5
        buff.modifiers = [Modifier("+", 30, Attributes.DEF)]
        buffspecs.register_buff(buff)

        @buffspecs.AddConditionFor([DamageEvent])
        def is_damage_higher_then(event, param):
            return event.damage > param

        # Add the buff
        add_buff(buffable, buff, CompleteBuildingEvent())

        # Damage lower then condition threshhold
        call_event(DamageEvent(buffable, 8))

        # Buff should not have been activated
        assert buff.buff_id not in buffable.active_buffs
        assert buffable.attributes[Attributes.DEF] == 0

        # Now a damage higher
        call_event(DamageEvent(buffable, 12))
        # Buff should have been activated
        assert buff.buff_id in buffable.active_buffs
        assert buffable.attributes[Attributes.DEF] == 30
Ejemplo n.º 5
0
    def test_buffable_force_attributes_setter(self):
        buffable = Buffable()

        # Forcing an attribute final value to be 10
        buffable.attributes[Attributes.MAX_HP] = 10

        attr_data = buffable.attributes.get_data(Attributes.MAX_HP)
        assert attr_data.final_value == 10
        assert attr_data.mod_add == 10  # Automatically granted 10 of the add modifier
        assert attr_data.mod_pct == 0  # no bonus pct
Ejemplo n.º 6
0
    def test_adding_buff(self):
        buffable = Buffable()

        buff = BuffSpec()
        buff.activation_triggers = []  # no triggers
        buff.conditions = []  # no conditions
        buff.modifiers = [Modifier("+", 30, Attributes.DEF)]

        # Add the buff
        add_buff(buffable, buff, CompleteBuildingEvent())

        # Since it has no triggers or conditions, it was added automatically
        assert buffable.attributes[Attributes.DEF] == 30
        assert buff.buff_id in buffable.active_buffs
Ejemplo n.º 7
0
	def test_apply_modifiers_not_cumulative(self):
		buffable = Buffable()
		attributes = buffable.attributes
		# +25 ATK
		apply_attributes_modification(attributes, BuffModification(Modifier("+", 25, Attributes.ATK)))
		assert buffable.attributes[Attributes.ATK] == 25

		# 100% Bonus Atk
		apply_attributes_modification(attributes, BuffModification(Modifier("%", 1.00, Attributes.ATK)))
		assert buffable.attributes[Attributes.ATK] == 50

		# 100% Bonus Atk Again
		apply_attributes_modification(attributes, BuffModification(Modifier("%", 1.00, Attributes.ATK)))
		assert buffable.attributes[Attributes.ATK] == 75
Ejemplo n.º 8
0
    def test_pct_modifier(self):
        buffable = Buffable()
        buffable.attributes[Attributes.MAX_HP] = 10

        attr_data = buffable.attributes.get_data(Attributes.MAX_HP)
        assert attr_data.final_value == 10

        # Adding 50% bonus to the the attribute modifiers
        attr_data.mod_mult = 0.5
        attr_data.calculate()

        # +10 + 50% of that (5) is 15
        assert attr_data.final_value == 15
        assert attr_data.mod_add == 10
        assert attr_data.mod_mult == 0.5
Ejemplo n.º 9
0
    def test_removing_buff(self):
        buffable = Buffable()
        buffable.attributes[Attributes.ATK] = 100

        buff = BuffSpec()
        buff.modifiers = [Modifier("%", 0.5, Attributes.ATK)]

        add_buff(buffable, buff, CompleteBuildingEvent())

        assert buffable.attributes[Attributes.ATK] == 150

        remove_buff(buffable, buff.buff_id)

        assert buffable.attributes[Attributes.ATK] == 100
        assert buff.buff_id not in buffable.active_buffs
Ejemplo n.º 10
0
    def test_negating_condition(self):
        buffable = Buffable()
        buff = BuffSpec()
        buff.activation_triggers = {}  # no triggers
        buff.conditions = ["not cond_is_blue_yellow"]
        buff.buff_id = 5
        buff.modifiers = [Modifier("+", 30, Attributes.DEF)]
        buffspecs.register_buff(buff)

        @buffspecs.AddConditionFor([CompleteBuildingEvent])
        def cond_is_blue_yellow(event):
            return False

        add_buff(buffable, buff, CompleteBuildingEvent())

        # This buff should be be applied as the condition was negated
        assert buff.buff_id in buffable.active_buffs
Ejemplo n.º 11
0
    def test_buff_modification_history(self):
        buffable = Buffable()

        buff = BuffSpec()
        buff.modifiers = [Modifier("+", 30, Attributes.DEF)]

        # Faking an event that would result in adding a buff
        event_to_get_the_buff = CompleteBuildingEvent()

        # Add the buff
        event_result = add_buff(buffable, buff, event_to_get_the_buff)
        added_modifications = event_result.added_modifications
        # Check modification history to debug/backtrack
        assert added_modifications[0].modifier.operator == "+"
        assert added_modifications[0].modifier.attribute_id == Attributes.DEF
        assert added_modifications[
            0].source_event.trigger_event == event_to_get_the_buff
Ejemplo n.º 12
0
    def test_basic_condition_failing(self):
        buffable = Buffable()
        buff = BuffSpec()
        buff.activation_triggers = {}  # no triggers
        buff.conditions = ["cond_is_blue_yellow"]
        buff.buff_id = 5
        buff.modifiers = [Modifier("+", 30, Attributes.DEF)]
        buffspecs.register_buff(buff)

        # A condition that can be triggered by a MockEvent
        @buffspecs.AddConditionFor([CompleteBuildingEvent])
        def cond_is_blue_yellow(event):
            return False

        add_buff(buffable, buff, CompleteBuildingEvent())

        # This buff should not be applied
        assert buff.buff_id not in buffable.active_buffs
Ejemplo n.º 13
0
    def test_registering_1_expiry_per_stack(self):
        buffable = Buffable()

        buff = BuffSpec(1)
        buff.activation_triggers = []  # no triggers
        buff.conditions = []  # no conditions
        buff.duration_seconds = 10  # Only lasts for 10 seconds
        buff.max_stack = 2
        buff.modifiers = [Modifier("+", 50, Attributes.DEF)]

        # Add the buff 2 times
        add_buff(buffable, buff, CompleteBuildingEvent())
        add_buff(buffable, buff, CompleteBuildingEvent())

        # Should have registered one expiry time per stack
        assert buffable.attributes[Attributes.DEF] == 100
        assert buffable.active_buffs[buff.buff_id].stack == 2
        assert len(buffable.expiry_times) == 2
Ejemplo n.º 14
0
    def test_adding_multiple_modifiers(self):
        buffable = Buffable()

        buff = BuffSpec()
        buff.activation_triggers = []  # no triggers
        buff.conditions = []  # no conditions
        buff.modifiers = [
            Modifier("+", 50, Attributes.DEF),
            Modifier("+", 50, Attributes.DEF),
            Modifier("%", 0.5, Attributes.DEF)
        ]
        buffspecs.register_buff(buff)  # Add buff to registry

        # Adding a possible buff
        add_buff(buffable, buff, CompleteBuildingEvent())

        # +50 +50 + 50% is 100 + 50% = 150
        asd = buffable.attributes.get_data(Attributes.DEF)
        assert buffable.attributes[Attributes.DEF] == 150
Ejemplo n.º 15
0
    def test_buff_event_modifications_log(self):
        buffable = Buffable()

        # Building a buff with the builder
        buff = BuffBuilder().modify(
            "+", 5, Attributes.ATK).whenever(FartEvent).build()
        add_buff(buffable, buff, CompleteBuildingEvent())

        fart_event = FartEvent(buffable)
        event_result = call_event(fart_event)
        modifications = event_result.added_modifications

        # Check if the event returns the correct modifications that happened
        assert len(modifications) == 1
        assert modifications[0].buff_id == buff.buff_id
        assert modifications[0].source_event == fart_event
        assert modifications[0].modifier.operator == "+"
        assert modifications[0].modifier.value == 5
        assert modifications[0].modifier.attribute_id == Attributes.ATK
Ejemplo n.º 16
0
    def test_buff_trigger(self):
        buffable = Buffable()
        buff = BuffSpec()
        buff.activation_triggers = ["FartEvent"]
        buff.conditions = []
        buff.buff_id = 5
        buff.modifiers = [Modifier("+", 30, Attributes.DEF)]
        buffspecs.register_buff(buff)

        add_buff(buffable, buff, CompleteBuildingEvent())

        # The buff was not triggered yet as "FartEvent" was not called
        assert buffable.attributes[Attributes.DEF] == 0
        # Instead, we did not added a buff, we just added a trigger for a buff
        assert "FartEvent" in buffable.activation_triggers

        # Now we call the event
        call_event(FartEvent(buffable))

        # Now the buff should be added
        assert buffable.attributes[Attributes.DEF] == 30
        # And the trigger removed
        assert "FartEvent" not in buffable.activation_triggers
Ejemplo n.º 17
0
    def test_adding_buff(self):
        buffable = Buffable()

        buff = BuffSpec(1)
        buff.activation_triggers = []  # no triggers
        buff.conditions = []  # no conditions
        buff.duration_seconds = 10  # Only lasts for 10 seconds
        buff.modifiers = [Modifier("+", 50, Attributes.DEF)]

        with FixedTime(get_timestamp()):
            # Add the buff
            expiry_time = get_timestamp() + 10

            add_buff(buffable, buff, CompleteBuildingEvent())

            # Since it has no triggers or conditions, it was added automatically
            assert buffable.attributes[Attributes.DEF] == 50
            assert buff.buff_id in buffable.active_buffs

            # Check the expiry time was registered
            registered_expiry_time, buff_id = buffable.expiry_times[0]
            assert registered_expiry_time == expiry_time
            assert buff_id == buff.buff_id
Ejemplo n.º 18
0
    def test_buff_expiring(self):
        buffable = Buffable()

        buff = BuffSpec(1)
        buff.activation_triggers = []  # no triggers
        buff.conditions = []  # no conditions
        buff.duration_seconds = 10  # Only lasts for 10 seconds
        buff.modifiers = [Modifier("+", 50, Attributes.DEF)]

        expiry_time = get_timestamp() + buff.duration_seconds

        # Add the buff
        add_buff(buffable, buff, CompleteBuildingEvent())

        assert buffable.attributes[Attributes.DEF] == 50

        with FixedTime(expiry_time):
            # Simply by reading the attribute we will expire that buff
            assert buffable.attributes[Attributes.DEF] == 0
            # Should not be an active buff anymore
            assert buff.buff_id not in buffable.active_buffs
            # Expiry time
            assert len(buffable.expiry_times) == 0
Ejemplo n.º 19
0
    def test_condition_switching_buff(self):
        buffable = Buffable()
        buff = BuffSpec()
        buff.activation_triggers = ["DamageEvent"]
        buff.deactivation_triggers = ["DamageEvent"]
        buff.conditions = ["is_burning"]
        buff.buff_id = 5
        buff.modifiers = [Modifier("+", 30, Attributes.DEF)]
        buffspecs.register_buff(buff)

        buffable.attributes[
            "Burning"] = 0  # example to set a state, not burning

        @buffspecs.AddConditionFor([DamageEvent])
        def is_burning(event):
            return event.buffable.attributes["Burning"] == 1

        # Add the buff
        add_buff(buffable, buff, CompleteBuildingEvent())

        # The buff should not be applied because the buffable is not burning
        assert buff.buff_id not in buffable.active_buffs
        assert buffable.attributes[Attributes.DEF] == 0

        # Now make it burn
        damage = 10
        buffable.attributes["Burning"] = 1
        call_event(DamageEvent(buffable, damage))

        # Now the buff should have applied
        assert buff.buff_id in buffable.active_buffs
        assert buffable.attributes[Attributes.DEF] == 30

        # And we should have added the remove trigger
        assert buff.buff_id in buffable.deactivation_triggers["DamageEvent"]
        # Buff history contains this modification
        assert len(buffable.attributes.get_data(Attributes.DEF).history) == 1

        # Now After calling the other event the buff should be removed
        buffable.attributes["Burning"] = 0
        call_event(DamageEvent(buffable, damage))

        # Now the buff should be removed
        assert buff.buff_id not in buffable.active_buffs
        assert buff.buff_id not in buffable.deactivation_triggers
        assert buffable.attributes[Attributes.DEF] == 0

        # And the trigger should be added again and the remove trigger should be removed
        assert buff.buff_id not in buffable.deactivation_triggers[
            "DamageEvent"]
        assert buff.buff_id in buffable.activation_triggers["DamageEvent"]
        # Also the modification history is removed because this buff is inactive and not modifyng anything
        assert len(buffable.attributes.get_data(Attributes.DEF).history) == 0

        # In case we burn again...
        buffable.attributes["Burning"] = 1
        call_event(DamageEvent(buffable, damage))

        # Buff is activated again
        assert buff.buff_id in buffable.active_buffs
        assert buffable.attributes[Attributes.DEF] == 30
Ejemplo n.º 20
0
    def test_reuse_conditions_with_abstraction(self):
        # Lets say our game has an economy, of multiple types of coins.
        example_coin_types = ["gold", "silver", "copper"]

        class EconomyEvent(BuffEvent):
            def __init__(self, buffable, coin_type_changed, coin_amount):
                super(EconomyEvent, self).__init__(buffable)
                self.coin_type_changed = coin_type_changed
                self.coin_amount = coin_amount

        # The player can get coins by mining for instance
        class PlayerMineCoinsEvent(EconomyEvent):
            def __init__(self, buffable, coin_type_changed, coin_amount):
                super(PlayerMineCoinsEvent,
                      self).__init__(buffable, coin_type_changed, coin_amount)

        # The player can also get coins by looting enemies
        class PlayerLootEnemyEvent(EconomyEvent):
            def __init__(self, buffable, coin_type_changed, coin_amount):
                super(PlayerLootEnemyEvent,
                      self).__init__(buffable, coin_type_changed, coin_amount)

        # Now this condition works for any economy event generically
        @buffspecs.AddConditionFor([EconomyEvent])
        def is_coin_type(event, *coin_types):
            return event.coin_type_changed in coin_types

        # Now we create a buff that
        buffable = Buffable()

        # Making a buff that gives player DEF when if he mines a gold coin
        bdr = BuffBuilder().modify("+", 5, Attributes.DEF).whenever(
            PlayerMineCoinsEvent).just_if("is_coin_type gold")
        bonus_mine_gold_buff = bdr.build()

        # Making a buff that gives player ATK if he loots silver or copper coins
        bdr = BuffBuilder().modify(
            "+", 5, Attributes.ATK
        ).whenever(PlayerLootEnemyEvent).just_if(
            "is_coin_type copper silver"  # Multiple parameters in the condition
        )
        bonus_loot_copper_silver_buff = bdr.build()

        # Add the buffs
        add_buff(buffable, bonus_loot_copper_silver_buff,
                 CompleteBuildingEvent())
        add_buff(buffable, bonus_mine_gold_buff, CompleteBuildingEvent())

        # Now we mine some silver
        call_event(PlayerMineCoinsEvent(buffable, "silver", 10))

        # No buffs should be applied as no conditions matched
        assert len(buffable.active_buffs) == 0

        # Now he mines gold, should activate the buff cause the condition matched
        call_event(PlayerMineCoinsEvent(buffable, "gold", 10))
        assert bonus_mine_gold_buff.buff_id in buffable.active_buffs

        # Now he will loot gold, condition should not match
        call_event(PlayerLootEnemyEvent(buffable, "gold", 10))
        assert bonus_loot_copper_silver_buff.buff_id not in buffable.active_buffs

        # Now he finally loots silver or copper (in this case, silver) and the buff should apply
        call_event(PlayerLootEnemyEvent(buffable, "silver", 10))
        assert bonus_loot_copper_silver_buff.buff_id in buffable.active_buffs