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)
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} ))
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)
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 }))
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)
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}))
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)
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.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)
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)
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)
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,)
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,)
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,)
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)
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)
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}))
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,)
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)
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)
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)
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, )
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)
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)
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)
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)
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)
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)
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)
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)
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)
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)