changeset 664:f08e8e3c6196

Use bitflags for the rank, instead of an u16.
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sun, 11 Aug 2019 19:55:45 +0200
parents 994f41154be8
children 965ecdbf0316
files Cargo.toml examples/eclrenderer.rs src/th06/ecl.rs src/th06/ecl_vm.rs src/th06/enemy.rs
diffstat 5 files changed, 37 insertions(+), 13 deletions(-) [+]
line wrap: on
line diff
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,6 +13,7 @@ license = "GPL-3.0-or-later"
 nom = "5"
 encoding_rs = "0.8"
 image = { version = "0.22", default-features = false, features = ["png_codec"] }
+bitflags = "1"
 luminance = { version = "*", path = "../luminance/luminance" }
 luminance-glfw = { version = "*", path = "../luminance/luminance-glfw", default-features = false }
 luminance-derive = { version = "*", path = "../luminance/luminance-derive" }
--- a/examples/eclrenderer.rs
+++ b/examples/eclrenderer.rs
@@ -12,7 +12,7 @@ use luminance_glfw::event::{Action, Key,
 use luminance_glfw::surface::{GlfwSurface, Surface, WindowDim, WindowOpt};
 use touhou::th06::anm0::Anm0;
 use touhou::th06::anm0_vm::{Sprite, Vertex as FakeVertex};
-use touhou::th06::ecl::Ecl;
+use touhou::th06::ecl::{Ecl, Rank};
 use touhou::th06::ecl_vm::EclRunner;
 use touhou::th06::enemy::{Enemy, Game, Position};
 use touhou::util::math::{perspective, setup_camera};
@@ -124,7 +124,7 @@ fn main() {
     let prng = Rc::new(RefCell::new(Prng::new(0)));
 
     // Create the Game god object.
-    let game = Game::new(prng);
+    let game = Game::new(prng, Rank::Normal);
     let game = Rc::new(RefCell::new(game));
 
     // And the enemy object.
--- a/src/th06/ecl.rs
+++ b/src/th06/ecl.rs
@@ -6,6 +6,27 @@ use nom::{
     number::complete::{le_u8, le_u16, le_u32, le_i16, le_i32, le_f32},
 };
 use encoding_rs::SHIFT_JIS;
+use bitflags::bitflags;
+
+bitflags! {
+    /// Bit flags describing the current difficulty level.
+    pub struct Rank: u16 {
+        /// Easy mode.
+        const Easy = 0x100;
+
+        /// Normal mode.
+        const Normal = 0x200;
+
+        /// Hard mode.
+        const Hard = 0x400;
+
+        /// Lunatic mode.
+        const Lunatic = 0x800;
+
+        /// Any or all modes.
+        const All = 0xff00;
+    }
+}
 
 /// A single instruction, part of a `Script`.
 #[derive(Debug, Clone)]
@@ -13,8 +34,8 @@ pub struct CallSub {
     /// Time at which this instruction will be called.
     pub time: i32,
 
-    /// TODO
-    pub rank_mask: u16,
+    /// The difficulty level(s) this instruction will be called at.
+    pub rank_mask: Rank,
 
     /// TODO
     pub param_mask: u16,
@@ -209,7 +230,7 @@ declare_sub_instructions!{
     81 => fn SetBulletLaunchOffset(x: f32, y: f32, z: f32),
     82 => fn SetExtendedBulletAttributes(a: i32, b: i32, c: i32, d: i32, e: f32, f: f32, g: f32, h: f32),
     83 => fn ChangeBulletsInStarBonus(),
-    // 84: ('i', None),
+    84 => fn UNK0(UNK: i32),
     85 => fn NewLaser(laser_type: i16, sprite_idx_offset: i16, angle: f32, speed: f32, start_offset: f32, end_offset: f32, max_length: f32, width: f32, start_duration: i32, duration: i32, end_duration: i32, grazing_delay: i32, grazing_extra_duration: i32, UNK1: i32),
     86 => fn NewLaserTowardsPlayer(laser_type: i16, sprite_idx_offset: i16, angle: f32, speed: f32, start_offset: f32, end_offset: f32, max_length: f32, width: f32, start_duration: i32, duration: i32, end_duration: i32, grazing_delay: i32, grazing_extra_duration: i32, UNK1: i32),
     87 => fn SetUpcomingLaserId(id: i32),
@@ -295,6 +316,7 @@ fn parse_ecl(input: &[u8]) -> IResult<&[
 
             let (i2, size) = le_u16(i2)?;
             let (i2, rank_mask) = le_u16(i2)?;
+            let rank_mask = Rank::from_bits(rank_mask).unwrap();
             let (i2, param_mask) = le_u16(i2)?;
             // FIXME: this - 12 can trigger a panic, fuzz it!
             let data = &i2[..size as usize - 12];
--- a/src/th06/ecl_vm.rs
+++ b/src/th06/ecl_vm.rs
@@ -1,6 +1,6 @@
 //! ECL runner.
 
-use crate::th06::ecl::{Ecl, SubInstruction};
+use crate::th06::ecl::{Ecl, SubInstruction, Rank};
 use crate::th06::enemy::Enemy;
 use crate::util::prng::Prng;
 use std::cell::RefCell;
@@ -56,7 +56,7 @@ impl EclRunner {
             self.ip += 1;
 
             let rank = self.enemy.borrow().get_rank();
-            if call.rank_mask & (0x100 << rank) == 0 {
+            if (call.rank_mask & rank).is_empty() {
                 continue;
             }
 
@@ -82,7 +82,7 @@ impl EclRunner {
             -10010 => self.variables.2[1],
             -10011 => self.variables.2[2],
             -10012 => self.variables.2[3],
-            -10013 => enemy.get_rank(),
+            -10013 => enemy.get_rank().bits() as i32,
             -10014 => enemy.get_difficulty(),
             -10015 => enemy.pos.x as i32,
             -10016 => enemy.pos.y as i32,
@@ -114,7 +114,7 @@ impl EclRunner {
             -10010.0 => self.variables.2[1] as f32,
             -10011.0 => self.variables.2[2] as f32,
             -10012.0 => self.variables.2[3] as f32,
-            -10013.0 => enemy.get_rank() as f32,
+            -10013.0 => enemy.get_rank().bits() as f32,
             -10014.0 => enemy.get_difficulty() as f32,
             -10015.0 => enemy.pos.x,
             -10016.0 => enemy.pos.y,
--- a/src/th06/enemy.rs
+++ b/src/th06/enemy.rs
@@ -2,6 +2,7 @@
 
 use crate::th06::anm0::Anm0;
 use crate::th06::anm0_vm::{Sprite, AnmRunner};
+use crate::th06::ecl::Rank;
 use crate::th06::interpolator::{Interpolator1, Interpolator2};
 use crate::util::prng::Prng;
 use std::cell::RefCell;
@@ -60,18 +61,18 @@ pub struct Game {
     enemies: Vec<Rc<RefCell<Enemy>>>,
     anmrunners: Vec<Rc<RefCell<AnmRunner>>>,
     prng: Rc<RefCell<Prng>>,
-    rank: i32,
+    rank: Rank,
     difficulty: i32,
 }
 
 impl Game {
     /// Create said god struct.
-    pub fn new(prng: Rc<RefCell<Prng>>) -> Game {
+    pub fn new(prng: Rc<RefCell<Prng>>, rank: Rank) -> Game {
         Game {
             enemies: Vec::new(),
             anmrunners: Vec::new(),
             prng,
-            rank: 0,
+            rank,
             difficulty: 0,
         }
     }
@@ -262,7 +263,7 @@ impl Enemy {
         self.frame += 1;
     }
 
-    pub(crate) fn get_rank(&self) -> i32 {
+    pub(crate) fn get_rank(&self) -> Rank {
         let game = self.game.upgrade().unwrap();
         let game = game.borrow();
         game.rank