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 new_params
= [param(params
, rank
) for param
in self
.params
]
40 while len(new_params
) < len(params
):
41 new_params
.append(params
[len(new_params
)])
45 return "%s(%r)" % (type(self
).__name
__, self
.params
)
47 class Direction(object):
48 """Raw direction value."""
50 def __init__(self
, doc
, element
, type="absolute"):
51 self
.type = element
.get("type", type)
52 self
.value
= NumberDef(element
.text
)
54 def __call__(self
, params
, rank
):
55 return self
.value(params
, rank
)
58 return "%s(%r, type=%r)" % (
59 type(self
).__name
__, self
.value
, self
.type)
61 class ChangeDirection(object):
62 """Direction change over time."""
64 def __init__(self
, doc
, element
):
65 for subelem
in element
.getchildren():
66 tag
= realtag(subelem
)
67 if tag
== "direction":
68 self
.direction
= Direction(doc
, subelem
)
70 self
.term
= INumberDef(subelem
.text
)
72 self
.term
, self
.direction
73 except AttributeError:
76 def __call__(self
, params
, rank
):
77 return self
.term(params
, rank
), self
.direction(params
, rank
)
80 return "%s(term=%r, direction=%r)" % (
81 type(self
).__name
__, self
.term
, self
.direction
)
84 """Raw speed value."""
86 def __init__(self
, doc
, element
, type="absolute"):
87 self
.type = element
.get("type", type)
88 self
.value
= NumberDef(element
.text
)
90 def __call__(self
, params
, rank
):
91 return self
.value(params
, rank
)
94 return "%s(%r, type=%r)" % (
95 type(self
).__name
__, self
.value
, self
.type)
97 class ChangeSpeed(object):
98 """Speed change over time."""
100 def __init__(self
, doc
, element
):
101 for subelem
in element
.getchildren():
102 tag
= realtag(subelem
)
104 self
.speed
= Speed(doc
, subelem
)
106 self
.term
= INumberDef(subelem
.text
)
108 self
.term
, self
.speed
109 except AttributeError:
112 def __call__(self
, params
, rank
):
113 return self
.term(params
, rank
), self
.speed(params
, rank
)
116 return "%s(term=%r, speed=%r)" % (
117 type(self
).__name
__, self
.term
, self
.speed
)
120 """Wait for some frames."""
121 def __init__(self
, doc
, element
):
122 self
.frames
= INumberDef(element
.text
)
124 def __call__(self
, params
, rank
):
125 return self
.frames(params
, rank
)
128 return "%s(%r)" % (type(self
).__name
__, self
.frames
)
130 class Vanish(object):
131 """Make the owner disappear."""
132 def __init__(self
, doc
, element
):
136 return "%s()" % (type(self
).__name
__)
138 class Repeat(object):
139 """Repeat an action definition."""
141 def __init__(self
, doc
, element
):
142 for subelem
in element
.getchildren():
143 tag
= realtag(subelem
)
145 self
.times
= INumberDef(subelem
.text
)
146 elif tag
== "action":
147 self
.action
= ActionDef(doc
, subelem
)
148 elif tag
== "actionRef":
149 self
.action
= ActionRef(doc
, subelem
)
152 self
.times
, self
.action
153 except AttributeError:
156 def __call__(self
, params
, rank
):
157 return self
.times(params
, rank
), self
.action(params
, rank
)
160 return "%s(%r, %r)" % (type(self
).__name
__, self
.times
, self
.action
)
163 """Accelerate over some time."""
168 def __init__(self
, doc
, element
):
169 for subelem
in element
.getchildren():
170 tag
= realtag(subelem
)
172 self
.term
= INumberDef(subelem
.text
)
173 elif tag
== "horizontal":
174 self
.horizontal
= Speed(doc
, subelem
)
175 elif tag
== "vertical":
176 self
.vertical
= Speed(doc
, subelem
)
180 except AttributeError:
183 def __call__(self
, params
, rank
):
184 frames
= self
.term(params
, rank
)
185 horizontal
= self
.horizontal
and self
.horizontal(params
, rank
)
186 vertical
= self
.vertical
and self
.vertical(params
, rank
)
187 return frames
, horizontal
, vertical
190 return "%s(%r, horizontal=%r, vertical=%r)" % (
191 type(self
).__name
__, self
.term
, self
.horizontal
, self
.vertical
)
193 class BulletDef(object):
194 """Bullet definition."""
199 def __init__(self
, doc
, element
):
201 doc
.bullets
[element
.get("label")] = self
202 for subelem
in element
.getchildren():
203 tag
= realtag(subelem
)
204 if tag
== "direction":
205 self
.direction
= Direction(doc
, subelem
)
207 self
.speed
= Speed(doc
, subelem
)
208 elif tag
== "action":
209 self
.actions
.append(ActionDef(doc
, element
))
210 elif tag
== "actionRef":
211 self
.actions
.append(ActionRef(doc
, element
))
213 def __call__(self
, params
, rank
):
215 for action
in self
.actions
:
217 actions
.append((action
.params(params
), action
.action
))
218 except AttributeError:
219 actions
.append((params
, action
))
220 return (self
.direction
and self
.direction(params
, rank
),
221 self
.speed
and self
.speed(params
, rank
),
225 return "%s(direction=%r, speed=%r, actions=%r)" % (
226 type(self
).__name
__, self
.direction
, self
.speed
, self
.actions
)
228 class BulletRef(object):
229 """Create a bullet by name with parameters."""
231 def __init__(self
, doc
, element
):
232 self
.bullet
= element
.get("label")
233 self
.params
= ParamList(element
)
234 doc
._bullet
_refs
.append(self
)
236 def __call__(self
, params
, rank
):
237 return self
.bullet(self
.params(params
, rank
), rank
)
240 return "%s(params=%r, bullet=%r)" % (
241 type(self
).__name
__, self
.params
, self
.bullet
)
243 class ActionDef(object):
244 """Action definition."""
246 def __init__(self
, doc
, element
):
247 doc
.actions
[element
.get("label")] = self
249 for subelem
in element
.getchildren():
250 tag
= realtag(subelem
)
256 changeSpeed
=ChangeSpeed
,
257 changeDirection
=ChangeDirection
,
262 actionRef
=ActionRef
)[tag
]
266 self
.actions
.append(ctr(doc
, subelem
))
268 def __call__(self
, params
, rank
):
269 return self
.actions
, params
272 return "%s(%r)" % (type(self
).__name
__, self
.actions
)
274 class ActionRef(object):
275 """Run an action by name with parameters."""
277 def __init__(self
, doc
, element
):
278 self
.action
= element
.get("label")
279 self
.params
= ParamList(element
)
280 doc
._action
_refs
.append(self
)
282 def __call__(self
, params
, rank
):
283 return self
.action(self
.params(params
, rank
), rank
)
286 return "%s(params=%r, action=%r)" % (
287 type(self
).__name
__, self
.params
, self
.action
)
289 class FireDef(object):
290 """Fire definition (creates a bullet)."""
295 def __init__(self
, doc
, element
):
296 doc
.fires
[element
.get("label")] = self
297 for subelem
in element
.getchildren():
298 tag
= realtag(subelem
)
299 if tag
== "direction":
300 self
.direction
= Direction(doc
, subelem
)
302 self
.speed
= Speed(doc
, subelem
)
303 elif tag
== "bullet":
304 self
.bullet
= BulletDef(doc
, subelem
)
305 elif tag
== "bulletRef":
306 self
.bullet
= BulletRef(doc
, subelem
)
309 except AttributeError:
312 def __call__(self
, params
, rank
):
313 direction
, speed
, actions
= self
.bullet(params
, rank
)
315 direction
= self
.direction(params
, rank
)
317 speed
= self
.speed(params
, rank
)
318 return direction
, speed
, actions
321 return "%s(direction=%r, speed=%r, bullet=%r)" % (
322 type(self
).__name
__, self
.direction
, self
.speed
, self
.bullet
)
324 class FireRef(object):
325 """Fire a bullet by name with parameters."""
327 def __init__(self
, doc
, element
):
328 self
.fire
= element
.get("label")
329 self
.params
= ParamList(element
)
330 doc
._fire
_refs
.append(self
)
332 def __call__(self
, params
, rank
):
333 """Generate a Bullet from the FireDef and params."""
334 return self
.fire(self
.params(params
, rank
), rank
)
337 return "%s(params=%r, fire=%r)" % (
338 type(self
).__name
__, self
.params
, self
.fire
)
340 class BulletML(object):
341 """BulletML document.
343 A BulletML document is a collection of bullets, actions, and
344 firings, as well as a base game type.
353 def __init__(self
, source
):
358 self
._bullet
_refs
= []
359 self
._action
_refs
= []
362 if isinstance(source
, (str, unicode)):
363 source
= StringIO(source
)
366 root
= tree
.parse(source
)
368 self
.type = root
.get("type", "none")
370 for element
in root
.getchildren():
371 tag
= realtag(element
)
372 if tag
in self
.CONSTRUCTORS
:
373 self
.CONSTRUCTORS
[tag
](self
, element
)
376 for ref
in self
._bullet
_refs
:
377 ref
.bullet
= self
.bullets
[ref
.bullet
]
378 for ref
in self
._fire
_refs
:
379 ref
.fire
= self
.fires
[ref
.fire
]
380 for ref
in self
._action
_refs
:
381 ref
.action
= self
.actions
[ref
.action
]
382 except KeyError as exc
:
383 raise ParseError("unknown reference %s" % exc
)
385 del(self
._bullet
_refs
)
386 del(self
._action
_refs
)
391 """Get a list of all top-level actions."""
392 return [dfn
for name
, dfn
in self
.actions
.iteritems()
393 if name
and name
.startswith("top")]
396 return "%s(type=%r, bullets=%r, actions=%r, fires=%r)" % (
397 type(self
).__name
__, self
.type, self
.bullets
, self
.actions
,