Пример #1
0
 def test_combination(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     invalid_modifier = Modifier()
     invalid_modifier.state = State.offline
     invalid_modifier.scope = Scope.local
     invalid_modifier.src_attr = src_attr.id
     invalid_modifier.operator = 1008
     invalid_modifier.tgt_attr = tgt_attr.id
     invalid_modifier.domain = Domain.self_
     invalid_modifier.filter_type = None
     invalid_modifier.filter_value = None
     valid_modifier = Modifier()
     valid_modifier.state = State.offline
     valid_modifier.scope = Scope.local
     valid_modifier.src_attr = src_attr.id
     valid_modifier.operator = Operator.post_mul
     valid_modifier.tgt_attr = tgt_attr.id
     valid_modifier.domain = Domain.self_
     valid_modifier.filter_type = None
     valid_modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (invalid_modifier, valid_modifier)
     holder = IndependentItem(self.ch.type_(type_id=1, effects=(effect,),
                                            attributes={src_attr.id: 1.5, tgt_attr.id: 100}))
     self.fit.items.add(holder)
     # Make sure presence of invalid operator doesn't prevent
     # from calculating value based on valid modifiers
     self.assertNotAlmostEqual(holder.attributes[tgt_attr.id], 100)
     self.fit.items.remove(holder)
     self.assertEqual(len(self.log), 1)
     self.assert_link_buffers_empty(self.fit)
Пример #2
0
 def setUp(self):
     super().setUp()
     self.tgt_attr = self.ch.attribute(attribute_id=1, stackable=1)
     src_attr1 = self.ch.attribute(attribute_id=2)
     src_attr2 = self.ch.attribute(attribute_id=3)
     modifier1 = Modifier()
     modifier1.state = State.offline
     modifier1.scope = Scope.local
     modifier1.src_attr = src_attr1.id
     modifier1.operator = Operator.post_mul
     modifier1.tgt_attr = self.tgt_attr.id
     modifier1.domain = Domain.self_
     modifier1.filter_type = None
     modifier1.filter_value = None
     modifier2 = Modifier()
     modifier2.state = State.offline
     modifier2.scope = Scope.local
     modifier2.src_attr = src_attr2.id
     modifier2.operator = Operator.post_mul
     modifier2.tgt_attr = self.tgt_attr.id
     modifier2.domain = Domain.self_
     modifier2.filter_type = None
     modifier2.filter_value = None
     self.effect1 = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     self.effect1.modifiers = (modifier1,)
     self.effect2 = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     self.effect2.modifiers = (modifier2,)
     self.holder = IndependentItem(self.ch.type_(
         type_id=1, effects=(self.effect1, self.effect2),
         attributes={self.tgt_attr.id: 100, src_attr1.id: 1.1, src_attr2.id: 1.3}
     ))
Пример #3
0
 def test_combination(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     invalid_modifier = Modifier()
     invalid_modifier.state = State.offline
     invalid_modifier.scope = Scope.local
     invalid_modifier.src_attr = src_attr.id
     invalid_modifier.operator = 1008
     invalid_modifier.tgt_attr = tgt_attr.id
     invalid_modifier.domain = Domain.self_
     invalid_modifier.filter_type = None
     invalid_modifier.filter_value = None
     valid_modifier = Modifier()
     valid_modifier.state = State.offline
     valid_modifier.scope = Scope.local
     valid_modifier.src_attr = src_attr.id
     valid_modifier.operator = Operator.post_mul
     valid_modifier.tgt_attr = tgt_attr.id
     valid_modifier.domain = Domain.self_
     valid_modifier.filter_type = None
     valid_modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (invalid_modifier, valid_modifier)
     holder = IndependentItem(self.ch.type_(
         type_id=1, effects=(effect,), attributes={src_attr.id: 1.5, tgt_attr.id: 100}))
     self.fit.items.add(holder)
     # Make sure presence of invalid operator doesn't prevent
     # from calculating value based on valid modifiers
     self.assertNotAlmostEqual(holder.attributes[tgt_attr.id], 100)
     self.fit.items.remove(holder)
     self.assertEqual(len(self.log), 1)
     self.assert_link_buffers_empty(self.fit)
Пример #4
0
 def setUp(self):
     super().setUp()
     self.tgt_attr = self.ch.attribute(attribute_id=1, stackable=1)
     src_attr1 = self.ch.attribute(attribute_id=2)
     src_attr2 = self.ch.attribute(attribute_id=3)
     src_attr3 = self.ch.attribute(attribute_id=4)
     src_attr4 = self.ch.attribute(attribute_id=5)
     modifier_off = Modifier()
     modifier_off.state = State.offline
     modifier_off.scope = Scope.local
     modifier_off.src_attr = src_attr1.id
     modifier_off.operator = Operator.post_mul
     modifier_off.tgt_attr = self.tgt_attr.id
     modifier_off.domain = Domain.self_
     modifier_off.filter_type = None
     modifier_off.filter_value = None
     modifier_on = Modifier()
     modifier_on.state = State.online
     modifier_on.scope = Scope.local
     modifier_on.src_attr = src_attr2.id
     modifier_on.operator = Operator.post_mul
     modifier_on.tgt_attr = self.tgt_attr.id
     modifier_on.domain = Domain.self_
     modifier_on.filter_type = None
     modifier_on.filter_value = None
     modifier_act = Modifier()
     modifier_act.state = State.active
     modifier_act.scope = Scope.local
     modifier_act.src_attr = src_attr3.id
     modifier_act.operator = Operator.post_mul
     modifier_act.tgt_attr = self.tgt_attr.id
     modifier_act.domain = Domain.self_
     modifier_act.filter_type = None
     modifier_act.filter_value = None
     modifier_over = Modifier()
     modifier_over.state = State.overload
     modifier_over.scope = Scope.local
     modifier_over.src_attr = src_attr4.id
     modifier_over.operator = Operator.post_mul
     modifier_over.tgt_attr = self.tgt_attr.id
     modifier_over.domain = Domain.self_
     modifier_over.filter_type = None
     modifier_over.filter_value = None
     # Overload category will make sure that holder can enter all states
     effect = self.ch.effect(effect_id=1, category=EffectCategory.overload)
     effect.modifiers = (modifier_off, modifier_on, modifier_act,
                         modifier_over)
     self.holder = IndependentItem(
         self.ch.type_(type_id=1,
                       effects=(effect, ),
                       attributes={
                           self.tgt_attr.id: 100,
                           src_attr1.id: 1.1,
                           src_attr2.id: 1.3,
                           src_attr3.id: 1.5,
                           src_attr4.id: 1.7
                       }))
Пример #5
0
 def test_calculation(self):
     attr1 = self.ch.attribute(attribute_id=1)
     attr2 = self.ch.attribute(attribute_id=2)
     attr3 = self.ch.attribute(attribute_id=3)
     attr4 = self.ch.attribute(attribute_id=4)
     modifier1 = Modifier()
     modifier1.state = State.offline
     modifier1.scope = Scope.local
     modifier1.src_attr = attr1.id
     modifier1.operator = Operator.post_mul
     modifier1.tgt_attr = attr2.id
     modifier1.domain = Domain.self_
     modifier1.filter_type = None
     modifier1.filter_value = None
     effect1 = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect1.modifiers = (modifier1,)
     modifier2 = Modifier()
     modifier2.state = State.offline
     modifier2.scope = Scope.local
     modifier2.src_attr = attr2.id
     modifier2.operator = Operator.post_percent
     modifier2.tgt_attr = attr3.id
     modifier2.domain = Domain.ship
     modifier2.filter_type = None
     modifier2.filter_value = None
     effect2 = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     effect2.modifiers = (modifier2,)
     holder1 = CharacterItem(self.ch.type_(type_id=1, effects=(effect1, effect2),
                             attributes={attr1.id: 5, attr2.id: 20}))
     modifier3 = Modifier()
     modifier3.state = State.offline
     modifier3.scope = Scope.local
     modifier3.src_attr = attr3.id
     modifier3.operator = Operator.post_percent
     modifier3.tgt_attr = attr4.id
     modifier3.domain = Domain.ship
     modifier3.filter_type = FilterType.all_
     modifier3.filter_value = None
     effect3 = self.ch.effect(effect_id=3, category=EffectCategory.passive)
     effect3.modifiers = (modifier3,)
     holder2 = IndependentItem(self.ch.type_(type_id=2, effects=(effect3,), attributes={attr3.id: 150}))
     holder3 = ShipItem(self.ch.type_(type_id=3, attributes={attr4.id: 12.5}))
     self.fit.items.add(holder1)
     self.fit.ship = holder2
     self.fit.items.add(holder3)
     # If everything is processed properly, holder1 will multiply attr2 by attr1
     # on self, resulting in 20 * 5 = 100, then apply it as percentage modifier
     # on ship's (holder2) attr3, resulting in 150 + 100% = 300, then it is applied
     # to all entities assigned to ship, including holder3, to theirs attr4 as
     # percentage modifier again - so final result is 12.5 + 300% = 50
     self.assertAlmostEqual(holder3.attributes[attr4.id], 50)
     self.fit.items.remove(holder1)
     self.fit.ship = None
     self.fit.items.remove(holder3)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #6
0
 def setUp(self):
     AttrCalcTestCase.setUp(self)
     self.tgt_attr = self.ch.attribute(attribute_id=1, stackable=1)
     src_attr1 = self.ch.attribute(attribute_id=2)
     src_attr2 = self.ch.attribute(attribute_id=3)
     src_attr3 = self.ch.attribute(attribute_id=4)
     src_attr4 = self.ch.attribute(attribute_id=5)
     modifier_off = Modifier()
     modifier_off.state = State.offline
     modifier_off.scope = Scope.local
     modifier_off.src_attr = src_attr1.id
     modifier_off.operator = Operator.post_mul
     modifier_off.tgt_attr = self.tgt_attr.id
     modifier_off.domain = Domain.self_
     modifier_off.filter_type = None
     modifier_off.filter_value = None
     modifier_on = Modifier()
     modifier_on.state = State.online
     modifier_on.scope = Scope.local
     modifier_on.src_attr = src_attr2.id
     modifier_on.operator = Operator.post_mul
     modifier_on.tgt_attr = self.tgt_attr.id
     modifier_on.domain = Domain.self_
     modifier_on.filter_type = None
     modifier_on.filter_value = None
     modifier_act = Modifier()
     modifier_act.state = State.active
     modifier_act.scope = Scope.local
     modifier_act.src_attr = src_attr3.id
     modifier_act.operator = Operator.post_mul
     modifier_act.tgt_attr = self.tgt_attr.id
     modifier_act.domain = Domain.self_
     modifier_act.filter_type = None
     modifier_act.filter_value = None
     modifier_over = Modifier()
     modifier_over.state = State.overload
     modifier_over.scope = Scope.local
     modifier_over.src_attr = src_attr4.id
     modifier_over.operator = Operator.post_mul
     modifier_over.tgt_attr = self.tgt_attr.id
     modifier_over.domain = Domain.self_
     modifier_over.filter_type = None
     modifier_over.filter_value = None
     # Overload category will make sure that holder can enter all states
     effect = self.ch.effect(effect_id=1, category=EffectCategory.overload)
     effect.modifiers = (modifier_off, modifier_on, modifier_act, modifier_over)
     self.holder = IndependentItem(self.ch.type_(type_id=1, effects=(effect,),
                                                 attributes={self.tgt_attr.id: 100, src_attr1.id: 1.1,
                                                             src_attr2.id: 1.3, src_attr3.id: 1.5,
                                                             src_attr4.id: 1.7}))
Пример #7
0
 def test_attribute(self):
     attr1 = self.ch.attribute(attribute_id=1)
     attr2 = self.ch.attribute(attribute_id=2)
     attr3 = self.ch.attribute(attribute_id=3)
     modifier1 = Modifier()
     modifier1.state = State.offline
     modifier1.scope = Scope.local
     modifier1.src_attr = attr1.id
     modifier1.operator = Operator.post_mul
     modifier1.tgt_attr = attr2.id
     modifier1.domain = Domain.ship
     modifier1.filter_type = None
     modifier1.filter_value = None
     effect1 = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect1.modifiers = (modifier1, )
     holder1 = CharacterItem(
         self.ch.type_(type_id=1,
                       effects=(effect1, ),
                       attributes={attr1.id: 5}))
     modifier2 = Modifier()
     modifier2.state = State.offline
     modifier2.scope = Scope.local
     modifier2.src_attr = attr2.id
     modifier2.operator = Operator.post_percent
     modifier2.tgt_attr = attr3.id
     modifier2.domain = Domain.ship
     modifier2.filter_type = FilterType.all_
     modifier2.filter_value = None
     effect2 = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     effect2.modifiers = (modifier2, )
     holder2 = IndependentItem(
         self.ch.type_(type_id=2,
                       effects=(effect2, ),
                       attributes={attr2.id: 7.5}))
     holder3 = ShipItem(self.ch.type_(type_id=3, attributes={attr3.id:
                                                             0.5}))
     self.fit.items.add(holder1)
     self.fit.ship = holder2
     self.fit.items.add(holder3)
     self.assertAlmostEqual(holder3.attributes[attr3.id], 0.6875)
     holder1.attributes[attr1.id] = 4
     # Manually changed attribute must trigger damaging whole chain
     # of attributes, effectively allowing us to recalculate its new value
     self.assertAlmostEqual(holder3.attributes[attr3.id], 0.65)
     self.fit.items.remove(holder1)
     self.fit.ship = None
     self.fit.items.remove(holder3)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
 def test_attribute(self):
     attr1 = self.ch.attribute(attribute_id=1)
     attr2 = self.ch.attribute(attribute_id=2)
     attr3 = self.ch.attribute(attribute_id=3)
     modifier1 = Modifier()
     modifier1.state = State.offline
     modifier1.scope = Scope.local
     modifier1.src_attr = attr1.id
     modifier1.operator = Operator.post_mul
     modifier1.tgt_attr = attr2.id
     modifier1.domain = Domain.ship
     modifier1.filter_type = None
     modifier1.filter_value = None
     effect1 = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect1.modifiers = (modifier1, )
     holder1 = CharacterItem(
         self.ch.type_(type_id=1,
                       effects=(effect1, ),
                       attributes={attr1.id: 5}))
     modifier2 = Modifier()
     modifier2.state = State.offline
     modifier2.scope = Scope.local
     modifier2.src_attr = attr2.id
     modifier2.operator = Operator.post_percent
     modifier2.tgt_attr = attr3.id
     modifier2.domain = Domain.ship
     modifier2.filter_type = FilterType.all_
     modifier2.filter_value = None
     effect2 = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     effect2.modifiers = (modifier2, )
     holder2 = IndependentItem(
         self.ch.type_(type_id=2,
                       effects=(effect2, ),
                       attributes={attr2.id: 7.5}))
     holder3 = ShipItem(self.ch.type_(type_id=3, attributes={attr3.id:
                                                             0.5}))
     self.fit.items.add(holder1)
     self.fit.ship = holder2
     self.fit.items.add(holder3)
     self.assertAlmostEqual(holder3.attributes[attr3.id], 0.6875)
     self.fit.items.remove(holder1)
     # When holder1 is removed, attr2 of holder2 and attr3 of holder3
     # must be cleaned to allow recalculation of attr3 based on new data
     self.assertAlmostEqual(holder3.attributes[attr3.id], 0.5375)
     self.fit.ship = None
     self.fit.items.remove(holder3)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #9
0
 def test_log_other(self):
     # Check how unknown operator value influences
     # attribute calculator
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     invalid_modifier = Modifier()
     invalid_modifier.state = State.offline
     invalid_modifier.scope = Scope.local
     invalid_modifier.src_attr = src_attr.id
     invalid_modifier.operator = 1008
     invalid_modifier.tgt_attr = tgt_attr.id
     invalid_modifier.domain = Domain.self_
     invalid_modifier.filter_type = None
     invalid_modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (invalid_modifier,)
     holder = IndependentItem(self.ch.type_(type_id=83, effects=(effect,),
                                            attributes={src_attr.id: 1.2, tgt_attr.id: 100}))
     self.fit.items.add(holder)
     self.assertAlmostEqual(holder.attributes[tgt_attr.id], 100)
     self.assertEqual(len(self.log), 1)
     log_record = self.log[0]
     self.assertEqual(log_record.name, 'eos_test.attribute_calculator')
     self.assertEqual(log_record.levelno, Logger.WARNING)
     self.assertEqual(log_record.msg, 'malformed modifier on item 83: unknown operator 1008')
     self.fit.items.remove(holder)
     self.assert_link_buffers_empty(self.fit)
Пример #10
0
 def test_cap_update(self):
     # If cap updates, capped attributes should
     # be updated too
     holder = ShipItem(self.ch.type_(
         type_id=1, effects=(self.effect,),
         attributes={self.capped_attr.id: 3, self.source_attr.id: 6, self.capping_attr.id: 2}
     ))
     self.fit.items.add(holder)
     # Check attribute vs original cap
     self.assertAlmostEqual(holder.attributes[self.capped_attr.id], 2)
     # Add something which changes capping attribute
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = self.source_attr.id
     modifier.operator = Operator.post_mul
     modifier.tgt_attr = self.capping_attr.id
     modifier.domain = Domain.ship
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     cap_updater = IndependentItem(self.ch.type_(
         type_id=2, effects=(effect,),
         attributes={self.source_attr.id: 3.5}
     ))
     self.fit.items.add(cap_updater)
     # As capping attribute is updated, capped attribute must be updated too
     self.assertAlmostEqual(holder.attributes[self.capped_attr.id], 7)
     self.fit.items.remove(holder)
     self.fit.items.remove(cap_updater)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #11
0
 def test_error(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = tgt_attr.id
     modifier.domain = Domain.space
     modifier.filter_type = None
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier, )
     influence_source = IndependentItem(
         self.ch.type_(type_id=34,
                       effects=(effect, ),
                       attributes={src_attr.id: 20}))
     # Space domain was introduced in Eos as holder to contain in-space
     # items like missiles or drones, but it can't be targeted directly
     self.fit.items.add(influence_source)
     self.assertEqual(len(self.log), 2)
     for log_record in self.log:
         self.assertEqual(log_record.name,
                          'eos.fit.attribute_calculator.register')
         self.assertEqual(log_record.levelno, logging.WARNING)
         self.assertEqual(
             log_record.msg,
             'malformed modifier on item 34: unsupported target '
             'domain {} for direct modification'.format(Domain.space))
     self.fit.items.remove(influence_source)
     self.assert_link_buffers_empty(self.fit)
Пример #12
0
 def test_log_other(self):
     # Check how unknown operator value influences
     # attribute calculator
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     invalid_modifier = Modifier()
     invalid_modifier.state = State.offline
     invalid_modifier.scope = Scope.local
     invalid_modifier.src_attr = src_attr.id
     invalid_modifier.operator = 1008
     invalid_modifier.tgt_attr = tgt_attr.id
     invalid_modifier.domain = Domain.self_
     invalid_modifier.filter_type = None
     invalid_modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (invalid_modifier,)
     holder = IndependentItem(self.ch.type_(
         type_id=83, effects=(effect,), attributes={src_attr.id: 1.2, tgt_attr.id: 100}))
     self.fit.items.add(holder)
     self.assertAlmostEqual(holder.attributes[tgt_attr.id], 100)
     self.assertEqual(len(self.log), 1)
     log_record = self.log[0]
     self.assertEqual(log_record.name, 'eos.fit.attribute_calculator.map')
     self.assertEqual(log_record.levelno, logging.WARNING)
     self.assertEqual(log_record.msg, 'malformed modifier on item 83: unknown operator 1008')
     self.fit.items.remove(holder)
     self.assert_link_buffers_empty(self.fit)
Пример #13
0
 def test_cap_modified(self):
     # Make sure that holder's own specified attribute
     # value is taken as cap, and it's taken with all
     # modifications applied onto it
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = self.source_attr.id
     modifier.operator = Operator.post_mul
     modifier.tgt_attr = self.capping_attr.id
     modifier.domain = Domain.self_
     modifier.filter_type = None
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     effect.modifiers = (modifier, )
     holder = IndependentItem(
         self.ch.type_(type_id=1,
                       effects=(self.effect, effect),
                       attributes={
                           self.capped_attr.id: 3,
                           self.source_attr.id: 6,
                           self.capping_attr.id: 0.1
                       }))
     self.fit.items.add(holder)
     # Attr value is 3 * 6 = 18, but cap value is 0.1 * 6 = 0.6
     self.assertAlmostEqual(holder.attributes[self.capped_attr.id], 0.6)
     self.fit.items.remove(holder)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #14
0
 def test_error(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = tgt_attr.id
     modifier.domain = Domain.target
     modifier.filter_type = None
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     influence_source = IndependentItem(self.ch.type_(type_id=102, effects=(effect,), attributes={src_attr.id: 20}))
     # This functionality isn't implemented for now
     self.fit.items.add(influence_source)
     self.assertEqual(len(self.log), 2)
     for log_record in self.log:
         self.assertEqual(log_record.name, 'eos.fit.attribute_calculator.register')
         self.assertEqual(log_record.levelno, logging.WARNING)
         self.assertEqual(
             log_record.msg,
             'malformed modifier on item 102: unsupported target '
             'domain {} for direct modification'.format(Domain.target)
         )
     self.fit.items.remove(influence_source)
     self.assert_link_buffers_empty(self.fit)
Пример #15
0
 def test_character(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = tgt_attr.id
     modifier.domain = Domain.character
     modifier.filter_type = None
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     influence_source = IndependentItem(self.ch.type_(type_id=1, effects=(effect,), attributes={src_attr.id: 20}))
     self.fit.items.add(influence_source)
     item = self.ch.type_(type_id=2, attributes={tgt_attr.id: 100})
     influence_target1 = IndependentItem(item)
     self.fit.character = influence_target1
     self.assertNotAlmostEqual(influence_target1.attributes[tgt_attr.id], 100)
     self.fit.character = None
     influence_target2 = IndependentItem(item)
     self.fit.character = influence_target2
     self.assertNotAlmostEqual(influence_target2.attributes[tgt_attr.id], 100)
     self.fit.items.remove(influence_source)
     self.fit.character = None
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #16
0
 def test_error(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = tgt_attr.id
     modifier.domain = Domain.area
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     influence_source = IndependentItem(self.ch.type_(
         type_id=56, effects=(effect,), attributes={src_attr.id: 20}))
     # This domain just isn't used in EVE and unsupported by Eos by design
     self.fit.items.add(influence_source)
     self.assertEqual(len(self.log), 2)
     for log_record in self.log:
         self.assertEqual(log_record.name, 'eos.fit.attribute_calculator.register')
         self.assertEqual(log_record.levelno, logging.WARNING)
         self.assertEqual(
             log_record.msg,
             'malformed modifier on item 56: unsupported target domain '
             '{} for filtered modification'.format(Domain.area)
         )
     self.fit.items.remove(influence_source)
     self.assert_link_buffers_empty(self.fit)
Пример #17
0
 def test_error(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = tgt_attr.id
     modifier.domain = Domain.target
     modifier.filter_type = None
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier, )
     influence_source = IndependentItem(
         self.ch.type_(type_id=102,
                       effects=(effect, ),
                       attributes={src_attr.id: 20}))
     # This functionality isn't implemented for now
     self.fit.items.add(influence_source)
     self.assertEqual(len(self.log), 2)
     for log_record in self.log:
         self.assertEqual(log_record.name,
                          'eos.fit.attribute_calculator.register')
         self.assertEqual(log_record.levelno, logging.WARNING)
         self.assertEqual(
             log_record.msg,
             'malformed modifier on item 102: unsupported target '
             'domain {} for direct modification'.format(Domain.target))
     self.fit.items.remove(influence_source)
     self.assert_link_buffers_empty(self.fit)
Пример #18
0
 def test_character(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = tgt_attr.id
     modifier.domain = Domain.character
     modifier.filter_type = None
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier, )
     influence_source = IndependentItem(
         self.ch.type_(type_id=1,
                       effects=(effect, ),
                       attributes={src_attr.id: 20}))
     self.fit.items.add(influence_source)
     item = self.ch.type_(type_id=2, attributes={tgt_attr.id: 100})
     influence_target1 = IndependentItem(item)
     self.fit.character = influence_target1
     self.assertNotAlmostEqual(influence_target1.attributes[tgt_attr.id],
                               100)
     self.fit.character = None
     influence_target2 = IndependentItem(item)
     self.fit.character = influence_target2
     self.assertNotAlmostEqual(influence_target2.attributes[tgt_attr.id],
                               100)
     self.fit.items.remove(influence_source)
     self.fit.character = None
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #19
0
 def setUp(self):
     super().setUp()
     self.tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.mod_sub
     modifier.tgt_attr = self.tgt_attr.id
     modifier.domain = Domain.ship
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     self.influence_source1 = IndependentItem(self.ch.type_(
         type_id=1, effects=(effect,), attributes={src_attr.id: -10}))
     self.influence_source2 = IndependentItem(self.ch.type_(
         type_id=2, effects=(effect,), attributes={src_attr.id: 20}))
     self.influence_source3 = IndependentItem(self.ch.type_(
         type_id=3, effects=(effect,), attributes={src_attr.id: -53}))
     self.influence_target = ShipItem(self.ch.type_(type_id=4, attributes={self.tgt_attr.id: 100}))
     self.fit.items.add(self.influence_source1)
     self.fit.items.add(self.influence_source2)
     self.fit.items.add(self.influence_source3)
     self.fit.items.add(self.influence_target)
Пример #20
0
 def test_error(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = tgt_attr.id
     modifier.domain = Domain.space
     modifier.filter_type = None
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     influence_source = IndependentItem(self.ch.type_(type_id=34, effects=(effect,), attributes={src_attr.id: 20}))
     # Space domain was introduced in Eos as holder to contain in-space
     # items like missiles or drones, but it can't be targeted directly
     self.fit.items.add(influence_source)
     self.assertEqual(len(self.log), 1)
     log_record = self.log[0]
     self.assertEqual(log_record.name, 'eos_test.attribute_calculator')
     self.assertEqual(log_record.levelno, Logger.WARNING)
     self.assertEqual(log_record.msg,
                      'malformed modifier on item 34: unsupported target '
                      'domain {} for direct modification'.format(Domain.space))
     self.fit.items.remove(influence_source)
     self.assert_link_buffers_empty(self.fit)
Пример #21
0
 def test_error(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = tgt_attr.id
     modifier.domain = Domain.other
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     influence_source = IndependentItem(self.ch.type_(
         type_id=90, effects=(effect,), attributes={src_attr.id: 20}))
     # Charge's container or module's charge can't be 'owner'
     # of other holders, thus such modification type is unsupported
     self.fit.items.add(influence_source)
     self.assertEqual(len(self.log), 2)
     for log_record in self.log:
         self.assertEqual(log_record.name, 'eos.fit.attribute_calculator.register')
         self.assertEqual(log_record.levelno, logging.WARNING)
         self.assertEqual(
             log_record.msg,
             'malformed modifier on item 90: unsupported target domain '
             '{} for filtered modification'.format(Domain.other)
         )
     self.fit.items.remove(influence_source)
     self.assert_link_buffers_empty(self.fit)
Пример #22
0
 def test_error(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = tgt_attr.id
     modifier.domain = Domain.area
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     influence_source = IndependentItem(self.ch.type_(type_id=56, effects=(effect,),
                                                      attributes={src_attr.id: 20}))
     # This domain just isn't used in EVE and unsupported by Eos by design
     self.fit.items.add(influence_source)
     self.assertEqual(len(self.log), 1)
     log_record = self.log[0]
     self.assertEqual(log_record.name, 'eos_test.attribute_calculator')
     self.assertEqual(log_record.levelno, Logger.WARNING)
     self.assertEqual(log_record.msg,
                      'malformed modifier on item 56: unsupported target domain '
                      '{} for filtered modification'.format(Domain.area))
     self.fit.items.remove(influence_source)
     self.assert_link_buffers_empty(self.fit)
Пример #23
0
 def setUp(self):
     super().setUp()
     self.tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.mod_sub
     modifier.tgt_attr = self.tgt_attr.id
     modifier.domain = Domain.ship
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier, )
     self.influence_source1 = IndependentItem(
         self.ch.type_(type_id=1,
                       effects=(effect, ),
                       attributes={src_attr.id: -10}))
     self.influence_source2 = IndependentItem(
         self.ch.type_(type_id=2,
                       effects=(effect, ),
                       attributes={src_attr.id: 20}))
     self.influence_source3 = IndependentItem(
         self.ch.type_(type_id=3,
                       effects=(effect, ),
                       attributes={src_attr.id: -53}))
     self.influence_target = ShipItem(
         self.ch.type_(type_id=4, attributes={self.tgt_attr.id: 100}))
     self.fit.items.add(self.influence_source1)
     self.fit.items.add(self.influence_source2)
     self.fit.items.add(self.influence_source3)
     self.fit.items.add(self.influence_target)
Пример #24
0
    def test_cpu_modified(self):
        src_attr = self.ch.attribute(attribute_id=1)
        tgt_attr = self.ch.attribute(attribute_id=Attribute.cpu)
        modifier = Modifier()
        modifier.state = State.offline
        modifier.scope = Scope.local
        modifier.src_attr = src_attr.id
        modifier.operator = Operator.post_percent
        modifier.tgt_attr = tgt_attr.id
        modifier.domain = Domain.self_
        modifier.filter_type = None
        modifier.filter_value = None
        effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
        effect.modifiers = (modifier, )

        holder = IndependentItem(
            self.ch.type_(type_id=1,
                          effects=(effect, ),
                          attributes={
                              src_attr.id: 20,
                              tgt_attr.id: 1.9444
                          }))
        self.fit.items.add(holder)
        self.assertAlmostEqual(holder.attributes[tgt_attr.id], 2.33)
        self.fit.items.remove(holder)
        self.assertEqual(len(self.log), 0)
        self.assert_link_buffers_empty(self.fit)
Пример #25
0
 def setUp(self):
     AttrCalcTestCase.setUp(self)
     self.tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_div
     modifier.tgt_attr = self.tgt_attr.id
     modifier.domain = Domain.ship
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     self.influence_source1 = IndependentItem(self.ch.type_(type_id=1, effects=(effect,),
                                                            attributes={src_attr.id: 1.2}))
     self.influence_source2 = IndependentItem(self.ch.type_(type_id=2, effects=(effect,),
                                                            attributes={src_attr.id: 1.5}))
     self.influence_source3 = IndependentItem(self.ch.type_(type_id=3, effects=(effect,),
                                                            attributes={src_attr.id: 0.1}))
     self.influence_source4 = IndependentItem(self.ch.type_(type_id=4, effects=(effect,),
                                                            attributes={src_attr.id: 0.75}))
     self.influence_source5 = IndependentItem(self.ch.type_(type_id=5, effects=(effect,),
                                                            attributes={src_attr.id: 5}))
     self.influence_target = ShipItem(self.ch.type_(type_id=6, attributes={self.tgt_attr.id: 100}))
     self.fit.items.add(self.influence_source1)
     self.fit.items.add(self.influence_source2)
     self.fit.items.add(self.influence_source3)
     self.fit.items.add(self.influence_source4)
     self.fit.items.add(self.influence_source5)
     self.fit.items.add(self.influence_target)
Пример #26
0
 def test_cap_modified(self):
     # Make sure that holder's own specified attribute
     # value is taken as cap, and it's taken with all
     # modifications applied onto it
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = self.source_attr.id
     modifier.operator = Operator.post_mul
     modifier.tgt_attr = self.capping_attr.id
     modifier.domain = Domain.self_
     modifier.filter_type = None
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     holder = IndependentItem(self.ch.type_(
         type_id=1, effects=(self.effect, effect),
         attributes={self.capped_attr.id: 3, self.source_attr.id: 6, self.capping_attr.id: 0.1}
     ))
     self.fit.items.add(holder)
     # Attr value is 3 * 6 = 18, but cap value is 0.1 * 6 = 0.6
     self.assertAlmostEqual(holder.attributes[self.capped_attr.id], 0.6)
     self.fit.items.remove(holder)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #27
0
 def test_target_attributes(self):
     tgt_attr1 = self.ch.attribute(attribute_id=1)
     tgt_attr2 = self.ch.attribute(attribute_id=2)
     tgt_attr3 = self.ch.attribute(attribute_id=3)
     src_attr = self.ch.attribute(attribute_id=4)
     modifier1 = Modifier()
     modifier1.state = State.offline
     modifier1.scope = Scope.local
     modifier1.src_attr = src_attr.id
     modifier1.operator = Operator.post_percent
     modifier1.tgt_attr = tgt_attr1.id
     modifier1.domain = Domain.self_
     modifier1.filter_type = None
     modifier1.filter_value = None
     modifier2 = Modifier()
     modifier2.state = State.offline
     modifier2.scope = Scope.local
     modifier2.src_attr = src_attr.id
     modifier2.operator = Operator.post_percent
     modifier2.tgt_attr = tgt_attr2.id
     modifier2.domain = Domain.self_
     modifier2.filter_type = None
     modifier2.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier1, modifier2)
     holder = IndependentItem(
         self.ch.type_(type_id=1,
                       effects=(effect, ),
                       attributes={
                           tgt_attr1.id: 50,
                           tgt_attr2.id: 80,
                           tgt_attr3.id: 100,
                           src_attr.id: 20
                       }))
     self.fit.items.add(holder)
     # First attribute should be modified by modifier1
     self.assertAlmostEqual(holder.attributes[tgt_attr1.id], 60)
     # Second should be modified by modifier2
     self.assertAlmostEqual(holder.attributes[tgt_attr2.id], 96)
     # Third should stay unmodified
     self.assertAlmostEqual(holder.attributes[tgt_attr3.id], 100)
     self.fit.items.remove(holder)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #28
0
 def test_combination(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     abs_attr = self.ch.attribute(attribute_id=2)
     src_attr = self.ch.attribute(attribute_id=3)
     invalid_modifier = Modifier()
     invalid_modifier.state = State.offline
     invalid_modifier.scope = Scope.local
     invalid_modifier.src_attr = abs_attr.id
     invalid_modifier.operator = Operator.post_percent
     invalid_modifier.tgt_attr = tgt_attr.id
     invalid_modifier.domain = Domain.self_
     invalid_modifier.filter_type = None
     invalid_modifier.filter_value = None
     valid_modifier = Modifier()
     valid_modifier.state = State.offline
     valid_modifier.scope = Scope.local
     valid_modifier.src_attr = src_attr.id
     valid_modifier.operator = Operator.post_mul
     valid_modifier.tgt_attr = tgt_attr.id
     valid_modifier.domain = Domain.self_
     valid_modifier.filter_type = None
     valid_modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (invalid_modifier, valid_modifier)
     holder = IndependentItem(
         self.ch.type_(type_id=1,
                       effects=(effect, ),
                       attributes={
                           src_attr.id: 1.5,
                           tgt_attr.id: 100
                       }))
     self.fit.items.add(holder)
     # Invalid source value shouldn't screw whole calculation process
     self.assertNotAlmostEqual(holder.attributes[tgt_attr.id], 100)
     self.assertEqual(len(self.log), 1)
     log_record = self.log[0]
     self.assertEqual(log_record.name, 'eos.fit.attribute_calculator.map')
     self.assertEqual(log_record.levelno, logging.WARNING)
     self.assertEqual(
         log_record.msg,
         'unable to find base value for attribute 2 on item 1')
     self.fit.items.remove(holder)
     self.assert_link_buffers_empty(self.fit)
Пример #29
0
 def test_attribute(self):
     attr1 = self.ch.attribute(attribute_id=1)
     attr2 = self.ch.attribute(attribute_id=2)
     attr3 = self.ch.attribute(attribute_id=3)
     modifier1 = Modifier()
     modifier1.state = State.offline
     modifier1.scope = Scope.local
     modifier1.src_attr = attr1.id
     modifier1.operator = Operator.post_mul
     modifier1.tgt_attr = attr2.id
     modifier1.domain = Domain.ship
     modifier1.filter_type = None
     modifier1.filter_value = None
     effect1 = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect1.modifiers = (modifier1,)
     holder1 = CharacterItem(self.ch.type_(type_id=1, effects=(effect1,), attributes={attr1.id: 5}))
     modifier2 = Modifier()
     modifier2.state = State.offline
     modifier2.scope = Scope.local
     modifier2.src_attr = attr2.id
     modifier2.operator = Operator.post_percent
     modifier2.tgt_attr = attr3.id
     modifier2.domain = Domain.ship
     modifier2.filter_type = FilterType.all_
     modifier2.filter_value = None
     effect2 = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     effect2.modifiers = (modifier2,)
     holder2 = IndependentItem(self.ch.type_(type_id=2, effects=(effect2,), attributes={attr2.id: 7.5}))
     holder3 = ShipItem(self.ch.type_(type_id=3, attributes={attr3.id: 0.5}))
     self.fit.items.add(holder1)
     self.fit.ship = holder2
     self.fit.items.add(holder3)
     self.assertAlmostEqual(holder3.attributes[attr3.id], 0.6875)
     holder1.attributes[attr1.id] = 4
     # Manually changed attribute must trigger damaging whole chain
     # of attributes, effectively allowing us to recalculate its new value
     self.assertAlmostEqual(holder3.attributes[attr3.id], 0.65)
     self.fit.items.remove(holder1)
     self.fit.ship = None
     self.fit.items.remove(holder3)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #30
0
 def test_attribute(self):
     attr1 = self.ch.attribute(attribute_id=1)
     attr2 = self.ch.attribute(attribute_id=2)
     attr3 = self.ch.attribute(attribute_id=3)
     modifier1 = Modifier()
     modifier1.state = State.offline
     modifier1.scope = Scope.local
     modifier1.src_attr = attr1.id
     modifier1.operator = Operator.post_mul
     modifier1.tgt_attr = attr2.id
     modifier1.domain = Domain.ship
     modifier1.filter_type = None
     modifier1.filter_value = None
     effect1 = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect1.modifiers = (modifier1,)
     holder1 = CharacterItem(self.ch.type_(type_id=1, effects=(effect1,), attributes={attr1.id: 5}))
     modifier2 = Modifier()
     modifier2.state = State.offline
     modifier2.scope = Scope.local
     modifier2.src_attr = attr2.id
     modifier2.operator = Operator.post_percent
     modifier2.tgt_attr = attr3.id
     modifier2.domain = Domain.ship
     modifier2.filter_type = FilterType.all_
     modifier2.filter_value = None
     effect2 = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     effect2.modifiers = (modifier2,)
     holder2 = IndependentItem(self.ch.type_(type_id=2, effects=(effect2,), attributes={attr2.id: 7.5}))
     holder3 = ShipItem(self.ch.type_(type_id=3, attributes={attr3.id: 0.5}))
     self.fit.ship = holder2
     self.fit.items.add(holder3)
     self.assertAlmostEqual(holder3.attributes[attr3.id], 0.5375)
     self.fit.items.add(holder1)
     # Added holder must clean all already calculated attributes
     # which are now affected by it, to allow recalculation
     self.assertAlmostEqual(holder3.attributes[attr3.id], 0.6875)
     self.fit.items.remove(holder1)
     self.fit.ship = None
     self.fit.items.remove(holder3)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #31
0
 def test_target_attributes(self):
     tgt_attr1 = self.ch.attribute(attribute_id=1)
     tgt_attr2 = self.ch.attribute(attribute_id=2)
     tgt_attr3 = self.ch.attribute(attribute_id=3)
     src_attr = self.ch.attribute(attribute_id=4)
     modifier1 = Modifier()
     modifier1.state = State.offline
     modifier1.scope = Scope.local
     modifier1.src_attr = src_attr.id
     modifier1.operator = Operator.post_percent
     modifier1.tgt_attr = tgt_attr1.id
     modifier1.domain = Domain.self_
     modifier1.filter_type = None
     modifier1.filter_value = None
     modifier2 = Modifier()
     modifier2.state = State.offline
     modifier2.scope = Scope.local
     modifier2.src_attr = src_attr.id
     modifier2.operator = Operator.post_percent
     modifier2.tgt_attr = tgt_attr2.id
     modifier2.domain = Domain.self_
     modifier2.filter_type = None
     modifier2.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier1, modifier2)
     holder = IndependentItem(self.ch.type_(
         type_id=1, effects=(effect,),
         attributes={tgt_attr1.id: 50, tgt_attr2.id: 80, tgt_attr3.id: 100, src_attr.id: 20}
     ))
     self.fit.items.add(holder)
     # First attribute should be modified by modifier1
     self.assertAlmostEqual(holder.attributes[tgt_attr1.id], 60)
     # Second should be modified by modifier2
     self.assertAlmostEqual(holder.attributes[tgt_attr2.id], 96)
     # Third should stay unmodified
     self.assertAlmostEqual(holder.attributes[tgt_attr3.id], 100)
     self.fit.items.remove(holder)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #32
0
 def test_log_unorderable_combination(self):
     # Check how non-orderable operator value influences
     # attribute calculator. Previously, bug in calculation
     # method made it to crash
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     invalid_modifier = Modifier()
     invalid_modifier.state = State.offline
     invalid_modifier.scope = Scope.local
     invalid_modifier.src_attr = src_attr.id
     invalid_modifier.operator = None
     invalid_modifier.tgt_attr = tgt_attr.id
     invalid_modifier.domain = Domain.self_
     invalid_modifier.filter_type = None
     invalid_modifier.filter_value = None
     valid_modifier = Modifier()
     valid_modifier.state = State.offline
     valid_modifier.scope = Scope.local
     valid_modifier.src_attr = src_attr.id
     valid_modifier.operator = Operator.post_mul
     valid_modifier.tgt_attr = tgt_attr.id
     valid_modifier.domain = Domain.self_
     valid_modifier.filter_type = None
     valid_modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (invalid_modifier, valid_modifier)
     holder = IndependentItem(
         self.ch.type_(type_id=83, effects=(effect,), attributes={src_attr.id: 1.2, tgt_attr.id: 100})
     )
     self.fit.items.add(holder)
     self.assertAlmostEqual(holder.attributes[tgt_attr.id], 120)
     self.assertEqual(len(self.log), 1)
     log_record = self.log[0]
     self.assertEqual(log_record.name, "eos.fit.attribute_calculator.map")
     self.assertEqual(log_record.levelno, logging.WARNING)
     self.assertEqual(log_record.msg, "malformed modifier on item 83: unknown operator None")
     self.fit.items.remove(holder)
     self.assert_link_buffers_empty(self.fit)
Пример #33
0
 def setUp(self):
     super().setUp()
     self.tgt_attr = self.ch.attribute(attribute_id=1, stackable=0)
     self.src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = self.src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = self.tgt_attr.id
     modifier.domain = Domain.ship
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     self.effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     self.effect.modifiers = (modifier,)
Пример #34
0
 def setUp(self):
     super().setUp()
     self.tgt_attr = self.ch.attribute(attribute_id=1)
     self.src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = self.src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = self.tgt_attr.id
     modifier.domain = Domain.other
     modifier.filter_type = None
     modifier.filter_value = None
     self.effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     self.effect.modifiers = (modifier,)
Пример #35
0
 def setUp(self):
     AttrCalcTestCase.setUp(self)
     self.tgt_attr = self.ch.attribute(attribute_id=1, stackable=0)
     self.src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = self.src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = self.tgt_attr.id
     modifier.domain = Domain.ship
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     self.effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     self.effect.modifiers = (modifier,)
Пример #36
0
 def test_combination(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     abs_attr = self.ch.attribute(attribute_id=2)
     src_attr = self.ch.attribute(attribute_id=3)
     invalid_modifier = Modifier()
     invalid_modifier.state = State.offline
     invalid_modifier.scope = Scope.local
     invalid_modifier.src_attr = abs_attr.id
     invalid_modifier.operator = Operator.post_percent
     invalid_modifier.tgt_attr = tgt_attr.id
     invalid_modifier.domain = Domain.self_
     invalid_modifier.filter_type = None
     invalid_modifier.filter_value = None
     valid_modifier = Modifier()
     valid_modifier.state = State.offline
     valid_modifier.scope = Scope.local
     valid_modifier.src_attr = src_attr.id
     valid_modifier.operator = Operator.post_mul
     valid_modifier.tgt_attr = tgt_attr.id
     valid_modifier.domain = Domain.self_
     valid_modifier.filter_type = None
     valid_modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (invalid_modifier, valid_modifier)
     holder = IndependentItem(self.ch.type_(
         type_id=1, effects=(effect,), attributes={src_attr.id: 1.5, tgt_attr.id: 100}))
     self.fit.items.add(holder)
     # Invalid source value shouldn't screw whole calculation process
     self.assertNotAlmostEqual(holder.attributes[tgt_attr.id], 100)
     self.assertEqual(len(self.log), 1)
     log_record = self.log[0]
     self.assertEqual(log_record.name, 'eos.fit.attribute_calculator.map')
     self.assertEqual(log_record.levelno, logging.WARNING)
     self.assertEqual(log_record.msg, 'unable to find base value for attribute 2 on item 1')
     self.fit.items.remove(holder)
     self.assert_link_buffers_empty(self.fit)
Пример #37
0
 def setUp(self):
     super().setUp()
     self.tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = self.tgt_attr.id
     modifier.domain = Domain.ship
     modifier.filter_type = FilterType.skill_self
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     self.influence_source = IndependentItem(self.ch.type_(
         type_id=772, effects=(effect,), attributes={src_attr.id: 20}))
     self.fit.items.add(self.influence_source)
Пример #38
0
 def setUp(self):
     AttrCalcTestCase.setUp(self)
     self.tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = self.tgt_attr.id
     modifier.domain = Domain.self_
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     self.influence_source = IndependentItem(self.ch.type_(type_id=1061, effects=(effect,),
                                                           attributes={src_attr.id: 20}))
Пример #39
0
 def setUp(self):
     super().setUp()
     self.capped_attr = self.ch.attribute(attribute_id=1, max_attribute=2)
     self.capping_attr = self.ch.attribute(attribute_id=2, default_value=5)
     self.source_attr = self.ch.attribute(attribute_id=3)
     # Just to make sure cap is applied to final value, not
     # base, make some basic modification modifier
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = self.source_attr.id
     modifier.operator = Operator.post_mul
     modifier.tgt_attr = self.capped_attr.id
     modifier.domain = Domain.self_
     modifier.filter_type = None
     modifier.filter_value = None
     self.effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     self.effect.modifiers = (modifier,)
Пример #40
0
 def test_fit_attr_update(self):
     # Here we create 2 separate fits with ships affecting it;
     # each ship affects module with different strength. When we
     # pass module from one fit to another, its internal attribute
     # storage should be cleared. If it wasn't cleared, we wouldn't
     # be able to get refreshed value of attribute
     src_attr = self.ch.attribute(attribute_id=1)
     tgt_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = tgt_attr.id
     modifier.domain = Domain.ship
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier, )
     ship1 = IndependentItem(
         self.ch.type_(type_id=1,
                       effects=(effect, ),
                       attributes={src_attr.id: 10}))
     ship2 = IndependentItem(
         self.ch.type_(type_id=2,
                       effects=(effect, ),
                       attributes={src_attr.id: 20}))
     module = ShipItem(
         self.ch.type_(type_id=3, attributes={tgt_attr.id: 50}))
     fit1 = Fit(self.ch)
     fit1.ship = ship1
     fit2 = Fit(self.ch)
     fit2.ship = ship2
     fit1.items.add(module)
     self.assertAlmostEqual(module.attributes.get(tgt_attr.id), 55)
     fit1.items.remove(module)
     fit1.ship = None
     self.assert_link_buffers_empty(fit1)
     fit2.items.add(module)
     self.assertAlmostEqual(module.attributes.get(tgt_attr.id), 60)
     fit2.ship = None
     fit2.items.remove(module)
     self.assert_link_buffers_empty(fit2)
Пример #41
0
 def test_combination(self):
     valid_modifier = Modifier()
     valid_modifier.state = State.offline
     valid_modifier.scope = Scope.local
     valid_modifier.src_attr = self.src_attr.id
     valid_modifier.operator = Operator.post_percent
     valid_modifier.tgt_attr = self.tgt_attr.id
     valid_modifier.domain = Domain.self_
     valid_modifier.filter_type = None
     valid_modifier.filter_value = None
     self.effect.modifiers = (self.invalid_modifier, valid_modifier)
     holder = IndependentItem(self.ch.type_(type_id=1, effects=(self.effect,),
                                            attributes={self.src_attr.id: 20, self.tgt_attr.id: 100}))
     self.fit.items.add(holder)
     # Invalid domain in modifier should prevent proper processing of other modifiers
     self.assertNotAlmostEqual(holder.attributes[self.tgt_attr.id], 100)
     self.fit.items.remove(holder)
     self.assertEqual(len(self.log), 1)
     self.assert_link_buffers_empty(self.fit)
Пример #42
0
 def test_combination(self):
     valid_modifier = Modifier()
     valid_modifier.state = State.offline
     valid_modifier.scope = Scope.local
     valid_modifier.src_attr = self.src_attr.id
     valid_modifier.operator = Operator.post_percent
     valid_modifier.tgt_attr = self.tgt_attr.id
     valid_modifier.domain = Domain.self_
     valid_modifier.filter_type = None
     valid_modifier.filter_value = None
     self.effect.modifiers = (self.invalid_modifier, valid_modifier)
     holder = IndependentItem(self.ch.type_(
         type_id=1, effects=(self.effect,), attributes={self.src_attr.id: 20, self.tgt_attr.id: 100}))
     self.fit.items.add(holder)
     # Invalid domain in modifier should prevent proper processing of other modifiers
     self.assertNotAlmostEqual(holder.attributes[self.tgt_attr.id], 100)
     self.fit.items.remove(holder)
     self.assertEqual(len(self.log), 5)
     self.assert_link_buffers_empty(self.fit)
Пример #43
0
 def setUp(self):
     super().setUp()
     self.capped_attr = self.ch.attribute(attribute_id=1, max_attribute=2)
     self.capping_attr = self.ch.attribute(attribute_id=2, default_value=5)
     self.source_attr = self.ch.attribute(attribute_id=3)
     # Just to make sure cap is applied to final value, not
     # base, make some basic modification modifier
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = self.source_attr.id
     modifier.operator = Operator.post_mul
     modifier.tgt_attr = self.capped_attr.id
     modifier.domain = Domain.self_
     modifier.filter_type = None
     modifier.filter_value = None
     self.effect = self.ch.effect(effect_id=1,
                                  category=EffectCategory.passive)
     self.effect.modifiers = (modifier, )
Пример #44
0
 def setUp(self):
     super().setUp()
     self.tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = self.tgt_attr.id
     modifier.domain = Domain.character
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     # It doesn't matter holder of which type we're using,
     # the only thing which matters is its position in fit
     self.influence_source = IndependentItem(self.ch.type_(
         type_id=1, effects=(effect,), attributes={src_attr.id: 20}))
     self.fit.items.add(self.influence_source)
Пример #45
0
 def setUp(self):
     super().setUp()
     self.tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = self.tgt_attr.id
     modifier.domain = Domain.character
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier, )
     # It doesn't matter holder of which type we're using,
     # the only thing which matters is its position in fit
     self.influence_source = IndependentItem(
         self.ch.type_(type_id=1,
                       effects=(effect, ),
                       attributes={src_attr.id: 20}))
     self.fit.items.add(self.influence_source)
Пример #46
0
 def test_cap_update(self):
     # If cap updates, capped attributes should
     # be updated too
     holder = ShipItem(
         self.ch.type_(type_id=1,
                       effects=(self.effect, ),
                       attributes={
                           self.capped_attr.id: 3,
                           self.source_attr.id: 6,
                           self.capping_attr.id: 2
                       }))
     self.fit.items.add(holder)
     # Check attribute vs original cap
     self.assertAlmostEqual(holder.attributes[self.capped_attr.id], 2)
     # Add something which changes capping attribute
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = self.source_attr.id
     modifier.operator = Operator.post_mul
     modifier.tgt_attr = self.capping_attr.id
     modifier.domain = Domain.ship
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     effect.modifiers = (modifier, )
     cap_updater = IndependentItem(
         self.ch.type_(type_id=2,
                       effects=(effect, ),
                       attributes={self.source_attr.id: 3.5}))
     self.fit.items.add(cap_updater)
     # As capping attribute is updated, capped attribute must be updated too
     self.assertAlmostEqual(holder.attributes[self.capped_attr.id], 7)
     self.fit.items.remove(holder)
     self.fit.items.remove(cap_updater)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #47
0
 def test_fit_attr_update(self):
     # Here we create 2 separate fits with ships affecting it;
     # each ship affects module with different strength. When we
     # pass module from one fit to another, its internal attribute
     # storage should be cleared. If it wasn't cleared, we wouldn't
     # be able to get refreshed value of attribute
     src_attr = self.ch.attribute(attribute_id=1)
     tgt_attr = self.ch.attribute(attribute_id=2)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = src_attr.id
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = tgt_attr.id
     modifier.domain = Domain.ship
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect.modifiers = (modifier,)
     ship1 = IndependentItem(self.ch.type_(type_id=1, effects=(effect,), attributes={src_attr.id: 10}))
     ship2 = IndependentItem(self.ch.type_(type_id=2, effects=(effect,), attributes={src_attr.id: 20}))
     module = ShipItem(self.ch.type_(type_id=3, attributes={tgt_attr.id: 50}))
     fit1 = Fit(self.ch)
     fit1.ship = ship1
     fit2 = Fit(self.ch)
     fit2.ship = ship2
     fit1.items.add(module)
     self.assertAlmostEqual(module.attributes.get(tgt_attr.id), 55)
     fit1.items.remove(module)
     fit1.ship = None
     self.assert_link_buffers_empty(fit1)
     fit2.items.add(module)
     self.assertAlmostEqual(module.attributes.get(tgt_attr.id), 60)
     fit2.ship = None
     fit2.items.remove(module)
     self.assert_link_buffers_empty(fit2)
Пример #48
0
    def test_cpu_modified(self):
        src_attr = self.ch.attribute(attribute_id=1)
        tgt_attr = self.ch.attribute(attribute_id=Attribute.cpu)
        modifier = Modifier()
        modifier.state = State.offline
        modifier.scope = Scope.local
        modifier.src_attr = src_attr.id
        modifier.operator = Operator.post_percent
        modifier.tgt_attr = tgt_attr.id
        modifier.domain = Domain.self_
        modifier.filter_type = None
        modifier.filter_value = None
        effect = self.ch.effect(effect_id=1, category=EffectCategory.passive)
        effect.modifiers = (modifier,)

        holder = IndependentItem(self.ch.type_(
            type_id=1, effects=(effect,),
            attributes={src_attr.id: 20, tgt_attr.id: 1.9444}
        ))
        self.fit.items.add(holder)
        self.assertAlmostEqual(holder.attributes[tgt_attr.id], 2.33)
        self.fit.items.remove(holder)
        self.assertEqual(len(self.log), 0)
        self.assert_link_buffers_empty(self.fit)
Пример #49
0
 def test_source_attr_update(self):
     # Here we check if attributes are updated if fit gets new
     # source instance; we do not actually switch source but we
     # switch cache_handler, and it should be enough
     cache_handler1 = CacheHandler()
     cache_handler2 = CacheHandler()
     src_attr1 = cache_handler1.attribute(attribute_id=1)
     tgt_attr1 = cache_handler1.attribute(attribute_id=2, max_attribute=33)
     cache_handler1.attribute(attribute_id=33, default_value=100)
     src_attr2 = cache_handler2.attribute(attribute_id=1)
     tgt_attr2 = cache_handler2.attribute(attribute_id=2, max_attribute=333)
     cache_handler2.attribute(attribute_id=333, default_value=500)
     modifier = Modifier()
     modifier.state = State.offline
     modifier.scope = Scope.local
     modifier.src_attr = 1
     modifier.operator = Operator.post_percent
     modifier.tgt_attr = 2
     modifier.domain = Domain.ship
     modifier.filter_type = FilterType.all_
     modifier.filter_value = None
     effect1 = cache_handler1.effect(effect_id=1,
                                     category=EffectCategory.passive)
     effect1.modifiers = (modifier, )
     effect2 = cache_handler1.effect(effect_id=111,
                                     category=EffectCategory.passive)
     effect2.modifiers = (modifier, )
     # Our holders from test environment fo not update undelying
     # item automatically when source is changed, thus we do it
     # manually
     ship_item1 = cache_handler1.type_(type_id=8,
                                       effects=(effect1, ),
                                       attributes={src_attr1.id: 10})
     ship_item2 = cache_handler2.type_(type_id=8,
                                       effects=(effect2, ),
                                       attributes={src_attr2.id: 20})
     module_item1 = cache_handler1.type_(type_id=4,
                                         attributes={tgt_attr1.id: 50})
     module_item2 = cache_handler2.type_(type_id=4,
                                         attributes={tgt_attr2.id: 75})
     fit = Fit(cache_handler1)
     ship = IndependentItem(ship_item1)
     module = ShipItem(module_item1)
     fit.ship = ship
     fit.items.add(module)
     self.assertAlmostEqual(module.attributes.get(tgt_attr1.id), 55)
     # As we have capped attr, this auxiliary map shouldn't be None
     self.assertIsNotNone(module.attributes._cap_map)
     # Make an 'source switch': remove holders from attribute_calculator
     for holder in (ship, module):
         disabled_states = set(filter(lambda s: s <= holder.state, State))
         fit._link_tracker.disable_states(holder, disabled_states)
         fit._link_tracker.remove_holder(holder)
     # Refresh holders and replace source
     fit.source.cache_handler = cache_handler2
     ship.attributes.clear()
     ship.item = ship_item2
     module.attributes.clear()
     module.item = module_item2
     # When we cleared holders, auxiliary map for capped attrs should be None.
     # Using data in this map, attributes which depend on capping attribute will
     # be cleared. If we don't clear it, there're chances that in new data this
     # capping-capped attribute pair won't exist, thus if attribute with ID which
     # used to cap is changed, it will clear attribute which used to be capped -
     # and we do not want it within scope of new data.
     self.assertIsNone(module.attributes._cap_map)
     # Add holders again, when new items are in holders
     for holder in (ship, module):
         fit._link_tracker.add_holder(holder)
         enabled_states = set(filter(lambda s: s <= holder.state, State))
         fit._link_tracker.enable_states(holder, enabled_states)
     # Now we should have calculated value based on both updated attribs
     # if attribs weren't refreshed, we would use old value for modification
     # (10 instead of 20)
     self.assertAlmostEqual(module.attributes.get(tgt_attr2.id), 90)
     fit.ship = None
     fit.items.remove(module)
     self.assert_link_buffers_empty(fit)
Пример #50
0
 def test_all_in(self):
     tgt_attr = self.ch.attribute(attribute_id=1, stackable=0)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier_pre_ass = Modifier()
     modifier_pre_ass.state = State.offline
     modifier_pre_ass.scope = Scope.local
     modifier_pre_ass.src_attr = src_attr.id
     modifier_pre_ass.operator = Operator.pre_assign
     modifier_pre_ass.tgt_attr = tgt_attr.id
     modifier_pre_ass.domain = Domain.ship
     modifier_pre_ass.filter_type = FilterType.all_
     modifier_pre_ass.filter_value = None
     effect_pre_ass = self.ch.effect(effect_id=1,
                                     category=EffectCategory.passive)
     effect_pre_ass.modifiers = (modifier_pre_ass, )
     value_pre_ass = 5
     influence_source_pre_ass = IndependentItem(
         self.ch.type_(type_id=1,
                       effects=(effect_pre_ass, ),
                       attributes={src_attr.id: value_pre_ass}))
     self.fit.items.add(influence_source_pre_ass)
     modifier_pre_mul = Modifier()
     modifier_pre_mul.state = State.offline
     modifier_pre_mul.scope = Scope.local
     modifier_pre_mul.src_attr = src_attr.id
     modifier_pre_mul.operator = Operator.pre_mul
     modifier_pre_mul.tgt_attr = tgt_attr.id
     modifier_pre_mul.domain = Domain.ship
     modifier_pre_mul.filter_type = FilterType.all_
     modifier_pre_mul.filter_value = None
     effect_pre_mul = self.ch.effect(effect_id=2,
                                     category=EffectCategory.passive)
     effect_pre_mul.modifiers = (modifier_pre_mul, )
     value_pre_mul = 50
     influence_source_pre_mul = IndependentItem(
         self.ch.type_(type_id=2,
                       effects=(effect_pre_mul, ),
                       attributes={src_attr.id: value_pre_mul}))
     self.fit.items.add(influence_source_pre_mul)
     modifier_pre_div = Modifier()
     modifier_pre_div.state = State.offline
     modifier_pre_div.scope = Scope.local
     modifier_pre_div.src_attr = src_attr.id
     modifier_pre_div.operator = Operator.pre_div
     modifier_pre_div.tgt_attr = tgt_attr.id
     modifier_pre_div.domain = Domain.ship
     modifier_pre_div.filter_type = FilterType.all_
     modifier_pre_div.filter_value = None
     effect_pre_div = self.ch.effect(effect_id=3,
                                     category=EffectCategory.passive)
     effect_pre_div.modifiers = (modifier_pre_div, )
     value_pre_div = 0.5
     influence_source_pre_div = IndependentItem(
         self.ch.type_(type_id=3,
                       effects=(effect_pre_div, ),
                       attributes={src_attr.id: value_pre_div}))
     self.fit.items.add(influence_source_pre_div)
     modifier_mod_add = Modifier()
     modifier_mod_add.state = State.offline
     modifier_mod_add.scope = Scope.local
     modifier_mod_add.src_attr = src_attr.id
     modifier_mod_add.operator = Operator.mod_add
     modifier_mod_add.tgt_attr = tgt_attr.id
     modifier_mod_add.domain = Domain.ship
     modifier_mod_add.filter_type = FilterType.all_
     modifier_mod_add.filter_value = None
     effect_mod_add = self.ch.effect(effect_id=4,
                                     category=EffectCategory.passive)
     effect_mod_add.modifiers = (modifier_mod_add, )
     value_mod_add = 10
     influence_source_mod_add = IndependentItem(
         self.ch.type_(type_id=4,
                       effects=(effect_mod_add, ),
                       attributes={src_attr.id: value_mod_add}))
     self.fit.items.add(influence_source_mod_add)
     modifier_mod_sub = Modifier()
     modifier_mod_sub.state = State.offline
     modifier_mod_sub.scope = Scope.local
     modifier_mod_sub.src_attr = src_attr.id
     modifier_mod_sub.operator = Operator.mod_sub
     modifier_mod_sub.tgt_attr = tgt_attr.id
     modifier_mod_sub.domain = Domain.ship
     modifier_mod_sub.filter_type = FilterType.all_
     modifier_mod_sub.filter_value = None
     effect_mod_sub = self.ch.effect(effect_id=5,
                                     category=EffectCategory.passive)
     effect_mod_sub.modifiers = (modifier_mod_sub, )
     value_mod_sub = 63
     influence_source_mod_sub = IndependentItem(
         self.ch.type_(type_id=5,
                       effects=(effect_mod_sub, ),
                       attributes={src_attr.id: value_mod_sub}))
     self.fit.items.add(influence_source_mod_sub)
     modifier_post_mul = Modifier()
     modifier_post_mul.state = State.offline
     modifier_post_mul.scope = Scope.local
     modifier_post_mul.src_attr = src_attr.id
     modifier_post_mul.operator = Operator.post_mul
     modifier_post_mul.tgt_attr = tgt_attr.id
     modifier_post_mul.domain = Domain.ship
     modifier_post_mul.filter_type = FilterType.all_
     modifier_post_mul.filter_value = None
     effect_post_mul = self.ch.effect(effect_id=6,
                                      category=EffectCategory.passive)
     effect_post_mul.modifiers = (modifier_post_mul, )
     value_post_mul = 1.35
     influence_source_post_mul = IndependentItem(
         self.ch.type_(type_id=6,
                       effects=(effect_post_mul, ),
                       attributes={src_attr.id: value_post_mul}))
     self.fit.items.add(influence_source_post_mul)
     modifier_post_div = Modifier()
     modifier_post_div.state = State.offline
     modifier_post_div.scope = Scope.local
     modifier_post_div.src_attr = src_attr.id
     modifier_post_div.operator = Operator.post_div
     modifier_post_div.tgt_attr = tgt_attr.id
     modifier_post_div.domain = Domain.ship
     modifier_post_div.filter_type = FilterType.all_
     modifier_post_div.filter_value = None
     effect_post_div = self.ch.effect(effect_id=7,
                                      category=EffectCategory.passive)
     effect_post_div.modifiers = (modifier_post_div, )
     value_post_div = 2.7
     influence_source_post_div = IndependentItem(
         self.ch.type_(type_id=7,
                       effects=(effect_post_div, ),
                       attributes={src_attr.id: value_post_div}))
     self.fit.items.add(influence_source_post_div)
     modifier_post_perc = Modifier()
     modifier_post_perc.state = State.offline
     modifier_post_perc.scope = Scope.local
     modifier_post_perc.src_attr = src_attr.id
     modifier_post_perc.operator = Operator.post_percent
     modifier_post_perc.tgt_attr = tgt_attr.id
     modifier_post_perc.domain = Domain.ship
     modifier_post_perc.filter_type = FilterType.all_
     modifier_post_perc.filter_value = None
     effect_post_perc = self.ch.effect(effect_id=8,
                                       category=EffectCategory.passive)
     effect_post_perc.modifiers = (modifier_post_perc, )
     value_post_perc = 15
     influence_source_post_perc = IndependentItem(
         self.ch.type_(type_id=8,
                       effects=(effect_post_perc, ),
                       attributes={src_attr.id: value_post_perc}))
     self.fit.items.add(influence_source_post_perc)
     influence_target = ShipItem(
         self.ch.type_(type_id=9, attributes={tgt_attr.id: 100}))
     self.fit.items.add(influence_target)
     # Operators shouldn't be penalized and should go in this order
     exp_value = (((value_pre_ass * value_pre_mul / value_pre_div) +
                   value_mod_add - value_mod_sub) * value_post_mul /
                  value_post_div * (1 + value_post_perc / 100))
     self.assertAlmostEqual(influence_target.attributes[tgt_attr.id],
                            exp_value)
     self.fit.items.remove(influence_source_pre_ass)
     self.fit.items.remove(influence_source_pre_mul)
     self.fit.items.remove(influence_source_pre_div)
     self.fit.items.remove(influence_source_mod_add)
     self.fit.items.remove(influence_source_mod_sub)
     self.fit.items.remove(influence_source_post_mul)
     self.fit.items.remove(influence_source_post_div)
     self.fit.items.remove(influence_source_post_perc)
     self.fit.items.remove(influence_target)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #51
0
 def test_all_in(self):
     tgt_attr = self.ch.attribute(attribute_id=1, stackable=0)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier_pre_ass = Modifier()
     modifier_pre_ass.state = State.offline
     modifier_pre_ass.scope = Scope.local
     modifier_pre_ass.src_attr = src_attr.id
     modifier_pre_ass.operator = Operator.pre_assign
     modifier_pre_ass.tgt_attr = tgt_attr.id
     modifier_pre_ass.domain = Domain.ship
     modifier_pre_ass.filter_type = FilterType.all_
     modifier_pre_ass.filter_value = None
     effect_pre_ass = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect_pre_ass.modifiers = (modifier_pre_ass,)
     value_pre_ass = 5
     influence_source_pre_ass = IndependentItem(self.ch.type_(type_id=1, effects=(effect_pre_ass,),
                                                              attributes={src_attr.id: value_pre_ass}))
     self.fit.items.add(influence_source_pre_ass)
     modifier_pre_mul = Modifier()
     modifier_pre_mul.state = State.offline
     modifier_pre_mul.scope = Scope.local
     modifier_pre_mul.src_attr = src_attr.id
     modifier_pre_mul.operator = Operator.pre_mul
     modifier_pre_mul.tgt_attr = tgt_attr.id
     modifier_pre_mul.domain = Domain.ship
     modifier_pre_mul.filter_type = FilterType.all_
     modifier_pre_mul.filter_value = None
     effect_pre_mul = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     effect_pre_mul.modifiers = (modifier_pre_mul,)
     value_pre_mul = 50
     influence_source_pre_mul = IndependentItem(self.ch.type_(type_id=2, effects=(effect_pre_mul,),
                                                              attributes={src_attr.id: value_pre_mul}))
     self.fit.items.add(influence_source_pre_mul)
     modifier_pre_div = Modifier()
     modifier_pre_div.state = State.offline
     modifier_pre_div.scope = Scope.local
     modifier_pre_div.src_attr = src_attr.id
     modifier_pre_div.operator = Operator.pre_div
     modifier_pre_div.tgt_attr = tgt_attr.id
     modifier_pre_div.domain = Domain.ship
     modifier_pre_div.filter_type = FilterType.all_
     modifier_pre_div.filter_value = None
     effect_pre_div = self.ch.effect(effect_id=3, category=EffectCategory.passive)
     effect_pre_div.modifiers = (modifier_pre_div,)
     value_pre_div = 0.5
     influence_source_pre_div = IndependentItem(self.ch.type_(type_id=3, effects=(effect_pre_div,),
                                                              attributes={src_attr.id: value_pre_div}))
     self.fit.items.add(influence_source_pre_div)
     modifier_mod_add = Modifier()
     modifier_mod_add.state = State.offline
     modifier_mod_add.scope = Scope.local
     modifier_mod_add.src_attr = src_attr.id
     modifier_mod_add.operator = Operator.mod_add
     modifier_mod_add.tgt_attr = tgt_attr.id
     modifier_mod_add.domain = Domain.ship
     modifier_mod_add.filter_type = FilterType.all_
     modifier_mod_add.filter_value = None
     effect_mod_add = self.ch.effect(effect_id=4, category=EffectCategory.passive)
     effect_mod_add.modifiers = (modifier_mod_add,)
     value_mod_add = 10
     influence_source_mod_add = IndependentItem(self.ch.type_(type_id=4, effects=(effect_mod_add,),
                                                              attributes={src_attr.id: value_mod_add}))
     self.fit.items.add(influence_source_mod_add)
     modifier_mod_sub = Modifier()
     modifier_mod_sub.state = State.offline
     modifier_mod_sub.scope = Scope.local
     modifier_mod_sub.src_attr = src_attr.id
     modifier_mod_sub.operator = Operator.mod_sub
     modifier_mod_sub.tgt_attr = tgt_attr.id
     modifier_mod_sub.domain = Domain.ship
     modifier_mod_sub.filter_type = FilterType.all_
     modifier_mod_sub.filter_value = None
     effect_mod_sub = self.ch.effect(effect_id=5, category=EffectCategory.passive)
     effect_mod_sub.modifiers = (modifier_mod_sub,)
     value_mod_sub = 63
     influence_source_mod_sub = IndependentItem(self.ch.type_(type_id=5, effects=(effect_mod_sub,),
                                                              attributes={src_attr.id: value_mod_sub}))
     self.fit.items.add(influence_source_mod_sub)
     modifier_post_mul = Modifier()
     modifier_post_mul.state = State.offline
     modifier_post_mul.scope = Scope.local
     modifier_post_mul.src_attr = src_attr.id
     modifier_post_mul.operator = Operator.post_mul
     modifier_post_mul.tgt_attr = tgt_attr.id
     modifier_post_mul.domain = Domain.ship
     modifier_post_mul.filter_type = FilterType.all_
     modifier_post_mul.filter_value = None
     effect_post_mul = self.ch.effect(effect_id=6, category=EffectCategory.passive)
     effect_post_mul.modifiers = (modifier_post_mul,)
     value_post_mul = 1.35
     influence_source_post_mul = IndependentItem(self.ch.type_(type_id=6, effects=(effect_post_mul,),
                                                               attributes={src_attr.id: value_post_mul}))
     self.fit.items.add(influence_source_post_mul)
     modifier_post_div = Modifier()
     modifier_post_div.state = State.offline
     modifier_post_div.scope = Scope.local
     modifier_post_div.src_attr = src_attr.id
     modifier_post_div.operator = Operator.post_div
     modifier_post_div.tgt_attr = tgt_attr.id
     modifier_post_div.domain = Domain.ship
     modifier_post_div.filter_type = FilterType.all_
     modifier_post_div.filter_value = None
     effect_post_div = self.ch.effect(effect_id=7, category=EffectCategory.passive)
     effect_post_div.modifiers = (modifier_post_div,)
     value_post_div = 2.7
     influence_source_post_div = IndependentItem(self.ch.type_(type_id=7, effects=(effect_post_div,),
                                                               attributes={src_attr.id: value_post_div}))
     self.fit.items.add(influence_source_post_div)
     modifier_post_perc = Modifier()
     modifier_post_perc.state = State.offline
     modifier_post_perc.scope = Scope.local
     modifier_post_perc.src_attr = src_attr.id
     modifier_post_perc.operator = Operator.post_percent
     modifier_post_perc.tgt_attr = tgt_attr.id
     modifier_post_perc.domain = Domain.ship
     modifier_post_perc.filter_type = FilterType.all_
     modifier_post_perc.filter_value = None
     effect_post_perc = self.ch.effect(effect_id=8, category=EffectCategory.passive)
     effect_post_perc.modifiers = (modifier_post_perc,)
     value_post_perc = 15
     influence_source_post_perc = IndependentItem(self.ch.type_(type_id=8, effects=(effect_post_perc,),
                                                                attributes={src_attr.id: value_post_perc}))
     self.fit.items.add(influence_source_post_perc)
     influence_target = ShipItem(self.ch.type_(type_id=9, attributes={tgt_attr.id: 100}))
     self.fit.items.add(influence_target)
     # Operators shouldn't be penalized and should go in this order
     exp_value = (((value_pre_ass * value_pre_mul / value_pre_div) + value_mod_add - value_mod_sub) *
                  value_post_mul / value_post_div * (1 + value_post_perc / 100))
     self.assertAlmostEqual(influence_target.attributes[tgt_attr.id], exp_value)
     self.fit.items.remove(influence_source_pre_ass)
     self.fit.items.remove(influence_source_pre_mul)
     self.fit.items.remove(influence_source_pre_div)
     self.fit.items.remove(influence_source_mod_add)
     self.fit.items.remove(influence_source_mod_sub)
     self.fit.items.remove(influence_source_post_mul)
     self.fit.items.remove(influence_source_post_div)
     self.fit.items.remove(influence_source_post_perc)
     self.fit.items.remove(influence_target)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #52
0
 def test_forced_value(self):
     tgt_attr = self.ch.attribute(attribute_id=1)
     src_attr = self.ch.attribute(attribute_id=2)
     modifier_pre_ass = Modifier()
     modifier_pre_ass.state = State.offline
     modifier_pre_ass.scope = Scope.local
     modifier_pre_ass.src_attr = src_attr.id
     modifier_pre_ass.operator = Operator.pre_assign
     modifier_pre_ass.tgt_attr = tgt_attr.id
     modifier_pre_ass.domain = Domain.ship
     modifier_pre_ass.filter_type = FilterType.all_
     modifier_pre_ass.filter_value = None
     effect_pre_ass = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect_pre_ass.modifiers = (modifier_pre_ass,)
     influence_source_pre_ass = IndependentItem(self.ch.type_(
         type_id=1, effects=(effect_pre_ass,), attributes={src_attr.id: 5}))
     self.fit.items.add(influence_source_pre_ass)
     modifier_pre_mul = Modifier()
     modifier_pre_mul.state = State.offline
     modifier_pre_mul.scope = Scope.local
     modifier_pre_mul.src_attr = src_attr.id
     modifier_pre_mul.operator = Operator.pre_mul
     modifier_pre_mul.tgt_attr = tgt_attr.id
     modifier_pre_mul.domain = Domain.ship
     modifier_pre_mul.filter_type = FilterType.all_
     modifier_pre_mul.filter_value = None
     effect_pre_mul = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     effect_pre_mul.modifiers = (modifier_pre_mul,)
     influence_source_pre_mul = IndependentItem(self.ch.type_(
         type_id=2, effects=(effect_pre_mul,), attributes={src_attr.id: 50}))
     self.fit.items.add(influence_source_pre_mul)
     modifier_pre_div = Modifier()
     modifier_pre_div.state = State.offline
     modifier_pre_div.scope = Scope.local
     modifier_pre_div.src_attr = src_attr.id
     modifier_pre_div.operator = Operator.pre_div
     modifier_pre_div.tgt_attr = tgt_attr.id
     modifier_pre_div.domain = Domain.ship
     modifier_pre_div.filter_type = FilterType.all_
     modifier_pre_div.filter_value = None
     effect_pre_div = self.ch.effect(effect_id=3, category=EffectCategory.passive)
     effect_pre_div.modifiers = (modifier_pre_div,)
     influence_source_pre_div = IndependentItem(self.ch.type_(
         type_id=3, effects=(effect_pre_div,), attributes={src_attr.id: 0.5}))
     self.fit.items.add(influence_source_pre_div)
     modifier_mod_add = Modifier()
     modifier_mod_add.state = State.offline
     modifier_mod_add.scope = Scope.local
     modifier_mod_add.src_attr = src_attr.id
     modifier_mod_add.operator = Operator.mod_add
     modifier_mod_add.tgt_attr = tgt_attr.id
     modifier_mod_add.domain = Domain.ship
     modifier_mod_add.filter_type = FilterType.all_
     modifier_mod_add.filter_value = None
     effect_mod_add = self.ch.effect(effect_id=4, category=EffectCategory.passive)
     effect_mod_add.modifiers = (modifier_mod_add,)
     influence_source_mod_add = IndependentItem(self.ch.type_(
         type_id=4, effects=(effect_mod_add,), attributes={src_attr.id: 10}))
     self.fit.items.add(influence_source_mod_add)
     modifier_mod_sub = Modifier()
     modifier_mod_sub.state = State.offline
     modifier_mod_sub.scope = Scope.local
     modifier_mod_sub.src_attr = src_attr.id
     modifier_mod_sub.operator = Operator.mod_sub
     modifier_mod_sub.tgt_attr = tgt_attr.id
     modifier_mod_sub.domain = Domain.ship
     modifier_mod_sub.filter_type = FilterType.all_
     modifier_mod_sub.filter_value = None
     effect_mod_sub = self.ch.effect(effect_id=5, category=EffectCategory.passive)
     effect_mod_sub.modifiers = (modifier_mod_sub,)
     influence_source_mod_sub = IndependentItem(self.ch.type_(
         type_id=5, effects=(effect_mod_sub,), attributes={src_attr.id: 63}))
     self.fit.items.add(influence_source_mod_sub)
     modifier_post_mul = Modifier()
     modifier_post_mul.state = State.offline
     modifier_post_mul.scope = Scope.local
     modifier_post_mul.src_attr = src_attr.id
     modifier_post_mul.operator = Operator.post_mul
     modifier_post_mul.tgt_attr = tgt_attr.id
     modifier_post_mul.domain = Domain.ship
     modifier_post_mul.filter_type = FilterType.all_
     modifier_post_mul.filter_value = None
     effect_post_mul = self.ch.effect(effect_id=6, category=EffectCategory.passive)
     effect_post_mul.modifiers = (modifier_post_mul,)
     influence_source_post_mul = IndependentItem(self.ch.type_(
         type_id=6, effects=(effect_post_mul,), attributes={src_attr.id: 1.35}))
     self.fit.items.add(influence_source_post_mul)
     modifier_post_div = Modifier()
     modifier_post_div.state = State.offline
     modifier_post_div.scope = Scope.local
     modifier_post_div.src_attr = src_attr.id
     modifier_post_div.operator = Operator.post_div
     modifier_post_div.tgt_attr = tgt_attr.id
     modifier_post_div.domain = Domain.ship
     modifier_post_div.filter_type = FilterType.all_
     modifier_post_div.filter_value = None
     effect_post_div = self.ch.effect(effect_id=7, category=EffectCategory.passive)
     effect_post_div.modifiers = (modifier_post_div,)
     influence_source_post_div = IndependentItem(self.ch.type_(
         type_id=7, effects=(effect_post_div,), attributes={src_attr.id: 2.7}))
     self.fit.items.add(influence_source_post_div)
     modifier_post_perc = Modifier()
     modifier_post_perc.state = State.offline
     modifier_post_perc.scope = Scope.local
     modifier_post_perc.src_attr = src_attr.id
     modifier_post_perc.operator = Operator.post_percent
     modifier_post_perc.tgt_attr = tgt_attr.id
     modifier_post_perc.domain = Domain.ship
     modifier_post_perc.filter_type = FilterType.all_
     modifier_post_perc.filter_value = None
     effect_post_perc = self.ch.effect(effect_id=8, category=EffectCategory.passive)
     effect_post_perc.modifiers = (modifier_post_perc,)
     influence_source_post_perc = IndependentItem(self.ch.type_(
         type_id=8, effects=(effect_post_perc,), attributes={src_attr.id: 15}))
     self.fit.items.add(influence_source_post_perc)
     modifier_post_ass = Modifier()
     modifier_post_ass.state = State.offline
     modifier_post_ass.scope = Scope.local
     modifier_post_ass.src_attr = src_attr.id
     modifier_post_ass.operator = Operator.post_assign
     modifier_post_ass.tgt_attr = tgt_attr.id
     modifier_post_ass.domain = Domain.ship
     modifier_post_ass.filter_type = FilterType.all_
     modifier_post_ass.filter_value = None
     effect_post_ass = self.ch.effect(effect_id=9, category=EffectCategory.passive)
     effect_post_ass.modifiers = (modifier_post_ass,)
     influence_source_post_ass = IndependentItem(self.ch.type_(
         type_id=9, effects=(effect_post_ass,), attributes={src_attr.id: 68}))
     self.fit.items.add(influence_source_post_ass)
     influence_target = ShipItem(self.ch.type_(type_id=10, attributes={tgt_attr.id: 100}))
     self.fit.items.add(influence_target)
     # Post-assignment value must override all other modifications
     self.assertAlmostEqual(influence_target.attributes[tgt_attr.id], 68)
     self.fit.items.remove(influence_source_pre_ass)
     self.fit.items.remove(influence_source_pre_mul)
     self.fit.items.remove(influence_source_pre_div)
     self.fit.items.remove(influence_source_mod_add)
     self.fit.items.remove(influence_source_mod_sub)
     self.fit.items.remove(influence_source_post_mul)
     self.fit.items.remove(influence_source_post_div)
     self.fit.items.remove(influence_source_post_perc)
     self.fit.items.remove(influence_source_post_ass)
     self.fit.items.remove(influence_target)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)
Пример #53
0
 def test_calculation(self):
     attr1 = self.ch.attribute(attribute_id=1)
     attr2 = self.ch.attribute(attribute_id=2)
     attr3 = self.ch.attribute(attribute_id=3)
     attr4 = self.ch.attribute(attribute_id=4)
     modifier1 = Modifier()
     modifier1.state = State.offline
     modifier1.scope = Scope.local
     modifier1.src_attr = attr1.id
     modifier1.operator = Operator.post_mul
     modifier1.tgt_attr = attr2.id
     modifier1.domain = Domain.self_
     modifier1.filter_type = None
     modifier1.filter_value = None
     effect1 = self.ch.effect(effect_id=1, category=EffectCategory.passive)
     effect1.modifiers = (modifier1, )
     modifier2 = Modifier()
     modifier2.state = State.offline
     modifier2.scope = Scope.local
     modifier2.src_attr = attr2.id
     modifier2.operator = Operator.post_percent
     modifier2.tgt_attr = attr3.id
     modifier2.domain = Domain.ship
     modifier2.filter_type = None
     modifier2.filter_value = None
     effect2 = self.ch.effect(effect_id=2, category=EffectCategory.passive)
     effect2.modifiers = (modifier2, )
     holder1 = CharacterItem(
         self.ch.type_(type_id=1,
                       effects=(effect1, effect2),
                       attributes={
                           attr1.id: 5,
                           attr2.id: 20
                       }))
     modifier3 = Modifier()
     modifier3.state = State.offline
     modifier3.scope = Scope.local
     modifier3.src_attr = attr3.id
     modifier3.operator = Operator.post_percent
     modifier3.tgt_attr = attr4.id
     modifier3.domain = Domain.ship
     modifier3.filter_type = FilterType.all_
     modifier3.filter_value = None
     effect3 = self.ch.effect(effect_id=3, category=EffectCategory.passive)
     effect3.modifiers = (modifier3, )
     holder2 = IndependentItem(
         self.ch.type_(type_id=2,
                       effects=(effect3, ),
                       attributes={attr3.id: 150}))
     holder3 = ShipItem(
         self.ch.type_(type_id=3, attributes={attr4.id: 12.5}))
     self.fit.items.add(holder1)
     self.fit.ship = holder2
     self.fit.items.add(holder3)
     # If everything is processed properly, holder1 will multiply attr2 by attr1
     # on self, resulting in 20 * 5 = 100, then apply it as percentage modifier
     # on ship's (holder2) attr3, resulting in 150 + 100% = 300, then it is applied
     # to all entities assigned to ship, including holder3, to theirs attr4 as
     # percentage modifier again - so final result is 12.5 + 300% = 50
     self.assertAlmostEqual(holder3.attributes[attr4.id], 50)
     self.fit.items.remove(holder1)
     self.fit.ship = None
     self.fit.items.remove(holder3)
     self.assertEqual(len(self.log), 0)
     self.assert_link_buffers_empty(self.fit)