use std::collections::HashMap;
use crate::game::fs::VirtualFileSystem;
use crate::game::state::{GameTime, TerminalState};
use crate::game::commands::Commands;
/// Enum representing terminal command results
pub enum CommandResult {
/// Success with optional message
Success(String),
/// Error with message
Error(String),
/// Special event triggered by the command
Event(String),
/// No output
Empty,
}
impl CommandResult {
pub fn to_string(&self) -> String {
match self {
CommandResult::Success(msg) => msg.clone(),
CommandResult::Error(msg) => format!("Error: {}", msg),
CommandResult::Event(msg) => msg.clone(),
CommandResult::Empty => String::new(),
}
}
}
/// Function type for command handlers
type CommandHandlerFn = fn(&mut TerminalState, &mut VirtualFileSystem, &GameTime, &[&str]) -> CommandResult;
/// Terminal command handler
pub struct TerminalController {
pub filesystem: VirtualFileSystem,
command_handlers: HashMap<String, CommandHandlerFn>,
pub win_conditions: crate::game::state::WinConditions,
}
impl TerminalController {
pub fn new() -> Self {
let mut command_handlers = HashMap::<String, CommandHandlerFn>::new();
// Register command handlers from the Commands module
command_handlers.insert("help".to_string(), Commands::cmd_help);
command_handlers.insert("ls".to_string(), Commands::cmd_ls);
command_handlers.insert("cd".to_string(), Commands::cmd_cd);
command_handlers.insert("cat".to_string(), Commands::cmd_cat);
command_handlers.insert("pwd".to_string(), Commands::cmd_pwd);
command_handlers.insert("echo".to_string(), Commands::cmd_echo);
command_handlers.insert("grep".to_string(), Commands::cmd_grep);
command_handlers.insert("touch".to_string(), Commands::cmd_touch);
command_handlers.insert("mkdir".to_string(), Commands::cmd_mkdir);
command_handlers.insert("rm".to_string(), Commands::cmd_rm);
command_handlers.insert("clear".to_string(), Commands::cmd_clear);
command_handlers.insert("time".to_string(), Commands::cmd_time);
command_handlers.insert("whoami".to_string(), Commands::cmd_whoami);
command_handlers.insert("man".to_string(), Commands::cmd_man);
command_handlers.insert("flags".to_string(), Commands::cmd_flags);
command_handlers.insert("submit".to_string(), Commands::cmd_submit);
command_handlers.insert("watcher".to_string(), Commands::cmd_watcher);
Self {
filesystem: VirtualFileSystem::new(),
command_handlers,
win_conditions: crate::game::state::WinConditions::default(),
}
}
/// Process a command and return the result
pub fn process_command(
&mut self,
terminal: &mut TerminalState,
game_time: &GameTime,
command: &str,
win_conditions: &mut crate::game::state::WinConditions
) -> CommandResult {
if command.trim().is_empty() {
return CommandResult::Empty;
}
// Add command to history
terminal.command_history.push(command.to_string());
// Special case: Check if someone is writing the special phrase to the diary
if command.starts_with("echo") && command.contains("i see you for who you are") {
let diary_path = "/home/user/personal/diary.txt";
if self.filesystem.get_file(diary_path).is_some() {
// When the phrase is echoed, mark the hidden flag as discoverable
// We'll check for this when cat command is used on the diary
if let Some(idx) = win_conditions.flags.iter().position(|f| f.name == "HIDDEN_TRUTH") {
win_conditions.flags[idx].found = true;
}
}
}
// Split command into parts
let parts: Vec<&str> = command.split_whitespace().collect();
if parts.is_empty() {
return CommandResult::Empty;
}
let cmd_name = parts[0].to_lowercase();
let args = &parts[1..];
// Check for secret commands first (like summon and forbidden)
if let Some(result) = Commands::handle_secret_command(
terminal,
&mut self.filesystem,
game_time,
&cmd_name,
args,
win_conditions
) {
return result;
}
// Check for midnight or 3 AM effects
let mut corrupted_command = false;
if game_time.is_midnight() || game_time.is_three_am() {
// 20% chance of command corruption at midnight/3AM
if rand::random::<f32>() < 0.2 {
corrupted_command = true;
}
}
// Special handling for cat command with diary
if cmd_name == "cat" && !args.is_empty() {
let target = args[0];
let target_path = self.filesystem.resolve_path(&terminal.current_dir, target);
// Check if we're looking at the diary file and the hidden flag is found
if target_path == "/home/user/personal/diary.txt" {
let hidden_flag_found = win_conditions.flags
.iter().any(|f| f.name == "HIDDEN_TRUTH" && f.found);
if hidden_flag_found {
if let Some(file) = self.filesystem.get_file(&target_path) {
let mut content = file.content.clone();
content.push_str("\n\n---------- HIDDEN MESSAGE REVEALED ----------\n");
content.push_str("You have found the HIDDEN_TRUTH flag!\n");
content.push_str("This reveals the full middle part of the command: 'shouldhavelistened'\n");
content.push_str("The entity has been watching you all along.\n");
content.push_str("--------------------------------------------\n");
return CommandResult::Success(content);
}
}
}
}
// Process the command
let result = if corrupted_command {
self.handle_corrupted_command(&cmd_name, args, game_time)
} else if let Some(handler) = self.command_handlers.get(&cmd_name) {
handler(terminal, &mut self.filesystem, game_time, args)
} else {
CommandResult::Error(format!("Command not found: {}", cmd_name))
};
result
}
/// Handle corrupted commands (when at midnight or 3AM)
fn handle_corrupted_command(&self, cmd: &str, _args: &[&str], game_time: &GameTime) -> CommandResult {
if game_time.is_three_am() {
let messages = [
"I̴ ̶s̴e̵e̷ ̸y̷o̴u̷",
"I̷̞̹̭̞̮̫̜̘̽̏͒̾̒̋̕͝t̵̡͕̝̪͕̓̆̾̔͗̾'̷̧͉̳̟̄s̵̻̠̬̈̒̌̉͆ ̸̗̠͔̭̬̤̌̔̈̚͠a̸̰̹̖̤̎̃͒ͅl̶̡̗̘͈̖̓͆̾̌w̴̻̞̠̗̟̌͂a̴̻̗̣̝̼̋ý̵̫̜͚̍s̴̡̳̫̠̆̾͛̎̋̄͝ ̴̠̣̑̒̎̒͊̃͠w̸̳̖̼̉͆̌̈͘̚͝ǎ̷̲͍̔͑̂ͅt̶̢̬͚͙̖͇͉̃́̆͗̈́c̷̹̬͊̃̏̌̔h̴̹̙͙̜̮̑͜͝͠i̸̢̝̗̱̦̼̝̗̒̂n̷̩̰̱̫̭̖̖̮̑̋̈́͆̇̈́͝g̵̬̼̋̋̿̏̕̚̚ͅ",
"D̷̗̦̱̱̯̍͆̎̀̀̒̑͜͠ơ̸̡̧̰̺̱͔̙̩̒̏̈̇͝ ̶̯̯͚̳͈̮̉͗̑͒n̶͚̤̞̽͜ö̴̠̯̯̩̲̹̹́̂́́̋̓͘t̸̮̦̭͗̓̎̏̀ ̶̢̜̝̙̐̃̈́́̉̏̍͝t̴̤̪̏̓͛͐͛̚͝r̵̠̗̋͆̈̈́ų̵̰̤͉̯͕͈̄̋s̵̢̮̦͑̌̒̈̏̿̏̚ͅt̵̩̞͓͚̫̝͊̿̓̍͘͜ ̴̜̙͚͐͛͗̓t̵̛̘̬̞̩͓͕̳̹̐̇h̵̟̀͑̅̾͊̽̚͘e̵̤̤̝̟̟̲̙̒̃ ̶̖̻͈̺͌̓t̵̢̳̯͙̝̽ẹ̴̓̕r̶̢͈̳̝̰̣͆͘ͅṃ̴̦̺̠͖͒i̶̢̻̮̱͇̮̎͐̿̽̈́̄ͅņ̵̤͓͑̒͋͛͝ȧ̶̛͔̰̯͖̳͖̋͌̈́l̸̢̯͊̅̕",
"I̵̱̩͒̐ẗ̶̢̻̹̹́'̶̗̉s̸͚̬̪̄ ̴̖̀͘͘3̸̧̗̑̈:̵̧̬̌0̸̨̛̜̠͊̈́0̶̪̥̻̒ ̷͉̹̆a̵̭͔̬͆̇͊m̴͓̫̀̿.̴̨͚̙̽ ̵͓̣̆́D̵̫̭͒̅͜o̷̲̦̒̇ ̸̯̈́̄ÿ̶̩́o̶̧̧͘u̶̬̖͛̏͜ ̷͎̬̽̆͘k̵̮̜̥͐̏͊n̴̡̘̥̅ọ̸̢̥̈́̾͝w̵̨̢̢͐ ̶̗͈̗̽̃w̸̧̟̣͑̿̍h̶̞̫͕̋̓̎ä̸̼͖͕̍͝t̶͉̦̂ ̶̻͊w̶̯͖̭̽a̶̩͓̠̿t̴̡̯̀͂c̵̨̠̼̔͊ḧ̴̺́̓e̵̘̊̌s̴̨̗̙̀̔ ̸̬̤͗̆̐ŷ̶̗̱o̶̬̔u̸̹̬̇̑ ̷̥̠̍̑͋i̶̪̖̓̃n̴̬̗̲̈́̕͝ ̸̧̼̼͂ẗ̴͓͙́̽h̶̩̠͓͋͘e̵̡̦̠̐̔ ̵̢̮͇̄̌d̵̼̈́̒a̵̩͎̙̍̍̀r̴̪̞͙̽̎k̵̻̉̃?̸̗͍̓̎̈",
"S̷̪̣͓̩͉̬̩̪̳͎̫̟͛̈̀͑̂̾͘̚͜͝h̶̬̗͉̰̿̋̐͐͂̿̿̎̏̐͊͝e̴͍̫̼̺̜̋͛͒͂͊ ̷̧̯͎͔̤̜͚̈́̂̒̄̊̕͜w̶̡̠̝͚̭̻̣̞͕̫̽͂̅͒̏̐͐̽̾̈́̓̑́̔ḁ̸̱̦̖͈̦̜̥̱̬͔̔̓̂̍͜͜ͅṡ̸͔͂̋̔̅͝ ̸̻̠͙̀̒̃̀͝͝ǹ̴̨̢̡̪̹̦̹̤̹͉͓̣̦̍̓͆̈́̽͂̍̆̒̅͜͠ͅè̵̞̬͇̥̗̫̙̣̥̎̏̌̊́͑v̶̭͙̩̻̙͍̟̳̲͙̣̖̏̿̐̃̌̈̿̓̕̕͝e̸̡̫͎̬̤̙̮͔̱̱̦͓͑̋͜r̵̡̼̯̳͊̾̆̓̍͋̑̒̌͜ ̴̮̮̼̞̰̈̒̈́̓̏̐̿͌̊̿̆̓͠ͅd̵̦͒̿̄̆̌̽̎̒̋̚͝ę̸̮̜̫̲͈̰̜̲͍̍͂̊̊̅͐͑̈́̊̂͠â̵̫̥̗͕̘̘̗̽͜ͅḑ̶̢̯͓̖̎͋̎̓́"
];
CommandResult::Event(messages[rand::random::<usize>() % messages.len()].to_string())
} else if game_time.is_midnight() {
let messages = [
"It's midnight. They're here.",
"The terminal seems to be watching you.",
"You hear something moving in the system.",
"The command failed in an unexpected way.",
"The lights in the room seem to dim for a moment."
];
// 50% chance to execute original command, 50% chance for creepy message
if rand::random::<bool>() {
CommandResult::Error(messages[rand::random::<usize>() % messages.len()].to_string())
} else {
// Let it execute the real command with a glitchy warning
CommandResult::Error(format!("Warning: {} processed with unexpected side effects", cmd))
}
} else {
CommandResult::Error(format!("Command failed: {}", cmd))
}
}
}