Merge lp:~ashfall/divmod.org/1320678-remove-imaginary into lp:divmod.org
- 1320678-remove-imaginary
- Merge into trunk
Proposed by
Ashwini Oruganti
Status: | Merged | ||||
---|---|---|---|---|---|
Approved by: | Tristan Seligmann | ||||
Approved revision: | 2743 | ||||
Merged at revision: | 2747 | ||||
Proposed branch: | lp:~ashfall/divmod.org/1320678-remove-imaginary | ||||
Merge into: | lp:divmod.org | ||||
Diff against target: |
16870 lines (+1/-16267) 115 files modified
Divmod.pth (+1/-3) Imaginary/COMPATIBILITY.txt (+0/-6) Imaginary/DEPS.txt (+0/-4) Imaginary/ExampleGame/examplegame/furniture.py (+0/-139) Imaginary/ExampleGame/examplegame/glass.py (+0/-72) Imaginary/ExampleGame/examplegame/japanese.py (+0/-43) Imaginary/ExampleGame/examplegame/mice.py (+0/-264) Imaginary/ExampleGame/examplegame/quiche.py (+0/-116) Imaginary/ExampleGame/examplegame/squeaky.py (+0/-42) Imaginary/ExampleGame/examplegame/test/test_furniture.py (+0/-104) Imaginary/ExampleGame/examplegame/test/test_glass.py (+0/-95) Imaginary/ExampleGame/examplegame/test/test_japanese.py (+0/-474) Imaginary/ExampleGame/examplegame/test/test_mice.py (+0/-155) Imaginary/ExampleGame/examplegame/test/test_quiche.py (+0/-93) Imaginary/ExampleGame/examplegame/test/test_squeaky.py (+0/-51) Imaginary/ExampleGame/examplegame/test/test_tether.py (+0/-96) Imaginary/ExampleGame/examplegame/tether.py (+0/-121) Imaginary/ExampleGame/imaginary/plugins/monsters.py (+0/-6) Imaginary/ExampleGame/imaginary/plugins/quiche.py (+0/-9) Imaginary/LICENSE (+0/-20) Imaginary/MANIFEST.in (+0/-6) Imaginary/NAME.txt (+0/-10) Imaginary/NEWS.txt (+0/-36) Imaginary/README.txt (+0/-98) Imaginary/axiom/plugins/imaginaryversion.py (+0/-12) Imaginary/imaginary/__init__.py (+0/-19) Imaginary/imaginary/_version.py (+0/-3) Imaginary/imaginary/action.py (+0/-1299) Imaginary/imaginary/copyright.py (+0/-22) Imaginary/imaginary/creation.py (+0/-179) Imaginary/imaginary/eimaginary.py (+0/-90) Imaginary/imaginary/enhancement.py (+0/-95) Imaginary/imaginary/events.py (+0/-284) Imaginary/imaginary/garments.py (+0/-370) Imaginary/imaginary/idea.py (+0/-625) Imaginary/imaginary/iimaginary.py (+0/-707) Imaginary/imaginary/iterutils.py (+0/-15) Imaginary/imaginary/language.py (+0/-389) Imaginary/imaginary/manipulation.py (+0/-82) Imaginary/imaginary/objects.py (+0/-1288) Imaginary/imaginary/plugins/__init__.py (+0/-5) Imaginary/imaginary/plugins/clothes.py (+0/-8) Imaginary/imaginary/plugins/imaginary_basic.py (+0/-9) Imaginary/imaginary/plugins/lighting.py (+0/-6) Imaginary/imaginary/pyparsing.py (+0/-2641) Imaginary/imaginary/resources/help/actions (+0/-5) Imaginary/imaginary/resources/help/bury (+0/-6) Imaginary/imaginary/resources/help/close (+0/-5) Imaginary/imaginary/resources/help/commands (+0/-3) Imaginary/imaginary/resources/help/create (+0/-12) Imaginary/imaginary/resources/help/describe (+0/-5) Imaginary/imaginary/resources/help/dig (+0/-9) Imaginary/imaginary/resources/help/drop (+0/-6) Imaginary/imaginary/resources/help/eat (+0/-5) Imaginary/imaginary/resources/help/emote (+0/-9) Imaginary/imaginary/resources/help/equipment (+0/-5) Imaginary/imaginary/resources/help/find (+0/-5) Imaginary/imaginary/resources/help/get (+0/-6) Imaginary/imaginary/resources/help/go (+0/-6) Imaginary/imaginary/resources/help/help (+0/-5) Imaginary/imaginary/resources/help/hit (+0/-5) Imaginary/imaginary/resources/help/illuminate (+0/-6) Imaginary/imaginary/resources/help/inventory (+0/-5) Imaginary/imaginary/resources/help/list (+0/-10) Imaginary/imaginary/resources/help/list thing types (+0/-5) Imaginary/imaginary/resources/help/look (+0/-6) Imaginary/imaginary/resources/help/name (+0/-5) Imaginary/imaginary/resources/help/open (+0/-5) Imaginary/imaginary/resources/help/put (+0/-5) Imaginary/imaginary/resources/help/quit (+0/-5) Imaginary/imaginary/resources/help/rebuild (+0/-5) Imaginary/imaginary/resources/help/remove (+0/-5) Imaginary/imaginary/resources/help/restore (+0/-5) Imaginary/imaginary/resources/help/say (+0/-5) Imaginary/imaginary/resources/help/score (+0/-5) Imaginary/imaginary/resources/help/scrutinize (+0/-5) Imaginary/imaginary/resources/help/search (+0/-5) Imaginary/imaginary/resources/help/set (+0/-7) Imaginary/imaginary/resources/help/take (+0/-3) Imaginary/imaginary/resources/help/wear (+0/-5) Imaginary/imaginary/resources/help/who (+0/-5) Imaginary/imaginary/resources/motd (+0/-5) Imaginary/imaginary/test/__init__.py (+0/-1) Imaginary/imaginary/test/commandutils.py (+0/-253) Imaginary/imaginary/test/test_actions.py (+0/-842) Imaginary/imaginary/test/test_actor.py (+0/-37) Imaginary/imaginary/test/test_concept.py (+0/-245) Imaginary/imaginary/test/test_container.py (+0/-286) Imaginary/imaginary/test/test_create.py (+0/-269) Imaginary/imaginary/test/test_drop.py (+0/-30) Imaginary/imaginary/test/test_enhancement.py (+0/-194) Imaginary/imaginary/test/test_garments.py (+0/-306) Imaginary/imaginary/test/test_hit.py (+0/-63) Imaginary/imaginary/test/test_idea.py (+0/-241) Imaginary/imaginary/test/test_illumination.py (+0/-370) Imaginary/imaginary/test/test_language.py (+0/-116) Imaginary/imaginary/test/test_look.py (+0/-65) Imaginary/imaginary/test/test_objects.py (+0/-439) Imaginary/imaginary/test/test_player.py (+0/-69) Imaginary/imaginary/test/test_put.py (+0/-114) Imaginary/imaginary/test/test_set.py (+0/-123) Imaginary/imaginary/test/test_text.py (+0/-478) Imaginary/imaginary/test/test_util.py (+0/-24) Imaginary/imaginary/test/test_who.py (+0/-53) Imaginary/imaginary/test/test_wiring.py (+0/-79) Imaginary/imaginary/test/test_world.py (+0/-58) Imaginary/imaginary/text.py (+0/-277) Imaginary/imaginary/unc.py (+0/-66) Imaginary/imaginary/wiring/faucet.py (+0/-62) Imaginary/imaginary/wiring/player.py (+0/-104) Imaginary/imaginary/wiring/textserver.py (+0/-379) Imaginary/imaginary/wiring/tuiserver.py (+0/-75) Imaginary/imaginary/world.py (+0/-78) Imaginary/setup.py (+0/-26) Imaginary/xmantissa/plugins/imaginaryoff.py (+0/-25) |
||||
To merge this branch: | bzr merge lp:~ashfall/divmod.org/1320678-remove-imaginary | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Tristan Seligmann | Approve | ||
Review via email: mp+219969@code.launchpad.net |
Commit message
Description of the change
Removes Imaginary from lp:divmod.org
To post a comment you must log in.
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'Divmod.pth' |
2 | --- Divmod.pth 2013-06-27 06:02:46 +0000 |
3 | +++ Divmod.pth 2014-05-18 17:55:49 +0000 |
4 | @@ -1,4 +1,4 @@ |
5 | -# -*- test-case-name: axiom,combinator,epsilon,xmantissa,nevow,formless,xquotient,reverend,sine,hyperbola,imaginary,examplegame -*- |
6 | +# -*- test-case-name: axiom,combinator,epsilon,xmantissa,nevow,formless,xquotient,reverend,sine,hyperbola -*- |
7 | Axiom |
8 | Combinator |
9 | Epsilon |
10 | @@ -8,6 +8,4 @@ |
11 | Reverend |
12 | Sine |
13 | Hyperbola |
14 | -Imaginary |
15 | -Imaginary/ExampleGame |
16 | Prime |
17 | |
18 | === removed directory 'Imaginary' |
19 | === removed file 'Imaginary/COMPATIBILITY.txt' |
20 | --- Imaginary/COMPATIBILITY.txt 2009-08-17 02:40:03 +0000 |
21 | +++ Imaginary/COMPATIBILITY.txt 1970-01-01 00:00:00 +0000 |
22 | @@ -1,6 +0,0 @@ |
23 | -Imaginary provides _no_ source-level compatibility from one release to the next. |
24 | - |
25 | -Efforts will be made to provide database level compatibility (i.e. data from |
26 | -one release can be loaded with the next). However, although we will try to |
27 | -ensure that data will load, there is no guarantee that it will be meaningfully |
28 | -upgraded yet. |
29 | |
30 | === removed file 'Imaginary/DEPS.txt' |
31 | --- Imaginary/DEPS.txt 2013-07-10 00:22:10 +0000 |
32 | +++ Imaginary/DEPS.txt 1970-01-01 00:00:00 +0000 |
33 | @@ -1,4 +0,0 @@ |
34 | -Python 2.7 |
35 | -Twisted 13.1 |
36 | -Epsilon SVN-Trunk |
37 | -Axiom SVN-Trunk |
38 | |
39 | === removed directory 'Imaginary/ExampleGame' |
40 | === removed directory 'Imaginary/ExampleGame/examplegame' |
41 | === removed file 'Imaginary/ExampleGame/examplegame/__init__.py' |
42 | === removed file 'Imaginary/ExampleGame/examplegame/furniture.py' |
43 | --- Imaginary/ExampleGame/examplegame/furniture.py 2009-08-17 02:40:03 +0000 |
44 | +++ Imaginary/ExampleGame/examplegame/furniture.py 1970-01-01 00:00:00 +0000 |
45 | @@ -1,139 +0,0 @@ |
46 | -# -*- test-case-name: examplegame.test.test_furniture -*- |
47 | - |
48 | -""" |
49 | - |
50 | - Furniture is the mass noun for the movable objects which may support the |
51 | - human body (seating furniture and beds), provide storage, or hold objects |
52 | - on horizontal surfaces above the ground. |
53 | - |
54 | - -- Wikipedia, http://en.wikipedia.org/wiki/Furniture |
55 | - |
56 | -L{imaginary.furniture} contains L{Action}s which allow players to interact with |
57 | -household objects such as chairs and tables, and L{Enhancement}s which allow |
58 | -L{Thing}s to behave as same. |
59 | - |
60 | -This has the same implementation weakness as L{examplegame.tether}, in that it |
61 | -needs to make some assumptions about who is moving what in its restrictions of |
62 | -movement; it should be moved into imaginary proper when that can be properly |
63 | -addressed. It's also a bit too draconian in terms of preventing the player |
64 | -from moving for any reason just because they're seated. However, it's a |
65 | -workable approximation for some uses, and thus useful as an example. |
66 | -""" |
67 | - |
68 | -from zope.interface import implements |
69 | - |
70 | -from axiom.item import Item |
71 | -from axiom.attributes import reference |
72 | - |
73 | -from imaginary.iimaginary import ISittable, IContainer, IMovementRestriction |
74 | -from imaginary.eimaginary import ActionFailure |
75 | -from imaginary.events import ThatDoesntWork |
76 | -from imaginary.language import Noun |
77 | -from imaginary.action import Action, TargetAction |
78 | -from imaginary.events import Success |
79 | -from imaginary.enhancement import Enhancement |
80 | -from imaginary.objects import Container |
81 | -from imaginary.pyparsing import Literal, Optional, restOfLine |
82 | - |
83 | -class Sit(TargetAction): |
84 | - """ |
85 | - An action allowing a player to sit down in a chair. |
86 | - """ |
87 | - expr = (Literal("sit") + Optional(Literal("on")) + |
88 | - restOfLine.setResultsName("target")) |
89 | - |
90 | - targetInterface = ISittable |
91 | - |
92 | - def do(self, player, line, target): |
93 | - """ |
94 | - Do the action; sit down. |
95 | - """ |
96 | - target.seat(player) |
97 | - |
98 | - actorMessage=["You sit in ", |
99 | - Noun(target.thing).definiteNounPhrase(),"."] |
100 | - otherMessage=[player.thing, " sits in ", |
101 | - Noun(target.thing).definiteNounPhrase(),"."] |
102 | - Success(actor=player.thing, location=player.thing.location, |
103 | - actorMessage=actorMessage, |
104 | - otherMessage=otherMessage).broadcast() |
105 | - |
106 | - |
107 | -class Stand(Action): |
108 | - """ |
109 | - Stand up from a sitting position. |
110 | - """ |
111 | - expr = (Literal("stand") + Optional(Literal("up"))) |
112 | - |
113 | - def do(self, player, line): |
114 | - """ |
115 | - Do the action; stand up. |
116 | - """ |
117 | - # XXX This is wrong. I should be issuing an obtain() query to find |
118 | - # something that qualifies as "my location" or "the thing I'm already |
119 | - # sitting in". |
120 | - chair = ISittable(player.thing.location, None) |
121 | - if chair is None: |
122 | - raise ActionFailure(ThatDoesntWork( |
123 | - actor=player.thing, |
124 | - actorMessage=["You're already standing."])) |
125 | - chair.unseat(player) |
126 | - Success(actor=player.thing, location=player.thing.location, |
127 | - actorMessage=["You stand up."], |
128 | - otherMessage=[player.thing, " stands up."]).broadcast() |
129 | - |
130 | - |
131 | - |
132 | -class Chair(Enhancement, Item): |
133 | - """ |
134 | - A chair is a thing you can sit in. |
135 | - """ |
136 | - |
137 | - implements(ISittable, IMovementRestriction) |
138 | - |
139 | - powerupInterfaces = [ISittable] |
140 | - |
141 | - thing = reference() |
142 | - container = reference() |
143 | - |
144 | - |
145 | - def movementImminent(self, movee, destination): |
146 | - """ |
147 | - A player tried to move while they were seated. Prevent them from doing |
148 | - so, noting that they must stand first. |
149 | - |
150 | - (Assume the player was trying to move themselves, although there's no |
151 | - way to know currently.) |
152 | - """ |
153 | - raise ActionFailure(ThatDoesntWork( |
154 | - actor=movee, |
155 | - actorMessage=u"You can't do that while sitting down.")) |
156 | - |
157 | - |
158 | - def applyEnhancement(self): |
159 | - """ |
160 | - Apply this enhancement to this L{Chair}'s thing, creating a |
161 | - L{Container} to hold the seated player, if necessary. |
162 | - """ |
163 | - super(Chair, self).applyEnhancement() |
164 | - container = IContainer(self.thing, None) |
165 | - if container is None: |
166 | - container = Container.createFor(self.thing, capacity=300) |
167 | - self.container = container |
168 | - |
169 | - |
170 | - def seat(self, player): |
171 | - """ |
172 | - The player sat down on this chair; place them into it and prevent them |
173 | - from moving elsewhere until they stand up. |
174 | - """ |
175 | - player.thing.moveTo(self.container) |
176 | - player.thing.powerUp(self, IMovementRestriction) |
177 | - |
178 | - |
179 | - def unseat(self, player): |
180 | - """ |
181 | - The player stood up; remove them from this chair. |
182 | - """ |
183 | - player.thing.powerDown(self, IMovementRestriction) |
184 | - player.thing.moveTo(self.container.thing.location) |
185 | |
186 | === removed file 'Imaginary/ExampleGame/examplegame/glass.py' |
187 | --- Imaginary/ExampleGame/examplegame/glass.py 2009-08-17 02:40:03 +0000 |
188 | +++ Imaginary/ExampleGame/examplegame/glass.py 1970-01-01 00:00:00 +0000 |
189 | @@ -1,72 +0,0 @@ |
190 | -# -*- test-case-name: examplegame.test.test_glass -*- |
191 | -""" |
192 | -This example implements a transparent container that you can see, but not |
193 | -reach, the contents of. |
194 | -""" |
195 | -from zope.interface import implements |
196 | - |
197 | -from axiom.item import Item |
198 | -from axiom.attributes import reference |
199 | - |
200 | -from imaginary.iimaginary import ( |
201 | - ILinkContributor, IWhyNot, IObstruction, IContainer) |
202 | -from imaginary.enhancement import Enhancement |
203 | -from imaginary.objects import ContainmentRelationship |
204 | -from imaginary.idea import Link |
205 | - |
206 | -class _CantReachThroughGlassBox(object): |
207 | - """ |
208 | - This object provides an explanation for why the user cannot access a target |
209 | - that is inside a L{imaginary.objects.Thing} enhanced with a L{GlassBox}. |
210 | - """ |
211 | - implements(IWhyNot) |
212 | - |
213 | - def tellMeWhyNot(self): |
214 | - """ |
215 | - Return a simple message explaining that the user can't reach through |
216 | - the glass box. |
217 | - """ |
218 | - return "You can't reach through the glass box." |
219 | - |
220 | - |
221 | - |
222 | -class _ObstructedByGlass(object): |
223 | - """ |
224 | - This is an annotation on a link between two objects which represents a |
225 | - physical obstruction between them. It is used to annotate between a |
226 | - L{GlassBox} and its contents, so you can see them without reaching them. |
227 | - """ |
228 | - implements(IObstruction) |
229 | - |
230 | - def whyNot(self): |
231 | - """ |
232 | - @return: an object which explains why you can't reach through the glass |
233 | - box. |
234 | - """ |
235 | - return _CantReachThroughGlassBox() |
236 | - |
237 | - |
238 | - |
239 | -class GlassBox(Item, Enhancement): |
240 | - """ |
241 | - L{GlassBox} is an L{Enhancement} which modifies a container such that it is |
242 | - contained. |
243 | - """ |
244 | - |
245 | - powerupInterfaces = (ILinkContributor,) |
246 | - |
247 | - thing = reference() |
248 | - |
249 | - def links(self): |
250 | - """ |
251 | - If the container attached to this L{GlassBox}'s C{thing} is closed, |
252 | - yield its list of contents with each link annotated with |
253 | - L{_ObstructedByGlass}, indicating that the object cannot be reached. |
254 | - """ |
255 | - container = IContainer(self.thing) |
256 | - if container.closed: |
257 | - for content in container.getContents(): |
258 | - link = Link(self.thing.idea, content.idea) |
259 | - link.annotate([_ObstructedByGlass(), |
260 | - ContainmentRelationship(container)]) |
261 | - yield link |
262 | |
263 | === removed file 'Imaginary/ExampleGame/examplegame/japanese.py' |
264 | --- Imaginary/ExampleGame/examplegame/japanese.py 2007-08-17 04:46:38 +0000 |
265 | +++ Imaginary/ExampleGame/examplegame/japanese.py 1970-01-01 00:00:00 +0000 |
266 | @@ -1,43 +0,0 @@ |
267 | -""" |
268 | -Japanese language data. |
269 | - |
270 | -This module contains a dict named 'hiragana' which maps hiragana |
271 | -unicode characters to romaji pronunciations, as well as a |
272 | -'romajiToHiragana' dict which maps romaji pronunciation to *lists* of |
273 | -hiragana characters. There are multiple hiragana characters with the |
274 | -same pronunciation, thus the multiple values per romaji in the |
275 | -romajiToHiragana dict. |
276 | - |
277 | -""" |
278 | - |
279 | - |
280 | -# Hiragana. |
281 | -hiragana = { |
282 | - u'\u3042': 'A', u'\u3044': 'I', u'\u3046': 'U', u'\u3048': 'E', |
283 | - u'\u3081': 'ME', u'\u3080': 'MU', u'\u3082': 'MO', u'\u3084': 'YA', |
284 | - u'\u3086': 'YU', u'\u3089': 'RA', u'\u3088': 'YO', u'\u308b': 'RU', |
285 | - u'\u308a': 'RI', u'\u308d': 'RO', u'\u308c': 'RE', u'\u308f': 'WA', |
286 | - u'\u3091': 'WE', u'\u3090': 'WI', u'\u3093': 'N', u'\u3092': 'WO', |
287 | - u'\u304b': 'KA', u'\u304a': 'O', u'\u304d': 'KI', u'\u304c': 'GA', |
288 | - u'\u304f': 'KU', u'\u304e': 'GI', u'\u3051': 'KE', u'\u3050': 'GU', |
289 | - u'\u3053': 'KO', u'\u3052': 'GE', u'\u3055': 'SA', u'\u3054': 'GO', |
290 | - u'\u3057': 'SHI',u'\u3056': 'ZA', u'\u3059': 'SU', u'\u3058': 'JI', |
291 | - u'\u305b': 'SE', u'\u305a': 'ZU', u'\u305d': 'SO', u'\u305c': 'ZE', |
292 | - u'\u305f': 'TA', u'\u305e': 'ZO', u'\u3061': 'CHI', u'\u3060': 'DA', |
293 | - u'\u3062': 'JI', u'\u3065': 'ZU', u'\u3064': 'TSU', u'\u3067': 'DE', |
294 | - u'\u3066': 'TE', u'\u3069': 'DO', u'\u3068': 'TO', u'\u306b': 'NI', |
295 | - u'\u306a': 'NA', u'\u306d': 'NE', u'\u306c': 'NU', u'\u306f': 'HA', |
296 | - u'\u306e': 'NO', u'\u3071': 'PA', u'\u3070': 'BA', u'\u3073': 'BI', |
297 | - u'\u3072': 'HI', u'\u3075': 'FU', u'\u3074': 'PI', u'\u3077': 'PU', |
298 | - u'\u3076': 'BU', u'\u3079': 'BE', u'\u3078': 'HE', u'\u307b': 'HO', |
299 | - u'\u307a': 'PE', u'\u307d': 'PO', u'\u307c': 'BO', u'\u307f': 'MI', |
300 | - u'\u307e': 'MA'} |
301 | - |
302 | - |
303 | -romajiToHiragana = {} |
304 | -for k, v in hiragana.iteritems(): |
305 | - romajiToHiragana.setdefault(v, []).append(k) |
306 | - |
307 | -# Katakana. |
308 | -# katakana = { |
309 | -# } |
310 | |
311 | === removed file 'Imaginary/ExampleGame/examplegame/mice.py' |
312 | --- Imaginary/ExampleGame/examplegame/mice.py 2009-08-17 02:40:03 +0000 |
313 | +++ Imaginary/ExampleGame/examplegame/mice.py 1970-01-01 00:00:00 +0000 |
314 | @@ -1,264 +0,0 @@ |
315 | -# -*- test-case-name: examplegame.test.test_mice,examplegame.test.test_japanese -*- |
316 | - |
317 | -import random |
318 | - |
319 | -from zope.interface import implements |
320 | - |
321 | -from axiom import item, attributes |
322 | - |
323 | -from imaginary import iimaginary, events, objects, action, language |
324 | -from examplegame import japanese |
325 | - |
326 | - |
327 | -class Mouse(item.Item): |
328 | - """ |
329 | - A silly mouse which squeaks when actors enter the room it is in. |
330 | - |
331 | - @ivar _callLater: The scheduling function to use. Override in unit |
332 | - tests only. |
333 | - """ |
334 | - |
335 | - implements(iimaginary.IEventObserver) |
336 | - |
337 | - squeakiness = attributes.integer(doc=""" |
338 | - How likely the mouse is to squeak when intruded upon (0 - 100). |
339 | - |
340 | - This mouse is so angry that he will pretty much always squeak. |
341 | - """, default=100) |
342 | - |
343 | - _callLater = attributes.inmemory() |
344 | - |
345 | - def activate(self): |
346 | - from twisted.internet import reactor |
347 | - self._callLater = reactor.callLater |
348 | - |
349 | - |
350 | - def prepare(self, concept): |
351 | - """ |
352 | - An event was received. Squeak if it represents the arrival of a dude. |
353 | - """ |
354 | - if isinstance(concept, events.ArrivalEvent): |
355 | - return lambda: self._callLater(0, self.squeak) |
356 | - return lambda: None |
357 | - |
358 | - |
359 | - def squeak(self): |
360 | - actor = self.store.findUnique( |
361 | - objects.Actor, |
362 | - objects.Actor._enduringIntelligence == self) |
363 | - evt = events.Success( |
364 | - actor=actor.thing, |
365 | - otherMessage=u"SQUEAK!") |
366 | - evt.broadcast() |
367 | - |
368 | - |
369 | - |
370 | -class ChallengeCollision(Exception): |
371 | - """ |
372 | - Raised when a L{HiraganaMouse} is asked to start issuing challenges when it |
373 | - is already issuing challenges. |
374 | - """ |
375 | - |
376 | - |
377 | - |
378 | -class ChallengeVacuum(Exception): |
379 | - """ |
380 | - Raised when a L{HiraganaMouse} is asked to stop issuing challenges when it |
381 | - is already not issuing challenges. |
382 | - """ |
383 | - |
384 | - |
385 | - |
386 | -class HiraganaMouse(item.Item): |
387 | - """ |
388 | - A mouse which occasionally challenges those in its location to |
389 | - transliterate Hiragana. |
390 | - |
391 | - @ivar _callLater: The scheduling function to use. Defaults to the |
392 | - reactor's callLater method. This is parameterized for the sake of |
393 | - unit tests. |
394 | - """ |
395 | - |
396 | - implements(iimaginary.IEventObserver) |
397 | - |
398 | - challenging = attributes.boolean(doc=""" |
399 | - Whether or not this mouse is currently creating random challenges. |
400 | - """, default=False) |
401 | - |
402 | - challengeInterval = attributes.integer(doc=""" |
403 | - Number of seconds between challenges. |
404 | - """, default=15, allowNone=False) |
405 | - |
406 | - _currentChallenge = attributes.text(doc=""" |
407 | - The Hiragana character which the mouse has most recently issued as a |
408 | - challenge. |
409 | - """, default=None) |
410 | - |
411 | - |
412 | - _callLater = attributes.inmemory() |
413 | - _currentChallengeCall = attributes.inmemory() |
414 | - |
415 | - def activate(self): |
416 | - from twisted.internet import reactor |
417 | - self._callLater = reactor.callLater |
418 | - |
419 | - def _actor(self): |
420 | - """ |
421 | - Get the h-mouse's associated actor. PRIVATE. WHY DID I DOCUMENT THIS. |
422 | - """ |
423 | - return self.store.findUnique( |
424 | - objects.Actor, |
425 | - objects.Actor._enduringIntelligence == self) |
426 | - |
427 | - |
428 | - def _numDudes(self): |
429 | - """ |
430 | - Get the number of actors (other than the h-mouse) in the |
431 | - h-mouse's location. PRIVATE. |
432 | - """ |
433 | - actor = self._actor() |
434 | - numDudes = len([actor |
435 | - for dude |
436 | - in actor.thing.findProviders(iimaginary.IActor, 1) |
437 | - if dude is not actor]) |
438 | - return numDudes |
439 | - |
440 | - |
441 | - def maybeChallenge(self): |
442 | - """ |
443 | - Start challenging if there is anyone around to challenge (and |
444 | - this h-mouse isn't already challenging). |
445 | - """ |
446 | - if not self.challenging and self._numDudes() >= 1: |
447 | - self.startChallenging() |
448 | - |
449 | - |
450 | - def prepare(self, concept): |
451 | - """ |
452 | - An event was received. Start or stop challenging as |
453 | - appropriate, based on whether there is anyone to challenge. |
454 | - """ |
455 | - if isinstance(concept, events.ArrivalEvent): |
456 | - self.maybeChallenge() |
457 | - elif isinstance(concept, events.DepartureEvent) and self._numDudes() == 0: |
458 | - self.stopChallenging() |
459 | - elif isinstance(concept, events.SpeechEvent) and concept.speaker is not self._actor().thing: |
460 | - self.responseReceived(concept.speaker, concept.text) |
461 | - return lambda: None |
462 | - |
463 | - |
464 | - def startChallenging(self): |
465 | - """ |
466 | - Start shouting hiragana in the hope that someone knows what it means. |
467 | - |
468 | - @raises ChallengeCollision: If this h-mouse is already challenging. |
469 | - """ |
470 | - if self.challenging: |
471 | - raise ChallengeCollision() |
472 | - |
473 | - self.challenging = True |
474 | - self._scheduleChallenge() |
475 | - |
476 | - |
477 | - def _scheduleChallenge(self): |
478 | - """ |
479 | - Schedule a challenge to happen in the number of seconds set in |
480 | - the instance attribute 'challengeInterval'. |
481 | - """ |
482 | - self._currentChallengeCall = self._callLater(self.challengeInterval, |
483 | - self._challengeAndRepeat) |
484 | - |
485 | - |
486 | - def stopChallenging(self): |
487 | - """ |
488 | - Stop shouting hiragana. |
489 | - |
490 | - @raises ChallengeVacuum: If this h-mouse is not currently challenging. |
491 | - """ |
492 | - if not self.challenging: |
493 | - raise ChallengeVacuum() |
494 | - |
495 | - self.challenging = False |
496 | - |
497 | - self._currentChallenge = None |
498 | - self._currentChallengeCall.cancel() |
499 | - self._currentChallengeCall = None |
500 | - |
501 | - |
502 | - def _challengeAndRepeat(self): |
503 | - """ |
504 | - Shout a challenge and then schedule another one. |
505 | - """ |
506 | - self.challenge() |
507 | - self._scheduleChallenge() |
508 | - |
509 | - |
510 | - def getCurrentChallenge(self): |
511 | - """ |
512 | - Return the Hiragana character which is this mouse's current challenge, |
513 | - if it has one. |
514 | - |
515 | - @rtype: C{unicode} or C{None} |
516 | - """ |
517 | - return self._currentChallenge |
518 | - |
519 | - |
520 | - def vetteChallengeResponse(self, romajiResponse): |
521 | - """ |
522 | - Return True if the given response matches the current challenge, False |
523 | - otherwise. |
524 | - """ |
525 | - hiragana = japanese.romajiToHiragana.get(romajiResponse.upper(), None) |
526 | - return hiragana is not None and self.getCurrentChallenge() in hiragana |
527 | - |
528 | - |
529 | - def responseReceived(self, responder, romajiResponse): |
530 | - """ |
531 | - Called when some speech is observed. |
532 | - """ |
533 | - me = self._actor().thing |
534 | - if self.vetteChallengeResponse(romajiResponse): |
535 | - self._currentChallenge = None |
536 | - verb = u"salute" |
537 | - else: |
538 | - verb = u"bite" |
539 | - evt = events.Success( |
540 | - actor=me, |
541 | - target=responder, |
542 | - actorMessage=language.Sentence(["You ", verb, " ", responder, "."]), |
543 | - targetMessage=language.Sentence([language.Noun(me).shortName(), " ", verb, "s you!"]), |
544 | - otherMessage=language.Sentence([me, " ", verb, "s ", responder, "."])) |
545 | - # Fuck the reactor, Fuck scheduling, why does responseReceived |
546 | - # need to be concerned with these stupid scheduling details |
547 | - # when all it wants to do is respond basically-immediately. |
548 | - self._callLater(0, evt.broadcast) |
549 | - |
550 | - |
551 | - def challenge(self, character=None): |
552 | - """ |
553 | - Say only a single random hiragana character. |
554 | - """ |
555 | - if character is None: |
556 | - character = random.choice(japanese.hiragana.keys()) |
557 | - self._currentChallenge = character |
558 | - actor = self._actor() |
559 | - action.Say().do(actor, None, character) |
560 | - |
561 | - |
562 | - |
563 | -def createMouseCreator(mouseIntelligenceFactory): |
564 | - """ |
565 | - Create a createMouse function, which can be called to create a |
566 | - mouse object. Used for the 'Create' command plugin system. |
567 | - """ |
568 | - def createMouse(**kw): |
569 | - store = kw['store'] |
570 | - mouse = objects.Thing(**kw) |
571 | - mouseActor = objects.Actor.createFor(mouse) |
572 | - mousehood = mouseIntelligenceFactory(store=store) |
573 | - mouseActor.setEnduringIntelligence(mousehood) |
574 | - return mouse |
575 | - return createMouse |
576 | - |
577 | -createMouse = createMouseCreator(Mouse) |
578 | -createHiraganaMouse = createMouseCreator(HiraganaMouse) |
579 | |
580 | === removed file 'Imaginary/ExampleGame/examplegame/quiche.py' |
581 | --- Imaginary/ExampleGame/examplegame/quiche.py 2009-06-29 04:03:17 +0000 |
582 | +++ Imaginary/ExampleGame/examplegame/quiche.py 1970-01-01 00:00:00 +0000 |
583 | @@ -1,116 +0,0 @@ |
584 | -# -*- test-case-name: examplegame.test.test_quiche -*- |
585 | - |
586 | -""" |
587 | -This module is a mid-level proof of concept of various features in Imaginary. |
588 | - |
589 | -Currently its implementation is a bit messy and it assumes lots of things about |
590 | -the reader's knowledge, but we are working on more thoroughly documenting it |
591 | -and making it into a good example of how to build functionality that interacts |
592 | -with multiple systems (currency, containment, object creation) in Imaginary. |
593 | - |
594 | -""" |
595 | - |
596 | -from zope.interface import implements, Interface |
597 | - |
598 | -from axiom import item, attributes |
599 | - |
600 | -from imaginary import iimaginary, objects, events, language |
601 | -from imaginary.enhancement import Enhancement |
602 | - |
603 | -from imaginary.creation import createCreator |
604 | - |
605 | - |
606 | -class ICoin(Interface): |
607 | - """ |
608 | - Something small and probably flat and round and which probably serves as |
609 | - some form of currency. |
610 | - """ |
611 | - |
612 | - |
613 | - |
614 | -class Coinage(object): |
615 | - implements(ICoin) |
616 | - powerupInterfaces = (ICoin,) |
617 | - |
618 | - |
619 | - |
620 | -class Quarter(item.Item, Coinage, Enhancement): |
621 | - thing = attributes.reference(doc=""" |
622 | - The object this coin powers up. |
623 | - """) |
624 | - |
625 | - |
626 | - |
627 | -class VendingMachine(item.Item, objects.Containment, Enhancement): |
628 | - implements(iimaginary.IContainer) |
629 | - |
630 | - capacity = attributes.integer(doc=""" |
631 | - Units of weight which can be contained. |
632 | - """, allowNone=False, default=1) |
633 | - |
634 | - closed = attributes.boolean(doc=""" |
635 | - Indicates whether the container is currently closed or open. |
636 | - """, allowNone=False, default=True) |
637 | - |
638 | - thing = attributes.reference(doc=""" |
639 | - The object this container powers up. |
640 | - """) |
641 | - |
642 | - _currencyCounter = attributes.integer(doc=""" |
643 | - The number of coins which have been added to this vending machine since it |
644 | - last ejected an item. |
645 | - """, allowNone=False, default=0) |
646 | - |
647 | - def coinAdded(self, coin): |
648 | - """ |
649 | - Called when a coin is added to this thing. |
650 | - |
651 | - @type coin: C{ICoin} provider |
652 | - """ |
653 | - self._currencyCounter += 1 |
654 | - if self._currencyCounter >= 5 and self.getContents(): |
655 | - self._currencyCounter = 0 |
656 | - try: |
657 | - obj = iter(self.getContents()).next() |
658 | - except StopIteration: |
659 | - evt = events.Success( |
660 | - actor=self.thing, |
661 | - target=obj, |
662 | - otherMessage=language.Sentence([self.thing, " thumps loudly."])) |
663 | - else: |
664 | - evt = events.Success( |
665 | - actor=self.thing, |
666 | - target=obj, |
667 | - otherMessage=language.Sentence([ |
668 | - language.Noun(self.thing).definiteNounPhrase(), |
669 | - " thumps loudly and spits out ", obj, |
670 | - " onto the ground."])) |
671 | - state = self.closed |
672 | - self.closed = False |
673 | - try: |
674 | - obj.moveTo(self.thing.location) |
675 | - finally: |
676 | - self.closed = state |
677 | - evt.broadcast() |
678 | - |
679 | - |
680 | - def add(self, obj): |
681 | - coin = ICoin(obj, None) |
682 | - if coin is not None: |
683 | - self.coinAdded(coin) |
684 | - else: |
685 | - return super(VendingMachine, self).add(obj) |
686 | - |
687 | - |
688 | - |
689 | -def createVendingMachine(store, name, description=u""): |
690 | - o = objects.Thing(store=store, name=name, description=description) |
691 | - VendingMachine.createFor(o) |
692 | - return o |
693 | - |
694 | - |
695 | - |
696 | -createCoin = createCreator((Quarter, {})) |
697 | -createVendingMachine = createCreator((VendingMachine, {})) |
698 | -createQuiche = createCreator() |
699 | - |
700 | |
701 | === removed file 'Imaginary/ExampleGame/examplegame/squeaky.py' |
702 | --- Imaginary/ExampleGame/examplegame/squeaky.py 2009-08-17 02:40:03 +0000 |
703 | +++ Imaginary/ExampleGame/examplegame/squeaky.py 1970-01-01 00:00:00 +0000 |
704 | @@ -1,42 +0,0 @@ |
705 | -# -*- test-case-name: examplegame.test.test_squeaky -*- |
706 | - |
707 | -""" |
708 | -This module implements an L{ILinkAnnotator} which causes an object to squeak |
709 | -when it is moved. It should serve as a simple example for overriding what |
710 | -happens when an action is executed (in this case, 'take' and 'drop'). |
711 | -""" |
712 | - |
713 | -from zope.interface import implements |
714 | - |
715 | -from axiom.item import Item |
716 | -from axiom.attributes import reference |
717 | - |
718 | -from imaginary.iimaginary import IMovementRestriction, IConcept |
719 | -from imaginary.events import Success |
720 | -from imaginary.enhancement import Enhancement |
721 | -from imaginary.objects import Thing |
722 | - |
723 | - |
724 | -class Squeaker(Item, Enhancement): |
725 | - """ |
726 | - This is an L{Enhancement} which, when installed on a L{Thing}, causes that |
727 | - L{Thing} to squeak when you pick it up. |
728 | - """ |
729 | - |
730 | - implements(IMovementRestriction) |
731 | - |
732 | - powerupInterfaces = [IMovementRestriction] |
733 | - |
734 | - thing = reference(allowNone=False, |
735 | - whenDeleted=reference.CASCADE, |
736 | - reftype=Thing) |
737 | - |
738 | - |
739 | - def movementImminent(self, movee, destination): |
740 | - """ |
741 | - The object enhanced by this L{Squeaker} is about to move - emit a |
742 | - L{Success} event which describes its squeak. |
743 | - """ |
744 | - Success(otherMessage=(IConcept(self.thing).capitalizeConcept(), |
745 | - " emits a faint squeak."), |
746 | - location=self.thing.location).broadcast() |
747 | |
748 | === removed directory 'Imaginary/ExampleGame/examplegame/test' |
749 | === removed file 'Imaginary/ExampleGame/examplegame/test/__init__.py' |
750 | === removed file 'Imaginary/ExampleGame/examplegame/test/test_furniture.py' |
751 | --- Imaginary/ExampleGame/examplegame/test/test_furniture.py 2013-07-03 23:55:37 +0000 |
752 | +++ Imaginary/ExampleGame/examplegame/test/test_furniture.py 1970-01-01 00:00:00 +0000 |
753 | @@ -1,104 +0,0 @@ |
754 | - |
755 | -""" |
756 | -This module contains tests for the examplegame.furniture module. |
757 | -""" |
758 | - |
759 | -from twisted.trial.unittest import TestCase |
760 | - |
761 | -from imaginary.test.commandutils import CommandTestCaseMixin, E, createLocation |
762 | - |
763 | -from imaginary.objects import Thing, Exit |
764 | -from examplegame.furniture import Chair |
765 | - |
766 | -class SitAndStandTests(CommandTestCaseMixin, TestCase): |
767 | - """ |
768 | - Tests for the 'sit' and 'stand' actions. |
769 | - """ |
770 | - |
771 | - def setUp(self): |
772 | - """ |
773 | - Create a room, with a dude in it, and a chair he can sit in. |
774 | - """ |
775 | - CommandTestCaseMixin.setUp(self) |
776 | - self.chairThing = Thing(store=self.store, name=u"chair") |
777 | - self.chairThing.moveTo(self.location) |
778 | - self.chair = Chair.createFor(self.chairThing) |
779 | - |
780 | - |
781 | - def test_sitDown(self): |
782 | - """ |
783 | - Sitting in a chair should move your location to that chair. |
784 | - """ |
785 | - self.assertCommandOutput( |
786 | - "sit chair", |
787 | - ["You sit in the chair."], |
788 | - ["Test Player sits in the chair."]) |
789 | - self.assertEquals(self.player.location, self.chair.thing) |
790 | - |
791 | - |
792 | - def test_standWhenStanding(self): |
793 | - """ |
794 | - You can't stand up - you're already standing up. |
795 | - """ |
796 | - self.assertCommandOutput( |
797 | - "stand up", |
798 | - ["You're already standing."]) |
799 | - |
800 | - |
801 | - def test_standWhenSitting(self): |
802 | - """ |
803 | - If a player stands up when sitting in a chair, they should be seen to |
804 | - stand up, and they should be placed back into the room where the chair |
805 | - is located. |
806 | - """ |
807 | - self.test_sitDown() |
808 | - self.assertCommandOutput( |
809 | - "stand up", |
810 | - ["You stand up."], |
811 | - ["Test Player stands up."]) |
812 | - self.assertEquals(self.player.location, self.location) |
813 | - |
814 | - |
815 | - def test_takeWhenSitting(self): |
816 | - """ |
817 | - When a player is seated, they should still be able to take objects on |
818 | - the floor around them. |
819 | - """ |
820 | - self.test_sitDown() |
821 | - self.ball = Thing(store=self.store, name=u'ball') |
822 | - self.ball.moveTo(self.location) |
823 | - self.assertCommandOutput( |
824 | - "take ball", |
825 | - ["You take a ball."], |
826 | - ["Test Player takes a ball."]) |
827 | - |
828 | - |
829 | - def test_moveWhenSitting(self): |
830 | - """ |
831 | - A player who is sitting shouldn't be able to move without standing up |
832 | - first. |
833 | - """ |
834 | - self.test_sitDown() |
835 | - otherRoom = createLocation(self.store, u"elsewhere", None).thing |
836 | - Exit.link(self.location, otherRoom, u'north') |
837 | - self.assertCommandOutput( |
838 | - "go north", |
839 | - ["You can't do that while sitting down."]) |
840 | - self.assertCommandOutput( |
841 | - "go south", |
842 | - ["You can't go that way."]) |
843 | - |
844 | - |
845 | - def test_lookWhenSitting(self): |
846 | - """ |
847 | - Looking around when sitting should display the description of the room. |
848 | - """ |
849 | - self.test_sitDown() |
850 | - self.assertCommandOutput( |
851 | - "look", |
852 | - # I'd like to add ', in the chair' to this test, but there's |
853 | - # currently no way to modify the name of the object being looked |
854 | - # at. |
855 | - [E("[ Test Location ]"), |
856 | - "Location for testing.", |
857 | - "Here, you see Observer Player and a chair."]) |
858 | |
859 | === removed file 'Imaginary/ExampleGame/examplegame/test/test_glass.py' |
860 | --- Imaginary/ExampleGame/examplegame/test/test_glass.py 2013-07-03 23:55:37 +0000 |
861 | +++ Imaginary/ExampleGame/examplegame/test/test_glass.py 1970-01-01 00:00:00 +0000 |
862 | @@ -1,95 +0,0 @@ |
863 | - |
864 | -""" |
865 | -Tests for L{examplegame.glass} |
866 | -""" |
867 | - |
868 | -from twisted.trial.unittest import TestCase |
869 | - |
870 | -from imaginary.test.commandutils import CommandTestCaseMixin, E |
871 | - |
872 | -from imaginary.objects import Thing, Container |
873 | - |
874 | -from examplegame.glass import GlassBox |
875 | - |
876 | -class GlassBoxTests(CommandTestCaseMixin, TestCase): |
877 | - """ |
878 | - Tests for L{GlassBox} |
879 | - """ |
880 | - |
881 | - def setUp(self): |
882 | - """ |
883 | - Create a room with a L{GlassBox} in it, which itself contains a ball. |
884 | - """ |
885 | - CommandTestCaseMixin.setUp(self) |
886 | - self.box = Thing(store=self.store, name=u'box', |
887 | - description=u'The system under test.') |
888 | - self.ball = Thing(store=self.store, name=u'ball', |
889 | - description=u'an interesting object') |
890 | - self.container = Container.createFor(self.box) |
891 | - GlassBox.createFor(self.box) |
892 | - self.ball.moveTo(self.box) |
893 | - self.box.moveTo(self.location) |
894 | - self.container.closed = True |
895 | - |
896 | - |
897 | - def test_lookThrough(self): |
898 | - """ |
899 | - You can see items within a glass box by looking at them directly. |
900 | - """ |
901 | - self.assertCommandOutput( |
902 | - "look at ball", |
903 | - [E("[ ball ]"), |
904 | - "an interesting object"]) |
905 | - |
906 | - |
907 | - def test_lookAt(self): |
908 | - """ |
909 | - You can see the contents within a glass box by looking at the box. |
910 | - """ |
911 | - self.assertCommandOutput( |
912 | - "look at box", |
913 | - [E("[ box ]"), |
914 | - "The system under test.", |
915 | - "It contains a ball."]) |
916 | - |
917 | - |
918 | - def test_take(self): |
919 | - """ |
920 | - You can't take items within a glass box. |
921 | - """ |
922 | - self.assertCommandOutput( |
923 | - "get ball", |
924 | - ["You can't reach through the glass box."]) |
925 | - |
926 | - |
927 | - def test_openTake(self): |
928 | - """ |
929 | - Taking items from a glass box should work if it's open. |
930 | - """ |
931 | - self.container.closed = False |
932 | - self.assertCommandOutput( |
933 | - "get ball", |
934 | - ["You take a ball."], |
935 | - ["Test Player takes a ball."]) |
936 | - |
937 | - |
938 | - def test_put(self): |
939 | - """ |
940 | - You can't put items into a glass box. |
941 | - """ |
942 | - self.container.closed = False |
943 | - self.ball.moveTo(self.location) |
944 | - self.container.closed = True |
945 | - self.assertCommandOutput( |
946 | - "put ball in box", |
947 | - ["The box is closed."]) |
948 | - |
949 | - |
950 | - def test_whyNot(self): |
951 | - """ |
952 | - A regression test; there was a bug where glass boxes would interfere |
953 | - with normal target-acquisition error reporting. |
954 | - """ |
955 | - self.assertCommandOutput( |
956 | - "get foobar", |
957 | - ["Nothing like that around here."]) |
958 | |
959 | === removed file 'Imaginary/ExampleGame/examplegame/test/test_japanese.py' |
960 | --- Imaginary/ExampleGame/examplegame/test/test_japanese.py 2013-07-03 23:55:37 +0000 |
961 | +++ Imaginary/ExampleGame/examplegame/test/test_japanese.py 1970-01-01 00:00:00 +0000 |
962 | @@ -1,474 +0,0 @@ |
963 | -import weakref |
964 | - |
965 | -from twisted.internet import task |
966 | -from twisted.trial import unittest |
967 | - |
968 | -from axiom import store |
969 | - |
970 | -from imaginary import iimaginary, objects, events, action |
971 | - |
972 | -from imaginary.test import commandutils |
973 | - |
974 | -from examplegame import mice |
975 | -from examplegame import japanese |
976 | - |
977 | -class MouseChallengeMixin(object): |
978 | - """ |
979 | - A mixin meant to be used in TestCases which want to assert things |
980 | - about mouse challenges. |
981 | - |
982 | - The subclass must be sure to provide a C{player} instance |
983 | - attribute, which is the L{IThing<iimaginary.IThing>} provider of |
984 | - the player which observes the mouse, and a C{mouseName} attribute |
985 | - which should be the mouse's name. |
986 | - """ |
987 | - def assertChallenge(self, concept): |
988 | - """ |
989 | - Assert that the given concept is a challenge from the mouse |
990 | - named self.mouseName, as observed by self.player. |
991 | - """ |
992 | - said = commandutils.flatten(concept.plaintext(self.player)) |
993 | - self.failUnless(said.startswith(u"A %s says, '" % (self.mouseName,)), repr(said)) |
994 | - self.failUnlessIn(said[-3], japanese.hiragana) |
995 | - self.failUnless(said.endswith("'\n"), repr(said)) |
996 | - |
997 | - |
998 | - |
999 | -class HiraganaMouseTestCase(MouseChallengeMixin, unittest.TestCase): |
1000 | - """ |
1001 | - Test that there is a mouse that says hiragana and stuff |
1002 | - """ |
1003 | - |
1004 | - def setUp(self): |
1005 | - self.store = store.Store() |
1006 | - |
1007 | - self.clock = objects.Thing(store=self.store, name=u"Clock") |
1008 | - self.clockContainer = objects.Container.createFor(self.clock, capacity=10) |
1009 | - |
1010 | - self.mouseName = u"\N{KATAKANA LETTER PI}\N{KATAKANA LETTER SMALL YU}" |
1011 | - self.mouse = mice.createHiraganaMouse( |
1012 | - store=self.store, |
1013 | - name=self.mouseName) |
1014 | - self.mouseActor = iimaginary.IActor(self.mouse) |
1015 | - self.mousehood = self.mouseActor.getIntelligence() |
1016 | - self.mouse.moveTo(self.clock) |
1017 | - |
1018 | - (self.player, |
1019 | - self.playerActor, |
1020 | - self.playerIntelligence) = commandutils.createPlayer(self.store, |
1021 | - u"Mean Old Man") |
1022 | - |
1023 | - |
1024 | - self.player.moveTo(self.clock) |
1025 | - |
1026 | - self.reactorTime = task.Clock() |
1027 | - self.mousehood._callLater = self.reactorTime.callLater |
1028 | - |
1029 | - |
1030 | - def test_mouseCanSqueak(self): |
1031 | - """ |
1032 | - When explicitly told to challenge with a given romaji syllable, the |
1033 | - mouse should say a hiragana letter. |
1034 | - """ |
1035 | - events.runEventTransaction( |
1036 | - self.store, |
1037 | - self.mousehood.challenge, |
1038 | - character=u"\N{HIRAGANA LETTER A}") |
1039 | - |
1040 | - self.assertEquals(len(self.playerIntelligence.concepts), 1) |
1041 | - event = self.playerIntelligence.concepts[0] |
1042 | - self.assertEquals( |
1043 | - commandutils.flatten(event.otherMessage.plaintext(self.player)), |
1044 | - u"A %s says, '\N{HIRAGANA LETTER A}'" % (self.mouseName,)) |
1045 | - |
1046 | - |
1047 | - def test_randomHiragana(self): |
1048 | - """ |
1049 | - When explicitly told to challenge without specifying a syllable, the |
1050 | - mouse should say a random one. |
1051 | - """ |
1052 | - events.runEventTransaction(self.store, self.mousehood.challenge) |
1053 | - self.assertEquals(len(self.playerIntelligence.concepts), 1) |
1054 | - event = self.playerIntelligence.concepts[0] |
1055 | - self.assertChallenge(event) |
1056 | - |
1057 | - |
1058 | - def test_ji(self): |
1059 | - """ |
1060 | - Two hiragana characters map to the romaji 'ji'. Test that we do the |
1061 | - right thing for them. |
1062 | - """ |
1063 | - self.mousehood.challenge(character=u"\N{HIRAGANA LETTER DI}") |
1064 | - self.failUnless(self.mousehood.vetteChallengeResponse(u"ji")) |
1065 | - self.mousehood.challenge(character=u"\N{HIRAGANA LETTER ZI}") |
1066 | - self.failUnless(self.mousehood.vetteChallengeResponse(u"ji")) |
1067 | - |
1068 | - |
1069 | - def test_zu(self): |
1070 | - """ |
1071 | - Two hiragana characters map to the romaji 'zu'. Test that we do the |
1072 | - right thing for them. |
1073 | - """ |
1074 | - self.mousehood.challenge(character=u"\N{HIRAGANA LETTER DU}") |
1075 | - self.failUnless(self.mousehood.vetteChallengeResponse(u"zu")) |
1076 | - self.mousehood.challenge(character=u"\N{HIRAGANA LETTER ZU}") |
1077 | - self.failUnless(self.mousehood.vetteChallengeResponse(u"zu")) |
1078 | - |
1079 | - |
1080 | - def test_mouseStartsChallengingWhenPlayersArrive(self): |
1081 | - """ |
1082 | - When a player arrives, the mouse should go into the 'I am |
1083 | - challenging' state. |
1084 | - """ |
1085 | - # Whitebox |
1086 | - self.assertEquals(self.mousehood.challenging, False) |
1087 | - |
1088 | - evt = events.ArrivalEvent(actor=self.player) |
1089 | - self.mouseActor.send(evt) |
1090 | - |
1091 | - self.assertEquals(self.mousehood.challenging, True) |
1092 | - |
1093 | - |
1094 | - def test_mouseSchedulesChallenges(self): |
1095 | - """ |
1096 | - After telling a mouse to start challenging, it should schedule timed |
1097 | - events to say challenges. |
1098 | - """ |
1099 | - self.mousehood.startChallenging() |
1100 | - self.reactorTime.advance(self.mousehood.challengeInterval) |
1101 | - concepts = self.playerIntelligence.concepts |
1102 | - self.assertEquals(len(concepts), 1) |
1103 | - self.assertChallenge(concepts[0]) |
1104 | - |
1105 | - |
1106 | - def test_mouseStopsChallengingWhenPlayersLeave(self): |
1107 | - """ |
1108 | - When the 'last' player leaves, the mouse stops challenging. |
1109 | - """ |
1110 | - # Whitebox |
1111 | - self.mousehood.startChallenging() |
1112 | - |
1113 | - evt = events.DepartureEvent(location=self.clock, |
1114 | - actor=self.player) |
1115 | - self.player.moveTo(None) |
1116 | - self.mouseActor.send(evt) |
1117 | - |
1118 | - self.assertEquals(self.mousehood.challenging, False) |
1119 | - |
1120 | - |
1121 | - def test_mouseStopsSchedulingChallenges(self): |
1122 | - """ |
1123 | - When a mouse is told to stop challenging, it should cancel any |
1124 | - challenges it had scheduled. |
1125 | - """ |
1126 | - self.mousehood.startChallenging() |
1127 | - self.mousehood.stopChallenging() |
1128 | - |
1129 | - self.reactorTime.advance(self.mousehood.challengeInterval) |
1130 | - self.assertEquals(self.playerIntelligence.concepts, []) |
1131 | - |
1132 | - |
1133 | - def test_stopChallengingWhenNotChallengingFails(self): |
1134 | - """ |
1135 | - Don't stop challenging when you're not challenging. |
1136 | - """ |
1137 | - self.assertRaises(mice.ChallengeVacuum, self.mousehood.stopChallenging) |
1138 | - |
1139 | - |
1140 | - def test_startChallengingTwiceFails(self): |
1141 | - """ |
1142 | - Don't start challenging twice. |
1143 | - """ |
1144 | - self.mousehood.startChallenging() |
1145 | - self.assertRaises(mice.ChallengeCollision, self.mousehood.startChallenging) |
1146 | - |
1147 | - |
1148 | - def test_challengeRecurrence(self): |
1149 | - """ |
1150 | - After a challenge is issued another one should be issued later. |
1151 | - """ |
1152 | - self.mousehood.startChallenging() |
1153 | - self.reactorTime.advance(self.mousehood.challengeInterval) |
1154 | - |
1155 | - self.assertIn(self.mousehood.getCurrentChallenge(), japanese.hiragana) |
1156 | - |
1157 | - self.mousehood._currentChallenge = None # Clear his challenge evilly |
1158 | - |
1159 | - self.reactorTime.advance(self.mousehood.challengeInterval) |
1160 | - |
1161 | - self.assertIn(self.mousehood.getCurrentChallenge(), japanese.hiragana) |
1162 | - |
1163 | - |
1164 | - def test_twoMenEnter(self): |
1165 | - """ |
1166 | - Test that when *TWO* players join, the mouse doesn't schedule too many |
1167 | - challenges. |
1168 | - """ |
1169 | - otherPlayer = commandutils.createPlayer(self.store, |
1170 | - u"Polite Young Man")[0] |
1171 | - |
1172 | - # Send an arrival event because setUp doesn't |
1173 | - firstEvent = events.ArrivalEvent(actor=self.player) |
1174 | - |
1175 | - self.mouseActor.send(firstEvent) |
1176 | - otherPlayer.moveTo(self.clock, arrivalEventFactory=events.MovementArrivalEvent) |
1177 | - |
1178 | - self.playerIntelligence.concepts = [] |
1179 | - self.reactorTime.advance(self.mousehood.challengeInterval) |
1180 | - |
1181 | - self.assertEquals(len(self.playerIntelligence.concepts), 1) |
1182 | - self.assertChallenge(self.playerIntelligence.concepts[0]) |
1183 | - |
1184 | - |
1185 | - def test_twoMenLeave(self): |
1186 | - """ |
1187 | - Test that when two players are near the mouse, the mouse doesn't |
1188 | - unschedule its challenge until they both leave. |
1189 | - """ |
1190 | - otherPlayer = commandutils.createPlayer(self.store, |
1191 | - u"Polite Young Man")[0] |
1192 | - otherPlayer.moveTo(self.clock) |
1193 | - |
1194 | - self.mousehood.startChallenging() |
1195 | - |
1196 | - firstEvent = events.DepartureEvent(location=self.clock, |
1197 | - actor=self.player) |
1198 | - secondEvent = events.DepartureEvent(location=self.clock, |
1199 | - actor=otherPlayer) |
1200 | - |
1201 | - otherPlayer.moveTo(None) |
1202 | - self.mouseActor.send(secondEvent) |
1203 | - |
1204 | - self.playerIntelligence.concepts = [] |
1205 | - |
1206 | - self.reactorTime.advance(self.mousehood.challengeInterval) |
1207 | - |
1208 | - self.assertEquals(len(self.playerIntelligence.concepts), 1) |
1209 | - self.assertChallenge(self.playerIntelligence.concepts[0]) |
1210 | - |
1211 | - self.player.moveTo(None) |
1212 | - self.mouseActor.send(firstEvent) |
1213 | - |
1214 | - self.failIf(self.mousehood.challenging) |
1215 | - |
1216 | - |
1217 | - def test_getCurrentChallenge(self): |
1218 | - """ |
1219 | - Test that we can introspect the current challenge of a mouse. |
1220 | - """ |
1221 | - self.mousehood.startChallenging() |
1222 | - self.reactorTime.advance(self.mousehood.challengeInterval) |
1223 | - self.failUnlessIn(self.mousehood.getCurrentChallenge(), japanese.hiragana) |
1224 | - |
1225 | - self.mousehood.stopChallenging() |
1226 | - self.assertIdentical(self.mousehood.getCurrentChallenge(), None) |
1227 | - |
1228 | - |
1229 | - def test_vetteChallengeResponse(self): |
1230 | - """ |
1231 | - Test that the correct response to the current challenge is accepted by |
1232 | - the mouse. |
1233 | - """ |
1234 | - self.mousehood.startChallenging() |
1235 | - self.reactorTime.advance(self.mousehood.challengeInterval) |
1236 | - |
1237 | - romaji = japanese.hiragana[self.mousehood.getCurrentChallenge()] |
1238 | - self.failUnless(self.mousehood.vetteChallengeResponse(romaji)) |
1239 | - |
1240 | - for romaji in japanese.hiragana.values(): |
1241 | - if romaji != japanese.hiragana[self.mousehood.getCurrentChallenge()]: |
1242 | - self.failIf(self.mousehood.vetteChallengeResponse(romaji)) |
1243 | - |
1244 | - |
1245 | - def test_respondToChallengeCorrectly(self): |
1246 | - """ |
1247 | - Test that when a correct response is received, the current challenge is |
1248 | - expired and the mouse salutes you. |
1249 | - """ |
1250 | - self.mousehood.startChallenging() |
1251 | - self.reactorTime.advance(self.mousehood.challengeInterval) |
1252 | - |
1253 | - correctResponse = japanese.hiragana[ |
1254 | - self.mousehood.getCurrentChallenge()] |
1255 | - |
1256 | - self.mousehood.responseReceived(self.player, correctResponse) |
1257 | - self.reactorTime.advance(0) |
1258 | - |
1259 | - self.assertIdentical(self.mousehood.getCurrentChallenge(), None) |
1260 | - |
1261 | - self.assertEquals(len(self.playerIntelligence.concepts), 2) |
1262 | - c = self.playerIntelligence.concepts[1] |
1263 | - self.assertEquals( |
1264 | - commandutils.flatten(c.plaintext(self.player)), |
1265 | - u"%s salutes you!\n" % (self.mouseName,)) |
1266 | - |
1267 | - |
1268 | - def test_respondToChallengeInorrectly(self): |
1269 | - """ |
1270 | - Test that when an incorrect response is received, the current challenge |
1271 | - is not expired and the mouse bites you. |
1272 | - """ |
1273 | - self.mousehood.startChallenging() |
1274 | - self.reactorTime.advance(self.mousehood.challengeInterval) |
1275 | - |
1276 | - correctResponse = japanese.hiragana[ |
1277 | - self.mousehood.getCurrentChallenge()] |
1278 | - |
1279 | - for ch in japanese.hiragana.values(): |
1280 | - if ch != correctResponse: |
1281 | - self.mousehood.responseReceived(self.player, ch) |
1282 | - break |
1283 | - else: |
1284 | - self.fail("Buggy test") |
1285 | - |
1286 | - self.reactorTime.advance(0) |
1287 | - |
1288 | - self.assertIn(self.mousehood.getCurrentChallenge(), |
1289 | - japanese.romajiToHiragana[correctResponse]) |
1290 | - |
1291 | - self.assertEquals(len(self.playerIntelligence.concepts), 2) |
1292 | - c = self.playerIntelligence.concepts[1] |
1293 | - self.assertEquals( |
1294 | - commandutils.flatten(c.plaintext(self.player)), |
1295 | - u"%s bites you!\n" % (self.mouseName,)) |
1296 | - |
1297 | - |
1298 | - def test_playerSaysCorrectThing(self): |
1299 | - """ |
1300 | - Test that when someone gives voice to the correct response to a mouse's |
1301 | - current challenge, the mouse acknowledges this with a salute. |
1302 | - """ |
1303 | - self.mousehood.startChallenging() |
1304 | - self.reactorTime.advance(self.mousehood.challengeInterval) |
1305 | - action.Say().do( |
1306 | - # http://divmod.org/trac/ticket/2917 |
1307 | - iimaginary.IActor(self.player), |
1308 | - None, |
1309 | - japanese.hiragana[self.mousehood.getCurrentChallenge()]) |
1310 | - |
1311 | - self.assertIdentical(self.mousehood.getCurrentChallenge(), None) |
1312 | - self.reactorTime.advance(0) |
1313 | - |
1314 | - self.assertEquals(len(self.playerIntelligence.concepts), 3) |
1315 | - c = self.playerIntelligence.concepts[2] |
1316 | - self.assertEquals( |
1317 | - commandutils.flatten(c.plaintext(self.player)), |
1318 | - u"%s salutes you!\n" % (self.mouseName,)) |
1319 | - |
1320 | - |
1321 | - def test_playerSaysIncorrectThing(self): |
1322 | - """ |
1323 | - Test that when someone gives voice to the correct response to a mouse's |
1324 | - current challenge, the mouse acknowledges this with a salute. |
1325 | - """ |
1326 | - self.mousehood.startChallenging() |
1327 | - self.reactorTime.advance(self.mousehood.challengeInterval) |
1328 | - |
1329 | - action.Say().do( |
1330 | - # http://divmod.org/trac/ticket/2917 |
1331 | - iimaginary.IActor(self.player), None, u"lolololo pew") |
1332 | - |
1333 | - self.failIfIdentical(self.mousehood.getCurrentChallenge(), None) |
1334 | - self.reactorTime.advance(0) |
1335 | - |
1336 | - self.assertEquals(len(self.playerIntelligence.concepts), 3) |
1337 | - c = self.playerIntelligence.concepts[2] |
1338 | - self.assertEquals( |
1339 | - commandutils.flatten(c.plaintext(self.player)), |
1340 | - u"%s bites you!\n" % (self.mouseName,)) |
1341 | - |
1342 | - |
1343 | - def test_activationUsesReactorScheduling(self): |
1344 | - """ |
1345 | - Test that the default scheduler of the mouse is the Twisted |
1346 | - reactor, since that is the scheduler that needs to be used |
1347 | - with the actual Imaginary server. |
1348 | - """ |
1349 | - deletions = [] |
1350 | - ref = weakref.ref(self.mousehood, deletions.append) |
1351 | - # This is a hack to reload the mouse since it gets its |
1352 | - # _callLater set in setUp. |
1353 | - del self.mouse |
1354 | - del self.mouseActor |
1355 | - del self.mousehood |
1356 | - self.assertEquals(deletions, [ref]) |
1357 | - mousehood = self.store.findUnique(mice.HiraganaMouse) |
1358 | - from twisted.internet import reactor |
1359 | - self.assertEquals(mousehood._callLater, reactor.callLater) |
1360 | - |
1361 | - |
1362 | - |
1363 | -class HiraganaMouseCommandTestCase(commandutils.CommandTestCaseMixin, unittest.TestCase): |
1364 | - """ |
1365 | - H-mouse tests which use the command system. |
1366 | - """ |
1367 | - |
1368 | - mouseName = u"\N{KATAKANA LETTER PI}\N{KATAKANA LETTER SMALL YU}" |
1369 | - hiraganaCharacterPattern = u"'[" + u''.join(japanese.hiragana.keys()) + u"]'" |
1370 | - speechPattern = mouseName + u" says, " + hiraganaCharacterPattern |
1371 | - |
1372 | - def test_oneManEnters(self): |
1373 | - """ |
1374 | - Test that when a fellow jaunts into a venue inhabited by a mouse of the |
1375 | - Nipponese persuasion, a hiragana allocution follows. |
1376 | - """ |
1377 | - clock = task.Clock() |
1378 | - |
1379 | - closetContainer = commandutils.createLocation( |
1380 | - self.store, u"Closet", None) |
1381 | - closet = closetContainer.thing |
1382 | - |
1383 | - mouse = mice.createHiraganaMouse( |
1384 | - store=self.store, |
1385 | - name=self.mouseName, |
1386 | - proper=True) |
1387 | - mouseActor = iimaginary.IActor(mouse) |
1388 | - mousehood = mouseActor.getIntelligence() |
1389 | - mousehood._callLater = clock.callLater |
1390 | - mouse.moveTo(closet) |
1391 | - |
1392 | - objects.Exit.link(self.location, closet, u"north") |
1393 | - |
1394 | - self._test( |
1395 | - "north", |
1396 | - [commandutils.E("[ Closet ]"), |
1397 | - commandutils.E("( south )"), |
1398 | - commandutils.E(u"Here, you see " + self.mouseName + u".")], |
1399 | - ["Test Player leaves north."]) |
1400 | - |
1401 | - clock.advance(mousehood.challengeInterval) |
1402 | - |
1403 | - self._test(None, [self.speechPattern]) |
1404 | - |
1405 | - |
1406 | - def test_creation(self): |
1407 | - """ |
1408 | - Test the creation of a hiragana-speaking mouse using the thing creation |
1409 | - plugin system. |
1410 | - """ |
1411 | - self._test( |
1412 | - u"create the 'hiragana mouse' named " + self.mouseName, |
1413 | - [commandutils.E(u"You create " + self.mouseName + u".")], |
1414 | - [commandutils.E(u"Test Player creates %s." % (self.mouseName,))]) |
1415 | - |
1416 | - for thing in self.location.findProviders(iimaginary.IThing, 0): |
1417 | - if thing.name == self.mouseName: |
1418 | - break |
1419 | - else: |
1420 | - self.fail("Could not find the mouse! Test bug.") |
1421 | - |
1422 | - clock = task.Clock() |
1423 | - jimhood = iimaginary.IActor(thing).getIntelligence() |
1424 | - jimhood._callLater = clock.callLater |
1425 | - |
1426 | - self._test( |
1427 | - u"drop " + self.mouseName, |
1428 | - [commandutils.E(u"You drop %s." % (self.mouseName,))], |
1429 | - [commandutils.E(u"Test Player drops %s." % (self.mouseName,))]) |
1430 | - |
1431 | - clock.advance(jimhood.challengeInterval) |
1432 | - |
1433 | - self._test( |
1434 | - None, |
1435 | - [self.speechPattern], |
1436 | - [self.speechPattern]) |
1437 | |
1438 | === removed file 'Imaginary/ExampleGame/examplegame/test/test_mice.py' |
1439 | --- Imaginary/ExampleGame/examplegame/test/test_mice.py 2013-07-03 23:50:20 +0000 |
1440 | +++ Imaginary/ExampleGame/examplegame/test/test_mice.py 1970-01-01 00:00:00 +0000 |
1441 | @@ -1,155 +0,0 @@ |
1442 | - |
1443 | -from twisted.trial import unittest |
1444 | -from twisted.internet import task |
1445 | - |
1446 | -from axiom import store |
1447 | - |
1448 | -from imaginary import iimaginary, events, objects |
1449 | -from imaginary.test import commandutils |
1450 | - |
1451 | -from examplegame import mice |
1452 | - |
1453 | - |
1454 | -class IntelligenceTestCase(unittest.TestCase): |
1455 | - def setUp(self): |
1456 | - self.store = store.Store() |
1457 | - |
1458 | - self.locationContainer = commandutils.createLocation( |
1459 | - self.store, u"Place", None) |
1460 | - self.location = self.locationContainer.thing |
1461 | - |
1462 | - self.alice = objects.Thing(store=self.store, name=u"Alice") |
1463 | - self.actor = objects.Actor.createFor(self.alice) |
1464 | - |
1465 | - self.alice.moveTo(self.location) |
1466 | - |
1467 | - self.intelligence = commandutils.MockIntelligence(store=self.store) |
1468 | - self.actor.setEnduringIntelligence(self.intelligence) |
1469 | - |
1470 | - |
1471 | - def test_intelligenceReceivesEvent(self): |
1472 | - """ |
1473 | - Enduring intelligences should receive events. |
1474 | - """ |
1475 | - evt = events.Success( |
1476 | - location=self.location, |
1477 | - otherMessage=u"Hello, how are you?") |
1478 | - |
1479 | - self.actor.send(evt) |
1480 | - self.assertEquals(self.intelligence.concepts, [evt]) |
1481 | - |
1482 | - |
1483 | - def test_persistentIntelligence(self): |
1484 | - """ |
1485 | - Whitebox test that enduring intelligencii are actually persistent. |
1486 | - """ |
1487 | - # TB <---- THAT MEANS IT'S TRANSLUCENT |
1488 | - self.assertIdentical( |
1489 | - self.store.findUnique( |
1490 | - objects.Actor, |
1491 | - objects.Actor._enduringIntelligence == self.intelligence), |
1492 | - self.actor) |
1493 | - |
1494 | - |
1495 | - |
1496 | -class MouseTestCase(unittest.TestCase): |
1497 | - def setUp(self): |
1498 | - self.store = store.Store() |
1499 | - |
1500 | - self.clock = objects.Thing(store=self.store, name=u"Clock") |
1501 | - self.clockContainer = objects.Container.createFor(self.clock, capacity=10) |
1502 | - |
1503 | - self.mouse = mice.createMouse(store=self.store, name=u"Squeaker McSqueakenson") |
1504 | - self.mouseActor = iimaginary.IActor(self.mouse) |
1505 | - self.mousehood = self.mouseActor.getIntelligence() |
1506 | - self.mouse.moveTo(self.clock) |
1507 | - |
1508 | - self.player = objects.Thing(store=self.store, name=u"Mean Old Man") |
1509 | - self.playerActor = objects.Actor.createFor(self.player) |
1510 | - self.playerIntelligence = commandutils.MockIntelligence( |
1511 | - store=self.store) |
1512 | - self.playerActor.setEnduringIntelligence(self.playerIntelligence) |
1513 | - |
1514 | - self.player.moveTo(self.clock) |
1515 | - |
1516 | - |
1517 | - def test_mouseSqueaksAtIntruders(self): |
1518 | - """ |
1519 | - When a mean old man walks into the mouse's clock, the mouse will squeak |
1520 | - ruthlessly. |
1521 | - """ |
1522 | - clock = task.Clock() |
1523 | - self.mousehood._callLater = clock.callLater |
1524 | - evt = events.ArrivalEvent(actor=self.player) |
1525 | - self.mouseActor.send(evt) |
1526 | - |
1527 | - self.assertEquals(len(self.playerIntelligence.concepts), 0) |
1528 | - clock.advance(0) |
1529 | - |
1530 | - self.assertEquals(len(self.playerIntelligence.concepts), 1) |
1531 | - event = self.playerIntelligence.concepts[0] |
1532 | - self.assertEquals( |
1533 | - commandutils.flatten(event.otherMessage.plaintext(self.player)), |
1534 | - u"SQUEAK!") |
1535 | - |
1536 | - |
1537 | - def test_mouseCanSqueak(self): |
1538 | - events.runEventTransaction(self.store, self.mousehood.squeak) |
1539 | - self.assertEquals(len(self.playerIntelligence.concepts), 1) |
1540 | - event = self.playerIntelligence.concepts[0] |
1541 | - self.assertEquals( |
1542 | - commandutils.flatten(event.otherMessage.plaintext(self.player)), |
1543 | - u"SQUEAK!") |
1544 | - |
1545 | - |
1546 | - def test_mouseActivation(self): |
1547 | - """ |
1548 | - Activating a mouse should set the scheduling mechanism to the |
1549 | - reactor's. |
1550 | - """ |
1551 | - from twisted.internet import reactor |
1552 | - self.assertEquals(self.mousehood._callLater, reactor.callLater) |
1553 | - |
1554 | - |
1555 | - |
1556 | -class MouseReactionTestCase(commandutils.CommandTestCaseMixin, |
1557 | - unittest.TestCase): |
1558 | - def testCreation(self): |
1559 | - """ |
1560 | - Test that a mouse can be created with the create command. |
1561 | - """ |
1562 | - self._test( |
1563 | - "create the mouse named squeaker", |
1564 | - ['You create squeaker.'], |
1565 | - ['Test Player creates squeaker.']) |
1566 | - |
1567 | - [mouse] = list(self.playerContainer.getContents()) |
1568 | - self.failUnless(isinstance(iimaginary.IActor(mouse).getIntelligence(), mice.Mouse)) |
1569 | - |
1570 | - |
1571 | - def testSqueak(self): |
1572 | - """ |
1573 | - Test that when someone walks into a room with a mouse, the mouse |
1574 | - squeaks and the person who walked in hears it. |
1575 | - """ |
1576 | - mouse = mice.createMouse(store=self.store, name=u"squeaker") |
1577 | - clock = task.Clock() |
1578 | - intelligence = iimaginary.IActor(mouse).getIntelligence() |
1579 | - intelligence._callLater = clock.callLater |
1580 | - |
1581 | - elsewhere = commandutils.createLocation( |
1582 | - self.store, u"Mouse Hole", None).thing |
1583 | - |
1584 | - objects.Exit.link(self.location, elsewhere, u"south") |
1585 | - |
1586 | - mouse.moveTo(elsewhere) |
1587 | - |
1588 | - self._test( |
1589 | - "south", |
1590 | - [commandutils.E("[ Mouse Hole ]"), |
1591 | - commandutils.E("( north )"), |
1592 | - commandutils.E("Here, you see a squeaker.")], |
1593 | - ['Test Player leaves south.']) |
1594 | - |
1595 | - clock.advance(0) |
1596 | - self._test(None, ["SQUEAK!"]) |
1597 | |
1598 | === removed file 'Imaginary/ExampleGame/examplegame/test/test_quiche.py' |
1599 | --- Imaginary/ExampleGame/examplegame/test/test_quiche.py 2009-06-29 04:03:17 +0000 |
1600 | +++ Imaginary/ExampleGame/examplegame/test/test_quiche.py 1970-01-01 00:00:00 +0000 |
1601 | @@ -1,93 +0,0 @@ |
1602 | -from twisted.trial import unittest |
1603 | - |
1604 | -from imaginary import objects, iimaginary |
1605 | -from imaginary.test import commandutils |
1606 | - |
1607 | -from examplegame import quiche |
1608 | - |
1609 | - |
1610 | -class VendingTest(commandutils.CommandTestCaseMixin, unittest.TestCase): |
1611 | - def testTheyExist(self): |
1612 | - self._test("create the 'vending machine' named vendy", |
1613 | - ["You create vendy."], |
1614 | - ["Test Player creates vendy."]) |
1615 | - |
1616 | - |
1617 | - def testPopulateVendingMachine(self): |
1618 | - self._test("create the 'vending machine' named vendy", |
1619 | - ["You create vendy."], |
1620 | - ["Test Player creates vendy."]) |
1621 | - |
1622 | - self._test("create a quiche named quiche", |
1623 | - ["You create a quiche."], |
1624 | - ["Test Player creates a quiche."]) |
1625 | - |
1626 | - self._test("open vendy", |
1627 | - ["You open vendy."], |
1628 | - ["Test Player opens vendy."]) |
1629 | - |
1630 | - self._test("put quiche in vendy", |
1631 | - ["You put the quiche in vendy."], |
1632 | - ["Test Player puts a quiche in vendy."]) |
1633 | - |
1634 | - |
1635 | - def testBuyingQuiche(self): |
1636 | - self._test("create the 'vending machine' named vendy", |
1637 | - ["You create vendy."], |
1638 | - ["Test Player creates vendy."]) |
1639 | - |
1640 | - self._test("drop vendy", |
1641 | - ["You drop vendy."], |
1642 | - ["Test Player drops vendy."]) |
1643 | - |
1644 | - self._test("create a quiche named quiche", |
1645 | - ["You create a quiche."], |
1646 | - ["Test Player creates a quiche."]) |
1647 | - |
1648 | - self._test("open vendy", |
1649 | - ["You open vendy."], |
1650 | - ["Test Player opens vendy."]) |
1651 | - |
1652 | - self._test("put quiche in vendy", |
1653 | - ["You put the quiche in vendy."], |
1654 | - ["Test Player puts a quiche in vendy."]) |
1655 | - |
1656 | - for i in range(5): |
1657 | - self._test("create the quarter named quarter%s " % i, |
1658 | - ["You create quarter%s." % i], |
1659 | - ["Test Player creates quarter%s." % i]) |
1660 | - |
1661 | - for i in range(4): |
1662 | - self._test("put quarter%i in vendy" % i, |
1663 | - ["You put quarter%s in vendy." % i], |
1664 | - ["Test Player puts quarter%s in vendy." % i]) |
1665 | - |
1666 | - self._test("put quarter4 in vendy", |
1667 | - ["You put quarter4 in vendy.", |
1668 | - "Vendy thumps loudly and spits out a quiche onto the ground."], |
1669 | - ["Test Player puts quarter4 in vendy.", |
1670 | - "Vendy thumps loudly and spits out a quiche onto the ground."]) |
1671 | - |
1672 | - |
1673 | - def testProgrammaticQuichePurchase(self): |
1674 | - location = objects.Thing(store=self.store, name=u"room") |
1675 | - icloc = objects.Container.createFor(location, capacity=500) |
1676 | - |
1677 | - vm = quiche.createVendingMachine(store=self.store, name=u"Vendy", description=u"VEEEENDYYYYY") |
1678 | - vm.moveTo(location) |
1679 | - |
1680 | - icvm = iimaginary.IContainer(vm) |
1681 | - icvm.closed = False |
1682 | - theQuiche = quiche.createQuiche(store=self.store, name=u"quiche") |
1683 | - icvm.add(theQuiche) |
1684 | - icvm.closed = True |
1685 | - |
1686 | - for i in range(4): |
1687 | - quarter = quiche.createCoin(store=self.store, name=u"quarter%s" % (i,)) |
1688 | - icvm.add(quarter) |
1689 | - |
1690 | - quarter = quiche.createCoin(store=self.store, name=u"quarter4") |
1691 | - icvm.add(quarter) |
1692 | - |
1693 | - self.failUnless(icloc.contains(theQuiche)) |
1694 | - |
1695 | |
1696 | === removed file 'Imaginary/ExampleGame/examplegame/test/test_squeaky.py' |
1697 | --- Imaginary/ExampleGame/examplegame/test/test_squeaky.py 2009-08-17 02:40:03 +0000 |
1698 | +++ Imaginary/ExampleGame/examplegame/test/test_squeaky.py 1970-01-01 00:00:00 +0000 |
1699 | @@ -1,51 +0,0 @@ |
1700 | - |
1701 | -from twisted.trial.unittest import TestCase |
1702 | - |
1703 | -from imaginary.test.commandutils import CommandTestCaseMixin |
1704 | - |
1705 | -from imaginary.objects import Thing, Container |
1706 | - |
1707 | -from examplegame.squeaky import Squeaker |
1708 | - |
1709 | -class SqueakTest(CommandTestCaseMixin, TestCase): |
1710 | - """ |
1711 | - Squeak Test. |
1712 | - """ |
1713 | - |
1714 | - def setUp(self): |
1715 | - """ |
1716 | - Set Up. |
1717 | - """ |
1718 | - CommandTestCaseMixin.setUp(self) |
1719 | - self.squeaker = Thing(store=self.store, name=u"squeaker") |
1720 | - self.squeaker.moveTo(self.location) |
1721 | - self.squeakification = Squeaker.createFor(self.squeaker) |
1722 | - |
1723 | - |
1724 | - def test_itSqueaks(self): |
1725 | - """ |
1726 | - Picking up a squeaky thing makes it emit a squeak. |
1727 | - """ |
1728 | - self.assertCommandOutput( |
1729 | - "take squeaker", |
1730 | - ["You take a squeaker.", |
1731 | - "A squeaker emits a faint squeak."], |
1732 | - ["Test Player takes a squeaker.", |
1733 | - "A squeaker emits a faint squeak."]) |
1734 | - |
1735 | - |
1736 | - def test_squeakyContainer(self): |
1737 | - """ |
1738 | - If a container is squeaky, that shouldn't interfere with its function |
1739 | - as a container. (i.e. let's make sure that links keep working even |
1740 | - though we're using an annotator here.) |
1741 | - """ |
1742 | - cont = Container.createFor(self.squeaker) |
1743 | - |
1744 | - mcguffin = Thing(store=self.store, name=u"mcguffin") |
1745 | - mcguffin.moveTo(cont) |
1746 | - |
1747 | - self.assertCommandOutput( |
1748 | - "take mcguffin from squeaker", |
1749 | - ["You take a mcguffin from the squeaker."], |
1750 | - ["Test Player takes a mcguffin from the squeaker."]) |
1751 | |
1752 | === removed file 'Imaginary/ExampleGame/examplegame/test/test_tether.py' |
1753 | --- Imaginary/ExampleGame/examplegame/test/test_tether.py 2009-08-17 02:40:03 +0000 |
1754 | +++ Imaginary/ExampleGame/examplegame/test/test_tether.py 1970-01-01 00:00:00 +0000 |
1755 | @@ -1,96 +0,0 @@ |
1756 | - |
1757 | -from twisted.trial.unittest import TestCase |
1758 | - |
1759 | -from imaginary.test.commandutils import CommandTestCaseMixin, E |
1760 | - |
1761 | -from imaginary.objects import Thing, Container, Exit |
1762 | -from imaginary.garments import Garment |
1763 | - |
1764 | -from examplegame.furniture import Chair |
1765 | -from examplegame.tether import Tether |
1766 | - |
1767 | -class TetherTest(CommandTestCaseMixin, TestCase): |
1768 | - """ |
1769 | - A test for tethering an item to its location, such that a player who picks |
1770 | - it up can't leave until they drop it. |
1771 | - """ |
1772 | - |
1773 | - def setUp(self): |
1774 | - """ |
1775 | - Tether a ball to the room. |
1776 | - """ |
1777 | - CommandTestCaseMixin.setUp(self) |
1778 | - self.ball = Thing(store=self.store, name=u'ball') |
1779 | - self.ball.moveTo(self.location) |
1780 | - self.tether = Tether.createFor(self.ball, to=self.location) |
1781 | - self.otherPlace = Thing(store=self.store, name=u'elsewhere') |
1782 | - Container.createFor(self.otherPlace, capacity=1000) |
1783 | - Exit.link(self.location, self.otherPlace, u'north') |
1784 | - |
1785 | - |
1786 | - def test_takeAndLeave(self): |
1787 | - """ |
1788 | - You can't leave the room if you're holding the ball that's tied to it. |
1789 | - """ |
1790 | - self.assertCommandOutput( |
1791 | - "take ball", |
1792 | - ["You take a ball."], |
1793 | - ["Test Player takes a ball."]) |
1794 | - self.assertCommandOutput( |
1795 | - "go north", |
1796 | - ["You can't move, you're still holding a ball."], |
1797 | - ["Test Player struggles with a ball."]) |
1798 | - self.assertCommandOutput( |
1799 | - "drop ball", |
1800 | - ["You drop the ball."], |
1801 | - ["Test Player drops a ball."]) |
1802 | - self.assertCommandOutput( |
1803 | - "go north", |
1804 | - [E("[ elsewhere ]"), |
1805 | - E("( south )"), |
1806 | - ""], |
1807 | - ["Test Player leaves north."]) |
1808 | - |
1809 | - |
1810 | - def test_allTiedUp(self): |
1811 | - """ |
1812 | - If you're tied to a chair, you can't leave. |
1813 | - """ |
1814 | - chairThing = Thing(store=self.store, name=u'chair') |
1815 | - chairThing.moveTo(self.location) |
1816 | - chair = Chair.createFor(chairThing) |
1817 | - self.assertCommandOutput("sit chair", |
1818 | - ["You sit in the chair."], |
1819 | - ["Test Player sits in the chair."]) |
1820 | - Tether.createFor(self.player, to=chairThing) |
1821 | - self.assertCommandOutput( |
1822 | - "stand up", |
1823 | - ["You can't move, you're tied to a chair."], |
1824 | - ["Test Player struggles."]) |
1825 | - |
1826 | - |
1827 | - def test_tetheredClothing(self): |
1828 | - """ |
1829 | - Clothing that is tethered will also prevent movement if you wear it. |
1830 | - |
1831 | - This isn't just simply a test for clothing; it's an example of |
1832 | - integrating with a foreign system which doesn't know about tethering, |
1833 | - but can move objects itself. |
1834 | - |
1835 | - Tethering should I{not} have any custom logic related to clothing to |
1836 | - make this test pass; if it does get custom clothing code for some |
1837 | - reason, more tests should be added to deal with other systems that do |
1838 | - not take tethering into account (and vice versa). |
1839 | - """ |
1840 | - Garment.createFor(self.ball, garmentDescription=u"A lovely ball.", |
1841 | - garmentSlots=[u"head"]) |
1842 | - self.assertCommandOutput( |
1843 | - "wear ball", |
1844 | - ["You put on the ball."], |
1845 | - ["Test Player puts on a ball."]) |
1846 | - self.assertCommandOutput( |
1847 | - "go north", |
1848 | - ["You can't move, you're still holding a ball."], |
1849 | - ["Test Player struggles with a ball."]) |
1850 | - |
1851 | - |
1852 | |
1853 | === removed file 'Imaginary/ExampleGame/examplegame/tether.py' |
1854 | --- Imaginary/ExampleGame/examplegame/tether.py 2009-08-17 02:40:03 +0000 |
1855 | +++ Imaginary/ExampleGame/examplegame/tether.py 1970-01-01 00:00:00 +0000 |
1856 | @@ -1,121 +0,0 @@ |
1857 | -# -*- test-case-name: examplegame.test.test_tether -*- |
1858 | - |
1859 | -""" |
1860 | -A simplistic implementation of tethering, which demonstrates how to prevent |
1861 | -someone from moving around. |
1862 | - |
1863 | -This implementation is somewhat limited, as it assumes that tethered objects |
1864 | -can only be located in players' inventories and on the ground. It also makes |
1865 | -several assumptions about who is actually doing the moving in moveTo; in order |
1866 | -to be really correct, the implementation of movement needs to relay more |
1867 | -information about what is moving and how. |
1868 | -""" |
1869 | - |
1870 | -from zope.interface import implements |
1871 | - |
1872 | -from axiom.item import Item |
1873 | -from axiom.attributes import reference |
1874 | - |
1875 | -from imaginary.iimaginary import IMovementRestriction, IActor |
1876 | -from imaginary.eimaginary import ActionFailure |
1877 | -from imaginary.events import ThatDoesntWork |
1878 | -from imaginary.enhancement import Enhancement |
1879 | -from imaginary.objects import Thing |
1880 | - |
1881 | - |
1882 | -class Tether(Item, Enhancement): |
1883 | - """ |
1884 | - I am a force that binds two objects together. |
1885 | - |
1886 | - Right now this force isn't symmetric; the idea is that the thing that we |
1887 | - are tethered 'to' is immovable for some other reason. This is why we're in |
1888 | - the example rather than a real robust piece of game-library functionality |
1889 | - in imaginary proper. |
1890 | - |
1891 | - The C{thing} that we are installed on is prevented from moving more than a |
1892 | - certain distance away from the thing it is tethered C{to}. |
1893 | - |
1894 | - This is accomplished by preventing movement of the object's container; |
1895 | - i.e. if you pick up a ball that is tied to the ground, you can't move until |
1896 | - you drop it. |
1897 | - """ |
1898 | - |
1899 | - thing = reference(reftype=Thing, |
1900 | - whenDeleted=reference.CASCADE, |
1901 | - allowNone=False) |
1902 | - |
1903 | - # XXX 'thing' and 'to' should be treated more consistently, or at least the |
1904 | - # differences between them explained officially. |
1905 | - to = reference(reftype=Thing, |
1906 | - whenDeleted=reference.CASCADE, |
1907 | - allowNone=False) |
1908 | - |
1909 | - implements(IMovementRestriction) |
1910 | - |
1911 | - powerupInterfaces = [IMovementRestriction] |
1912 | - |
1913 | - def movementImminent(self, movee, destination): |
1914 | - """ |
1915 | - The object which is tethered is trying to move somewhere. If it has an |
1916 | - IActor, assume that it's a player trying to move on its own, and emit |
1917 | - an appropriate message. |
1918 | - |
1919 | - Otherwise, assume that it is moving *to* an actor, and install a |
1920 | - L{MovementBlocker} on that actor. |
1921 | - """ |
1922 | - # There isn't enough information provided to moveTo just yet; we need |
1923 | - # to know who is doing the moving. In the meanwhile, if you have an |
1924 | - # actor, we'll assume you're a player. |
1925 | - if IActor(movee, None) is not None: |
1926 | - raise ActionFailure( |
1927 | - ThatDoesntWork( |
1928 | - actor=self.thing, |
1929 | - actorMessage=[u"You can't move, you're tied to ", |
1930 | - self.to, |
1931 | - "."], |
1932 | - otherMessage=[self.thing, u' struggles.'])) |
1933 | - MovementBlocker.destroyFor(self.thing.location) |
1934 | - if self.to != destination: |
1935 | - MovementBlocker.createFor(destination, tether=self) |
1936 | - |
1937 | - return False |
1938 | - |
1939 | - |
1940 | -class MovementBlocker(Item, Enhancement): |
1941 | - """ |
1942 | - A L{MovementBlocker} is an L{Enhancement} which prevents the movement of a |
1943 | - player holding a tethered object. |
1944 | - """ |
1945 | - implements(IMovementRestriction) |
1946 | - |
1947 | - powerupInterfaces = [IMovementRestriction] |
1948 | - |
1949 | - thing = reference( |
1950 | - doc=""" |
1951 | - The L{Thing} whose movement is blocked. |
1952 | - """, reftype=Thing, allowNone=False, |
1953 | - whenDeleted=reference.CASCADE) |
1954 | - |
1955 | - tether = reference( |
1956 | - doc=""" |
1957 | - The L{Tether} ultimely responsible for blocking movement. |
1958 | - """, |
1959 | - reftype=Tether, allowNone=False, |
1960 | - whenDeleted=reference.CASCADE) |
1961 | - |
1962 | - |
1963 | - def movementImminent(self, movee, destination): |
1964 | - """ |
1965 | - The player this blocker is installed on is trying to move. Assume that |
1966 | - they are trying to move themselves (via a 'go' action) and prevent it |
1967 | - by raising an L{ActionFailure} with an appropriate error message for |
1968 | - the player. |
1969 | - """ |
1970 | - raise ActionFailure( |
1971 | - ThatDoesntWork( |
1972 | - actor=self.thing, |
1973 | - actorMessage= |
1974 | - [u"You can't move, you're still holding ", |
1975 | - self.tether.thing,u'.'], |
1976 | - otherMessage= |
1977 | - [self.thing, u' struggles with ', self.tether.thing,u'.'])) |
1978 | |
1979 | === removed directory 'Imaginary/ExampleGame/imaginary' |
1980 | === removed directory 'Imaginary/ExampleGame/imaginary/plugins' |
1981 | === removed file 'Imaginary/ExampleGame/imaginary/plugins/monsters.py' |
1982 | --- Imaginary/ExampleGame/imaginary/plugins/monsters.py 2007-08-17 04:46:38 +0000 |
1983 | +++ Imaginary/ExampleGame/imaginary/plugins/monsters.py 1970-01-01 00:00:00 +0000 |
1984 | @@ -1,6 +0,0 @@ |
1985 | - |
1986 | -from imaginary.creation import CreationPluginHelper |
1987 | -from examplegame.mice import createMouse, createHiraganaMouse |
1988 | - |
1989 | -mouse = CreationPluginHelper(u'mouse', createMouse) |
1990 | -hiraganaMouse = CreationPluginHelper(u'hiragana mouse', createHiraganaMouse) |
1991 | |
1992 | === removed file 'Imaginary/ExampleGame/imaginary/plugins/quiche.py' |
1993 | --- Imaginary/ExampleGame/imaginary/plugins/quiche.py 2007-08-17 04:46:38 +0000 |
1994 | +++ Imaginary/ExampleGame/imaginary/plugins/quiche.py 1970-01-01 00:00:00 +0000 |
1995 | @@ -1,9 +0,0 @@ |
1996 | -# -*- test-case-name: examplegame.test.test_vending -*- |
1997 | - |
1998 | -from imaginary.creation import CreationPluginHelper |
1999 | -from examplegame.quiche import createQuiche, createCoin, createVendingMachine |
2000 | - |
2001 | -quichePlugin = CreationPluginHelper('quiche', createQuiche) |
2002 | -vendingPlugin = CreationPluginHelper('vending machine', createVendingMachine) |
2003 | -quarterPlugin = CreationPluginHelper('quarter', createCoin) |
2004 | - |
2005 | |
2006 | === removed file 'Imaginary/LICENSE' |
2007 | --- Imaginary/LICENSE 2006-02-26 02:37:39 +0000 |
2008 | +++ Imaginary/LICENSE 1970-01-01 00:00:00 +0000 |
2009 | @@ -1,20 +0,0 @@ |
2010 | -Copyright (c) 2005 Divmod Inc. |
2011 | - |
2012 | -Permission is hereby granted, free of charge, to any person obtaining |
2013 | -a copy of this software and associated documentation files (the |
2014 | -"Software"), to deal in the Software without restriction, including |
2015 | -without limitation the rights to use, copy, modify, merge, publish, |
2016 | -distribute, sublicense, and/or sell copies of the Software, and to |
2017 | -permit persons to whom the Software is furnished to do so, subject to |
2018 | -the following conditions: |
2019 | - |
2020 | -The above copyright notice and this permission notice shall be |
2021 | -included in all copies or substantial portions of the Software. |
2022 | - |
2023 | -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
2024 | -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
2025 | -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
2026 | -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE |
2027 | -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION |
2028 | -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION |
2029 | -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
2030 | |
2031 | === removed file 'Imaginary/MANIFEST.in' |
2032 | --- Imaginary/MANIFEST.in 2008-07-16 19:12:33 +0000 |
2033 | +++ Imaginary/MANIFEST.in 1970-01-01 00:00:00 +0000 |
2034 | @@ -1,6 +0,0 @@ |
2035 | -include NAME.txt |
2036 | -include DEPS.txt |
2037 | -include NEWS.txt |
2038 | -include LICENSE |
2039 | -graft imaginary |
2040 | -graft axiom |
2041 | |
2042 | === removed file 'Imaginary/NAME.txt' |
2043 | --- Imaginary/NAME.txt 2006-02-26 02:37:39 +0000 |
2044 | +++ Imaginary/NAME.txt 1970-01-01 00:00:00 +0000 |
2045 | @@ -1,10 +0,0 @@ |
2046 | - |
2047 | -See: http://achewood.com/index.php?date=04272005 |
2048 | - |
2049 | -Imaginary numbers are so named not because they are fictitious, but because |
2050 | -they are along a different axis from real numbers. |
2051 | - |
2052 | -Divmod Imaginary is a simulationists take on the realm of role playing, |
2053 | -interactive fiction, and multiplayer dungeons. It incorporates gameplay |
2054 | -features from each area while attempting to provide a richer environment |
2055 | -than is generally available from existing systems. |
2056 | |
2057 | === removed file 'Imaginary/NEWS.txt' |
2058 | --- Imaginary/NEWS.txt 2009-11-30 01:08:55 +0000 |
2059 | +++ Imaginary/NEWS.txt 1970-01-01 00:00:00 +0000 |
2060 | @@ -1,36 +0,0 @@ |
2061 | -0.0.5 (2009-11-25): |
2062 | - - Remove the dead imaginary.objects.Thing.locate method |
2063 | - - Introduce an interface intended to be provided by administrative actors |
2064 | - and require it for the "illuminate" command. |
2065 | - - Remove the custom SSH server and instead plug in to the Mantissa SSH |
2066 | - application server. |
2067 | - - Remove all uses of "axiom.dependency.installOn". |
2068 | - - Fix a bug which caused newly created avatars to not be announced when |
2069 | - they arrived at the starting location. |
2070 | - - When presenting an ambiguity error to an actor, enumerate the possible |
2071 | - resolutions. |
2072 | - - Fix certain terminal handling issues with east asian characters. |
2073 | - |
2074 | -0.0.4 (2008-08-12): |
2075 | - |
2076 | - - A "plain" Thing type has now been added and is available to the |
2077 | - "create" command. |
2078 | - - "scrutinize" now works when the target is not a container. |
2079 | - - a "list thing types" command has been added, to allow viewing |
2080 | - types of things that can be created. |
2081 | - - "create" now allows users to specify if a thing is considered a |
2082 | - common or proper noun. |
2083 | - - Improved grammar in action text for various verbs. |
2084 | - - Added a "set" action for changing thing attributes. |
2085 | - - Changed noun resolution to match substrings and to match |
2086 | - case-insensitively. |
2087 | - |
2088 | -0.0.3 (2007-01-23): |
2089 | - - Work with Axiom dependency api |
2090 | - |
2091 | -0.0.2 (2006-09-20): |
2092 | - - Some changes |
2093 | - |
2094 | -0.0.1 (2006-06-16): |
2095 | - - Imported from Pottery repository |
2096 | - - Imported from Imagination repository |
2097 | |
2098 | === removed file 'Imaginary/README.txt' |
2099 | --- Imaginary/README.txt 2009-06-26 20:38:23 +0000 |
2100 | +++ Imaginary/README.txt 1970-01-01 00:00:00 +0000 |
2101 | @@ -1,98 +0,0 @@ |
2102 | - |
2103 | -Imaginary is an experimental simulation-construction toolkit. |
2104 | - |
2105 | -Be warned! We aren't kidding when we say "experimental". Many features are |
2106 | -not implemented yet and documentation is incomplete. We think there are some |
2107 | -pretty cool ideas here, but if you are intending to use this system, be |
2108 | -prepared to participate heavily in its development. |
2109 | - |
2110 | -This document is mainly concerned with getting an Imaginary server up and |
2111 | -running, to the point where you can edit the code and see things change. Some |
2112 | -familiarity with Python, Twisted, Nevow, Axiom, and Mantissa are all helpful, |
2113 | -but we will try to make sure they aren't really required just to get started. |
2114 | - |
2115 | -While we have tried to make it possible to get a taste of what is possible |
2116 | -here, if you want to make any serious progress, you will want to join the IRC |
2117 | -channel "#imagination" on chat.freenode.net and start asking questions. If you |
2118 | -are curious about what needs to be done, have a look here: |
2119 | - |
2120 | - http://tinyurl.com/2tuo9o |
2121 | - |
2122 | -The first step in configuring a new installation of Imaginary will normally be |
2123 | -creating a new Mantissa database. |
2124 | - |
2125 | -(This is assuming you have already set up Combinator, installed Twisted, and |
2126 | -all necessary Divmod dependencies. If not, see |
2127 | -http://divmod.org/trac/wiki/CombinatorTutorial for more information.) |
2128 | - |
2129 | -First run the following command: |
2130 | - |
2131 | - axiomatic mantissa |
2132 | - |
2133 | -And answer the prompts appropriately. Please take note of the new password you |
2134 | -enter for the "admin" user, as you will need it in a few steps. |
2135 | - |
2136 | -This should create a directory called "mantissa.axiom", containing the server |
2137 | -for a web interface that will allow you to install "offerings" (plugins for |
2138 | -Mantissa, in this case, Imaginary), create users, and grant them |
2139 | -privileges. You can start this webserver with the following command: (the -n |
2140 | -option will run it in the foreground on the current terminal) |
2141 | - |
2142 | - axiomatic start -n |
2143 | - |
2144 | -You should now be able to access this server at http://localhost:8080 in your |
2145 | -web browser. |
2146 | - |
2147 | -Click the "Sign In" link in the upper right hand corner, and log in as "admin" |
2148 | -with the password you chose previously while configuring Mantissa. |
2149 | - |
2150 | -If you logged in successfully, you should now be presented with a list of |
2151 | -"offerings" that can be installed. Click on "Imaginary" to install it. |
2152 | - |
2153 | -Next, mouse over the "Admin" menu at the upper left of the screen and then |
2154 | -click on the "Products" sub-menu. |
2155 | - |
2156 | -In the "Installable Powerups" section, check the box corresponding to |
2157 | -"Imaginary Game". Then click the "Installable Powerups" button below. You |
2158 | -will hopefully be presented with a green confirmation dialog to confirm your |
2159 | -success. This creates a "product" which can be given to users. |
2160 | - |
2161 | -Mouse over the "Admin" menu again and click "Local Users". You should be |
2162 | -presented with a page including a table of users - probably with only the |
2163 | -"admin" user in it. Click the word "Endow" in the "Actions" column of that |
2164 | -table, then select the product with "ImaginaryApp" in it (again, this is |
2165 | -probably the only one presented) and click the "Installproducton |
2166 | -admin@localhost" button. You should again be presented with a green |
2167 | -confirmation dialog. Hooray! |
2168 | - |
2169 | -Ideally, you will now be able to ssh into your Imaginary server. In a new |
2170 | -terminal, ssh to localhost on the Mantissa server's SSH port (by default, this |
2171 | -is 8022). For example: |
2172 | - |
2173 | - ssh -p 8022 admin@localhost@localhost |
2174 | - |
2175 | -Note the odd username/host specifier - "admin@localhost" is the user, and the |
2176 | -last "localhost" specifies the host to connect to. |
2177 | - |
2178 | -Log in with the same password you used to log in to the web interface. You |
2179 | -should be presented with a screen including several options, one of which is |
2180 | -"imaginary". Use tab to highlight that option (the highlighted option should |
2181 | -appear red), then hit enter to select it. |
2182 | - |
2183 | -At the Imaginary character prompt, choose to create a new character; enter a |
2184 | -new username (e.g. not "admin"). You will then join the game as that new |
2185 | -character. |
2186 | - |
2187 | -Once in the game, you should see a row of dashes along the bottom of the |
2188 | -display. To confirm your new MUDness, try typing "look" and hit enter; You |
2189 | -should see some indication of the generic place that you are in, the available |
2190 | -exits, and other players in the area, though initially you won't see much more |
2191 | -than "[The Place]". |
2192 | - |
2193 | -You can enter "actions" for a list of actions, and use "help" along with one of |
2194 | -them ("help dig") for specific information on how to use them. You can even log |
2195 | -in via other telnet windows, create additional accounts, and interact with your |
2196 | -initial user (for example, beating them to death with "hit"). |
2197 | - |
2198 | -When you've tired of self-abuse, you can stop your Imaginary server by hitting |
2199 | -control-c in the terminal where you ran "axiomatic start -n". |
2200 | |
2201 | === removed directory 'Imaginary/axiom' |
2202 | === removed directory 'Imaginary/axiom/plugins' |
2203 | === removed file 'Imaginary/axiom/plugins/imaginaryversion.py' |
2204 | --- Imaginary/axiom/plugins/imaginaryversion.py 2008-07-16 19:12:33 +0000 |
2205 | +++ Imaginary/axiom/plugins/imaginaryversion.py 1970-01-01 00:00:00 +0000 |
2206 | @@ -1,12 +0,0 @@ |
2207 | -# Copyright 2008 Divmod, Inc. |
2208 | -# See LICENSE file for details |
2209 | - |
2210 | -""" |
2211 | -Register an Axiom version plugin for Imaginary. |
2212 | -""" |
2213 | - |
2214 | -from zope.interface import directlyProvides |
2215 | -from twisted.plugin import IPlugin |
2216 | -from axiom.iaxiom import IVersion |
2217 | -from imaginary import version |
2218 | -directlyProvides(version, IPlugin, IVersion) |
2219 | |
2220 | === removed directory 'Imaginary/imaginary' |
2221 | === removed file 'Imaginary/imaginary/__init__.py' |
2222 | --- Imaginary/imaginary/__init__.py 2009-06-29 04:03:17 +0000 |
2223 | +++ Imaginary/imaginary/__init__.py 1970-01-01 00:00:00 +0000 |
2224 | @@ -1,19 +0,0 @@ |
2225 | -# -*- test-case-name: imaginary,examplegame -*- |
2226 | - |
2227 | -""" |
2228 | -Virtual simulation framework. |
2229 | -""" |
2230 | - |
2231 | -from imaginary._version import version |
2232 | -version # exported |
2233 | - |
2234 | -# Verbs are only registered when they are imported, and important verbs are |
2235 | -# found in the following modules: |
2236 | -from imaginary import action, creation |
2237 | -action # exported |
2238 | -creation # exported |
2239 | - |
2240 | - |
2241 | -# Ideally there would be a nice, passive way to register verbs which would only |
2242 | -# load them as necessary rather than forcing the entire package to get |
2243 | -# imported, but this will work okay for now. |
2244 | |
2245 | === removed file 'Imaginary/imaginary/_version.py' |
2246 | --- Imaginary/imaginary/_version.py 2009-11-30 01:08:55 +0000 |
2247 | +++ Imaginary/imaginary/_version.py 1970-01-01 00:00:00 +0000 |
2248 | @@ -1,3 +0,0 @@ |
2249 | -# This is an auto-generated file. Use Epsilon/bin/release-divmod to update. |
2250 | -from twisted.python import versions |
2251 | -version = versions.Version(__name__[:__name__.rfind('.')], 0, 0, 5) |
2252 | |
2253 | === removed file 'Imaginary/imaginary/action.py' |
2254 | --- Imaginary/imaginary/action.py 2013-09-22 10:01:56 +0000 |
2255 | +++ Imaginary/imaginary/action.py 1970-01-01 00:00:00 +0000 |
2256 | @@ -1,1299 +0,0 @@ |
2257 | -# -*- test-case-name: imaginary.test.test_actions -*- |
2258 | - |
2259 | -import time, random, operator |
2260 | -import pprint |
2261 | - |
2262 | -from zope.interface import implements |
2263 | - |
2264 | -from twisted.python import log, filepath |
2265 | -from twisted.internet import defer |
2266 | - |
2267 | -from axiom import iaxiom |
2268 | -from axiom.attributes import AND |
2269 | - |
2270 | -import imaginary.plugins |
2271 | -from imaginary import (iimaginary, eimaginary, iterutils, events, |
2272 | - objects, text as T, language, pyparsing) |
2273 | -from imaginary.world import ImaginaryWorld |
2274 | -from imaginary.idea import ( |
2275 | - CanSee, Proximity, ProviderOf, Named, Traversability) |
2276 | - |
2277 | -## Hacks because pyparsing doesn't have fantastic unicode support |
2278 | -_quoteRemovingQuotedString = pyparsing.quotedString.copy() |
2279 | -_quoteRemovingQuotedString.setParseAction(pyparsing.removeQuotes) |
2280 | - |
2281 | -class UnicodeWord(pyparsing.Token): |
2282 | - def parseImpl(self, instring, loc, doActions=True): |
2283 | - maxLoc = len(instring) |
2284 | - while loc < maxLoc and instring[loc].isspace(): |
2285 | - loc += 1 |
2286 | - start = loc |
2287 | - while loc < maxLoc and not instring[loc].isspace(): |
2288 | - loc += 1 |
2289 | - end = loc |
2290 | - return end, instring[start:end] |
2291 | - |
2292 | - |
2293 | - |
2294 | -class _ActionType(type): |
2295 | - actions = [] |
2296 | - def __new__(cls, name, bases, attrs): |
2297 | - infrastructure = attrs.pop('infrastructure', False) |
2298 | - t = super(_ActionType, cls).__new__(cls, name, bases, attrs) |
2299 | - if not infrastructure: |
2300 | - cls.actions.append(t) |
2301 | - return t |
2302 | - |
2303 | - |
2304 | - def parse(self, player, line): |
2305 | - """ |
2306 | - Parse an action. |
2307 | - """ |
2308 | - for eachActionType in self.actions: |
2309 | - try: |
2310 | - match = eachActionType.match(player, line) |
2311 | - except pyparsing.ParseException: |
2312 | - pass |
2313 | - else: |
2314 | - if match is not None: |
2315 | - match = dict(match) |
2316 | - for k,v in match.items(): |
2317 | - if isinstance(v, pyparsing.ParseResults): |
2318 | - match[k] = v[0] |
2319 | - |
2320 | - return eachActionType().runEventTransaction(player, line, match) |
2321 | - return defer.fail(eimaginary.NoSuchCommand(line)) |
2322 | - |
2323 | - |
2324 | - |
2325 | -class Action(object): |
2326 | - """ |
2327 | - An L{Action} represents an intention of a player to do something. |
2328 | - """ |
2329 | - __metaclass__ = _ActionType |
2330 | - infrastructure = True |
2331 | - |
2332 | - actorInterface = iimaginary.IActor |
2333 | - |
2334 | - def runEventTransaction(self, player, line, match): |
2335 | - """ |
2336 | - Take a player, input, and dictionary of parse results, resolve those |
2337 | - parse results into implementations of appropriate interfaces in the |
2338 | - game world, and execute the actual Action implementation (contained in |
2339 | - the 'do' method) in an event transaction. |
2340 | - |
2341 | - This is the top level of action invocation. |
2342 | - |
2343 | - @param player: A L{Thing} representing the actor's body. |
2344 | - |
2345 | - @param line: A unicode string containing the original input |
2346 | - |
2347 | - @param match: A dictionary containing some parse results to pass |
2348 | - through to this L{Action}'s C{do} method as keyword arguments. |
2349 | - |
2350 | - @raise eimaginary.AmbiguousArgument: if multiple valid targets are |
2351 | - found for an argument. |
2352 | - """ |
2353 | - def thunk(): |
2354 | - begin = time.time() |
2355 | - try: |
2356 | - actor = self.actorInterface(player) |
2357 | - for (k, v) in match.items(): |
2358 | - try: |
2359 | - objs = self.resolve(player, k, v) |
2360 | - except NotImplementedError: |
2361 | - pass |
2362 | - else: |
2363 | - if len(objs) == 1: |
2364 | - match[k] = objs[0] |
2365 | - elif len(objs) == 0: |
2366 | - self.cantFind(player, actor, k, v) |
2367 | - else: |
2368 | - raise eimaginary.AmbiguousArgument(self, k, v, objs) |
2369 | - return self.do(actor, line, **match) |
2370 | - finally: |
2371 | - end = time.time() |
2372 | - log.msg(interface=iaxiom.IStatEvent, |
2373 | - stat_actionDuration=end - begin, |
2374 | - stat_actionExecuted=1) |
2375 | - events.runEventTransaction(player.store, thunk) |
2376 | - |
2377 | - |
2378 | - def cantFind(self, player, actor, slot, name): |
2379 | - """ |
2380 | - This hook is invoked when a target cannot be found. |
2381 | - |
2382 | - This will delegate to a method like C{self.cantFind_<slot>(actor, |
2383 | - name)} if one exists, to determine the error message to show to the |
2384 | - actor. It will then raise L{eimaginary.ActionFailure} to stop |
2385 | - processing of this action. |
2386 | - |
2387 | - @param player: The L{Thing} doing the searching. |
2388 | - |
2389 | - @type player: L{IThing} |
2390 | - |
2391 | - @param actor: The L{IActor} doing the searching. |
2392 | - |
2393 | - @type actor: L{IActor} |
2394 | - |
2395 | - @param slot: The slot in question. |
2396 | - |
2397 | - @type slot: C{str} |
2398 | - |
2399 | - @param name: The name of the object being searched for. |
2400 | - |
2401 | - @type name: C{unicode} |
2402 | - |
2403 | - @raise eimaginary.ActionFailure: always. |
2404 | - """ |
2405 | - func = getattr(self, "cantFind_"+slot, None) |
2406 | - if func: |
2407 | - msg = func(actor, name) |
2408 | - else: |
2409 | - msg = "Who's that?" |
2410 | - raise eimaginary.ActionFailure( |
2411 | - events.ThatDoesntWork( |
2412 | - actorMessage=msg, |
2413 | - actor=player)) |
2414 | - |
2415 | - |
2416 | - @classmethod |
2417 | - def match(cls, player, line): |
2418 | - """ |
2419 | - Parse the given C{line} using this L{Action} type's pyparsing C{expr} |
2420 | - attribute. A C{pyparsing.LineEnd} is appended to C{expr} to avoid |
2421 | - accidentally matching a prefix instead of the whole line. |
2422 | - |
2423 | - @return: a list of 2-tuples of all the results of parsing, or None if |
2424 | - the expression does not match the given line. |
2425 | - |
2426 | - @param line: a line of user input to be interpreted as an action. |
2427 | - |
2428 | - @see: L{imaginary.pyparsing} |
2429 | - """ |
2430 | - return (cls.expr + pyparsing.LineEnd()).parseString(line) |
2431 | - |
2432 | - |
2433 | - def do(self, player, line, **slots): |
2434 | - """ |
2435 | - Subclasses override this method to actually perform the action. |
2436 | - |
2437 | - This method is performed in an event transaction, by 'run'. |
2438 | - |
2439 | - NB: The suggested implementation strategy for a 'do' method is to do |
2440 | - action-specific setup but then delegate the bulk of the actual logic to |
2441 | - a method on a target/tool interface. The 'do' method's job is to |
2442 | - select the appropriate methods to invoke. |
2443 | - |
2444 | - @param player: a provider of this L{Action}'s C{actorInterface}. |
2445 | - |
2446 | - @param line: the input string that created this action. |
2447 | - |
2448 | - @param slots: The results of calling C{self.resolve} on each parsing |
2449 | - result (described by a setResultsName in C{self.expr}). |
2450 | - """ |
2451 | - raise NotImplementedError("'do' method not implemented") |
2452 | - |
2453 | - |
2454 | - def resolve(self, player, name, value): |
2455 | - """ |
2456 | - Resolve a given parsed value to a valid action parameter by calling a |
2457 | - 'resolve_<name>' method on this L{Action} with the given C{player} and |
2458 | - C{value}. |
2459 | - |
2460 | - @param player: the L{Thing} attempting to perform this action. |
2461 | - |
2462 | - @type player: L{Thing} |
2463 | - |
2464 | - @param name: the name of the slot being filled. For example, 'target'. |
2465 | - |
2466 | - @type name: L{str} |
2467 | - |
2468 | - @param value: a string representing the value that was parsed. For |
2469 | - example, if the user typed 'get fish', this would be 'fish'. |
2470 | - |
2471 | - @return: a value which will be passed as the 'name' parameter to this |
2472 | - L{Action}'s C{do} method. |
2473 | - """ |
2474 | - resolver = getattr(self, 'resolve_%s' % (name,), None) |
2475 | - if resolver is None: |
2476 | - raise NotImplementedError( |
2477 | - "Don't know how to resolve %r (%r)" % (name, value)) |
2478 | - return resolver(player, value) |
2479 | - |
2480 | - |
2481 | - |
2482 | -def targetString(name): |
2483 | - return ( |
2484 | - _quoteRemovingQuotedString ^ |
2485 | - UnicodeWord()).setResultsName(name) |
2486 | - |
2487 | - |
2488 | - |
2489 | -class TargetAction(Action): |
2490 | - """ |
2491 | - Subclass L{TargetAction} to implement an action that acts on a target, like |
2492 | - 'take foo' or 'eat foo' where 'foo' is the target. |
2493 | - |
2494 | - @cvar targetInterface: the interface which the 'target' parameter to 'do' |
2495 | - must provide. |
2496 | - """ |
2497 | - |
2498 | - infrastructure = True |
2499 | - |
2500 | - targetInterface = iimaginary.IThing |
2501 | - |
2502 | - def targetRadius(self, player): |
2503 | - return 2 |
2504 | - |
2505 | - def resolve_target(self, player, targetName): |
2506 | - return _getIt(player, targetName, |
2507 | - self.targetInterface, self.targetRadius(player)) |
2508 | - |
2509 | - |
2510 | - |
2511 | -class ToolAction(TargetAction): |
2512 | - """ |
2513 | - Subclass L{ToolAction} to implement an action that acts on a target by |
2514 | - using a tool, like 'unlock door with key', where 'door' is the target and |
2515 | - 'key' is the tool. |
2516 | - |
2517 | - @cvar toolInterface: the L{zope.interface.Interface} which the 'tool' |
2518 | - parameter to 'do' must provide. |
2519 | - """ |
2520 | - infrastructure = True |
2521 | - |
2522 | - toolInterface = iimaginary.IThing |
2523 | - |
2524 | - def toolRadius(self, player): |
2525 | - return 2 |
2526 | - |
2527 | - def resolve_tool(self, player, toolName): |
2528 | - return _getIt(player, toolName, |
2529 | - self.toolInterface, self.toolRadius(player)) |
2530 | - |
2531 | - |
2532 | - |
2533 | -def _getIt(player, thingName, iface, radius): |
2534 | - return list(player.search(radius, iface, thingName)) |
2535 | - |
2536 | - |
2537 | - |
2538 | -class LookAround(Action): |
2539 | - actionName = "look" |
2540 | - expr = pyparsing.Literal("look") + pyparsing.StringEnd() |
2541 | - |
2542 | - def do(self, player, line): |
2543 | - ultimateLocation = player.thing.location |
2544 | - while ultimateLocation.location is not None: |
2545 | - ultimateLocation = ultimateLocation.location |
2546 | - for visible in player.thing.findProviders(iimaginary.IVisible, 1): |
2547 | - # XXX what if my location is furniture? I want to see '( Foo, |
2548 | - # sitting in the Bar )', not '( Bar )'. |
2549 | - if visible.isViewOf(ultimateLocation): |
2550 | - concept = visible.visualize() |
2551 | - break |
2552 | - else: |
2553 | - concept = u"You are floating in an empty, formless void." |
2554 | - events.Success(actor=player.thing, |
2555 | - actorMessage=concept).broadcast() |
2556 | - |
2557 | - |
2558 | - |
2559 | -class LookAt(TargetAction): |
2560 | - actionName = "look" |
2561 | - expr = (pyparsing.Literal("look") + |
2562 | - pyparsing.Optional(pyparsing.White() + |
2563 | - pyparsing.Literal("at")) + |
2564 | - pyparsing.White() + |
2565 | - pyparsing.restOfLine.setResultsName("target")) |
2566 | - |
2567 | - targetInterface = iimaginary.IVisible |
2568 | - |
2569 | - def resolve_target(self, player, targetName): |
2570 | - """ |
2571 | - Resolve the target to look at by looking for a named, visible object in |
2572 | - a proximity of 3 meters from the player. |
2573 | - |
2574 | - @param player: The player doing the looking. |
2575 | - |
2576 | - @type player: L{IThing} |
2577 | - |
2578 | - @param targetName: The name of the object we are looking for. |
2579 | - |
2580 | - @type targetName: C{unicode} |
2581 | - |
2582 | - @return: A list of visible objects. |
2583 | - |
2584 | - @rtype: C{list} of L{IVisible} |
2585 | - |
2586 | - @raise eimaginary.ActionFailure: with an appropriate message if the |
2587 | - target cannot be resolved for an identifiable reason. See |
2588 | - L{imaginary.objects.Thing.obtainOrReportWhyNot} for a description |
2589 | - of how such reasons may be identified. |
2590 | - """ |
2591 | - return player.obtainOrReportWhyNot( |
2592 | - Proximity(3.0, Named(targetName, |
2593 | - CanSee(ProviderOf(iimaginary.IVisible)), |
2594 | - player))) |
2595 | - |
2596 | - |
2597 | - def cantFind_target(self, player, name): |
2598 | - return "You don't see that." |
2599 | - |
2600 | - def targetRadius(self, player): |
2601 | - return 3 |
2602 | - |
2603 | - def do(self, player, line, target): |
2604 | - if player.thing is not target: |
2605 | - evt = events.Success( |
2606 | - actor=player.thing, |
2607 | - target=target, |
2608 | - actorMessage=target.visualize(), |
2609 | - targetMessage=(player.thing, " looks at you.")) |
2610 | - else: |
2611 | - evt = events.Success( |
2612 | - actor=player.thing, |
2613 | - actorMessage=target.visualize()) |
2614 | - evt.broadcast() |
2615 | - |
2616 | - |
2617 | - |
2618 | -class Illuminate(Action): |
2619 | - """ |
2620 | - Change the ambient light level at the location of the actor. Since this is |
2621 | - an administrative action that directly manipulates the environment, the |
2622 | - actor must be a L{iimaginary.IManipulator}. |
2623 | - |
2624 | - The argument taken by this action is an integer which specifies the light |
2625 | - level in U{candelas<http://en.wikipedia.org/wiki/Candela>}. |
2626 | - """ |
2627 | - |
2628 | - actorInterface = iimaginary.IManipulator |
2629 | - |
2630 | - expr = (pyparsing.Literal("illuminate") + |
2631 | - pyparsing.White() + |
2632 | - pyparsing.Word("0123456789").setResultsName("candelas")) |
2633 | - |
2634 | - |
2635 | - def do(self, player, line, candelas): |
2636 | - """ |
2637 | - Attempt to change the illumination of the player's surroundings. |
2638 | - |
2639 | - @param player: a manipulator that can change the illumination of its |
2640 | - room. |
2641 | - @type player: L{IManipulator} |
2642 | - |
2643 | - @param line: the text being parsed |
2644 | - @type line: L{str} |
2645 | - |
2646 | - @param candelas: the number of candelas to change the ambient |
2647 | - illumination to. |
2648 | - @type candelas: L{str} |
2649 | - """ |
2650 | - candelas = int(candelas) |
2651 | - oldCandelas = player.setIllumination(candelas) |
2652 | - otherMessage = None |
2653 | - if oldCandelas == candelas: |
2654 | - actorMessage = u"You do it. Swell." |
2655 | - elif candelas == 0: |
2656 | - actorMessage = ( |
2657 | - u"Your environs fade to black due to Ineffable Spooky Magic.") |
2658 | - otherMessage = actorMessage |
2659 | - elif oldCandelas == 0: |
2660 | - actorMessage = u"Your environs are suddenly alight." |
2661 | - otherMessage = actorMessage |
2662 | - elif candelas < oldCandelas: |
2663 | - actorMessage = u"Your environs seem slightly dimmer." |
2664 | - otherMessage = actorMessage |
2665 | - elif candelas > oldCandelas: |
2666 | - actorMessage = u"Your environs seem slightly brighter." |
2667 | - otherMessage = actorMessage |
2668 | - events.Success(actor=player.thing, |
2669 | - actorMessage=actorMessage, |
2670 | - otherMessage=otherMessage).broadcast() |
2671 | - |
2672 | - |
2673 | - |
2674 | -class Describe(TargetAction): |
2675 | - expr = (pyparsing.Literal("describe") + |
2676 | - pyparsing.White() + |
2677 | - targetString("target") + |
2678 | - pyparsing.White() + |
2679 | - pyparsing.restOfLine.setResultsName("description")) |
2680 | - |
2681 | - def targetRadius(self, player): |
2682 | - return 3 |
2683 | - |
2684 | - def do(self, player, line, target, description): |
2685 | - target.description = description |
2686 | - evt = events.Success( |
2687 | - actor=player.thing, |
2688 | - actorMessage=("You change ", target, "'s description."), |
2689 | - otherMessage=(player.thing, " changes ", target, "'s description.")) |
2690 | - evt.broadcast() |
2691 | - |
2692 | - |
2693 | -class Name(TargetAction): |
2694 | - expr = (pyparsing.Literal("name") + |
2695 | - pyparsing.White() + |
2696 | - targetString("target") + |
2697 | - pyparsing.White() + |
2698 | - pyparsing.restOfLine.setResultsName("name")) |
2699 | - |
2700 | - def targetRadius(self, player): |
2701 | - return 3 |
2702 | - |
2703 | - def do(self, player, line, target, name): |
2704 | - evt = events.Success( |
2705 | - actor=player.thing, |
2706 | - actorMessage=("You change ", target, "'s name."), |
2707 | - otherMessage=language.Sentence([player.thing, " changes ", target, "'s name to ", name, "."])) |
2708 | - evt.broadcast() |
2709 | - target.name = name |
2710 | - |
2711 | - |
2712 | - |
2713 | -class Open(TargetAction): |
2714 | - expr = (pyparsing.Literal("open") + |
2715 | - pyparsing.White() + |
2716 | - targetString("target")) |
2717 | - |
2718 | - targetInterface = iimaginary.IContainer |
2719 | - |
2720 | - def do(self, player, line, target): |
2721 | - dnf = language.Noun(target.thing).definiteNounPhrase() |
2722 | - if not target.closed: |
2723 | - raise eimaginary.ActionFailure(events.ThatDoesntWork( |
2724 | - actor=player.thing, |
2725 | - target=target.thing, |
2726 | - actorMessage=language.Sentence([dnf, " is already open."]))) |
2727 | - |
2728 | - target.closed = False |
2729 | - evt = events.Success( |
2730 | - actor=player.thing, |
2731 | - target=target.thing, |
2732 | - actorMessage=("You open ", dnf, "."), |
2733 | - targetMessage=language.Sentence([player.thing, " opens you."]), |
2734 | - otherMessage=language.Sentence([player.thing, " opens ", target.thing, "."])) |
2735 | - evt.broadcast() |
2736 | - |
2737 | - |
2738 | - |
2739 | -class Close(TargetAction): |
2740 | - expr = (pyparsing.Literal("close") + |
2741 | - pyparsing.White() + |
2742 | - targetString("target")) |
2743 | - |
2744 | - targetInterface = iimaginary.IContainer |
2745 | - |
2746 | - def do(self, player, line, target): |
2747 | - dnf = language.Noun(target.thing).definiteNounPhrase() |
2748 | - if target.closed: |
2749 | - raise eimaginary.ActionFailure(events.ThatDoesntWork( |
2750 | - actor=player.thing, |
2751 | - target=target.thing, |
2752 | - actorMessage=language.Sentence([dnf, " is already closed."]))) |
2753 | - |
2754 | - target.closed = True |
2755 | - evt = events.Success( |
2756 | - actor=player.thing, |
2757 | - target=target.thing, |
2758 | - actorMessage=("You close ", dnf, "."), |
2759 | - targetMessage=language.Sentence([player.thing, " closes you."]), |
2760 | - otherMessage=language.Sentence([player.thing, " closes ", target.thing, "."])) |
2761 | - evt.broadcast() |
2762 | - |
2763 | - |
2764 | - |
2765 | -def tooHeavy(player, target): |
2766 | - return eimaginary.ActionFailure(events.ThatDoesntWork( |
2767 | - actor=player, target=target, |
2768 | - actorMessage=(target, " is too heavy to pick up."), |
2769 | - otherMessage=(player, " struggles to lift ", target, ", but fails."), |
2770 | - targetMessage=(player, " tries to pick you up, but fails."))) |
2771 | - |
2772 | - |
2773 | - |
2774 | -def targetTaken(player, target, container=None): |
2775 | - if container is None: |
2776 | - return events.Success( |
2777 | - actor=player, target=target, |
2778 | - actorMessage=("You take ", target, "."), |
2779 | - targetMessage=(player, " takes you."), |
2780 | - otherMessage=(player, " takes ", target, ".")) |
2781 | - idop = language.Noun(container).definiteNounPhrase() |
2782 | - return events.Success( |
2783 | - actor=player, |
2784 | - target=target, |
2785 | - tool=container, |
2786 | - actorMessage=("You take ", target, " from ", idop, "."), |
2787 | - targetMessage=(player, " takes you from ", idop, "."), |
2788 | - toolMessage=(player, " takes ", target, " from you."), |
2789 | - otherMessage=(player, " takes ", target, " from ", idop, ".")) |
2790 | - |
2791 | - |
2792 | - |
2793 | -class Remove(TargetAction): |
2794 | - expr = ((pyparsing.Literal("remove") | |
2795 | - pyparsing.Literal("take off")) + |
2796 | - pyparsing.White() + |
2797 | - targetString("target")) |
2798 | - |
2799 | - targetInterface = iimaginary.IClothing |
2800 | - actorInterface = iimaginary.IClothingWearer |
2801 | - |
2802 | - def do(self, player, line, target): |
2803 | - from imaginary import garments |
2804 | - try: |
2805 | - player.takeOff(target) |
2806 | - except garments.InaccessibleGarment, e: |
2807 | - raise eimaginary.ActionFailure(events.ThatDoesntWork( |
2808 | - actor=player.thing, |
2809 | - target=target.thing, |
2810 | - actorMessage=(u"You cannot take off ", |
2811 | - language.Noun(target.thing).definiteNounPhrase(), |
2812 | - u" because you are wearing ", |
2813 | - e.obscuringGarment.thing, u"."), |
2814 | - otherMessage=language.Sentence([ |
2815 | - player.thing, |
2816 | - u" gets a dumb look on ", |
2817 | - language.Noun(player.thing).hisHer(), |
2818 | - u" face."]))) |
2819 | - |
2820 | - evt = events.Success( |
2821 | - actor=player.thing, |
2822 | - target=target.thing, |
2823 | - actorMessage=(u"You take off ", |
2824 | - language.Noun(target.thing).definiteNounPhrase(), |
2825 | - u"."), |
2826 | - otherMessage=language.Sentence([ |
2827 | - player.thing, u" takes off ", target.thing, u"."])) |
2828 | - evt.broadcast() |
2829 | - |
2830 | - |
2831 | - |
2832 | -class Wear(TargetAction): |
2833 | - expr = (pyparsing.Literal("wear") + |
2834 | - pyparsing.White() + |
2835 | - targetString("target")) |
2836 | - |
2837 | - targetInterface = iimaginary.IClothing |
2838 | - actorInterface = iimaginary.IClothingWearer |
2839 | - |
2840 | - def do(self, player, line, target): |
2841 | - from imaginary import garments |
2842 | - try: |
2843 | - player.putOn(target) |
2844 | - except garments.TooBulky, e: |
2845 | - raise eimaginary.ActionFailure(events.ThatDoesntWork( |
2846 | - actor=player.thing, |
2847 | - target=target.thing, |
2848 | - actorMessage=language.Sentence([ |
2849 | - language.Noun(e.wornGarment.thing).definiteNounPhrase(), |
2850 | - u" you are already wearing is too bulky for you to do" |
2851 | - u" that."]), |
2852 | - otherMessage=language.Sentence([ |
2853 | - player.thing, |
2854 | - u" wrestles with basic personal problems."]))) |
2855 | - |
2856 | - evt = events.Success( |
2857 | - actor=player.thing, |
2858 | - target=target.thing, |
2859 | - actorMessage=(u"You put on ", |
2860 | - language.Noun(target.thing).definiteNounPhrase(), |
2861 | - "."), |
2862 | - otherMessage=language.Sentence([ |
2863 | - player.thing, " puts on ", target.thing, "."])) |
2864 | - evt.broadcast() |
2865 | - |
2866 | - |
2867 | - |
2868 | -class Equipment(Action): |
2869 | - expr = pyparsing.Literal("equipment") |
2870 | - |
2871 | - actorInterface = iimaginary.IClothingWearer |
2872 | - |
2873 | - def do(self, player, line): |
2874 | - from imaginary import garments |
2875 | - equipment = list(player.store.query( |
2876 | - objects.Thing, |
2877 | - AND( |
2878 | - garments.Garment.thing == objects.Thing.storeID, |
2879 | - garments.Garment.wearer == player), |
2880 | - sort=objects.Thing.name.ascending)) |
2881 | - if equipment: |
2882 | - evt = events.Success( |
2883 | - actor=player.thing, |
2884 | - actorMessage=[ |
2885 | - u"You are wearing ", |
2886 | - language.ItemizedList(equipment), |
2887 | - u"."]) |
2888 | - else: |
2889 | - evt = events.Success( |
2890 | - actor=player.thing, |
2891 | - actorMessage=language.ExpressString( |
2892 | - u"You aren't wearing any equipment.")) |
2893 | - evt.broadcast() |
2894 | - |
2895 | - |
2896 | - |
2897 | -class TakeFrom(ToolAction): |
2898 | - actionName = "take" |
2899 | - |
2900 | - expr = ((pyparsing.Literal("get") ^ pyparsing.Literal("take")) + |
2901 | - pyparsing.White() + |
2902 | - targetString("target") + |
2903 | - pyparsing.Optional(pyparsing.White() + |
2904 | - pyparsing.Literal("from")) + |
2905 | - pyparsing.White() + |
2906 | - targetString("tool")) |
2907 | - |
2908 | - def cantFind_target(self, player, targetName): |
2909 | - return "Nothing like that around here." |
2910 | - cantFind_tool = cantFind_target |
2911 | - |
2912 | - def do(self, player, line, target, tool): |
2913 | - # XXX Make sure target is in tool |
2914 | - targetTaken(player.thing, target, tool).broadcast() |
2915 | - try: |
2916 | - target.moveTo(player.thing) |
2917 | - except eimaginary.DoesntFit: |
2918 | - raise tooHeavy(player.thing, target) |
2919 | - |
2920 | - |
2921 | - |
2922 | -class PutIn(ToolAction): |
2923 | - |
2924 | - toolInterface = iimaginary.IThing |
2925 | - targetInterface = iimaginary.IContainer |
2926 | - |
2927 | - def cantFind_target(self, player, targetName): |
2928 | - return "That doesn't work." |
2929 | - |
2930 | - expr = (pyparsing.Literal("put") + |
2931 | - pyparsing.White() + |
2932 | - targetString("tool") + |
2933 | - pyparsing.Optional(pyparsing.White() + |
2934 | - pyparsing.Literal("in")) + |
2935 | - pyparsing.White() + |
2936 | - targetString("target")) |
2937 | - |
2938 | - def do(self, player, line, tool, target): |
2939 | - ctool = iimaginary.IContainer(tool, None) |
2940 | - targetObject = target.thing |
2941 | - if ctool is not None and (ctool.contains(targetObject) or ctool is target): |
2942 | - raise eimaginary.ActionFailure( |
2943 | - events.ThatDoesntWork( |
2944 | - actor=player.thing, |
2945 | - target=targetObject, |
2946 | - tool=tool, |
2947 | - actorMessage="A thing cannot contain itself in euclidean space.")) |
2948 | - |
2949 | - dnf = language.Noun(targetObject).definiteNounPhrase() |
2950 | - evt = events.Success( |
2951 | - actor=player.thing, |
2952 | - target=targetObject, |
2953 | - tool=tool, |
2954 | - actorMessage=("You put ", |
2955 | - language.Noun(tool).definiteNounPhrase(), |
2956 | - " in ", dnf, "."), |
2957 | - targetMessage=language.Sentence([player.thing, " puts ", " tool in you."]), |
2958 | - toolMessage=language.Sentence([player.thing, " puts you in ", targetObject, "."]), |
2959 | - otherMessage=language.Sentence([player.thing, " puts ", tool, " in ", targetObject, "."])) |
2960 | - evt.broadcast() |
2961 | - |
2962 | - try: |
2963 | - tool.moveTo(target) |
2964 | - except eimaginary.DoesntFit: |
2965 | - # <allexpro> dash: put me in a tent and give it to moshez! |
2966 | - raise eimaginary.ActionFailure( |
2967 | - events.ThatDoesntWork( |
2968 | - actor=player.thing, |
2969 | - target=targetObject, |
2970 | - tool=tool, |
2971 | - actorMessage=language.Sentence([ |
2972 | - language.Noun(tool).definiteNounPhrase(), |
2973 | - u" does not fit in ", dnf, u"."]))) |
2974 | - except eimaginary.Closed: |
2975 | - raise eimaginary.ActionFailure( |
2976 | - events.ThatDoesntWork( |
2977 | - actor=player.thing, |
2978 | - target=targetObject, |
2979 | - tool=tool, |
2980 | - actorMessage=language.Sentence([dnf, " is closed."]))) |
2981 | - |
2982 | - |
2983 | - |
2984 | -class Take(TargetAction): |
2985 | - expr = ((pyparsing.Literal("get") ^ pyparsing.Literal("take")) + |
2986 | - pyparsing.White() + |
2987 | - targetString("target")) |
2988 | - |
2989 | - def cantFind_target(self, player, targetName): |
2990 | - return u"Nothing like that around here." |
2991 | - |
2992 | - def targetRadius(self, player): |
2993 | - return 1 |
2994 | - |
2995 | - def do(self, player, line, target): |
2996 | - if target in (player.thing, player.thing.location) or target.location is player.thing: |
2997 | - raise eimaginary.ActionFailure(events.ThatDoesntMakeSense( |
2998 | - actor=player.thing, |
2999 | - actorMessage=("You cannot take ", target, "."))) |
3000 | - |
3001 | - targetTaken(player.thing, target).broadcast() |
3002 | - try: |
3003 | - target.moveTo(player.thing) |
3004 | - except eimaginary.DoesntFit: |
3005 | - raise tooHeavy(player.thing, target) |
3006 | - |
3007 | - |
3008 | - |
3009 | -def insufficientSpace(player): |
3010 | - return eimaginary.ActionFailure(events.ThatDoesntWork( |
3011 | - actor=player, |
3012 | - actorMessage="There's not enough space for that.")) |
3013 | - |
3014 | - |
3015 | - |
3016 | -class Drop(TargetAction): |
3017 | - expr = (pyparsing.Literal("drop") + |
3018 | - pyparsing.White() + |
3019 | - targetString("target")) |
3020 | - |
3021 | - def cantFind_target(self, player, targetName): |
3022 | - return "Nothing like that around here." |
3023 | - |
3024 | - def targetRadius(self, player): |
3025 | - return 1 |
3026 | - |
3027 | - def do(self, player, line, target): |
3028 | - if target.location is not player.thing: |
3029 | - raise eimaginary.ActionFailure( |
3030 | - events.ThatDoesntMakeSense( |
3031 | - actor=player.thing, |
3032 | - actorMessage="You can't drop that.")) |
3033 | - |
3034 | - try: |
3035 | - target.moveTo( |
3036 | - player.thing.location, |
3037 | - arrivalEventFactory=lambda target: events.ArrivalEvent( |
3038 | - actor=player.thing, |
3039 | - actorMessage=("You drop ", |
3040 | - language.Noun(target).definiteNounPhrase(), |
3041 | - "."), |
3042 | - target=target, |
3043 | - targetMessage=(player.thing, " drops you."), |
3044 | - otherMessage=(player.thing, " drops ", target, "."))) |
3045 | - except eimaginary.DoesntFit: |
3046 | - raise insufficientSpace(player.thing) |
3047 | - |
3048 | - |
3049 | - |
3050 | -_directionNames = objects.OPPOSITE_DIRECTIONS.keys() |
3051 | -_directionNames.extend(objects.DIRECTION_ALIASES.keys()) |
3052 | - |
3053 | -DIRECTION_LITERAL = reduce( |
3054 | - operator.xor, [ |
3055 | - pyparsing.Literal(d) |
3056 | - for d in _directionNames]).setResultsName("direction") |
3057 | - |
3058 | - |
3059 | - |
3060 | -def expandDirection(direction): |
3061 | - """ |
3062 | - Expand direction aliases into the names of the directions they refer to. |
3063 | - """ |
3064 | - return objects.DIRECTION_ALIASES.get(direction, direction) |
3065 | - |
3066 | - |
3067 | - |
3068 | -class Dig(Action): |
3069 | - expr = (pyparsing.Literal("dig") + |
3070 | - pyparsing.White() + |
3071 | - DIRECTION_LITERAL + |
3072 | - pyparsing.White() + |
3073 | - pyparsing.restOfLine.setResultsName("name")) |
3074 | - |
3075 | - def do(self, player, line, direction, name): |
3076 | - direction = expandDirection(direction) |
3077 | - if iimaginary.IContainer(player.thing.location).getExitNamed(direction, None) is not None: |
3078 | - raise eimaginary.ActionFailure(events.ThatDoesntMakeSense( |
3079 | - actor=player.thing, |
3080 | - actorMessage="There is already an exit in that direction.")) |
3081 | - |
3082 | - room = objects.Thing(store=player.store, name=name) |
3083 | - objects.Container.createFor(room, capacity=1000) |
3084 | - objects.Exit.link(player.thing.location, room, direction) |
3085 | - |
3086 | - evt = events.Success( |
3087 | - actor=player.thing, |
3088 | - actorMessage="You create an exit.", |
3089 | - otherMessage=language.Sentence([player.thing, " created an exit to the ", direction, "."])) |
3090 | - evt.broadcast() |
3091 | - |
3092 | - # XXX Right now there can't possibly be anyone in the |
3093 | - # destination room, but someday there could be. When there |
3094 | - # could be, broadcast this to them too. |
3095 | - |
3096 | - |
3097 | - |
3098 | -class Bury(Action): |
3099 | - expr = (pyparsing.Literal("bury") + |
3100 | - pyparsing.White() + |
3101 | - DIRECTION_LITERAL) |
3102 | - |
3103 | - def do(self, player, line, direction): |
3104 | - direction = expandDirection(direction) |
3105 | - for exit in iimaginary.IContainer(player.thing.location).getExits(): |
3106 | - if exit.name == direction: |
3107 | - if exit.sibling is not None: |
3108 | - evt = events.Success( |
3109 | - location=exit.toLocation, |
3110 | - otherMessage=language.Sentence([ |
3111 | - exit.sibling, " crumbles and disappears."])) |
3112 | - evt.broadcast() |
3113 | - |
3114 | - evt = events.Success( |
3115 | - actor=player.thing, |
3116 | - actorMessage="It's gone.", |
3117 | - otherMessage=language.Sentence([ |
3118 | - language.Noun(player.thing).nounPhrase(), |
3119 | - " destroyed ", exit, "."])) |
3120 | - evt.broadcast() |
3121 | - exit.destroy() |
3122 | - return |
3123 | - |
3124 | - raise eimaginary.ActionFailure(events.ThatDoesntMakeSense( |
3125 | - actor=player.thing, |
3126 | - actorMessage="There isn't an exit in that direction.")) |
3127 | - |
3128 | - |
3129 | - |
3130 | -class Go(Action): |
3131 | - expr = ( |
3132 | - (pyparsing.Literal("go") + pyparsing.White() + |
3133 | - targetString("direction")) | |
3134 | - (pyparsing.Literal("enter") + pyparsing.White() + |
3135 | - targetString("direction")) | |
3136 | - (pyparsing.Literal("exit") + pyparsing.White() + |
3137 | - targetString("direction")) | |
3138 | - DIRECTION_LITERAL) |
3139 | - |
3140 | - actorInterface = iimaginary.IThing |
3141 | - |
3142 | - def resolve_direction(self, player, directionName): |
3143 | - """ |
3144 | - Identify a direction by having the player search for L{IExit} |
3145 | - providers that they can see and reach. |
3146 | - """ |
3147 | - directionName = expandDirection(directionName) |
3148 | - return player.obtainOrReportWhyNot( |
3149 | - Proximity( |
3150 | - 3.0, |
3151 | - Traversability( |
3152 | - Named(directionName, |
3153 | - CanSee(ProviderOf(iimaginary.IExit)), player)))) |
3154 | - |
3155 | - |
3156 | - def cantFind_direction(self, actor, directionName): |
3157 | - """ |
3158 | - Explain to the user that they can't go in a direction that they can't |
3159 | - locate. |
3160 | - """ |
3161 | - return u"You can't go that way." |
3162 | - |
3163 | - |
3164 | - def do(self, player, line, direction): |
3165 | - location = player.location |
3166 | - |
3167 | - evt = events.Success( |
3168 | - location=location, |
3169 | - actor=player, |
3170 | - otherMessage=(player, " leaves ", direction.name, ".")) |
3171 | - evt.broadcast() |
3172 | - |
3173 | - try: |
3174 | - direction.traverse(player) |
3175 | - except eimaginary.DoesntFit: |
3176 | - raise eimaginary.ActionFailure(events.ThatDoesntWork( |
3177 | - actor=player, |
3178 | - actorMessage=language.ExpressString( |
3179 | - u"There's no room for you there."))) |
3180 | - |
3181 | - # This is subtly incorrect: see http://divmod.org/trac/ticket/2917 |
3182 | - lookAroundActor = iimaginary.IActor(player) |
3183 | - LookAround().do(lookAroundActor, "look") |
3184 | - |
3185 | - |
3186 | - |
3187 | -class Restore(TargetAction): |
3188 | - expr = (pyparsing.Literal("restore") + |
3189 | - pyparsing.White() + |
3190 | - pyparsing.restOfLine.setResultsName("target")) |
3191 | - |
3192 | - targetInterface = iimaginary.IActor |
3193 | - |
3194 | - def cantFind_target(self, player, targetName): |
3195 | - for thing in player.thing.search(self.targetRadius(player), |
3196 | - iimaginary.IThing, targetName): |
3197 | - return (language.Noun(thing).nounPhrase().plaintext(player), |
3198 | - " cannot be restored.") |
3199 | - return "Who's that?" |
3200 | - |
3201 | - def targetRadius(self, player): |
3202 | - return 3 |
3203 | - |
3204 | - |
3205 | - def do(self, player, line, target): |
3206 | - target.hitpoints.current = target.hitpoints.max |
3207 | - target.stamina.current = target.stamina.max |
3208 | - |
3209 | - if player is target: |
3210 | - evt = events.Success( |
3211 | - actor=player.thing, |
3212 | - actorMessage="You have fully restored yourself.") |
3213 | - evt.broadcast() |
3214 | - else: |
3215 | - evt = events.Success( |
3216 | - actor=player.thing, |
3217 | - actorMessage=("You have restored ", target.thing, " to full health."), |
3218 | - target=target.thing, |
3219 | - targetMessage=(player.thing, " has restored you to full health."), |
3220 | - otherMessage=(player.thing, " has restored ", target.thing, " to full health.")) |
3221 | - evt.broadcast() |
3222 | - |
3223 | - |
3224 | - |
3225 | -class Hit(TargetAction): |
3226 | - expr = ((pyparsing.Literal("hit") ^ |
3227 | - pyparsing.Literal("attack") ^ |
3228 | - pyparsing.Literal("kill")) + |
3229 | - pyparsing.White() + |
3230 | - pyparsing.restOfLine.setResultsName("target")) |
3231 | - |
3232 | - targetInterface = iimaginary.IActor |
3233 | - |
3234 | - def targetRadius(self, player): |
3235 | - return 3 |
3236 | - |
3237 | - def do(self, player, line, target): |
3238 | - if target is player: |
3239 | - raise eimaginary.ActionFailure( |
3240 | - events.ThatDoesntMakeSense(u"Hit yourself? Stupid.", |
3241 | - actor=player.thing)) |
3242 | - |
3243 | - cost = random.randrange(1, 5) |
3244 | - if player.stamina < cost: |
3245 | - raise eimaginary.ActionFailure( |
3246 | - events.ThatDoesntWork(u"You're too tired!", |
3247 | - actor=player.thing)) |
3248 | - |
3249 | - damage = random.randrange(1, 5) |
3250 | - player.stamina.decrease(cost) |
3251 | - thp = target.hitpoints.decrease(damage) |
3252 | - events.Success( |
3253 | - actor=player.thing, |
3254 | - target=target.thing, |
3255 | - targetMessage=language.Sentence([player.thing, " hits you for ", damage, " hitpoints."]), |
3256 | - actorMessage=language.Sentence(["You hit ", language.Noun(target.thing).definiteNounPhrase(), " for ", damage, " hitpoints."]), |
3257 | - otherMessage=language.Sentence([player.thing, " hits ", target.thing, "."])).broadcast() |
3258 | - |
3259 | - if thp <= 0: |
3260 | - xp = target.experience / 2 + 1 |
3261 | - player.gainExperience(xp) # I LOVE IT |
3262 | - targetIsDead = [target.thing, " is dead!", "\n"] |
3263 | - events.Success( |
3264 | - actor=player.thing, target=target.thing, |
3265 | - actorMessage=["\n", targetIsDead, "You gain ", xp, " experience"], |
3266 | - targetMessage=["You are dead!"], |
3267 | - otherMessage=targetIsDead).broadcast() |
3268 | - target.thing.destroy() |
3269 | - |
3270 | - |
3271 | - |
3272 | -class Say(Action): |
3273 | - expr = (((pyparsing.Literal("say") + pyparsing.White()) ^ |
3274 | - pyparsing.Literal("'")) + |
3275 | - pyparsing.restOfLine.setResultsName("text")) |
3276 | - |
3277 | - def do(self, player, line, text): |
3278 | - evt = events.SpeechEvent(speaker=player.thing, text=text) |
3279 | - evt.broadcast() |
3280 | - |
3281 | - |
3282 | - |
3283 | -class Emote(Action): |
3284 | - expr = (((pyparsing.Literal("emote") + pyparsing.White()) ^ |
3285 | - pyparsing.Literal(":")) + |
3286 | - pyparsing.restOfLine.setResultsName("text")) |
3287 | - |
3288 | - def do(self, player, line, text): |
3289 | - evt = events.Success(actor=player.thing, |
3290 | - actorMessage=[player.thing, " ", text], |
3291 | - otherMessage=[player.thing, " ", text]) |
3292 | - evt.broadcast() |
3293 | - |
3294 | - |
3295 | - |
3296 | -class Actions(Action): |
3297 | - expr = pyparsing.Literal("actions") |
3298 | - |
3299 | - def do(self, player, line): |
3300 | - cmds = dict.fromkeys( |
3301 | - getattr(cmd, 'actionName', cmd.__name__.lower()) |
3302 | - for cmd |
3303 | - in self.__class__.actions).keys() |
3304 | - cmds.sort() |
3305 | - player.send((iterutils.interlace(" ", cmds), "\n")) |
3306 | - |
3307 | - |
3308 | - |
3309 | -class Commands(Action): |
3310 | - """ |
3311 | - The I{commands} action provides a pointer to inexperienced players that |
3312 | - they should be thinking in terms of I{actions} instead. |
3313 | - |
3314 | - This has no world side-effects; it just provides some user-interface |
3315 | - information to the player. |
3316 | - """ |
3317 | - expr = pyparsing.Literal("commands") |
3318 | - |
3319 | - def do(self, player, line): |
3320 | - player.send("Try 'actions' instead.") |
3321 | - |
3322 | - |
3323 | - |
3324 | -class Search(Action): |
3325 | - expr = (pyparsing.Literal("search") + |
3326 | - targetString("name")) |
3327 | - |
3328 | - def do(self, player, line, name): |
3329 | - srch = player.thing.search(2, iimaginary.IVisible, name) |
3330 | - evt = events.Success( |
3331 | - actor=player.thing, |
3332 | - actorMessage=language.ExpressList( |
3333 | - list(iterutils.interlace('\n', |
3334 | - (o.visualize() |
3335 | - for o |
3336 | - in srch))))) |
3337 | - evt.broadcast() |
3338 | - |
3339 | - |
3340 | - |
3341 | -class Score(Action): |
3342 | - expr = pyparsing.Literal("score") |
3343 | - |
3344 | - scoreFormat = ( |
3345 | - '/----------------------------------------------------------------------------\\\n' |
3346 | - '| Level: %20d Experience: %10d\n' |
3347 | - '| Hitpoints: %16s\n' |
3348 | - '| Stamina: %18s\n' |
3349 | - '\\----------------------------------------------------------------------------/\n') |
3350 | - |
3351 | - def do(self, player, line): |
3352 | - events.Success( |
3353 | - actor=player.thing, |
3354 | - actorMessage=self.scoreFormat % (player.level, player.experience, player.hitpoints, player.stamina)).broadcast() |
3355 | - |
3356 | - |
3357 | - |
3358 | -class ExpressWho(language.BaseExpress): |
3359 | - header = (u"/============ Currently Playing ===========\\") |
3360 | - footer = (u"\\================ Total %(playerCount)03d ===============/") |
3361 | - |
3362 | - def vt102(self, observer): |
3363 | - players = self.original.connected |
3364 | - |
3365 | - return [[T.bold, self.header], u'\n', |
3366 | - [[language.Noun(p).shortName().vt102(observer), u'\n'] |
3367 | - for p in players], |
3368 | - [T.bold, self.footer % {'playerCount': len(players)}], u'\n'] |
3369 | - |
3370 | - |
3371 | - |
3372 | -class Who(Action): |
3373 | - expr = pyparsing.Literal("who") |
3374 | - |
3375 | - def do(self, player, line): |
3376 | - player.send(ExpressWho(player.store.findUnique(ImaginaryWorld))) |
3377 | - |
3378 | - |
3379 | - |
3380 | -class Scrutinize(TargetAction): |
3381 | - """ |
3382 | - Show detailed information about the model structure of a game object. |
3383 | - """ |
3384 | - expr = (pyparsing.Literal("scrutinize") + |
3385 | - pyparsing.White() + |
3386 | - targetString("target")) |
3387 | - |
3388 | - def targetRadius(self, player): |
3389 | - return 3 |
3390 | - |
3391 | - def do(self, player, line, target): |
3392 | - v = dict((k, getattr(target, k)) |
3393 | - for (k, ign) |
3394 | - in target.getSchema() |
3395 | - if hasattr(target, k)) |
3396 | - |
3397 | - targetContainer = iimaginary.IContainer(target, None) |
3398 | - if targetContainer is not None: |
3399 | - v['contents'] = list(targetContainer.getContents()) |
3400 | - exits = list(targetContainer.getExits()) |
3401 | - if exits: |
3402 | - v['exits'] = exits |
3403 | - s = pprint.pformat((target.__class__.__name__, v)) |
3404 | - # XXX FIXME Send a real Concept |
3405 | - player.send(s, '\n') |
3406 | - |
3407 | - |
3408 | - |
3409 | -class ExpressInventory(language.BaseExpress): |
3410 | - implements(iimaginary.IConcept) |
3411 | - |
3412 | - def __init__(self, original): |
3413 | - self.original = original |
3414 | - |
3415 | - def vt102(self, observer): |
3416 | - return [[T.fg.yellow, "Inventory:\n"], |
3417 | - [T.fg.green, |
3418 | - [(language.Noun(o).shortName().vt102(observer), '\n') |
3419 | - for o |
3420 | - in iimaginary.IContainer(self.original).getContents()]]] |
3421 | - |
3422 | - |
3423 | - |
3424 | -class Inventory(Action): |
3425 | - expr = pyparsing.Literal("inventory") |
3426 | - |
3427 | - def do(self, player, line): |
3428 | - events.Success(actor=player.thing, |
3429 | - actorMessage=ExpressInventory(player.thing)).broadcast() |
3430 | - |
3431 | - |
3432 | - |
3433 | -class Set(TargetAction): |
3434 | - """ |
3435 | - Direct model-level state manipulation command. |
3436 | - """ |
3437 | - expr = ( |
3438 | - pyparsing.Literal("set") + pyparsing.White() + |
3439 | - targetString("attribute") + pyparsing.White() + |
3440 | - pyparsing.Literal("of") + pyparsing.White() + |
3441 | - targetString("target") + pyparsing.White() + |
3442 | - pyparsing.Literal("to") + pyparsing.White() + |
3443 | - targetString("value")) |
3444 | - |
3445 | - def do(self, player, line, attribute, target, value): |
3446 | - """ |
3447 | - Dispatch handling to an attribute-specific method. |
3448 | - |
3449 | - @type attribute: C{unicode} |
3450 | - @param attribute: The model-level attribute of which to manipulate |
3451 | - the value. Handling of each attribute will be dispatched to a |
3452 | - C{set_}-prefixed method for that attribute based on this value. |
3453 | - |
3454 | - @type target: L{Thing} |
3455 | - @param target: The model object to manipulate. |
3456 | - |
3457 | - @type value: C{unicode} |
3458 | - @param value: The new value for the specified attribute. |
3459 | - """ |
3460 | - try: |
3461 | - method = getattr(self, "set_" + attribute.upper()) |
3462 | - except AttributeError: |
3463 | - raise eimaginary.ActionFailure( |
3464 | - events.ThatDoesntMakeSense( |
3465 | - actor=player.thing, |
3466 | - actorMessage="You cannot set that.")) |
3467 | - else: |
3468 | - method(player, line, target, value) |
3469 | - |
3470 | - |
3471 | - def set_GENDER(self, player, line, target, value): |
3472 | - """ |
3473 | - Attempt to change the gender of a thing. |
3474 | - |
3475 | - @param target: The thing to change the gender of. |
3476 | - @param value: A string naming a gender on L{language.Gender}. |
3477 | - """ |
3478 | - try: |
3479 | - target.gender = getattr(language.Gender, value.upper()) |
3480 | - except AttributeError: |
3481 | - gender = {language.Gender.MALE: "male", |
3482 | - language.Gender.FEMALE: "female", |
3483 | - language.Gender.NEUTER: "neuter"}.get(target.gender) |
3484 | - raise eimaginary.ActionFailure(events.ThatDoesntMakeSense( |
3485 | - actor=player.thing, |
3486 | - actorMessage=("Only male, female, and neuter are valid " |
3487 | - "genders. You remain ", gender, "."))) |
3488 | - else: |
3489 | - if player.thing is target: |
3490 | - # XXX Why can't I do something with Noun to collapse these |
3491 | - # cases? |
3492 | - event = events.Success( |
3493 | - actor=player.thing, |
3494 | - actorMessage=(u"You set your gender to ", value, ".")) |
3495 | - else: |
3496 | - event = events.Success( |
3497 | - actor=player.thing, |
3498 | - target=target, |
3499 | - actorMessage=("You set ", language.Noun(target).hisHer(), |
3500 | - " gender to ", value, "."), |
3501 | - targetMessage=(player.thing, " set your gender to ", |
3502 | - value, ".")) |
3503 | - event.broadcast() |
3504 | - |
3505 | - |
3506 | - def set_PROPER(self, player, line, target, value): |
3507 | - """ |
3508 | - Attempt to change the name of a thing from a proper noun to a common |
3509 | - noun or the other way around. |
3510 | - |
3511 | - @param target: The thing to change. |
3512 | - @param value: The string C{"true"} or C{"false"}. |
3513 | - """ |
3514 | - if value == "true": |
3515 | - target.proper = True |
3516 | - phrase = '" a proper noun.' |
3517 | - elif value == "false": |
3518 | - target.proper = False |
3519 | - phrase = '" a common noun.' |
3520 | - else: |
3521 | - raise eimaginary.ActionFailure( |
3522 | - events.ThatDoesntMakeSense( |
3523 | - actor=player.thing, |
3524 | - actorMessage=("Only true and false are valid settings " |
3525 | - "for proper."))) |
3526 | - events.Success( |
3527 | - actor=player.thing, |
3528 | - actorMessage=('You make the name of "', |
3529 | - language.Noun(target).shortName(), |
3530 | - phrase)).broadcast() |
3531 | - |
3532 | - |
3533 | - |
3534 | -class Help(Action): |
3535 | - """ |
3536 | - A command for looking up help files. |
3537 | - |
3538 | - @cvar helpContentPath: The path in which to search for files. |
3539 | - @type helpContentPath: L{filepath.FilePath} |
3540 | - """ |
3541 | - expr = (pyparsing.Literal("help") + |
3542 | - pyparsing.White() + |
3543 | - pyparsing.restOfLine.setResultsName("topic")) |
3544 | - |
3545 | - helpContentPath = filepath.FilePath(imaginary.__file__).sibling( |
3546 | - "resources").child("help") |
3547 | - |
3548 | - def do(self, player, line, topic): |
3549 | - topic = topic.lower().strip() |
3550 | - try: |
3551 | - helpFile = self.helpContentPath.child(topic).open() |
3552 | - except (OSError, IOError, filepath.InsecurePath): |
3553 | - player.send("No help available on ", topic, ".", "\n") |
3554 | - else: |
3555 | - player.send(helpFile.read(), '\n') |
3556 | |
3557 | === removed file 'Imaginary/imaginary/copyright.py' |
3558 | --- Imaginary/imaginary/copyright.py 2006-04-12 02:41:46 +0000 |
3559 | +++ Imaginary/imaginary/copyright.py 1970-01-01 00:00:00 +0000 |
3560 | @@ -1,22 +0,0 @@ |
3561 | - |
3562 | -# <major> <minor> <patch> <alpha | pre | final | zzz> <iteration> |
3563 | -version_info = (0, 1, 0, 'alpha', 0) |
3564 | - |
3565 | -# Sortable version information. This will always only |
3566 | -# increase from an older version to a newer version. |
3567 | -hexversion = (version_info[0] << 24 | |
3568 | - version_info[1] << 16 | |
3569 | - version_info[2] << 8 | |
3570 | - ['alpha', 'pre', 'final', 'zzz'].index(version_info[3]) << 4 | |
3571 | - version_info[4]) |
3572 | - |
3573 | -# Human-readable format |
3574 | -if version_info[3] == 'final': |
3575 | - version = '%d.%d.%d%s' % version_info[:-1] |
3576 | -elif version_info[3] != 'zzz': |
3577 | - version = '%d.%d.%d%s%d' % version_info |
3578 | -else: |
3579 | - version = "SVN-trunk" |
3580 | - |
3581 | -# Longer human-readable format |
3582 | -longversion= "Imaginary " + version |
3583 | |
3584 | === removed file 'Imaginary/imaginary/creation.py' |
3585 | --- Imaginary/imaginary/creation.py 2009-08-17 02:40:03 +0000 |
3586 | +++ Imaginary/imaginary/creation.py 1970-01-01 00:00:00 +0000 |
3587 | @@ -1,179 +0,0 @@ |
3588 | -# -*- test-case-name: imaginary.test.test_create -*- |
3589 | -""" |
3590 | -This module contains code associated with creating objects in game. |
3591 | -""" |
3592 | - |
3593 | -from zope.interface import implements |
3594 | - |
3595 | -from twisted import plugin |
3596 | - |
3597 | -import imaginary.plugins |
3598 | - |
3599 | -from imaginary import objects |
3600 | -from imaginary import events |
3601 | -from imaginary import language |
3602 | - |
3603 | -from imaginary.iimaginary import IThingType |
3604 | -from imaginary.eimaginary import ActionFailure, DoesntFit |
3605 | - |
3606 | -from imaginary.action import Action, insufficientSpace |
3607 | -from imaginary.action import targetString |
3608 | - |
3609 | -from imaginary.pyparsing import Literal, White, Optional, restOfLine |
3610 | - |
3611 | - |
3612 | -def getPlugins(iface, package): |
3613 | - """ |
3614 | - Get plugins. See L{twisted.plugin.getPlugins}. |
3615 | - |
3616 | - This is in place only so the tests specifically for creation can replace |
3617 | - it. Please use L{twisted.plugin.getPlugins} instead. |
3618 | - """ |
3619 | - # XXX the tests should not need to do that, make it per-instance or |
3620 | - # something... |
3621 | - return plugin.getPlugins(iface, package) |
3622 | - |
3623 | - |
3624 | -def createCreator(*enhancements): |
3625 | - """ |
3626 | - Create and return a function which can create objects in the game world. |
3627 | - |
3628 | - This is a utility function to make it easy to define factories for certain |
3629 | - configurations of power-ups to be used with Imaginary. It doesn't do |
3630 | - anything magical; you can replicate its effects simply by writing a |
3631 | - function that calls L{Enhancement.createFor} on the set of L{Enhancement}s. |
3632 | - L{createCreator} exists because you will frequently need to do that, and it |
3633 | - can be tedious. |
3634 | - |
3635 | - @param enhancements: The arguments to this function are a list of 2-tuples |
3636 | - of (L{Enhancement}-subclass, keyword arguments to that class's |
3637 | - constructor). |
3638 | - |
3639 | - @return: a function which takes keyword arguments that will be passed on to |
3640 | - L{objects.Thing}'s constructor, and will return a L{Thing} with an |
3641 | - instance of each class in C{enhancements} installed, via C{createFor}, |
3642 | - on it. |
3643 | - |
3644 | - @rtype: L{Thing} |
3645 | - """ |
3646 | - def create(**kw): |
3647 | - o = objects.Thing(**kw) |
3648 | - for enhancementClass, enhancementKeywords in enhancements: |
3649 | - enhancementClass.createFor(o, **(enhancementKeywords or {})) |
3650 | - return o |
3651 | - return create |
3652 | - |
3653 | - |
3654 | -class CreationPluginHelper(object): |
3655 | - """ |
3656 | - A helper for creating plugins for the 'Create' command. |
3657 | - |
3658 | - Create will search for L{IThingType} plugins and allow users to |
3659 | - instantiate a new L{objects.Thing} using the one with the name which |
3660 | - matches what was supplied to the action. |
3661 | - """ |
3662 | - |
3663 | - implements(plugin.IPlugin, IThingType) |
3664 | - |
3665 | - def __init__(self, typeName, typeObject): |
3666 | - """ |
3667 | - @type typeName: C{unicode} |
3668 | - @param typeName: A short string describing the kind of object this |
3669 | - plugin will create. |
3670 | - |
3671 | - @param typeObject: A factory for creating instances of |
3672 | - L{objects.Thing}. This will be invoked with four keyword arguments: |
3673 | - store, name, description, and proper. See attributes of |
3674 | - L{objects.Thing} for documentation of these arguments. |
3675 | - """ |
3676 | - self.type = typeName |
3677 | - self.typeObject = typeObject |
3678 | - |
3679 | - |
3680 | - def getType(self): |
3681 | - return self.typeObject |
3682 | - |
3683 | - |
3684 | - |
3685 | -def creationSuccess(player, creation): |
3686 | - """ |
3687 | - Create and return an event describing that an object was successfully |
3688 | - created. |
3689 | - """ |
3690 | - phrase = language.Noun(creation).nounPhrase() |
3691 | - return events.Success( |
3692 | - actor=player, |
3693 | - target=creation, |
3694 | - actorMessage=language.Sentence(["You create ", phrase, "."]), |
3695 | - targetMessage=language.Sentence([player, " creates you."]), |
3696 | - otherMessage=language.Sentence([player, " creates ", phrase, "."])) |
3697 | - |
3698 | - |
3699 | -class Create(Action): |
3700 | - """ |
3701 | - An action which can create items by looking at the L{IThingType} plugin |
3702 | - registry. |
3703 | - """ |
3704 | - expr = (Literal("create") + |
3705 | - Optional(White() + |
3706 | - (Literal("an") | Literal("a") | Literal("the")).setResultsName("article")) + |
3707 | - White() + |
3708 | - targetString("typeName") + |
3709 | - White() + |
3710 | - Literal("named") + |
3711 | - White() + |
3712 | - targetString("name") + |
3713 | - Optional(White() + |
3714 | - restOfLine.setResultsName("description"))) |
3715 | - |
3716 | - def do(self, player, line, typeName, name, description=None, article=None): |
3717 | - """ |
3718 | - Create an item, and notify everyone present that it now exists. |
3719 | - """ |
3720 | - if not description: |
3721 | - description = u'an undescribed object' |
3722 | - for plug in getPlugins(IThingType, imaginary.plugins): |
3723 | - if plug.type == typeName: |
3724 | - proper = (article == "the") |
3725 | - o = plug.getType()(store=player.store, name=name, |
3726 | - description=description, proper=proper) |
3727 | - break |
3728 | - else: |
3729 | - raise ActionFailure( |
3730 | - events.ThatDoesntMakeSense( |
3731 | - actor=player.thing, |
3732 | - actorMessage=language.ExpressString( |
3733 | - u"Can't find " + typeName + u"."))) |
3734 | - |
3735 | - creationSuccess(player.thing, o).broadcast() |
3736 | - try: |
3737 | - o.moveTo(player.thing) |
3738 | - except DoesntFit: |
3739 | - raise insufficientSpace(player.thing) |
3740 | - |
3741 | - |
3742 | - |
3743 | - |
3744 | -def listThingTypes(): |
3745 | - """ |
3746 | - Return a list of C{unicode} strings each of which gives the name of a type |
3747 | - which can be created with the create command. |
3748 | - """ |
3749 | - return sorted([type.type for type in getPlugins(IThingType, imaginary.plugins)]) |
3750 | - |
3751 | - |
3752 | - |
3753 | -class ListThingTypes(Action): |
3754 | - """ |
3755 | - An action which tells the invoker what thing types exist to be created with |
3756 | - the L{Create} command. |
3757 | - """ |
3758 | - expr = Literal("list thing types") |
3759 | - |
3760 | - def do(self, player, line): |
3761 | - """ |
3762 | - Tell the player the thing types which exist. |
3763 | - """ |
3764 | - events.Success( |
3765 | - actor=player.thing, |
3766 | - actorMessage=[(t, "\n") for t in listThingTypes()]).broadcast() |
3767 | |
3768 | === removed file 'Imaginary/imaginary/eimaginary.py' |
3769 | --- Imaginary/imaginary/eimaginary.py 2009-06-29 04:03:17 +0000 |
3770 | +++ Imaginary/imaginary/eimaginary.py 1970-01-01 00:00:00 +0000 |
3771 | @@ -1,90 +0,0 @@ |
3772 | - |
3773 | -from twisted.cred import error |
3774 | - |
3775 | -# Authentication errors |
3776 | -class BadPassword(error.UnauthorizedLogin): |
3777 | - pass |
3778 | - |
3779 | -class NoSuchUser(error.UnauthorizedLogin): |
3780 | - pass |
3781 | - |
3782 | - |
3783 | -# Base Imaginary error |
3784 | -class ImaginaryError(Exception): |
3785 | - pass |
3786 | - |
3787 | - |
3788 | -# Input handling errors |
3789 | -class NoSuchCommand(ImaginaryError): |
3790 | - """ |
3791 | - There is no command like the one you tried to execute. |
3792 | - """ |
3793 | - |
3794 | -class AmbiguousArgument(ImaginaryError): |
3795 | - """ |
3796 | - One or more of the inputs specified can not be narrowed down to |
3797 | - just one thing. This can be due to the presence of multiple |
3798 | - things with similar names, or due to the absence of anything named |
3799 | - similarly to the given input. |
3800 | - |
3801 | - @ivar action: The action which was being processed when an ambiguity was |
3802 | - found. |
3803 | - |
3804 | - @type part: C{str} |
3805 | - @ivar part: The part of the command which was ambiguous. |
3806 | - Typically something like 'target' or 'tool'. |
3807 | - |
3808 | - @type partValue: C{str} |
3809 | - @ivar partValue: The string which was supplied by the user for the indicated part. |
3810 | - |
3811 | - @type objects: C{list} of C{IThing} |
3812 | - @ivar objects: The objects which were involved in the ambiguity. |
3813 | - """ |
3814 | - |
3815 | - def __init__(self, action, part, partValue, objects): |
3816 | - ImaginaryError.__init__(self, action, part, partValue, objects) |
3817 | - self.action = action |
3818 | - self.part = part |
3819 | - self.partValue = partValue |
3820 | - self.objects = objects |
3821 | - |
3822 | - |
3823 | - |
3824 | -class ActionFailure(ImaginaryError): |
3825 | - """ |
3826 | - Wrapper exception for an Event that caused an action to fail (such that the |
3827 | - transaction in which it was running should be reverted). |
3828 | - """ |
3829 | - def __init__(self, event): |
3830 | - ImaginaryError.__init__(self) |
3831 | - self.event = event |
3832 | - |
3833 | - |
3834 | - def __repr__(self): |
3835 | - return '<Action Failure: %r>' % (self.event,) |
3836 | - |
3837 | - |
3838 | - |
3839 | -class ThingNotFound(ImaginaryError): |
3840 | - """ |
3841 | - Resolving a Thing by identity failed. |
3842 | - """ |
3843 | - |
3844 | - |
3845 | -# Game logic errors |
3846 | -class DoesntFit(ImaginaryError): |
3847 | - """ |
3848 | - An object tried to go into a container, but the container was full. |
3849 | - """ |
3850 | - |
3851 | - |
3852 | -class Closed(ImaginaryError): |
3853 | - """ |
3854 | - An object tried to go into a container, but the container was closed. |
3855 | - """ |
3856 | - |
3857 | - |
3858 | -class CannotMove(ImaginaryError): |
3859 | - """ |
3860 | - An object tried to move but it was not portable so it couldn't. |
3861 | - """ |
3862 | |
3863 | === removed file 'Imaginary/imaginary/enhancement.py' |
3864 | --- Imaginary/imaginary/enhancement.py 2009-06-29 04:03:17 +0000 |
3865 | +++ Imaginary/imaginary/enhancement.py 1970-01-01 00:00:00 +0000 |
3866 | @@ -1,95 +0,0 @@ |
3867 | -# -*- test-case-name: imaginary.test.test_enhancement -*- |
3868 | - |
3869 | -""" |
3870 | -This module contains objects for application code to use to implement behaviors |
3871 | -that attach to objects in a simulation. |
3872 | -""" |
3873 | - |
3874 | -class Enhancement(object): |
3875 | - """ |
3876 | - An L{Enhancement} is an object attached to a L{imaginary.objects.Thing} |
3877 | - that provides some additional functionality. |
3878 | - |
3879 | - This class is a mixin; it expects to be mixed in to an L{Item} subclass, |
3880 | - since it passes itself as an argument to L{Item.powerUp}. |
3881 | - |
3882 | - Note that an L{Enhancement} embodies the behavior, but not the physical |
3883 | - attributes, of the object in question. |
3884 | - |
3885 | - For example, let's say you wanted to implement a cell phone in Imaginary. |
3886 | - You would make an L{Enhancement} called C{CellPhone} which had various |
3887 | - attributes, for example C{phoneNumber}. Then you would do C{phoneBody = |
3888 | - Thing(...)} to create a physical 'phone' object in a world. Next, you |
3889 | - would do C{cellPhone = CellPhone.createFor(phoneBody, ...)}, which would |
3890 | - create a C{CellPhone} object that endowed your physical 'phone' with the |
3891 | - properties of being an actual phone, like having a phone number, ringing |
3892 | - when dialed, etc. |
3893 | - |
3894 | - Note that it is not enough to simply create your C{CellPhone}, as it will |
3895 | - not have a physical body, and therefore not exist in the world. |
3896 | - |
3897 | - @ivar thing: a L{imaginary.objects.Thing} powered up with this |
3898 | - L{Enhancement}. All subclasses which mix in L{Item} should declare |
3899 | - this as an L{attributes.reference} attribute. Unless your |
3900 | - L{Enhancement} subclass is specifically designed to exist |
3901 | - independently of its L{Thing}, or to accept other types for this |
3902 | - attribute, it should also be declared as C{(allowNone=False, |
3903 | - reftype=Thing, whenDeleted=CASCADE)}. |
3904 | - """ |
3905 | - |
3906 | - def installed(self): |
3907 | - """ |
3908 | - Override the C{installed()} hook that C{axiom.dependency} provides. |
3909 | - When L{Enhancement} was called C{ThingMixin}, the suggested mechanism |
3910 | - to install simulation components was to use the dependency system, |
3911 | - which was wrong, c.f. U{http://divmod.org/trac/ticket/2558}. |
3912 | - |
3913 | - @raise RuntimeError: to indicate that you shouldn't use this |
3914 | - functionality. |
3915 | - """ |
3916 | - raise RuntimeError("Use Enhancement.createFor, not installOn(), " |
3917 | - "to apply an Enhancement to a Thing.") |
3918 | - |
3919 | - |
3920 | - def applyEnhancement(self): |
3921 | - """ |
3922 | - Apply this L{Enhancement} to its C{thing} attribute, by powering it up. |
3923 | - """ |
3924 | - self.thing.powerUp(self) |
3925 | - |
3926 | - |
3927 | - def removeEnhancement(self): |
3928 | - """ |
3929 | - Remove this L{Enhancement} from its C{thing} attribute, by powering it |
3930 | - down. |
3931 | - """ |
3932 | - self.thing.powerDown(self) |
3933 | - |
3934 | - |
3935 | - @classmethod |
3936 | - def createFor(cls, thing, **kw): |
3937 | - """ |
3938 | - Create an L{Enhancement} of this type for the given |
3939 | - L{imaginary.objects.Thing}, in the given L{imaginary.objects.Thing}'s |
3940 | - store. |
3941 | - """ |
3942 | - self = cls(store=thing.store, thing=thing, **kw) |
3943 | - self.applyEnhancement() |
3944 | - return self |
3945 | - |
3946 | - |
3947 | - @classmethod |
3948 | - def destroyFor(cls, thing): |
3949 | - """ |
3950 | - Destroy the L{Enhancement}s of the given subclass associated with the |
3951 | - given L{Thing}, if one exists. |
3952 | - |
3953 | - @param thing: A L{Thing} which may be the value of the C{thing} |
3954 | - attribute of an instance of the given L{Enhancement} subclass. |
3955 | - |
3956 | - @type thing: L{Thing} |
3957 | - """ |
3958 | - it = thing.store.findUnique(cls, cls.thing == thing, default=None) |
3959 | - if it is not None: |
3960 | - it.removeEnhancement() |
3961 | - it.deleteFromStore() |
3962 | |
3963 | === removed file 'Imaginary/imaginary/events.py' |
3964 | --- Imaginary/imaginary/events.py 2009-08-18 00:20:31 +0000 |
3965 | +++ Imaginary/imaginary/events.py 1970-01-01 00:00:00 +0000 |
3966 | @@ -1,284 +0,0 @@ |
3967 | -# -*- test-case-name: imaginary.test.test_actions.TargetActionTests.test_resolveTargetCaseInsensitively -*- |
3968 | - |
3969 | -from zope.interface import implements |
3970 | - |
3971 | -from twisted.python import context |
3972 | - |
3973 | -from imaginary import iimaginary, language, eimaginary |
3974 | -from imaginary.idea import Proximity, ProviderOf |
3975 | - |
3976 | - |
3977 | -class Event(language.BaseExpress): |
3978 | - implements(iimaginary.IConcept) |
3979 | - |
3980 | - actorMessage = targetMessage = toolMessage = otherMessage = None |
3981 | - |
3982 | - def __init__(self, |
3983 | - location=None, actor=None, target=None, tool=None, |
3984 | - actorMessage=None, targetMessage=None, toolMessage=None, |
3985 | - otherMessage=None): |
3986 | - |
3987 | - if location is None and actor is not None: |
3988 | - location = actor.location |
3989 | - |
3990 | - self.location = location |
3991 | - self.actor = actor |
3992 | - self.target = target |
3993 | - self.tool = tool |
3994 | - if actorMessage is not None: |
3995 | - self.actorMessage = iimaginary.IConcept(actorMessage) |
3996 | - if targetMessage is not None: |
3997 | - self.targetMessage = iimaginary.IConcept(targetMessage) |
3998 | - if toolMessage is not None: |
3999 | - self.toolMessage = iimaginary.IConcept(toolMessage) |
4000 | - if otherMessage is not None: |
4001 | - self.otherMessage = iimaginary.IConcept(otherMessage) |
4002 | - |
4003 | - |
4004 | - def conceptFor(self, observer): |
4005 | - """ |
4006 | - Retrieve the appropriate L{IConcept} provider for a given observer. If |
4007 | - the observer is this L{Event}'s C{actor}, it will return the |
4008 | - C{actorMessage} for this event, and so on for the tool and the target. |
4009 | - If it doesn't match a L{Thing} known to this event, it will return |
4010 | - C{otherMessage}. |
4011 | - """ |
4012 | - if observer is self.actor: |
4013 | - msg = self.actorMessage |
4014 | - elif observer is self.target: |
4015 | - msg = self.targetMessage |
4016 | - elif observer is self.tool: |
4017 | - msg = self.toolMessage |
4018 | - else: |
4019 | - msg = self.otherMessage |
4020 | - return msg |
4021 | - |
4022 | - |
4023 | - def reify(self): |
4024 | - """ |
4025 | - Determine which objects should receive this event and return a callable |
4026 | - object which will deliver it to them. |
4027 | - |
4028 | - Note that this occurs during event propagation, and you probably don't |
4029 | - need to call it directly. |
4030 | - |
4031 | - @see: L{iimaginary.IEventObserver.prepare} and |
4032 | - L{TransactionalEventBroadcaster} for a more thorough description of |
4033 | - how this method is used to interact with transactions. |
4034 | - |
4035 | - @return: a 0-arg callable object which, when called, will call the |
4036 | - results of all L{IEventObserver}s which were contained within this |
4037 | - L{Event}'s location when this method, L{Event.reify}, was called. |
4038 | - """ |
4039 | - L = [] |
4040 | - for observer in (self.location.idea.obtain( |
4041 | - Proximity(0.5, ProviderOf(iimaginary.IEventObserver)))): |
4042 | - sender = observer.prepare(self) |
4043 | - if not callable(sender): |
4044 | - raise TypeError("Senders must be callable", sender) |
4045 | - L.append(sender) |
4046 | - return lambda: map(apply, L) |
4047 | - |
4048 | - |
4049 | - def vt102(self, observer): |
4050 | - c = self.conceptFor(observer) |
4051 | - if c is not None: |
4052 | - return [c.vt102(observer), '\n'] |
4053 | - return u'' |
4054 | - |
4055 | - |
4056 | - |
4057 | -class TransactionalEventBroadcaster(object): |
4058 | - """ |
4059 | - Collect a bunch of output events as a transaction is being executed, then |
4060 | - distribute them when it has completed. |
4061 | - |
4062 | - Events can be added normally or as revert events. Normal events are |
4063 | - broadcast after the transaction is successfully committed. Revert events |
4064 | - are broadcast if the transaction failed somehow and was been reverted. |
4065 | - """ |
4066 | - implements(iimaginary.ITransactionalEventBroadcaster) |
4067 | - |
4068 | - def __init__(self): |
4069 | - self._events = [] |
4070 | - self._revertEvents = [] |
4071 | - |
4072 | - |
4073 | - def addEvent(self, event): |
4074 | - """ |
4075 | - Add a normal event. |
4076 | - |
4077 | - @param event: A no-argument callable to be invoked when this |
4078 | - transaction has been committed. |
4079 | - """ |
4080 | - if not callable(event): |
4081 | - raise ValueError("Events must be callable", event) |
4082 | - self._events.append(event) |
4083 | - |
4084 | - |
4085 | - def addRevertEvent(self, event): |
4086 | - """ |
4087 | - Add a revert event. |
4088 | - |
4089 | - @param event: A no-argument callable to be invoked when this |
4090 | - transaction has been reverted. |
4091 | - """ |
4092 | - if not callable(event): |
4093 | - raise ValueError("Events must be callable", event) |
4094 | - self._revertEvents.append(event) |
4095 | - |
4096 | - |
4097 | - def broadcastEvents(self): |
4098 | - """ |
4099 | - Send all normal events. |
4100 | - """ |
4101 | - events = self._events |
4102 | - self._events = self._revertEvents = None |
4103 | - map(apply, events) |
4104 | - |
4105 | - |
4106 | - def broadcastRevertEvents(self): |
4107 | - """ |
4108 | - Send all revert events. |
4109 | - """ |
4110 | - events = self._revertEvents |
4111 | - self._events = self._revertEvents = None |
4112 | - map(apply, events) |
4113 | - |
4114 | - |
4115 | - |
4116 | -def runEventTransaction(store, func, *args, **kwargs): |
4117 | - """ |
4118 | - This takes responsibility for setting up the transactional event |
4119 | - broadcasting junk, handling action errors, and broadcasting commit or |
4120 | - revert events. |
4121 | - """ |
4122 | - broadcaster = TransactionalEventBroadcaster() |
4123 | - def runHelper(): |
4124 | - # Set up event context for the duration of the action |
4125 | - # run. Additionally, handle raised ActionFailures by |
4126 | - # adding their events to the revert event list and |
4127 | - # re-raising them so they will revert the transaction. |
4128 | - try: |
4129 | - return context.call( |
4130 | - {iimaginary.ITransactionalEventBroadcaster: broadcaster}, |
4131 | - func, *args, **kwargs) |
4132 | - except eimaginary.ActionFailure, e: |
4133 | - broadcaster.addRevertEvent(e.event.reify()) |
4134 | - raise |
4135 | - try: |
4136 | - result = store.transact(runHelper) |
4137 | - except eimaginary.ActionFailure: |
4138 | - broadcaster.broadcastRevertEvents() |
4139 | - return None |
4140 | - else: |
4141 | - broadcaster.broadcastEvents() |
4142 | - return result |
4143 | - |
4144 | - |
4145 | - |
4146 | -class ThatDoesntMakeSense(Event): |
4147 | - """ |
4148 | - An action was attempted which is logically impossible. |
4149 | - """ |
4150 | - def __init__(self, actorMessage="That doesn't make sense.", **kw): |
4151 | - super(ThatDoesntMakeSense, self).__init__(actorMessage=actorMessage, **kw) |
4152 | - |
4153 | - |
4154 | -class ThatDoesntWork(Event): |
4155 | - """ |
4156 | - An action was attempted which is phyically impossible. |
4157 | - """ |
4158 | - def __init__(self, actorMessage="That doesn't work.", **kw): |
4159 | - super(ThatDoesntWork, self).__init__(actorMessage=actorMessage, **kw) |
4160 | - |
4161 | - |
4162 | -class Success(Event): |
4163 | - """ |
4164 | - You do it. Swell. |
4165 | - """ |
4166 | - |
4167 | - def broadcast(self): |
4168 | - """ |
4169 | - Don't really broadcast. Add this event to the events which will be |
4170 | - sent when the action (or whatever) execution transaction is committed |
4171 | - successfully. |
4172 | - """ |
4173 | - broadcaster = context.get(iimaginary.ITransactionalEventBroadcaster) |
4174 | - if broadcaster is not None: |
4175 | - broadcaster.addEvent(self.reify()) |
4176 | - else: |
4177 | - self.reify()() |
4178 | - |
4179 | - |
4180 | - |
4181 | -class ArrivalEvent(Success): |
4182 | - """ |
4183 | - An event representing the arrival of an object. |
4184 | - """ |
4185 | - |
4186 | - |
4187 | - |
4188 | -class MovementArrivalEvent(ArrivalEvent): |
4189 | - """ |
4190 | - An event representing the arrival of an object at a location from an |
4191 | - origin. |
4192 | - """ |
4193 | - def __init__(self, thing, origin=None, direction=None): |
4194 | - self.thing = thing |
4195 | - self.origin = origin |
4196 | - self.direction = direction |
4197 | - self.location = self.thing.location |
4198 | - |
4199 | - |
4200 | - def conceptFor(self, observer): |
4201 | - if observer is self.thing: |
4202 | - return None |
4203 | - if self.origin is not None: |
4204 | - msg = [" arrives from ", self.origin, "."] |
4205 | - elif self.direction is not None: |
4206 | - msg = [" arrives from the ", self.direction, "."] |
4207 | - else: |
4208 | - msg = [" arrives."] |
4209 | - msg.insert(0, self.thing) |
4210 | - return language.Sentence(msg) |
4211 | - |
4212 | - |
4213 | - |
4214 | -class DepartureEvent(Success): |
4215 | - """ |
4216 | - An event representing the departure of an object at a location to a |
4217 | - destination. |
4218 | - """ |
4219 | - def __init__(self, location, actor, **kw): |
4220 | - """ |
4221 | - @type location: L{iimaginary.IThing} provider. |
4222 | - @param location: The location that the actor is leaving. |
4223 | - @type actor: L{iimaginary.IThing} provider. |
4224 | - @param actor: The actor that is leaving. |
4225 | - """ |
4226 | - super(DepartureEvent, self).__init__(location, actor, **kw) |
4227 | - |
4228 | - |
4229 | -class SpeechEvent(Success): |
4230 | - """ |
4231 | - An event representing something somebody said. |
4232 | - |
4233 | - @ivar speaker: The Thing which spoke. |
4234 | - @ivar text: The text which was spoken. |
4235 | - """ |
4236 | - def __init__(self, speaker, text): |
4237 | - """ |
4238 | - @type speaker: L{iimaginary.IThing} provider. |
4239 | - @param speaker: The actor emitting this speech. |
4240 | - @type text: C{unicode} |
4241 | - @param text: The text that the actor said. |
4242 | - """ |
4243 | - self.speaker = speaker |
4244 | - self.text = text |
4245 | - Success.__init__( |
4246 | - self, |
4247 | - location=speaker.location, |
4248 | - actor=speaker, |
4249 | - actorMessage=["You say, '", text, "'"], |
4250 | - otherMessage=language.Sentence([speaker, " says, '", text, "'"])) |
4251 | |
4252 | === removed file 'Imaginary/imaginary/garments.py' |
4253 | --- Imaginary/imaginary/garments.py 2011-09-16 18:52:54 +0000 |
4254 | +++ Imaginary/imaginary/garments.py 1970-01-01 00:00:00 +0000 |
4255 | @@ -1,370 +0,0 @@ |
4256 | -# -*- test-case-name: imaginary.test.test_garments -*- |
4257 | - |
4258 | -""" |
4259 | - |
4260 | -Layered clothing. |
4261 | - |
4262 | -""" |
4263 | - |
4264 | -from zope.interface import implements |
4265 | - |
4266 | -from axiom import item, attributes |
4267 | - |
4268 | -from imaginary import iimaginary, language, objects |
4269 | -from imaginary.eimaginary import ActionFailure |
4270 | -from imaginary.events import ThatDoesntWork |
4271 | -from imaginary.idea import Link |
4272 | -from imaginary.creation import createCreator |
4273 | -from imaginary.enhancement import Enhancement |
4274 | - |
4275 | - |
4276 | -class Unwearable(Exception): |
4277 | - pass |
4278 | - |
4279 | -class TooBulky(Unwearable): |
4280 | - def __init__(self, wornGarment, newGarment): |
4281 | - self.wornGarment = wornGarment |
4282 | - self.newGarment = newGarment |
4283 | - Unwearable.__init__(self, wornGarment, newGarment) |
4284 | - |
4285 | - |
4286 | - |
4287 | -class InaccessibleGarment(Exception): |
4288 | - """The garment is covered by another, therefore it cannot be removed. |
4289 | - """ |
4290 | - def __init__(self, wearer, garment, obscuringGarment): |
4291 | - self.wearer = wearer |
4292 | - self.garment = garment |
4293 | - self.obscuringGarment = obscuringGarment |
4294 | - |
4295 | - |
4296 | - def __str__(self): |
4297 | - return "%s tried taking off %s which was covered by %s" % ( |
4298 | - self.wearer, self.garment, self.obscuringGarment) |
4299 | - |
4300 | - |
4301 | - |
4302 | -GARMENT_SLOTS = [ |
4303 | - u"crown", |
4304 | - u"left eye", |
4305 | - u"right eye", |
4306 | - u"left ear", |
4307 | - u"right ear", |
4308 | - |
4309 | - u"neck", |
4310 | - u"chest", |
4311 | - u"back", |
4312 | - |
4313 | - u"left arm", |
4314 | - u"right arm", |
4315 | - u"left wrist", |
4316 | - u"right wrist", |
4317 | - u"left hand", |
4318 | - u"right hand", |
4319 | - u"left fingers", |
4320 | - u"right fingers", |
4321 | - |
4322 | - u"waist", |
4323 | - u"left leg", |
4324 | - u"right leg", |
4325 | - u"left ankle", |
4326 | - u"right ankle", |
4327 | - u"left foot", |
4328 | - u"right foot" |
4329 | - ] |
4330 | - |
4331 | -class GarmentSlot: |
4332 | - pass |
4333 | - |
4334 | -for gslot in GARMENT_SLOTS: |
4335 | - gslotname = gslot.upper().replace(" ", "_").encode('ascii') |
4336 | - setattr(GarmentSlot, gslotname, gslot) |
4337 | - |
4338 | - |
4339 | - |
4340 | -class Garment(item.Item, Enhancement): |
4341 | - """ |
4342 | - An enhancement for a L{Thing} representing its utility as an article of |
4343 | - clothing. |
4344 | - """ |
4345 | - implements(iimaginary.IClothing, |
4346 | - iimaginary.IDescriptionContributor, |
4347 | - iimaginary.IMovementRestriction) |
4348 | - |
4349 | - powerupInterfaces = (iimaginary.IClothing, |
4350 | - iimaginary.IDescriptionContributor, |
4351 | - iimaginary.IMovementRestriction) |
4352 | - |
4353 | - thing = attributes.reference() |
4354 | - |
4355 | - # templated / constant stuff |
4356 | - garmentSlots = attributes.textlist(allowNone=False) |
4357 | - bulk = attributes.integer(allowNone=False, |
4358 | - default=1) |
4359 | - garmentDescription = attributes.text(doc=""" |
4360 | - Description of this as an individual garment. |
4361 | - """, allowNone=False) |
4362 | - |
4363 | - # transient / mutable stuff |
4364 | - wearer = attributes.reference() |
4365 | - wearLevel = attributes.integer(default=0) |
4366 | - |
4367 | - |
4368 | - def conceptualize(self): |
4369 | - return language.ExpressString(u'This can be worn.') |
4370 | - |
4371 | - |
4372 | - def expressTo(self, observer): |
4373 | - """ |
4374 | - Describe the garment as it looks when it is worn. |
4375 | - |
4376 | - The garment's normal description is C{self.thing.description} or |
4377 | - somesuch. |
4378 | - """ |
4379 | - return self.garmentDescription |
4380 | - |
4381 | - |
4382 | - def nowWornBy(self, wearer): |
4383 | - """ |
4384 | - This garment is now worn by the given wearer. As this garment is now |
4385 | - on top, set its C{wearLevel} to be higher than any other L{Garment} |
4386 | - related to the new C{wearer}. |
4387 | - """ |
4388 | - self.wearer = wearer |
4389 | - self.wearLevel = wearer.store.query( |
4390 | - Garment, |
4391 | - Garment.wearer == wearer).getColumn("wearLevel").max(default=0) + 1 |
4392 | - |
4393 | - |
4394 | - def noLongerWorn(self): |
4395 | - """ |
4396 | - This garment is no longer being worn by anyone. |
4397 | - """ |
4398 | - self.wearer = None |
4399 | - self.wearLevel = None |
4400 | - |
4401 | - |
4402 | - def movementImminent(self, movee, destination): |
4403 | - """ |
4404 | - Something is trying to move. Don't allow it if I'm currently worn. |
4405 | - """ |
4406 | - if self.wearer is not None and movee is self.thing: |
4407 | - raise ActionFailure( |
4408 | - ThatDoesntWork( |
4409 | - # XXX I don't actually know who is performing the action |
4410 | - # :-(. |
4411 | - actor=self.wearer.thing, |
4412 | - actorMessage=[ |
4413 | - "You can't move ", |
4414 | - language.Noun(self.thing).definiteNounPhrase(), |
4415 | - " without removing it first."])) |
4416 | - |
4417 | - |
4418 | - |
4419 | -def _orderTopClothingByGlobalSlotList(tempClothes): |
4420 | - """ |
4421 | - This function orders a dict as returned by getGarmentDict in the order that |
4422 | - they should be shown to the user. |
4423 | - |
4424 | - @param tempClothes: {clothingSlot: list of clothing objects (top last)} |
4425 | - @type tempClothes: dict |
4426 | - """ |
4427 | - if not tempClothes: |
4428 | - return None |
4429 | - yetDescribed = [] |
4430 | - for universalSlot in GARMENT_SLOTS: |
4431 | - slotlist = tempClothes.pop(universalSlot, ()) |
4432 | - if slotlist: |
4433 | - topGarment = slotlist[-1] |
4434 | - if topGarment not in yetDescribed: |
4435 | - yetDescribed.append(topGarment) |
4436 | - |
4437 | - # if somebody decided to make a wacky slot that is not in the universal |
4438 | - # slots list, just describe it last. |
4439 | - for k in tempClothes.keys(): |
4440 | - x = tempClothes.pop(k) |
4441 | - if x: |
4442 | - topGarment = x[-1] |
4443 | - if topGarment not in yetDescribed: |
4444 | - yetDescribed.append(topGarment) |
4445 | - |
4446 | - assert tempClothes == {}, ( |
4447 | - "tempClothes not empty after all clothes eliminated: " + |
4448 | - repr(tempClothes)) |
4449 | - |
4450 | - return yetDescribed |
4451 | - |
4452 | - |
4453 | - |
4454 | -class Wearer(item.Item, Enhancement): |
4455 | - """ |
4456 | - The clothing-wearing component of an object that can wear clothing; e.g. a |
4457 | - person or mannequin. |
4458 | - """ |
4459 | - |
4460 | - _interfaces = (iimaginary.IClothingWearer, |
4461 | - iimaginary.IDescriptionContributor, |
4462 | - iimaginary.ILinkContributor, |
4463 | - iimaginary.ILinkAnnotator, |
4464 | - ) |
4465 | - |
4466 | - implements(*_interfaces) |
4467 | - |
4468 | - powerupInterfaces = _interfaces |
4469 | - |
4470 | - |
4471 | - thing = attributes.reference() |
4472 | - |
4473 | - |
4474 | - def getGarmentDict(self): |
4475 | - c = {} |
4476 | - for garment in self.store.query(Garment, Garment.wearer == self, |
4477 | - sort=Garment.wearLevel.ascending): |
4478 | - for usedSlot in garment.garmentSlots: |
4479 | - c.setdefault(usedSlot, []).append(garment) |
4480 | - return c |
4481 | - |
4482 | - |
4483 | - def putOn(self, newGarment): |
4484 | - """ |
4485 | - Wear a new L{Garment} on this L{Wearer}, first moving it to this |
4486 | - L{Wearer}'s C{thing} if it is not already there. |
4487 | - |
4488 | - @param newGarment: the article of clothing to wear. |
4489 | - |
4490 | - @type newGarment: L{Garment} |
4491 | - |
4492 | - @raise TooBulky: if the bulk of any of the slots occupied by |
4493 | - C{newGarment} is greater than the bulk of any other clothing |
4494 | - already in that slot. (For example, if you tried to wear a T-shirt |
4495 | - over a heavy coat.) |
4496 | - """ |
4497 | - c = self.getGarmentDict() |
4498 | - for garmentSlot in newGarment.garmentSlots: |
4499 | - if garmentSlot in c: |
4500 | - currentTopOfSlot = c[garmentSlot][-1] |
4501 | - if currentTopOfSlot.bulk >= newGarment.bulk: |
4502 | - raise TooBulky(currentTopOfSlot, newGarment) |
4503 | - |
4504 | - newGarment.thing.moveTo(self.thing) |
4505 | - newGarment.nowWornBy(self) |
4506 | - |
4507 | - |
4508 | - def takeOff(self, garment): |
4509 | - """ |
4510 | - Remove a garment which this player is wearing. |
4511 | - |
4512 | - (Note: no error checking is currently performed to see if this garment |
4513 | - is actually already worn by this L{Wearer}.) |
4514 | - |
4515 | - @param garment: the article of clothing to remove. |
4516 | - |
4517 | - @type garment: L{Garment} |
4518 | - |
4519 | - @raise InaccessibleGarment: if the garment is obscured by any other |
4520 | - clothing, and is therefore not in the top slot for any of the slots |
4521 | - it occupies. For example, if you put on an undershirt, then a |
4522 | - turtleneck, you can't remove the undershirt without removing the |
4523 | - turtleneck first. |
4524 | - """ |
4525 | - gdict = self.getGarmentDict() |
4526 | - for slot in garment.garmentSlots: |
4527 | - if gdict[slot][-1] is not garment: |
4528 | - raise InaccessibleGarment(self, garment, gdict[slot][-1]) |
4529 | - garment.noLongerWorn() |
4530 | - |
4531 | - |
4532 | - # IDescriptionContributor |
4533 | - def conceptualize(self): |
4534 | - """ |
4535 | - Describe the list of clothing. |
4536 | - """ |
4537 | - return ExpressClothing(self.thing, self.getGarmentDict()) |
4538 | - |
4539 | - |
4540 | - # ILinkContributor |
4541 | - def links(self): |
4542 | - for garmentThing in self.store.query(objects.Thing, |
4543 | - attributes.AND( |
4544 | - Garment.thing == objects.Thing.storeID, |
4545 | - Garment.wearer == self)): |
4546 | - yield Link(self.thing.idea, garmentThing.idea) |
4547 | - |
4548 | - |
4549 | - # ILinkAnnotator |
4550 | - def annotationsFor(self, link, idea): |
4551 | - """ |
4552 | - Tell the containment system to disregard containment relationships for |
4553 | - which I will generate a link. |
4554 | - """ |
4555 | - if list(link.of(iimaginary.IContainmentRelationship)): |
4556 | - if link.source.delegate is self.thing: |
4557 | - clothing = iimaginary.IClothing(link.target.delegate, None) |
4558 | - if clothing is not None: |
4559 | - if clothing.wearer is self: |
4560 | - yield _DisregardYourWearingIt() |
4561 | - |
4562 | - |
4563 | - |
4564 | -class _DisregardYourWearingIt(object): |
4565 | - """ |
4566 | - This is an annotation, produced by L{Wearer} for containment relationships |
4567 | - between people (who are containers) and the clothing that they're wearing. |
4568 | - A hopefully temporary workaround for the fact that clothing is rendered in |
4569 | - its own way and therefor shouldn't show up in the list of a person's |
4570 | - contents. |
4571 | - """ |
4572 | - implements(iimaginary.IElectromagneticMedium) |
4573 | - |
4574 | - def isOpaque(self): |
4575 | - """ |
4576 | - I am opaque, so that clothing will show up only once (in your "wearing" |
4577 | - list, rather than there and in your "contained" list), and obscured |
4578 | - clothing won't show up at all. |
4579 | - """ |
4580 | - return True |
4581 | - |
4582 | - |
4583 | - |
4584 | -class ExpressClothing(language.BaseExpress): |
4585 | - def __init__(self, thing, garments): |
4586 | - self.thing = thing |
4587 | - self.garments = garments |
4588 | - |
4589 | - |
4590 | - def vt102(self, observer): |
4591 | - heshe = language.Noun(self.thing).heShe() |
4592 | - L = _orderTopClothingByGlobalSlotList(self.garments) |
4593 | - if L is None: |
4594 | - return language.Sentence([heshe, u' is naked.']).vt102(observer) |
4595 | - return language.Sentence([ |
4596 | - heshe, |
4597 | - u' is wearing ', |
4598 | - language.ItemizedList([language.Noun(g.thing).nounPhrase() |
4599 | - for g in L]), |
4600 | - u'.']).vt102(observer) |
4601 | - |
4602 | - |
4603 | - |
4604 | -createShirt = createCreator( |
4605 | - (Garment, dict(garmentDescription=u'an undescribed shirt', |
4606 | - bulk=2, |
4607 | - garmentSlots=[GarmentSlot.CHEST, |
4608 | - GarmentSlot.BACK, |
4609 | - GarmentSlot.RIGHT_ARM, |
4610 | - GarmentSlot.LEFT_ARM]))) |
4611 | - |
4612 | - |
4613 | -createUnderwear = createCreator( |
4614 | - (Garment, dict(garmentDescription=u'an undescribed pair of underwear', |
4615 | - bulk=1, |
4616 | - garmentSlots=[GarmentSlot.WAIST]))) |
4617 | - |
4618 | -createPants = createCreator( |
4619 | - (Garment, dict(garmentDescription=u'an undescribed pair of pants', |
4620 | - bulk=2, |
4621 | - garmentSlots=[GarmentSlot.RIGHT_LEG, |
4622 | - GarmentSlot.LEFT_LEG, |
4623 | - GarmentSlot.WAIST, |
4624 | - GarmentSlot.LEFT_ANKLE, |
4625 | - GarmentSlot.RIGHT_ANKLE]))) |
4626 | |
4627 | === removed file 'Imaginary/imaginary/idea.py' |
4628 | --- Imaginary/imaginary/idea.py 2010-04-24 18:00:14 +0000 |
4629 | +++ Imaginary/imaginary/idea.py 1970-01-01 00:00:00 +0000 |
4630 | @@ -1,625 +0,0 @@ |
4631 | -# -*- test-case-name: imaginary -*- |
4632 | - |
4633 | -""" |
4634 | -This module implements a highly abstract graph-traversal system for actions and |
4635 | -events to locate the objects which can respond to them. The top-level |
4636 | -entry-point to this system is L{Idea.obtain}. |
4637 | - |
4638 | -It also implements several basic retrievers related to visibility and physical |
4639 | -reachability. |
4640 | -""" |
4641 | - |
4642 | -from zope.interface import implements |
4643 | -from epsilon.structlike import record |
4644 | - |
4645 | -from imaginary.iimaginary import ( |
4646 | - INameable, ILitLink, IThing, IObstruction, IElectromagneticMedium, |
4647 | - IDistance, IRetriever, IExit) |
4648 | - |
4649 | - |
4650 | - |
4651 | -class Link(record("source target")): |
4652 | - """ |
4653 | - A L{Link} is a connection between two L{Idea}s in a L{Path}. |
4654 | - |
4655 | - @ivar source: the idea that this L{Link} originated from. |
4656 | - @type source: L{Idea} |
4657 | - |
4658 | - @ivar target: the idea that this L{Link} refers to. |
4659 | - @type target: L{Idea} |
4660 | - """ |
4661 | - |
4662 | - def __init__(self, *a, **k): |
4663 | - super(Link, self).__init__(*a, **k) |
4664 | - self.annotations = [] |
4665 | - |
4666 | - |
4667 | - def annotate(self, annotations): |
4668 | - """ |
4669 | - Annotate this link with a list of annotations. |
4670 | - """ |
4671 | - self.annotations.extend(annotations) |
4672 | - |
4673 | - |
4674 | - def of(self, interface): |
4675 | - """ |
4676 | - Yield all annotations on this link which provide the given interface. |
4677 | - """ |
4678 | - for annotation in self.annotations: |
4679 | - provider = interface(annotation, None) |
4680 | - if provider is not None: |
4681 | - yield provider |
4682 | - |
4683 | - |
4684 | - |
4685 | -class Path(record('links')): |
4686 | - """ |
4687 | - A list of L{Link}s. |
4688 | - """ |
4689 | - |
4690 | - def of(self, interface): |
4691 | - """ |
4692 | - @return: an iterator of providers of interfaces, adapted from each link |
4693 | - in this path. |
4694 | - """ |
4695 | - for link in self.links: |
4696 | - for annotation in link.of(interface): |
4697 | - yield annotation |
4698 | - |
4699 | - |
4700 | - def eachTargetAs(self, interface): |
4701 | - """ |
4702 | - @return: an iterable of all non-None results of each L{Link.targetAs} |
4703 | - method in this L{Path}'s C{links} attribute. |
4704 | - """ |
4705 | - for link in self.links: |
4706 | - provider = interface(link.target.delegate, None) |
4707 | - if provider is not None: |
4708 | - yield provider |
4709 | - |
4710 | - |
4711 | - def targetAs(self, interface): |
4712 | - """ |
4713 | - Retrieve the target of the last link of this path, its final |
4714 | - destination, as a given interface. |
4715 | - |
4716 | - @param interface: the interface to retrieve. |
4717 | - @type interface: L{zope.interface.interfaces.IInterface} |
4718 | - |
4719 | - @return: the last link's target, adapted to the given interface, or |
4720 | - C{None} if no appropriate adapter or component exists. |
4721 | - @rtype: C{interface} or C{NoneType} |
4722 | - """ |
4723 | - return interface(self.links[-1].target.delegate, None) |
4724 | - |
4725 | - |
4726 | - def isCyclic(self): |
4727 | - """ |
4728 | - Determine if this path is cyclic, to avoid descending down infinite |
4729 | - loops. |
4730 | - |
4731 | - @return: a boolean indicating whether this L{Path} is cyclic or not, |
4732 | - i.e. whether the L{Idea} its last link points at is the source of |
4733 | - any of its links. |
4734 | - """ |
4735 | - if len(self.links) < 2: |
4736 | - return False |
4737 | - return (self.links[-1].target in (x.source for x in self.links)) |
4738 | - |
4739 | - |
4740 | - def to(self, link): |
4741 | - """ |
4742 | - Create a new path, extending this one by one new link. |
4743 | - """ |
4744 | - return Path(self.links + [link]) |
4745 | - |
4746 | - |
4747 | - def __repr__(self): |
4748 | - """ |
4749 | - @return: an expanded pretty-printed representation of this Path, |
4750 | - suitable for debugging. |
4751 | - """ |
4752 | - s = 'Path(' |
4753 | - for link in self.links: |
4754 | - dlgt = link.target.delegate |
4755 | - src = link.source.delegate |
4756 | - s += "\n\t" |
4757 | - s += repr(getattr(src, 'name', src)) |
4758 | - s += " => " |
4759 | - s += repr(getattr(dlgt, 'name', dlgt)) |
4760 | - s += " " |
4761 | - s += repr(link.annotations) |
4762 | - s += ')' |
4763 | - return s |
4764 | - |
4765 | - |
4766 | - |
4767 | -class Idea(record("delegate linkers annotators")): |
4768 | - """ |
4769 | - Consider a person's activities with the world around them as having two |
4770 | - layers. One is a physical layer, out in the world, composed of matter and |
4771 | - energy. The other is a cognitive layer, internal to the person, composed |
4772 | - of ideas about that matter and energy. |
4773 | - |
4774 | - For example, when a person wants to sit in a wooden chair, they must first |
4775 | - visually locate the arrangement of wood in question, make the determination |
4776 | - of that it is a "chair" based on its properties, and then perform the |
4777 | - appropriate actions to sit upon it. |
4778 | - |
4779 | - However, a person may also interact with symbolic abstractions rather than |
4780 | - physical objects. They may read a word, or point at a window on a computer |
4781 | - screen. An L{Idea} is a representation of the common unit that can be |
4782 | - referred to in this way. |
4783 | - |
4784 | - Both physical and cognitive layers are present in Imaginary. The cognitive |
4785 | - layer is modeled by L{imaginary.idea}. The physical layer is modeled by a |
4786 | - rudimentary point-of-interest simulation in L{imaginary.objects}. An |
4787 | - L{imaginary.thing.Thing} is a physical object; an L{Idea} is a node in a |
4788 | - non-physical graph, related by links that are annotated to describe the |
4789 | - nature of the relationship between it and other L{Idea}s. |
4790 | - |
4791 | - L{Idea} is the most abstract unit of simulation. It does not have any |
4792 | - behavior or simulation semantics of its own; it merely ties together |
4793 | - different related systems. |
4794 | - |
4795 | - An L{Idea} is composed of a C{delegate}, which is an object that implements |
4796 | - simulation-defined interfaces; a list of L{ILinkContributor}s, which |
4797 | - produce L{Link}s to other L{Idea}s, an a set of C{ILinkAnnotator}s, which |
4798 | - apply annotations (which themselves implement simulation-defined |
4799 | - link-annotation interfaces) to those links. |
4800 | - |
4801 | - Each L{imaginary.thing.Thing} has a corresponding L{Idea} to represent it |
4802 | - in the simulation. The physical simulation defines only a few types of |
4803 | - links: objects have links to their containers, containers have links to |
4804 | - their contents, rooms have links to their exits, exits have links to their |
4805 | - destinations. Any L{imaginary.thing.Thing} can have a powerup applied to |
4806 | - it which adds to the list of linkers or annotators for its L{Idea}, |
4807 | - however, which allows users to create arbitrary objects. |
4808 | - |
4809 | - For example, the target of the "look" action must implement |
4810 | - L{imaginary.iimaginary.IVisible}, but need not be a |
4811 | - L{iimaginary.objects.Thing}. A simulation might want to provide a piece of |
4812 | - graffiti that you could look at, but would not be a physical object, in the |
4813 | - sense that you couldn't pick it up, weigh it, push it, etc. Such an object |
4814 | - could be implemented as a powerup for both |
4815 | - L{imaginary.iimaginary.IDescriptionContributor}, which would impart some |
4816 | - short flavor text to the room, and L{imaginary.iimaginary.IVisible}, which |
4817 | - would be an acceptable target of 'look'. The |
4818 | - L{imaginary.iimaginary.IVisible} implementation could even be an in-memory |
4819 | - object, not stored in the database at all; and there could be different |
4820 | - implementations for different observers, depending on their level of |
4821 | - knowledge about the in-world graffiti. |
4822 | - |
4823 | - @ivar delegate: this object is the object which may be adaptable to a set |
4824 | - of interfaces. This L{Idea} delegates all adaptation to its delegate. |
4825 | - In many cases (when referring to a physical object), this will be an |
4826 | - L{imaginary.thing.Thing}, but not necessarily. |
4827 | - |
4828 | - @ivar linkers: a L{list} of L{ILinkContributor}s which are used to gather |
4829 | - L{Link}s from this L{Idea} during L{Idea.obtain} traversal. |
4830 | - |
4831 | - @ivar annotators: a L{list} of L{ILinkAnnotator}s which are used to annotate |
4832 | - L{Link}s gathered from this L{Idea} via the C{linkers} list. |
4833 | - """ |
4834 | - |
4835 | - def __init__(self, delegate): |
4836 | - super(Idea, self).__init__(delegate, [], []) |
4837 | - |
4838 | - |
4839 | - def _allLinks(self): |
4840 | - """ |
4841 | - Return an iterator of all L{Links} away from this idea. |
4842 | - """ |
4843 | - for linker in self.linkers: |
4844 | - for link in linker.links(): |
4845 | - yield link |
4846 | - |
4847 | - |
4848 | - def _applyAnnotators(self, linkiter): |
4849 | - """ |
4850 | - Apply my list of annotators to each link in the given iterable. |
4851 | - """ |
4852 | - for link in linkiter: |
4853 | - self._annotateOneLink(link) |
4854 | - yield link |
4855 | - |
4856 | - |
4857 | - def _annotateOneLink(self, link): |
4858 | - """ |
4859 | - Apply all L{ILinkAnnotator}s in this L{Idea}'s C{annotators} list. |
4860 | - """ |
4861 | - allAnnotations = [] |
4862 | - for annotator in self.annotators: |
4863 | - # XXX important to test: annotators shouldn't mutate the links. |
4864 | - # The annotators show up in a non-deterministic order, so in order |
4865 | - # to facilitate a consistent view of the link in annotationsFor(), |
4866 | - # all annotations are applied at the end. |
4867 | - allAnnotations.extend(annotator.annotationsFor(link, self)) |
4868 | - link.annotate(allAnnotations) |
4869 | - |
4870 | - |
4871 | - def obtain(self, retriever): |
4872 | - """ |
4873 | - Traverse the graph of L{Idea}s, starting with C{self}, looking for |
4874 | - objects which the given L{IRetriever} can retrieve. |
4875 | - |
4876 | - The graph will be traversed by looking at all the links generated by |
4877 | - this L{Idea}'s C{linkers}, only continuing down those links for which |
4878 | - the given L{IRetriever}'s C{shouldKeepGoing} returns L{True}. |
4879 | - |
4880 | - @param retriever: an object which will be passed each L{Path} in turn, |
4881 | - discovered during traversal of the L{Idea} graph. If any |
4882 | - invocation of L{IRetriever.retrieve} on this parameter should |
4883 | - succeed, that will be yielded as a result from this method. |
4884 | - @type retriever: L{IRetriever} |
4885 | - |
4886 | - @return: a generator which yields the results of C{retriever.retrieve} |
4887 | - which are not L{None}. |
4888 | - """ |
4889 | - return ObtainResult(self, retriever) |
4890 | - |
4891 | - |
4892 | - def _doObtain(self, retriever, path, reasonsWhyNot): |
4893 | - """ |
4894 | - A generator that implements the logic for obtain() |
4895 | - """ |
4896 | - if path is None: |
4897 | - # Special case: we only get a self->self link if we are the |
4898 | - # beginning _and_ the end. |
4899 | - path = Path([]) |
4900 | - selfLink = Link(self, self) |
4901 | - self._annotateOneLink(selfLink) |
4902 | - finalPath = path.to(selfLink) |
4903 | - else: |
4904 | - finalPath = Path(path.links[:]) |
4905 | - self._annotateOneLink(finalPath.links[-1]) |
4906 | - |
4907 | - result = retriever.retrieve(finalPath) |
4908 | - objections = set(retriever.objectionsTo(finalPath, result)) |
4909 | - reasonsWhyNot |= objections |
4910 | - if result is not None: |
4911 | - if not objections: |
4912 | - yield result |
4913 | - |
4914 | - for link in self._applyAnnotators(self._allLinks()): |
4915 | - subpath = path.to(link) |
4916 | - if subpath.isCyclic(): |
4917 | - continue |
4918 | - if retriever.shouldKeepGoing(subpath): |
4919 | - for obtained in link.target._doObtain(retriever, subpath, reasonsWhyNot): |
4920 | - yield obtained |
4921 | - |
4922 | - |
4923 | - |
4924 | -class ObtainResult(record("idea retriever")): |
4925 | - """ |
4926 | - The result of L{Idea.obtain}, this provides an iterable of results. |
4927 | - |
4928 | - @ivar reasonsWhyNot: If this iterator has already been exhausted, this will |
4929 | - be a C{set} of L{IWhyNot} objects explaining possible reasons why there |
4930 | - were no results. For example, if the room where the player attempted |
4931 | - to obtain targets is dark, this may contain an L{IWhyNot} provider. |
4932 | - However, until this iterator has been exhausted, it will be C{None}. |
4933 | - @type reasonsWhyNot: C{set} of L{IWhyNot}, or C{NoneType} |
4934 | - |
4935 | - @ivar idea: the L{Idea} that L{Idea.obtain} was invoked on. |
4936 | - @type idea: L{Idea} |
4937 | - |
4938 | - @ivar retriever: The L{IRetriever} that L{Idea.obtain} was invoked with. |
4939 | - @type retriever: L{IRetriever} |
4940 | - """ |
4941 | - |
4942 | - reasonsWhyNot = None |
4943 | - |
4944 | - def __iter__(self): |
4945 | - """ |
4946 | - A generator which yields each result of the query, then sets |
4947 | - C{reasonsWhyNot}. |
4948 | - """ |
4949 | - reasonsWhyNot = set() |
4950 | - for result in self.idea._doObtain(self.retriever, None, reasonsWhyNot): |
4951 | - yield result |
4952 | - self.reasonsWhyNot = reasonsWhyNot |
4953 | - |
4954 | - |
4955 | - |
4956 | -class DelegatingRetriever(object): |
4957 | - """ |
4958 | - A delegating retriever, so that retrievers can be easily composed. |
4959 | - |
4960 | - See the various methods marked for overriding. |
4961 | - |
4962 | - @ivar retriever: A retriever to delegate most operations to. |
4963 | - @type retriever: L{IRetriever} |
4964 | - """ |
4965 | - |
4966 | - implements(IRetriever) |
4967 | - |
4968 | - def __init__(self, retriever): |
4969 | - """ |
4970 | - Create a delegator with a retriever to delegate to. |
4971 | - """ |
4972 | - self.retriever = retriever |
4973 | - |
4974 | - |
4975 | - def moreObjectionsTo(self, path, result): |
4976 | - """ |
4977 | - Override in subclasses to yield objections to add to this |
4978 | - L{DelegatingRetriever}'s C{retriever}'s C{objectionsTo}. |
4979 | - |
4980 | - By default, offer no additional objections. |
4981 | - """ |
4982 | - return [] |
4983 | - |
4984 | - |
4985 | - def objectionsTo(self, path, result): |
4986 | - """ |
4987 | - Concatenate C{self.moreObjectionsTo} with C{self.moreObjectionsTo}. |
4988 | - """ |
4989 | - for objection in self.retriever.objectionsTo(path, result): |
4990 | - yield objection |
4991 | - for objection in self.moreObjectionsTo(path, result): |
4992 | - yield objection |
4993 | - |
4994 | - |
4995 | - def shouldStillKeepGoing(self, path): |
4996 | - """ |
4997 | - Override in subclasses to halt traversal via a C{False} return value for |
4998 | - C{shouldKeepGoing} if this L{DelegatingRetriever}'s C{retriever}'s |
4999 | - C{shouldKeepGoing} returns C{True}. |
5000 | - |
The diff has been truncated for viewing.
Looks good, please merge (I'm assuming you have commit access to lp:divmod.org; let me know if this isn't the case).