1 """BulletML implementation.
3 http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/index_e.html
6 from __future__
import division
10 from bulletml
import parser
, errors
12 # TODO(jfw): This is very non-Pythonic, it's pretty much just the
13 # BulletML reference ActionImpl translated to Python.
16 """Running action implementation."""
18 def __init__(self
, owner
, parent
, actions
, params
, rank
):
19 self
.actions
= actions
25 self
.aim_direction
= 0
27 self
.direction_frames
= 0
35 self
.previous_fire_direction
= 0
36 self
.previous_fire_speed
= 0
41 self
.copy_state(parent
)
44 return "%s(pc=%r, actions=%r)" % (
45 type(self
).__name
__, self
.pc
, self
.actions
)
49 return self
.pc
is None
56 def copy_state(self
, other
):
57 self
.direction_frames
= other
.direction_frames
58 self
.direction
= other
.direction
59 self
.aiming
= other
.aiming
60 self
.speed_frames
= other
.speed_frames
61 self
.speed
= other
.speed
62 self
.accel_frames
= other
.accel_frames
65 self
.previous_fire_direction
= other
.previous_fire_direction
66 self
.previous_fire_speed
= other
.previous_fire_speed
71 if self
.speed_frames
> 0:
72 self
.speed_frames
-= 1
73 self
.owner
.speed
+= self
.speed
75 if self
.direction_frames
> 0:
76 self
.direction_frames
-= 1
77 if self
.direction_frames
<= 0:
79 self
.owner
.direction
+= self
.owner
.aim
81 self
.owner
.direction
+= self
.direction
83 if self
.accel_frames
> 0:
84 self
.accel_frames
-= 1
85 self
.owner
.mx
+= self
.mx
86 self
.owner
.my
+= self
.my
91 if self
.wait_frames
> 0:
98 if self
.pc
>= len(self
.actions
):
102 if self
.parent
is not None:
103 self
.parent
.copy_state(self
)
104 self
.owner
.replace(self
, self
.parent
)
109 action
= self
.actions
[self
.pc
]
111 if isinstance(action
, parser
.Repeat
):
112 repeat
, (actions
, params
) = action(self
.params
, self
.rank
)
113 child
= Action(self
.owner
, self
, actions
, params
, self
.rank
)
114 child
.repeat
= repeat
115 self
.owner
.replace(self
, child
)
116 created
.extend(child
.step())
119 elif isinstance(action
, (parser
.ActionDef
, parser
.ActionRef
)):
120 actions
, params
= action(self
.params
, self
.rank
)
121 child
= Action(self
.owner
, self
, actions
, params
, self
.rank
)
122 self
.owner
.replace(self
, child
)
123 created
.extend(child
.step())
126 elif isinstance(action
, (parser
.FireDef
, parser
.FireRef
)):
127 direction
, speed
, actions
= action(self
.params
, self
.rank
)
129 direction
, type = direction
130 if type == "aim" or type is None:
131 direction
+= self
.owner
.aim
132 elif type == "sequence":
133 direction
+= self
.previous_fire_direction
134 elif type == "relative":
135 direction
+= self
.owner
.direction
137 direction
= self
.owner
.aim
138 self
.previous_fire_direction
= direction
143 if type == "sequence":
144 speed
+= self
.previous_fire_speed
145 elif type == "relative":
146 # FIXME(jfw): Reference impl uses prvFireSpeed
147 # here? That doesn't seem right at all.
148 speed
+= self
.owner
.speed
151 self
.previous_fire_speed
= speed
153 bullet
= Bullet(self
.owner
.x
, self
.owner
.y
, direction
, speed
,
154 self
.owner
.target
, actions
, self
)
155 created
.append(bullet
)
157 elif isinstance(action
, parser
.ChangeSpeed
):
158 frames
, (speed
, type) = action(self
.params
, self
.rank
)
159 self
.speed_frames
= frames
160 if type == "sequence":
162 elif type == "relative":
163 self
.speed
= speed
/ frames
165 self
.speed
= (speed
- self
.owner
.speed
) / frames
167 elif isinstance(action
, parser
.ChangeDirection
):
168 frames
, (direction
, type) = action(self
.params
, self
.rank
)
169 self
.direction_frames
= frames
171 if type == "sequence":
173 self
.direction
= direction
175 if type == "absolute":
178 direction
- self
.owner
.direction
) % 360
179 elif type == "relative":
181 self
.direction
= direction
187 - self
.owner
.direction
) % 360
189 while self
.direction
> 180:
190 self
.direction
-= 360
191 while self
.direction
< -180:
192 self
.direction
+= 360
193 self
.direction
/= self
.direction_frames
195 elif isinstance(action
, parser
.Accel
):
196 frames
, horizontal
, vertical
= action(self
.params
, self
.rank
)
197 self
.accel_frames
= frames
199 mx
, type = horizontal
200 if type == "sequence":
202 elif type == "absolute":
203 self
.mx
= (mx
- self
.owner
.mx
) / frames
204 elif type == "relative":
205 self
.mx
= mx
/ frames
208 if type == "sequence":
210 elif type == "absolute":
211 self
.my
= (my
- self
.owner
.my
) / frames
212 elif type == "relative":
213 self
.my
= my
/ frames
215 elif isinstance(action
, parser
.Wait
):
216 self
.wait_frames
= action(self
.params
, self
.rank
)
219 elif isinstance(action
, parser
.Vanish
):
225 class Bullet(object):
226 """Simple bullet implementation."""
228 def __init__(self
, x
=0, y
=0, direction
=0, speed
=0, target
=None,
229 actions
=(), parent
=None, rank
=None):
234 self
.direction
= direction
236 self
.vanished
= False
240 rank
= parent
.rank
if parent
else 0.5
241 # New bullets reset the parent hierarchy.
242 self
.actions
= [Action(self
, None, action
, params
, rank
)
243 for action
, params
in actions
]
246 return ("%s(%r, %r, accel=%r, direction=%r, speed=%r, "
247 "actions=%r, target=%r, vanished=%r)") % (
248 type(self
).__name
__, self
.x
, self
.y
, (self
.mx
, self
.my
),
249 self
.direction
, self
.speed
, self
.actions
, self
.target
,
254 """Angle to the target."""
255 if self
.target
is None:
256 return self
.direction
259 math
.atan2(self
.target
.x
- self
.x
, self
.y
- self
.target
.y
))
263 for action
in self
.actions
:
264 if not action
.finished
:
269 """Vanish this bullet and stop all actions."""
271 for action
in self
.actions
:
275 def replace(self
, old
, new
):
277 idx
= self
.actions
.index(old
)
281 self
.actions
[idx
] = new
286 for action
in self
.actions
:
287 created
.extend(action
.step())
289 direction
= math
.radians(self
.direction
)
292 self
.x
+= self
.mx
+ math
.sin(direction
) * self
.speed
293 self
.y
+= self
.my
- math
.cos(direction
) * self
.speed
298 def FromDoc(cls
, doc
, params
=(), x
=0, y
=0, speed
=0, direction
=0,
299 target
=None, rank
=0.5):
300 actions
= [act(params
, rank
) for act
in doc
.top
]
301 return cls(x
, y
, direction
, speed
, target
, actions
, rank
=rank
)