1 | # This program is free software: you can redistribute it and/or modify |
---|
2 | # it under the terms of the GNU General Public License as published by |
---|
3 | # the Free Software Foundation, either version 3 of the License, or |
---|
4 | # (at your option) any later version. |
---|
5 | |
---|
6 | # This program is distributed in the hope that it will be useful, |
---|
7 | # but WITHOUT ANY WARRANTY; without even the implied warranty of |
---|
8 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
---|
9 | # GNU General Public License for more details. |
---|
10 | |
---|
11 | # You should have received a copy of the GNU General Public License |
---|
12 | # along with this program. If not, see <http://www.gnu.org/licenses/>. |
---|
13 | """ |
---|
14 | Provides classes that define character stats and traits. |
---|
15 | """ |
---|
16 | |
---|
17 | from abc import ABCMeta, abstractmethod |
---|
18 | from weakref import ref as weakref |
---|
19 | |
---|
20 | from .serializers import SerializableRegistry |
---|
21 | |
---|
22 | class AbstractCharacterStatistic(object): |
---|
23 | __metaclass__ = ABCMeta |
---|
24 | |
---|
25 | @abstractmethod |
---|
26 | def __init__(self, description, minimum, maximum): |
---|
27 | self.description = description |
---|
28 | self.minimum = minimum |
---|
29 | self.maximum = maximum |
---|
30 | |
---|
31 | |
---|
32 | class PrimaryCharacterStatistic(AbstractCharacterStatistic): |
---|
33 | def __init__(self, long_name, short_name, description, minimum=0, |
---|
34 | maximum=100): |
---|
35 | AbstractCharacterStatistic.__init__(self, description=description, |
---|
36 | minimum=minimum, maximum=maximum) |
---|
37 | self.long_name = long_name |
---|
38 | self.short_name = short_name |
---|
39 | |
---|
40 | SerializableRegistry.registerClass( |
---|
41 | 'PrimaryCharacterStatistic', |
---|
42 | PrimaryCharacterStatistic, |
---|
43 | init_args=[ |
---|
44 | ('long_name', unicode), |
---|
45 | ('short_name', unicode), |
---|
46 | ('description', unicode), |
---|
47 | ('minimum', int), |
---|
48 | ('maximum', int), |
---|
49 | ], |
---|
50 | ) |
---|
51 | |
---|
52 | |
---|
53 | class SecondaryCharacterStatistic(AbstractCharacterStatistic): |
---|
54 | def __init__(self, name, description, unit, mean, sd, stat_modifiers, |
---|
55 | minimum=None, maximum=None): |
---|
56 | AbstractCharacterStatistic.__init__(self, description=description, |
---|
57 | minimum=minimum, maximum=maximum) |
---|
58 | self.name = name |
---|
59 | self.unit = unit |
---|
60 | self.mean = mean |
---|
61 | self.sd = sd |
---|
62 | self.stat_modifiers = stat_modifiers |
---|
63 | |
---|
64 | SerializableRegistry.registerClass( |
---|
65 | 'SecondaryCharacterStatistic', |
---|
66 | SecondaryCharacterStatistic, |
---|
67 | init_args=[ |
---|
68 | ('name', unicode), |
---|
69 | ('description', unicode), |
---|
70 | ('unit', unicode), |
---|
71 | ('mean', float), |
---|
72 | ('sd', float), |
---|
73 | ('stat_modifiers', dict), |
---|
74 | ('minimum', float), |
---|
75 | ('maximum', float), |
---|
76 | ], |
---|
77 | ) |
---|
78 | |
---|
79 | |
---|
80 | class AbstractStatisticValue(object): |
---|
81 | __metaclass__ = ABCMeta |
---|
82 | |
---|
83 | @abstractmethod |
---|
84 | def __init__(self, statistic_type, character): |
---|
85 | self.statistic_type = statistic_type |
---|
86 | self.character = weakref(character) |
---|
87 | |
---|
88 | |
---|
89 | class PrimaryStatisticValue(AbstractStatisticValue): |
---|
90 | def value(): |
---|
91 | def fget(self): |
---|
92 | return self._value |
---|
93 | def fset(self, new_value): |
---|
94 | assert 0 <= new_value <= 100 |
---|
95 | self._value = new_value |
---|
96 | |
---|
97 | def __init__(self, statistic_type, character, value): |
---|
98 | AbstractStatisticValue.__init__(self, statistic_type=statistic_type, |
---|
99 | character=character) |
---|
100 | self._value = None |
---|
101 | self.value = value |
---|
102 | |
---|
103 | |
---|
104 | class SecondaryStatisticValue(AbstractStatisticValue): |
---|
105 | def normalized_value(): |
---|
106 | def fget(self): |
---|
107 | return self._normalized_value |
---|
108 | def fset(self, new_value): |
---|
109 | self._normalized_value = new_value |
---|
110 | statistic_type = self.statistic_type |
---|
111 | mean = statistic_type.mean |
---|
112 | sd = statistic_type.sd |
---|
113 | self._value = self.calculate_value(mean, sd, new_value) |
---|
114 | return locals() |
---|
115 | normalized_value = property(**normalized_value()) |
---|
116 | |
---|
117 | def value(): |
---|
118 | def fget(self): |
---|
119 | return self._value |
---|
120 | def fset(self, new_value): |
---|
121 | self._value = new_value |
---|
122 | statistic_type = self.statistic_type |
---|
123 | mean = statistic_type.mean |
---|
124 | sd = statistic_type.sd |
---|
125 | self._normalized_value = self.calculate_value(mean, sd, new_value) |
---|
126 | return locals() |
---|
127 | value = property(**value()) |
---|
128 | |
---|
129 | def __init__(self, statistic_type, character): |
---|
130 | AbstractStatisticValue.__init__(self, statistic_type=statistic_type, |
---|
131 | character=character) |
---|
132 | mean = statistic_type.mean |
---|
133 | sd = statistic_type.sd |
---|
134 | normalized_value = self.derive_value(normalized=True) |
---|
135 | self._normalized_value = normalized_value |
---|
136 | self._value = self.calculate_value(mean, sd, normalized_value) |
---|
137 | |
---|
138 | def derive_value(self, normalized=True): |
---|
139 | """ |
---|
140 | Derive the current value |
---|
141 | """ |
---|
142 | statistic_type = self.statistic_type |
---|
143 | stat_modifiers = statistic_type.stat_modifiers |
---|
144 | character = self.character() |
---|
145 | |
---|
146 | value = sum( |
---|
147 | character.statistics[name].value * modifier for name, modifier in |
---|
148 | stat_modifiers.items() |
---|
149 | ) |
---|
150 | assert 0 <= value <= 100 |
---|
151 | if not normalized: |
---|
152 | mean = statistic_type.mean |
---|
153 | sd = statistic_type.sd |
---|
154 | value = self.calculate_value(mean, sd, value) |
---|
155 | return value |
---|
156 | |
---|
157 | @staticmethod |
---|
158 | def calculate_value(mean, sd, normalized_value): |
---|
159 | value = sd * (normalized_value - 50) + mean |
---|
160 | return value |
---|
161 | |
---|
162 | @staticmethod |
---|
163 | def calculate_normalized_value(mean, sd, value): |
---|
164 | normalized_value = ((value - mean) / sd) + 50 |
---|
165 | return normalized_value |
---|