Merge lp:~ashfall/divmod.org/1320678-remove-imaginary into lp:divmod.org

Proposed by Ashwini Oruganti on 2014-05-18
Status: Merged
Approved by: Tristan Seligmann on 2014-06-07
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
Reviewer Review Type Date Requested Status
Tristan Seligmann 2014-05-18 Approve on 2014-06-07
Review via email: mp+219969@code.launchpad.net

Description of the change

Removes Imaginary from lp:divmod.org

To post a comment you must log in.
Tristan Seligmann (mithrandi) wrote :

Looks good, please merge (I'm assuming you have commit access to lp:divmod.org; let me know if this isn't the case).

review: Approve

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.

Subscribers

People subscribed via source and target branches

to all changes: