Added HealthAndArmour getting
This commit is contained in:
149
src/wad.rs
149
src/wad.rs
@@ -1,9 +1,9 @@
|
|||||||
use bincode;
|
use bincode;
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{BufReader, Seek, SeekFrom};
|
use std::io::{BufReader, Seek, SeekFrom};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
A great document I've used as a reference is The Unofficial Doom Specs v1.666
|
A great document I've used as a reference is The Unofficial Doom Specs v1.666
|
||||||
@@ -49,14 +49,20 @@ pub struct WadThingLump {
|
|||||||
pub options: u16,
|
pub options: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_wad(path: &PathBuf) -> WadHeader {
|
pub struct OpenWad {
|
||||||
|
path: PathBuf,
|
||||||
|
header: WadHeader,
|
||||||
|
nice_lumps: Vec<NiceWadLumpEntry>,
|
||||||
|
level_indicies: Vec<usize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_wad(path: &PathBuf) -> OpenWad {
|
||||||
let mut file = BufReader::new(File::open(path).unwrap());
|
let mut file = BufReader::new(File::open(path).unwrap());
|
||||||
let header: WadHeader = bincode::deserialize_from(&mut file).unwrap();
|
let header: WadHeader = bincode::deserialize_from(&mut file).unwrap();
|
||||||
file.seek(SeekFrom::Start(header.file_offset_to_start as u64))
|
file.seek(SeekFrom::Start(header.file_offset_to_start as u64))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut lumps: Vec<WadLumpDirectoryEntry> = Vec::new();
|
|
||||||
let mut nice_lumps: Vec<NiceWadLumpEntry> = Vec::new();
|
let mut nice_lumps: Vec<NiceWadLumpEntry> = Vec::new();
|
||||||
let mut levels_indicies = Vec::new();
|
let mut level_indicies = Vec::new();
|
||||||
for lump_num in 0..header.num_lumps {
|
for lump_num in 0..header.num_lumps {
|
||||||
let lump: WadLumpDirectoryEntry = bincode::deserialize_from(&mut file).unwrap();
|
let lump: WadLumpDirectoryEntry = bincode::deserialize_from(&mut file).unwrap();
|
||||||
let nice_lump = NiceWadLumpEntry {
|
let nice_lump = NiceWadLumpEntry {
|
||||||
@@ -64,7 +70,7 @@ pub fn open_wad(path: &PathBuf) -> WadHeader {
|
|||||||
size: lump.size,
|
size: lump.size,
|
||||||
name: std::str::from_utf8(&lump.name).unwrap().to_string(),
|
name: std::str::from_utf8(&lump.name).unwrap().to_string(),
|
||||||
};
|
};
|
||||||
println!("{:?}", nice_lump);
|
|
||||||
// I stole this from rust-doom. I looked up idSoftware Linux Doom, but they searched
|
// I stole this from rust-doom. I looked up idSoftware Linux Doom, but they searched
|
||||||
// for the strings "mapXY" or ExMy - I'm not 100% sure, but I bet many PWADs don't
|
// for the strings "mapXY" or ExMy - I'm not 100% sure, but I bet many PWADs don't
|
||||||
// neccesarily use this... I do think that probably PWADs provide different THINGS
|
// neccesarily use this... I do think that probably PWADs provide different THINGS
|
||||||
@@ -72,40 +78,79 @@ pub fn open_wad(path: &PathBuf) -> WadHeader {
|
|||||||
// https://doomwiki.org/wiki/WAD says THINGS always comes after map name
|
// https://doomwiki.org/wiki/WAD says THINGS always comes after map name
|
||||||
if &lump.name == b"THINGS\0\0" {
|
if &lump.name == b"THINGS\0\0" {
|
||||||
assert!(lump_num > 0);
|
assert!(lump_num > 0);
|
||||||
levels_indicies.push((lump_num - 1) as usize);
|
level_indicies.push((lump_num - 1) as usize);
|
||||||
}
|
}
|
||||||
lumps.push(lump);
|
|
||||||
nice_lumps.push(nice_lump);
|
nice_lumps.push(nice_lump);
|
||||||
}
|
}
|
||||||
let mut _level_summaries: Vec<LevelSummary> = Vec::new();
|
OpenWad {
|
||||||
|
path: path.clone(),
|
||||||
|
header,
|
||||||
|
nice_lumps,
|
||||||
|
level_indicies,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_enemies_and_health_per_level(
|
||||||
|
ow: OpenWad,
|
||||||
|
) -> (
|
||||||
|
HashMap<String, HashMap<Enemy, u16>>,
|
||||||
|
HashMap<String, HashMap<HealthAndArmour, u16>>,
|
||||||
|
) {
|
||||||
|
let mut file = BufReader::new(File::open(ow.path).unwrap());
|
||||||
let mut enemy_maps: HashMap<String, HashMap<Enemy, u16>> = HashMap::new();
|
let mut enemy_maps: HashMap<String, HashMap<Enemy, u16>> = HashMap::new();
|
||||||
for level_i in levels_indicies {
|
let mut health_maps: HashMap<String, HashMap<HealthAndArmour, u16>> = HashMap::new();
|
||||||
let name = nice_lumps.get(level_i).unwrap().name.clone();
|
for level_i in ow.level_indicies {
|
||||||
let level_things_wad_lump = nice_lumps.get(level_i + 1).unwrap();
|
let name = ow.nice_lumps.get(level_i).unwrap().name.clone();
|
||||||
|
let level_things_wad_lump = ow.nice_lumps.get(level_i + 1).unwrap();
|
||||||
file.seek(SeekFrom::Start(level_things_wad_lump.offset as u64))
|
file.seek(SeekFrom::Start(level_things_wad_lump.offset as u64))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let mut enemy_map: HashMap<Enemy, u16> = HashMap::new();
|
let mut enemy_map: HashMap<Enemy, u16> = HashMap::new();
|
||||||
|
let mut health_map: HashMap<HealthAndArmour, u16> = HashMap::new();
|
||||||
for _ in 0..(level_things_wad_lump.size / std::mem::size_of::<WadThingLump>() as i32) {
|
for _ in 0..(level_things_wad_lump.size / std::mem::size_of::<WadThingLump>() as i32) {
|
||||||
let map_thing: WadThingLump = bincode::deserialize_from(&mut file).unwrap();
|
let map_thing: WadThingLump = bincode::deserialize_from(&mut file).unwrap();
|
||||||
// Just checking UV
|
// Just checking UV
|
||||||
if map_thing.options & (1 << 2) > 0 {
|
if map_thing.options & (1 << 2) > 0 {
|
||||||
if let Some(n) = enemy_map.get(&map_thing.thing_type.into()) {
|
// This doesn't feel overly rust like - but it works...
|
||||||
enemy_map.insert(map_thing.thing_type.into(), n + 1);
|
let health_thing: HealthAndArmour = map_thing.thing_type.into();
|
||||||
} else {
|
let enemy_thing: Enemy = map_thing.thing_type.into();
|
||||||
enemy_map.insert(map_thing.thing_type.into(), 1);
|
if health_thing != HealthAndArmour::Unknown {
|
||||||
|
if let Some(n) = health_map.get(&map_thing.thing_type.into()) {
|
||||||
|
health_map.insert(map_thing.thing_type.into(), n + 1);
|
||||||
|
} else {
|
||||||
|
health_map.insert(map_thing.thing_type.into(), 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if enemy_thing != Enemy::Unknown {
|
||||||
|
if let Some(n) = enemy_map.get(&map_thing.thing_type.into()) {
|
||||||
|
enemy_map.insert(map_thing.thing_type.into(), n + 1);
|
||||||
|
} else {
|
||||||
|
enemy_map.insert(map_thing.thing_type.into(), 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
enemy_maps.insert(name, enemy_map);
|
enemy_maps.insert(name.clone(), enemy_map);
|
||||||
break;
|
health_maps.insert(name, health_map);
|
||||||
}
|
}
|
||||||
println!("{:#?}", enemy_maps);
|
(enemy_maps, health_maps)
|
||||||
header
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Eq, Hash, PartialEq, Debug)]
|
#[derive(Eq, Hash, PartialEq, Debug)]
|
||||||
enum Enemy {
|
pub enum HealthAndArmour {
|
||||||
|
HealthPotion,
|
||||||
|
Stimpack,
|
||||||
|
Medikit,
|
||||||
|
Soulsphere,
|
||||||
|
SpiritArmour,
|
||||||
|
GreenArmour,
|
||||||
|
BlueArmour,
|
||||||
|
Megasphere,
|
||||||
|
Invulnerability,
|
||||||
|
Unknown,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, Hash, PartialEq, Debug)]
|
||||||
|
pub enum Enemy {
|
||||||
FormerHuman,
|
FormerHuman,
|
||||||
WolfensteinSs,
|
WolfensteinSs,
|
||||||
FormerHumanSergeant,
|
FormerHumanSergeant,
|
||||||
@@ -136,7 +181,7 @@ impl std::convert::From<u16> for Enemy {
|
|||||||
9 => Self::FormerHumanSergeant,
|
9 => Self::FormerHumanSergeant,
|
||||||
65 => Self::HeavyWeaponDude,
|
65 => Self::HeavyWeaponDude,
|
||||||
3001 => Self::Imp,
|
3001 => Self::Imp,
|
||||||
3002 => Self:: Demon,
|
3002 => Self::Demon,
|
||||||
58 => Self::Spectre,
|
58 => Self::Spectre,
|
||||||
3006 => Self::LostSoul,
|
3006 => Self::LostSoul,
|
||||||
3005 => Self::Cacodemon,
|
3005 => Self::Cacodemon,
|
||||||
@@ -150,13 +195,27 @@ impl std::convert::From<u16> for Enemy {
|
|||||||
7 => Self::SpiderMastermind,
|
7 => Self::SpiderMastermind,
|
||||||
16 => Self::CyberDemon,
|
16 => Self::CyberDemon,
|
||||||
88 => Self::BossBrain,
|
88 => Self::BossBrain,
|
||||||
_ => Self::Unknown
|
_ => Self::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::convert::From<u16> for HealthAndArmour {
|
||||||
|
fn from(ttype: u16) -> Self {
|
||||||
|
match ttype {
|
||||||
|
2011 => Self::Stimpack,
|
||||||
|
2012 => Self::Medikit,
|
||||||
|
2014 => Self::HealthPotion,
|
||||||
|
2015 => Self::SpiritArmour,
|
||||||
|
2018 => Self::GreenArmour,
|
||||||
|
2019 => Self::BlueArmour,
|
||||||
|
83 => Self::Soulsphere,
|
||||||
|
2013 => Self::Megasphere,
|
||||||
|
2022 => Self::Invulnerability,
|
||||||
|
_ => Self::Unknown,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
@@ -170,19 +229,37 @@ mod tests {
|
|||||||
"WAD test need freedoom1.wad - get it from here https://freedoom.github.io"
|
"WAD test need freedoom1.wad - get it from here https://freedoom.github.io"
|
||||||
);
|
);
|
||||||
let ow = open_wad(&freedoom_iwad);
|
let ow = open_wad(&freedoom_iwad);
|
||||||
assert_eq!(&ow.identifier, b"IWAD");
|
assert_eq!(&ow.header.identifier, b"IWAD");
|
||||||
assert_eq!(std::str::from_utf8(&ow.identifier).unwrap(), "IWAD");
|
assert_eq!(std::str::from_utf8(&ow.header.identifier).unwrap(), "IWAD");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_failed() {
|
fn test_num_levels_correct() {
|
||||||
let freedoom_iwad = PathBuf::from("DOOM2.WAD");
|
let freedoom_iwad = PathBuf::from("freedoom1.wad");
|
||||||
assert!(
|
let ow = open_wad(&freedoom_iwad);
|
||||||
freedoom_iwad.exists(),
|
let (enemy_summary, _) = get_enemies_and_health_per_level(ow);
|
||||||
"WAD test need freedoom1.wad - get it from here https://freedoom.github.io"
|
assert_eq!(enemy_summary.len(), 9 * 4);
|
||||||
);
|
}
|
||||||
let _ow = open_wad(&freedoom_iwad);
|
|
||||||
panic!();
|
#[test]
|
||||||
|
fn test_enemies_correct() {
|
||||||
|
let freedoom_iwad = PathBuf::from("freedoom1.wad");
|
||||||
|
let ow = open_wad(&freedoom_iwad);
|
||||||
|
let (enemy_summary, _) = get_enemies_and_health_per_level(ow);
|
||||||
|
let c1m1 = enemy_summary.get("E1M1\0\0\0\0").unwrap();
|
||||||
|
assert_eq!(c1m1.get(&Enemy::Imp), Some(&14));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_health_correct() {
|
||||||
|
let freedoom_iwad = PathBuf::from("freedoom1.wad");
|
||||||
|
let ow = open_wad(&freedoom_iwad);
|
||||||
|
let (_, health_summary) = get_enemies_and_health_per_level(ow);
|
||||||
|
let c1m1 = health_summary.get("E1M1\0\0\0\0").unwrap();
|
||||||
|
assert_eq!(c1m1.get(&HealthAndArmour::BlueArmour), None); // I wonder if this should be a Some(&0)
|
||||||
|
assert_eq!(c1m1.get(&HealthAndArmour::HealthPotion), Some(&17));
|
||||||
|
let c4m1 = health_summary.get("E4M1\0\0\0\0").unwrap();
|
||||||
|
assert_eq!(c4m1.get(&HealthAndArmour::Stimpack), Some(&12));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
Reference in New Issue
Block a user