DOOM modding library
       2023-05-03
       Last edit: 2023-05-03
       ---------------------
       
       This project is a WAD library/manager, it can be used as a base for other WAD projects like a GUI, a CLI, etc..
       
       I have played around with some well known `IWAD` like `doom.wad` and `doom2.wad` (registered).
       
       To test the `IWAD`/`PWAD` generated, I have used two engines:
       - 
 (HTM) GZDoom
        (tests + screenshots)
       - 
 (HTM) WAD Commander
        (tests + preview in multiple contexts)
       
       ## Use cases
       
       Some use cases you could use in a DOOM modding context.
       
       ### IWAD patching
       
       ```rust
       use tinywad::error::WadError;
       use tinywad::models::operation::WadOp;
       use tinywad::wad::Wad;
       
       fn main() -> Result<(), WadError> {
           let mut doom_2 = Wad::new();
           doom_2.load_from_file("wads/doom2.wad")?;
       
           let gate = doom_2.lump("GATE3").unwrap();
       
           let mut doom_1 = Wad::new();
           doom_1.load_from_file("doom1.wad")?;
       
           doom_1.select("^FLAT|FLOOR");
           doom_1.update_lumps_raw(&gate.data().buffer);
           doom_1.save("doom1.wad");
       
           Ok(())
       }
       ```
       
       So basically (above) it loads a first `IWAD` file, in our case it is `doom2.wad`. It borrows a lump (`GATE3`) into the variable `gate`, then we load a second `IWAD` which is `doom1.wad`, it selects desired lumps, then it update the selected lumps in `DOOM1` and finally overwrite the file.
       
       ### Screenhot(s)
       
       ### Lumps extracting
       
       ```rust
       use std::fs;
       
       use tinywad::dir::MAX_PAL;
       use tinywad::error::WadError;
       use tinywad::models::operation::WadOp;
       use tinywad::wad::Wad;
       
       fn main() -> Result<(), WadError> {
           let mut doom_2 = Wad::new();
           doom_2.load_from_file("wads/doom2.wad")?;
       
           for pal in 0..MAX_PAL {
               doom_2.set_palette(pal);
               doom_2.reload()?;
               doom_2.select("^BOSF");
               
               let dirpath = format!("doom2/pal_{}", pal);
       
               fs::create_dir_all(dirpath.clone()).unwrap();
       
               doom_2.save_lumps(dirpath);
           }
       
           Ok(())
       }
       ```
       
       In this part of code, it extracts as PNG the selected lumps with different palettes (13).
       
       ### Extracted lumps (as PNGs)
       
       ### Dumping metadata
       
       ```rust
       use tinywad::error::WadError;
       use tinywad::models::operation::WadOp;
       use tinywad::wad::Wad;
       
       fn main() -> Result<(), WadError> {
           let mut src = Wad::new();
       
           src.load_from_file("wads/hexen.wad")?;
           src.dump();
       
           Ok(())
       }
       ```
       
       ### Output
       
       ```text
       Name: XXTIC, Size: 8, Offset: 12
       Name: STARTUP, Size: 153648, Offset: 20
       Name: PLAYPAL, Size: 21504, Offset: 153668, Palettes amount: 28
       Name: COLORMAP, Size: 8704, Offset: 175172
       Name: FOGMAP, Size: 8704, Offset: 183876
       Name: TINTTAB, Size: 65536, Offset: 192580
       Name: TRANTBL0, Size: 256, Offset: 258116
       Name: TRANTBL1, Size: 256, Offset: 258372
       Name: TRANTBL2, Size: 256, Offset: 258628
       ...
       ```
       
       ### Building a PWAD from scratch
       
       ```rust
       use tinywad::error::WadError;
       use tinywad::lump::{LumpAdd, LumpAddKind};
       use tinywad::models::operation::WadOp;
       use tinywad::wad::{Wad, WadKind,};
       
       fn main() -> Result<(), WadError> {
           let mut src = Wad::new();
       
           let lump_names = [
               "FLOOR0_1", "FLOOR0_3", "FLOOR0_6",
               "FLOOR1_1", "FLOOR1_7", "FLOOR3_3",
               "FLOOR4_1", "FLOOR4_5", "FLOOR4_6",
               "FLOOR4_8", "FLOOR5_1", "FLOOR5_2",
               "FLOOR5_3", "FLOOR5_4", "FLOOR6_1",
               "FLOOR6_2", "FLOOR7_1", "FLOOR7_2",
           ];
       
           src.load_from_file("doom.wad")?;
       
           let gate = src.lump("FLOOR6_1").unwrap();
       
           let mut dest = Wad::new();
       
           dest.set_kind(WadKind::Pwad);
           dest.add_lump_raw(
               LumpAdd::new(
                   LumpAddKind::Back,
                   &vec![],
                   "FF_START",
               )
           )?;
       
           for lump_name in lump_names {
               dest.add_lump_raw(
                   LumpAdd::new(
                       LumpAddKind::Back,
                       &gate.data().buffer,
                       lump_name,
                   )
               )?;
           }
       
           dest.add_lump_raw(
               LumpAdd::new(
                   LumpAddKind::Back,
                   &vec![],
                   "F_END",
               )
           )?;
       
           dest.save("doom1_patch.wad");
       
           Ok(())
       }
       ```
       
       To take the screenshot (below) `doom1_patch.wad` has been injected into GZDOOM with the `IWAD` `doom.wad` (registered).
       
       ### Result
       
       ### Files
       
       [doom1_patch.wad](/doom1_patch.wad)  
       [doom1_patch.asc](/doom1_patch.asc)  
       [checksum](/checksum.txt)
       
       ### Extracting MIDI lumps
       
       Extracting every musics from the `IWAD` `doom.wad`.
       
       ```rust
       use tinywad::error::WadError;
       use tinywad::models::operation::WadOp;
       use tinywad::wad::{Wad};
       
       fn main() -> Result<(), WadError> {
           let mut src = Wad::new();
       
           src.load_from_file("doom.wad")?;
           src.select("D_");
           src.save_lumps(".");
       
           Ok(())
       }
       ```
       
       ### `D_E1M1` converted from MIDI to MP3
       
       ## Links
       
 (HTM) https://github.com/theobori/tinywad