add gamemodes
This commit is contained in:
136
src/main.rs
136
src/main.rs
@@ -17,40 +17,42 @@ const LOCK_RESET: u32 = 15;
|
||||
mod tetromino;
|
||||
|
||||
fn main() {
|
||||
let game_mode = args();
|
||||
let mut game = Game::new();
|
||||
let mut speed_time = frame_time_for_level(0);
|
||||
let mut lock_timer = Instant::now();
|
||||
let mut lock_count = 0;
|
||||
let mut lock_override = false;
|
||||
let total_time = Instant::now();
|
||||
|
||||
terminal::enable_raw_mode().unwrap();
|
||||
print!("\x1b[?25l");
|
||||
let mut current = Current::new();
|
||||
|
||||
loop {
|
||||
let expr = match game_mode {
|
||||
GameMode::Marathon => true,
|
||||
GameMode::Sprint => game.score.lines < 41,
|
||||
GameMode::Ultra => total_time.elapsed() < Duration::from_secs(60 * 2),
|
||||
};
|
||||
|
||||
while expr {
|
||||
let frame_time = frame_time_for_level(game.score.level());
|
||||
let frame_dur = Instant::now();
|
||||
render(&game, ¤t);
|
||||
while speed_time.checked_sub(frame_dur.elapsed()).is_some() {
|
||||
if let Some(input) = input(&frame_dur, frame_time) {
|
||||
let rot_index = handle_action(&input, &mut game, &mut speed_time, &frame_time);
|
||||
render(&game, ¤t);
|
||||
if input == Action::HardDrop {
|
||||
lock_timer -= LOCK_DELAY;
|
||||
break;
|
||||
} else if input == Action::SonicDrop {
|
||||
lock_timer = Instant::now();
|
||||
break;
|
||||
}
|
||||
let mut speed_time = frame_time;
|
||||
render(&game, ¤t, &game_mode, &total_time.elapsed());
|
||||
while speed_time > frame_dur.elapsed() && !lock_override {
|
||||
if let Some(input) = input(&frame_dur, speed_time) {
|
||||
handle_action(
|
||||
&input,
|
||||
&mut game,
|
||||
&mut speed_time,
|
||||
&mut lock_timer,
|
||||
&mut lock_override,
|
||||
);
|
||||
render(&game, ¤t, &game_mode, &total_time.elapsed());
|
||||
|
||||
if lock_count < LOCK_RESET {
|
||||
lock_count += 1;
|
||||
lock_timer = Instant::now();
|
||||
}
|
||||
if let Action::Rotate(r) = input {
|
||||
if let Some(i) = rot_index {
|
||||
game.last_rotation = Some((r, i));
|
||||
}
|
||||
} else {
|
||||
game.last_rotation = None;
|
||||
lock_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,14 +61,11 @@ fn main() {
|
||||
true
|
||||
} else {
|
||||
game.last_rotation = None;
|
||||
lock_timer = Instant::now();
|
||||
false
|
||||
};
|
||||
|
||||
if !should_lock {
|
||||
lock_timer = Instant::now();
|
||||
}
|
||||
|
||||
if should_lock && lock_timer.elapsed() > LOCK_DELAY {
|
||||
if should_lock && (lock_timer.elapsed() > LOCK_DELAY || lock_override) {
|
||||
if game.tetromino.pos.1 == 17 {
|
||||
exit();
|
||||
}
|
||||
@@ -89,10 +88,18 @@ fn main() {
|
||||
game.score.lines += current.lines;
|
||||
game.score.points += current.points;
|
||||
}
|
||||
render(&game, ¤t);
|
||||
render(&game, ¤t, &game_mode, &total_time.elapsed());
|
||||
lock_override = false;
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq)]
|
||||
enum GameMode {
|
||||
Marathon,
|
||||
Sprint,
|
||||
Ultra,
|
||||
}
|
||||
|
||||
struct Game {
|
||||
score: Score,
|
||||
tetromino: Tetromino,
|
||||
@@ -404,13 +411,12 @@ fn handle_action(
|
||||
action: &Action,
|
||||
game: &mut Game,
|
||||
speed_time: &mut Duration,
|
||||
frame_time: &Duration,
|
||||
) -> Option<u32> {
|
||||
lock_timer: &mut Instant,
|
||||
lock_override: &mut bool,
|
||||
) {
|
||||
let tetromino = &mut game.tetromino;
|
||||
let block_grid = &game.block_grid;
|
||||
|
||||
let mut rot_index = None;
|
||||
|
||||
match action {
|
||||
Action::MoveRight => {
|
||||
tetromino.move_tetromino((1, 0), block_grid);
|
||||
@@ -418,7 +424,11 @@ fn handle_action(
|
||||
Action::MoveLeft => {
|
||||
tetromino.move_tetromino((-1, 0), block_grid);
|
||||
}
|
||||
Action::Rotate(r) => rot_index = tetromino.rotate(r, block_grid),
|
||||
Action::Rotate(r) => {
|
||||
if let Some(i) = tetromino.rotate(r, block_grid) {
|
||||
game.last_rotation = Some((r.clone(), i));
|
||||
}
|
||||
}
|
||||
Action::SoftDrop => {
|
||||
game.score.points += 1;
|
||||
if game.score.level() < 19 {
|
||||
@@ -429,14 +439,15 @@ fn handle_action(
|
||||
while tetromino.move_tetromino((0, -1), block_grid) {
|
||||
game.score.points += 2;
|
||||
}
|
||||
*speed_time = Duration::from_secs(0);
|
||||
*lock_override = true;
|
||||
}
|
||||
Action::SonicDrop => {
|
||||
while tetromino.move_tetromino((0, -1), block_grid) {}
|
||||
*lock_timer = Instant::now();
|
||||
}
|
||||
Action::SonicDrop => while tetromino.move_tetromino((0, -1), block_grid) {},
|
||||
Action::Hold => game.hold(),
|
||||
}
|
||||
if *action != Action::SoftDrop {
|
||||
*speed_time = *frame_time;
|
||||
}
|
||||
rot_index
|
||||
}
|
||||
|
||||
fn input(now: &Instant, frame_time: Duration) -> Option<Action> {
|
||||
@@ -444,19 +455,19 @@ fn input(now: &Instant, frame_time: Duration) -> Option<Action> {
|
||||
if event::poll(poll_duration).ok()? {
|
||||
if let Event::Key(k) = event::read().ok()? {
|
||||
if let KeyCode::Char(c) = k.code {
|
||||
match c {
|
||||
'a' => return Some(Action::MoveLeft),
|
||||
'd' => return Some(Action::MoveRight),
|
||||
'l' => return Some(Action::Rotate(Rotation::Right)),
|
||||
'j' => return Some(Action::Rotate(Rotation::Left)),
|
||||
'k' => return Some(Action::Rotate(Rotation::Flip)),
|
||||
's' => return Some(Action::SoftDrop),
|
||||
' ' => return Some(Action::HardDrop),
|
||||
'w' => return Some(Action::SonicDrop),
|
||||
'c' => return Some(Action::Hold),
|
||||
return match c {
|
||||
'a' => Some(Action::MoveLeft),
|
||||
'd' => Some(Action::MoveRight),
|
||||
'l' => Some(Action::Rotate(Rotation::Right)),
|
||||
'j' => Some(Action::Rotate(Rotation::Left)),
|
||||
'k' => Some(Action::Rotate(Rotation::Flip)),
|
||||
's' => Some(Action::SoftDrop),
|
||||
' ' => Some(Action::HardDrop),
|
||||
'w' => Some(Action::SonicDrop),
|
||||
'c' => Some(Action::Hold),
|
||||
'q' => exit(),
|
||||
_ => (),
|
||||
}
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -468,7 +479,7 @@ fn frame_time_for_level(level: u32) -> Duration {
|
||||
Duration::from_secs_f32((0.8 - ((level as f32 - 1.) * 0.007)).powf(level as f32 - 1.))
|
||||
}
|
||||
|
||||
fn render(game: &Game, current: &Current) {
|
||||
fn render(game: &Game, current: &Current, game_mode: &GameMode, total_time: &Duration) {
|
||||
let mut s = String::with_capacity(2 * 22 * 22);
|
||||
s.push_str("\x1b[48;2;128;128;128m \x1b[0m\n");
|
||||
let next_pos = game.next_tetromino.get_blocks(&Rotation::Neutral);
|
||||
@@ -514,7 +525,9 @@ fn render(game: &Game, current: &Current) {
|
||||
if y == 18 {
|
||||
s.push_str(" \x1b[1mLINES ");
|
||||
s.push_str(&game.score.lines.to_string());
|
||||
s.push_str("\x1b[0m");
|
||||
if *game_mode == GameMode::Sprint {
|
||||
s.push_str("/40");
|
||||
}
|
||||
}
|
||||
if y == 17 {
|
||||
s.push_str(" \x1b[1mSCORE ");
|
||||
@@ -522,9 +535,17 @@ fn render(game: &Game, current: &Current) {
|
||||
s.push_str("\x1b[0m");
|
||||
}
|
||||
|
||||
if *game_mode == GameMode::Ultra && y == 16 {
|
||||
s.push_str(" \x1b[1mTIME ");
|
||||
s.push_str(&total_time.as_secs().to_string());
|
||||
s.push_str("/120");
|
||||
s.push_str("\x1b[0m");
|
||||
}
|
||||
|
||||
if y == 14 {
|
||||
s.push_str(" \x1b[1mNEXT\x1b[0m");
|
||||
}
|
||||
s.push_str("\x1b[0m");
|
||||
if y < 15 && y > 9 {
|
||||
let y = y - 10;
|
||||
s.push_str(" ");
|
||||
@@ -598,6 +619,17 @@ fn exit() -> ! {
|
||||
std::process::exit(0);
|
||||
}
|
||||
|
||||
fn args() -> GameMode {
|
||||
if let Some(arg) = std::env::args().nth(1) {
|
||||
return match &arg[..] {
|
||||
"s" | "sprint" => GameMode::Sprint,
|
||||
"u" | "ultra" => GameMode::Ultra,
|
||||
_ => GameMode::Marathon,
|
||||
};
|
||||
}
|
||||
GameMode::Marathon
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
BIN
term_tetris
Executable file
BIN
term_tetris
Executable file
Binary file not shown.
Reference in New Issue
Block a user