Added HealthAndArmour getting

This commit is contained in:
2023-07-04 21:20:21 +01:00
parent 905ac2b7e2
commit 67c8ad81b9

View File

@@ -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 {
// This doesn't feel overly rust like - but it works...
let health_thing: HealthAndArmour = map_thing.thing_type.into();
let enemy_thing: Enemy = map_thing.thing_type.into();
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()) { if let Some(n) = enemy_map.get(&map_thing.thing_type.into()) {
enemy_map.insert(map_thing.thing_type.into(), n + 1); enemy_map.insert(map_thing.thing_type.into(), n + 1);
} else { } else {
enemy_map.insert(map_thing.thing_type.into(), 1); enemy_map.insert(map_thing.thing_type.into(), 1);
} }
} }
} }
enemy_maps.insert(name, enemy_map);
break;
} }
println!("{:#?}", enemy_maps); enemy_maps.insert(name.clone(), enemy_map);
header health_maps.insert(name, health_map);
}
(enemy_maps, health_maps)
} }
#[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]