diff src/th06/anm0_vm.rs @ 741:3555845f8cf4

Make it so we can use more than a single anm0 in an EclRunner.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Tue, 07 Jan 2020 00:06:18 +0100
parents 6d4802abe134
children 0a250ddfae79
line wrap: on
line diff
--- a/src/th06/anm0_vm.rs
+++ b/src/th06/anm0_vm.rs
@@ -214,9 +214,50 @@ impl Sprite {
     }
 }
 
+struct Anms {
+    inner: Rc<RefCell<[Anm0; 2]>>,
+}
+
+impl Anms {
+    fn new(anms: Rc<RefCell<[Anm0; 2]>>) -> Anms {
+        Anms {
+            inner: anms,
+        }
+    }
+
+    fn load_sprite(&self, sprite: &mut Sprite, id: u8) {
+        let anms = self.inner.borrow();
+        let mut anm = None;
+        let mut texcoords = None;
+        'anm: for anm0 in anms.iter() {
+            for sp in anm0.sprites.iter() {
+                if sp.index == id as u32 {
+                    texcoords = Some(sp);
+                    anm = Some(anm0.clone());
+                    break 'anm;
+                }
+            }
+        }
+        sprite.anm = anm;
+        if let Some(texcoords) = texcoords {
+            sprite.texcoords = [texcoords.x, texcoords.y, texcoords.width, texcoords.height];
+        }
+    }
+
+    fn get_script(&self, id: u8) -> Script {
+        let anms = self.inner.borrow();
+        for anm0 in anms.iter() {
+            if anm0.scripts.contains_key(&id) {
+                return anm0.scripts[&id].clone();
+            }
+        }
+        unreachable!();
+    }
+}
+
 /// Interpreter for `Anm0` instructions to update a `Sprite`.
 pub struct AnmRunner {
-    anm: Anm0,
+    anms: Anms,
     sprite: Rc<RefCell<Sprite>>,
     prng: Weak<RefCell<Prng>>,
     running: bool,
@@ -231,15 +272,17 @@ pub struct AnmRunner {
 
 impl AnmRunner {
     /// Create a new `AnmRunner`.
-    pub fn new(anm: &Anm0, script_id: u8, sprite: Rc<RefCell<Sprite>>, prng: Weak<RefCell<Prng>>, sprite_index_offset: u32) -> AnmRunner {
+    pub fn new(anms: Rc<RefCell<[Anm0; 2]>>, script_id: u8, sprite: Rc<RefCell<Sprite>>, prng: Weak<RefCell<Prng>>, sprite_index_offset: u32) -> AnmRunner {
+        let anms = Anms::new(anms);
+        let script = anms.get_script(script_id);
         let mut runner = AnmRunner {
-            anm: anm.clone(),
+            anms,
             sprite: sprite,
             prng,
             running: true,
             waiting: false,
 
-            script: anm.scripts[&script_id].clone(),
+            script,
             frame: 0,
             timeout: None,
             instruction_pointer: 0,
@@ -321,9 +364,7 @@ impl AnmRunner {
                 self.running = false;
             }
             Instruction::LoadSprite(sprite_index) => {
-                sprite.anm = Some(self.anm.clone());
-                let texcoords = &self.anm.sprites[(sprite_index + self.sprite_index_offset) as usize];
-                sprite.texcoords = [texcoords.x, texcoords.y, texcoords.width, texcoords.height];
+                self.anms.load_sprite(&mut sprite, (sprite_index + self.sprite_index_offset) as u8);
             }
             Instruction::SetScale(sx, sy) => {
                 sprite.rescale = [sx, sy];
@@ -375,11 +416,7 @@ impl AnmRunner {
                     amplitude = (rand as u32) % amplitude;
                 }
                 let sprite_index = min_index + amplitude;
-
-                // TODO: refactor that with Instruction::LoadSprite.
-                sprite.anm = Some(self.anm.clone());
-                let texcoords = &self.anm.sprites[(sprite_index + self.sprite_index_offset) as usize];
-                sprite.texcoords = [texcoords.x, texcoords.y, texcoords.width, texcoords.height];
+                self.anms.load_sprite(&mut sprite, (sprite_index + self.sprite_index_offset) as u8);
             }
             Instruction::Move(x, y, z) => {
                 sprite.dest_offset = [x, y, z];