home · contact · privacy
In web client, enable keyboard control except if in outer HTML input field.
[plomrogue2] / plomrogue / tasks.py
1 from plomrogue.errors import PlayError, GameError
2 from plomrogue.misc import quote
3
4
5
6 class Task:
7     argtypes = ''
8     todo = 1
9
10     def __init__(self, thing, args=()):
11         self.thing = thing
12         self.args = args
13
14     def _get_move_target(self):
15         if self.args[0] == 'HERE':
16             return self.thing.position
17         return self.thing.game.map_geometry.move_yxyx(self.thing.position,
18                                                       self.args[0])
19
20     def check(self):
21         pass
22
23
24
25 class Task_WAIT(Task):
26
27     def do(self):
28         pass
29
30
31
32 class Task_MOVE(Task):
33     argtypes = 'string:direction'
34
35     def check(self):
36         test_yxyx = self._get_move_target()
37         move_blockers = self.thing.game.get_movement_blockers()
38         if test_yxyx in [t.position for t in self.thing.game.things
39                          if t.blocking]:
40             raise PlayError('blocked by other thing')
41         elif self.thing.game.maps[test_yxyx[0]][test_yxyx[1]] in move_blockers:
42             raise PlayError('blocked by impassable tile')
43
44     def do(self):
45         self.thing.game.record_fov_change(self.thing.position)
46         self.thing.position = self._get_move_target()
47         self.thing.game.record_fov_change(self.thing.position)
48         if self.thing.carrying:
49             self.thing.carrying.position = self.thing.position
50
51
52
53 class Task_WRITE(Task):
54     argtypes = 'string:char string'
55
56     def check(self):
57         if not self.thing.game.can_do_tile_with_pw(*self.thing.position,
58                                                    self.args[1]):
59             raise GameError('wrong password for tile')
60
61     def do(self):
62         big_yx = self.thing.position[0]
63         little_yx = self.thing.position[1]
64         self.thing.game.maps[big_yx][little_yx] = self.args[0]
65         self.thing.game.record_fov_change((big_yx, little_yx))
66
67
68
69 class Task_FLATTEN_SURROUNDINGS(Task):
70     argtypes = 'string'
71
72     def check(self):
73         pass
74
75     def do(self):
76         for yxyx in [self.thing.position] + \
77                 list(self.thing.game.map_geometry.get_neighbors_yxyx(
78                     self.thing.position).values()):
79             if not self.thing.game.can_do_tile_with_pw(*yxyx, self.args[0]):
80                 continue
81             self.thing.game.maps[yxyx[0]][yxyx[1]] = self.game.get_flatland()
82             self.thing.game.record_fov_change(yxyx)
83
84
85
86 class Task_PICK_UP(Task):
87     argtypes = 'int:pos'
88
89     def check(self):
90         if self.thing.carrying:
91             raise PlayError('already carrying something')
92         to_pick_up = self.thing.game.get_thing(self.args[0])
93         neighbors = self.thing.game.map_geometry.\
94             get_neighbors_yxyx(self.thing.position).values()
95         reach = [self.thing.position] + list(neighbors)
96         if to_pick_up is None:
97             raise PlayError('no such thing exists')
98         elif to_pick_up == self.thing:
99             raise PlayError('cannot pick up oneself')
100         elif to_pick_up.type_ == 'Player':
101             raise PlayError('cannot pick up player')
102         elif to_pick_up.carried:
103             raise PlayError('thing already carried by a player')
104         elif to_pick_up.position not in reach:
105             raise PlayError('thing not in reach')
106         elif not to_pick_up.portable:
107             raise PlayError('thing not portable')
108
109     def do(self):
110         to_pick_up = self.thing.game.get_thing(self.args[0])
111         to_pick_up.position = self.thing.position[:]
112         self.thing.carrying = to_pick_up
113         to_pick_up.carried = True
114         # FIXME: pseudo-FOV-change actually
115         self.thing.game.record_fov_change(self.thing.position)
116
117
118
119 class Task_DROP(Task):
120     argtypes = 'string:direction+here'
121
122     def check(self):
123         if not self.thing.carrying:
124             raise PlayError('nothing to drop')
125         target_position = self._get_move_target()
126         if self.thing.carrying.type_ == 'Bottle' and self.thing.carrying.full:
127             for t in [t for t in self.thing.game.things
128                       if t.type_ == 'BottleDeposit'
129                       and t.position == target_position]:
130                 raise PlayError('cannot drop full bottle into bottle deposit')
131
132     def do(self):
133         target_position = self._get_move_target()
134         dropped = self.thing.uncarry()
135         dropped.position = target_position
136         if dropped.type_ == 'Bottle' and not dropped.full:
137             for t in [t for t in self.thing.game.things
138                       if t.type_ == 'BottleDeposit'
139                       and t.position == dropped.position]:
140                 t.accept()
141                 self.thing.game.remove_thing(dropped)
142                 break
143         elif dropped.type_ == 'Hat':
144             for t in [t for t in self.thing.game.things
145                       if t.type_ == 'HatRemixer'
146                       and t.position == dropped.position]:
147                 t.accept(dropped)
148                 break
149         # FIXME: pseudo-FOV-change actually
150         self.thing.game.record_fov_change(self.thing.position)
151
152
153
154 class Task_DOOR(Task):
155
156     def do(self):
157         action_radius = list(self.thing.game.map_geometry.
158                              get_neighbors_yxyx(self.thing.position).values())
159         for t in [t for t in self.thing.game.things if
160                   t.type_ == 'Door' and t.position in action_radius]:
161             if t.blocking:
162                 t.open()
163             else:
164                 t.close()
165             self.thing.game.record_fov_change(t.position)
166
167
168
169 class Task_INTOXICATE(Task):
170
171     def check(self):
172         if self.thing.carrying is None:
173             raise PlayError('carrying nothing to drink from')
174         if self.thing.carrying.type_ != 'Bottle':
175             raise PlayError('cannot drink from non-bottle')
176         if not self.thing.carrying.full:
177             raise PlayError('bottle is empty')
178
179     def do(self):
180         self.thing.carrying.full = False
181         self.thing.carrying.empty()
182         self.thing.send_msg('RANDOM_COLORS')
183         self.thing.send_msg('CHAT "You are drunk now."')
184         self.thing.drunk = 10000
185         # FIXME: pseudo-FOV-change actually
186         self.thing.game.record_fov_change(self.thing.position)
187
188
189
190 class Task_COMMAND(Task):
191     argtypes = 'string'
192
193     def check(self):
194         if self.thing.carrying is None:
195             raise PlayError('nothing to command')
196         if not self.thing.carrying.commandable:
197             raise PlayError('cannot command this item type')
198
199     def do(self):
200         reply_lines = self.thing.carrying.interpret(self.args[0])
201         for line in reply_lines:
202             self.thing.send_msg('REPLY ' + quote(line))
203
204
205
206 class Task_INSTALL(Task):
207     argtypes = 'string'
208
209     def _get_uninstallables(self):
210         return [t for t in self.thing.game.things
211                 if t != self.thing
212                 and hasattr(t, 'installable') and t.installable
213                 and (not t.portable)
214                 and t.position == self.thing.position]
215
216     def check(self):
217         if not self.thing.game.can_do_tile_with_pw(*self.thing.position,
218                                                    self.args[0]):
219             raise GameError('wrong password for tile')
220         if self.thing.carrying:
221             if not hasattr(self.thing.carrying, 'installable')\
222                or not self.thing.carrying.installable:
223                 raise PlayError('carried thing not installable')
224         elif len(self._get_uninstallables()) == 0:
225             raise PlayError('nothing to uninstall here')
226
227     def do(self):
228         if self.thing.carrying:
229             t = self.thing.uncarry()
230             t.install()
231             self.thing.send_msg('CHAT "You install the thing you carry."')
232         else:
233             self._get_uninstallables()[0].uninstall()
234             self.thing.send_msg('CHAT "You uninstall the thing here."')
235         # FIXME: pseudo-FOV-change actually
236         self.thing.game.record_fov_change(self.thing.position)
237
238
239
240 class Task_WEAR(Task):
241
242     def check(self):
243         if self.thing.name in self.thing.game.hats:
244             return
245         if not self.thing.carrying:
246             raise PlayError('carrying nothing to wear')
247         if self.thing.name in self.thing.game.hats:
248             raise PlayError('already wearing a hat')
249         if self.thing.carrying.type_ not in {'Hat', 'Bottle'}:
250             raise PlayError('can not wear the kind of thing you hold')
251
252     def do(self):
253         if self.thing.name in self.thing.game.hats:
254             t = self.thing.game.add_thing('Hat', self.thing.position)
255             t.design = self.thing.game.hats[self.thing.name]
256             del self.thing.game.hats[self.thing.name]
257             self.thing.send_msg('CHAT "You drop your hat."')
258             for remixer in [t for t in self.thing.game.things
259                             if t.type_ == 'HatRemixer'
260                             and t.position == self.thing.position]:
261                 remixer.accept(t)
262                 break
263         else:
264             if self.thing.carrying.type_ == 'Bottle':
265                 self.thing.send_msg('CHAT "Your attempt to wear a bottle on '
266                                     'your head fails."')
267                 self.thing.carrying.sound('BOTTLE', 'SMASH')
268             elif self.thing.carrying.type_ == 'Hat':
269                 self.thing.game.hats[self.thing.name] =\
270                     self.thing.carrying.design
271                 self.thing.send_msg('CHAT "You put on a hat."')
272             self.thing.game.remove_thing(self.thing.carrying)
273             self.thing.carrying = None
274         # FIXME: pseudo-FOV-change actually
275         self.thing.game.record_fov_change(self.thing.position)
276
277
278
279 class Task_SPIN(Task):
280
281     def check(self):
282         if not self.thing.carrying:
283             raise PlayError('holding nothing to spin')
284         if not hasattr(self.thing.carrying, 'spinnable'):
285             raise PlayError('held object not spinnable')
286
287     def do(self):
288         self.thing.carrying.spin()
289         self.thing.send_msg('CHAT "You spin this object."')