Compare commits
6 Commits
feature/in
...
feature/im
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
dad59e261d | ||
|
|
93a3c8548e | ||
|
|
0a979dd8e0 | ||
|
|
dd7573a807 | ||
|
|
fd9bbaee2d | ||
|
|
f0b04bbcc2 |
10
.gitignore
vendored
10
.gitignore
vendored
@@ -1,5 +1,5 @@
|
|||||||
# ---> VisualStudioCode
|
# ---> VisualStudioCode
|
||||||
.vscode/*
|
.vscode/
|
||||||
!.vscode/settings.json
|
!.vscode/settings.json
|
||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
!.vscode/launch.json
|
!.vscode/launch.json
|
||||||
@@ -12,3 +12,11 @@
|
|||||||
# Built Visual Studio Code Extensions
|
# Built Visual Studio Code Extensions
|
||||||
*.vsix
|
*.vsix
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Added by cargo
|
||||||
|
|
||||||
|
/target
|
||||||
|
|
||||||
|
/WADS/*
|
||||||
|
!/WADS/DOOM1.wad
|
||||||
44
.vscode/launch.json
vendored
Normal file
44
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Debug Executable",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--bin=RustyDoom"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "RustyDoom",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [
|
||||||
|
"./WADS/DOOM.WAD", "-dev", "-nomonsters", "-skill", "3", "-config", "DEFAULT.CFG"
|
||||||
|
],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "lldb",
|
||||||
|
"request": "launch",
|
||||||
|
"name": "Release Executable",
|
||||||
|
"cargo": {
|
||||||
|
"args": [
|
||||||
|
"build",
|
||||||
|
"--release",
|
||||||
|
"--bin=RustyDoom"
|
||||||
|
],
|
||||||
|
"filter": {
|
||||||
|
"name": "RustyDoom",
|
||||||
|
"kind": "bin"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"args": [
|
||||||
|
"./WADS/DOOM.WAD", "arg2", "-fast"
|
||||||
|
],
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "RustyDoom"
|
||||||
|
version = "0.1.0"
|
||||||
10
Cargo.toml
Normal file
10
Cargo.toml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[package]
|
||||||
|
name = "RustyDoom"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = []
|
||||||
|
french = []
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
46
DEFAULT.CFG
Normal file
46
DEFAULT.CFG
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
mouse_sensitivity 5
|
||||||
|
sfx_volume 8
|
||||||
|
music_volume 8
|
||||||
|
show_messages 1
|
||||||
|
key_right 77
|
||||||
|
key_left 75
|
||||||
|
key_up 72
|
||||||
|
key_down 80
|
||||||
|
key_strafeleft 51
|
||||||
|
key_straferight 52
|
||||||
|
key_fire 29
|
||||||
|
key_use 57
|
||||||
|
key_strafe 56
|
||||||
|
key_speed 54
|
||||||
|
use_mouse 1
|
||||||
|
mouseb_fire 0
|
||||||
|
mouseb_strafe 1
|
||||||
|
mouseb_forward 2
|
||||||
|
use_joystick 0
|
||||||
|
joyb_fire 0
|
||||||
|
joyb_strafe 1
|
||||||
|
joyb_use 3
|
||||||
|
joyb_speed 2
|
||||||
|
screenblocks 9
|
||||||
|
detaillevel 0
|
||||||
|
showmessages 1
|
||||||
|
comport 1
|
||||||
|
snd_channels 8
|
||||||
|
snd_musicdevice 4
|
||||||
|
snd_sfxdevice 3
|
||||||
|
snd_sbport 544
|
||||||
|
snd_sbirq 7
|
||||||
|
snd_sbdma 1
|
||||||
|
snd_mport -1
|
||||||
|
usegamma 0
|
||||||
|
chatmacro0 "no macro"
|
||||||
|
chatmacro1 "no macro"
|
||||||
|
chatmacro2 "no macro"
|
||||||
|
chatmacro3 "no macro"
|
||||||
|
chatmacro4 "no macro"
|
||||||
|
chatmacro5 "no macro"
|
||||||
|
chatmacro6 "no macro"
|
||||||
|
chatmacro7 "no macro"
|
||||||
|
chatmacro8 "no macro"
|
||||||
|
chatmacro9 "no macro"
|
||||||
|
0
|
||||||
11
README.md
11
README.md
@@ -1,5 +1,12 @@
|
|||||||
# RustyDoom
|
# RustyDoom
|
||||||
|
|
||||||
A rust version of the original Doom.
|
A Rust version of the original DOOM base on the offically released source code found at [https://github.com/id-software/doom](https://github.com/id-software/doom)
|
||||||
|
|
||||||
This is more of a learning exercise than something good!
|
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
|
||||||
|
|||||||
BIN
WADS/doom1.wad
Normal file
BIN
WADS/doom1.wad
Normal file
Binary file not shown.
1
configs.txt
Normal file
1
configs.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-warp 1 5
|
||||||
560
src/d_main/mod.rs
Normal file
560
src/d_main/mod.rs
Normal file
@@ -0,0 +1,560 @@
|
|||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::io::{self, Write};
|
||||||
|
use std::path::{self};
|
||||||
|
use std::process;
|
||||||
|
|
||||||
|
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;
|
||||||
|
use crate::w_wad::{W_CheckNumForName, W_InitMultipleFiles};
|
||||||
|
use crate::z_zone::Z_Init;
|
||||||
|
|
||||||
|
use crate::doomdef::{
|
||||||
|
VERSION,
|
||||||
|
// D_DEVSTR,
|
||||||
|
GameMode,
|
||||||
|
Skill,
|
||||||
|
DOOMGLOBALS
|
||||||
|
};
|
||||||
|
|
||||||
|
fn flush_and_wait() {
|
||||||
|
let _ = io::stdout().flush();
|
||||||
|
|
||||||
|
// Replaces C's getchar() by waiting for the Enter key
|
||||||
|
let mut buffer = String::new();
|
||||||
|
let _ = io::stdin().read_line(&mut buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn D_AddFile(file: &str) {
|
||||||
|
DOOMGLOBALS::with_mut(|g| {
|
||||||
|
g.wadfiles.push(file.to_string());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn D_ProcessFileParameters(p_file: i32) {
|
||||||
|
let args = m_argv::M_GetAll();
|
||||||
|
let pos = p_file as usize;
|
||||||
|
// Find the index of "-file"
|
||||||
|
// Look at everything after the index
|
||||||
|
for &arg in args.iter().skip(pos + 1) {
|
||||||
|
if arg.starts_with('-') {
|
||||||
|
break; // Stop if we hit another flag like -debug
|
||||||
|
}
|
||||||
|
D_AddFile(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads a Response file for additional command line arguments
|
||||||
|
/// A response file is a text file that may store additional command line parameters.
|
||||||
|
/// The file may have any name that is valid to the system, optionally with an extension.
|
||||||
|
/// The parameters are typed as in the command line (-episode 2, for example),
|
||||||
|
/// but one per line, where up to 100 lines may be used.
|
||||||
|
/// The additional parameters may be disabled for later use by placing a vertical bar
|
||||||
|
/// (the | character) between the prefixing dash (-) and the rest of the parameter name.
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn FindResponseFile(args: &mut Vec<String>) -> Result<(), String> {
|
||||||
|
const MAX_ARGVS: usize = 100;
|
||||||
|
|
||||||
|
let mut i = 0;
|
||||||
|
while i < args.len() {
|
||||||
|
let arg = &args[i];
|
||||||
|
if arg.len() > 0 && arg.as_bytes()[0] == b'@' {
|
||||||
|
|
||||||
|
let f_name = &arg[1..]; // remove @
|
||||||
|
let f_content: String;
|
||||||
|
|
||||||
|
match fs::read_to_string(f_name) {
|
||||||
|
Ok(content) => f_content = content,
|
||||||
|
Err(e) => {
|
||||||
|
eprintln!("Found response file {}! (Error reading: {})", f_name, e);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
eprintln!("Found response file {}!", f_name);
|
||||||
|
|
||||||
|
let f_args: Vec<String> = f_content
|
||||||
|
.split_whitespace()
|
||||||
|
.map(|s| s.to_string())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
args.remove(i);
|
||||||
|
|
||||||
|
for (offset, new_arg) in f_args.into_iter().enumerate() {
|
||||||
|
args.insert(i+offset, new_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if args.len() > MAX_ARGVS {
|
||||||
|
eprintln!("Warning: Recieved {} total arguments, exceeding original MAX_ARGSV limit {}", args.len(), MAX_ARGVS)
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{} command-line args:", args.len());
|
||||||
|
for arg in args {
|
||||||
|
println!("\t{}", arg);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
i +=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn IdentifyVersion() -> Result<(), String> {
|
||||||
|
|
||||||
|
if M_CheckParm("-shdev") != PARM_NOT_FOUND {
|
||||||
|
eprintln!("-shddev param not implemented in this port");
|
||||||
|
eprintln!("Usage: RustyDoom <iwad-file> <Options>");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
if M_CheckParm("-regdev") != PARM_NOT_FOUND {
|
||||||
|
eprintln!("-regdev param not implemented in this port");
|
||||||
|
eprintln!("Usage: RustyDoom <iwad-file> <Options>");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
if M_CheckParm("-comdev") != PARM_NOT_FOUND {
|
||||||
|
eprintln!("-comdev param not implemented in this port");
|
||||||
|
eprintln!("Usage: RustyDoom <iwad-file> <Options>");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let iwad_arg = m_argv::M_GetPositionalArgv()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
eprintln!("Usage: RustyDoom <iwad-file> <Options>");
|
||||||
|
process::exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
let Ok(iwad_path) = path::absolute(std::path::PathBuf::from(iwad_arg)) else {
|
||||||
|
eprintln!("FATAL: Could not resolve the IWAD path: {}", iwad_arg);
|
||||||
|
process::exit(1);
|
||||||
|
};
|
||||||
|
if !iwad_path.is_file() {
|
||||||
|
eprintln!("FATAL: IWAD file not found: {}", iwad_path.display());
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let filename = iwad_path
|
||||||
|
.file_name()
|
||||||
|
.and_then(|f| f.to_str())
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
eprintln!("FATAL: Unable to get WAD filename from path: {:?}", iwad_path);
|
||||||
|
std::process::exit(1);
|
||||||
|
})
|
||||||
|
.to_ascii_lowercase();
|
||||||
|
|
||||||
|
DOOMGLOBALS::with_mut(|g| {
|
||||||
|
g.language = 0;
|
||||||
|
|
||||||
|
g.gamemode = match filename.as_str() {
|
||||||
|
|
||||||
|
"doom1.wad" => GameMode::Shareware,
|
||||||
|
|
||||||
|
"doom.wad" => GameMode::Registered,
|
||||||
|
|
||||||
|
"doomu.wad" | "ultimate.wad" => {
|
||||||
|
GameMode::Retail
|
||||||
|
}
|
||||||
|
|
||||||
|
"doom2.wad" => GameMode::Commercial,
|
||||||
|
|
||||||
|
"doom2f.wad" => {
|
||||||
|
g.language = 1;
|
||||||
|
GameMode::Commercial
|
||||||
|
}
|
||||||
|
|
||||||
|
"tnt.wad" => GameMode::Commercial,
|
||||||
|
|
||||||
|
"plutonia.wad" => GameMode::Commercial,
|
||||||
|
|
||||||
|
_ => GameMode::Indetermined,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
D_AddFile(&iwad_arg);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Converts the given string into a valid [u8; 128] array
|
||||||
|
fn to_fixed_bytes(input: &str) -> [u8; 128] {
|
||||||
|
let mut b = [0u8; 128];
|
||||||
|
let src = input.as_bytes();
|
||||||
|
let len = src.len().min(128);
|
||||||
|
b[..len].copy_from_slice(&src[..len]);
|
||||||
|
b
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn D_DoomMain() {
|
||||||
|
// get cli args from env
|
||||||
|
// Original doom uses a static module argc, argv
|
||||||
|
// Collects arguments into a Vector of Strings
|
||||||
|
// Process args
|
||||||
|
let mut args: Vec<String> = env::args().collect();
|
||||||
|
let _ = FindResponseFile(&mut args);
|
||||||
|
|
||||||
|
m_argv::init(args);
|
||||||
|
let _ = IdentifyVersion();
|
||||||
|
|
||||||
|
// setbuf (stdout, NULL); // TODO: Investigate this
|
||||||
|
DOOMGLOBALS::with_mut(|g| {
|
||||||
|
g.modifiedgame = false;
|
||||||
|
g.nomonsters = M_CheckParm("-nomonsters") != 0;
|
||||||
|
g.respawnparm = M_CheckParm("-respawn") != 0;
|
||||||
|
g.fastparm = M_CheckParm("-fastparm") != 0;
|
||||||
|
g.devparm = M_CheckParm("-devparam") != 0;
|
||||||
|
g.deathmatch = if M_CheckParm("-altdeath") != 0 {
|
||||||
|
2
|
||||||
|
} else if M_CheckParm("-deathmatch") != 0 {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
};
|
||||||
|
// TODO: fix the original issue to handle TnT + Plutonia
|
||||||
|
g.title = match g.gamemode {
|
||||||
|
GameMode::Retail => to_fixed_bytes(&format!(" The Ultimate DOOM Startup v{}.{} ", VERSION / 100, VERSION % 100)),
|
||||||
|
GameMode::Shareware => to_fixed_bytes(&format!(" DOOM Shareware Startup v{}.{} ", VERSION / 100, VERSION % 100)),
|
||||||
|
GameMode::Registered => to_fixed_bytes(&format!(" DOOM Registered Startup v{}.{} ", VERSION / 100, VERSION % 100)),
|
||||||
|
GameMode::Commercial => to_fixed_bytes(&format!(" DOOM 2: Hell on Earth v{}.{} ", VERSION / 100, VERSION % 100)),
|
||||||
|
GameMode::Indetermined => to_fixed_bytes(&format!(" Public DOOM - v{}.{} ", VERSION / 100, VERSION % 100)),
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("{}", String::from_utf8_lossy(&g.title));
|
||||||
|
|
||||||
|
if g.devparm {
|
||||||
|
eprintln!("devparm not implemented in this port");
|
||||||
|
eprintln!("Usage: RustyDoom <iwad-file> <Options>");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check and parse turbo options if applicable
|
||||||
|
if M_CheckParm("-turbo") != PARM_NOT_FOUND {
|
||||||
|
let mut scale :i32 = 200;
|
||||||
|
// TODO: Resolve externs (int should be fixed_t) or FixedPoint in our case
|
||||||
|
// extern int forwardmove[2];
|
||||||
|
// extern int sidemove[2];
|
||||||
|
if let Some(arg_str) = M_GetOptionalArgumentValueByArgument("-turbo") {
|
||||||
|
if let Ok(parsed_val) = arg_str.parse() {
|
||||||
|
scale = parsed_val;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scale = scale.clamp(10, 400);
|
||||||
|
println!("turbo scale: {}%", scale);
|
||||||
|
// TODO: Resolve externs
|
||||||
|
//forwardmove[0] = forwardmove[0]*scale/100;
|
||||||
|
//forwardmove[1] = forwardmove[1]*scale/100;
|
||||||
|
//sidemove[0] = sidemove[0]*scale/100;
|
||||||
|
//sidemove[1] = sidemove[1]*scale/100;
|
||||||
|
}
|
||||||
|
|
||||||
|
if M_CheckParm ("-wart") != PARM_NOT_FOUND {
|
||||||
|
eprintln!("-wart is not implemented in this port");
|
||||||
|
eprintln!("Usage: RustyDoom <iwad-file> <Options>");
|
||||||
|
process::exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut p = M_CheckParm("-file");{
|
||||||
|
if p != PARM_NOT_FOUND {
|
||||||
|
// Params after -file are wadfile/lump names
|
||||||
|
// Continue collecting until end of params or another `-` preceded param
|
||||||
|
DOOMGLOBALS::with_mut(|g|{
|
||||||
|
g.modifiedgame = true;
|
||||||
|
});
|
||||||
|
D_ProcessFileParameters(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Playing a dmeo?
|
||||||
|
p = M_CheckParm("-playdemo");
|
||||||
|
if p != PARM_NOT_FOUND {
|
||||||
|
p = M_CheckParm("-timedemo");
|
||||||
|
}
|
||||||
|
|
||||||
|
if p != PARM_NOT_FOUND && p < m_argv::M_GetArgC() - 1 {
|
||||||
|
if let Some(demo_file) = m_argv::M_GetOptionalArgumentValueByIndex(p+1) {
|
||||||
|
D_AddFile(demo_file);
|
||||||
|
println!("Playing demo {}.lmp.\n", demo_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the skill, episode and map from the parms if given
|
||||||
|
|
||||||
|
DOOMGLOBALS::with_mut(|g| {
|
||||||
|
g.startskill = Skill::sk_medium as i32;
|
||||||
|
g.startepisode = 1;
|
||||||
|
g.startmap = 1;
|
||||||
|
g.autostart = false;
|
||||||
|
});
|
||||||
|
|
||||||
|
p = M_CheckParm("-skill");
|
||||||
|
if p != PARM_NOT_FOUND && p < m_argv::M_GetArgC() - 1 {
|
||||||
|
if let Some(skill_val) = m_argv::M_GetOptionalArgumentValueByIndex(p + 1) {
|
||||||
|
if let Some(first_char) = skill_val.chars().next() {
|
||||||
|
let start_skill = (first_char as i32).wrapping_sub('1' as i32);
|
||||||
|
|
||||||
|
DOOMGLOBALS::with_mut(|g| {
|
||||||
|
g.startskill = start_skill;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p = M_CheckParm("-episode");
|
||||||
|
if p != PARM_NOT_FOUND && p < m_argv::M_GetArgC() - 1 {
|
||||||
|
if let Some(episode_val) = m_argv::M_GetOptionalArgumentValueByIndex(p + 1) {
|
||||||
|
if let Some(first_char) = episode_val.chars().next() {
|
||||||
|
let start_episode = (first_char as i32).wrapping_sub('0' as i32);
|
||||||
|
|
||||||
|
DOOMGLOBALS::with_mut(|g| {
|
||||||
|
g.startepisode = start_episode;
|
||||||
|
g.startmap = 1;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p = M_CheckParm("-timer");
|
||||||
|
let is_deathmath = DOOMGLOBALS::with_ref(|g| g.deathmatch);
|
||||||
|
if p != PARM_NOT_FOUND && p < m_argv::M_GetArgC() - 1 && is_deathmath > 0 {
|
||||||
|
if let Some(timer_val) = m_argv::M_GetOptionalArgumentValueByIndex(p + 1) {
|
||||||
|
match timer_val.parse::<u32>() {
|
||||||
|
Ok(time) => {
|
||||||
|
if time > 1 {
|
||||||
|
println!("Levels will end after {} minutes", time)
|
||||||
|
} else {
|
||||||
|
|
||||||
|
println!("Levels will end after {} minute", time)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!("value for -timer is not a valid number of minutes");
|
||||||
|
eprintln!("Usage: RustyDoom <iwad-file> <Options>");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p = M_CheckParm("-avg");
|
||||||
|
if p != PARM_NOT_FOUND && p < m_argv::M_GetArgC() - 1 && is_deathmath > 0 {
|
||||||
|
println!("Austin Virtual Gaming: Levels will end after 20 minutes\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
p = M_CheckParm("-warp");
|
||||||
|
if p != PARM_NOT_FOUND && p < m_argv::M_GetArgC() - 1 {
|
||||||
|
let g_mode = DOOMGLOBALS::with_ref(|g| g.gamemode);
|
||||||
|
if g_mode == GameMode::Commercial {
|
||||||
|
if let Some(gamemode_val) = m_argv::M_GetOptionalArgumentValueByIndex(p + 1) {
|
||||||
|
match gamemode_val.parse::<i32>() {
|
||||||
|
Ok(mapstart) => {
|
||||||
|
DOOMGLOBALS::with_mut(|g| {
|
||||||
|
g.startmap = mapstart;
|
||||||
|
g.autostart = true;
|
||||||
|
})
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
eprintln!("value for -warp is not a valid map number");
|
||||||
|
eprintln!("Usage: RustyDoom <iwad-file> <Options>");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if let Some(episode_val) = m_argv::M_GetOptionalArgumentValueByIndex(p + 1) {
|
||||||
|
if let Some(map_val) = m_argv::M_GetOptionalArgumentValueByIndex(p + 2) {
|
||||||
|
match (episode_val.parse::<i32>(), map_val.parse::<i32>()) {
|
||||||
|
(Ok(startepisode), Ok(startmap)) => {
|
||||||
|
DOOMGLOBALS::with_mut(|g| {
|
||||||
|
g.startepisode = startepisode;
|
||||||
|
g.startmap = startmap;
|
||||||
|
g.autostart = true;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
(Ok(_), Err(_)) => {
|
||||||
|
eprintln!("value for starting map in -warp is not a valid number");
|
||||||
|
eprintln!("Usage: RustyDoom <iwad-file> <Options>");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
(Err(_), Ok(_)) => {
|
||||||
|
eprintln!("value for starting episode in -warp is not a valid number");
|
||||||
|
eprintln!("Usage: RustyDoom <iwad-file> <Options>");
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
(Err(_), Err(_)) => {
|
||||||
|
eprintln!("Values for starting episode and map in -warp are not a valid numbers");
|
||||||
|
eprintln!("Usage: RustyDoom <iwad-file> <Options>");
|
||||||
|
std::process::exit(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
println!("V_Init: allocate screens.");
|
||||||
|
V_Init();
|
||||||
|
|
||||||
|
println!("M_LoadDefaults: Load system defaults.");
|
||||||
|
M_LoadDefaults();
|
||||||
|
|
||||||
|
println!("Z_init: Init zone memory allocation daemon.");
|
||||||
|
Z_Init();
|
||||||
|
|
||||||
|
println!("W_Init: Init WADfiles");
|
||||||
|
W_InitMultipleFiles(DOOMGLOBALS::with_ref(|g| g.wadfiles.clone())); // we are loading so how cares about a borrow
|
||||||
|
|
||||||
|
let is_modified = DOOMGLOBALS::with_ref(|g| g.modifiedgame);
|
||||||
|
|
||||||
|
if is_modified {
|
||||||
|
let iwads_lumps_to_check: Vec<&str> = vec!["e2m1","e2m2","e2m3","e2m4","e2m5","e2m6","e2m7","e2m8","e2m9",
|
||||||
|
"e3m1","e3m3","e3m3","e3m4","e3m5","e3m6","e3m7","e3m8","e3m9",
|
||||||
|
"dphoof","bfgga0","heada1","cybra1","spida1d1"];
|
||||||
|
|
||||||
|
let g_mode = DOOMGLOBALS::with_ref(|g| g.gamemode);
|
||||||
|
|
||||||
|
if g_mode == GameMode::Shareware {
|
||||||
|
// I_ERROR?
|
||||||
|
}
|
||||||
|
|
||||||
|
if g_mode == GameMode::Registered {
|
||||||
|
let missing_registered_lump = iwads_lumps_to_check
|
||||||
|
.iter()
|
||||||
|
.any(|lump_name| W_CheckNumForName(lump_name) == -1);
|
||||||
|
if missing_registered_lump {
|
||||||
|
// TODO: Implement I_Error
|
||||||
|
// I_Error("\nThis is not the registered version.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Display the modifed game header
|
||||||
|
|
||||||
|
if is_modified {
|
||||||
|
print!("===========================================================================\n\
|
||||||
|
ATTENTION: This version of DOOM has been modified. If you would like to\n\
|
||||||
|
get a copy of the original game, call 1-800-IDGAMES or see the readme file.\n\
|
||||||
|
You will not receive technical support for modified games.\n\
|
||||||
|
press enter to continue\n\
|
||||||
|
===========================================================================\n"
|
||||||
|
);
|
||||||
|
flush_and_wait();
|
||||||
|
}
|
||||||
|
|
||||||
|
match DOOMGLOBALS::with_ref(|g| g.gamemode) {
|
||||||
|
GameMode::Shareware | GameMode::Indetermined => {
|
||||||
|
print!("===========================================================================\n\
|
||||||
|
Shareware!\n\
|
||||||
|
===========================================================================\n")
|
||||||
|
}
|
||||||
|
GameMode::Registered | GameMode::Retail | GameMode::Commercial => {
|
||||||
|
print!("===========================================================================\n\
|
||||||
|
Commercial product - do not distribute!\n\
|
||||||
|
Please report software piracy to the SPA: 1-800-388-PIR8\n\
|
||||||
|
===========================================================================\n")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
println!("M_Init: Init miscellaneous info.");
|
||||||
|
M_Init();
|
||||||
|
|
||||||
|
// TODO: Implement other inits
|
||||||
|
/*
|
||||||
|
println!("R_Init: Init DOOM refresh daemon - ")
|
||||||
|
R_Init();
|
||||||
|
|
||||||
|
println!("P_Init: Init Playloop state.");
|
||||||
|
P_Init();
|
||||||
|
|
||||||
|
println!("I_Init: Setting up machine state.");
|
||||||
|
I_Init()
|
||||||
|
|
||||||
|
println!("D_CheckNetGame: Checking network game status.");
|
||||||
|
D_CheckNetGame()
|
||||||
|
|
||||||
|
println!("S_Init: Setting up sound.");
|
||||||
|
S_Init (snd_SfxVolume /* *8 */, snd_MusicVolume /* *8*/ );
|
||||||
|
|
||||||
|
printf ("HU_Init: Setting up heads up display.\n");
|
||||||
|
HU_Init ();
|
||||||
|
|
||||||
|
printf ("ST_Init: Init status bar.\n");
|
||||||
|
ST_Init ();
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Check for a driver that wants intermission stats
|
||||||
|
|
||||||
|
|
||||||
|
p = M_CheckParm("-statcopy");
|
||||||
|
if p != PARM_NOT_FOUND && p < m_argv::M_GetArgC() - 1 {
|
||||||
|
// TODO: implement for statistics driver
|
||||||
|
/*extern void* statcopy;
|
||||||
|
|
||||||
|
statcopy = (void*)atoi(myargv[p+1]);
|
||||||
|
printf ("External statistics registered.\n");*/
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start the approiate gaem based on parms
|
||||||
|
p = M_CheckParm("-record");
|
||||||
|
if p != PARM_NOT_FOUND && p < m_argv::M_GetArgC() - 1 {
|
||||||
|
// TODO: Implement G_RecordDemo
|
||||||
|
//G_RecordDemo(m_argv::M_GetOptionalArgumentValueByIndex(p+1));
|
||||||
|
DOOMGLOBALS::with_mut(|g| g.autostart = true);
|
||||||
|
}
|
||||||
|
|
||||||
|
p = M_CheckParm("-playdemo");
|
||||||
|
if p != PARM_NOT_FOUND && p < m_argv::M_GetArgC() - 1 {
|
||||||
|
// TODO: Implement G_DeferedPlayDemo
|
||||||
|
// G_DeferedPlayDemo (myargv[p+1]);
|
||||||
|
// D_DoomLoop (); // never returns
|
||||||
|
}
|
||||||
|
|
||||||
|
p = M_CheckParm("-timedemo");
|
||||||
|
if p != PARM_NOT_FOUND && p < m_argv::M_GetArgC() - 1 {
|
||||||
|
// TODO: Implement G_TimeDemo
|
||||||
|
// G_TimeDemo (myargv[p+1]);
|
||||||
|
// D_DoomLoop (); // never returns
|
||||||
|
}
|
||||||
|
|
||||||
|
p = M_CheckParm("-loadgame");
|
||||||
|
if p != PARM_NOT_FOUND && p < m_argv::M_GetArgC() - 1 {
|
||||||
|
// TODO: Implement loadgame param G_LoadGame
|
||||||
|
// G_TimeDemo (myargv[p+1]);
|
||||||
|
// D_DoomLoop (); // never returns
|
||||||
|
if M_CheckParm("-cdrom") != PARM_NOT_FOUND {
|
||||||
|
// sprintf(file, "c:\\doomdata\\"SAVEGAMENAME"%c.dsg",myargv[p+1][0]);
|
||||||
|
} else {
|
||||||
|
// sprintf(file, SAVEGAMENAME"%c.dsg",myargv[p+1][0]);
|
||||||
|
}
|
||||||
|
// G_LoagGame(file)
|
||||||
|
}
|
||||||
|
|
||||||
|
p = M_CheckParm("-ga_loadgame");
|
||||||
|
if p != PARM_NOT_FOUND && p < m_argv::M_GetArgC() - 1 {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// let g_action = DOOMGLOBALS::with_ref(|g| g.gameaction);
|
||||||
|
|
||||||
|
// TODO: Impement Game actions
|
||||||
|
// if g_action != ga_loadgame {
|
||||||
|
// let autostart = DOOMGLOBALS::with_ref(|g| g.autostart);
|
||||||
|
// let netgame = DOOMGLOBALS::with_ref(|G| G.)
|
||||||
|
// }
|
||||||
|
|
||||||
|
// D_DoomLoop()
|
||||||
|
|
||||||
|
}
|
||||||
638
src/d_strings/d_english/mod.rs
Normal file
638
src/d_strings/d_english/mod.rs
Normal file
@@ -0,0 +1,638 @@
|
|||||||
|
/// English Language string constants
|
||||||
|
|
||||||
|
//
|
||||||
|
// D_Main
|
||||||
|
//
|
||||||
|
pub const D_DEVSTR: &'static str = "Development mode ON.\n";
|
||||||
|
pub const D_CDROM: &'static str = "CD-ROM Version: default.cfg from c:\\doomdata\n";
|
||||||
|
|
||||||
|
//
|
||||||
|
// M_Menu
|
||||||
|
//
|
||||||
|
pub const PRESSKEY: &'static str = "press a key.";
|
||||||
|
pub const PRESSYN: &'static str = "press y or n.";
|
||||||
|
pub const QUITMSG: &'static str = "are you sure you want to\nquit this great game?";
|
||||||
|
pub const LOADNET: &'static str = concat!("you can't do load while in a net game!\n\n", "press a key.");
|
||||||
|
pub const QLOADNET: &'static str = concat!("you can't quickload during a netgame!\n\n", "press a key.");
|
||||||
|
pub const QSAVESPOT: &'static str = concat!("you haven't picked a quicksave slot yet!\n\n", "press a key.");
|
||||||
|
pub const SAVEDEAD: &'static str = concat!("you can't save if you aren't playing!\n\n", "press a key.");
|
||||||
|
pub const QSPROMPT: &'static str = concat!("quicksave over your game named\n\n'%s'?\n\n", "press y or n.");
|
||||||
|
pub const QLPROMPT: &'static str = concat!("do you want to quickload the game named\n\n'%s'?\n\n", "press y or n.");
|
||||||
|
|
||||||
|
pub const NEWGAME: &'static str = concat!("you can't start a new game\n", "while in a network game.\n\n", "press a key.");
|
||||||
|
|
||||||
|
pub const NIGHTMARE: &'static str = concat!("are you sure? this skill level\n","isn't even remotely fair.\n\n", "press y or n.");
|
||||||
|
|
||||||
|
pub const SWSTRING: &'static str = concat!("this is the shareware version of doom.\n\n", "you need to order the entire trilogy.\n\n", "press a key.");
|
||||||
|
|
||||||
|
pub const MSGOFF: &'static str = "Messages OFF";
|
||||||
|
pub const MSGON: &'static str = "Messages ON";
|
||||||
|
pub const NETEND: &'static str = concat!("you can't end a netgame!\n\n", "press a key.");
|
||||||
|
pub const ENDGAME: &'static str = concat!("are you sure you want to end the game?\n\n", "press y or n.");
|
||||||
|
|
||||||
|
pub const DOSY: &'static str = "(press y to quit)";
|
||||||
|
|
||||||
|
pub const DETAILHI: &'static str = "High detail";
|
||||||
|
pub const DETAILLO: &'static str = "Low detail";
|
||||||
|
pub const GAMMALVL0: &'static str = "Gamma correction OFF";
|
||||||
|
pub const GAMMALVL1: &'static str = "Gamma correction level 1";
|
||||||
|
pub const GAMMALVL2: &'static str = "Gamma correction level 2";
|
||||||
|
pub const GAMMALVL3: &'static str = "Gamma correction level 3";
|
||||||
|
pub const GAMMALVL4: &'static str = "Gamma correction level 4";
|
||||||
|
pub const EMPTYSTRING: &'static str = "empty slot";
|
||||||
|
|
||||||
|
//
|
||||||
|
// P_inter.C
|
||||||
|
//
|
||||||
|
pub const GOTARMOR: &'static str = "Picked up the armor.";
|
||||||
|
pub const GOTMEGA: &'static str = "Picked up the MegaArmor!";
|
||||||
|
pub const GOTHTHBONUS: &'static str = "Picked up a health bonus.";
|
||||||
|
pub const GOTARMBONUS: &'static str = "Picked up an armor bonus.";
|
||||||
|
pub const GOTSTIM: &'static str = "Picked up a stimpack.";
|
||||||
|
pub const GOTMEDINEED: &'static str = "Picked up a medikit that you REALLY need!";
|
||||||
|
pub const GOTMEDIKIT: &'static str = "Picked up a medikit.";
|
||||||
|
pub const GOTSUPER: &'static str = "Supercharge!";
|
||||||
|
|
||||||
|
pub const GOTBLUECARD: &'static str = "Picked up a blue keycard.";
|
||||||
|
pub const GOTYELWCARD: &'static str = "Picked up a yellow keycard.";
|
||||||
|
pub const GOTREDCARD: &'static str = "Picked up a red keycard.";
|
||||||
|
pub const GOTBLUESKUL: &'static str = "Picked up a blue skull key.";
|
||||||
|
pub const GOTYELWSKUL: &'static str = "Picked up a yellow skull key.";
|
||||||
|
pub const GOTREDSKULL: &'static str = "Picked up a red skull key.";
|
||||||
|
|
||||||
|
pub const GOTINVUL: &'static str = "Invulnerability!";
|
||||||
|
pub const GOTBERSERK: &'static str = "Berserk!";
|
||||||
|
pub const GOTINVIS: &'static str = "Partial Invisibility";
|
||||||
|
pub const GOTSUIT: &'static str = "Radiation Shielding Suit";
|
||||||
|
pub const GOTMAP: &'static str = "Computer Area Map";
|
||||||
|
pub const GOTVISOR: &'static str = "Light Amplification Visor";
|
||||||
|
pub const GOTMSPHERE: &'static str = "MegaSphere!";
|
||||||
|
|
||||||
|
pub const GOTCLIP: &'static str = "Picked up a clip.";
|
||||||
|
pub const GOTCLIPBOX: &'static str = "Picked up a box of bullets.";
|
||||||
|
pub const GOTROCKET: &'static str = "Picked up a rocket.";
|
||||||
|
pub const GOTROCKBOX: &'static str = "Picked up a box of rockets.";
|
||||||
|
pub const GOTCELL: &'static str = "Picked up an energy cell.";
|
||||||
|
pub const GOTCELLBOX: &'static str = "Picked up an energy cell pack.";
|
||||||
|
pub const GOTSHELLS: &'static str = "Picked up 4 shotgun shells.";
|
||||||
|
pub const GOTSHELLBOX: &'static str = "Picked up a box of shotgun shells.";
|
||||||
|
pub const GOTBACKPACK: &'static str = "Picked up a backpack full of ammo!";
|
||||||
|
|
||||||
|
pub const GOTBFG9000: &'static str = "You got the BFG9000! Oh, yes.";
|
||||||
|
pub const GOTCHAINGUN: &'static str = "You got the chaingun!";
|
||||||
|
pub const GOTCHAINSAW: &'static str = "A chainsaw! Find some meat!";
|
||||||
|
pub const GOTLAUNCHER: &'static str = "You got the rocket launcher!";
|
||||||
|
pub const GOTPLASMA: &'static str = "You got the plasma gun!";
|
||||||
|
pub const GOTSHOTGUN: &'static str = "You got the shotgun!";
|
||||||
|
pub const GOTSHOTGUN2: &'static str = "You got the super shotgun!";
|
||||||
|
|
||||||
|
//
|
||||||
|
// P_Doors.C
|
||||||
|
//
|
||||||
|
pub const PD_BLUEO: &'static str = "You need a blue key to activate this object";
|
||||||
|
pub const PD_REDO: &'static str = "You need a red key to activate this object";
|
||||||
|
pub const PD_YELLOWO: &'static str = "You need a yellow key to activate this object";
|
||||||
|
pub const PD_BLUEK: &'static str = "You need a blue key to open this door";
|
||||||
|
pub const PD_REDK: &'static str = "You need a red key to open this door";
|
||||||
|
pub const PD_YELLOWK: &'static str = "You need a yellow key to open this door";
|
||||||
|
|
||||||
|
//
|
||||||
|
// G_game.C
|
||||||
|
//
|
||||||
|
pub const GGSAVED: &'static str = "game saved.";
|
||||||
|
|
||||||
|
//
|
||||||
|
// HU_stuff.C
|
||||||
|
//
|
||||||
|
pub const HUSTR_MSGU: &'static str = "[Message unsent]";
|
||||||
|
|
||||||
|
pub const HUSTR_E1M1: &'static str = "E1M1: Hangar";
|
||||||
|
pub const HUSTR_E1M2: &'static str = "E1M2: Nuclear Plant";
|
||||||
|
pub const HUSTR_E1M3: &'static str = "E1M3: Toxin Refinery";
|
||||||
|
pub const HUSTR_E1M4: &'static str = "E1M4: Command Control";
|
||||||
|
pub const HUSTR_E1M5: &'static str = "E1M5: Phobos Lab";
|
||||||
|
pub const HUSTR_E1M6: &'static str = "E1M6: Central Processing";
|
||||||
|
pub const HUSTR_E1M7: &'static str = "E1M7: Computer Station";
|
||||||
|
pub const HUSTR_E1M8: &'static str = "E1M8: Phobos Anomaly";
|
||||||
|
pub const HUSTR_E1M9: &'static str = "E1M9: Military Base";
|
||||||
|
|
||||||
|
pub const HUSTR_E2M1: &'static str = "E2M1: Deimos Anomaly";
|
||||||
|
pub const HUSTR_E2M2: &'static str = "E2M2: Containment Area";
|
||||||
|
pub const HUSTR_E2M3: &'static str = "E2M3: Refinery";
|
||||||
|
pub const HUSTR_E2M4: &'static str = "E2M4: Deimos Lab";
|
||||||
|
pub const HUSTR_E2M5: &'static str = "E2M5: Command Center";
|
||||||
|
pub const HUSTR_E2M6: &'static str = "E2M6: Halls of the Damned";
|
||||||
|
pub const HUSTR_E2M7: &'static str = "E2M7: Spawning Vats";
|
||||||
|
pub const HUSTR_E2M8: &'static str = "E2M8: Tower of Babel";
|
||||||
|
pub const HUSTR_E2M9: &'static str = "E2M9: Fortress of Mystery";
|
||||||
|
|
||||||
|
pub const HUSTR_E3M1: &'static str = "E3M1: Hell Keep";
|
||||||
|
pub const HUSTR_E3M2: &'static str = "E3M2: Slough of Despair";
|
||||||
|
pub const HUSTR_E3M3: &'static str = "E3M3: Pandemonium";
|
||||||
|
pub const HUSTR_E3M4: &'static str = "E3M4: House of Pain";
|
||||||
|
pub const HUSTR_E3M5: &'static str = "E3M5: Unholy Cathedral";
|
||||||
|
pub const HUSTR_E3M6: &'static str = "E3M6: Mt. Erebus";
|
||||||
|
pub const HUSTR_E3M7: &'static str = "E3M7: Limbo";
|
||||||
|
pub const HUSTR_E3M8: &'static str = "E3M8: Dis";
|
||||||
|
pub const HUSTR_E3M9: &'static str = "E3M9: Warrens";
|
||||||
|
|
||||||
|
pub const HUSTR_E4M1: &'static str = "E4M1: Hell Beneath";
|
||||||
|
pub const HUSTR_E4M2: &'static str = "E4M2: Perfect Hatred";
|
||||||
|
pub const HUSTR_E4M3: &'static str = "E4M3: Sever The Wicked";
|
||||||
|
pub const HUSTR_E4M4: &'static str = "E4M4: Unruly Evil";
|
||||||
|
pub const HUSTR_E4M5: &'static str = "E4M5: They Will Repent";
|
||||||
|
pub const HUSTR_E4M6: &'static str = "E4M6: Against Thee Wickedly";
|
||||||
|
pub const HUSTR_E4M7: &'static str = "E4M7: And Hell Followed";
|
||||||
|
pub const HUSTR_E4M8: &'static str = "E4M8: Unto The Cruel";
|
||||||
|
pub const HUSTR_E4M9: &'static str = "E4M9: Fear";
|
||||||
|
|
||||||
|
pub const HUSTR_1: &'static str = "level 1: entryway";
|
||||||
|
pub const HUSTR_2: &'static str = "level 2: underhalls";
|
||||||
|
pub const HUSTR_3: &'static str = "level 3: the gantlet";
|
||||||
|
pub const HUSTR_4: &'static str = "level 4: the focus";
|
||||||
|
pub const HUSTR_5: &'static str = "level 5: the waste tunnels";
|
||||||
|
pub const HUSTR_6: &'static str = "level 6: the crusher";
|
||||||
|
pub const HUSTR_7: &'static str = "level 7: dead simple";
|
||||||
|
pub const HUSTR_8: &'static str = "level 8: tricks and traps";
|
||||||
|
pub const HUSTR_9: &'static str = "level 9: the pit";
|
||||||
|
pub const HUSTR_10: &'static str = "level 10: refueling base";
|
||||||
|
pub const HUSTR_11: &'static str = "level 11: 'o' of destruction!";
|
||||||
|
|
||||||
|
pub const HUSTR_12: &'static str = "level 12: the factory";
|
||||||
|
pub const HUSTR_13: &'static str = "level 13: downtown";
|
||||||
|
pub const HUSTR_14: &'static str = "level 14: the inmost dens";
|
||||||
|
pub const HUSTR_15: &'static str = "level 15: industrial zone";
|
||||||
|
pub const HUSTR_16: &'static str = "level 16: suburbs";
|
||||||
|
pub const HUSTR_17: &'static str = "level 17: tenements";
|
||||||
|
pub const HUSTR_18: &'static str = "level 18: the courtyard";
|
||||||
|
pub const HUSTR_19: &'static str = "level 19: the citadel";
|
||||||
|
pub const HUSTR_20: &'static str = "level 20: gotcha!";
|
||||||
|
|
||||||
|
pub const HUSTR_21: &'static str = "level 21: nirvana";
|
||||||
|
pub const HUSTR_22: &'static str = "level 22: the catacombs";
|
||||||
|
pub const HUSTR_23: &'static str = "level 23: barrels o' fun";
|
||||||
|
pub const HUSTR_24: &'static str = "level 24: the chasm";
|
||||||
|
pub const HUSTR_25: &'static str = "level 25: bloodfalls";
|
||||||
|
pub const HUSTR_26: &'static str = "level 26: the abandoned mines";
|
||||||
|
pub const HUSTR_27: &'static str = "level 27: monster condo";
|
||||||
|
pub const HUSTR_28: &'static str = "level 28: the spirit world";
|
||||||
|
pub const HUSTR_29: &'static str = "level 29: the living end";
|
||||||
|
pub const HUSTR_30: &'static str = "level 30: icon of sin";
|
||||||
|
|
||||||
|
pub const HUSTR_31: &'static str = "level 31: wolfenstein";
|
||||||
|
pub const HUSTR_32: &'static str = "level 32: grosse";
|
||||||
|
|
||||||
|
pub const PHUSTR_1: &'static str ="level 1: congo";
|
||||||
|
pub const PHUSTR_2: &'static str ="level 2: well of souls";
|
||||||
|
pub const PHUSTR_3: &'static str ="level 3: aztec";
|
||||||
|
pub const PHUSTR_4: &'static str ="level 4: caged";
|
||||||
|
pub const PHUSTR_5: &'static str ="level 5: ghost town";
|
||||||
|
pub const PHUSTR_6: &'static str ="level 6: baron's lair";
|
||||||
|
pub const PHUSTR_7: &'static str ="level 7: caughtyard";
|
||||||
|
pub const PHUSTR_8: &'static str ="level 8: realm";
|
||||||
|
pub const PHUSTR_9: &'static str ="level 9: abattoire";
|
||||||
|
pub const PHUSTR_10: &'static str = "level 10: onslaught";
|
||||||
|
pub const PHUSTR_11: &'static str = "level 11: hunted";
|
||||||
|
|
||||||
|
pub const PHUSTR_12: &'static str = "level 12: speed";
|
||||||
|
pub const PHUSTR_13: &'static str = "level 13: the crypt";
|
||||||
|
pub const PHUSTR_14: &'static str = "level 14: genesis";
|
||||||
|
pub const PHUSTR_15: &'static str = "level 15: the twilight";
|
||||||
|
pub const PHUSTR_16: &'static str = "level 16: the omen";
|
||||||
|
pub const PHUSTR_17: &'static str = "level 17: compound";
|
||||||
|
pub const PHUSTR_18: &'static str = "level 18: neurosphere";
|
||||||
|
pub const PHUSTR_19: &'static str = "level 19: nme";
|
||||||
|
pub const PHUSTR_20: &'static str = "level 20: the death domain";
|
||||||
|
|
||||||
|
pub const PHUSTR_21: &'static str = "level 21: slayer";
|
||||||
|
pub const PHUSTR_22: &'static str = "level 22: impossible mission";
|
||||||
|
pub const PHUSTR_23: &'static str = "level 23: tombstone";
|
||||||
|
pub const PHUSTR_24: &'static str = "level 24: the final frontier";
|
||||||
|
pub const PHUSTR_25: &'static str = "level 25: the temple of darkness";
|
||||||
|
pub const PHUSTR_26: &'static str = "level 26: bunker";
|
||||||
|
pub const PHUSTR_27: &'static str = "level 27: anti-christ";
|
||||||
|
pub const PHUSTR_28: &'static str = "level 28: the sewers";
|
||||||
|
pub const PHUSTR_29: &'static str = "level 29: odyssey of noises";
|
||||||
|
pub const PHUSTR_30: &'static str = "level 30: the gateway of hell";
|
||||||
|
|
||||||
|
pub const PHUSTR_31: &'static str = "level 31: cyberden";
|
||||||
|
pub const PHUSTR_32: &'static str = "level 32: go 2 it";
|
||||||
|
|
||||||
|
pub const THUSTR_1: &'static str = "level 1: system control";
|
||||||
|
pub const THUSTR_2: &'static str = "level 2: human bbq";
|
||||||
|
pub const THUSTR_3: &'static str = "level 3: power control";
|
||||||
|
pub const THUSTR_4: &'static str = "level 4: wormhole";
|
||||||
|
pub const THUSTR_5: &'static str = "level 5: hanger";
|
||||||
|
pub const THUSTR_6: &'static str = "level 6: open season";
|
||||||
|
pub const THUSTR_7: &'static str = "level 7: prison";
|
||||||
|
pub const THUSTR_8: &'static str = "level 8: metal";
|
||||||
|
pub const THUSTR_9: &'static str = "level 9: stronghold";
|
||||||
|
pub const THUSTR_10: &'static str = "level 10: redemption";
|
||||||
|
pub const THUSTR_11: &'static str = "level 11: storage facility";
|
||||||
|
|
||||||
|
pub const THUSTR_12: &'static str = "level 12: crater";
|
||||||
|
pub const THUSTR_13: &'static str = "level 13: nukage processing";
|
||||||
|
pub const THUSTR_14: &'static str = "level 14: steel works";
|
||||||
|
pub const THUSTR_15: &'static str = "level 15: dead zone";
|
||||||
|
pub const THUSTR_16: &'static str = "level 16: deepest reaches";
|
||||||
|
pub const THUSTR_17: &'static str = "level 17: processing area";
|
||||||
|
pub const THUSTR_18: &'static str = "level 18: mill";
|
||||||
|
pub const THUSTR_19: &'static str = "level 19: shipping/respawning";
|
||||||
|
pub const THUSTR_20: &'static str = "level 20: central processing";
|
||||||
|
|
||||||
|
pub const THUSTR_21: &'static str = "level 21: administration center";
|
||||||
|
pub const THUSTR_22: &'static str = "level 22: habitat";
|
||||||
|
pub const THUSTR_23: &'static str = "level 23: lunar mining project";
|
||||||
|
pub const THUSTR_24: &'static str = "level 24: quarry";
|
||||||
|
pub const THUSTR_25: &'static str = "level 25: baron's den";
|
||||||
|
pub const THUSTR_26: &'static str = "level 26: ballistyx";
|
||||||
|
pub const THUSTR_27: &'static str = "level 27: mount pain";
|
||||||
|
pub const THUSTR_28: &'static str = "level 28: heck";
|
||||||
|
pub const THUSTR_29: &'static str = "level 29: river styx";
|
||||||
|
pub const THUSTR_30: &'static str = "level 30: last call";
|
||||||
|
|
||||||
|
pub const THUSTR_31: &'static str ="level 31: pharaoh";
|
||||||
|
pub const THUSTR_32: &'static str ="level 32: caribbean";
|
||||||
|
|
||||||
|
pub const HUSTR_CHATMACRO1: &'static str = "I'm ready to kick butt!";
|
||||||
|
pub const HUSTR_CHATMACRO2: &'static str = "I'm OK.";
|
||||||
|
pub const HUSTR_CHATMACRO3: &'static str = "I'm not looking too good!";
|
||||||
|
pub const HUSTR_CHATMACRO4: &'static str = "Help!";
|
||||||
|
pub const HUSTR_CHATMACRO5: &'static str = "You suck!";
|
||||||
|
pub const HUSTR_CHATMACRO6: &'static str = "Next time, scumbag...";
|
||||||
|
pub const HUSTR_CHATMACRO7: &'static str = "Come here!";
|
||||||
|
pub const HUSTR_CHATMACRO8: &'static str = "I'll take care of it.";
|
||||||
|
pub const HUSTR_CHATMACRO9: &'static str = "Yes";
|
||||||
|
pub const HUSTR_CHATMACRO0: &'static str = "No";
|
||||||
|
|
||||||
|
pub const HUSTR_TALKTOSELF1: &'static str = "You mumble to yourself";
|
||||||
|
pub const HUSTR_TALKTOSELF2: &'static str = "Who's there?";
|
||||||
|
pub const HUSTR_TALKTOSELF3: &'static str = "You scare yourself";
|
||||||
|
pub const HUSTR_TALKTOSELF4: &'static str = "You start to rave";
|
||||||
|
pub const HUSTR_TALKTOSELF5: &'static str = "You've lost it...";
|
||||||
|
|
||||||
|
pub const HUSTR_MESSAGESENT: &'static str = "[Message Sent]";
|
||||||
|
|
||||||
|
// The following should NOT be changed unless it seems
|
||||||
|
// just AWFULLY necessary
|
||||||
|
|
||||||
|
pub const HUSTR_PLRGREEN: &'static str = "Green: ";
|
||||||
|
pub const HUSTR_PLRINDIGO: &'static str = "Indigo: ";
|
||||||
|
pub const HUSTR_PLRBROWN: &'static str = "Brown: ";
|
||||||
|
pub const HUSTR_PLRRED: &'static str = "Red: ";
|
||||||
|
|
||||||
|
pub const HUSTR_KEYGREEN: &'static str = "g";
|
||||||
|
pub const HUSTR_KEYINDIGO: &'static str = "i";
|
||||||
|
pub const HUSTR_KEYBROWN: &'static str = "b";
|
||||||
|
pub const HUSTR_KEYRED: &'static str = "r";
|
||||||
|
|
||||||
|
//
|
||||||
|
// AM_map.C
|
||||||
|
//
|
||||||
|
|
||||||
|
pub const AMSTR_FOLLOWON: &'static str = "Follow Mode ON";
|
||||||
|
pub const AMSTR_FOLLOWOFF: &'static str = "Follow Mode OFF";
|
||||||
|
|
||||||
|
pub const AMSTR_GRIDON: &'static str = "Grid ON";
|
||||||
|
pub const AMSTR_GRIDOFF: &'static str = "Grid OFF";
|
||||||
|
|
||||||
|
pub const AMSTR_MARKEDSPOT: &'static str = "Marked Spot";
|
||||||
|
pub const AMSTR_MARKSCLEARED: &'static str = "All Marks Cleared";
|
||||||
|
|
||||||
|
//
|
||||||
|
// ST_stuff.C
|
||||||
|
//
|
||||||
|
|
||||||
|
pub const STSTR_MUS: &'static str = "Music Change";
|
||||||
|
pub const STSTR_NOMUS: &'static str = "IMPOSSIBLE SELECTION";
|
||||||
|
pub const STSTR_DQDON: &'static str = "Degreelessness Mode On";
|
||||||
|
pub const STSTR_DQDOFF: &'static str = "Degreelessness Mode Off";
|
||||||
|
|
||||||
|
pub const STSTR_KFAADDED: &'static str = "Very Happy Ammo Added";
|
||||||
|
pub const STSTR_FAADDED: &'static str = "Ammo (no keys) Added";
|
||||||
|
|
||||||
|
pub const STSTR_NCON: &'static str = "No Clipping Mode ON";
|
||||||
|
pub const STSTR_NCOFF: &'static str = "No Clipping Mode OFF";
|
||||||
|
|
||||||
|
pub const STSTR_BEHOLD: &'static str = "inVuln, Str, Inviso, Rad, Allmap, or Lite-amp";
|
||||||
|
pub const STSTR_BEHOLDX: &'static str = "Power-up Toggled";
|
||||||
|
|
||||||
|
pub const STSTR_CHOPPERS: &'static str = "... doesn't suck - GM";
|
||||||
|
pub const STSTR_CLEV: &'static str = "Changing Level...";
|
||||||
|
|
||||||
|
//
|
||||||
|
// F_Finale.C
|
||||||
|
//
|
||||||
|
pub const E1TEXT: &'static str = concat!("Once you beat the big badasses and\n",
|
||||||
|
"clean out the moon base you're supposed\n",
|
||||||
|
"to win, aren't you? Aren't you? Where's\n",
|
||||||
|
"your fat reward and ticket home? What\n",
|
||||||
|
"the hell is this? It's not supposed to\n",
|
||||||
|
"end this way!\n",
|
||||||
|
"\n" ,
|
||||||
|
"It stinks like rotten meat, but looks\n",
|
||||||
|
"like the lost Deimos base. Looks like\n",
|
||||||
|
"you're stuck on The Shores of Hell.\n",
|
||||||
|
"The only way out is through.\n",
|
||||||
|
"\n",
|
||||||
|
"To continue the DOOM experience, play\n",
|
||||||
|
"The Shores of Hell and its amazing\n",
|
||||||
|
"sequel, Inferno!\n");
|
||||||
|
|
||||||
|
|
||||||
|
pub const E2TEXT: &'static str = concat!("You've done it! The hideous cyber-\n",
|
||||||
|
"demon lord that ruled the lost Deimos\n",
|
||||||
|
"moon base has been slain and you\n",
|
||||||
|
"are triumphant! But ... where are\n",
|
||||||
|
"you? You clamber to the edge of the\n",
|
||||||
|
"moon and look down to see the awful\n",
|
||||||
|
"truth.\n" ,
|
||||||
|
"\n",
|
||||||
|
"Deimos floats above Hell itself!\n",
|
||||||
|
"You've never heard of anyone escaping\n",
|
||||||
|
"from Hell, but you'll make the bastards\n",
|
||||||
|
"sorry they ever heard of you! Quickly,\n",
|
||||||
|
"you rappel down to the surface of\n",
|
||||||
|
"Hell.\n",
|
||||||
|
"\n" ,
|
||||||
|
"Now, it's on to the final chapter of\n",
|
||||||
|
"DOOM! -- Inferno.");
|
||||||
|
|
||||||
|
|
||||||
|
pub const E3TEXT: &'static str = concat!("The loathsome spiderdemon that\n",
|
||||||
|
"masterminded the invasion of the moon\n",
|
||||||
|
"bases and caused so much death has had\n",
|
||||||
|
"its ass kicked for all time.\n",
|
||||||
|
"\n",
|
||||||
|
"A hidden doorway opens and you enter.\n",
|
||||||
|
"You've proven too tough for Hell to\n",
|
||||||
|
"contain, and now Hell at last plays\n",
|
||||||
|
"fair -- for you emerge from the door\n",
|
||||||
|
"to see the green fields of Earth!\n",
|
||||||
|
"Home at last.\n" ,
|
||||||
|
"\n",
|
||||||
|
"You wonder what's been happening on\n",
|
||||||
|
"Earth while you were battling evil\n",
|
||||||
|
"unleashed. It's good that no Hell-\n",
|
||||||
|
"spawn could have come through that\n",
|
||||||
|
"door with you ...");
|
||||||
|
|
||||||
|
|
||||||
|
pub const E4TEXT: &'static str = concat!("the spider mastermind must have sent forth\n",
|
||||||
|
"its legions of hellspawn before your\n",
|
||||||
|
"final confrontation with that terrible\n",
|
||||||
|
"beast from hell. but you stepped forward\n",
|
||||||
|
"and brought forth eternal damnation and\n",
|
||||||
|
"suffering upon the horde as a true hero\n",
|
||||||
|
"would in the face of something so evil.\n",
|
||||||
|
"\n",
|
||||||
|
"besides, someone was gonna pay for what\n",
|
||||||
|
"happened to daisy, your pet rabbit.\n",
|
||||||
|
"\n",
|
||||||
|
"but now, you see spread before you more\n",
|
||||||
|
"potential pain and gibbitude as a nation\n",
|
||||||
|
"of demons run amok among our cities.\n",
|
||||||
|
"\n",
|
||||||
|
"next stop, hell on earth!");
|
||||||
|
|
||||||
|
|
||||||
|
// after level 6, put this:
|
||||||
|
|
||||||
|
pub const C1TEXT: &'static str = concat!("YOU HAVE ENTERED DEEPLY INTO THE INFESTED\n",
|
||||||
|
"STARPORT. BUT SOMETHING IS WRONG. THE\n",
|
||||||
|
"MONSTERS HAVE BROUGHT THEIR OWN REALITY\n",
|
||||||
|
"WITH THEM, AND THE STARPORT'S TECHNOLOGY\n",
|
||||||
|
"IS BEING SUBVERTED BY THEIR PRESENCE.\n",
|
||||||
|
"\n",
|
||||||
|
"AHEAD, YOU SEE AN OUTPOST OF HELL, A\n",
|
||||||
|
"FORTIFIED ZONE. IF YOU CAN GET PAST IT,\n",
|
||||||
|
"YOU CAN PENETRATE INTO THE HAUNTED HEART\n",
|
||||||
|
"OF THE STARBASE AND FIND THE CONTROLLING\n",
|
||||||
|
"SWITCH WHICH HOLDS EARTH'S POPULATION\n",
|
||||||
|
"HOSTAGE.");
|
||||||
|
|
||||||
|
// After level 11, put this:
|
||||||
|
|
||||||
|
pub const C2TEXT: &'static str = concat!("YOU HAVE WON! YOUR VICTORY HAS ENABLED\n",
|
||||||
|
"HUMANKIND TO EVACUATE EARTH AND ESCAPE\n",
|
||||||
|
"THE NIGHTMARE. NOW YOU ARE THE ONLY\n",
|
||||||
|
"HUMAN LEFT ON THE FACE OF THE PLANET.\n",
|
||||||
|
"CANNIBAL MUTATIONS, CARNIVOROUS ALIENS,\n",
|
||||||
|
"AND EVIL SPIRITS ARE YOUR ONLY NEIGHBORS.\n",
|
||||||
|
"YOU SIT BACK AND WAIT FOR DEATH, CONTENT\n",
|
||||||
|
"THAT YOU HAVE SAVED YOUR SPECIES.\n",
|
||||||
|
"\n",
|
||||||
|
"BUT THEN, EARTH CONTROL BEAMS DOWN A\n",
|
||||||
|
"MESSAGE FROM SPACE: \"SENSORS HAVE LOCATED\n",
|
||||||
|
"THE SOURCE OF THE ALIEN INVASION. IF YOU\n",
|
||||||
|
"GO THERE, YOU MAY BE ABLE TO BLOCK THEIR\n",
|
||||||
|
"ENTRY. THE ALIEN BASE IS IN THE HEART OF\n",
|
||||||
|
"YOUR OWN HOME CITY, NOT FAR FROM THE\n",
|
||||||
|
"STARPORT.\" SLOWLY AND PAINFULLY YOU GET\n",
|
||||||
|
"UP AND RETURN TO THE FRAY.");
|
||||||
|
|
||||||
|
|
||||||
|
// After level 20, put this:
|
||||||
|
|
||||||
|
pub const C3TEXT: &'static str = concat!("YOU ARE AT THE CORRUPT HEART OF THE CITY,\n",
|
||||||
|
"SURROUNDED BY THE CORPSES OF YOUR ENEMIES.\n",
|
||||||
|
"YOU SEE NO WAY TO DESTROY THE CREATURES'\n",
|
||||||
|
"ENTRYWAY ON THIS SIDE, SO YOU CLENCH YOUR\n",
|
||||||
|
"TEETH AND PLUNGE THROUGH IT.\n",
|
||||||
|
"\n",
|
||||||
|
"THERE MUST BE A WAY TO CLOSE IT ON THE\n",
|
||||||
|
"OTHER SIDE. WHAT DO YOU CARE IF YOU'VE\n",
|
||||||
|
"GOT TO GO THROUGH HELL TO GET TO IT?");
|
||||||
|
|
||||||
|
|
||||||
|
// After level 29, put this:
|
||||||
|
|
||||||
|
pub const C4TEXT: &'static str = concat!("THE HORRENDOUS VISAGE OF THE BIGGEST\n",
|
||||||
|
"DEMON YOU'VE EVER SEEN CRUMBLES BEFORE\n",
|
||||||
|
"YOU, AFTER YOU PUMP YOUR ROCKETS INTO\n",
|
||||||
|
"HIS EXPOSED BRAIN. THE MONSTER SHRIVELS\n",
|
||||||
|
"UP AND DIES, ITS THRASHING LIMBS\n",
|
||||||
|
"DEVASTATING UNTOLD MILES OF HELL'S\n",
|
||||||
|
"SURFACE.\n",
|
||||||
|
"\n",
|
||||||
|
"YOU'VE DONE IT. THE INVASION IS OVER.\n",
|
||||||
|
"EARTH IS SAVED. HELL IS A WRECK. YOU\n",
|
||||||
|
"WONDER WHERE BAD FOLKS WILL GO WHEN THEY\n",
|
||||||
|
"DIE, NOW. WIPING THE SWEAT FROM YOUR\n",
|
||||||
|
"FOREHEAD YOU BEGIN THE LONG TREK BACK\n",
|
||||||
|
"HOME. REBUILDING EARTH OUGHT TO BE A\n",
|
||||||
|
"LOT MORE FUN THAN RUINING IT WAS.\n");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Before level 31, put this:
|
||||||
|
|
||||||
|
pub const C5TEXT: &'static str = concat!("CONGRATULATIONS, YOU'VE FOUND THE SECRET\n",
|
||||||
|
"LEVEL! LOOKS LIKE IT'S BEEN BUILT BY\n",
|
||||||
|
"HUMANS, RATHER THAN DEMONS. YOU WONDER\n",
|
||||||
|
"WHO THE INMATES OF THIS CORNER OF HELL\n",
|
||||||
|
"WILL BE.");
|
||||||
|
|
||||||
|
|
||||||
|
// Before level 32, put this:
|
||||||
|
|
||||||
|
pub const C6TEXT: &'static str = concat!("CONGRATULATIONS, YOU'VE FOUND THE\n",
|
||||||
|
"SUPER SECRET LEVEL! YOU'D BETTER\n",
|
||||||
|
"BLAZE THROUGH THIS ONE!\n");
|
||||||
|
|
||||||
|
|
||||||
|
// after map 06
|
||||||
|
|
||||||
|
pub const P1TEXT: &'static str = concat!("You gloat over the steaming carcass of the\n",
|
||||||
|
"Guardian. With its death, you've wrested\n",
|
||||||
|
"the Accelerator from the stinking claws\n",
|
||||||
|
"of Hell. You relax and glance around the\n",
|
||||||
|
"room. Damn! There was supposed to be at\n",
|
||||||
|
"least one working prototype, but you can't\n",
|
||||||
|
"see it. The demons must have taken it.\n",
|
||||||
|
"\n",
|
||||||
|
"You must find the prototype, or all your\n",
|
||||||
|
"struggles will have been wasted. Keep\n",
|
||||||
|
"moving, keep fighting, keep killing.\n",
|
||||||
|
"Oh yes, keep living, too.");
|
||||||
|
|
||||||
|
|
||||||
|
// after map 11
|
||||||
|
|
||||||
|
pub const P2TEXT: &'static str = concat!("Even the deadly Arch-Vile labyrinth could\n",
|
||||||
|
"not stop you, and you've gotten to the\n",
|
||||||
|
"prototype Accelerator which is soon\n",
|
||||||
|
"efficiently and permanently deactivated.\n",
|
||||||
|
"\n",
|
||||||
|
"You're good at that kind of thing.");
|
||||||
|
|
||||||
|
|
||||||
|
// after map 20
|
||||||
|
|
||||||
|
pub const P3TEXT: &'static str = concat!("You've bashed and battered your way into\n",
|
||||||
|
"the heart of the devil-hive. Time for a\n",
|
||||||
|
"Search-and-Destroy mission, aimed at the\n",
|
||||||
|
"Gatekeeper, whose foul offspring is\n",
|
||||||
|
"cascading to Earth. Yeah, he's bad. But\n",
|
||||||
|
"you know who's worse!\n",
|
||||||
|
"\n",
|
||||||
|
"Grinning evilly, you check your gear, and\n",
|
||||||
|
"get ready to give the bastard a little Hell\n",
|
||||||
|
"of your own making!");
|
||||||
|
|
||||||
|
// after map 30
|
||||||
|
|
||||||
|
pub const P4TEXT: &'static str = concat!("The Gatekeeper's evil face is splattered\n",
|
||||||
|
"all over the place. As its tattered corpse\n",
|
||||||
|
"collapses, an inverted Gate forms and\n",
|
||||||
|
"sucks down the shards of the last\n",
|
||||||
|
"prototype Accelerator, not to mention the\n",
|
||||||
|
"few remaining demons. You're done. Hell\n",
|
||||||
|
"has gone back to pounding bad dead folks \n",
|
||||||
|
"instead of good live ones. Remember to\n",
|
||||||
|
"tell your grandkids to put a rocket\n",
|
||||||
|
"launcher in your coffin. If you go to Hell\n",
|
||||||
|
"when you die, you'll need it for some\n",
|
||||||
|
"final cleaning-up ...");
|
||||||
|
|
||||||
|
// before map 31
|
||||||
|
|
||||||
|
pub const P5TEXT: &'static str = concat!("You've found the second-hardest level we\n",
|
||||||
|
"got. Hope you have a saved game a level or\n",
|
||||||
|
"two previous. If not, be prepared to die\n",
|
||||||
|
"aplenty. For master marines only.");
|
||||||
|
|
||||||
|
// before map 32
|
||||||
|
|
||||||
|
pub const P6TEXT: &'static str = concat!("Betcha wondered just what WAS the hardest\n",
|
||||||
|
"level we had ready for ya? Now you know.\n",
|
||||||
|
"No one gets out alive.");
|
||||||
|
|
||||||
|
|
||||||
|
pub const T1TEXT: &'static str = concat!("You've fought your way out of the infested\n",
|
||||||
|
"experimental labs. It seems that UAC has\n",
|
||||||
|
"once again gulped it down. With their\n",
|
||||||
|
"high turnover, it must be hard for poor\n",
|
||||||
|
"old UAC to buy corporate health insurance\n",
|
||||||
|
"nowadays..\n",
|
||||||
|
"\n",
|
||||||
|
"Ahead lies the military complex, now\n",
|
||||||
|
"swarming with diseased horrors hot to get\n",
|
||||||
|
"their teeth into you. With luck, the\n",
|
||||||
|
"complex still has some warlike ordnance\n",
|
||||||
|
"laying around.");
|
||||||
|
|
||||||
|
|
||||||
|
pub const T2TEXT: &'static str = concat!("You hear the grinding of heavy machinery\n",
|
||||||
|
"ahead. You sure hope they're not stamping\n",
|
||||||
|
"out new hellspawn, but you're ready to\n",
|
||||||
|
"ream out a whole herd if you have to.\n",
|
||||||
|
"They might be planning a blood feast, but\n",
|
||||||
|
"you feel about as mean as two thousand\n",
|
||||||
|
"maniacs packed into one mad killer.\n",
|
||||||
|
"\n",
|
||||||
|
"You don't plan to go down easy.");
|
||||||
|
|
||||||
|
|
||||||
|
pub const T3TEXT: &'static str = concat!("The vista opening ahead looks real damn\n",
|
||||||
|
"familiar. Smells familiar, too -- like\n",
|
||||||
|
"fried excrement. You didn't like this\n",
|
||||||
|
"place before, and you sure as hell ain't\n",
|
||||||
|
"planning to like it now. The more you\n",
|
||||||
|
"brood on it, the madder you get.\n",
|
||||||
|
"Hefting your gun, an evil grin trickles\n",
|
||||||
|
"onto your face. Time to take some names.");
|
||||||
|
|
||||||
|
pub const T4TEXT: &'static str = concat!("Suddenly, all is silent, from one horizon\n",
|
||||||
|
"to the other. The agonizing echo of Hell\n",
|
||||||
|
"fades away, the nightmare sky turns to\n",
|
||||||
|
"blue, the heaps of monster corpses start \n",
|
||||||
|
"to evaporate along with the evil stench \n",
|
||||||
|
"that filled the air. Jeeze, maybe you've\n",
|
||||||
|
"done it. Have you really won?\n",
|
||||||
|
"\n",
|
||||||
|
"Something rumbles in the distance.\n",
|
||||||
|
"A blue light begins to glow inside the\n",
|
||||||
|
"ruined skull of the demon-spitter.");
|
||||||
|
|
||||||
|
|
||||||
|
pub const T5TEXT: &'static str = concat!("What now? Looks totally different. Kind\n",
|
||||||
|
"of like King Tut's condo. Well,\n",
|
||||||
|
"whatever's here can't be any worse\n",
|
||||||
|
"than usual. Can it? Or maybe it's best\n",
|
||||||
|
"to let sleeping gods lie..");
|
||||||
|
|
||||||
|
|
||||||
|
pub const T6TEXT: &'static str = concat!("Time for a vacation. You've burst the\n",
|
||||||
|
"bowels of hell and by golly you're ready\n",
|
||||||
|
"for a break. You mutter to yourself,\n",
|
||||||
|
"Maybe someone else can kick Hell's ass\n",
|
||||||
|
"next time around. Ahead lies a quiet town,\n",
|
||||||
|
"with peaceful flowing water, quaint\n",
|
||||||
|
"buildings, and presumably no Hellspawn.\n",
|
||||||
|
"\n",
|
||||||
|
"As you step off the transport, you hear\n",
|
||||||
|
"the stomp of a cyberdemon's iron shoe.");
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Character cast strings F_FINALE.C
|
||||||
|
//
|
||||||
|
pub const CC_ZOMBIE: &'static str = "ZOMBIEMAN";
|
||||||
|
pub const CC_SHOTGUN: &'static str = "SHOTGUN GUY";
|
||||||
|
pub const CC_HEAVY: &'static str = "HEAVY WEAPON DUDE";
|
||||||
|
pub const CC_IMP: &'static str = "IMP";
|
||||||
|
pub const CC_DEMON: &'static str = "DEMON";
|
||||||
|
pub const CC_LOST: &'static str = "LOST SOUL";
|
||||||
|
pub const CC_CACO: &'static str = "CACODEMON";
|
||||||
|
pub const CC_HELL: &'static str = "HELL KNIGHT";
|
||||||
|
pub const CC_BARON: &'static str = "BARON OF HELL";
|
||||||
|
pub const CC_ARACH: &'static str = "ARACHNOTRON";
|
||||||
|
pub const CC_PAIN: &'static str = "PAIN ELEMENTAL";
|
||||||
|
pub const CC_REVEN: &'static str = "REVENANT";
|
||||||
|
pub const CC_MANCU: &'static str = "MANCUBUS";
|
||||||
|
pub const CC_ARCH: &'static str = "ARCH-VILE";
|
||||||
|
pub const CC_SPIDER: &'static str = "THE SPIDER MASTERMIND";
|
||||||
|
pub const CC_CYBER: &'static str = "THE CYBERDEMON";
|
||||||
|
pub const CC_HERO: &'static str = "OUR HERO";
|
||||||
3
src/d_strings/french/mod.rs
Normal file
3
src/d_strings/french/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
/// French Language string constants
|
||||||
|
///
|
||||||
|
/// NOT IMPLEMENTED "C'est injuste envers les Français !"
|
||||||
20
src/d_strings/mod.rs
Normal file
20
src/d_strings/mod.rs
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
#[cfg(feature = "french")]
|
||||||
|
mod d_french;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "french"))]
|
||||||
|
mod d_english;
|
||||||
|
|
||||||
|
#[cfg(feature = "french")]
|
||||||
|
pub use d_french::*;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "french"))]
|
||||||
|
pub use d_english::*;
|
||||||
|
|
||||||
|
pub const SAVEGAMENAME: &'static str = "doomsav";
|
||||||
|
|
||||||
|
pub const DEVMPAS: &'static str = "devmaps";
|
||||||
|
|
||||||
|
pub const DEVDATA: &'static str = "devdata";
|
||||||
|
|
||||||
|
pub const NUM_QUITMESSAGES: i32 = 22;
|
||||||
|
|
||||||
176
src/doomdef/mod.rs
Normal file
176
src/doomdef/mod.rs
Normal file
@@ -0,0 +1,176 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
|
|
||||||
|
/// DOOM version
|
||||||
|
pub const VERSION:i32 = 110;
|
||||||
|
|
||||||
|
/// BASE_WIDTH
|
||||||
|
/// For resize of screen, at start of game.
|
||||||
|
/// It will not work dynamically, see visplanes. TODO: Investigate what this means.
|
||||||
|
pub const BASE_WIDTH: i32 = 320;
|
||||||
|
|
||||||
|
/// Screen scale multiplier?
|
||||||
|
/// Original source comment:
|
||||||
|
/// It is educational but futile to change this
|
||||||
|
/// scaling e.g. to 2. Drawing of status bar,
|
||||||
|
/// menues etc. is tied to the scale implied
|
||||||
|
/// by the graphics.
|
||||||
|
pub const SCREEN_MUL: i32 = 1;
|
||||||
|
|
||||||
|
/// Inverse of the aspect ratio
|
||||||
|
pub const INV_ASPECT_RATIO: f32 = 0.625; // 0.75, ideally according to the original source
|
||||||
|
|
||||||
|
/// SCREENWIDTH
|
||||||
|
/// = SCREEN_MUL*BASE_WIDTH //320
|
||||||
|
pub const SCREENWIDTH: i32 = 320;
|
||||||
|
|
||||||
|
/// SCREENHEIGHT
|
||||||
|
/// (int)(SCREEN_MUL*BASE_WIDTH*INV_ASPECT_RATIO) //200
|
||||||
|
pub const SCREENHEIGHT:i32 = 200;
|
||||||
|
|
||||||
|
|
||||||
|
/// The maximum number of players, multiplayer/networking.
|
||||||
|
pub const MAXPLAYERS: i32 = 4;
|
||||||
|
|
||||||
|
/// The number of state updates (ticks) to be done per second
|
||||||
|
pub const TICRATE: i32 = 35;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum GameMode {
|
||||||
|
Shareware,
|
||||||
|
Registered,
|
||||||
|
Retail,
|
||||||
|
Commercial,
|
||||||
|
Indetermined
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
pub enum GameState {
|
||||||
|
Level,
|
||||||
|
Intermission,
|
||||||
|
Finale,
|
||||||
|
Demoscreen,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||||
|
#[repr(i32)]
|
||||||
|
#[allow(non_camel_case_types)]
|
||||||
|
pub enum Skill {
|
||||||
|
sk_baby = 0,
|
||||||
|
sk_easy = 1,
|
||||||
|
sk_medium = 2,
|
||||||
|
sk_hard = 3,
|
||||||
|
sk_nightmare = 4
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DoomGlobalState {
|
||||||
|
pub devparm: bool,
|
||||||
|
pub nomonsters: bool,
|
||||||
|
pub respawnparm: bool,
|
||||||
|
pub fastparm: bool,
|
||||||
|
pub drone: bool,
|
||||||
|
pub singletics: bool,
|
||||||
|
pub advancedemo: bool,
|
||||||
|
pub automapactive: bool,
|
||||||
|
pub scaledviewwidth: usize,
|
||||||
|
pub viewheight: usize,
|
||||||
|
pub inhelpscreens: bool,
|
||||||
|
pub paused: bool,
|
||||||
|
pub viewactive: bool,
|
||||||
|
pub menuactive: bool,
|
||||||
|
pub gameaction: bool,
|
||||||
|
pub usergame: bool,
|
||||||
|
pub autostart: bool,
|
||||||
|
pub demorecording: bool,
|
||||||
|
pub modifiedgame: bool,
|
||||||
|
pub deathmatch: u32,
|
||||||
|
pub language: u32,
|
||||||
|
pub singledemo: bool,
|
||||||
|
pub consoleplayer: u32,
|
||||||
|
pub maketic: u32,
|
||||||
|
|
||||||
|
// Buffers
|
||||||
|
pub wadfile: [u8; 1024],
|
||||||
|
pub mapdir: [u8; 1024],
|
||||||
|
pub basedefault: [u8; 1024],
|
||||||
|
pub title: [u8; 128],
|
||||||
|
|
||||||
|
// System State
|
||||||
|
pub gamemode: GameMode,
|
||||||
|
pub startskill: i32,
|
||||||
|
pub startepisode: i32,
|
||||||
|
pub startmap: i32,
|
||||||
|
pub wipegamestate: GameState,
|
||||||
|
pub gametic: u32,
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
pub wadfiles: Vec<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for DoomGlobalState {
|
||||||
|
fn default () -> Self {
|
||||||
|
Self {
|
||||||
|
devparm: false,
|
||||||
|
nomonsters: false,
|
||||||
|
respawnparm: false,
|
||||||
|
fastparm: false,
|
||||||
|
drone: false,
|
||||||
|
singletics: false,
|
||||||
|
advancedemo: false,
|
||||||
|
automapactive: false,
|
||||||
|
scaledviewwidth: 0,
|
||||||
|
viewheight: 0,
|
||||||
|
inhelpscreens: false,
|
||||||
|
paused: false,
|
||||||
|
viewactive: true,
|
||||||
|
menuactive: false,
|
||||||
|
gameaction: false, // ga_nothing
|
||||||
|
usergame: true,
|
||||||
|
autostart: false,
|
||||||
|
demorecording: false,
|
||||||
|
modifiedgame: false,
|
||||||
|
deathmatch: 0,
|
||||||
|
language: 0, // english
|
||||||
|
singledemo: false,
|
||||||
|
consoleplayer: 0,
|
||||||
|
maketic: 0,
|
||||||
|
wadfile: [0; 1024],
|
||||||
|
mapdir: [0; 1024],
|
||||||
|
basedefault: [0; 1024],
|
||||||
|
title: [0; 128],
|
||||||
|
gamemode: GameMode::Indetermined,
|
||||||
|
startskill: Skill::sk_medium as i32,
|
||||||
|
startepisode: 1,
|
||||||
|
startmap: 1,
|
||||||
|
wipegamestate: GameState::Demoscreen,
|
||||||
|
gametic: 0,
|
||||||
|
wadfiles: Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
// We promise not to be naughty and access this from another thread :)
|
||||||
|
static GLOBALS: RefCell<DoomGlobalState> = RefCell::new(DoomGlobalState::default());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct DOOMGLOBALS;
|
||||||
|
|
||||||
|
impl DOOMGLOBALS {
|
||||||
|
/// Provides mutable access to the globals
|
||||||
|
pub fn with_mut<F, R>(f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut DoomGlobalState) -> R
|
||||||
|
{
|
||||||
|
GLOBALS.with(|g| f(&mut g.borrow_mut()))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Provides reference only access to the globals
|
||||||
|
pub fn with_ref<F, R>(f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&DoomGlobalState) -> R
|
||||||
|
{
|
||||||
|
GLOBALS.with(|g| f(&g.borrow()))
|
||||||
|
}
|
||||||
|
}
|
||||||
10
src/doomtype/mod.rs
Normal file
10
src/doomtype/mod.rs
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
const MAXCHAR: i8 = i8::MAX;
|
||||||
|
const MAXSHORT: i16 = i16::MAX;
|
||||||
|
const MAXINT: i32 = i32::MAX;
|
||||||
|
const MAXLONG: i32 = i32::MAX;
|
||||||
|
|
||||||
|
// Minimum values
|
||||||
|
const MINCHAR: i8 = i8::MIN;
|
||||||
|
const MINSHORT: i16 = i16::MIN;
|
||||||
|
const MININT: i32 = i32::MIN;
|
||||||
|
const MINLONG: i32 = i32::MIN;
|
||||||
99
src/hu_stuff/mod.rs
Normal file
99
src/hu_stuff/mod.rs
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
/// Heads up display stuff
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
use crate::doomdef::TICRATE;
|
||||||
|
use crate::d_strings;
|
||||||
|
|
||||||
|
/// The first font characters
|
||||||
|
pub const HU_FONTSTART: char = '!';
|
||||||
|
|
||||||
|
/// The last font characters
|
||||||
|
pub const HU_FONTEND: char = '_';
|
||||||
|
|
||||||
|
/// Number of glyphs in the font
|
||||||
|
pub const HU_FONTSIZE: u8 = (HU_FONTEND as u8 - HU_FONTSTART as u8) + 1;
|
||||||
|
|
||||||
|
pub const HU_BROADCAST: i32 = 5;
|
||||||
|
|
||||||
|
// pub const HU_MSGREFRESH = KEY_ENTER // Comes from doomdef.h TODO: implement more doomdef!
|
||||||
|
|
||||||
|
pub const HU_MSGX: i32 = 0;
|
||||||
|
|
||||||
|
pub const HU_MSGY: i32 = 0;
|
||||||
|
|
||||||
|
/// The width of a message in characters
|
||||||
|
pub const HU_MSGWIDTH: i32 = 64;
|
||||||
|
|
||||||
|
/// The height of a message in lines
|
||||||
|
pub const HU_MSGHEIGHT: i32 = 1;
|
||||||
|
|
||||||
|
/// The time a message should be displayed for before it disapears
|
||||||
|
pub const HU_MSGTIMEOUT: i32 = 4 * TICRATE;
|
||||||
|
|
||||||
|
|
||||||
|
/// Constant string arrays
|
||||||
|
static CHAT_MACROS_LOCK: OnceLock<[String; 10]> = OnceLock::new();
|
||||||
|
|
||||||
|
pub fn get_chat_macro_ptr(index: usize) -> *mut String {
|
||||||
|
let array_ref = CHAT_MACROS_LOCK.get_or_init(|| [
|
||||||
|
d_strings::HUSTR_CHATMACRO0.to_string(),
|
||||||
|
d_strings::HUSTR_CHATMACRO1.to_string(),
|
||||||
|
d_strings::HUSTR_CHATMACRO2.to_string(),
|
||||||
|
d_strings::HUSTR_CHATMACRO3.to_string(),
|
||||||
|
d_strings::HUSTR_CHATMACRO4.to_string(),
|
||||||
|
d_strings::HUSTR_CHATMACRO5.to_string(),
|
||||||
|
d_strings::HUSTR_CHATMACRO6.to_string(),
|
||||||
|
d_strings::HUSTR_CHATMACRO7.to_string(),
|
||||||
|
d_strings::HUSTR_CHATMACRO8.to_string(),
|
||||||
|
d_strings::HUSTR_CHATMACRO9.to_string(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Cast the immutable reference from the lock to a raw mutable pointer
|
||||||
|
unsafe {
|
||||||
|
let array_ptr = array_ref.as_ptr() as *mut String;
|
||||||
|
array_ptr.add(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// HUD text stuff
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn HU_INIT() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn HU_Start() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
// TODO: Implement d_event.h/c
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn HU_Responder(event_t* ev) {
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn HU_Ticker() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn HU_Ticket() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn HU_dequeueChatChar() /*-> char */ {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn HU_Erase() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
101
src/m_argv.rs
Normal file
101
src/m_argv.rs
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
// Stores argc and argv from the original Doom
|
||||||
|
// M_CheckParm as well as a helper to get a param value (e.g -file MyWad.wad)
|
||||||
|
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
static MYARGC: OnceLock<usize> = OnceLock::new();
|
||||||
|
|
||||||
|
static MYARGV: OnceLock<Vec<String>> = OnceLock::new();
|
||||||
|
|
||||||
|
pub const PARM_NOT_FOUND: i32 = 0;
|
||||||
|
|
||||||
|
pub fn init(args: Vec<String>) {
|
||||||
|
MYARGC.set(args.len()).ok();
|
||||||
|
MYARGV.set(args).ok();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the value of the pass CLI arguments at the position specified by `index`
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_GetPositionalArgv() -> Option<&'static str> {
|
||||||
|
let args = MYARGV.get()?;
|
||||||
|
|
||||||
|
args.iter()
|
||||||
|
.skip(1)
|
||||||
|
.find(|arg| {
|
||||||
|
!arg.starts_with('-')
|
||||||
|
})
|
||||||
|
.map(|s| s.as_str())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the value of a optional argument specified by the argument
|
||||||
|
///
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_GetOptionalArgumentValueByArgument(arg: &str) -> Option<&'static str> {
|
||||||
|
|
||||||
|
let idx: usize = M_CheckParm(arg) as usize;
|
||||||
|
|
||||||
|
if idx == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let argv: &Vec<String> = MYARGV.get()?;
|
||||||
|
let idx_val = idx + 1;
|
||||||
|
if idx_val > argv.len() - 1 {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
Some(argv[idx_val].as_str())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the value of a optional argument specified by the argument
|
||||||
|
///
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_GetOptionalArgumentValueByIndex(index: i32) -> Option<&'static str> {
|
||||||
|
|
||||||
|
let idx = index as usize;
|
||||||
|
if idx == 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let argv: &Vec<String> = MYARGV.get()?;
|
||||||
|
let idx_val = idx + 1;
|
||||||
|
if idx_val > argv.len() - 1 {
|
||||||
|
return None
|
||||||
|
}
|
||||||
|
Some(argv[idx_val].as_str())
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks for the given paramter in the program command line arugments
|
||||||
|
/// Returns the argument number or zero if not present
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_CheckParm(c_str: &str) -> i32 {
|
||||||
|
|
||||||
|
let args = match MYARGV.get() {
|
||||||
|
Some(a) => a,
|
||||||
|
None => return 0, // Not initialized yet
|
||||||
|
};
|
||||||
|
|
||||||
|
for i in 1..args.len() {
|
||||||
|
if args[i] == c_str {
|
||||||
|
return i as i32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PARM_NOT_FOUND
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets all the parameters of myargv
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_GetAll() -> Vec<&'static str> {
|
||||||
|
match MYARGV.get() {
|
||||||
|
Some(args) => args.iter().map(|s| s.as_str()).collect(),
|
||||||
|
None => Vec::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the number of arguments passed to the program
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_GetArgC() -> i32 {
|
||||||
|
*MYARGC.get().unwrap() as i32
|
||||||
|
}
|
||||||
320
src/m_menu/mod.rs
Normal file
320
src/m_menu/mod.rs
Normal file
@@ -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<fn(choice: i32)>,
|
||||||
|
|
||||||
|
// 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<fn()>,
|
||||||
|
|
||||||
|
/// 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() {
|
||||||
|
|
||||||
|
}
|
||||||
367
src/m_misc/mod.rs
Normal file
367
src/m_misc/mod.rs
Normal file
@@ -0,0 +1,367 @@
|
|||||||
|
use std::ptr::addr_of_mut;
|
||||||
|
|
||||||
|
use crate::d_strings;
|
||||||
|
use crate::doomtype;
|
||||||
|
use crate::hu_stuff::get_chat_macro_ptr;
|
||||||
|
use crate::m_argv::{M_CheckParm, M_GetOptionalArgumentValueByArgument, PARM_NOT_FOUND};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// static mut variable stuff
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut mouseSensitivity: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut snd_SfxVolumne: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut snd_MusicVolume: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut showMessages: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut usemouse: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut mousebfire: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut mousebstrafe: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut mousebforward: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut usejoystick: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut joybfire: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut joybstrafe: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut joybuse: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut joybspeed: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut screenblocks: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut detailLevel: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut numChannels: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut usegamma: i32 = 0;
|
||||||
|
|
||||||
|
/// Represents a type-safe pointer to either a numeric or string global variable
|
||||||
|
pub enum DefaultLocation {
|
||||||
|
|
||||||
|
/// Pointer to an integer(i32) value
|
||||||
|
Int(*mut i32),
|
||||||
|
|
||||||
|
/// Pointer to a String value
|
||||||
|
Str(*mut String)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents a type to represent the extacted default fallback value
|
||||||
|
pub enum ConfigValue {
|
||||||
|
|
||||||
|
/// Represents an integer(i32) configuration value
|
||||||
|
Int(i32),
|
||||||
|
|
||||||
|
/// Represents a String configuration value
|
||||||
|
Str(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents the name, location and default value of a configuation variable
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct default_t {
|
||||||
|
|
||||||
|
/// The key used for the configuration value from the corresponding '.cfg' file
|
||||||
|
pub name: &'static str,
|
||||||
|
|
||||||
|
/// The memory location of the global variable to update
|
||||||
|
pub location: DefaultLocation,
|
||||||
|
|
||||||
|
/// The fallback value if the setting is missing from the file
|
||||||
|
pub default_value: ConfigValue
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn get_defaults() -> Vec<default_t> {
|
||||||
|
unsafe {
|
||||||
|
vec![
|
||||||
|
// mouse_sensitivity
|
||||||
|
default_t {
|
||||||
|
name: "mouse_sensitivity",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(mouseSensitivity)),
|
||||||
|
default_value: ConfigValue::Int(5)
|
||||||
|
},
|
||||||
|
// snd_SfxVolumne
|
||||||
|
default_t {
|
||||||
|
name: "sfx_volume",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(snd_SfxVolumne)),
|
||||||
|
default_value: ConfigValue::Int(8)
|
||||||
|
},
|
||||||
|
// snd_MusicVolume
|
||||||
|
default_t {
|
||||||
|
name: "snd_MusicVolumne",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(snd_MusicVolume)),
|
||||||
|
default_value: ConfigValue::Int(8)
|
||||||
|
},
|
||||||
|
// showMessages
|
||||||
|
default_t {
|
||||||
|
name: "show_messages",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(showMessages)),
|
||||||
|
default_value: ConfigValue::Int(1)
|
||||||
|
},
|
||||||
|
// usemouse
|
||||||
|
default_t {
|
||||||
|
name: "use_mouse",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(usemouse)),
|
||||||
|
default_value: ConfigValue::Int(1)
|
||||||
|
},
|
||||||
|
// mousebfire
|
||||||
|
default_t {
|
||||||
|
name: "mouseb_fire",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(mousebfire)),
|
||||||
|
default_value: ConfigValue::Int(0)
|
||||||
|
},
|
||||||
|
// mousebstrafe
|
||||||
|
default_t {
|
||||||
|
name: "mouseb_strafe",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(mousebstrafe)),
|
||||||
|
default_value: ConfigValue::Int(1)
|
||||||
|
},
|
||||||
|
// mousebforward
|
||||||
|
default_t {
|
||||||
|
name: "mouseb_forward",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(mousebforward)),
|
||||||
|
default_value: ConfigValue::Int(2)
|
||||||
|
},
|
||||||
|
// usejoystick
|
||||||
|
default_t {
|
||||||
|
name: "use_joystick",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(usejoystick)),
|
||||||
|
default_value: ConfigValue::Int(0)
|
||||||
|
},
|
||||||
|
// joybfire
|
||||||
|
default_t {
|
||||||
|
name: "joyb_fire",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(joybfire)),
|
||||||
|
default_value: ConfigValue::Int(0)
|
||||||
|
},
|
||||||
|
// joybstrafe
|
||||||
|
default_t {
|
||||||
|
name: "joyb_strafe",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(joybstrafe)),
|
||||||
|
default_value: ConfigValue::Int(1)
|
||||||
|
},
|
||||||
|
// joybuse
|
||||||
|
default_t {
|
||||||
|
name: "joyb_use",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(joybuse)),
|
||||||
|
default_value: ConfigValue::Int(3)
|
||||||
|
},
|
||||||
|
// joybspeed
|
||||||
|
default_t {
|
||||||
|
name: "joyb_speed",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(joybspeed)),
|
||||||
|
default_value: ConfigValue::Int(2)
|
||||||
|
},
|
||||||
|
// screenblocks
|
||||||
|
default_t {
|
||||||
|
name: "screenblocks",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(screenblocks)),
|
||||||
|
default_value: ConfigValue::Int(9)
|
||||||
|
},
|
||||||
|
// detailLevel
|
||||||
|
default_t {
|
||||||
|
name: "detailLevel",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(detailLevel)),
|
||||||
|
default_value: ConfigValue::Int(0)
|
||||||
|
},
|
||||||
|
// numChannels
|
||||||
|
default_t {
|
||||||
|
name: "snd_channels",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(numChannels)),
|
||||||
|
default_value: ConfigValue::Int(3)
|
||||||
|
},
|
||||||
|
// usegamma
|
||||||
|
default_t {
|
||||||
|
name: "usegamma",
|
||||||
|
location: DefaultLocation::Int(addr_of_mut!(usegamma)),
|
||||||
|
default_value: ConfigValue::Int(0)
|
||||||
|
},
|
||||||
|
// chatmacro0
|
||||||
|
default_t {
|
||||||
|
name: "chatmacro0",
|
||||||
|
location: DefaultLocation::Str(get_chat_macro_ptr(0)),
|
||||||
|
default_value: ConfigValue::Str(d_strings::HUSTR_CHATMACRO0.to_string())
|
||||||
|
},
|
||||||
|
// chatmacro1
|
||||||
|
default_t {
|
||||||
|
name: "chatmacro1",
|
||||||
|
location: DefaultLocation::Str(get_chat_macro_ptr(1)),
|
||||||
|
default_value: ConfigValue::Str(d_strings::HUSTR_CHATMACRO1.to_string())
|
||||||
|
},
|
||||||
|
// chatmacro2
|
||||||
|
default_t {
|
||||||
|
name: "chatmacro2",
|
||||||
|
location: DefaultLocation::Str(get_chat_macro_ptr(2)),
|
||||||
|
default_value: ConfigValue::Str(d_strings::HUSTR_CHATMACRO2.to_string())
|
||||||
|
},
|
||||||
|
// chatmacro3
|
||||||
|
default_t {
|
||||||
|
name: "chatmacro3",
|
||||||
|
location: DefaultLocation::Str(get_chat_macro_ptr(3)),
|
||||||
|
default_value: ConfigValue::Str(d_strings::HUSTR_CHATMACRO3.to_string())
|
||||||
|
},
|
||||||
|
// chatmacro4
|
||||||
|
default_t {
|
||||||
|
name: "chatmacro4",
|
||||||
|
location: DefaultLocation::Str(get_chat_macro_ptr(4)),
|
||||||
|
default_value: ConfigValue::Str(d_strings::HUSTR_CHATMACRO4.to_string())
|
||||||
|
},
|
||||||
|
// chatmacro5
|
||||||
|
default_t {
|
||||||
|
name: "chatmacro5",
|
||||||
|
location: DefaultLocation::Str(get_chat_macro_ptr(5)),
|
||||||
|
default_value: ConfigValue::Str(d_strings::HUSTR_CHATMACRO5.to_string())
|
||||||
|
},
|
||||||
|
// chatmacro6
|
||||||
|
default_t {
|
||||||
|
name: "chatmacro6",
|
||||||
|
location: DefaultLocation::Str(get_chat_macro_ptr(6)),
|
||||||
|
default_value: ConfigValue::Str(d_strings::HUSTR_CHATMACRO6.to_string())
|
||||||
|
},
|
||||||
|
// chatmacro7
|
||||||
|
default_t {
|
||||||
|
name: "chatmacro7",
|
||||||
|
location: DefaultLocation::Str(get_chat_macro_ptr(7)),
|
||||||
|
default_value: ConfigValue::Str(d_strings::HUSTR_CHATMACRO7.to_string())
|
||||||
|
},
|
||||||
|
// chatmacro8
|
||||||
|
default_t {
|
||||||
|
name: "chatmacro8",
|
||||||
|
location: DefaultLocation::Str(get_chat_macro_ptr(8)),
|
||||||
|
default_value: ConfigValue::Str(d_strings::HUSTR_CHATMACRO8.to_string())
|
||||||
|
},
|
||||||
|
// chatmacro9
|
||||||
|
default_t {
|
||||||
|
name: "chatmacro9",
|
||||||
|
location: DefaultLocation::Str(get_chat_macro_ptr(9)),
|
||||||
|
default_value: ConfigValue::Str(d_strings::HUSTR_CHATMACRO9.to_string())
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_WriteFile(name: &str, source: std::fs::File, length: i64) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_ReadFile(name: &str, buffer: Vec<u8>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_ScreenShot() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_LoadDefaults() {
|
||||||
|
// Set to defaults
|
||||||
|
let mut defaults = get_defaults();
|
||||||
|
for item in &defaults {
|
||||||
|
unsafe {
|
||||||
|
match &item.location {
|
||||||
|
DefaultLocation::Int(ptr) => {
|
||||||
|
if let ConfigValue::Int(val) = item.default_value {
|
||||||
|
**ptr = val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DefaultLocation::Str(ptr) => {
|
||||||
|
if let ConfigValue::Str(val) = &item.default_value {
|
||||||
|
**ptr = val.clone();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // end iter
|
||||||
|
|
||||||
|
// load custom cfg?
|
||||||
|
let mut cfg_location = "DEFAULT.CFG";
|
||||||
|
let p = M_CheckParm("-config");
|
||||||
|
if p != PARM_NOT_FOUND {
|
||||||
|
cfg_location = M_GetOptionalArgumentValueByArgument("-config").unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// read contents
|
||||||
|
if let Ok(cfg_content) = std::fs::read_to_string(cfg_location) {
|
||||||
|
for line in cfg_content.lines() {
|
||||||
|
let cfg_line = line.trim();
|
||||||
|
if cfg_line.is_empty() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
// split the non-empty cfg line into two
|
||||||
|
if let Some((parsed_cfg_key, parsed_cfg_value)) = cfg_line.split_once(char::is_whitespace) {
|
||||||
|
let key = parsed_cfg_key.trim();
|
||||||
|
let value = parsed_cfg_value.trim();
|
||||||
|
|
||||||
|
if let Some(cfg_item) = defaults.iter_mut().find(|d| d.name == key) {
|
||||||
|
unsafe {
|
||||||
|
match &cfg_item.location {
|
||||||
|
DefaultLocation::Int(ptr) => {
|
||||||
|
if value.starts_with("0x") {
|
||||||
|
if let Ok(num) = i32::from_str_radix(value, 16) {
|
||||||
|
**ptr = num;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
println!("Unable to parse value '{}' as an integer for configuation setting '{}'", value, key);
|
||||||
|
println!("Using defaults");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if let Ok(num) = i32::from_str_radix(value, 10) {
|
||||||
|
**ptr = num;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
println!("Unable to parse value '{}' as an integer for configuation setting '{}'", value, key);
|
||||||
|
println!("Using defaults");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DefaultLocation::Str(ptr) => {
|
||||||
|
let cleaned_str = value.trim_matches('"').to_string();
|
||||||
|
**ptr = cleaned_str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
println!("Unable to read configuation file '{}'", &cfg_location);
|
||||||
|
println!("Using defaults");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_SaveDefaults() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn M_DrawText(x: i32, y: i32, direct: bool, text: &str) {
|
||||||
|
|
||||||
|
}
|
||||||
24
src/main.rs
Normal file
24
src/main.rs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
mod d_main;
|
||||||
|
mod d_strings;
|
||||||
|
mod doomdef;
|
||||||
|
mod doomtype;
|
||||||
|
mod hu_stuff;
|
||||||
|
mod m_argv;
|
||||||
|
mod m_menu;
|
||||||
|
mod m_misc;
|
||||||
|
mod v_video;
|
||||||
|
mod w_wad;
|
||||||
|
mod z_zone;
|
||||||
|
mod math;
|
||||||
|
|
||||||
|
|
||||||
|
/// Main entry pointz
|
||||||
|
///
|
||||||
|
fn main() {
|
||||||
|
|
||||||
|
if let Err(e) = std::panic::catch_unwind(|| {
|
||||||
|
d_main::D_DoomMain();
|
||||||
|
}) {
|
||||||
|
eprintln!("Panic in Doom Main: {:?}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
src/math/m_fixed.rs
Normal file
47
src/math/m_fixed.rs
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
/* Implemnetation of *m_fixed.c/h
|
||||||
|
|
||||||
|
This provides fixed-point arithmetic as 32-bit 16.16
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub const FRACBITS: i32 = 16;
|
||||||
|
pub const FRACUNIT: i32 = 1 << FRACBITS;
|
||||||
|
|
||||||
|
pub const MININT: i32 = 0x80000000;
|
||||||
|
pub const MAXINT: i32 = 0x7fffffff;
|
||||||
|
/// Struct representing a fixed point 32-bit value
|
||||||
|
#[derive(Copy, Clone, PartialEq, Debug)]
|
||||||
|
pub struct FixedPoint {
|
||||||
|
pub value: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FixedPoint {
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn FixedMul(a: FixedPoint, b: FixedPoint) -> FixedPoint {
|
||||||
|
let value = ((a.value as u64) * (b.value as u64) >> FRACBITS) as i32;
|
||||||
|
FixedPoint{value}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn FixedDiv(a: FixedPoint, b: FixedPoint) -> FixedPoint {
|
||||||
|
if (i32::abs(a.value) >> 14) >= i32::abs(b.value) {
|
||||||
|
if a.value^b.value == 0 {
|
||||||
|
FixedPoint{value: MININT};
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FixedPoint{value: MAXINT};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
FixedPoint::FixedDiv2(a,b)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn FixedDiv2(a: FixedPoint, b: FixedPoint) -> FixedPoint {
|
||||||
|
let c: f64 = ((a.value as f64) / (b.value as f64)) * FRACUNIT as f64;
|
||||||
|
if c >= 2147483648.0 || c < -2147483648.0 {
|
||||||
|
panic!("FixedDiv: divide by zero");
|
||||||
|
}
|
||||||
|
FixedPoint { value: c as i32 }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
3
src/math/mod.rs
Normal file
3
src/math/mod.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
// pub mod m_fixed;
|
||||||
|
|
||||||
|
// pub use m_fixed::FixedPoint;
|
||||||
43
src/v_video/mod.rs
Normal file
43
src/v_video/mod.rs
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
use crate::doomdef::{SCREENHEIGHT, SCREENWIDTH};
|
||||||
|
use crate::doomtype;
|
||||||
|
|
||||||
|
pub const CENTERY: i32 = SCREENHEIGHT / 2;
|
||||||
|
|
||||||
|
// static var stuff
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut screens: [[u8; (SCREENWIDTH*SCREENHEIGHT) as usize]; 5] = [[0u8; (SCREENWIDTH*SCREENHEIGHT) as usize]; 5];
|
||||||
|
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn V_Init() {
|
||||||
|
// Do nothing :)
|
||||||
|
// the memory is already allocated
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn V_CopyRect(srcx: i32, srcy: i32, srcscrn: i32, width: i32, height: i32, destx: i32, desty: i32, destscrn: i32) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO: Implement "r_data"
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn V_DrawPatch(x: i32, y: i32, scrn: i32, patch: Vec<patch_t>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn V_DrawPatchDirect(x: i32, y: i32, scrn: i32, patch: Vec<patch_t>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn V_GetBlock(x: i32, y: i32, scrn: i32, width: i32, height: i32, dest: Vec<u8>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn V_MarkRect(x: i32, y: i32, width: i32, height: i32) {
|
||||||
|
|
||||||
|
}
|
||||||
235
src/w_wad/mod.rs
Normal file
235
src/w_wad/mod.rs
Normal file
@@ -0,0 +1,235 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::{Read, Seek, SeekFrom};
|
||||||
|
use std::mem::size_of;
|
||||||
|
use std::os::windows::io::AsRawHandle;
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut numlumps: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut lumpinfo: Vec<lumpinfo_t> = Vec::new();
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut reloadlump: i32 = 0;
|
||||||
|
|
||||||
|
#[allow(non_upper_case_globals)]
|
||||||
|
static mut reloadname: String = String::new();
|
||||||
|
|
||||||
|
/// Struct of the header of a WAD file
|
||||||
|
/// All integers are 4 bytes long in x86-style little-endian order. Their values can never exceed 231-1
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct wadinfo_t {
|
||||||
|
/// ASCII identifer, either IWAD or PWAD
|
||||||
|
pub identification: [u8; 4],
|
||||||
|
|
||||||
|
/// The number of lumps in the WAD
|
||||||
|
pub numlumps: i32,
|
||||||
|
|
||||||
|
/// Pointer to the location of the directory
|
||||||
|
pub infotableofs: i32,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Struct of fileumps of a WAD file
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct filelump_t {
|
||||||
|
|
||||||
|
/// Pointer to the start of the lumps data in the WAD file
|
||||||
|
pub filepos: i32,
|
||||||
|
|
||||||
|
/// The size of the lump in bytes
|
||||||
|
pub size: i32,
|
||||||
|
|
||||||
|
/// ASCII string identifying the lumps name
|
||||||
|
/// must be null terminated if less than 8 characters long
|
||||||
|
/// For safety, padd till end with null chars
|
||||||
|
pub name: [u8; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// TODO: RD-2: fill in if it is even needed for this port??
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct lumpinfo_t {
|
||||||
|
|
||||||
|
pub name: [u8; 8],
|
||||||
|
|
||||||
|
pub handle: isize,
|
||||||
|
|
||||||
|
pub position: i32,
|
||||||
|
|
||||||
|
pub size: i32
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn W_AddFile(file: &str) {
|
||||||
|
// Get reference to static vvariables to be used locally
|
||||||
|
let (lumpinfo_ref, reloadname_ref) = unsafe {
|
||||||
|
(
|
||||||
|
&mut *std::ptr::addr_of_mut!(lumpinfo),
|
||||||
|
&mut *std::ptr::addr_of_mut!(reloadname)
|
||||||
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
if file.as_bytes()[0] == '~' as u8 {
|
||||||
|
unsafe {
|
||||||
|
reloadname = file.chars().skip(1).collect();
|
||||||
|
reloadlump = numlumps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut fileinfo: Vec<filelump_t> = Vec::new();
|
||||||
|
|
||||||
|
let mut handle: File = match std::fs::File::open(&file) {
|
||||||
|
Ok(file) => file,
|
||||||
|
Err(_) => {
|
||||||
|
println!(" couldn't open {}", file);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
println!("adding {}",file);
|
||||||
|
|
||||||
|
if !file.to_ascii_lowercase().ends_with(".wad") {
|
||||||
|
// process single lump
|
||||||
|
let file_meta = handle.metadata().unwrap();
|
||||||
|
// Single lump file
|
||||||
|
let mut singleinfo = filelump_t {
|
||||||
|
filepos: 0,
|
||||||
|
size: file_meta.len() as i32,
|
||||||
|
name: [0; 8]
|
||||||
|
};
|
||||||
|
let name = Path::new(file)
|
||||||
|
.file_name()
|
||||||
|
.and_then(|os_str| os_str.to_str()).unwrap();
|
||||||
|
for (i, byte) in name.as_bytes().iter().take(8).enumerate() {
|
||||||
|
singleinfo.name[i] = *byte;
|
||||||
|
}
|
||||||
|
fileinfo.push(singleinfo);
|
||||||
|
unsafe {numlumps += 1};
|
||||||
|
} else {
|
||||||
|
// WAD file
|
||||||
|
let mut header: wadinfo_t = wadinfo_t {
|
||||||
|
identification: [0; 4],
|
||||||
|
numlumps: 0,
|
||||||
|
infotableofs: 0
|
||||||
|
};
|
||||||
|
handle.read_exact(&mut header.identification).unwrap();
|
||||||
|
let mut int_buf:[u8; 4] = [0u8; 4];
|
||||||
|
handle.read_exact(&mut int_buf).unwrap();
|
||||||
|
header.numlumps = i32::from_le_bytes(int_buf);
|
||||||
|
handle.read_exact(&mut int_buf).unwrap();
|
||||||
|
header.infotableofs = i32::from_le_bytes(int_buf);
|
||||||
|
|
||||||
|
if !header.identification.eq_ignore_ascii_case(b"IWAD") {
|
||||||
|
if !header.identification.eq_ignore_ascii_case(b"PWAD") {
|
||||||
|
// TODO: Implement I_Error
|
||||||
|
// I_Error ("Wad file %s doesn't have IWAD or PWAD id\n", file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = handle.seek(SeekFrom::Start(header.infotableofs as u64));
|
||||||
|
fileinfo.resize(header.numlumps as usize, filelump_t {
|
||||||
|
filepos: 0,
|
||||||
|
size: 0,
|
||||||
|
name: [0; 8],
|
||||||
|
});
|
||||||
|
let dirinfo_bytes = header.numlumps as usize * size_of::<filelump_t>();
|
||||||
|
unsafe {
|
||||||
|
let fileinfo_slice = std::slice::from_raw_parts_mut(
|
||||||
|
fileinfo.as_mut_ptr() as *mut u8,
|
||||||
|
dirinfo_bytes,
|
||||||
|
);
|
||||||
|
handle.read_exact(fileinfo_slice).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
// enusre LE-ness of the ints
|
||||||
|
for fl in &mut fileinfo {
|
||||||
|
fl.filepos = i32::from_le(fl.filepos);
|
||||||
|
fl.size = i32::from_le(fl.size);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe{numlumps += header.numlumps}
|
||||||
|
};
|
||||||
|
|
||||||
|
let is_reloaded = !reloadname_ref.is_empty();
|
||||||
|
let storehandle: isize = if is_reloaded {
|
||||||
|
-1 // Original C code closes the file immediately if it's a reloaded file
|
||||||
|
} else {
|
||||||
|
// get raw Windows HANDLE as an integer pointer
|
||||||
|
let raw_handle = handle.as_raw_handle() as isize;
|
||||||
|
// Tells rust to "trust us" and keeps the handle open after this function scope
|
||||||
|
std::mem::forget(handle);
|
||||||
|
raw_handle
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
lumpinfo_ref.reserve(fileinfo.len());
|
||||||
|
for info in fileinfo {
|
||||||
|
lumpinfo_ref.push( lumpinfo_t {
|
||||||
|
handle: storehandle,
|
||||||
|
position: info.filepos,
|
||||||
|
size: info.size,
|
||||||
|
name: info.name
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn W_InitMultipleFiles(filenames: Vec<String>) {
|
||||||
|
|
||||||
|
for file in filenames {
|
||||||
|
W_AddFile(&file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if unsafe{numlumps == 0} {
|
||||||
|
// TODO: Implement I_Error
|
||||||
|
// I_Error("W_InitFiles: no files found")
|
||||||
|
}
|
||||||
|
|
||||||
|
// set up lump cache
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn W_Reload() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn W_CheckNumForName(name: &str) -> i32 {
|
||||||
|
let lumpinfo_ref = unsafe { &*std::ptr::addr_of!(lumpinfo) };
|
||||||
|
|
||||||
|
let mut search_name = [0u8; 8];
|
||||||
|
for (i, byte) in name.as_bytes().iter().take(8).enumerate() {
|
||||||
|
search_name[i] = byte.to_ascii_uppercase();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Scan backwards so PWAD patches take precedence over IWAD assets
|
||||||
|
lumpinfo_ref
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.rev() // Iterates backward from the end
|
||||||
|
.find(|(_, lump)| lump.name == search_name)
|
||||||
|
.map(|(index, _)| index as i32) // If found, return the index
|
||||||
|
.unwrap_or(-1) // "TFB. Not found." -> return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn W_LumpLength() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn W_ReadLump() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn W_CacheLumpNum() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn W_CacheLumpName() {
|
||||||
|
|
||||||
|
}
|
||||||
165
src/z_zone/mod.rs
Normal file
165
src/z_zone/mod.rs
Normal file
@@ -0,0 +1,165 @@
|
|||||||
|
/// Memory allocator stuff
|
||||||
|
/// Compared to the original source, this will be some what "lean n' mean"
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
|
||||||
|
/// The PurgeTags (PUs)
|
||||||
|
/// Tags < 100 are not overwritten untill freed
|
||||||
|
pub enum PurgeTag {
|
||||||
|
/// Static the entire execution time
|
||||||
|
Static = 1,
|
||||||
|
/// Static while playing
|
||||||
|
Sound = 2,
|
||||||
|
/// static while playing
|
||||||
|
Music = 3,
|
||||||
|
/// Original source comment: anything else dave wants static
|
||||||
|
Dave = 4,
|
||||||
|
/// static until level exit
|
||||||
|
Level = 50,
|
||||||
|
/// static for special thinkers in a level
|
||||||
|
LevSpec = 51,
|
||||||
|
// Tags >= 100 are "purgable" whenever needed
|
||||||
|
PurgeLevel = 100,
|
||||||
|
Cache = 101,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Provides metadata on
|
||||||
|
struct AllocMeta {
|
||||||
|
/// The size of the allocation
|
||||||
|
size: usize,
|
||||||
|
/// The PU tag associated with the allocation
|
||||||
|
tag: i32,
|
||||||
|
/// A pointer to the caller's tracking pointer, cleared automatically upon freeing
|
||||||
|
user: *mut *mut u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
thread_local! {
|
||||||
|
// We promise not to be naughty and access this from another thread :)
|
||||||
|
/// Mapping from pointers (as usize) to the correspond AllocationMeta
|
||||||
|
static REGISTRY: RefCell<HashMap<usize, AllocMeta>> = RefCell::new(HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper method that we can use to access the registry
|
||||||
|
fn with_registry<F, R>(f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut HashMap<usize, AllocMeta>) -> R
|
||||||
|
{
|
||||||
|
REGISTRY.with(|registry| f(&mut *registry.borrow_mut()))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
/// Initalized the Zone memory allocator sub-system
|
||||||
|
pub fn Z_Init() {
|
||||||
|
// do nothing, we get lazy init of the registry.
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
/// Allocate a contiguous chunk of zeroed memory from the zone allocator
|
||||||
|
/// # Safety
|
||||||
|
/// This function returns a raw pointer that bypasses Rust's automatic memory
|
||||||
|
/// tracking. The returned memory must be manually reclaimed using `Z_Free`.
|
||||||
|
pub unsafe fn Z_Malloc(size: usize, tag: i32, user: *mut *mut u8) -> *mut u8 {
|
||||||
|
let mut buffer = vec![0u8; size];
|
||||||
|
let ptr = buffer.as_mut_ptr();
|
||||||
|
|
||||||
|
// ensures Rust does not drop the buffer at the end of this block
|
||||||
|
std::mem::forget(buffer);
|
||||||
|
|
||||||
|
// Update the engine's tracking pointer if one was provided
|
||||||
|
if !user.is_null() {
|
||||||
|
unsafe {
|
||||||
|
*user = ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save allocation details using the pointer address as the key
|
||||||
|
with_registry(|map| {
|
||||||
|
map.insert(ptr as usize, AllocMeta { size, tag, user });
|
||||||
|
});
|
||||||
|
|
||||||
|
ptr
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
/// Reclaims and frees a allocation from Z_Malloc
|
||||||
|
/// # Safety
|
||||||
|
/// The provided pointer must point to a valid allocation tracked by the registry.
|
||||||
|
/// Passing an invalid or already freed pointer can result in undefined behavior
|
||||||
|
pub unsafe fn Z_Free(ptr: *mut u8) {
|
||||||
|
if ptr.is_null() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let removed = with_registry(|map| map.remove(&(ptr as usize)));
|
||||||
|
|
||||||
|
if let Some(meta) = removed {
|
||||||
|
// Clear the caller's tracking pointer to prevent use-after-free
|
||||||
|
if !meta.user.is_null() {
|
||||||
|
unsafe {
|
||||||
|
*meta.user = std::ptr::null_mut();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// re-build the vector so Rust can drop it
|
||||||
|
unsafe {
|
||||||
|
let _dropped_vec = Vec::from_raw_parts(ptr, meta.size, meta.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
/// Frees all memory allocations between the specific lifetime PU tags.
|
||||||
|
/// # Safety
|
||||||
|
/// All pointers tracked within this tag boundary are invalidated and deallocate
|
||||||
|
pub unsafe fn Z_FreeTags(low_tag: i32, high_tag: i32) {
|
||||||
|
|
||||||
|
// get all of the allocations to free
|
||||||
|
let tags_to_free: Vec<usize> = with_registry(|map| {
|
||||||
|
map.iter()
|
||||||
|
.filter(|(_, meta)| meta.tag >= low_tag && meta.tag <= high_tag)
|
||||||
|
.map(|(ptr_addr,_)| *ptr_addr)
|
||||||
|
.collect()
|
||||||
|
});
|
||||||
|
|
||||||
|
// remove each pointer returned from the map and drop the memory
|
||||||
|
|
||||||
|
for ptr_addr in tags_to_free {
|
||||||
|
let removed_ptr = with_registry(|map| map.remove(&ptr_addr));
|
||||||
|
|
||||||
|
if let Some(meta) = removed_ptr {
|
||||||
|
let p = ptr_addr as *mut u8;
|
||||||
|
unsafe {
|
||||||
|
// clear caller tracking pointer to preven use after free
|
||||||
|
if !meta.user.is_null() {
|
||||||
|
*meta.user = std::ptr::null_mut();
|
||||||
|
}
|
||||||
|
|
||||||
|
let _dropped_vec = Vec::from_raw_parts(p, meta.size, meta.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Internal ChangeTag function
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
fn Z_ChangeTagInternal(ptr: *mut u8, tag: i32) {
|
||||||
|
if ptr.is_null() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
with_registry(|map| {
|
||||||
|
if let Some(meta) = map.get_mut(&(ptr as usize)) {
|
||||||
|
meta.tag = tag;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
/// Modifies the lifetime tag of an active allocation.
|
||||||
|
///
|
||||||
|
/// # Safety
|
||||||
|
/// The provided pointer must point to a valid allocation tracked by the registry
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub unsafe fn Z_ChangeTag(ptr: *mut u8, tag: i32) {
|
||||||
|
// removes the original helper macro from the original C, we don't need withcraft here
|
||||||
|
Z_ChangeTagInternal(ptr, tag);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user