Browse code
refactoring combat.py
edwlan authored on 29/07/2013 03:58:09
Showing 1 changed files
Showing 1 changed files
... | ... |
@@ -1,6 +1,9 @@ |
1 | 1 |
from . import dice |
2 |
-from .dice import MULT,ADD |
|
3 |
-from . import type_dict |
|
2 |
+ |
|
3 |
+from .combat_parts import races |
|
4 |
+from .combat_parts import equipment |
|
5 |
+from .combat_parts import skills |
|
6 |
+from .combat_parts import constants as const |
|
4 | 7 |
|
5 | 8 |
import collections |
6 | 9 |
|
... | ... |
@@ -10,261 +13,26 @@ class Attributes(object): |
10 | 13 |
self.int = intellect |
11 | 14 |
self.dex = dexterity |
12 | 15 |
self.spt = spirit |
13 |
- self.state = HEALTHY |
|
14 |
- |
|
15 |
-def health_mod(func): |
|
16 |
- def _inner(self): |
|
17 |
- mod = 0 |
|
18 |
- if self.attr.state >= WOUNDED: |
|
19 |
- mod = -3 |
|
20 |
- result = func(self) |
|
21 |
- result += mod |
|
22 |
- return result |
|
23 |
- return _inner |
|
24 |
- |
|
25 |
- |
|
26 |
- |
|
27 |
-class Skills(object): |
|
28 |
- def __init__(self, attr): |
|
29 |
- self.skills = { |
|
30 |
- 'agility','craft','fighting','knowledge', |
|
31 |
- 'perception','persuasion','shooting','speed', |
|
32 |
- 'stealth','toughness' |
|
33 |
- } |
|
34 |
- self.attr = attr |
|
35 |
- self.training = Trainer(self) |
|
36 |
- self.train = self.training.select |
|
37 |
- |
|
38 |
- def check(self, skill, dieroll): |
|
39 |
- dieroll.dice = dice.DieJar().d20 |
|
40 |
- roll = dieroll.roll() |
|
41 |
- if roll == 1: |
|
42 |
- result = False |
|
43 |
- if roll == 20: |
|
44 |
- result = True |
|
45 |
- else: |
|
46 |
- result = roll < getattr(self, skill) |
|
47 |
- return result, roll-result # (passes, difference) |
|
48 |
- |
|
49 |
- @property |
|
50 |
- @health_mod |
|
51 |
- def agility(self): |
|
52 |
- return (self.attr.dex * 2) + self.training.agility |
|
53 |
- @property |
|
54 |
- @health_mod |
|
55 |
- def craft(self): |
|
56 |
- return self.attr.dex + self.attr.int + self.training.craft |
|
57 |
- @property |
|
58 |
- @health_mod |
|
59 |
- def fighting(self): |
|
60 |
- return self.attr.str + self.attr.int + self.training.fighting |
|
61 |
- @property |
|
62 |
- @health_mod |
|
63 |
- def knowledge(self): |
|
64 |
- return self.attr.int * 2 + self.training.knowledge |
|
65 |
- @property |
|
66 |
- @health_mod |
|
67 |
- def perception(self): |
|
68 |
- return self.attr.int + attr.spt + self.training.perception |
|
69 |
- @property |
|
70 |
- @health_mod |
|
71 |
- def persuasion(self): |
|
72 |
- return self.attr.spt * 2 + self.training.persuasion |
|
73 |
- @property |
|
74 |
- @health_mod |
|
75 |
- def shooting(self): |
|
76 |
- return self.attr.dex + self.attr.int + self.training.shooting |
|
77 |
- @property |
|
78 |
- @health_mod |
|
79 |
- def speed(self): |
|
80 |
- return self.attr.str + self.attr.dex + self.training.speed |
|
81 |
- @property |
|
82 |
- @health_mod |
|
83 |
- def stealth(self): |
|
84 |
- return self.attr.dex + self.attr.spt + self.training.stealth |
|
85 |
- @property |
|
86 |
- @health_mod |
|
87 |
- def toughness(self): |
|
88 |
- return self.attr.str + self.attr.spt + self.training.toughness |
|
89 |
- |
|
90 |
-class Trainer(object): |
|
91 |
- mods = dict( |
|
92 |
- untrained=-1, |
|
93 |
- familiar=0, |
|
94 |
- trained=1, |
|
95 |
- experienced=2, |
|
96 |
- mastered=3 |
|
97 |
- ) |
|
98 |
- |
|
99 |
- def __init__(self, skills): |
|
100 |
- self.skills = skills |
|
101 |
- self.training = collections.defaultdict(lambda: -1) |
|
102 |
- self.points = 500 |
|
103 |
- self.training_cost = 100 |
|
104 |
- |
|
105 |
- def select(self, skill, degree): |
|
106 |
- if hasattr(degree, 'upper'): |
|
107 |
- degree = self.mods.get(degree, 0) |
|
108 |
- if self.points >= self.training_cost and degree in self.mods.values(): |
|
109 |
- self.training[skill] = degree |
|
110 |
- self.points -= self.training_cost |
|
111 |
- |
|
112 |
- def __getattr__(self, key): |
|
113 |
- skills = object.__getattribute__(self, 'skills') |
|
114 |
- if key in self.skills.skills: |
|
115 |
- return self.training[key] |
|
116 |
- else: |
|
117 |
- raise |
|
118 |
- def __setattr__(self, key, value): |
|
119 |
- if hasattr(self, 'skills') and key in self.skills.skills: |
|
120 |
- if -1 <= value <= 3: |
|
121 |
- self.training[key] = int(round(value)) |
|
122 |
- else: |
|
123 |
- raise AttributeError( |
|
124 |
- 'cannot set training of %s to %d, (out of range [-1,3])' % (key, value) |
|
125 |
- ) |
|
126 |
- else: |
|
127 |
- object.__setattr__(self, key, value) |
|
128 |
- |
|
129 |
- |
|
130 |
-class Equipment(object): pass |
|
131 |
-class Weapon(Equipment): pass |
|
132 |
-class Armor(Equipment): pass |
|
133 |
- |
|
134 |
- |
|
135 |
-class Slot(object): |
|
136 |
- def __init__(self, name, type): |
|
137 |
- self.name = name |
|
138 |
- self.attr = 'slotted_%s' % name |
|
139 |
- self.type = type |
|
140 |
- |
|
141 |
- def __get__(self, instance, owner): |
|
142 |
- return self.getitem(instance) |
|
143 |
- def __set__(self, instance, value): |
|
144 |
- self.setitem(instance, value) |
|
145 |
- |
|
146 |
- def setitem(self, instance, value): |
|
147 |
- if isinstance(value, self.type): |
|
148 |
- setattr(instance, 'slotted_%s' % self.name, value) |
|
149 |
- else: |
|
150 |
- raise ValueError( |
|
151 |
- 'Can\'t use an object of type %s in a slot of type %s' % (type(value), self.type) |
|
152 |
- ) |
|
153 |
- |
|
154 |
- |
|
155 |
- def getitem(self, instance): |
|
156 |
- return getattr(instance, self.attr, None) |
|
157 |
- |
|
158 |
- def filled(self, instance): |
|
159 |
- return self.getitem(instance) is not None |
|
160 |
- |
|
161 |
- @classmethod |
|
162 |
- def add_slot(cls, name, type): |
|
163 |
- def _inner(to_cls): |
|
164 |
- inst = cls(name, type) |
|
165 |
- setattr(to_cls, name, inst) |
|
166 |
- if not hasattr(to_cls, 'equipment_slots'): |
|
167 |
- to_cls.equipment_slots = Slots((name,inst)) |
|
168 |
- else: |
|
169 |
- to_cls.equipment_slots[name] = inst |
|
170 |
- return to_cls |
|
171 |
- return _inner |
|
16 |
+ self.state = const.HEALTHY |
|
172 | 17 |
|
173 | 18 |
|
174 |
-class Slots(collections.MutableMapping): |
|
175 |
- def __init__(self, *args, **kw): |
|
176 |
- self.slots = dict(args) |
|
177 |
- self.slots.update(kw) |
|
178 |
- self.slots_by_type = type_dict.TypeDict(__default=[]) |
|
179 |
- for k in self.slots: |
|
180 |
- slot = self.slots[k] |
|
181 |
- self.slots_by_type[slot.type].append(slot) |
|
182 |
- |
|
183 |
- def __getitem__(self, key): |
|
184 |
- return self.slots[key] |
|
185 |
- def __setitem__(self, k, v): |
|
186 |
- self.slots[k] = v |
|
187 |
- def __delitem__(self, key): |
|
188 |
- del self.slots[key] |
|
189 |
- |
|
190 |
- def __iter__(self): |
|
191 |
- return iter(self.slots) |
|
192 |
- def __len__(self): |
|
193 |
- return len(self.slots) |
|
194 |
- |
|
195 |
- def slots_of_type(self, slot_type): |
|
196 |
- return self.slots_by_type[slot_type] |
|
197 |
- |
|
198 |
-class Race(object): |
|
199 |
- registry = {} |
|
200 |
- @classmethod |
|
201 |
- def register(cls, new): |
|
202 |
- cls.registry[new.__name__.lower()] = new |
|
203 |
- |
|
204 |
- @classmethod |
|
205 |
- def random_race(cls): |
|
206 |
- return random.choice(self.registry.values()) |
|
207 |
- @property |
|
208 |
- def name(self): |
|
209 |
- return self.__class__.__name__.lower() |
|
210 |
- |
|
211 |
- allowed_professions = set() |
|
212 |
- def __init__(self, attr): |
|
213 |
- self.mod(attr) |
|
214 |
- |
|
215 |
- def allows_profession(self, prof): |
|
216 |
- return prof in self.allowed_professions |
|
217 |
- |
|
218 |
-@Race.register |
|
219 |
-class Human(Race): |
|
220 |
- def mod(self, attr): |
|
221 |
- attr.spt += 1 |
|
222 |
- |
|
223 |
-@Race.register |
|
224 |
-class Elf(Race): |
|
225 |
- allowed_professions = {'fighter', 'wizard', 'thief'} |
|
226 |
- def mod(self, attr): |
|
227 |
- attr.int += 1 |
|
228 |
- |
|
229 |
-@Race.register |
|
230 |
-class Dwarf(Race): |
|
231 |
- allowed_professions = {'fighter', 'Priest', 'thief'} |
|
232 |
- def mod(self, atr): |
|
233 |
- attr.str += 1 |
|
234 |
- |
|
235 |
-@Race.register |
|
236 |
-class Hobbit(Race): |
|
237 |
- allowed_professions = {'thief', 'barbarian'} |
|
238 |
- def mod(self, atr): |
|
239 |
- attr.dex += 1 |
|
240 |
- |
|
241 |
- |
|
242 |
-class Sword(Weapon): |
|
243 |
- attack = 1 |
|
244 |
- damage_mod = 1 |
|
245 |
- |
|
246 |
- |
|
247 |
-HEALTHY = 0 |
|
248 |
-WOUNDED = 1 |
|
249 |
-KNOCKOUT = 2 |
|
250 |
- |
|
251 |
-@Slot.add_slot('weapon', Weapon) |
|
252 |
-@Slot.add_slot('armor', Armor) |
|
19 |
+@equipment.Slot.add_slot('weapon', equipment.Weapon) |
|
20 |
+@equipment.Slot.add_slot('armor', equipment.Armor) |
|
253 | 21 |
class Adventurer(object): |
254 | 22 |
@property |
255 | 23 |
def state(self): |
256 | 24 |
return self.attributes.state |
257 | 25 |
@state.setter |
258 | 26 |
def state(self, val): |
259 |
- if val not in {HEALTHY, WOUNDED, KNOCKOUT}: |
|
27 |
+ if val not in {const.HEALTHY, const.WOUNDED, const.KNOCKOUT}: |
|
260 | 28 |
raise ValueError('Value for state invalid') |
261 | 29 |
self.attributes.state = val |
262 | 30 |
|
263 | 31 |
def __init__(self, name, race, str, int, dex, spt): |
264 | 32 |
self.name = name |
265 | 33 |
self.attributes = Attributes(str, int, dex, spt) |
266 |
- self.skills = Skills(self.attributes) |
|
267 |
- self.race = Race.registry[race](self.attributes) |
|
34 |
+ self.skills = skills.Skills(self.attributes) |
|
35 |
+ self.race = races.Race.registry[race](self.attributes) |
|
268 | 36 |
|
269 | 37 |
def wield(self, slot, equipment): |
270 | 38 |
turns = 1 |
... | ... |
@@ -300,7 +68,7 @@ class Adventurer(object): |
300 | 68 |
if damage > 0: |
301 | 69 |
self.state += 1 |
302 | 70 |
print '%s takes %d damage and is now %s' % (self.name, damage, ['healthy', 'wounded', 'ko'][self.state if self.state < 3 else 2]) |
303 |
- if self.state >= KNOCKOUT: |
|
71 |
+ if self.state >= const.KNOCKOUT: |
|
304 | 72 |
self.die() |
305 | 73 |
|
306 | 74 |
def die(self): pass |
... | ... |
@@ -316,13 +84,13 @@ def get_stats(): |
316 | 84 |
print sum(stats), stats |
317 | 85 |
return stats |
318 | 86 |
|
87 |
+if __name__ == '__main__': |
|
88 |
+ a = Adventurer('bob', 'elf', *get_stats()) |
|
89 |
+ b = Adventurer('bill', 'elf', *get_stats()) |
|
319 | 90 |
|
320 |
-a = Adventurer('bob', 'elf', *get_stats()) |
|
321 |
-b = Adventurer('bill', 'elf', *get_stats()) |
|
322 |
- |
|
323 |
-while KNOCKOUT not in {a.state, b.state}: |
|
324 |
- a.attack(b) |
|
325 |
- b.attack(a) |
|
91 |
+ while const.KNOCKOUT not in {a.state, b.state}: |
|
92 |
+ a.attack(b) |
|
93 |
+ b.attack(a) |
|
326 | 94 |
|
327 |
-print a.name, 'is', ['healthy', 'wounded', 'ko'][a.state if a.state < 3 else 2] |
|
328 |
-print b.name, 'is', ['healthy', 'wounded', 'ko'][b.state if b.state < 3 else 2] |
|
95 |
+ print a.name, 'is', ['healthy', 'wounded', 'ko'][a.state if a.state < 3 else 2] |
|
96 |
+ print b.name, 'is', ['healthy', 'wounded', 'ko'][b.state if b.state < 3 else 2] |