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
)
49 def copy_state(self
, other
):
50 self
.direction_frames
= other
.direction_frames
51 self
.direction
= other
.direction
52 self
.aiming
= other
.aiming
53 self
.speed_frames
= other
.speed_frames
54 self
.speed
= other
.speed
55 self
.accel_frames
= other
.accel_frames
58 self
.previous_fire_direction
= other
.previous_fire_direction
59 self
.previous_fire_speed
= other
.previous_fire_speed
64 if self
.speed_frames
> 0:
65 self
.speed_frames
-= 1
66 self
.owner
.speed
+= self
.speed
67 if self
.direction_frames
> 0:
68 self
.direction_frames
-= 1
69 if self
.direction_frames
<= 0:
71 self
.owner
.direction
+= self
.owner
.aim
73 self
.owner
.direction
+= self
.direction
74 if self
.accel_frames
> 0:
75 self
.accel_frames
-= 1
76 self
.owner
.mx
+= self
.mx
77 self
.owner
.my
+= self
.my
82 if self
.wait_frames
> 0:
88 if self
.pc
>= len(self
.actions
):
91 if self
.parent
is not None:
92 self
.parent
.copy_state(self
)
93 self
.owner
.replace(self
, self
.parent
)
98 action
= self
.actions
[self
.pc
]
100 if isinstance(action
, parser
.Repeat
):
101 repeat
, (actions
, params
) = action(self
.params
, self
.rank
)
102 child
= Action(self
.owner
, self
, actions
, params
, self
.rank
)
103 child
.repeat
= repeat
104 self
.owner
.replace(self
, child
)
105 created
.extend(child
.step())
108 elif isinstance(action
, (parser
.ActionDef
, parser
.ActionRef
)):
109 action
, params
= action(self
.params
, self
.rank
)
110 child
= Action(self
.owner
, self
, actions
, params
, self
.rank
)
111 self
.owner
.replace(self
, child
)
112 created
.extend(child
.step())
115 elif isinstance(action
, (parser
.FireDef
, parser
.FireRef
)):
116 direction
, speed
, actions
= action(self
.params
, self
.rank
)
118 direction
, type = direction
120 direction
+= self
.owner
.aim
121 elif type == "sequence":
122 direction
+= self
.previous_fire_direction
123 elif type == "relative":
124 direction
+= self
.owner
.direction
126 direction
= self
.owner
.aim
127 self
.previous_fire_direction
= direction
132 if type == "sequence":
133 speed
+= self
.previous_fire_speed
134 elif type == "relative":
135 # FIXME(jfw): Reference impl uses prvFireSpeed
136 # here? That doesn't seem right at all.
137 speed
+= self
.owner
.speed
140 self
.previous_fire_speed
= speed
142 bullet
= Bullet(self
.owner
.x
, self
.owner
.y
, direction
, speed
,
143 self
.owner
.target
, actions
, self
)
144 created
.append(bullet
)
146 elif isinstance(action
, parser
.ChangeSpeed
):
147 frames
, (speed
, type) = action(self
.params
, self
.rank
)
148 self
.speed_frames
= frames
149 if type == "sequence":
151 elif type == "relative":
152 self
.speed
= speed
/ frames
154 self
.speed
= (speed
- self
.owner
.speed
) / frames
156 elif isinstance(action
, parser
.ChangeDirection
):
157 frames
, (direction
, type) = action(self
.params
, self
.rank
)
158 self
.direction_frames
= frames
160 if type == "sequence":
162 self
.direction
= direction
164 if type == "absolute":
167 direction
- self
.owner
.direction
) % 360
168 elif type == "relative":
170 self
.direction
= direction
176 - self
.owner
.direction
) % 360
178 while self
.direction
> 180:
179 self
.direction
-= 360
180 while self
.direction
< -180:
181 self
.direction
+= 360
182 self
.direction
/= self
.direction_frames
184 elif isinstance(action
, parser
.Accel
):
185 frames
, horizontal
, vertical
= action(self
.params
, self
.rank
)
186 self
.accel_frames
= frames
188 mx
, type = horizontal
189 if type == "sequence":
191 elif type == "absolute":
192 self
.mx
= (mx
- bullet
.mx
) / frames
193 elif type == "relative":
194 self
.mx
= mx
/ frames
197 if type == "sequence":
199 elif type == "absolute":
200 self
.my
= (my
- bullet
.my
) / frames
201 elif type == "relative":
202 self
.my
= my
/ frames
204 elif isinstance(action
, parser
.Wait
):
205 self
.wait_frames
= action(self
.params
, self
.rank
)
208 elif isinstance(action
, parser
.Vanish
):
214 class Bullet(object):
215 """Simple bullet implementation."""
217 def __init__(self
, x
=0, y
=0, direction
=0, speed
=0, target
=None,
218 actions
=(), parent
=None):
223 self
.direction
= direction
225 self
.vanished
= False
228 if actions
and not parent
:
230 for action
, params
in actions
:
232 Action(self
, parent
, action
, params
, parent
.rank
))
235 return ("%s(%r, %r, accel=%r, direction=%r, speed=%r, "
236 "actions=%r, target=%r, vanished=%r)") % (
237 type(self
).__name
__, self
.x
, self
.y
, (self
.mx
, self
.my
),
238 self
.direction
, self
.speed
, self
.actions
, self
.target
,
243 """Angle to the target."""
244 if self
.target
is None:
245 return self
.direction
247 return math
.atan2(self
.target
.x
- self
.x
, self
.target
.y
- self
.y
)
250 """Vanish this bullet and stop all actions."""
252 for action
in self
.actions
:
256 def replace(self
, old
, new
):
258 idx
= self
.actions
.index(old
)
262 self
.actions
[idx
] = new
267 for action
in self
.actions
:
268 created
.extend(action
.step())
270 direction
= math
.degrees(self
.direction
)
271 self
.x
+= self
.mx
+ math
.sin(direction
) * self
.speed
272 self
.y
+= self
.my
+ math
.cos(direction
) * self
.speed