Skip to main content

bulletml/
runner.rs

1use indextree::{Arena, Node, NodeId};
2use std::collections::HashSet;
3use std::ops::{Deref, DerefMut};
4
5use crate::tree::{
6    BulletML, BulletMLExpression, BulletMLNode, BulletMLType, DirectionType, HVType, SpeedType,
7};
8
9/// Set of data required during a BulletML run.
10///
11/// `D` is the type of the application data used in the [AppRunner](trait.AppRunner.html) callbacks.
12pub struct RunnerData<'a, D: 'a> {
13    pub bml: &'a BulletML,
14    pub data: &'a mut D,
15}
16
17type Parameters = Vec<f64>;
18
19/// State information that can be used to call
20/// [Runner::new_from_state](struct.Runner.html#method.new_from_state) or
21/// [Runner::init_from_state](struct.Runner.html#method.init_from_state) when creating new bullets.
22///
23/// See also [AppRunner::create_bullet](trait.AppRunner.html#tymethod.create_bullet).
24pub struct State {
25    bml_type: Option<BulletMLType>,
26    nodes: Box<[NodeId]>,
27    parameters: Parameters,
28}
29
30/// Elementary bullet runner. It is used either to run one single bullet or to run one or more "top"
31/// actions.
32pub struct Runner<R> {
33    runners: Vec<RunnerImpl>,
34    app_runner: R,
35}
36
37impl<'a, R> Runner<R> {
38    /// Creates a new runner for all the "top" actions of the provided BulletML document.
39    ///
40    /// `app_runner` is the application runner which contains all the specific behaviours.
41    ///
42    /// `bml` is the parsed BulletML document to be used by the runner until the bullet dies.
43    pub fn new(app_runner: R, bml: &BulletML) -> Self {
44        let bml_type = bml.get_type();
45        let runners = bml
46            .root
47            .children(&bml.arena)
48            .filter(|child| {
49                let child_node = &bml.arena[*child];
50                child_node.get().is_top_action()
51            })
52            .map(|action| {
53                let state = State {
54                    bml_type,
55                    nodes: Box::new([action]),
56                    parameters: Vec::new(),
57                };
58                RunnerImpl::new(state)
59            })
60            .collect();
61        Runner {
62            runners,
63            app_runner,
64        }
65    }
66
67    /// Reuses this runner for all the "top" actions of the provided BulletML document. It works
68    /// the same way as [new](#method.new).
69    ///
70    /// `app_runner` is the application runner which contains all the specific behaviours.
71    ///
72    /// `bml` is the parsed BulletML document to be used by the runner until the bullet dies.
73    pub fn init<D>(&mut self, bml: &BulletML)
74    where
75        R: AppRunner<D>,
76    {
77        let bml_type = bml.get_type();
78        self.runners.clear();
79        for action in bml.root.children(&bml.arena).filter(|child| {
80            let child_node = &bml.arena[*child];
81            child_node.get().is_top_action()
82        }) {
83            let state = State {
84                bml_type,
85                nodes: Box::new([action]),
86                parameters: Vec::new(),
87            };
88            self.runners.push(RunnerImpl::new(state))
89        }
90        self.app_runner.init();
91    }
92
93    /// Creates a new runner from an existing state.
94    ///
95    /// `app_runner` is the application runner which contains all the specific behaviours.
96    ///
97    /// `state` is the state with which
98    /// [AppRunner::create_bullet](trait.AppRunner.html#tymethod.create_bullet) is called.
99    pub fn new_from_state(app_runner: R, state: State) -> Self {
100        Runner {
101            runners: vec![RunnerImpl::new(state)],
102            app_runner,
103        }
104    }
105
106    /// Reuses this runner from an existing state.  It works
107    /// the same way as [new_from_state](#method.new_from_state) except that the application
108    /// runner cannot change.
109    ///
110    /// `state` is the state with which
111    /// [AppRunner::create_bullet](trait.AppRunner.html#tymethod.create_bullet) is called.
112    pub fn init_from_state<D>(&mut self, state: State)
113    where
114        R: AppRunner<D>,
115    {
116        self.runners.clear();
117        self.runners.push(RunnerImpl::new(state));
118        self.app_runner.init();
119    }
120
121    /// Runs one iteration of this runner.
122    ///
123    /// `data` contains the application data used in the [AppRunner](trait.AppRunner.html) callbacks.
124    pub fn run<D>(&mut self, data: &mut RunnerData<D>)
125    where
126        R: AppRunner<D>,
127    {
128        for runner in &mut self.runners {
129            runner.run(data, &mut self.app_runner);
130        }
131    }
132
133    /// Checks whether this runner is alive.
134    pub fn is_end(&self) -> bool {
135        for runner in &self.runners {
136            if runner.is_end() {
137                return true;
138            }
139        }
140        false
141    }
142}
143
144impl<R: Default> Default for Runner<R> {
145    fn default() -> Self {
146        Runner {
147            runners: Vec::default(),
148            app_runner: R::default(),
149        }
150    }
151}
152
153impl<R> Deref for Runner<R> {
154    type Target = R;
155    fn deref(&self) -> &Self::Target {
156        &self.app_runner
157    }
158}
159
160impl<R> DerefMut for Runner<R> {
161    fn deref_mut(&mut self) -> &mut Self::Target {
162        &mut self.app_runner
163    }
164}
165
166/// Application specific BulletML runner trait.
167pub trait AppRunner<D> {
168    /// Initializes the runner.
169    ///
170    /// This function is called when a new [Runner](struct.Runner.html) is created/reused.
171    fn init(&mut self) {}
172    /// Gets this bullet's direction based on application data.
173    fn get_bullet_direction(&self, data: &D) -> f64;
174    /// Gets this bullet's aim direction based on application data.
175    ///
176    /// The "target" related to the "aim" notion is application specific.
177    fn get_aim_direction(&self, data: &D) -> f64;
178    /// Gets this bullet's speed based on application data.
179    fn get_bullet_speed(&self, data: &D) -> f64;
180    /// Gets the bullet default speed.
181    fn get_default_speed(&self) -> f64;
182    /// Gets the BulletML "rank", a value between 0 and 1 indicating the level of difficulty.
183    /// The value is used in arithmetic expressions with `$rank`.
184    fn get_rank(&self, data: &D) -> f64;
185    /// Tells the application to create a bullet with the given `direction` and `speed`.
186    ///
187    /// The simple use case is to create a bullet whose direction and speed won't change until it
188    /// disappears or hits the target.
189    ///
190    /// Nevertheless there could be more complex use cases which involve creating a new runner with
191    /// the same BulletML document or even another one.
192    fn create_simple_bullet(&mut self, data: &mut D, direction: f64, speed: f64);
193    /// Tells the application to create a bullet based on the given `state`, initial `direction`
194    /// and initial `speed`.
195    ///
196    /// The typical use case is to create a new runner with the same BulletML document. See
197    /// [Runner::new_from_state](struct.Runner.html#method.new_from_state) and
198    /// [Runner::init_from_state](struct.Runner.html#method.init_from_state).
199    fn create_bullet(&mut self, data: &mut D, state: State, direction: f64, speed: f64);
200    /// Gets the current iteration number.
201    fn get_turn(&self, data: &D) -> u32;
202    /// Tells the application to make this bullet vanish.
203    fn do_vanish(&mut self, data: &mut D);
204    fn do_change_direction(&mut self, _data: &mut D, _direction: f64) {}
205    /// Tells the application to make this bullet change speed.
206    fn do_change_speed(&mut self, _data: &mut D, _speed: f64) {}
207    /// Tells the application to make this bullet accelerate.
208    fn do_accel_x(&mut self, _: f64) {}
209    /// Tells the application to make this bullet accelerate.
210    fn do_accel_y(&mut self, _: f64) {}
211    /// Gets this bullet's X speed.
212    fn get_bullet_speed_x(&self) -> f64 {
213        0.
214    }
215    /// Gets this bullet's Y speed.
216    fn get_bullet_speed_y(&self) -> f64 {
217        0.
218    }
219    /// Gets a new random value. The random number generator is managed by the application.
220    fn get_rand(&self, data: &mut D) -> f64;
221    #[cfg(test)]
222    fn log(&mut self, _data: &mut D, _node: &BulletMLNode) {}
223}
224
225struct Validatable<T: Copy> {
226    value: T,
227    valid: bool,
228}
229
230impl<T: Copy> Validatable<T> {
231    fn get(&self) -> T {
232        self.value
233    }
234
235    fn is_valid(&self) -> bool {
236        self.valid
237    }
238
239    fn set(&mut self, value: T) {
240        self.value = value;
241        self.valid = true;
242    }
243
244    fn invalidate(&mut self) {
245        self.valid = false;
246    }
247}
248
249impl<T: Copy + Default> Default for Validatable<T> {
250    fn default() -> Self {
251        Validatable {
252            value: T::default(),
253            valid: false,
254        }
255    }
256}
257
258struct LinearFunc<X, Y> {
259    first_x: X,
260    last_x: X,
261    first_y: Y,
262    last_y: Y,
263    gradient: Y,
264}
265
266impl<X, Y> LinearFunc<X, Y>
267where
268    X: Copy + PartialOrd + std::ops::Sub<Output = X> + Into<Y>,
269    Y: Copy
270        + Default
271        + std::ops::Add<Output = Y>
272        + std::ops::Sub<Output = Y>
273        + std::ops::Mul<Output = Y>
274        + std::ops::Div<Output = Y>,
275{
276    fn new(first_x: X, last_x: X, first_y: Y, last_y: Y) -> Self {
277        Self {
278            first_x,
279            last_x,
280            first_y,
281            last_y,
282            gradient: (last_y - first_y) / (last_x - first_x).into(),
283        }
284    }
285
286    fn get_value(&self, x: X) -> Y {
287        self.first_y + self.gradient * (x - self.first_x).into()
288    }
289
290    fn is_last(&self, x: X) -> bool {
291        x >= self.last_x
292    }
293
294    fn get_last(&self) -> Y {
295        self.last_y
296    }
297}
298
299struct StackedRef {
300    ref_id: NodeId,
301    prev: NodeId,
302    prev_parameters: Parameters,
303}
304
305pub struct RunnerImpl {
306    bml_type: Option<BulletMLType>,
307    nodes: Box<[NodeId]>,
308    root_nodes: HashSet<NodeId>,
309    change_dir: Option<LinearFunc<u32, f64>>,
310    change_spd: Option<LinearFunc<u32, f64>>,
311    accel_x: Option<LinearFunc<u32, f64>>,
312    accel_y: Option<LinearFunc<u32, f64>>,
313    spd: Validatable<f64>,
314    prev_spd: Validatable<f64>,
315    dir: Validatable<f64>,
316    prev_dir: Validatable<f64>,
317    act: Option<NodeId>,
318    act_turn: Option<u32>,
319    end_turn: u32,
320    act_iter: usize,
321    end: bool,
322    parameters: Parameters,
323    repeat_stack: Vec<RepeatElem>,
324    ref_stack: Vec<StackedRef>,
325}
326
327impl RunnerImpl {
328    fn new(state: State) -> Self {
329        let act = Some(state.nodes[0]);
330        let mut root_nodes = HashSet::new();
331        for node in state.nodes.iter() {
332            root_nodes.insert(*node);
333        }
334        RunnerImpl {
335            bml_type: state.bml_type,
336            nodes: state.nodes,
337            root_nodes,
338            change_dir: None,
339            change_spd: None,
340            accel_x: None,
341            accel_y: None,
342            spd: Validatable::default(),
343            prev_spd: Validatable::default(),
344            dir: Validatable::default(),
345            prev_dir: Validatable::default(),
346            act,
347            act_turn: None,
348            end_turn: 0,
349            act_iter: 0,
350            end: false,
351            parameters: state.parameters,
352            repeat_stack: Vec::new(),
353            ref_stack: Vec::new(),
354        }
355    }
356
357    fn run<D>(&mut self, data: &mut RunnerData<D>, runner: &mut dyn AppRunner<D>) {
358        if self.is_end() {
359            return;
360        }
361        self.changes(data, runner);
362        self.end_turn = runner.get_turn(data.data);
363        if self.act.is_none() {
364            if !self.is_turn_end()
365                && self.change_dir.is_none()
366                && self.change_spd.is_none()
367                && self.accel_x.is_none()
368                && self.accel_y.is_none()
369            {
370                self.end = true;
371            }
372            return;
373        }
374        self.act = Some(self.nodes[self.act_iter]);
375        if self.act_turn.is_none() {
376            self.act_turn = Some(runner.get_turn(data.data));
377        }
378        self.run_sub(data, runner);
379        match self.act {
380            None => {
381                self.act_iter += 1;
382                if self.act_iter < self.nodes.len() {
383                    self.act = Some(self.nodes[self.act_iter]);
384                }
385            }
386            Some(act) => self.nodes[self.act_iter] = act,
387        }
388    }
389
390    fn is_end(&self) -> bool {
391        self.end
392    }
393
394    fn is_turn_end(&self) -> bool {
395        self.is_end() || self.act_turn.unwrap_or(0) > self.end_turn
396    }
397
398    fn do_wait(&mut self, frame: u32) {
399        if frame > 0 {
400            self.act_turn = Some(self.act_turn.unwrap() + frame);
401        }
402    }
403
404    fn changes<D>(&mut self, data: &mut RunnerData<D>, runner: &mut dyn AppRunner<D>) {
405        let now = runner.get_turn(data.data);
406        let reset = if let Some(change_dir) = &self.change_dir {
407            if change_dir.is_last(now) {
408                runner.do_change_direction(&mut data.data, change_dir.get_last());
409                true
410            } else {
411                runner.do_change_direction(&mut data.data, change_dir.get_value(now));
412                false
413            }
414        } else {
415            false
416        };
417        if reset {
418            self.change_dir = None;
419        }
420        let reset = if let Some(change_spd) = &self.change_spd {
421            if change_spd.is_last(now) {
422                runner.do_change_speed(&mut data.data, change_spd.get_last());
423                true
424            } else {
425                runner.do_change_speed(&mut data.data, change_spd.get_value(now));
426                false
427            }
428        } else {
429            false
430        };
431        if reset {
432            self.change_spd = None;
433        }
434        let reset = if let Some(accel_x) = &self.accel_x {
435            if accel_x.is_last(now) {
436                runner.do_accel_x(accel_x.get_last());
437                true
438            } else {
439                runner.do_accel_x(accel_x.get_value(now));
440                false
441            }
442        } else {
443            false
444        };
445        if reset {
446            self.accel_x = None;
447        }
448        let reset = if let Some(accel_y) = &self.accel_y {
449            if accel_y.is_last(now) {
450                runner.do_accel_y(accel_y.get_last());
451                true
452            } else {
453                runner.do_accel_y(accel_y.get_value(now));
454                false
455            }
456        } else {
457            false
458        };
459        if reset {
460            self.accel_y = None;
461        }
462    }
463
464    fn run_sub<D>(&mut self, data: &mut RunnerData<D>, runner: &mut dyn AppRunner<D>) {
465        let bml = data.bml;
466        while let Some(act) = self.act {
467            if self.is_turn_end() {
468                break;
469            }
470            let mut prev = act;
471            let mut prev_node = &bml.arena[act];
472            let node = &bml.arena[act];
473            #[cfg(test)]
474            runner.log(&mut data.data, node.get());
475            match node.get() {
476                BulletMLNode::Bullet { .. } => self.run_bullet(data, runner),
477                BulletMLNode::Action { .. } => self.run_action(node),
478                BulletMLNode::Fire { .. } => self.run_fire(data, runner),
479                BulletMLNode::ChangeDirection => self.run_change_direction(data, runner),
480                BulletMLNode::ChangeSpeed => self.run_change_speed(data, runner),
481                BulletMLNode::Accel => self.run_accel(data, runner),
482                BulletMLNode::Wait(expr) => self.run_wait(*expr, data, runner),
483                BulletMLNode::Repeat => self.run_repeat(act, data, runner),
484                BulletMLNode::BulletRef(label) => {
485                    self.run_ref(act, bml.bullet_refs[label], data, runner)
486                }
487                BulletMLNode::ActionRef(label) => {
488                    self.run_ref(act, bml.action_refs[label], data, runner)
489                }
490                BulletMLNode::FireRef(label) => {
491                    self.run_ref(act, bml.fire_refs[label], data, runner)
492                }
493                BulletMLNode::Vanish => self.run_vanish(data, runner),
494                _ => (),
495            }
496            loop {
497                if self.act.is_none() {
498                    // Unstack reference if needed.
499                    if self
500                        .ref_stack
501                        .last()
502                        .map_or(false, |stacked| stacked.ref_id == prev)
503                    {
504                        let top = self.ref_stack.pop().unwrap();
505                        prev = top.prev;
506                        prev_node = &bml.arena[prev];
507                        self.parameters = top.prev_parameters;
508                    }
509
510                    // Jump to next sibling if any.
511                    if !self.root_nodes.contains(&prev) {
512                        self.act = prev_node.next_sibling();
513                    }
514                }
515
516                // Found something to run or hit a root node, break.
517                if self.act.is_some() || self.root_nodes.contains(&prev) {
518                    break;
519                }
520
521                // Go to parent unless it is an unfinished Repeat.
522                let parent = prev_node.parent();
523                let (new_act, new_act_node) = if let Some(parent) = parent {
524                    let parent_node = &bml.arena[parent];
525                    if let BulletMLNode::Repeat = parent_node.get() {
526                        let rep = self.repeat_stack.last_mut().unwrap();
527                        rep.iter += 1;
528                        if rep.iter < rep.end {
529                            // Unfinished Repeat, set act and break loop.
530                            self.act = Some(rep.act);
531                            break;
532                        }
533                        // Finished Repeat, pop.
534                        self.repeat_stack.pop();
535                    }
536                    (parent, parent_node)
537                } else {
538                    panic!("A run node must have a parent");
539                };
540
541                prev = new_act;
542                prev_node = new_act_node;
543            }
544        }
545    }
546
547    fn get_first_child_id_matching<M, N>(
548        arena: &Arena<BulletMLNode>,
549        parent: NodeId,
550        m: M,
551    ) -> Option<NodeId>
552    where
553        M: Fn(&BulletMLNode) -> Option<N>,
554    {
555        for child in parent.children(arena) {
556            let child_node = &arena[child];
557            if m(child_node.get()).is_some() {
558                return Some(child);
559            }
560        }
561        None
562    }
563
564    fn get_first_child_matching<M, N>(
565        arena: &Arena<BulletMLNode>,
566        parent: NodeId,
567        m: M,
568    ) -> Option<N>
569    where
570        M: Fn(&BulletMLNode) -> Option<N>,
571    {
572        for child in parent.children(arena) {
573            let child_node = &arena[child];
574            let n = m(child_node.get());
575            if n.is_some() {
576                return n;
577            }
578        }
579        None
580    }
581
582    fn get_children_ids_matching<M, N>(
583        arena: &Arena<BulletMLNode>,
584        parent: NodeId,
585        m: M,
586    ) -> Vec<NodeId>
587    where
588        M: Fn(&BulletMLNode) -> Option<N>,
589    {
590        parent
591            .children(arena)
592            .filter(|child| {
593                let child_node = &arena[*child];
594                m(child_node.get()).is_some()
595            })
596            .collect()
597    }
598
599    fn shot_init(&mut self) {
600        self.spd.invalidate();
601        self.dir.invalidate();
602    }
603
604    fn get_direction<D>(
605        &mut self,
606        dir_type: Option<DirectionType>,
607        expr: BulletMLExpression,
608        data: &mut RunnerData<D>,
609        runner: &dyn AppRunner<D>,
610    ) -> f64 {
611        let direction = self.get_number_contents(expr, data, runner);
612        let (mut direction, aim) = match dir_type {
613            None => (direction, true),
614            Some(DirectionType::Aim) => (direction, true),
615            Some(DirectionType::Absolute) => (
616                if self.bml_type == Some(BulletMLType::Horizontal) {
617                    direction - 90.
618                } else {
619                    direction
620                },
621                false,
622            ),
623            Some(DirectionType::Relative) => {
624                (direction + runner.get_bullet_direction(data.data), false)
625            }
626            Some(DirectionType::Sequence) => {
627                if !self.prev_dir.is_valid() {
628                    (0., true)
629                } else {
630                    (direction + self.prev_dir.get(), false)
631                }
632            }
633        };
634        if aim {
635            direction += runner.get_aim_direction(data.data);
636        }
637        while direction > 360. {
638            direction -= 360.
639        }
640        while direction < 0. {
641            direction += 360.
642        }
643        self.prev_dir.set(direction);
644        direction
645    }
646
647    fn set_direction<D>(&mut self, data: &mut RunnerData<D>, runner: &dyn AppRunner<D>) {
648        if let Some(act) = self.act {
649            let direction =
650                Self::get_first_child_matching(&data.bml.arena, act, BulletMLNode::match_direction);
651            if let Some((dir_type, dir)) = direction {
652                let direction = self.get_direction(dir_type, dir, data, runner);
653                self.dir.set(direction);
654            }
655        }
656    }
657
658    fn get_speed<D>(
659        &mut self,
660        spd_type: Option<SpeedType>,
661        expr: BulletMLExpression,
662        data: &mut RunnerData<D>,
663        runner: &dyn AppRunner<D>,
664    ) -> f64 {
665        let mut speed = self.get_number_contents(expr, data, runner);
666        speed = match spd_type {
667            None => speed,
668            Some(SpeedType::Absolute) => speed,
669            Some(SpeedType::Relative) => speed + runner.get_bullet_speed(data.data),
670            Some(SpeedType::Sequence) => {
671                if !self.prev_spd.is_valid() {
672                    1.
673                } else {
674                    speed + self.prev_spd.get()
675                }
676            }
677        };
678        self.prev_spd.set(speed);
679        speed
680    }
681
682    fn set_speed<D>(&mut self, data: &mut RunnerData<D>, runner: &dyn AppRunner<D>) {
683        if let Some(act) = self.act {
684            let speed =
685                Self::get_first_child_matching(&data.bml.arena, act, BulletMLNode::match_speed);
686            if let Some((spd_type, spd)) = speed {
687                let speed = self.get_speed(spd_type, spd, data, runner);
688                self.spd.set(speed);
689            }
690        }
691    }
692
693    fn run_bullet<D>(&mut self, data: &mut RunnerData<D>, runner: &mut dyn AppRunner<D>) {
694        let arena = &data.bml.arena;
695        self.set_speed(data, runner);
696        self.set_direction(data, runner);
697        if !self.spd.is_valid() {
698            let default = runner.get_default_speed();
699            self.spd.set(default);
700            self.prev_spd.set(default);
701        }
702        if !self.dir.is_valid() {
703            let default = runner.get_aim_direction(data.data);
704            self.dir.set(default);
705            self.prev_dir.set(default);
706        }
707        let all_actions = self.act.map_or_else(
708            || Vec::new(),
709            |act| Self::get_children_ids_matching(arena, act, BulletMLNode::match_any_action),
710        );
711        if all_actions.is_empty() {
712            runner.create_simple_bullet(&mut data.data, self.dir.get(), self.spd.get());
713        } else {
714            let state = State {
715                bml_type: self.bml_type,
716                nodes: all_actions.into_boxed_slice(),
717                parameters: self.parameters.clone(),
718            };
719            runner.create_bullet(&mut data.data, state, self.dir.get(), self.spd.get());
720        }
721        self.act = None;
722    }
723
724    fn run_fire<D>(&mut self, data: &mut RunnerData<D>, runner: &dyn AppRunner<D>) {
725        self.shot_init();
726        self.set_speed(data, runner);
727        self.set_direction(data, runner);
728        if let Some(act) = self.act {
729            let arena = &data.bml.arena;
730            let bullet =
731                Self::get_first_child_id_matching(arena, act, BulletMLNode::match_any_bullet);
732            if bullet.is_some() {
733                self.act = bullet;
734            }
735        }
736    }
737
738    fn run_action(&mut self, node: &Node<BulletMLNode>) {
739        self.act = node.first_child();
740    }
741
742    fn run_wait<D>(
743        &mut self,
744        expr: BulletMLExpression,
745        data: &mut RunnerData<D>,
746        runner: &dyn AppRunner<D>,
747    ) {
748        let frame = self.get_number_contents(expr, data, runner);
749        self.do_wait(frame as u32);
750        self.act = None;
751    }
752
753    fn run_repeat<D>(&mut self, act: NodeId, data: &mut RunnerData<D>, runner: &dyn AppRunner<D>) {
754        let times = Self::get_first_child_matching(&data.bml.arena, act, BulletMLNode::match_times);
755        if let Some(times) = times {
756            let times = self.get_number_contents(times, data, runner) as usize;
757            let arena = &data.bml.arena;
758            let action =
759                Self::get_first_child_id_matching(arena, act, BulletMLNode::match_any_action);
760            self.repeat_stack.push(RepeatElem {
761                iter: 0,
762                end: times,
763                act: action.unwrap(),
764            });
765            self.act = action;
766        }
767    }
768
769    fn run_ref<D>(
770        &mut self,
771        act: NodeId,
772        ref_id: NodeId,
773        data: &mut RunnerData<D>,
774        runner: &dyn AppRunner<D>,
775    ) {
776        let new_parameters = self.get_parameters(data, runner);
777        let prev_parameters = std::mem::replace(&mut self.parameters, new_parameters);
778        self.ref_stack.push(StackedRef {
779            ref_id,
780            prev: act,
781            prev_parameters: prev_parameters,
782        });
783        self.act = Some(ref_id);
784    }
785
786    fn run_change_direction<D>(&mut self, data: &mut RunnerData<D>, runner: &dyn AppRunner<D>) {
787        if let Some(act) = self.act {
788            let arena = &data.bml.arena;
789            let term = Self::get_first_child_matching(arena, act, BulletMLNode::match_term);
790            if let Some(term) = term {
791                let direction =
792                    Self::get_first_child_matching(arena, act, BulletMLNode::match_direction);
793                if let Some((dir_type, dir)) = direction {
794                    let term = self.get_number_contents(term, data, runner) as u32;
795                    let (dir, seq) = if let Some(DirectionType::Sequence) = dir_type {
796                        (self.get_number_contents(dir, data, runner), true)
797                    } else {
798                        (self.get_direction(dir_type, dir, data, runner), false)
799                    };
800                    self.calc_change_direction(dir, term, seq, data, runner);
801                }
802            }
803        }
804        self.act = None;
805    }
806
807    fn calc_change_direction<D>(
808        &mut self,
809        direction: f64,
810        term: u32,
811        seq: bool,
812        data: &RunnerData<D>,
813        runner: &dyn AppRunner<D>,
814    ) {
815        let act_turn = self.act_turn.unwrap_or(0);
816        let final_turn = act_turn + term;
817        let dir_first = runner.get_bullet_direction(data.data);
818        if seq {
819            self.change_dir = Some(LinearFunc::new(
820                act_turn,
821                final_turn,
822                dir_first,
823                dir_first + direction * f64::from(term),
824            ));
825        } else {
826            let dir_space1 = direction - dir_first;
827            let dir_space2 = if dir_space1 > 0. {
828                dir_space1 - 360.
829            } else {
830                dir_space1 + 360.
831            };
832            let dir_space = if f64::abs(dir_space1) < f64::abs(dir_space2) {
833                dir_space1
834            } else {
835                dir_space2
836            };
837            self.change_dir = Some(LinearFunc::new(
838                act_turn,
839                final_turn,
840                dir_first,
841                dir_first + dir_space,
842            ));
843        }
844    }
845
846    fn run_change_speed<D>(&mut self, data: &mut RunnerData<D>, runner: &dyn AppRunner<D>) {
847        if let Some(act) = self.act {
848            let arena = &data.bml.arena;
849            let term = Self::get_first_child_matching(arena, act, BulletMLNode::match_term);
850            if let Some(term) = term {
851                let speed = Self::get_first_child_matching(arena, act, BulletMLNode::match_speed);
852                if let Some((spd_type, spd)) = speed {
853                    let term = self.get_number_contents(term, data, runner) as u32;
854                    let spd = if let Some(SpeedType::Sequence) = spd_type {
855                        self.get_number_contents(spd, data, runner) * f64::from(term)
856                            + runner.get_bullet_speed(data.data)
857                    } else {
858                        self.get_speed(spd_type, spd, data, runner)
859                    };
860                    self.calc_change_speed(spd, term, data, runner);
861                }
862            }
863        }
864        self.act = None;
865    }
866
867    fn calc_change_speed<D>(
868        &mut self,
869        speed: f64,
870        term: u32,
871        data: &RunnerData<D>,
872        runner: &dyn AppRunner<D>,
873    ) {
874        let act_turn = self.act_turn.unwrap_or(0);
875        let final_turn = act_turn + term;
876        let spd_first = runner.get_bullet_speed(data.data);
877        self.change_spd = Some(LinearFunc::new(act_turn, final_turn, spd_first, speed));
878    }
879
880    fn run_accel<D>(&mut self, data: &mut RunnerData<D>, runner: &dyn AppRunner<D>) {
881        if let Some(act) = self.act {
882            let arena = &data.bml.arena;
883            let term = Self::get_first_child_matching(arena, act, BulletMLNode::match_term);
884            if let Some(term) = term {
885                let term = self.get_number_contents(term, data, runner) as u32;
886                let horizontal =
887                    Self::get_first_child_matching(arena, act, BulletMLNode::match_horizontal);
888                let vertical =
889                    Self::get_first_child_matching(arena, act, BulletMLNode::match_vertical);
890                if self.bml_type == Some(BulletMLType::Horizontal) {
891                    if let Some((v_type, v)) = vertical {
892                        self.accel_x = self.calc_accel_xy(
893                            runner.get_bullet_speed_x(),
894                            self.get_number_contents(v, data, runner),
895                            term,
896                            v_type,
897                        );
898                    }
899                    if let Some((h_type, h)) = horizontal {
900                        self.accel_y = self.calc_accel_xy(
901                            runner.get_bullet_speed_y(),
902                            self.get_number_contents(h, data, runner),
903                            term,
904                            h_type,
905                        );
906                    }
907                } else {
908                    if let Some((h_type, h)) = horizontal {
909                        self.accel_x = self.calc_accel_xy(
910                            runner.get_bullet_speed_x(),
911                            self.get_number_contents(h, data, runner),
912                            term,
913                            h_type,
914                        );
915                    }
916                    if let Some((v_type, v)) = vertical {
917                        self.accel_y = self.calc_accel_xy(
918                            runner.get_bullet_speed_y(),
919                            self.get_number_contents(v, data, runner),
920                            term,
921                            v_type,
922                        );
923                    }
924                }
925            }
926        }
927        self.act = None;
928    }
929
930    fn calc_accel_xy(
931        &self,
932        first_spd: f64,
933        value: f64,
934        term: u32,
935        hv_type: HVType,
936    ) -> Option<LinearFunc<u32, f64>> {
937        let act_turn = self.act_turn.unwrap_or(0);
938        let final_turn = act_turn + term;
939        let final_spd = match hv_type {
940            HVType::Sequence => first_spd + value * f64::from(term),
941            HVType::Relative => first_spd + value,
942            HVType::Absolute => value,
943        };
944        Some(LinearFunc::new(act_turn, final_turn, first_spd, final_spd))
945    }
946
947    fn run_vanish<D>(&mut self, data: &mut RunnerData<D>, runner: &mut dyn AppRunner<D>) {
948        runner.do_vanish(&mut data.data);
949        self.act = None;
950    }
951
952    fn get_parameters<D>(&self, data: &mut RunnerData<D>, runner: &dyn AppRunner<D>) -> Parameters {
953        let children = self.act.unwrap().children(&data.bml.arena);
954        let mut parameters = Vec::new();
955        for child in children {
956            let child_node = &data.bml.arena[child];
957            if let BulletMLNode::Param(expr) = child_node.get() {
958                parameters.push(self.get_number_contents(*expr, data, runner));
959            }
960        }
961        parameters
962    }
963
964    fn get_number_contents<D>(
965        &self,
966        expr: BulletMLExpression,
967        data: &mut RunnerData<D>,
968        runner: &dyn AppRunner<D>,
969    ) -> f64 {
970        match expr {
971            BulletMLExpression::Const(value) => value,
972            BulletMLExpression::Expr(expr) => {
973                let rank = runner.get_rank(&data.data);
974                let expr_ref = expr.from(&data.bml.expr_slab.ps);
975                use fasteval::Evaler;
976                expr_ref
977                    .eval(
978                        &data.bml.expr_slab,
979                        &mut |name: &str, args: Vec<f64>| match (name, args.as_slice()) {
980                            ("v", &[i]) => Some(self.parameters[i as usize - 1]),
981                            ("rank", &[]) => Some(rank),
982                            ("rand", &[]) => Some(runner.get_rand(data.data)),
983                            _ => None,
984                        },
985                    )
986                    .unwrap()
987            }
988        }
989    }
990}
991
992#[derive(Debug)]
993struct RepeatElem {
994    iter: usize,
995    end: usize,
996    act: NodeId,
997}
998
999#[cfg(test)]
1000mod test_runner {
1001    use super::{AppRunner, Runner, RunnerData, State};
1002    use crate::parse::BulletMLParser;
1003    use crate::tree::{BulletML, BulletMLNode};
1004
1005    pub struct TestAppRunner {
1006        index: usize,
1007        turn: u32,
1008        new_runners: Vec<Runner<TestAppRunner>>,
1009    }
1010
1011    impl From<Runner<TestAppRunner>> for TestAppRunner {
1012        fn from(runner: Runner<TestAppRunner>) -> Self {
1013            runner.app_runner
1014        }
1015    }
1016
1017    struct TestLog {
1018        log: Vec<String>,
1019        pos: usize,
1020        var_name: String,
1021    }
1022
1023    impl TestLog {
1024        fn new(var_name: String) -> Self {
1025            TestLog {
1026                log: Vec::new(),
1027                pos: 0,
1028                var_name,
1029            }
1030        }
1031
1032        fn assert_log(&mut self, value: &str, times: usize) {
1033            if self.pos + times > self.log.len() {
1034                panic!("too far {} > {}", self.pos + times, self.log.len());
1035            }
1036            for val in &self.log[self.pos..(self.pos + times)] {
1037                assert_eq!(val, value);
1038            }
1039            self.pos += times;
1040        }
1041
1042        fn assert_log_end(&mut self) {
1043            let mut pos = self.pos;
1044            if pos < self.log.len() {
1045                println!("{} at position {}", self.var_name, pos);
1046            }
1047            while pos < self.log.len() {
1048                let value = &self.log[pos];
1049                let mut count = 1;
1050                for val in &self.log[pos + 1..] {
1051                    if val == value {
1052                        count += 1;
1053                    } else {
1054                        break;
1055                    }
1056                }
1057                println!(
1058                    "    {}.assert_log(r#\"{}\"#, {});",
1059                    self.var_name, value, count
1060                );
1061                pos += count;
1062            }
1063            assert_eq!(self.pos, self.log.len());
1064            self.log.truncate(0);
1065        }
1066    }
1067
1068    struct TestLogs(Vec<TestLog>);
1069
1070    impl Drop for TestLogs {
1071        fn drop(&mut self) {
1072            for log in &mut self.0 {
1073                log.assert_log_end();
1074            }
1075        }
1076    }
1077
1078    impl TestAppRunner {
1079        pub fn new(index: usize) -> Self {
1080            TestAppRunner {
1081                index,
1082                turn: 0,
1083                new_runners: Vec::new(),
1084            }
1085        }
1086
1087        pub fn next_turn(&mut self) {
1088            self.turn += 1;
1089        }
1090
1091        fn log_iteration(&mut self, iteration: u32, logs: &mut Vec<TestLog>) {
1092            if self.index >= logs.len() {
1093                logs.push(TestLog::new(format!("logs[{}]", self.index)));
1094            }
1095            logs[self.index].log.push(format!("=== {}", iteration));
1096        }
1097    }
1098
1099    struct TestAppData<'a> {
1100        logs: &'a mut Vec<TestLog>,
1101    }
1102
1103    impl<'a> AppRunner<TestAppData<'a>> for TestAppRunner {
1104        fn get_bullet_direction(&self, _data: &TestAppData<'a>) -> f64 {
1105            0.
1106        }
1107
1108        fn get_aim_direction(&self, _data: &TestAppData<'a>) -> f64 {
1109            0.
1110        }
1111
1112        fn get_bullet_speed(&self, _data: &TestAppData<'a>) -> f64 {
1113            1.
1114        }
1115
1116        fn get_default_speed(&self) -> f64 {
1117            10.
1118        }
1119
1120        fn get_rank(&self, _data: &TestAppData<'a>) -> f64 {
1121            1.
1122        }
1123
1124        fn create_simple_bullet(&mut self, data: &mut TestAppData<'a>, direction: f64, speed: f64) {
1125            data.logs[self.index]
1126                .log
1127                .push(format!("create_simple_bullet({}, {})", direction, speed));
1128        }
1129
1130        fn create_bullet(
1131            &mut self,
1132            data: &mut TestAppData<'a>,
1133            state: State,
1134            direction: f64,
1135            speed: f64,
1136        ) {
1137            data.logs[self.index]
1138                .log
1139                .push(format!("create_bullet({}, {})", direction, speed));
1140            let runner = Runner::new_from_state(TestAppRunner::new(0), state);
1141            self.new_runners.push(runner);
1142        }
1143
1144        fn get_turn(&self, _data: &TestAppData<'a>) -> u32 {
1145            self.turn
1146        }
1147
1148        fn do_vanish(&mut self, _data: &mut TestAppData<'a>) {}
1149
1150        fn do_change_direction(&mut self, data: &mut TestAppData<'a>, direction: f64) {
1151            data.logs[self.index]
1152                .log
1153                .push(format!("do_change_direction({})", direction));
1154        }
1155
1156        fn do_change_speed(&mut self, data: &mut TestAppData<'a>, speed: f64) {
1157            data.logs[self.index]
1158                .log
1159                .push(format!("do_change_speed({})", speed));
1160        }
1161
1162        fn get_rand(&self, _data: &mut TestAppData<'a>) -> f64 {
1163            0.42
1164        }
1165
1166        fn log(&mut self, data: &mut TestAppData<'a>, node: &BulletMLNode) {
1167            data.logs[self.index].log.push(format!("{:?}", node));
1168        }
1169    }
1170
1171    struct TestManager {
1172        bml: BulletML,
1173        runners: Vec<Runner<TestAppRunner>>,
1174    }
1175
1176    impl<'a> TestManager {
1177        fn new(bml: BulletML) -> Self {
1178            TestManager {
1179                bml,
1180                runners: Vec::new(),
1181            }
1182        }
1183
1184        fn run(&mut self, iteration: u32, logs: &mut Vec<TestLog>) {
1185            let mut new_runners = Vec::new();
1186            for runner in &mut self.runners {
1187                if !runner.is_end() {
1188                    runner.app_runner.log_iteration(iteration, logs);
1189                    runner.run(&mut RunnerData {
1190                        bml: &self.bml,
1191                        data: &mut TestAppData { logs },
1192                    });
1193                    new_runners.extend(&mut runner.new_runners.drain(..));
1194                    runner.app_runner.next_turn();
1195                }
1196            }
1197            self.runners.reserve(new_runners.len());
1198            for mut runner in new_runners.drain(..) {
1199                runner.app_runner.index = self.runners.len();
1200                self.runners.push(runner);
1201            }
1202        }
1203
1204        fn run_test(&mut self, max_iter: u32, logs: &mut Vec<TestLog>) {
1205            let runner = Runner::new(TestAppRunner::new(self.runners.len()), &self.bml);
1206            self.runners.push(runner);
1207            for i in 0..max_iter {
1208                self.run(i, logs);
1209            }
1210        }
1211    }
1212
1213    #[test]
1214    fn test_mini() {
1215        let bml = BulletMLParser::new()
1216            .parse(
1217                r##"<?xml version="1.0" ?>
1218<!DOCTYPE bulletml SYSTEM "../../bulletml.dtd">
1219<bulletml>
1220<action label="top">
1221    <fire>
1222        <bullet />
1223    </fire>
1224</action>
1225</bulletml>"##,
1226            )
1227            .unwrap();
1228        let mut manager = TestManager::new(bml);
1229        let mut logs = Vec::new();
1230        manager.run_test(100, &mut logs);
1231        logs[0].assert_log(r#"=== 0"#, 1);
1232        logs[0].assert_log(r#"Action(Some("top"))"#, 1);
1233        logs[0].assert_log(r#"Fire(None)"#, 1);
1234        logs[0].assert_log(r#"Bullet(None)"#, 1);
1235        logs[0].assert_log(r#"create_simple_bullet(0, 10)"#, 1);
1236        logs[0].assert_log(r#"=== 1"#, 1);
1237        TestLogs(logs);
1238    }
1239
1240    #[test]
1241    fn test_mini_aim() {
1242        let bml = BulletMLParser::new()
1243            .parse(
1244                r##"<?xml version="1.0" ?>
1245<!DOCTYPE bulletml SYSTEM "../../bulletml.dtd">
1246<bulletml>
1247<action label="top">
1248    <repeat>
1249        <times>1000</times>
1250        <action>
1251            <fire>
1252                <bullet>
1253                    <direction type="aim">0</direction>
1254                    <speed>1</speed>
1255                </bullet>
1256            </fire>
1257            <wait>100</wait>
1258        </action>
1259    </repeat>
1260</action>
1261</bulletml>"##,
1262            )
1263            .unwrap();
1264        let mut manager = TestManager::new(bml);
1265        let mut logs = Vec::new();
1266        manager.run_test(110000, &mut logs);
1267        logs[0].assert_log(r#"=== 0"#, 1);
1268        logs[0].assert_log(r#"Action(Some("top"))"#, 1);
1269        logs[0].assert_log(r#"Repeat"#, 1);
1270        for i in 0..1000 {
1271            logs[0].assert_log(r#"Action(None)"#, 1);
1272            logs[0].assert_log(r#"Fire(None)"#, 1);
1273            logs[0].assert_log(r#"Bullet(None)"#, 1);
1274            logs[0].assert_log(r#"create_simple_bullet(0, 1)"#, 1);
1275            logs[0].assert_log(r#"Wait(Const(100.0))"#, 1);
1276            for j in 0..100 {
1277                logs[0].assert_log(&format!(r#"=== {}"#, i * 100 + j + 1), 1);
1278            }
1279        }
1280        TestLogs(logs);
1281    }
1282
1283    #[test]
1284    fn test_bulletsmorph_double_seduction() {
1285        let bml = BulletMLParser::with_capacities(12, 128)
1286            .parse(
1287                r##"<?xml version="1.0" ?>
1288    <!DOCTYPE bulletml SYSTEM "../bulletml.dtd">
1289    <bulletml type="vertical" xmlns="http://www.asahi-net.or.jp/~cs8k-cyu/bulletml">
1290    <action label="top">
1291        <fire>
1292            <direction type="aim">30</direction>
1293            <bulletRef label="parentbit">
1294                <param>1</param>
1295            </bulletRef>
1296        </fire>
1297        <fire>
1298            <direction type="aim">-30</direction>
1299            <bulletRef label="parentbit">
1300                <param>-1</param>
1301            </bulletRef>
1302        </fire>
1303        <wait>300</wait>
1304    </action>
1305    <bullet label="parentbit">
1306        <speed>2.0</speed>
1307        <action>
1308            <actionRef label="cross">
1309                <param>75</param>
1310                <param>0</param>
1311            </actionRef>
1312            <actionRef label="cross">
1313                <param>70</param>
1314                <param>0</param>
1315            </actionRef>
1316            <actionRef label="cross">
1317                <param>65</param>
1318                <param>0</param>
1319            </actionRef>
1320            <actionRef label="cross">
1321                <param>60</param>
1322                <param>0</param>
1323            </actionRef>
1324            <actionRef label="cross">
1325               <param>55</param>
1326                <param>0</param>
1327            </actionRef>
1328            <actionRef label="cross">
1329                <param>50</param>
1330                <param>0</param>
1331            </actionRef>
1332            <actionRef label="cross">
1333                <param>80</param>
1334                <param>15 * $1</param>
1335            </actionRef>
1336                <actionRef label="cross">
1337                <param>75</param>
1338                <param>10 * $1</param>
1339            </actionRef>
1340            <actionRef label="cross">
1341                <param>70</param>
1342                <param>6 * $1</param>
1343            </actionRef>
1344            <actionRef label="cross">
1345                <param>65</param>
1346                <param>3 * $1</param>
1347            </actionRef>
1348            <actionRef label="cross">
1349                <param>60</param>
1350                <param>1 * $1</param>
1351            </actionRef>
1352            <actionRef label="cross">
1353                <param>55</param>
1354                <param>0</param>
1355            </actionRef>
1356            <vanish/>
1357        </action>
1358    </bullet>
1359    <action label="cross">
1360        <fire>
1361            <direction type="absolute">0</direction>
1362            <bulletRef label="aimbit">
1363                <param>$1</param>
1364                <param>$2</param>
1365            </bulletRef>
1366        </fire>
1367        <fire>
1368            <direction type="absolute">90</direction>
1369            <bulletRef label="aimbit">
1370                <param>$1</param>
1371                <param>$2</param>
1372            </bulletRef>
1373        </fire>
1374        <fire>
1375            <direction type="absolute">180</direction>
1376            <bulletRef label="aimbit">
1377                <param>$1</param>
1378                <param>$2</param>
1379            </bulletRef>
1380        </fire>
1381        <fire>
1382            <direction type="absolute">270</direction>
1383            <bulletRef label="aimbit">
1384                <param>$1</param>
1385                <param>$2</param>
1386            </bulletRef>
1387        </fire>
1388        <wait>5</wait>
1389    </action>
1390    <bullet label="aimbit">
1391        <speed>0.6</speed>
1392        <action>
1393            <wait>$1</wait>
1394            <fire>
1395                <direction type="aim">$2</direction>
1396                <speed>1.6 * (0.5 + 0.5 * $rank)</speed>
1397                <bullet/>
1398            </fire>
1399            <repeat>
1400                <times>2 + 5 * $rank</times>
1401                <action>
1402                    <fire>
1403                        <direction type="sequence">0</direction>
1404                        <speed type="sequence">0.1</speed>
1405                        <bullet/>
1406                    </fire>
1407                </action>
1408            </repeat>
1409            <vanish/>
1410        </action>
1411    </bullet>
1412    </bulletml>"##,
1413            )
1414            .unwrap();
1415        let mut manager = TestManager::new(bml);
1416        let mut logs = Vec::new();
1417        manager.run_test(1000, &mut logs);
1418        logs[0].assert_log(r#"=== 0"#, 1);
1419        logs[0].assert_log(r#"Action(Some("top"))"#, 1);
1420        logs[0].assert_log(r#"Fire(None)"#, 1);
1421        logs[0].assert_log(r#"BulletRef("parentbit")"#, 1);
1422        logs[0].assert_log(r#"Bullet(Some("parentbit"))"#, 1);
1423        logs[0].assert_log(r#"create_bullet(30, 2)"#, 1);
1424        logs[0].assert_log(r#"Fire(None)"#, 1);
1425        logs[0].assert_log(r#"BulletRef("parentbit")"#, 1);
1426        logs[0].assert_log(r#"Bullet(Some("parentbit"))"#, 1);
1427        logs[0].assert_log(r#"create_bullet(330, 2)"#, 1);
1428        logs[0].assert_log(r#"Wait(Const(300.0))"#, 1);
1429        for i in 0..300 {
1430            logs[0].assert_log(&format!(r#"=== {}"#, i + 1), 1);
1431        }
1432
1433        for i in 1..3 {
1434            logs[i].assert_log(r#"=== 1"#, 1);
1435            logs[i].assert_log(r#"Action(None)"#, 1);
1436            for j in 0..12 {
1437                logs[i].assert_log(r#"ActionRef("cross")"#, 1);
1438                logs[i].assert_log(r#"Action(Some("cross"))"#, 1);
1439                for k in 0..4 {
1440                    logs[i].assert_log(r#"Fire(None)"#, 1);
1441                    logs[i].assert_log(r#"BulletRef("aimbit")"#, 1);
1442                    logs[i].assert_log(r#"Bullet(Some("aimbit"))"#, 1);
1443                    logs[i].assert_log(&format!(r#"create_bullet({}, 0.6)"#, k * 90 % 360), 1);
1444                }
1445                logs[i].assert_log(r#"Wait(Const(5.0))"#, 1);
1446                for k in 0..5 {
1447                    logs[i].assert_log(&format!(r#"=== {}"#, j * 5 + k + 2), 1);
1448                }
1449            }
1450            logs[i].assert_log(r#"Vanish"#, 1);
1451            logs[i].assert_log(&format!(r#"=== {}"#, 62), 1);
1452        }
1453
1454        let v1s = [75, 70, 65, 60, 55, 50, 80, 75, 70, 65, 60, 55];
1455        let v2_factors = [0, 0, 0, 0, 0, 0, 15, 10, 6, 3, 1, 0];
1456        for i in 3..99 {
1457            logs[i].assert_log(&format!(r#"=== {}"#, (i - 3) / 8 * 5 + 2), 1);
1458            let mut spd = 1.6;
1459            for j in 0..1 {
1460                logs[i].assert_log(r#"Action(None)"#, 1);
1461                logs[i].assert_log(r#"Wait(Expr(ExpressionI(27)))"#, 1);
1462                for k in 0..v1s[(i - 3) / 8 % 12] {
1463                    logs[i].assert_log(&format!(r#"=== {}"#, (i - 3) / 8 * 5 + k + 3), 1);
1464                }
1465                logs[i].assert_log(r#"Fire(None)"#, 1);
1466                logs[i].assert_log(r#"Bullet(None)"#, 1);
1467                let mut dir = v2_factors[j + (i - 3) / 8] * (((i - 3) % 8 / 4) as isize * -2 + 1);
1468                if dir > 360 {
1469                    dir -= 360;
1470                }
1471                if dir < 0 {
1472                    dir += 360;
1473                }
1474                logs[i].assert_log(&format!(r#"create_simple_bullet({}, {})"#, dir, spd), 1);
1475                logs[i].assert_log(r#"Repeat"#, 1);
1476                for _ in 0..7 {
1477                    logs[i].assert_log(r#"Action(None)"#, 1);
1478                    logs[i].assert_log(r#"Fire(None)"#, 1);
1479                    logs[i].assert_log(r#"Bullet(None)"#, 1);
1480                    spd += 0.1;
1481                    logs[i].assert_log(&format!(r#"create_simple_bullet({}, {})"#, dir, spd), 1);
1482                }
1483                logs[i].assert_log(r#"Vanish"#, 1);
1484            }
1485            logs[i].assert_log(
1486                &format!(r#"=== {}"#, (i - 3) / 8 * 5 + v1s[(i - 3) / 8 % 12] + 3),
1487                1,
1488            );
1489        }
1490        TestLogs(logs);
1491    }
1492
1493    #[test]
1494    fn test_tt_morph_0to1() {
1495        let bml = BulletMLParser::new()
1496            .parse(
1497                r##"<?xml version="1.0" ?>
1498<!DOCTYPE bulletml SYSTEM "http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/bulletml.dtd">
1499
1500<bulletml type="vertical"
1501          xmlns="http://www.asahi-net.or.jp/~cs8k-cyu/bulletml">
1502
1503<action label="top">
1504        <changeSpeed>
1505                <speed>0</speed>
1506                <term>1</term>
1507        </changeSpeed>
1508        <wait>1</wait>
1509        <changeSpeed>
1510                <speed>1</speed>
1511                <term>60-$rank*50</term>
1512        </changeSpeed>
1513        <wait>60-$rank*50</wait>
1514        <fire>
1515                <direction type="relative">0</direction>
1516                <bullet/>
1517        </fire>
1518</action>
1519
1520</bulletml>"##,
1521            )
1522            .unwrap();
1523        let mut manager = TestManager::new(bml);
1524        let mut logs = Vec::new();
1525        manager.run_test(100, &mut logs);
1526        logs[0].assert_log(r#"=== 0"#, 1);
1527        logs[0].assert_log(r#"Action(Some("top"))"#, 1);
1528        logs[0].assert_log(r#"ChangeSpeed"#, 1);
1529        logs[0].assert_log(r#"Wait(Const(1.0))"#, 1);
1530        logs[0].assert_log(r#"=== 1"#, 1);
1531        logs[0].assert_log(r#"do_change_speed(0)"#, 1);
1532        logs[0].assert_log(r#"ChangeSpeed"#, 1);
1533        logs[0].assert_log(r#"Wait(Expr(ExpressionI(1)))"#, 1);
1534        logs[0].assert_log(r#"=== 2"#, 1);
1535        logs[0].assert_log(r#"do_change_speed(1)"#, 1);
1536        logs[0].assert_log(r#"=== 3"#, 1);
1537        logs[0].assert_log(r#"do_change_speed(1)"#, 1);
1538        logs[0].assert_log(r#"=== 4"#, 1);
1539        logs[0].assert_log(r#"do_change_speed(1)"#, 1);
1540        logs[0].assert_log(r#"=== 5"#, 1);
1541        logs[0].assert_log(r#"do_change_speed(1)"#, 1);
1542        logs[0].assert_log(r#"=== 6"#, 1);
1543        logs[0].assert_log(r#"do_change_speed(1)"#, 1);
1544        logs[0].assert_log(r#"=== 7"#, 1);
1545        logs[0].assert_log(r#"do_change_speed(1)"#, 1);
1546        logs[0].assert_log(r#"=== 8"#, 1);
1547        logs[0].assert_log(r#"do_change_speed(1)"#, 1);
1548        logs[0].assert_log(r#"=== 9"#, 1);
1549        logs[0].assert_log(r#"do_change_speed(1)"#, 1);
1550        logs[0].assert_log(r#"=== 10"#, 1);
1551        logs[0].assert_log(r#"do_change_speed(1)"#, 1);
1552        logs[0].assert_log(r#"=== 11"#, 1);
1553        logs[0].assert_log(r#"do_change_speed(1)"#, 1);
1554        logs[0].assert_log(r#"Fire(None)"#, 1);
1555        logs[0].assert_log(r#"Bullet(None)"#, 1);
1556        logs[0].assert_log(r#"create_simple_bullet(0, 10)"#, 1);
1557        logs[0].assert_log(r#"=== 12"#, 1);
1558        TestLogs(logs);
1559    }
1560
1561    #[test]
1562    fn test_tt_morph_accelshot() {
1563        let bml = BulletMLParser::new()
1564            .parse(
1565                r##"<?xml version="1.0" ?>
1566<!DOCTYPE bulletml SYSTEM "http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/bulletml.dtd">
1567
1568<bulletml type="vertical"
1569          xmlns="http://www.asahi-net.or.jp/~cs8k-cyu/bulletml">
1570
1571<action label="top">
1572        <fire>
1573                <direction type="relative">0</direction>
1574                <speed type="relative">-0.9</speed>
1575                <bulletRef label="accel"/>
1576        </fire>
1577        <repeat><times>$rank*1.7</times>
1578        <action>
1579                <wait>2</wait>
1580                <fire>
1581                        <direction type="relative">0</direction>
1582                        <speed type="sequence">0.3</speed>
1583                        <bulletRef label="accel"/>
1584                </fire>
1585        </action>
1586        </repeat>
1587        <vanish/>
1588</action>
1589
1590<bullet label="accel">
1591        <action>
1592                <wait>3</wait>
1593                <changeSpeed>
1594                        <speed>1</speed>
1595                        <term>60</term>
1596                </changeSpeed>
1597        </action>
1598</bullet>
1599
1600</bulletml>"##,
1601            )
1602            .unwrap();
1603        let mut manager = TestManager::new(bml);
1604        let mut logs = Vec::new();
1605        manager.run_test(100, &mut logs);
1606        logs[0].assert_log(r#"=== 0"#, 1);
1607        logs[0].assert_log(r#"Action(Some("top"))"#, 1);
1608        logs[0].assert_log(r#"Fire(None)"#, 1);
1609        logs[0].assert_log(r#"BulletRef("accel")"#, 1);
1610        logs[0].assert_log(r#"Bullet(Some("accel"))"#, 1);
1611        logs[0].assert_log(r#"create_bullet(0, 0.09999999999999998)"#, 1);
1612        logs[0].assert_log(r#"Repeat"#, 1);
1613        logs[0].assert_log(r#"Action(None)"#, 1);
1614        logs[0].assert_log(r#"Wait(Const(2.0))"#, 1);
1615        logs[0].assert_log(r#"=== 1"#, 1);
1616        logs[0].assert_log(r#"=== 2"#, 1);
1617        logs[0].assert_log(r#"Fire(None)"#, 1);
1618        logs[0].assert_log(r#"BulletRef("accel")"#, 1);
1619        logs[0].assert_log(r#"Bullet(Some("accel"))"#, 1);
1620        logs[0].assert_log(r#"create_bullet(0, 0.39999999999999997)"#, 1);
1621        logs[0].assert_log(r#"Vanish"#, 1);
1622        logs[0].assert_log(r#"=== 3"#, 1);
1623
1624        logs[1].assert_log(r#"=== 1"#, 1);
1625        logs[1].assert_log(r#"Action(None)"#, 1);
1626        logs[1].assert_log(r#"Wait(Const(3.0))"#, 1);
1627        logs[1].assert_log(r#"=== 2"#, 1);
1628        logs[1].assert_log(r#"=== 3"#, 1);
1629        logs[1].assert_log(r#"=== 4"#, 1);
1630        logs[1].assert_log(r#"ChangeSpeed"#, 1);
1631        for i in 0..60 {
1632            logs[1].assert_log(&format!(r#"=== {}"#, i + 5), 1);
1633            logs[1].assert_log(r#"do_change_speed(1)"#, 1);
1634        }
1635
1636        logs[2].assert_log(r#"=== 3"#, 1);
1637        logs[2].assert_log(r#"Action(None)"#, 1);
1638        logs[2].assert_log(r#"Wait(Const(3.0))"#, 1);
1639        logs[2].assert_log(r#"=== 4"#, 1);
1640        logs[2].assert_log(r#"=== 5"#, 1);
1641        logs[2].assert_log(r#"=== 6"#, 1);
1642        logs[2].assert_log(r#"ChangeSpeed"#, 1);
1643        for i in 0..60 {
1644            logs[2].assert_log(&format!(r#"=== {}"#, i + 7), 1);
1645            logs[2].assert_log(r#"do_change_speed(1)"#, 1);
1646        }
1647        TestLogs(logs);
1648    }
1649
1650    #[test]
1651    fn test_tt_morph_twin() {
1652        let bml = BulletMLParser::new()
1653            .parse(
1654                r##"<?xml version="1.0" ?>
1655<!DOCTYPE bulletml SYSTEM "http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/bulletml.dtd">
1656
1657<bulletml type="vertical"
1658          xmlns="http://www.asahi-net.or.jp/~cs8k-cyu/bulletml">
1659
1660
1661 <action label="top">
1662  <wait>1</wait>
1663  <fire>
1664   <bullet>
1665        <direction type="relative">0</direction>
1666        <speed type="relative">$rank</speed>
1667    <actionRef label="ofs">
1668     <param>90</param>
1669    </actionRef>
1670   </bullet>
1671  </fire>
1672  <fire>
1673   <bullet>
1674        <direction type="relative">0</direction>
1675        <speed type="relative">$rank</speed>
1676    <actionRef label="ofs">
1677     <param>-90</param>
1678    </actionRef>
1679   </bullet>
1680  </fire>
1681  <vanish/>
1682 </action>
1683
1684<action label="ofs">
1685  <changeDirection>
1686   <direction type="relative">$1</direction>
1687   <term>1</term>
1688  </changeDirection>
1689  <wait>1</wait>
1690  <changeDirection>
1691   <direction type="relative">0-$1</direction>
1692   <term>1</term>
1693  </changeDirection>
1694  <wait>1</wait>
1695  <fire>
1696        <direction type="relative">0</direction>
1697        <speed type="relative">-$rank</speed>
1698        <bullet/>
1699  </fire>
1700  <vanish/>
1701</action>
1702
1703</bulletml>"##,
1704            )
1705            .unwrap();
1706        let mut manager = TestManager::new(bml);
1707        let mut logs = Vec::new();
1708        manager.run_test(100, &mut logs);
1709        logs[0].assert_log(r#"=== 0"#, 1);
1710        logs[0].assert_log(r#"Action(Some("top"))"#, 1);
1711        logs[0].assert_log(r#"Wait(Const(1.0))"#, 1);
1712        logs[0].assert_log(r#"=== 1"#, 1);
1713        logs[0].assert_log(r#"Fire(None)"#, 1);
1714        logs[0].assert_log(r#"Bullet(None)"#, 1);
1715        logs[0].assert_log(r#"create_bullet(0, 2)"#, 1);
1716        logs[0].assert_log(r#"Fire(None)"#, 1);
1717        logs[0].assert_log(r#"Bullet(None)"#, 1);
1718        logs[0].assert_log(r#"create_bullet(0, 2)"#, 1);
1719        logs[0].assert_log(r#"Vanish"#, 1);
1720        logs[0].assert_log(r#"=== 2"#, 1);
1721
1722        logs[1].assert_log(r#"=== 2"#, 1);
1723        logs[1].assert_log(r#"ActionRef("ofs")"#, 1);
1724        logs[1].assert_log(r#"Action(Some("ofs"))"#, 1);
1725        logs[1].assert_log(r#"ChangeDirection"#, 1);
1726        logs[1].assert_log(r#"Wait(Const(1.0))"#, 1);
1727        logs[1].assert_log(r#"=== 3"#, 1);
1728        logs[1].assert_log(r#"do_change_direction(90)"#, 1);
1729        logs[1].assert_log(r#"ChangeDirection"#, 1);
1730        logs[1].assert_log(r#"Wait(Const(1.0))"#, 1);
1731        logs[1].assert_log(r#"=== 4"#, 1);
1732        logs[1].assert_log(r#"do_change_direction(-90)"#, 1);
1733        logs[1].assert_log(r#"Fire(None)"#, 1);
1734        logs[1].assert_log(r#"Bullet(None)"#, 1);
1735        logs[1].assert_log(r#"create_simple_bullet(0, 0)"#, 1);
1736        logs[1].assert_log(r#"Vanish"#, 1);
1737        logs[1].assert_log(r#"=== 5"#, 1);
1738
1739        logs[2].assert_log(r#"=== 2"#, 1);
1740        logs[2].assert_log(r#"ActionRef("ofs")"#, 1);
1741        logs[2].assert_log(r#"Action(Some("ofs"))"#, 1);
1742        logs[2].assert_log(r#"ChangeDirection"#, 1);
1743        logs[2].assert_log(r#"Wait(Const(1.0))"#, 1);
1744        logs[2].assert_log(r#"=== 3"#, 1);
1745        logs[2].assert_log(r#"do_change_direction(-90)"#, 1);
1746        logs[2].assert_log(r#"ChangeDirection"#, 1);
1747        logs[2].assert_log(r#"Wait(Const(1.0))"#, 1);
1748        logs[2].assert_log(r#"=== 4"#, 1);
1749        logs[2].assert_log(r#"do_change_direction(90)"#, 1);
1750        logs[2].assert_log(r#"Fire(None)"#, 1);
1751        logs[2].assert_log(r#"Bullet(None)"#, 1);
1752        logs[2].assert_log(r#"create_simple_bullet(0, 0)"#, 1);
1753        logs[2].assert_log(r#"Vanish"#, 1);
1754        logs[2].assert_log(r#"=== 5"#, 1);
1755        TestLogs(logs);
1756    }
1757
1758    #[test]
1759    fn test_tt_morph_wedge_half() {
1760        let bml = BulletMLParser::new()
1761            .parse(
1762                r##"<?xml version="1.0" ?>
1763<!DOCTYPE bulletml SYSTEM "http://www.asahi-net.or.jp/~cs8k-cyu/bulletml/bulletml.dtd">
1764
1765<bulletml type="vertical"
1766          xmlns="http://www.asahi-net.or.jp/~cs8k-cyu/bulletml">
1767
1768 <action label="top">
1769  <wait>1</wait>
1770  <fire>
1771   <bullet>
1772        <direction type="relative">0</direction>
1773        <speed type="relative">$rank*0.4+0.2</speed>
1774    <actionRef label="ofs">
1775     <param>0</param>
1776     <param>-0.08</param>
1777    </actionRef>
1778   </bullet>
1779  </fire>
1780  <fire>
1781   <bullet>
1782        <direction type="relative">0</direction>
1783        <speed type="relative">$rank*0.4+0.2</speed>
1784    <actionRef label="ofs">
1785     <param>-120</param>
1786     <param>0.08</param>
1787    </actionRef>
1788   </bullet>
1789  </fire>
1790  <vanish/>
1791 </action>
1792
1793<action label="ofs">
1794  <changeDirection>
1795   <direction type="relative">$1</direction>
1796   <term>1</term>
1797  </changeDirection>
1798  <wait>1</wait>
1799  <changeDirection>
1800   <direction type="relative">0-$1</direction>
1801   <term>1</term>
1802  </changeDirection>
1803  <wait>1</wait>
1804  <fire>
1805        <direction type="relative">0</direction>
1806        <speed type="relative">$2-$rank*0.4-0.2</speed>
1807        <bullet/>
1808  </fire>
1809  <vanish/>
1810</action>
1811
1812</bulletml>"##,
1813            )
1814            .unwrap();
1815        let mut manager = TestManager::new(bml);
1816        let mut logs = Vec::new();
1817        manager.run_test(100, &mut logs);
1818        logs[0].assert_log(r#"=== 0"#, 1);
1819        logs[0].assert_log(r#"Action(Some("top"))"#, 1);
1820        logs[0].assert_log(r#"Wait(Const(1.0))"#, 1);
1821        logs[0].assert_log(r#"=== 1"#, 1);
1822        logs[0].assert_log(r#"Fire(None)"#, 1);
1823        logs[0].assert_log(r#"Bullet(None)"#, 1);
1824        logs[0].assert_log(r#"create_bullet(0, 1.6)"#, 1);
1825        logs[0].assert_log(r#"Fire(None)"#, 1);
1826        logs[0].assert_log(r#"Bullet(None)"#, 1);
1827        logs[0].assert_log(r#"create_bullet(0, 1.6)"#, 1);
1828        logs[0].assert_log(r#"Vanish"#, 1);
1829        logs[0].assert_log(r#"=== 2"#, 1);
1830
1831        logs[1].assert_log(r#"=== 2"#, 1);
1832        logs[1].assert_log(r#"ActionRef("ofs")"#, 1);
1833        logs[1].assert_log(r#"Action(Some("ofs"))"#, 1);
1834        logs[1].assert_log(r#"ChangeDirection"#, 1);
1835        logs[1].assert_log(r#"Wait(Const(1.0))"#, 1);
1836        logs[1].assert_log(r#"=== 3"#, 1);
1837        logs[1].assert_log(r#"do_change_direction(0)"#, 1);
1838        logs[1].assert_log(r#"ChangeDirection"#, 1);
1839        logs[1].assert_log(r#"Wait(Const(1.0))"#, 1);
1840        logs[1].assert_log(r#"=== 4"#, 1);
1841        logs[1].assert_log(r#"do_change_direction(0)"#, 1);
1842        logs[1].assert_log(r#"Fire(None)"#, 1);
1843        logs[1].assert_log(r#"Bullet(None)"#, 1);
1844        logs[1].assert_log(r#"create_simple_bullet(0, 0.31999999999999995)"#, 1);
1845        logs[1].assert_log(r#"Vanish"#, 1);
1846        logs[1].assert_log(r#"=== 5"#, 1);
1847
1848        logs[2].assert_log(r#"=== 2"#, 1);
1849        logs[2].assert_log(r#"ActionRef("ofs")"#, 1);
1850        logs[2].assert_log(r#"Action(Some("ofs"))"#, 1);
1851        logs[2].assert_log(r#"ChangeDirection"#, 1);
1852        logs[2].assert_log(r#"Wait(Const(1.0))"#, 1);
1853        logs[2].assert_log(r#"=== 3"#, 1);
1854        logs[2].assert_log(r#"do_change_direction(-120)"#, 1);
1855        logs[2].assert_log(r#"ChangeDirection"#, 1);
1856        logs[2].assert_log(r#"Wait(Const(1.0))"#, 1);
1857        logs[2].assert_log(r#"=== 4"#, 1);
1858        logs[2].assert_log(r#"do_change_direction(120)"#, 1);
1859        logs[2].assert_log(r#"Fire(None)"#, 1);
1860        logs[2].assert_log(r#"Bullet(None)"#, 1);
1861        logs[2].assert_log(r#"create_simple_bullet(0, 0.48)"#, 1);
1862        logs[2].assert_log(r#"Vanish"#, 1);
1863        logs[2].assert_log(r#"=== 5"#, 1);
1864        TestLogs(logs);
1865    }
1866}