28
|
1 #!/usr/bin/env python
|
|
2 # Copyright (C) 2000-2001 The OpenRPG Project
|
|
3 #
|
|
4 # openrpg-dev@lists.sourceforge.net
|
|
5 #
|
|
6 # This program is free software; you can redistribute it and/or modify
|
|
7 # it under the terms of the GNU General Public License as published by
|
|
8 # the Free Software Foundation; either version 2 of the License, or
|
|
9 # (at your option) any later version.
|
|
10 #
|
|
11 # This program is distributed in the hope that it will be useful,
|
|
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14 # GNU General Public License for more details.
|
|
15 #
|
|
16 # You should have received a copy of the GNU General Public License
|
|
17 # along with this program; if not, write to the Free Software
|
|
18 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
19 # --
|
|
20 #
|
|
21 # File: die.py
|
|
22 # Author: Andrew Bennett
|
|
23 # Maintainer:
|
|
24 # Version:
|
|
25 # $Id: die.py,v Traipse 'Ornery-Orc' prof.ebral Exp $
|
|
26 #
|
|
27 # Description: This class is used to make working with dice easier
|
|
28 #
|
|
29
|
|
30 __version__ = "$Id: die.py,v Traipse 'Ornery-Orc' prof.ebral Exp Exp $"
|
|
31
|
|
32 import random
|
|
33 import UserList
|
|
34 import copy
|
|
35
|
|
36 class die_base(UserList.UserList):
|
|
37 name = None
|
|
38
|
|
39 def __init__(self,source = []):
|
|
40 if isinstance(source, (int, float, basestring)):
|
|
41 s = []
|
|
42 s.append(di(source))
|
|
43 else: s = source
|
|
44 UserList.UserList.__init__(self,s)
|
|
45
|
|
46 def sum(self):
|
|
47 s = 0
|
|
48 for a in self.data:
|
|
49 s += int(a)
|
|
50 return s
|
|
51
|
|
52 def __lshift__(self,other):
|
|
53 if type(other) == type(3) or type(other) == type(3.0):
|
|
54 o = other
|
|
55 elif hasattr(other,"sum"):
|
|
56 o = other.sum()
|
|
57 else: return None
|
|
58 result = []
|
|
59 for die in self:
|
|
60 if die < o: result.append(die)
|
|
61 return self.__class__(result)
|
|
62
|
|
63 def __rshift__(self,other):
|
|
64 if type(other) == type(3) or type(other) == type(3.0): o = other
|
|
65 elif hasattr(other,"sum"): o = other.sum()
|
|
66 else: return None
|
|
67 result = []
|
|
68 for die in self:
|
|
69 if die > o: result.append(die)
|
|
70 return self.__class__(result)
|
|
71
|
|
72 def __rlshift__(self,other):
|
|
73 return self.__rshift__(other)
|
|
74
|
|
75 def __rrshift__(self,other):
|
|
76 return self.__lshift__(other)
|
|
77
|
|
78 def __str__(self):
|
|
79 if len(self.data) > 0:
|
|
80 myStr = "[" + str(self.data[0])
|
|
81 for a in self.data[1:]:
|
|
82 myStr += ","
|
|
83 myStr += str(a)
|
|
84 myStr += "] = (" + str(self.sum()) + ")"
|
|
85 else: myStr = "[] = (0)"
|
|
86 return myStr
|
|
87
|
|
88 def __lt__(self,other):
|
|
89 if type(other) == type(3) or type(other) == type(3.0):
|
|
90 return (self.sum() < other)
|
|
91 elif hasattr(other,"sum"): return (self.sum() < other.sum())
|
|
92 else: return UserList.UserList.__lt__(self,other)
|
|
93
|
|
94 def __le__(self,other):
|
|
95 if type(other) == type(3) or type(other) == type(3.0):
|
|
96 return (self.sum() <= other)
|
|
97 elif hasattr(other,"sum"): return (self.sum() <= other.sum())
|
|
98 else: return UserList.UserList.__le__(self,other)
|
|
99
|
|
100 def __eq__(self,other):
|
|
101 if type(other) == type(3) or type(other) == type(3.0):
|
|
102 return (self.sum() == other)
|
|
103 elif hasattr(other,"sum"): return (self.sum() == other.sum())
|
|
104 else: return UserList.UserList.__eq__(self,other)
|
|
105
|
|
106 def __ne__(self,other):
|
|
107 if type(other) == type(3) or type(other) == type(3.0): return (self.sum() != other)
|
|
108 elif hasattr(other,"sum"): return (self.sum() != other.sum())
|
|
109 else: return UserList.UserList.__ne__(self,other)
|
|
110
|
|
111 def __gt__(self,other):
|
|
112 if type(other) == type(3) or type(other) == type(3.0): return (self.sum() > other)
|
|
113 elif hasattr(other,"sum"): return (self.sum() > other.sum())
|
|
114 else: return UserList.UserList.__gt__(self,other)
|
|
115
|
|
116 def __ge__(self,other):
|
|
117 if type(other) == type(3) or type(other) == type(3.0): return (self.sum() >= other)
|
|
118 elif hasattr(other,"sum"): return (self.sum() >= other.sum())
|
|
119 else: return UserList.UserList.__ge__(self,other)
|
|
120
|
|
121 def __cmp__(self,other):
|
|
122 # this function included for backwards compatibility
|
|
123 # As of 2.1, lists implement the "rich comparison"
|
|
124 # methods overloaded above.
|
|
125 if type(other) == type(3) or type(other) == type(3.0): return cmp(self.sum(), other)
|
|
126 elif hasattr(other,"sum"): return cmp(self.sum(), other.sum())
|
|
127 else: return UserList.UserList.__cmp__(self,other)
|
|
128
|
|
129
|
|
130 def __rcmp__(self,other):
|
|
131 return self.__cmp__(other)
|
|
132
|
|
133 def __add__(self,other):
|
|
134 mycopy = copy.deepcopy(self)
|
|
135 if type(other) == type(3) or type(other) == type(3.0):
|
|
136 other = [static_di(other)]
|
|
137 elif type(other) == type("test"): return self
|
|
138 mycopy.extend(other)
|
|
139 return mycopy
|
|
140
|
|
141 def __iadd__(self,other):
|
|
142 return self.__add__(other)
|
|
143
|
|
144 def __radd__(self,other):
|
|
145 mycopy = copy.deepcopy(self)
|
|
146 if type(other) == type(3) or type(other) == type(3.0):
|
|
147 new_die = di(0)
|
|
148 new_die.set_value(other)
|
|
149 other = new_die
|
|
150 mycopy.insert(0,other)
|
|
151 return mycopy
|
|
152
|
|
153 def __int__(self):
|
|
154 return self.sum()
|
|
155
|
|
156 def __sub__(self,other):
|
|
157 mycopy = copy.deepcopy(self)
|
|
158 if type(other) == type(3) or type(other) == type(3.0):
|
|
159 neg_die = static_di(-other)
|
|
160 other = [neg_die]
|
|
161 else: other = -other
|
|
162 mycopy.extend(other)
|
|
163 return mycopy
|
|
164
|
|
165 def __rsub__(self,other):
|
|
166 mycopy = -copy.deepcopy(self)
|
|
167 if type(other) == type(3) or type(other) == type(3.0):
|
|
168 new_die = di(0)
|
|
169 new_die.set_value(other)
|
|
170 other = new_die
|
|
171 mycopy.insert(0,other)
|
|
172 return mycopy
|
|
173
|
|
174 def __isub__(self,other):
|
|
175 return self.__sub__(other)
|
|
176
|
|
177 def __mul__(self,other):
|
|
178 if type(other) == type(3) or type(other) == type(3.0): return self.sum() * other
|
|
179 elif hasattr(other,"sum"): return other.sum() * self.sum()
|
|
180 else: return UserList.UserList.__mul__(self,other)
|
|
181
|
|
182 def __rmul__(self,other):
|
|
183 return self.__mul__(other)
|
|
184
|
|
185 def __div__(self,other):
|
|
186 if type(other) == type(3) or type(other) == type(3.0): return float(self.sum()) / other
|
|
187 elif hasattr(other,"sum"): return float(self.sum()) / other.sum()
|
|
188 else: return UserList.UserList.__div__(self,other)
|
|
189
|
|
190 def __rdiv__(self,other):
|
|
191 if type(other) == type(3) or type(other) == type(3.0): return other / float(self.sum())
|
|
192 elif hasattr(other,"sum"): return other.sum() / float(self.sum())
|
|
193 else: return UserList.UserList.__rdiv__(self,other)
|
|
194
|
|
195 def __mod__(self,other):
|
|
196 if type(other) == type(3) or type(other) == type(3.0): return self.sum()%other
|
|
197 elif hasattr(other,"sum"): return self.sum() % other.sum()
|
|
198 else: return UserList.UserList.__mod__(self,other)
|
|
199
|
|
200 def __rmod__(self,other):
|
|
201 if type(other) == type(3) or type(other) == type(3.0): return other % self.sum()
|
|
202 elif hasattr(other,"sum"): return other.sum() % self.sum()
|
|
203 else: return UserList.UserList.__rmod__(self,other)
|
|
204
|
|
205 def __neg__(self):
|
|
206 for i in range(len(self.data)): self.data[i] = -self.data[i]
|
|
207 return self
|
|
208
|
|
209 def __pos__(self):
|
|
210 for i in range(len(self.data)): self.data[i] = +self.data[i]
|
|
211 return self
|
|
212
|
|
213 def __abs__(self):
|
|
214 for i in range(len(self.data)): self.data[i] = abs(self.data[i])
|
|
215 return self
|
|
216
|
|
217 def __pow__(self,other):
|
|
218 if type(other) == type(3) or type(other) == type(3.0): return self.sum() ** other
|
|
219 elif hasattr(other,"sum"): return self.sum() ** other.sum()
|
|
220 else: return UserList.UserList.__pow__(self,other)
|
|
221
|
|
222 def __rpow__(self,other):
|
|
223 # We're overloading exponentiation of ints to create "other" number of dice
|
|
224 if other >= 1:
|
|
225 result = self.__class__(self[0].sides)
|
|
226 for t in range(other-1): result+=self.__class__(self[0].sides)
|
|
227 else: result = None
|
|
228 return result
|
|
229
|
|
230 ### di class to handle actual dice
|
|
231
|
|
232 class di:
|
|
233 def __init__(self,sides,min=1):
|
|
234 self.sides = sides
|
|
235 self.history = None
|
|
236 self.value = None
|
|
237 self.target = None
|
|
238 self.roll(min)
|
|
239
|
|
240 def __str__(self):
|
|
241 if len(self.history) > 1: return str(self.history)
|
|
242 else: return str(self.value)
|
|
243
|
|
244 def __neg__(self):
|
|
245 self.value = -self.value
|
|
246 for i in range(len(self.history)): self.history[i] = -self.history[i]
|
|
247 return self
|
|
248
|
|
249 def __pos__(self):
|
|
250 self.value = +self.value
|
|
251 for i in range(len(self.history)): self.history[i] = +self.history[i]
|
|
252 return self
|
|
253
|
|
254 def __abs__(self):
|
|
255 self.value = abs(self.value)
|
|
256 for i in range(len(self.history)):
|
|
257 self.history[i] = abs(self.history[i])
|
|
258 return self
|
|
259
|
|
260 def __repr__(self):
|
|
261 if len(self.history) > 1: return str(self.history)
|
|
262 else: return str(self.value)
|
|
263
|
|
264 def __int__(self):
|
|
265 return self.value
|
|
266
|
|
267
|
|
268 def __lt__(self,other):
|
|
269 if type(other) == type(3) or type(other) == type(3.0): return self.value < other
|
|
270 elif hasattr(other,"value"): return self.value < other.value
|
|
271 else: return self < other
|
|
272
|
|
273 def __le__(self,other):
|
|
274 if type(other) == type(3) or type(other) == type(3.0): return self.value <= other
|
|
275 elif hasattr(other,"value"): return self.value <= other.value
|
|
276 else: return self <= other
|
|
277
|
|
278 def __eq__(self,other):
|
|
279 if type(other) == type(3) or type(other) == type(3.0): return self.value == other
|
|
280 elif hasattr(other,"value"): return self.value == other.value
|
|
281 else: return self == other
|
|
282
|
|
283 def __ne__(self,other):
|
|
284 if type(other) == type(3) or type(other) == type(3.0): return self.value != other
|
|
285 elif hasattr(other,"value"): return self.value != other.value
|
|
286 else: return self != other
|
|
287
|
|
288 def __gt__(self,other):
|
|
289 if type(other) == type(3) or type(other) == type(3.0): return self.value > other
|
|
290 elif hasattr(other,"value"): return self.value > other.value
|
|
291 else: return self > other
|
|
292
|
|
293 def __ge__(self,other):
|
|
294 if type(other) == type(3) or type(other) == type(3.0): return self.value >= other
|
|
295 elif hasattr(other,"value"): return self.value >= other.value
|
|
296 else: return self >= other
|
|
297
|
|
298 def __cmp__(self,other):
|
|
299 # this function included for backwards compatibility
|
|
300 # As of 2.1, lists implement the "rich comparison"
|
|
301 # methods overloaded above.
|
|
302 if type(other) == type(3) or type(other) == type(3.0): return cmp(self.value, other)
|
|
303 elif hasattr(other,"value"): return cmp(self.value, other.value)
|
|
304 else: return cmp(self,other)
|
|
305
|
|
306 def roll(self,min=1):
|
|
307 if isinstance(self.sides, basestring) and self.sides.lower() == 'f': self.value = random.randint(-1, 1)
|
|
308 else: self.value = int(random.uniform(min, self.sides+1))
|
|
309 self.history = []
|
|
310 self.history.append(self.value)
|
|
311
|
|
312 def extraroll(self):
|
|
313 if isinstance(self.sides, basestring) and self.sides.lower() == 'f': result = random.randint(-1, 1)
|
|
314 else: result = int(random.uniform(1,self.sides+1))
|
|
315 self.value += result
|
|
316 self.history.append(result)
|
|
317
|
|
318 def lastroll(self):
|
|
319 return self.history[len(self.history)-1]
|
|
320
|
|
321 def set_value(self,value):
|
|
322 self.value = value
|
|
323 self.history = []
|
|
324 self.history.append(self.value)
|
|
325
|
|
326 def modify(self,mod):
|
|
327 self.value += mod
|
|
328 self.history.append(mod)
|
|
329
|
|
330 def gethistory(self):
|
|
331 return self.history[:]
|
|
332
|
|
333 class static_di(di):
|
|
334 def __init__(self,value):
|
|
335 di.__init__(self,value,value)
|
|
336 self.set_value(value)
|
|
337
|
|
338 class DieRollers(object):
|
|
339 _rollers = {}
|
|
340 def __new__(cls):
|
|
341 it = cls.__dict__.get("__it__")
|
|
342 if it is not None: return it
|
|
343 cls.__it__ = it = object.__new__(cls)
|
|
344 return it
|
|
345
|
|
346 def keys(self):
|
|
347 return self._rollers.keys()
|
|
348
|
|
349 def register(self, roller):
|
|
350 if not self._rollers.has_key(roller.name):
|
|
351 self._rollers[roller.name] = roller
|
|
352
|
|
353 def __getitem__(self, roller_name):
|
|
354 return self._rollers.get(roller_name, None)
|
|
355
|
|
356 def __setitem__(self, *args):
|
|
357 raise AttributeError
|
|
358
|
|
359 die_rollers = DieRollers()
|