diff --git a/README.md b/README.md index a445d99..564c5a6 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,8 @@ A Rust version of the original DOOM base on the offically released source code f This is more of a learning exercise than something good! For example, the original `z_zone.c` and `z_zone.h` will be more "Rust-like" compared to the original version. This repository will only contain the SHAREWARE verison of the original DOOM1, but will be able to run both IWAD and PWADS. + +This repository will be done in two parts before a "release" + + 1. An initial port keeping as close to the original C code as possible, which some minor modifications where it is clear on how to convert the code to Rust + 2. Rust-ify any (hopefully all) parts of the code, that is removing `unsafe` and other such things. This will also include breaking down some of the `uber` sized funtions of the original source into more managable bits diff --git a/src/d_main/mod.rs b/src/d_main/mod.rs index 5ffb0b0..be735e3 100644 --- a/src/d_main/mod.rs +++ b/src/d_main/mod.rs @@ -8,6 +8,7 @@ use crate::m_argv; use crate::m_argv::M_CheckParm; use crate::m_argv::M_GetOptionalArgumentValueByArgument; use crate::m_argv::PARM_NOT_FOUND; +use crate::m_menu::M_Init; use crate::m_misc::M_LoadDefaults; use crate::v_video::V_Init; @@ -466,11 +467,12 @@ pub fn D_DoomMain() { } } - // TODO: Implement other inits - /* + println!("M_Init: Init miscellaneous info."); M_Init(); + // TODO: Implement other inits + /* println!("R_Init: Init DOOM refresh daemon - ") R_Init(); diff --git a/src/m_menu/mod.rs b/src/m_menu/mod.rs new file mode 100644 index 0000000..fc39f2b --- /dev/null +++ b/src/m_menu/mod.rs @@ -0,0 +1,320 @@ +// Menu Widget stuff i.e episode selection etc. + +// TODO: Implement d_event.handle + +use std::ptr::addr_of_mut; + +use crate::doomdef::{DOOMGLOBALS, GameMode}; + +#[repr(C)] +#[derive(Copy, Clone)] +#[allow(non_snake_case)] +struct menuitem_t { + status: i32, + name: [u8; 10], + routine: Option, + + // hotkey in menu + alpha_key: u8, +} + +#[repr(C)] +#[derive(Copy, Clone)] +#[allow(non_snake_case)] +struct menu_t { + + /// Number of items in the menu + numitems: i32, + + /// Pointer to the previous menu + prevMenu: *mut menu_t, + + /// The menu items + menuItems: *mut menuitem_t, + + /// draw routine + routine: Option, + + /// X of the menu + x: i32, + + /// y of the menu + y: i32, + + /// The last item the user was on in the menu + lastOn: i32 +} + +/// TEMP function +#[allow(non_snake_case)] +fn VoidRoutine() { + +} + +#[allow(non_snake_case)] +fn VoidRoutineWithChoice(choice: i32) { + let _ = choice; +} + + +// Main Menu +#[allow(non_snake_case)] +mod MainMenu { + use super::*; + + /// Enumeration of the main menu options + #[allow(non_camel_case_types)] + pub(super) enum main_e { + newgame = 0, + options, + loadgame, + savegame, + readthis, + quitdoom, + main_end + } + + /// Main Menu items + #[allow(non_upper_case_globals)] + pub(super) static mut MainMenu: [menuitem_t; 6] = [ + menuitem_t { + status: 1, + name: *b"M_NGAME\0\0\0", + routine: Some(VoidRoutineWithChoice), + alpha_key: b'n' + }, + menuitem_t { + status: 1, + name: *b"M_OPTION\0\0", + routine: Some(VoidRoutineWithChoice), + alpha_key: b'o' + }, + menuitem_t { + status: 1, + name: *b"M_LOADG\0\0\0", + routine: Some(VoidRoutineWithChoice), + alpha_key: b'l' + }, + menuitem_t { + status: 1, + name: *b"M_SAVEG\0\0\0", + routine: Some(VoidRoutineWithChoice), + alpha_key: b's' + }, + menuitem_t { + status: 1, + name: *b"M_RDTHIS\0\0", + routine: Some(VoidRoutineWithChoice), + alpha_key: b'r' + }, + menuitem_t { + status: 1, + name: *b"M_QUITG\0\0\0", + routine: Some(VoidRoutineWithChoice), + alpha_key: b'q' + } + ]; + + /// Default MainMenu + #[allow(non_upper_case_globals)] + pub(super) static mut MainDef: menu_t = menu_t { + numitems: main_e::main_end as i32, + prevMenu: std::ptr::null_mut(), + menuItems: &raw mut MainMenu as *mut menuitem_t, // Use &raw mut instead of .as_mut_ptr() to avoid illegal static mut references (Feels dirty) + routine: Some(VoidRoutine), + x: 97, + y: 64, + lastOn: 0, + }; +} + +// New Game menu +#[allow(non_snake_case)] +mod NewGameMenu { + use super::*; + + /// Enumeration of the New Game options + #[allow(non_camel_case_types)] + pub(super) enum newgame_e { + killthings, + toorough, + hurtme, + violence, + nightmare, + newg_end + } + + /// New Game Menu items + #[allow(non_upper_case_globals)] + pub(super) static mut NewGameMenu: [menuitem_t; 5] = [ + menuitem_t { + status: 1, + name: *b"M_JKILL\0\0\0", + routine: Some(VoidRoutineWithChoice), + alpha_key: b'i' + }, + menuitem_t { + status: 1, + name: *b"M_ROUGH\0\0\0", + routine: Some(VoidRoutineWithChoice), + alpha_key: b'h' + }, + menuitem_t { + status: 1, + name: *b"M_HURT\0\0\0\0", + routine: Some(VoidRoutineWithChoice), + alpha_key: b'h' + }, + menuitem_t { + status: 1, + name: *b"M_ULTRA\0\0\0", + routine: Some(VoidRoutineWithChoice), + alpha_key: b'u' + }, + menuitem_t { + status: 1, + name: *b"M_NMARE\0\0\0", + routine: Some(VoidRoutineWithChoice), + alpha_key: b'n' + } + ]; + + #[allow(non_upper_case_globals)] + pub(super) static mut NewDef: menu_t = menu_t { + numitems: newgame_e::newg_end as i32, + prevMenu: std::ptr::null_mut(), // TODO: Add EpiDef + menuItems: &raw mut NewGameMenu as *mut menuitem_t, // Use &raw mut instead of .as_mut_ptr() to avoid illegal static mut references (Feels dirty) + routine: Some(VoidRoutine), + x: 48, + y: 63, + lastOn: newgame_e::hurtme as i32, + }; +} + +// TODO: add OptionsMenu +#[allow(non_snake_case)] +mod ReadThis1 { + use super::*; + + /// Enumeration of the main menu options + #[allow(non_camel_case_types)] + pub(super) enum read_e { + rdthisempty1 = 0, + read1_end, + } + + /// Read1 Menu items + #[allow(non_upper_case_globals)] + pub(super) static mut ReadMenu1: [menuitem_t; 1] = [ + menuitem_t { + status: 1, + name: *b"\0\0\0\0\0\0\0\0\0\0", + routine: Some(VoidRoutineWithChoice), + alpha_key: b'0' + } + ]; + + /// Default MainMenu + #[allow(non_upper_case_globals)] + pub(super) static mut Read1Def: menu_t = menu_t { + numitems: read_e::rdthisempty1 as i32, + prevMenu: addr_of_mut!(MainMenu::MainDef), + menuItems: &raw mut ReadMenu1 as *mut menuitem_t, // Use &raw mut instead of .as_mut_ptr() to avoid illegal static mut references (Feels dirty) + routine: Some(VoidRoutine), + x: 280, + y: 185, + lastOn: 0, + }; +} + +// TODO: The rest of this hell! + +#[allow(non_upper_case_globals)] +static mut currentMenu: *mut menu_t = std::ptr::null_mut(); + +#[allow(non_upper_case_globals)] +static mut menuactive: bool = false; + +#[allow(non_upper_case_globals)] +static mut itemOn: i32 = 0; + +#[allow(non_upper_case_globals)] +static mut whichSkull: i32 = 0; + +#[allow(non_upper_case_globals)] +static mut skullAnimCounter: i32 = 0; + +#[allow(non_upper_case_globals)] +static mut screenSize: i32 = 0; + +#[allow(non_upper_case_globals)] +static mut screenBlocks: i32 = 0; + +#[allow(non_upper_case_globals)] +static mut messageToPrint: i32 = 0; + +#[allow(non_upper_case_globals)] +static mut messageString: *mut u8 = std::ptr::null_mut(); + +#[allow(non_upper_case_globals)] +static mut messageLastMenuActive: i32 = 0; + +#[allow(non_upper_case_globals)] +static mut quickSaveSlot: i32 = -1; + +#[allow(non_snake_case)] +pub fn M_Ticket() { + +} + +#[allow(non_snake_case)] +pub fn M_Drawer() { + +} + +#[allow(non_snake_case)] +pub fn M_Init() { + unsafe { + currentMenu = addr_of_mut!(MainMenu::MainDef); + menuactive = false; + itemOn = (*currentMenu).lastOn; + whichSkull = 0; + skullAnimCounter = 10; + screenSize = screenBlocks - 3; + messageToPrint = 0; + messageString = std::ptr::null_mut(); + messageLastMenuActive = menuactive as i32; + quickSaveSlot = -1; + + + match DOOMGLOBALS::with_ref(|g| g.gamemode) { + GameMode::Commercial => { + /* + Original source code comment: + // This is used because DOOM 2 had only one HELP + // page. I use CREDIT as second page now, but + // kept this hack for educational purposes. + */ + MainMenu::MainMenu[MainMenu::main_e::readthis as usize] = MainMenu::MainMenu[MainMenu::main_e::quitdoom as usize]; + MainMenu::MainDef.numitems -=1; + MainMenu::MainDef.y += 8; + NewGameMenu::NewDef.prevMenu = addr_of_mut!(MainMenu::MainDef); + ReadThis1::Read1Def.routine = Some(VoidRoutine); + ReadThis1::Read1Def.x = 330; + ReadThis1::Read1Def.y = 165; + ReadThis1::ReadMenu1[ReadThis1::read_e::rdthisempty1 as usize].routine = Some(VoidRoutineWithChoice); + }, + GameMode::Shareware | GameMode::Registered => { + // TODO EpiDef.numitems-- + } + _ => { + // do nothing :) + } + } + } +} + +#[allow(non_snake_case)] +pub fn M_StartControlPanel() { + +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 0cb8eb0..e8b849a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ mod doomdef; mod doomtype; mod hu_stuff; mod m_argv; +mod m_menu; mod m_misc; mod v_video; mod w_wad;