source: branches/active/character_customization/game/scripts/characterstatistics.py @ 722

Revision 722, 4.8 KB checked in by technomage, 8 years ago (diff)

Patch by Technomage

  • Added a new module, scripts/characterstatistics.py, which implements primary and secondary character stats logic;
  • Added a yEdit UML diagram describing the new character statistics module;
  • Added a few "mock" primary and secondary character stats XML scripts in the new character_scripts directory - the syntax is mostly solidified;
  • Modified the CharacterBase? class in scripts/objects/actors.py by adding a primary_stats and secondary_stats attribute which can be initialized in the constructor;
  • Fixed a bug in the dedent_chomp method defined in scripts/common/utils.py which caused an extra space to be added to the last line of the output string;
Line 
1"""
2Provides classes that define character stats and traits.
3"""
4
5from abc import ABCMeta, abstractmethod
6from weakref import ref as weakref
7
8from .serializers import SerializableRegistry
9
10class AbstractCharacterStatistic(object):
11    __metaclass__ = ABCMeta
12   
13    @abstractmethod
14    def __init__(self, description, minimum, maximum):
15        self.description = description
16        self.minimum = minimum
17        self.maximum = maximum
18
19
20class PrimaryCharacterStatistic(AbstractCharacterStatistic):
21    def __init__(self, long_name, short_name, description, minimum=0,
22                 maximum=100):
23        AbstractCharacterStatistic.__init__(self, description=description,
24                                            minimum=minimum, maximum=maximum)
25        self.long_name = long_name
26        self.short_name = short_name
27
28SerializableRegistry.registerClass(
29    'PrimaryCharacterStatistic',
30    PrimaryCharacterStatistic,
31    init_args=[
32        ('long_name', unicode),
33        ('short_name', unicode),
34        ('description', unicode),
35        ('minimum', int),
36        ('maximum', int),
37    ],
38)
39
40
41class SecondaryCharacterStatistic(AbstractCharacterStatistic):
42    def __init__(self, name, description, unit, mean, sd, stat_modifiers,
43                 minimum=None, maximum=None):
44        AbstractCharacterStatistic.__init__(self, description=description,
45                                            minimum=minimum, maximum=maximum)
46        self.name = name
47        self.unit = unit
48        self.mean = mean
49        self.sd = sd
50        self.stat_modifiers = stat_modifiers
51
52SerializableRegistry.registerClass(
53    'SecondaryCharacterStatistic',
54    SecondaryCharacterStatistic,
55    init_args=[
56        ('name', unicode),
57        ('description', unicode),
58        ('unit', unicode),
59        ('mean', float),
60        ('sd', float),
61        ('stat_modifiers', dict),
62        ('minimum', float),
63        ('maximum', float),
64    ],
65)
66
67
68class AbstractStatisticValue(object):
69    __metaclass__ = ABCMeta
70   
71    @abstractmethod
72    def __init__(self, statistic_type, character):
73        self.statistic_type = statistic_type
74        self.character = weakref(character)
75
76
77class PrimaryStatisticValue(AbstractStatisticValue):
78    def value():
79        def fget(self):
80            return self._value
81        def fset(self, new_value):
82            assert 0 <= new_value <= 100
83            self._value = new_value
84   
85    def __init__(self, statistic_type, character, value):
86        AbstractStatisticValue.__init__(self, statistic_type=statistic_type,
87                                        character=character)
88        self._value = None
89        self.value = value
90
91
92class SecondaryStatisticValue(AbstractStatisticValue):
93    def normalized_value():
94        def fget(self):
95            return self._normalized_value
96        def fset(self, new_value):
97            self._normalized_value = new_value
98            statistic_type = self.statistic_type
99            mean = statistic_type.mean
100            sd = statistic_type.sd
101            self._value = self.calculate_value(mean, sd, new_value)
102        return locals()
103    normalized_value = property(**normalized_value())
104   
105    def value():
106        def fget(self):
107            return self._value
108        def fset(self, new_value):
109            self._value = new_value
110            statistic_type = self.statistic_type
111            mean = statistic_type.mean
112            sd = statistic_type.sd
113            self._normalized_value = self.calculate_value(mean, sd, new_value)
114        return locals()
115    value = property(**value())
116   
117    def __init__(self, statistic_type, character):
118        AbstractStatisticValue.__init__(self, statistic_type=statistic_type,
119                                        character=character)
120        mean = statistic_type.mean
121        sd = statistic_type.sd
122        normalized_value = self.derive_value(normalized=True)
123        self._normalized_value = normalized_value
124        self._value = self.calculate_value(mean, sd, normalized_value)
125   
126    def derive_value(self, normalized=True):
127        """
128        Derive the current value
129        """
130        statistic_type = self.statistic_type
131        stat_modifiers = statistic_type.stat_modifiers
132        character = statistic_type.character
133       
134        value = sum(
135            character.statistics[name] * modifier for name, modifier in
136                stat_modifiers.items()
137        )
138        assert 0 <= value <= 100
139        if not normalized:
140            mean = statistic_type.mean
141            sd = statistic_type.sd
142            value = self.calculate_value(mean, sd, value)
143        return value
144   
145    @staticmethod
146    def calculate_value(mean, sd, normalized_value):
147        value = sd * (normalized_value - 50) + mean
148        return value
149   
150    @staticmethod
151    def calculate_normalized_value(mean, sd, value):
152        normalized_value = ((value - mean) / sd) + 50
153        return normalized_value
Note: See TracBrowser for help on using the repository browser.