From 2a4f92c9b3d5e7ba11cec61f735aef9c23dc8f1a Mon Sep 17 00:00:00 2001 From: Vinzenz Schroeter Date: Sun, 6 Jul 2025 22:03:11 +0200 Subject: [PATCH] clean up ui, more upgrades --- src/bar.rs | 37 ++++++----- src/border_panel.rs | 5 +- src/game.rs | 52 ++++----------- src/main.rs | 31 ++++----- src/row.rs | 26 ++++---- src/unlocks.rs | 152 +++++++++++++++++++------------------------- 6 files changed, 130 insertions(+), 173 deletions(-) diff --git a/src/bar.rs b/src/bar.rs index 9ebf194..b044066 100644 --- a/src/bar.rs +++ b/src/bar.rs @@ -1,4 +1,4 @@ -use servicepoint::GridMut; +use servicepoint::{Bitmap, WindowMut}; #[derive(Debug, Clone, Copy)] pub struct Bar { pub progress: f64, @@ -9,33 +9,38 @@ impl Bar { Self { progress: 0.0 } } - pub fn draw>(&self, bitmap: &mut P) { + pub fn draw(&self, mut bitmap: WindowMut) { bitmap.fill(false); - let margin = 1; - let bar_height = bitmap.height() - 2 * margin; - let bar_width = bitmap.width() - 2 * margin; - let border_thickness = 1; + let padding = 1; + let mut bitmap = bitmap + .window_mut( + padding, + padding, + bitmap.width() - 2 * padding, + bitmap.height() - 2 * padding, + ) + .unwrap(); // border top + bottom - let last_row = bitmap.height() - margin - border_thickness; - for x in margin..bar_width { - bitmap.set(x, margin, true); + let last_row = bitmap.height() - 1; + for x in 0..bitmap.width() { + bitmap.set(x, 0, true); bitmap.set(x, last_row, true); } // border left + right - let last_col = bitmap.width() - margin - border_thickness; - for y in 1..=bar_height { - bitmap.set(1, y, true); + let last_col = bitmap.width() - 1; + for y in 0..bitmap.height() { + bitmap.set(0, y, true); bitmap.set(last_col, y, true); } // progress fill - let fill_to = ((bar_width - 2) as f64 * self.progress) as usize; - for y in 2..bar_height { - for x in 2..=fill_to { - bitmap.set(x, y, (x + y) % 2 == 0); + let fill_to = (bitmap.width() as f64 * self.progress) as usize; + for y in 1..bitmap.height() - 1 { + for x in 1..bitmap.width() - 1 { + bitmap.set(x, y, x < fill_to && (x + y) % 2 == 0); } } } diff --git a/src/border_panel.rs b/src/border_panel.rs index 9834306..9d01005 100644 --- a/src/border_panel.rs +++ b/src/border_panel.rs @@ -1,5 +1,4 @@ -use servicepoint::{CharGridMutExt, Grid, GridMut, TILE_SIZE, WindowMut}; -use std::io::BufRead; +use servicepoint::{CharGridMutExt, GridMut, TILE_SIZE, WindowMut}; pub type BorderPattern = [bool; TILE_SIZE]; @@ -9,7 +8,7 @@ pub const INNER_BORDER: BorderPattern = [false, false, false, true, true, false, pub fn draw_border_panel<'t, C: GridMut, P: GridMut>( mut chars: WindowMut<'t, char, C>, mut bitmap: WindowMut<'t, bool, P>, - label: &'static str, + label: &str, border_pattern: BorderPattern, ) -> (WindowMut<'t, char, C>, WindowMut<'t, bool, P>) { let tile_width = chars.width(); diff --git a/src/game.rs b/src/game.rs index 69bcf63..83ae834 100644 --- a/src/game.rs +++ b/src/game.rs @@ -1,10 +1,7 @@ use crate::border_panel::{INNER_BORDER, OUTER_BORDER, draw_border_panel}; use crate::row::Row; -use crate::{ - Currency, - unlocks::{Unlock, UnlockSystem}, -}; -use servicepoint::{Bitmap, CharGrid, CharGridMutExt, GridMut, TILE_SIZE, WindowMut}; +use crate::{Currency, unlocks::UnlockSystem}; +use servicepoint::{Bitmap, CharGrid, TILE_SIZE, WindowMut}; use std::time::Duration; #[derive(Debug)] @@ -23,9 +20,8 @@ pub struct State { } impl Game { - const BAR_NAMES: [&'static str; 10] = [ + const BAR_NAMES: [&'static str; 11] = [ "Powering infrastructure", - "Dusting ServicePoint", "Activating colorful lights", "Dimming darkroom", "Refilling Matemat", @@ -34,7 +30,8 @@ impl Game { "Untangling 'block chain'", "Refilling sticker box", "Setting room to public", - // "Welcoming creatures", + "Welcoming creatures", + "Making Discordia proud", ]; pub fn new() -> Self { @@ -43,7 +40,7 @@ impl Game { .enumerate() .map(|(index, name)| { Row::new( - 2usize.pow(index as u32) as f64, + 5usize.pow(index as u32) as f64, 1.0 * (0.5f64.powi(index as i32)), *name, ) @@ -90,52 +87,31 @@ impl Game { ); let unlocks_height = 3 + 2; - let (unlocks_text, text_layer) = text_layer.split_vertical_mut(unlocks_height).unwrap(); - let (unlocks_pixel, pixel_layer) = pixel_layer + let (unlocks_text, bars_text) = text_layer.split_vertical_mut(unlocks_height).unwrap(); + let (unlocks_pixel, bars_pixel) = pixel_layer .split_vertical_mut(unlocks_height * TILE_SIZE) .unwrap(); self.unlocks.draw(unlocks_text, unlocks_pixel); - let bars_height = self.state.rows.len() + 2; - let (bars_text, text_layer) = text_layer.split_vertical_mut(bars_height).unwrap(); - let (bars_pixel, _) = pixel_layer - .split_vertical_mut(bars_height * TILE_SIZE) - .unwrap(); self.draw_bars(bars_text, bars_pixel); - - let free_row_bottom = text_layer.height() - 1; - self.draw_stats(text_layer, free_row_bottom); } - fn draw_stats>(&self, text_layer: WindowMut, row: usize) { - let middle = text_layer.width() / 2; - let (mut left, mut right) = text_layer.split_horizontal_mut(middle).unwrap(); - left.set_row_str(0, &format!("Hack Score: {:.2}", self.total_currency)) - .unwrap(); - - if self.unlocks.bought() > 0 { - right - .set_row_str(0, &format!(" Unlocks: {}", self.unlocks.bought())) - .unwrap(); - } - } - - fn draw_bars, P: GridMut>( + fn draw_bars( &self, - text_layer: WindowMut, - pixel_layer: WindowMut, + text_layer: WindowMut, + pixel_layer: WindowMut, ) { let (mut text_layer, mut pixel_layer) = draw_border_panel(text_layer, pixel_layer, " Processes ", INNER_BORDER); for (index, row) in self.state.rows.iter().enumerate() { - let mut bar_window = pixel_layer + let bar_window = pixel_layer .window_mut(0, index * TILE_SIZE, pixel_layer.width(), TILE_SIZE) .unwrap(); - let mut label_window = text_layer + let label_window = text_layer .window_mut(0, index, text_layer.width(), 1) .unwrap(); - row.draw(&mut label_window, &mut bar_window); + row.draw(label_window, bar_window); } } } diff --git a/src/main.rs b/src/main.rs index f7edece..965df53 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,9 @@ use game::Game; use servicepoint::{ - BinaryOperation, BitVecCommand, Bitmap, CharGrid, CharGridCommand, ClearCommand, - CompressionCode, FRAME_PACING, TILE_HEIGHT, TILE_WIDTH, UdpSocketExt, + Bitmap, BitmapCommand, CharGrid, CharGridCommand, ClearCommand, TILE_HEIGHT, TILE_WIDTH, + UdpSocketExt, }; -use std::{net::UdpSocket, thread::sleep, time::Instant}; +use std::{net::UdpSocket, time::Instant}; mod bar; mod border_panel; @@ -23,8 +23,8 @@ fn main() { let connection = UdpSocket::bind_connect(DESTINATION).unwrap(); connection.send_command(ClearCommand); - let mut chars = CharGrid::new(TILE_WIDTH, TILE_HEIGHT); - let mut pixels = Bitmap::max_sized(); + let mut bitmap_cmd = BitmapCommand::from(Bitmap::max_sized()); + let mut chars_cmd = CharGridCommand::from(CharGrid::new(TILE_WIDTH, TILE_HEIGHT)); let mut last_refresh = Instant::now(); loop { @@ -34,7 +34,10 @@ fn main() { state.progress(delta); - chars.fill(' '); + let chars = &mut chars_cmd.grid; + let pixels = &mut bitmap_cmd.bitmap; + + chars.fill('\0'); pixels.fill(false); let chars_view = chars @@ -45,18 +48,8 @@ fn main() { .unwrap(); state.draw(chars_view, pixels_view); - connection - .send_command(CharGridCommand::from(chars.clone())) - .unwrap(); - connection - .send_command(BitVecCommand { - bitvec: pixels.clone().into(), - compression: CompressionCode::default(), - operation: BinaryOperation::Or, - offset: 0, - }) - .unwrap(); - - sleep(FRAME_PACING / 2); + connection.send_command(&bitmap_cmd).unwrap(); + connection.send_command(&chars_cmd).unwrap(); + //sleep(FRAME_PACING / 10); } } diff --git a/src/row.rs b/src/row.rs index dc01eee..e28bef7 100644 --- a/src/row.rs +++ b/src/row.rs @@ -1,5 +1,5 @@ use crate::{Currency, bar::Bar}; -use servicepoint::{CharGridMutExt, GridMut, WindowMut}; +use servicepoint::{Bitmap, CharGrid, CharGridMutExt, GridMut, WindowMut}; use std::time::Duration; #[derive(Debug, Clone, Copy)] @@ -39,22 +39,24 @@ impl Row { completions * self.productivity } - pub fn draw, P: GridMut>(&self, chars: &mut C, bitmap: &mut P) { + pub fn draw(&self, mut chars: WindowMut, mut bitmap: WindowMut) { if !self.enabled { return; } - let mut bitmap = WindowMut::new(bitmap, 0, 0, bitmap.width() / 2, bitmap.height()).unwrap(); - self.bar.draw(&mut bitmap); + let bitmap = bitmap + .window_mut(0, 0, bitmap.width() / 2, bitmap.height()) + .unwrap(); + self.bar.draw(bitmap); - let mut chars = WindowMut::new( - chars, - chars.width() / 2 + 1, - 0, - chars.width() / 2 - 1, - chars.height(), - ) - .unwrap(); + let mut chars = chars + .window_mut( + chars.width() / 2 + 1, + 0, + chars.width() / 2 - 1, + chars.height(), + ) + .unwrap(); chars .set_row_str( diff --git a/src/unlocks.rs b/src/unlocks.rs index 6f3184d..1111e4f 100644 --- a/src/unlocks.rs +++ b/src/unlocks.rs @@ -1,11 +1,10 @@ use crate::border_panel::{INNER_BORDER, draw_border_panel}; use crate::{Currency, bar::Bar, game::State, row::Row}; -use servicepoint::{CharGridMutExt, GridMut, TILE_SIZE, WindowMut}; +use servicepoint::{Bitmap, CharGrid, CharGridMutExt, TILE_SIZE, WindowMut}; use std::{ collections::VecDeque, fmt::{Debug, Formatter}, - iter::Map, - ops::{Mul, Range}, + ops::Mul, }; #[derive(Debug)] @@ -15,6 +14,7 @@ pub struct UnlockSystem { unlock_queue: VecDeque, all_unlocks_bar: Bar, next_unlock_bar: Bar, + total_unlock_count: usize, } pub struct Unlock { @@ -34,13 +34,16 @@ impl Debug for Unlock { impl UnlockSystem { pub fn new(start_state: &State) -> Self { - let mut upgrades = Self::gen_bar_upgrades(&start_state.rows) - .chain(Self::gen_speed_upgrades()) - .chain(Self::gen_productivity_upgrades()) + let mut upgrades = Self::gen_bar_enable_unlocks(&start_state.rows) + .chain(Self::gen_global_speed_unlocks()) + .chain(Self::gen_global_productivity_unlocks()) + .chain(Self::gen_bar_speed_unlocks(&start_state.rows)) + .chain(Self::gen_bar_productivity_unlocks(&start_state.rows)) .collect::>(); upgrades.sort_by(|l, r| l.cost.total_cmp(&r.cost)); Self { + total_unlock_count: upgrades.len(), unlock_queue: upgrades.into(), bought: 0, last_unlock: None, @@ -64,52 +67,25 @@ impl UnlockSystem { } } - pub fn bought(&self) -> usize { - self.bought - } - pub fn previous(&self) -> Option<&String> { self.last_unlock.as_ref() } - pub fn draw, P: GridMut>( - &self, - chars: WindowMut, - bitmap: WindowMut, - ) { - let (mut chars, mut bitmap) = draw_border_panel(chars, bitmap, " Unlocks ", INNER_BORDER); - let mut free_row_bottom = chars.height() - 1; + pub fn draw(&self, chars: WindowMut, bitmap: WindowMut) { + let title = format!(" Stage {}/{} ", self.bought, self.total_unlock_count); - let pixel_width = bitmap.width(); - self.all_unlocks_bar.draw( - &mut WindowMut::new( - &mut bitmap, - 0, - free_row_bottom * TILE_SIZE, - pixel_width, - TILE_SIZE, - ) - .unwrap(), - ); - free_row_bottom -= 1; + let (mut chars, mut bitmap) = draw_border_panel(chars, bitmap, &title, INNER_BORDER); - self.next_unlock_bar.draw( - &mut WindowMut::new( - &mut bitmap, - 0, - free_row_bottom * TILE_SIZE, - pixel_width, - TILE_SIZE, - ) - .unwrap(), - ); - free_row_bottom -= 1; + let (all_unlocks_pixels, bitmap) = bitmap.split_vertical_mut(TILE_SIZE).unwrap(); + self.all_unlocks_bar.draw(all_unlocks_pixels); - if let Some(prev_unlock) = self.previous() { - let char_width = chars.width(); - WindowMut::new(&mut chars, 0, free_row_bottom, char_width, 1) - .unwrap() - .set_row_str(0, &format!("Unlocked: {}", prev_unlock)) + let (next_unlocks_pixels, _) = bitmap.split_vertical_mut(TILE_SIZE).unwrap(); + self.next_unlock_bar.draw(next_unlocks_pixels); + + if let Some(next) = self.peek_next() { + let (_, mut next_unlock_chars) = chars.split_vertical_mut(2).unwrap(); + next_unlock_chars + .set_row_str(0, &format!("Loading: {}", next.name)) .unwrap(); } } @@ -124,56 +100,62 @@ impl UnlockSystem { self.last_unlock = Some(next_upgrade.name); self.bought += 1; - let total = self.bought + self.unlock_queue.len(); - self.all_unlocks_bar.progress = self.bought as f64 / total as f64; + self.all_unlocks_bar.progress = self.bought as f64 / self.total_unlock_count as f64; } - fn gen_bar_upgrades(bars: &Vec) -> impl Iterator { - bars.iter().enumerate().flat_map(|(index, bar)| { - let initial_cost = 10usize.pow(index as u32); - [ - Unlock { - name: format!("Start {}", bar.name()), - cost: initial_cost as f64, - apply: Box::new(move |game| { - game.rows[index].enabled = true; - }), - }, - Unlock { - name: format!("{} productivity", bar.name()), - cost: initial_cost.mul(2) as f64, - apply: Box::new(move |game| { - game.rows[index].productivity *= 2.0; - }), - }, - Unlock { - name: format!("{} speed", bar.name()), - cost: initial_cost.mul(20) as f64, - apply: Box::new(move |game| { - game.rows[index].speed *= 1.5; - }), - }, - ] - }) - } - - fn gen_speed_upgrades() -> impl Iterator { - (1..10).map(|level| Unlock { - name: format!("The answer {}", level), - cost: (42usize * 10usize.pow(level)) as f64, + fn gen_bar_enable_unlocks(bars: &Vec) -> impl Iterator { + bars.iter().enumerate().map(|(index, bar)| Unlock { + name: format!("Start {}", bar.name()), + cost: 10f64.powi(index as i32), apply: Box::new(move |game| { - game.speed *= 1.1; + game.rows[index].enabled = true; }), }) } - fn gen_productivity_upgrades() -> Map, fn(u32) -> Unlock> { - (1..10).map(|level| Unlock { + fn gen_global_speed_unlocks() -> impl Iterator { + (1..32).map_while(|level| { + Some(Unlock { + name: format!("The answer {}", level), + cost: 42f64.mul(2f64.powi(level)), + apply: Box::new(move |game| { + game.speed *= 1.15; + }), + }) + }) + } + + fn gen_global_productivity_unlocks() -> impl Iterator { + (1..32).map(|level| Unlock { name: format!("??? {}", level), - cost: (23usize * 10usize.pow(level)) as f64, + cost: 23f64.mul(2f64.powi(level)), apply: Box::new(move |game| { - game.productivity *= 1.1; + game.productivity *= 1.15; }), }) } + + fn gen_bar_productivity_unlocks(bars: &Vec) -> impl Iterator { + bars.iter().enumerate().flat_map(|(index, bar)| { + (1..=20).map(move |level| Unlock { + name: format!("{} productivity {level}", bar.name()), + cost: 10f64.powi(index as i32).mul(3f64.powi(level)), + apply: Box::new(move |game| { + game.rows[index].productivity *= 1.5; + }), + }) + }) + } + + fn gen_bar_speed_unlocks(bars: &Vec) -> impl Iterator { + bars.iter().enumerate().flat_map(|(index, bar)| { + (1..=15).map(move |level| Unlock { + name: format!("{} speed {level}", bar.name()), + cost: 10f64.powi(index as i32).mul(5f64.powi(level)), + apply: Box::new(move |game| { + game.rows[index].speed *= 1.5; + }), + }) + }) + } }