add gamemodes

This commit is contained in:
2024-06-03 01:27:52 +02:00
parent 1c950d3934
commit 1c5af08585
2 changed files with 84 additions and 52 deletions

View File

@@ -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, &current);
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, &current);
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, &current, &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, &current, &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, &current);
render(&game, &current, &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

Binary file not shown.