diff --git a/evennia/contrib/rpg/traits/tests.py b/evennia/contrib/rpg/traits/tests.py index ddc746d2c4..4ef1da19e1 100644 --- a/evennia/contrib/rpg/traits/tests.py +++ b/evennia/contrib/rpg/traits/tests.py @@ -286,13 +286,14 @@ class TestTraitStatic(_TraitHandlerBase): trait_type="static", base=1, mod=2, + mult=1.0, extra_val1="xvalue1", extra_val2="xvalue2", ) self.trait = self.traithandler.get("test1") def _get_values(self): - return self.trait.base, self.trait.mod, self.trait.value + return self.trait.base, self.trait.mod, self.trait.mult, self.trait.value def test_init(self): self.assertEqual( @@ -302,25 +303,34 @@ class TestTraitStatic(_TraitHandlerBase): "trait_type": "static", "base": 1, "mod": 2, + "mult": 1.0, "extra_val1": "xvalue1", "extra_val2": "xvalue2", }, ) def test_value(self): - """value is base + mod""" - self.assertEqual(self._get_values(), (1, 2, 3)) + """value is (base + mod) * mult""" + self.assertEqual(self._get_values(), (1, 2, 1.0, 3)) self.trait.base += 4 - self.assertEqual(self._get_values(), (5, 2, 7)) + self.assertEqual(self._get_values(), (5, 2, 1.0, 7)) self.trait.mod -= 1 - self.assertEqual(self._get_values(), (5, 1, 6)) + self.assertEqual(self._get_values(), (5, 1, 1.0, 6)) + self.trait.mult += 1.0 + self.assertEqual(self._get_values(), (5, 1, 2.0, 12)) + self.trait.mult = 0.75 + self.assertEqual(self._get_values(), (5, 1, 0.75, 4.5)) + def test_delete(self): """Deleting resets to default.""" + self.trait.mult = 2.0 del self.trait.base - self.assertEqual(self._get_values(), (0, 2, 2)) + self.assertEqual(self._get_values(), (0, 2, 2.0, 4)) + del self.trait.mult + self.assertEqual(self._get_values(), (0, 2, 1.0, 2)) del self.trait.mod - self.assertEqual(self._get_values(), (0, 0, 0)) + self.assertEqual(self._get_values(), (0, 0, 1.0, 0)) class TestTraitCounter(_TraitHandlerBase): @@ -336,6 +346,7 @@ class TestTraitCounter(_TraitHandlerBase): trait_type="counter", base=1, mod=2, + mult=1.0, min=0, max=10, extra_val1="xvalue1", @@ -350,8 +361,8 @@ class TestTraitCounter(_TraitHandlerBase): self.trait = self.traithandler.get("test1") def _get_values(self): - """Get (base, mod, value, min, max).""" - return (self.trait.base, self.trait.mod, self.trait.value, self.trait.min, self.trait.max) + """Get (base, mod, mult, value, min, max).""" + return (self.trait.base, self.trait.mod, self.trait.mult, self.trait.value, self.trait.min, self.trait.max) def test_init(self): self.assertEqual( @@ -361,6 +372,7 @@ class TestTraitCounter(_TraitHandlerBase): "trait_type": "counter", "base": 1, "mod": 2, + "mult": 1.0, "min": 0, "max": 10, "extra_val1": "xvalue1", @@ -378,102 +390,105 @@ class TestTraitCounter(_TraitHandlerBase): ) def test_value(self): - """value is current + mod, where current defaults to base""" - self.assertEqual(self._get_values(), (1, 2, 3, 0, 10)) + """value is (current + mod) * mult, where current defaults to base""" + self.assertEqual(self._get_values(), (1, 2, 1.0, 3, 0, 10)) self.trait.base += 4 - self.assertEqual(self._get_values(), (5, 2, 7, 0, 10)) + self.assertEqual(self._get_values(), (5, 2, 1.0, 7, 0, 10)) self.trait.mod -= 1 - self.assertEqual(self._get_values(), (5, 1, 6, 0, 10)) + self.assertEqual(self._get_values(), (5, 1, 1.0, 6, 0, 10)) + self.trait.mult += 1.0 + self.assertEqual(self._get_values(), (5, 1, 2.0, 10, 0, 10)) def test_boundaries__minmax(self): """Test range""" # should not exceed min/max values self.trait.base += 20 - self.assertEqual(self._get_values(), (8, 2, 10, 0, 10)) + self.assertEqual(self._get_values(), (8, 2, 1.0, 10, 0, 10)) self.trait.base = 100 - self.assertEqual(self._get_values(), (8, 2, 10, 0, 10)) + self.assertEqual(self._get_values(), (8, 2, 1.0, 10, 0, 10)) self.trait.base -= 40 - self.assertEqual(self._get_values(), (-2, 2, 0, 0, 10)) + self.assertEqual(self._get_values(), (-2, 2, 1.0, 0, 0, 10)) self.trait.base = -100 - self.assertEqual(self._get_values(), (-2, 2, 0, 0, 10)) + self.assertEqual(self._get_values(), (-2, 2, 1.0, 0, 0, 10)) def test_boundaries__bigmod(self): """add a big mod""" self.trait.base = 5 self.trait.mod = 100 - self.assertEqual(self._get_values(), (5, 5, 10, 0, 10)) + self.assertEqual(self._get_values(), (5, 5, 1.0, 10, 0, 10)) self.trait.mod = -100 - self.assertEqual(self._get_values(), (5, -5, 0, 0, 10)) + self.assertEqual(self._get_values(), (5, -5, 1.0, 0, 0, 10)) def test_boundaries__change_boundaries(self): """Change boundaries after base/mod change""" self.trait.base = 5 self.trait.mod = -100 self.trait.min = -20 - self.assertEqual(self._get_values(), (5, -5, 0, -20, 10)) + self.assertEqual(self._get_values(), (5, -5, 1.0, 0, -20, 10)) self.trait.mod -= 100 - self.assertEqual(self._get_values(), (5, -25, -20, -20, 10)) + self.assertEqual(self._get_values(), (5, -25, 1.0, -20, -20, 10)) self.trait.mod = 100 self.trait.max = 20 - self.assertEqual(self._get_values(), (5, 5, 10, -20, 20)) + self.assertEqual(self._get_values(), (5, 5, 1.0, 10, -20, 20)) self.trait.mod = 100 - self.assertEqual(self._get_values(), (5, 15, 20, -20, 20)) + self.assertEqual(self._get_values(), (5, 15, 1.0, 20, -20, 20)) def test_boundaries__disable(self): """Disable and re-enable boundaries""" self.trait.base = 5 self.trait.mod = 100 - self.assertEqual(self._get_values(), (5, 5, 10, 0, 10)) + self.assertEqual(self._get_values(), (5, 5, 1.0, 10, 0, 10)) del self.trait.max self.assertEqual(self.trait.max, None) del self.trait.min self.assertEqual(self.trait.min, None) self.trait.base = 100 - self.assertEqual(self._get_values(), (100, 5, 105, None, None)) + self.assertEqual(self._get_values(), (100, 5, 1.0, 105, None, None)) self.trait.base = -200 - self.assertEqual(self._get_values(), (-200, 5, -195, None, None)) + self.assertEqual(self._get_values(), (-200, 5, 1.0, -195, None, None)) # re-activate boundaries self.trait.max = 15 self.trait.min = 10 # his is blocked since base+mod is lower - self.assertEqual(self._get_values(), (-200, 5, -195, -195, 15)) + self.assertEqual(self._get_values(), (-200, 5, 1.0, -195, -195, 15)) def test_boundaries__inverse(self): """Set inverse boundaries - limited by base""" self.trait.mod = 0 - self.assertEqual(self._get_values(), (1, 0, 1, 0, 10)) + self.assertEqual(self._get_values(), (1, 0, 1.0, 1, 0, 10)) self.trait.min = 20 # will be set to base - self.assertEqual(self._get_values(), (1, 0, 1, 1, 10)) + self.assertEqual(self._get_values(), (1, 0, 1.0, 1, 1, 10)) self.trait.max = -20 - self.assertEqual(self._get_values(), (1, 0, 1, 1, 1)) + self.assertEqual(self._get_values(), (1, 0, 1.0, 1, 1, 1)) def test_current(self): """Modifying current value""" self.trait.current = 5 - self.assertEqual(self._get_values(), (1, 2, 7, 0, 10)) + self.assertEqual(self._get_values(), (1, 2, 1.0, 7, 0, 10)) self.trait.current = 10 - self.assertEqual(self._get_values(), (1, 2, 10, 0, 10)) + self.assertEqual(self._get_values(), (1, 2, 1.0, 10, 0, 10)) self.trait.current = 12 - self.assertEqual(self._get_values(), (1, 2, 10, 0, 10)) + self.assertEqual(self._get_values(), (1, 2, 1.0, 10, 0, 10)) self.trait.current = -1 - self.assertEqual(self._get_values(), (1, 2, 2, 0, 10)) + self.assertEqual(self._get_values(), (1, 2, 1.0, 2, 0, 10)) self.trait.current -= 10 - self.assertEqual(self._get_values(), (1, 2, 2, 0, 10)) + self.assertEqual(self._get_values(), (1, 2, 1.0, 2, 0, 10)) def test_delete(self): """Deleting resets to default.""" del self.trait.base - self.assertEqual(self._get_values(), (0, 2, 2, 0, 10)) + self.assertEqual(self._get_values(), (0, 2, 1.0, 2, 0, 10)) del self.trait.mod - self.assertEqual(self._get_values(), (0, 0, 0, 0, 10)) + self.assertEqual(self._get_values(), (0, 0, 1.0, 0, 0, 10)) del self.trait.min del self.trait.max - self.assertEqual(self._get_values(), (0, 0, 0, None, None)) + self.assertEqual(self._get_values(), (0, 0, 1.0, 0, None, None)) def test_percentage(self): """Test percentage calculation""" self.trait.base = 8 self.trait.mod = 2 + self.trait.mult = 1.0 self.trait.min = 0 self.trait.max = 10 self.assertEqual(self.trait.percent(), "100.0%") @@ -494,7 +509,7 @@ class TestTraitCounter(_TraitHandlerBase): """Test descriptions""" self.trait.min = -5 self.trait.mod = 0 - self.assertEqual(self._get_values(), (1, 0, 1, -5, 10)) + self.assertEqual(self._get_values(), (1, 0, 1.0, 1, -5, 10)) self.trait.current = -2 self.assertEqual(self.trait.desc(), "range0") self.trait.current = 0 @@ -525,6 +540,7 @@ class TestTraitCounterTimed(_TraitHandlerBase): trait_type="counter", base=1, mod=2, + mult=1.0, min=0, max=100, extra_val1="xvalue1", @@ -602,8 +618,9 @@ class TestTraitGauge(_TraitHandlerBase): "test1", name="Test1", trait_type="gauge", - base=8, # max = base + mod + base=8, # max = (base + mod) * mult mod=2, + mult=1.0, extra_val1="xvalue1", extra_val2="xvalue2", descs={ @@ -617,7 +634,7 @@ class TestTraitGauge(_TraitHandlerBase): def _get_values(self): """Get (base, mod, value, min, max).""" - return (self.trait.base, self.trait.mod, self.trait.value, self.trait.min, self.trait.max) + return (self.trait.base, self.trait.mod, self.trait.mult, self.trait.value, self.trait.min, self.trait.max) def test_init(self): self.assertEqual( @@ -627,6 +644,7 @@ class TestTraitGauge(_TraitHandlerBase): "trait_type": "gauge", "base": 8, "mod": 2, + "mult": 1.0, "min": 0, "extra_val1": "xvalue1", "extra_val2": "xvalue2", @@ -645,71 +663,80 @@ class TestTraitGauge(_TraitHandlerBase): def test_value(self): """value is current, where current defaults to base + mod""" # current unset - follows base + mod - self.assertEqual(self._get_values(), (8, 2, 10, 0, 10)) + self.assertEqual(self._get_values(), (8, 2, 1.0, 10, 0, 10)) self.trait.base += 4 - self.assertEqual(self._get_values(), (12, 2, 14, 0, 14)) + self.assertEqual(self._get_values(), (12, 2, 1.0, 14, 0, 14)) self.trait.mod -= 1 - self.assertEqual(self._get_values(), (12, 1, 13, 0, 13)) + self.assertEqual(self._get_values(), (12, 1, 1.0, 13, 0, 13)) + self.trait.mult += 1.0 + self.assertEqual(self._get_values(), (12, 1, 2.0, 26, 0, 26)) # set current, decouple from base + mod self.trait.current = 5 - self.assertEqual(self._get_values(), (12, 1, 5, 0, 13)) + self.assertEqual(self._get_values(), (12, 1, 2.0, 5, 0, 26)) self.trait.mod += 1 self.trait.base -= 4 - self.assertEqual(self._get_values(), (8, 2, 5, 0, 10)) + self.trait.mult -= 1.0 + self.assertEqual(self._get_values(), (8, 2, 1.0, 5, 0, 10)) self.trait.min = -100 self.trait.base = -20 - self.assertEqual(self._get_values(), (-20, 2, -18, -100, -18)) + self.assertEqual(self._get_values(), (-20, 2, 1.0, -18, -100, -18)) def test_boundaries__minmax(self): """Test range""" # current unset - tied to base + mod self.trait.base += 20 - self.assertEqual(self._get_values(), (28, 2, 30, 0, 30)) + self.assertEqual(self._get_values(), (28, 2, 1.0, 30, 0, 30)) # set current - decouple from base + mod self.trait.current = 19 - self.assertEqual(self._get_values(), (28, 2, 19, 0, 30)) + self.assertEqual(self._get_values(), (28, 2, 1.0, 19, 0, 30)) # test upper bound self.trait.current = 100 - self.assertEqual(self._get_values(), (28, 2, 30, 0, 30)) + self.assertEqual(self._get_values(), (28, 2, 1.0, 30, 0, 30)) + # with multiplier + self.trait.mult = 2.0 + self.assertEqual(self._get_values(), (28, 2, 2.0, 30, 0, 60)) + self.trait.current = 100 + self.assertEqual(self._get_values(), (28, 2, 2.0, 60, 0, 60)) # min defaults to 0 + self.trait.mult = 1.0 self.trait.current = -10 - self.assertEqual(self._get_values(), (28, 2, 0, 0, 30)) + self.assertEqual(self._get_values(), (28, 2, 1.0, 0, 0, 30)) self.trait.min = -20 - self.assertEqual(self._get_values(), (28, 2, 0, -20, 30)) + self.assertEqual(self._get_values(), (28, 2, 1.0, 0, -20, 30)) self.trait.current = -10 - self.assertEqual(self._get_values(), (28, 2, -10, -20, 30)) + self.assertEqual(self._get_values(), (28, 2, 1.0, -10, -20, 30)) def test_boundaries__bigmod(self): """add a big mod""" self.trait.base = 5 self.trait.mod = 100 - self.assertEqual(self._get_values(), (5, 100, 105, 0, 105)) + self.assertEqual(self._get_values(), (5, 100, 1.0, 105, 0, 105)) # restricted by min self.trait.mod = -100 - self.assertEqual(self._get_values(), (5, -5, 0, 0, 0)) + self.assertEqual(self._get_values(), (5, -5, 1.0, 0, 0, 0)) self.trait.min = -200 - self.assertEqual(self._get_values(), (5, -5, 0, -200, 0)) + self.assertEqual(self._get_values(), (5, -5, 1.0, 0, -200, 0)) def test_boundaries__change_boundaries(self): """Change boundaries after current change""" self.trait.current = 20 - self.assertEqual(self._get_values(), (8, 2, 10, 0, 10)) + self.assertEqual(self._get_values(), (8, 2, 1.0, 10, 0, 10)) self.trait.mod = 102 - self.assertEqual(self._get_values(), (8, 102, 10, 0, 110)) + self.assertEqual(self._get_values(), (8, 102, 1.0, 10, 0, 110)) # raising min past current value will force it upwards self.trait.min = 20 - self.assertEqual(self._get_values(), (8, 102, 20, 20, 110)) + self.assertEqual(self._get_values(), (8, 102, 1.0, 20, 20, 110)) def test_boundaries__disable(self): """Disable and re-enable boundary""" self.trait.base = 5 self.trait.min = 1 - self.assertEqual(self._get_values(), (5, 2, 7, 1, 7)) + self.assertEqual(self._get_values(), (5, 2, 1.0, 7, 1, 7)) del self.trait.min - self.assertEqual(self._get_values(), (5, 2, 7, 0, 7)) + self.assertEqual(self._get_values(), (5, 2, 1.0, 7, 0, 7)) del self.trait.base del self.trait.mod - self.assertEqual(self._get_values(), (0, 0, 0, 0, 0)) + self.assertEqual(self._get_values(), (0, 0, 1.0, 0, 0, 0)) with self.assertRaises(traits.TraitException): del self.trait.max @@ -717,39 +744,39 @@ class TestTraitGauge(_TraitHandlerBase): """Try to set reversed boundaries""" self.trait.mod = 0 self.trait.base = -10 # limited by min - self.assertEqual(self._get_values(), (0, 0, 0, 0, 0)) + self.assertEqual(self._get_values(), (0, 0, 1.0, 0, 0, 0)) self.trait.min = -10 - self.assertEqual(self._get_values(), (0, 0, 0, -10, 0)) + self.assertEqual(self._get_values(), (0, 0, 1.0, 0, -10, 0)) self.trait.base = -10 - self.assertEqual(self._get_values(), (-10, 0, -10, -10, -10)) + self.assertEqual(self._get_values(), (-10, 0, 1.0, -10, -10, -10)) self.min = 0 # limited by base + mod - self.assertEqual(self._get_values(), (-10, 0, -10, -10, -10)) + self.assertEqual(self._get_values(), (-10, 0, 1.0, -10, -10, -10)) def test_current(self): """Modifying current value""" self.trait.base = 10 self.trait.current = 5 - self.assertEqual(self._get_values(), (10, 2, 5, 0, 12)) + self.assertEqual(self._get_values(), (10, 2, 1.0, 5, 0, 12)) self.trait.current = 10 - self.assertEqual(self._get_values(), (10, 2, 10, 0, 12)) + self.assertEqual(self._get_values(), (10, 2, 1.0, 10, 0, 12)) self.trait.current = 12 - self.assertEqual(self._get_values(), (10, 2, 12, 0, 12)) + self.assertEqual(self._get_values(), (10, 2, 1.0, 12, 0, 12)) self.trait.current = 0 - self.assertEqual(self._get_values(), (10, 2, 0, 0, 12)) + self.assertEqual(self._get_values(), (10, 2, 1.0, 0, 0, 12)) self.trait.current = -1 - self.assertEqual(self._get_values(), (10, 2, 0, 0, 12)) + self.assertEqual(self._get_values(), (10, 2, 1.0, 0, 0, 12)) def test_delete(self): """Deleting resets to default.""" del self.trait.mod - self.assertEqual(self._get_values(), (8, 0, 8, 0, 8)) + self.assertEqual(self._get_values(), (8, 0, 1.0, 8, 0, 8)) self.trait.mod = 2 del self.trait.base - self.assertEqual(self._get_values(), (0, 2, 2, 0, 2)) + self.assertEqual(self._get_values(), (0, 2, 1.0, 2, 0, 2)) del self.trait.min - self.assertEqual(self._get_values(), (0, 2, 2, 0, 2)) + self.assertEqual(self._get_values(), (0, 2, 1.0, 2, 0, 2)) self.trait.min = -10 - self.assertEqual(self._get_values(), (0, 2, 2, -10, 2)) + self.assertEqual(self._get_values(), (0, 2, 1.0, 2, -10, 2)) del self.trait.min self.assertEqual(self._get_values(), (0, 2, 2, 0, 2)) diff --git a/evennia/contrib/rpg/traits/traits.py b/evennia/contrib/rpg/traits/traits.py index fbc4f664bc..303fe89bf7 100644 --- a/evennia/contrib/rpg/traits/traits.py +++ b/evennia/contrib/rpg/traits/traits.py @@ -45,7 +45,7 @@ class Character(DefaultCharacter): def at_object_creation(self): # (or wherever you want) - self.traits.add("str", "Strength", trait_type="static", base=10, mod=2) + self.traits.add("str", "Strength", trait_type="static", base=10, mod=2, mult=2.0) self.traits.add("hp", "Health", trait_type="gauge", min=0, max=100) self.traits.add("hunting", "Hunting Skill", trait_type="counter", base=10, mod=1, min=0, max=100) @@ -74,9 +74,9 @@ from evennia.contrib.rpg.traits import TraitProperty class Object(DefaultObject): ... - strength = TraitProperty("Strength", trait_type="static", base=10, mod=2) + strength = TraitProperty("Strength", trait_type="static", base=10, mod=2, mult=1.5) health = TraitProperty("Health", trait_type="gauge", min=0, base=100, mod=2) - hunting = TraitProperty("Hunting Skill", trait_type="counter", base=10, mod=1, min=0, max=100) + hunting = TraitProperty("Hunting Skill", trait_type="counter", base=10, mod=1, mult=2.0, min=0, max=100) ``` @@ -102,14 +102,14 @@ each other depends on the trait type. ```python > obj.traits.strength.value -12 # base + mod +18 # (base + mod) * mult -> obj.traits.strength.base += 5 +> obj.traits.strength.base += 6 obj.traits.strength.value -17 +27 > obj.traits.hp.value -102 # base + mod +102 # (base + mod) * mult > obj.traits.hp.base -= 200 > obj.traits.hp.value @@ -131,11 +131,11 @@ obj.traits.strength.value # with TraitProperties: > obj.hunting.value -12 +22 > obj.strength.value += 5 > obj.strength.value -17 +32 ``` @@ -171,25 +171,27 @@ if trait1 > trait2: ``` ## Static trait -`value = base + mod` +`value = (base + mod) * mult` -The static trait has a `base` value and an optional `mod`-ifier. A typical use -of a static trait would be a Strength stat or Skill value. That is, something -that varies slowly or not at all, and which may be modified in-place. +The static trait has a `base` value and an optional `mod`-ifier and 'mult'-iplier. +The modifier defaults to 0, and the multiplier to 1.0, for no change in value. +A typical use of a static trait would be a Strength stat or Skill value. That is, +somethingthat varies slowly or not at all, and which may be modified in-place. ```python > obj.traits.add("str", "Strength", trait_type="static", base=10, mod=2) > obj.traits.mytrait.value - 12 # base + mod + > obj.traits.mytrait.base += 2 > obj.traits.mytrait.mod += 1 > obj.traits.mytrait.value 15 > obj.traits.mytrait.mod = 0 +> obj.traits.mytrait.mult = 2.0 > obj.traits.mytrait.value -12 +20 ``` @@ -199,18 +201,20 @@ that varies slowly or not at all, and which may be modified in-place. min/unset base base+mod max/unset |--------------|--------|---------X--------X------------| current value - = current - + mod + = (current + + mod) + * mult A counter describes a value that can move from a base. The `.current` property is the thing usually modified. It starts at the `.base`. One can also add a -modifier, which will both be added to the base and to current (forming -`.value`). The min/max of the range are optional, a boundary set to None will -remove it. A suggested use for a Counter Trait would be to track skill values. +modifier, which is added to both the base and to current. '.value' is then formed +by multiplying by the multiplier, which defaults to 1.0 for no change. The min/max +of the range are optional, a boundary set to None will remove it. A suggested use +for a Counter Trait would be to track skill values. ```python > obj.traits.add("hunting", "Hunting Skill", trait_type="counter", - base=10, mod=1, min=0, max=100) + base=10, mod=1, mult=1.0, min=0, max=100) > obj.traits.hunting.value 11 # current starts at base + mod @@ -222,7 +226,10 @@ remove it. A suggested use for a Counter Trait would be to track skill values. > del obj.traits.hunting.current > obj.traits.hunting.value 11 + > obj.traits.hunting.max = None # removing upper bound +> obj.traits.hunting.mult = 100.0 +1100 # for TraitProperties, pass the args/kwargs of traits.add() to the # TraitProperty constructor instead. @@ -1141,20 +1148,20 @@ class Trait: class StaticTrait(Trait): """ - Static Trait. This is a single value with a modifier, - with no concept of a 'current' value or min/max etc. + Static Trait. This is a single value with a modifier, + multiplier, and no concept of a 'current' value or min/max etc. - value = base + mod + value = (base + mod) * mult """ trait_type = "static" - default_keys = {"base": 0, "mod": 0} + default_keys = {"base": 0, "mod": 0, "mult": 1.0} def __str__(self): status = "{value:11}".format(value=self.value) - return "{name:12} {status} ({mod:+3})".format(name=self.name, status=status, mod=self.mod) + return "{name:12} {status} ({mod:+3}) (* {mult:.2f})".format(name=self.name, status=status, mod=self.mod, mult=self.mult) # Helpers @property @@ -1178,10 +1185,24 @@ class StaticTrait(Trait): if type(amount) in (int, float): self._data["mod"] = amount + @property + def mult(self): + """The trait's multiplier.""" + return self._data["mult"] + + @mult.setter + def mult(self, amount): + if type(amount) in (int, float): + self._data["mult"] = amount + + @mult.deleter + def mult(self): + self._data["mult"] = 1.0 + @property def value(self): - "The value of the Trait" - return self.base + self.mod + "The value of the Trait." + return (self.base + self.mod) * self.mult class CounterTrait(Trait): @@ -1191,13 +1212,14 @@ class CounterTrait(Trait): This includes modifications and min/max limits as well as the notion of a current value. The value can also be reset to the base value. - min/unset base base+mod max/unset + min/unset base (base+mod)*mult max/unset |--------------|--------|---------X--------X------------| current value - = current - + mod + = (current + + mod) + * mult - - value = current + mod, starts at base + mod + - value = (current + mod) * mult, starts at (base + mod) * mult - if min or max is None, there is no upper/lower bound (default) - if max is set to "base", max will be equal ot base+mod - descs are used to optionally describe each value interval. @@ -1224,6 +1246,7 @@ class CounterTrait(Trait): default_keys = { "base": 0, "mod": 0, + "mult": 1.0, "min": None, "max": None, "descs": None, @@ -1299,16 +1322,16 @@ class CounterTrait(Trait): now = time() tdiff = now - self._data["last_update"] current += rate * tdiff - value = current + self.mod + value = (current + self.mod) # we must make sure so we don't overstep our bounds # even if .mod is included if self._passed_ratetarget(value): - current = self._data["ratetarget"] - self.mod + current = (self._data["ratetarget"] - self.mod) self._stop_timer() elif not self._within_boundaries(value): - current = self._enforce_boundaries(value) - self.mod + current = (self._enforce_boundaries(value) - self.mod) self._stop_timer() else: self._data["last_update"] = now @@ -1352,6 +1375,19 @@ class CounterTrait(Trait): value = self.max - self.base self._data["mod"] = value + @property + def mult(self): + return self._data["mult"] + + @mult.setter + def mult(self, amount): + if type(amount) in (int, float): + self._data["mult"] = amount + + @mult.deleter + def mult(self): + self._data["mult"] = 1.0 + @property def min(self): return self._data["min"] @@ -1382,7 +1418,7 @@ class CounterTrait(Trait): @property def current(self): - """The `current` value of the `Trait`. This does not have .mod added.""" + """The `current` value of the `Trait`. This does not have .mod added and is not .mult-iplied.""" return self._update_current(self._data.get("current", self.base)) @current.setter @@ -1397,8 +1433,8 @@ class CounterTrait(Trait): @property def value(self): - "The value of the Trait (current + mod)" - return self._enforce_boundaries(self.current + self.mod) + "The value of the Trait. (current + mod) * mult" + return self._enforce_boundaries((self.current + self.mod) * self.mult) @property def ratetarget(self): @@ -1461,15 +1497,15 @@ class GaugeTrait(CounterTrait): """ Gauge Trait. - This emulates a gauge-meter that empties from a base+mod value. + This emulates a gauge-meter that empties from a (base+mod) * mult value. - min/0 max=base+mod + min/0 max=(base+mod)*mult |-----------------------X---------------------------| value = current - min defaults to 0 - - max value is always base + mad + - max value is always (base + mod) * mult - .max is an alias of .base - value = current and varies from min to max. - descs is a mapping {upper_bound_inclusive: desc}. These @@ -1493,6 +1529,7 @@ class GaugeTrait(CounterTrait): default_keys = { "base": 0, "mod": 0, + "mult": 1.0, "min": 0, "descs": None, "rate": 0, @@ -1530,11 +1567,11 @@ class GaugeTrait(CounterTrait): """Ensures that incoming value falls within trait's range.""" if self.min is not None and value <= self.min: return self.min - return min(self.mod + self.base, value) + return min((self.mod + self.base) * self.mult, value) def __str__(self): status = "{value:4} / {base:4}".format(value=self.value, base=self.base) - return "{name:12} {status} ({mod:+3})".format(name=self.name, status=status, mod=self.mod) + return "{name:12} {status} ({mod:+3}) (* {mult:.2f})".format(name=self.name, status=status, mod=self.mod, mult=self.mult) @property def base(self): @@ -1559,6 +1596,19 @@ class GaugeTrait(CounterTrait): if value + self.base < self.min: value = self.min - self.base self._data["mod"] = value + + @property + def mult(self): + return self._data["mult"] + + @mult.setter + def mult(self, amount): + if type(amount) in (int, float): + self._data["mult"] = amount + + @mult.deleter + def mult(self): + self._data["mult"] = 1.0 @property def min(self): @@ -1567,16 +1617,16 @@ class GaugeTrait(CounterTrait): @min.setter def min(self, value): - """Limit so min can never be greater than base+mod.""" + """Limit so min can never be greater than (base+mod)*mult.""" if value is None: self._data["min"] = self.default_keys["min"] elif type(value) in (int, float): - self._data["min"] = min(value, self.base + self.mod) + self._data["min"] = min(value, (self.base + self.mod) * self.mult) @property def max(self): - "The max is always base + mod." - return self.base + self.mod + "The max is always (base + mod) * mult." + return (self.base + self.mod) * self.mult @max.setter def max(self, value): @@ -1594,7 +1644,7 @@ class GaugeTrait(CounterTrait): def current(self): """The `current` value of the gauge.""" return self._update_current( - self._enforce_boundaries(self._data.get("current", self.base + self.mod)) + self._enforce_boundaries(self._data.get("current", (self.base + self.mod) * self.mult)) ) @current.setter @@ -1605,7 +1655,7 @@ class GaugeTrait(CounterTrait): @current.deleter def current(self): "Resets current back to 'full'" - self._data["current"] = self.base + self.mod + self._data["current"] = (self.base + self.mod) * self.mult @property def value(self):