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
), self
.type)
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
), self
.type)
94 return "%s(%r, type=%r)" % (type(self
).__name
__, self
.value
, self
.type)
96 class ChangeSpeed(object):
97 """Speed change over time."""
99 def __init__(self
, doc
, element
):
100 for subelem
in element
.getchildren():
101 tag
= realtag(subelem
)
103 self
.speed
= Speed(doc
, subelem
)
105 self
.term
= INumberDef(subelem
.text
)
107 self
.term
, self
.speed
108 except AttributeError:
111 def __call__(self
, params
, rank
):
112 return self
.term(params
, rank
), self
.speed(params
, rank
)
115 return "%s(term=%r, speed=%r)" % (
116 type(self
).__name
__, self
.term
, self
.speed
)
119 """Wait for some frames."""
120 def __init__(self
, doc
, element
):
121 self
.frames
= INumberDef(element
.text
)
123 def __call__(self
, params
, rank
):
124 return self
.frames(params
, rank
)
127 return "%s(%r)" % (type(self
).__name
__, self
.frames
)
129 class Vanish(object):
130 """Make the owner disappear."""
131 def __init__(self
, doc
, element
):
135 return "%s()" % (type(self
).__name
__)
137 class Repeat(object):
138 """Repeat an action definition."""
140 def __init__(self
, doc
, element
):
141 for subelem
in element
.getchildren():
142 tag
= realtag(subelem
)
144 self
.times
= INumberDef(subelem
.text
)
145 elif tag
== "action":
146 self
.action
= ActionDef(doc
, subelem
)
147 elif tag
== "actionRef":
148 self
.action
= ActionRef(doc
, subelem
)
151 self
.times
, self
.action
152 except AttributeError:
155 def __call__(self
, params
, rank
):
156 return self
.times(params
, rank
), self
.action(params
, rank
)
159 return "%s(%r, %r)" % (type(self
).__name
__, self
.times
, self
.action
)
162 """Accelerate over some time."""
167 def __init__(self
, doc
, element
):
168 for subelem
in element
.getchildren():
169 tag
= realtag(subelem
)
171 self
.term
= INumberDef(subelem
.text
)
172 elif tag
== "horizontal":
173 self
.horizontal
= Speed(doc
, subelem
)
174 elif tag
== "vertical":
175 self
.vertical
= Speed(doc
, subelem
)
179 except AttributeError:
182 def __call__(self
, params
, rank
):
183 frames
= self
.term(params
, rank
)
184 horizontal
= self
.horizontal
and self
.horizontal(params
, rank
)
185 vertical
= self
.vertical
and self
.vertical(params
, rank
)
186 return frames
, horizontal
, vertical
189 return "%s(%r, horizontal=%r, vertical=%r)" % (
190 type(self
).__name
__, self
.term
, self
.horizontal
, self
.vertical
)
192 class BulletDef(object):
193 """Bullet definition."""
198 def __init__(self
, doc
, element
):
200 doc
.bullets
[element
.get("label")] = self
201 for subelem
in element
.getchildren():
202 tag
= realtag(subelem
)
203 if tag
== "direction":
204 self
.direction
= Direction(doc
, subelem
)
206 self
.speed
= Speed(doc
, subelem
)
207 elif tag
== "action":
208 self
.actions
.append(ActionDef(doc
, subelem
))
209 elif tag
== "actionRef":
210 self
.actions
.append(ActionRef(doc
, subelem
))
212 def __call__(self
, params
, rank
):
214 for action
in self
.actions
:
215 actions
.append(action(params
, rank
))
217 self
.direction
and self
.direction(params
, rank
),
218 self
.speed
and self
.speed(params
, rank
),
222 return "%s(direction=%r, speed=%r, actions=%r)" % (
223 type(self
).__name
__, self
.direction
, self
.speed
, self
.actions
)
225 class BulletRef(object):
226 """Create a bullet by name with parameters."""
228 def __init__(self
, doc
, element
):
229 self
.bullet
= element
.get("label")
230 self
.params
= ParamList(element
)
231 doc
._bullet
_refs
.append(self
)
233 def __call__(self
, params
, rank
):
234 return self
.bullet(self
.params(params
, rank
), rank
)
237 return "%s(params=%r, bullet=%r)" % (
238 type(self
).__name
__, self
.params
, self
.bullet
)
240 class ActionDef(object):
241 """Action definition."""
243 def __init__(self
, doc
, element
):
244 doc
.actions
[element
.get("label")] = self
246 for subelem
in element
.getchildren():
247 tag
= realtag(subelem
)
253 changeSpeed
=ChangeSpeed
,
254 changeDirection
=ChangeDirection
,
259 actionRef
=ActionRef
)[tag
]
263 self
.actions
.append(ctr(doc
, subelem
))
265 def __call__(self
, params
, rank
):
266 return self
.actions
, params
269 return "%s(%r)" % (type(self
).__name
__, self
.actions
)
271 class ActionRef(object):
272 """Run an action by name with parameters."""
274 def __init__(self
, doc
, element
):
275 self
.action
= element
.get("label")
276 self
.params
= ParamList(element
)
277 doc
._action
_refs
.append(self
)
279 def __call__(self
, params
, rank
):
280 return self
.action(self
.params(params
, rank
), rank
)
283 return "%s(params=%r, action=%r)" % (
284 type(self
).__name
__, self
.params
, self
.action
)
286 class FireDef(object):
287 """Fire definition (creates a bullet)."""
292 def __init__(self
, doc
, element
):
293 doc
.fires
[element
.get("label")] = self
294 for subelem
in element
.getchildren():
295 tag
= realtag(subelem
)
296 if tag
== "direction":
297 self
.direction
= Direction(doc
, subelem
, "aim")
299 self
.speed
= Speed(doc
, subelem
)
300 elif tag
== "bullet":
301 self
.bullet
= BulletDef(doc
, subelem
)
302 elif tag
== "bulletRef":
303 self
.bullet
= BulletRef(doc
, subelem
)
306 except AttributeError:
309 def __call__(self
, params
, rank
):
310 direction
, speed
, actions
= self
.bullet(params
, rank
)
312 direction
= self
.direction(params
, rank
)
314 speed
= self
.speed(params
, rank
)
315 return direction
, speed
, actions
318 return "%s(direction=%r, speed=%r, bullet=%r)" % (
319 type(self
).__name
__, self
.direction
, self
.speed
, self
.bullet
)
321 class FireRef(object):
322 """Fire a bullet by name with parameters."""
324 def __init__(self
, doc
, element
):
325 self
.fire
= element
.get("label")
326 self
.params
= ParamList(element
)
327 doc
._fire
_refs
.append(self
)
329 def __call__(self
, params
, rank
):
330 """Generate a Bullet from the FireDef and params."""
331 return self
.fire(self
.params(params
, rank
), rank
)
334 return "%s(params=%r, fire=%r)" % (
335 type(self
).__name
__, self
.params
, self
.fire
)
337 class BulletML(object):
338 """BulletML document.
340 A BulletML document is a collection of bullets, actions, and
341 firings, as well as a base game type.
350 def __init__(self
, source
):
355 self
._bullet
_refs
= []
356 self
._action
_refs
= []
359 if isinstance(source
, (str, unicode)):
360 source
= StringIO(source
)
363 root
= tree
.parse(source
)
365 self
.type = root
.get("type", "none")
367 for element
in root
.getchildren():
368 tag
= realtag(element
)
369 if tag
in self
.CONSTRUCTORS
:
370 self
.CONSTRUCTORS
[tag
](self
, element
)
373 for ref
in self
._bullet
_refs
:
374 ref
.bullet
= self
.bullets
[ref
.bullet
]
375 for ref
in self
._fire
_refs
:
376 ref
.fire
= self
.fires
[ref
.fire
]
377 for ref
in self
._action
_refs
:
378 ref
.action
= self
.actions
[ref
.action
]
379 except KeyError as exc
:
380 raise ParseError("unknown reference %s" % exc
)
382 del(self
._bullet
_refs
)
383 del(self
._action
_refs
)
388 """Get a list of all top-level actions."""
389 return [dfn
for name
, dfn
in self
.actions
.iteritems()
390 if name
and name
.startswith("top")]
393 return "%s(type=%r, bullets=%r, actions=%r, fires=%r)" % (
394 type(self
).__name
__, self
.type, self
.bullets
, self
.actions
,