3 http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/index_e.html
6 from __future__
import division
8 from xml
.etree
.ElementTree
import ElementTree
11 from cStringIO
import StringIO
13 from StringIO
import StringIO
15 from bulletml
.errors
import Error
16 from bulletml
.expr
import NumberDef
, INumberDef
18 class ParseError(Error
):
19 """Raised when an error occurs parsing the XML structure."""
23 """Strip namespace poop off the front of a tag."""
25 return element
.tag
.rsplit('}', 1)[1]
29 class ParamList(object):
30 """List of parameter definitions."""
31 def __init__(self
, element
):
34 for subelem
in element
:
35 if realtag(subelem
) == "param":
36 self
.params
.append(NumberDef(subelem
.text
))
38 def __call__(self
, params
, rank
):
39 return [param(params
, rank
) for param
in self
.params
]
42 return "%s(%r)" % (type(self
).__name
__, self
.params
)
44 class Direction(object):
45 """Raw direction value."""
47 def __init__(self
, doc
, element
, type="absolute"):
48 self
.type = element
.get("type", type)
49 self
.value
= NumberDef(element
.text
)
51 def __call__(self
, params
, rank
):
52 return (self
.value(params
, rank
), self
.type)
55 return "%s(%r, type=%r)" % (
56 type(self
).__name
__, self
.value
, self
.type)
58 class ChangeDirection(object):
59 """Direction change over time."""
61 def __init__(self
, doc
, element
):
62 for subelem
in element
.getchildren():
63 tag
= realtag(subelem
)
64 if tag
== "direction":
65 self
.direction
= Direction(doc
, subelem
)
67 self
.term
= INumberDef(subelem
.text
)
69 self
.term
, self
.direction
70 except AttributeError:
73 def __call__(self
, params
, rank
):
74 return self
.term(params
, rank
), self
.direction(params
, rank
)
77 return "%s(term=%r, direction=%r)" % (
78 type(self
).__name
__, self
.term
, self
.direction
)
81 """Raw speed value."""
83 def __init__(self
, doc
, element
, type="absolute"):
84 self
.type = element
.get("type", type)
85 self
.value
= NumberDef(element
.text
)
87 def __call__(self
, params
, rank
):
88 return (self
.value(params
, rank
), self
.type)
91 return "%s(%r, type=%r)" % (type(self
).__name
__, self
.value
, self
.type)
93 class ChangeSpeed(object):
94 """Speed change over time."""
96 def __init__(self
, doc
, element
):
97 for subelem
in element
.getchildren():
98 tag
= realtag(subelem
)
100 self
.speed
= Speed(doc
, subelem
)
102 self
.term
= INumberDef(subelem
.text
)
104 self
.term
, self
.speed
105 except AttributeError:
108 def __call__(self
, params
, rank
):
109 return self
.term(params
, rank
), self
.speed(params
, rank
)
112 return "%s(term=%r, speed=%r)" % (
113 type(self
).__name
__, self
.term
, self
.speed
)
116 """Wait for some frames."""
117 def __init__(self
, doc
, element
):
118 self
.frames
= INumberDef(element
.text
)
120 def __call__(self
, params
, rank
):
121 return self
.frames(params
, rank
)
124 return "%s(%r)" % (type(self
).__name
__, self
.frames
)
126 class Vanish(object):
127 """Make the owner disappear."""
128 def __init__(self
, doc
, element
):
132 return "%s()" % (type(self
).__name
__)
134 class Repeat(object):
135 """Repeat an action definition."""
137 def __init__(self
, doc
, element
):
138 for subelem
in element
.getchildren():
139 tag
= realtag(subelem
)
141 self
.times
= INumberDef(subelem
.text
)
142 elif tag
== "action":
143 self
.action
= ActionDef(doc
, subelem
)
144 elif tag
== "actionRef":
145 self
.action
= ActionRef(doc
, subelem
)
148 self
.times
, self
.action
149 except AttributeError:
152 def __call__(self
, params
, rank
):
153 return self
.times(params
, rank
), self
.action(params
, rank
)
156 return "%s(%r, %r)" % (type(self
).__name
__, self
.times
, self
.action
)
159 """Accelerate over some time."""
164 def __init__(self
, doc
, element
):
165 for subelem
in element
.getchildren():
166 tag
= realtag(subelem
)
168 self
.term
= INumberDef(subelem
.text
)
169 elif tag
== "horizontal":
170 self
.horizontal
= Speed(doc
, subelem
)
171 elif tag
== "vertical":
172 self
.vertical
= Speed(doc
, subelem
)
176 except AttributeError:
179 def __call__(self
, params
, rank
):
180 frames
= self
.term(params
, rank
)
181 horizontal
= self
.horizontal
and self
.horizontal(params
, rank
)
182 vertical
= self
.vertical
and self
.vertical(params
, rank
)
183 return frames
, horizontal
, vertical
186 return "%s(%r, horizontal=%r, vertical=%r)" % (
187 type(self
).__name
__, self
.term
, self
.horizontal
, self
.vertical
)
189 class BulletDef(object):
190 """Bullet definition."""
195 def __init__(self
, doc
, element
):
197 doc
.bullets
[element
.get("label")] = self
198 for subelem
in element
.getchildren():
199 tag
= realtag(subelem
)
200 if tag
== "direction":
201 self
.direction
= Direction(doc
, subelem
)
203 self
.speed
= Speed(doc
, subelem
)
204 elif tag
== "action":
205 self
.actions
.append(ActionDef(doc
, subelem
))
206 elif tag
== "actionRef":
207 self
.actions
.append(ActionRef(doc
, subelem
))
209 def __call__(self
, params
, rank
):
210 actions
= [action(params
, rank
) for action
in self
.actions
]
212 self
.direction
and self
.direction(params
, rank
),
213 self
.speed
and self
.speed(params
, rank
),
217 return "%s(direction=%r, speed=%r, actions=%r)" % (
218 type(self
).__name
__, self
.direction
, self
.speed
, self
.actions
)
220 class BulletRef(object):
221 """Create a bullet by name with parameters."""
223 def __init__(self
, doc
, element
):
224 self
.bullet
= element
.get("label")
225 self
.params
= ParamList(element
)
226 doc
._bullet
_refs
.append(self
)
228 def __call__(self
, params
, rank
):
229 return self
.bullet(self
.params(params
, rank
), rank
)
232 return "%s(params=%r, bullet=%r)" % (
233 type(self
).__name
__, self
.params
, self
.bullet
)
235 class ActionDef(object):
236 """Action definition."""
238 def __init__(self
, doc
, element
):
239 doc
.actions
[element
.get("label")] = self
241 for subelem
in element
.getchildren():
242 tag
= realtag(subelem
)
248 changeSpeed
=ChangeSpeed
,
249 changeDirection
=ChangeDirection
,
254 actionRef
=ActionRef
)[tag
]
258 self
.actions
.append(ctr(doc
, subelem
))
260 def __call__(self
, params
, rank
):
261 return self
.actions
, params
264 return "%s(%r)" % (type(self
).__name
__, self
.actions
)
266 class ActionRef(object):
267 """Run an action by name with parameters."""
269 def __init__(self
, doc
, element
):
270 self
.action
= element
.get("label")
271 self
.params
= ParamList(element
)
272 doc
._action
_refs
.append(self
)
274 def __call__(self
, params
, rank
):
275 return self
.action(self
.params(params
, rank
), rank
)
278 return "%s(params=%r, action=%r)" % (
279 type(self
).__name
__, self
.params
, self
.action
)
281 class FireDef(object):
282 """Fire definition (creates a bullet)."""
287 def __init__(self
, doc
, element
):
288 doc
.fires
[element
.get("label")] = self
289 for subelem
in element
.getchildren():
290 tag
= realtag(subelem
)
291 if tag
== "direction":
292 self
.direction
= Direction(doc
, subelem
, "aim")
294 self
.speed
= Speed(doc
, subelem
)
295 elif tag
== "bullet":
296 self
.bullet
= BulletDef(doc
, subelem
)
297 elif tag
== "bulletRef":
298 self
.bullet
= BulletRef(doc
, subelem
)
301 except AttributeError:
304 def __call__(self
, params
, rank
):
305 direction
, speed
, actions
= self
.bullet(params
, rank
)
307 direction
= self
.direction(params
, rank
)
309 speed
= self
.speed(params
, rank
)
310 return direction
, speed
, actions
313 return "%s(direction=%r, speed=%r, bullet=%r)" % (
314 type(self
).__name
__, self
.direction
, self
.speed
, self
.bullet
)
316 class FireRef(object):
317 """Fire a bullet by name with parameters."""
319 def __init__(self
, doc
, element
):
320 self
.fire
= element
.get("label")
321 self
.params
= ParamList(element
)
322 doc
._fire
_refs
.append(self
)
324 def __call__(self
, params
, rank
):
325 """Generate a Bullet from the FireDef and params."""
326 return self
.fire(self
.params(params
, rank
), rank
)
329 return "%s(params=%r, fire=%r)" % (
330 type(self
).__name
__, self
.params
, self
.fire
)
332 class BulletML(object):
333 """BulletML document.
335 A BulletML document is a collection of bullets, actions, and
336 firings, as well as a base game type.
345 def __init__(self
, source
):
350 self
._bullet
_refs
= []
351 self
._action
_refs
= []
354 if isinstance(source
, (str, unicode)):
355 source
= StringIO(source
)
358 root
= tree
.parse(source
)
360 self
.type = root
.get("type", "none")
362 for element
in root
.getchildren():
363 tag
= realtag(element
)
364 if tag
in self
.CONSTRUCTORS
:
365 self
.CONSTRUCTORS
[tag
](self
, element
)
368 for ref
in self
._bullet
_refs
:
369 ref
.bullet
= self
.bullets
[ref
.bullet
]
370 for ref
in self
._fire
_refs
:
371 ref
.fire
= self
.fires
[ref
.fire
]
372 for ref
in self
._action
_refs
:
373 ref
.action
= self
.actions
[ref
.action
]
374 except KeyError as exc
:
375 raise ParseError("unknown reference %s" % exc
)
377 del(self
._bullet
_refs
)
378 del(self
._action
_refs
)
383 """Get a list of all top-level actions."""
384 return [dfn
for name
, dfn
in self
.actions
.iteritems()
385 if name
and name
.startswith("top")]
388 return "%s(type=%r, bullets=%r, actions=%r, fires=%r)" % (
389 type(self
).__name
__, self
.type, self
.bullets
, self
.actions
,