mod game; mod renderer; mod texture; use game::{Game, GameState}; use minifb::{Key, Window, WindowOptions}; use renderer::Renderer; use std::time::Instant; const SCREEN_W: usize = 640; const SCREEN_H: usize = 480; fn main() { println!("=== DUNGEON CRAWLER ==="); println!(" W / S — forward / backward"); println!(" A / D — strafe left / right"); println!(" Q / E — turn 90° left / right"); println!(" Space — attack"); println!(" Z — use selected inventory item"); println!(" X — discard selected inventory item"); println!(" 1-4 — select inventory slot"); println!(" C — skip turn"); println!(" Esc — quit\n"); let mut game = Game::new(); let renderer = Renderer::new(SCREEN_W, SCREEN_H); let mut window = Window::new( "Dungeon Crawler", SCREEN_W, SCREEN_H, WindowOptions::default(), ) .expect("Failed to create window"); let mut framebuffer = vec![0u32; SCREEN_W * SCREEN_H]; let mut last = Instant::now(); let frame_budget = std::time::Duration::from_micros(16600); // ~60 fps // Track previous key state for edge-triggered actions. let mut prev_w = false; let mut prev_s = false; let mut prev_a = false; let mut prev_d = false; let mut prev_q = false; let mut prev_e = false; let mut prev_space = false; let mut prev_z = false; let mut prev_x = false; let mut prev_c = false; let mut prev_1 = false; let mut prev_2 = false; let mut prev_3 = false; let mut prev_4 = false; while window.is_open() && !window.is_key_down(Key::Escape) { let frame_start = Instant::now(); let dt = (frame_start - last).as_secs_f64().min(0.1); last = frame_start; // ---- read current key states ---- let cur_w = window.is_key_down(Key::W); let cur_s = window.is_key_down(Key::S); let cur_a = window.is_key_down(Key::A); let cur_d = window.is_key_down(Key::D); let cur_q = window.is_key_down(Key::Q); let cur_e = window.is_key_down(Key::E); let cur_space = window.is_key_down(Key::Space); let cur_z = window.is_key_down(Key::Z); let cur_x = window.is_key_down(Key::X); let cur_c = window.is_key_down(Key::C); let cur_1 = window.is_key_down(Key::Key1); let cur_2 = window.is_key_down(Key::Key2); let cur_3 = window.is_key_down(Key::Key3); let cur_4 = window.is_key_down(Key::Key4); // ---- input (edge-triggered, only in WaitingForInput) ---- if game.can_act() { if cur_w && !prev_w { game.move_forward(); } else if cur_s && !prev_s { game.move_backward(); } else if cur_a && !prev_a { game.strafe_left(); } else if cur_d && !prev_d { game.strafe_right(); } else if cur_q && !prev_q { game.turn_left(); } else if cur_e && !prev_e { game.turn_right(); } else if cur_space && !prev_space { game.attack(); } else if cur_z && !prev_z { game.use_item(); } else if cur_x && !prev_x { game.discard_item(); } else if cur_c && !prev_c { game.skip_turn(); } else if cur_1 && !prev_1 { game.select_slot(0); } else if cur_2 && !prev_2 { game.select_slot(1); } else if cur_3 && !prev_3 { game.select_slot(2); } else if cur_4 && !prev_4 { game.select_slot(3); } } // Update previous states. prev_w = cur_w; prev_s = cur_s; prev_a = cur_a; prev_d = cur_d; prev_q = cur_q; prev_e = cur_e; prev_space = cur_space; prev_z = cur_z; prev_x = cur_x; prev_c = cur_c; prev_1 = cur_1; prev_2 = cur_2; prev_3 = cur_3; prev_4 = cur_4; // ---- advance animations / state machine ---- game.update_animation(dt); // ---- death check ---- if game.state == GameState::GameOver { let score = (game.kills * 100) + (game.depth.pow(2) * 50) + 500; // fists = base damage 1 println!( "You had become yet another legend of this dungeon.\nScore: {}", score ); std::process::exit(0); } // ---- win check (placeholder — becomes staircase in Phase 1) ---- if game.check_win() { println!("You found the exit in {} heartbeats!", game.heartbeats()); std::process::exit(0); } // ---- render ---- renderer.render(&game, &mut framebuffer); window .update_with_buffer(&framebuffer, SCREEN_W, SCREEN_H) .unwrap(); // Sleep the remainder of the frame budget (saves CPU). let elapsed = frame_start.elapsed(); if elapsed < frame_budget { std::thread::sleep(frame_budget - elapsed); } } }