# HG changeset patch # User Emmanuel Gil Peyrot # Date 1566008904 -7200 # Node ID aefe5b5f481e62fe63737229ad935f0c55d996c0 # Parent 11d7e4d6947ad54d8a90ef14b733410c650b340d ecl_vm: implement the SetBulletAttributes opcodes. diff --git a/src/th06/ecl.rs b/src/th06/ecl.rs --- a/src/th06/ecl.rs +++ b/src/th06/ecl.rs @@ -241,13 +241,13 @@ declare_sub_instructions!{ 63 => fn StopInAccel(duration: i32), 65 => fn SetScreenBox(xmin: f32, ymin: f32, xmax: f32, ymax: f32), 66 => fn ClearScreenBox(), - 67 => fn SetBulletAttributes1(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: i32), - 68 => fn SetBulletAttributes2(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: i32), - 69 => fn SetBulletAttributes3(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: i32), - 70 => fn SetBulletAttributes4(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: i32), - 71 => fn SetBulletAttributes5(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: i32), - 74 => fn SetBulletAttributes6(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: i32), - 75 => fn SetBulletAttributes7(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: i32), + 67 => fn SetBulletAttributes1(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: u32), + 68 => fn SetBulletAttributes2(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: u32), + 69 => fn SetBulletAttributes3(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: u32), + 70 => fn SetBulletAttributes4(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: u32), + 71 => fn SetBulletAttributes5(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: u32), + 74 => fn SetBulletAttributes6(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: u32), + 75 => fn SetBulletAttributes7(anim: i16, sprite_index_offset: i16, bullets_per_shot: i32, number_of_shots: i32, speed: f32, speed2: f32, launch_angle: f32, angle: f32, flags: u32), 76 => fn SetBulletInterval(interval: i32), 77 => fn SetBulletIntervalEx(interval: i32), 78 => fn DelayAttack(), diff --git a/src/th06/ecl_vm.rs b/src/th06/ecl_vm.rs --- a/src/th06/ecl_vm.rs +++ b/src/th06/ecl_vm.rs @@ -1,11 +1,29 @@ //! ECL runner. use crate::th06::ecl::{Ecl, SubInstruction}; -use crate::th06::enemy::Enemy; +use crate::th06::enemy::{Enemy, BulletAttributes}; use crate::util::prng::Prng; use std::cell::RefCell; use std::rc::Rc; +macro_rules! gen_SetBulletAttributes { + ($self:ident, $opcode:tt, $anim:ident, $sprite_index_offset:ident, $bullets_per_shot:ident, + $number_of_shots:ident, $speed:ident, $speed2:ident, $launch_angle:ident, $angle:ident, + $flags:ident) => {{ + let sprite_index_offset = $self.get_i32($sprite_index_offset as i32) as i16; + let bullets_per_shot = $self.get_i32($bullets_per_shot) as i16; + let number_of_shots = $self.get_i32($number_of_shots) as i16; + let speed = $self.get_f32($speed); + let speed2 = $self.get_f32($speed2); + let launch_angle = $self.get_f32($launch_angle); + let angle = $self.get_f32($angle); + + let mut enemy = $self.enemy.borrow_mut(); + enemy.set_bullet_attributes($opcode, $anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, angle, $flags); + }}; +} + type Variables = ([i32; 4], [f32; 4], [i32; 4]); /// Interpreter for enemy scripts. @@ -537,7 +555,57 @@ impl EclRunner { let mut enemy = self.enemy.borrow_mut(); enemy.screen_box = None; } + // 67 to 75 are set bullet attributes and it seems a pain to reverse rn + SubInstruction::SetBulletAttributes1(anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, + angle, flags) => { + gen_SetBulletAttributes!(self, 67, anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, angle, + flags); + } + SubInstruction::SetBulletAttributes2(anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, + angle, flags) => { + gen_SetBulletAttributes!(self, 68, anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, angle, + flags); + } + SubInstruction::SetBulletAttributes3(anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, + angle, flags) => { + gen_SetBulletAttributes!(self, 69, anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, angle, + flags); + } + SubInstruction::SetBulletAttributes4(anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, + angle, flags) => { + gen_SetBulletAttributes!(self, 70, anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, angle, + flags); + } + SubInstruction::SetBulletAttributes5(anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, + angle, flags) => { + gen_SetBulletAttributes!(self, 71, anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, angle, + flags); + } + SubInstruction::SetBulletAttributes6(anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, + angle, flags) => { + gen_SetBulletAttributes!(self, 74, anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, angle, + flags); + } + SubInstruction::SetBulletAttributes7(anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, + angle, flags) => { + gen_SetBulletAttributes!(self, 75, anim, sprite_index_offset, bullets_per_shot, + number_of_shots, speed, speed2, launch_angle, angle, + flags); + } diff --git a/src/th06/enemy.rs b/src/th06/enemy.rs --- a/src/th06/enemy.rs +++ b/src/th06/enemy.rs @@ -10,14 +10,14 @@ use std::collections::HashMap; use std::rc::{Rc, Weak}; /// The 2D position of an object in the game. -#[derive(Debug, Clone, Copy, Default)] +#[derive(Debug, Clone, Copy, Default, PartialEq)] pub struct Position { pub(crate) x: f32, pub(crate) y: f32, } /// An offset which can be added to a Position. -#[derive(Debug, Clone, Copy, Default)] +#[derive(Debug, Clone, Copy, Default, PartialEq)] pub struct Offset { dx: f32, dy: f32, @@ -120,10 +120,10 @@ struct Element { pub(crate) struct DifficultyCoeffs { pub(crate) speed_a: f32, pub(crate) speed_b: f32, - pub(crate) nb_a: u16, - pub(crate) nb_b: u16, - pub(crate) shots_a: u16, - pub(crate) shots_b: u16, + pub(crate) nb_a: i16, + pub(crate) nb_b: i16, + pub(crate) shots_a: i16, + pub(crate) shots_b: i16, } impl Default for DifficultyCoeffs { @@ -139,6 +139,32 @@ impl Default for DifficultyCoeffs { } } +#[derive(Debug, Clone, Default, PartialEq)] +pub(crate) struct BulletAttributes { + pub(crate) anim: i16, + pub(crate) sprite_index_offset: i16, + pub(crate) pos: Position, // Doesn’t have a z field. + pub(crate) launch_angle: f32, + pub(crate) angle: f32, + pub(crate) speed: f32, + pub(crate) speed2: f32, + pub(crate) extended_attributes: (i32, i32, i32, i32, f32, f32, f32, f32), + // unknown: x32, + pub(crate) bullets_per_shot: i16, + pub(crate) number_of_shots: i16, + pub(crate) bullet_type: i16, + // zero: x32, + pub(crate) flags: u32, + pub(crate) ins84_param: i32, +} + +impl BulletAttributes { + /// Fire! + pub fn fire(&mut self) { + println!("PAN!"); + } +} + #[derive(PartialEq)] pub(crate) enum Direction { Left, @@ -198,9 +224,8 @@ pub struct Enemy { // Tuples. pub(crate) difficulty_coeffs: DifficultyCoeffs, - pub(crate) extended_bullet_attributes: Option<(u32, u32, u32, u32, f32, f32, f32, f32)>, - pub(crate) bullet_attributes: Option<(i16, i16, u32, u32, u32, f32, f32, f32, f32, u32)>, - pub(crate) bullet_launch_offset: Offset, + pub(crate) bullet_attributes: BulletAttributes, + pub(crate) bullet_offset: Offset, pub(crate) movement_dependant_sprites: Option<(u8, u8, u8, u8)>, pub(crate) screen_box: Option<(f32, f32, f32, f32)>, @@ -274,6 +299,54 @@ impl Enemy { self.hitbox_half_size = [width / 2., height / 2.]; } + /// Defines the attributes for the next bullet fired, and fire it if delay_attack isn’t set! + pub fn set_bullet_attributes(&mut self, opcode: u16, anim: i16, sprite_index_offset: i16, + bullets_per_shot: i16, number_of_shots: i16, speed: f32, + speed2: f32, launch_angle: f32, angle: f32, flags: u32) { + // Get the coeffs for the current difficulty. + let difficulty = self.get_difficulty() as i16; + let coeff_nb = self.difficulty_coeffs.nb_a + (self.difficulty_coeffs.nb_b - self.difficulty_coeffs.nb_a) * difficulty / 32; + let coeff_shots = self.difficulty_coeffs.shots_a + (self.difficulty_coeffs.shots_b - self.difficulty_coeffs.shots_a) * difficulty / 32; + let coeff_speed = self.difficulty_coeffs.speed_a + (self.difficulty_coeffs.speed_b - self.difficulty_coeffs.speed_a) * difficulty as f32 / 32.; + + let opcode = 67; + let mut bullet = &mut self.bullet_attributes; + + bullet.anim = anim; + bullet.bullet_type = opcode - 67; + bullet.sprite_index_offset = sprite_index_offset; + + bullet.bullets_per_shot = bullets_per_shot + coeff_nb; + if bullet.bullets_per_shot < 1 { + bullet.bullets_per_shot = 1; + } + + bullet.number_of_shots = number_of_shots + coeff_shots; + if bullet.number_of_shots < 1 { + bullet.number_of_shots = 1; + } + + bullet.pos = self.pos + self.bullet_offset; + + bullet.speed = speed + coeff_speed; + if bullet.speed < 0.3 { + bullet.speed = 0.3; + } + + bullet.speed2 = speed2 + coeff_speed / 2.; + if bullet.speed2 < 0.3 { + bullet.speed2 = 0.3; + } + + bullet.launch_angle = launch_angle.atan2(0.); + bullet.angle = angle; + bullet.flags = flags; + + if !self.delay_attack { + bullet.fire(); + } + } + /// Run all interpolators and such, and update internal variables once per /// frame. pub fn update(&mut self) {