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
9pub struct RunnerData<'a, D: 'a> {
13 pub bml: &'a BulletML,
14 pub data: &'a mut D,
15}
16
17type Parameters = Vec<f64>;
18
19pub struct State {
25 bml_type: Option<BulletMLType>,
26 nodes: Box<[NodeId]>,
27 parameters: Parameters,
28}
29
30pub struct Runner<R> {
33 runners: Vec<RunnerImpl>,
34 app_runner: R,
35}
36
37impl<'a, R> Runner<R> {
38 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 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 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 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 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 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
166pub trait AppRunner<D> {
168 fn init(&mut self) {}
172 fn get_bullet_direction(&self, data: &D) -> f64;
174 fn get_aim_direction(&self, data: &D) -> f64;
178 fn get_bullet_speed(&self, data: &D) -> f64;
180 fn get_default_speed(&self) -> f64;
182 fn get_rank(&self, data: &D) -> f64;
185 fn create_simple_bullet(&mut self, data: &mut D, direction: f64, speed: f64);
193 fn create_bullet(&mut self, data: &mut D, state: State, direction: f64, speed: f64);
200 fn get_turn(&self, data: &D) -> u32;
202 fn do_vanish(&mut self, data: &mut D);
204 fn do_change_direction(&mut self, _data: &mut D, _direction: f64) {}
205 fn do_change_speed(&mut self, _data: &mut D, _speed: f64) {}
207 fn do_accel_x(&mut self, _: f64) {}
209 fn do_accel_y(&mut self, _: f64) {}
211 fn get_bullet_speed_x(&self) -> f64 {
213 0.
214 }
215 fn get_bullet_speed_y(&self) -> f64 {
217 0.
218 }
219 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 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 if !self.root_nodes.contains(&prev) {
512 self.act = prev_node.next_sibling();
513 }
514 }
515
516 if self.act.is_some() || self.root_nodes.contains(&prev) {
518 break;
519 }
520
521 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 self.act = Some(rep.act);
531 break;
532 }
533 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}