205 lines
7.5 KiB
Rust
205 lines
7.5 KiB
Rust
//! `Monster` type.
|
|
|
|
use crate::{bin::OptU16, err::*, fixed::{Fixed, Unit}};
|
|
use bitflags::bitflags;
|
|
|
|
use super::{attk, damg};
|
|
|
|
/// Reads a `MNpx` chunk.
|
|
pub fn read(b: &[u8]) -> ResultS<(Monster, usize)>
|
|
{
|
|
read_data! {
|
|
endian: BIG, buf: b, size: 156, start: 0, data {
|
|
let collection = u16[0];
|
|
let vitality = u16[2];
|
|
let dty_immune = u32[4] flag damg::DamageTypeFlags;
|
|
let dty_weak = u32[8] flag damg::DamageTypeFlags;
|
|
let flags = u32[12] flag MonsterFlags;
|
|
let cls_self = u32[16] flag MonsterClass;
|
|
let cls_friend = u32[20];
|
|
let cls_enemy = u32[24];
|
|
let snd_pitch = Fixed[28];
|
|
let snd_see_enemy = OptU16[32];
|
|
let snd_see_friend = OptU16[34];
|
|
let snd_seeclear = OptU16[36];
|
|
let snd_kill = OptU16[38];
|
|
let snd_apologize = OptU16[40];
|
|
let snd_amicide = OptU16[42];
|
|
let snd_flaming = OptU16[44];
|
|
let snd_active = OptU16[46];
|
|
let snd_active_mask = u16[48];
|
|
let typ_item = OptU16[50];
|
|
let radius = Unit[52];
|
|
let height = Unit[54];
|
|
let height_hover = Unit[56];
|
|
let ledge_min = Unit[58];
|
|
let ledge_max = Unit[60];
|
|
let ext_vel_scale = Fixed[62];
|
|
let fxt_impact = OptU16[66];
|
|
let fxt_impact_melee = OptU16[68];
|
|
let fxt_trail = OptU16[70];
|
|
let half_fov_horz = u16[72];
|
|
let half_fov_vert = u16[74];
|
|
let view_range = Unit[76];
|
|
let view_range_dark = Unit[78];
|
|
let intelligence = u16[80];
|
|
let speed = u16[82];
|
|
let gravity = u16[84];
|
|
let vel_terminal = u16[86];
|
|
let door_try_mask = u16[88];
|
|
let expl_radius = OptU16[90];
|
|
let expl_damage = damg::read[92; 12];
|
|
let seq_hit = OptU16[104];
|
|
let seq_dying_hard = OptU16[106];
|
|
let seq_dying_soft = OptU16[108];
|
|
let seq_dead_hard = OptU16[110];
|
|
let seq_dead_soft = OptU16[112];
|
|
let seq_standing = u16[114];
|
|
let seq_moving = u16[116];
|
|
let seq_tele_in = OptU16[118];
|
|
let seq_tele_out = OptU16[120];
|
|
let atk_frequency = u16[122];
|
|
let atk_melee = attk::read[124; 16];
|
|
let atk_range = attk::read[140; 16];
|
|
}
|
|
}
|
|
|
|
// friend and enemy fields MUST truncate because the original source code
|
|
// used `-1` to represent "all classes" which should be invalid normally
|
|
|
|
let cls_friend = MonsterClass::from_bits_truncate(cls_friend);
|
|
let cls_enemy = MonsterClass::from_bits_truncate(cls_enemy);
|
|
|
|
Ok((Monster{collection, vitality, dty_immune, dty_weak, flags, cls_self,
|
|
cls_friend, cls_enemy, snd_pitch, snd_see_enemy, snd_see_friend,
|
|
snd_seeclear, snd_kill, snd_apologize, snd_amicide, snd_flaming,
|
|
snd_active, snd_active_mask, typ_item, radius, height,
|
|
height_hover, ledge_min, ledge_max, ext_vel_scale, fxt_impact,
|
|
fxt_impact_melee, fxt_trail, half_fov_horz, half_fov_vert,
|
|
view_range, view_range_dark, intelligence, speed, gravity,
|
|
vel_terminal, door_try_mask, expl_radius, expl_damage, seq_hit,
|
|
seq_dying_hard, seq_dying_soft, seq_dead_hard, seq_dead_soft,
|
|
seq_standing, seq_moving, seq_tele_in, seq_tele_out,
|
|
atk_frequency, atk_melee, atk_range}, 156))
|
|
}
|
|
|
|
/// A monster definition.
|
|
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
|
#[derive(Debug, Eq, PartialEq)]
|
|
pub struct Monster
|
|
{
|
|
pub collection: u16,
|
|
pub vitality: u16,
|
|
pub dty_immune: damg::DamageTypeFlags,
|
|
pub dty_weak: damg::DamageTypeFlags,
|
|
pub flags: MonsterFlags,
|
|
pub cls_self: MonsterClass,
|
|
pub cls_friend: MonsterClass,
|
|
pub cls_enemy: MonsterClass,
|
|
pub snd_pitch: Fixed,
|
|
pub snd_see_enemy: OptU16,
|
|
pub snd_see_friend: OptU16,
|
|
pub snd_seeclear: OptU16,
|
|
pub snd_kill: OptU16,
|
|
pub snd_apologize: OptU16,
|
|
pub snd_amicide: OptU16,
|
|
pub snd_flaming: OptU16,
|
|
pub snd_active: OptU16,
|
|
pub snd_active_mask: u16,
|
|
pub typ_item: OptU16,
|
|
pub radius: Unit,
|
|
pub height: Unit,
|
|
pub height_hover: Unit,
|
|
pub ledge_min: Unit,
|
|
pub ledge_max: Unit,
|
|
pub ext_vel_scale: Fixed,
|
|
pub fxt_impact: OptU16,
|
|
pub fxt_impact_melee: OptU16,
|
|
pub fxt_trail: OptU16,
|
|
pub half_fov_horz: u16,
|
|
pub half_fov_vert: u16,
|
|
pub view_range: Unit,
|
|
pub view_range_dark: Unit,
|
|
pub intelligence: u16,
|
|
pub speed: u16,
|
|
pub gravity: u16,
|
|
pub vel_terminal: u16,
|
|
pub door_try_mask: u16,
|
|
pub expl_radius: OptU16,
|
|
pub expl_damage: damg::Damage,
|
|
pub seq_hit: OptU16,
|
|
pub seq_dying_hard: OptU16,
|
|
pub seq_dying_soft: OptU16,
|
|
pub seq_dead_hard: OptU16,
|
|
pub seq_dead_soft: OptU16,
|
|
pub seq_standing: u16,
|
|
pub seq_moving: u16,
|
|
pub seq_tele_in: OptU16,
|
|
pub seq_tele_out: OptU16,
|
|
pub atk_frequency: u16,
|
|
pub atk_melee: attk::Attack,
|
|
pub atk_range: attk::Attack,
|
|
}
|
|
|
|
bitflags! {
|
|
/// Flags for a monster.
|
|
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
|
pub struct MonsterFlags: u32
|
|
{
|
|
const IGNORE_LOS = 1;
|
|
const FLYING = 1 << 1;
|
|
const ALIEN = 1 << 2;
|
|
const MAJOR = 1 << 3;
|
|
const MINOR = 1 << 4;
|
|
const NO_OMIT = 1 << 5;
|
|
const FLOATS = 1 << 6;
|
|
const NO_ATTACK = 1 << 7;
|
|
const SNIPE = 1 << 8;
|
|
const INVISIBLE = 1 << 9;
|
|
const SUBTLY_INVISIBLE = 1 << 10;
|
|
const KAMIKAZE = 1 << 11;
|
|
const BERSERKER = 1 << 12;
|
|
const ENLARGED = 1 << 13;
|
|
const DELAYED_DEATH = 1 << 14;
|
|
const FIRE_SYMMETRICAL = 1 << 15;
|
|
const NUCLEAR_DEATH = 1 << 16;
|
|
const NO_FIRE_BACKWARDS = 1 << 17;
|
|
const CAN_DIE_IN_FLAMES = 1 << 18;
|
|
const WAIT_FOR_GOOD_SHOT = 1 << 19;
|
|
const TINY = 1 << 20;
|
|
const FAST_ATTACK = 1 << 21;
|
|
const LIKES_WATER = 1 << 22;
|
|
const LIKES_SEWAGE = 1 << 23;
|
|
const LIKES_LAVA = 1 << 24;
|
|
const LIKES_GOO = 1 << 25;
|
|
const TELE_UNDER_MEDIA = 1 << 26;
|
|
const USE_RANDOM_WEAPON = 1 << 27;
|
|
}
|
|
}
|
|
|
|
bitflags! {
|
|
/// The composite type of a monster.
|
|
#[cfg_attr(feature = "serde_obj", derive(serde::Serialize))]
|
|
pub struct MonsterClass: u32
|
|
{
|
|
const PLAYER = 1;
|
|
const CIVILIAN = 1 << 1;
|
|
const MADD = 1 << 2;
|
|
const POSSESSED_HUMMER = 1 << 3;
|
|
const DEFENDER = 1 << 4;
|
|
const FIGHTER = 1 << 5;
|
|
const TROOPER = 1 << 6;
|
|
const HUNTER = 1 << 7;
|
|
const ENFORCER = 1 << 8;
|
|
const JUGGERNAUT = 1 << 9;
|
|
const HUMMER = 1 << 10;
|
|
const COMPILER = 1 << 11;
|
|
const CYBORG = 1 << 12;
|
|
const ASSIMILATED = 1 << 13;
|
|
const TICK = 1 << 14;
|
|
const YETI = 1 << 15;
|
|
}
|
|
}
|
|
|
|
// EOF
|