implement upgrade system
This commit is contained in:
parent
64f4ea529a
commit
3468fff882
7 changed files with 558 additions and 100 deletions
59
src/bar.rs
59
src/bar.rs
|
|
@ -1,49 +1,60 @@
|
|||
use crate::{Currency, Progressable};
|
||||
use servicepoint::{GridMut};
|
||||
use servicepoint::{CharGridMutExt, GridMut, WindowMut};
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Bar {
|
||||
name: &'static str,
|
||||
pub(crate) enabled: bool,
|
||||
progress: f64,
|
||||
speed: f64,
|
||||
factor: f64,
|
||||
pub(crate) speed: f64,
|
||||
pub(crate) productivity: f64,
|
||||
}
|
||||
|
||||
impl Bar {
|
||||
pub(crate) fn new(factor: f64, speed: f64) -> Self {
|
||||
pub(crate) fn new(productivity: f64, speed: f64, name: &'static str) -> Self {
|
||||
Self {
|
||||
factor,
|
||||
name,
|
||||
enabled: false,
|
||||
productivity,
|
||||
progress: 0f64,
|
||||
speed,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn add_speed(&self, speed: f64) -> Self {
|
||||
Self {
|
||||
speed: self.speed + speed,
|
||||
..*self
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_enabled(&self) -> bool {
|
||||
self.speed > 0.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Progressable for Bar {
|
||||
fn progress(&self, delta: Duration) -> (Self, Currency) {
|
||||
let extra_progress = delta.as_secs_f64() * self.speed;
|
||||
impl Bar {
|
||||
pub(crate) fn progress(&mut self, delta: Duration) -> Currency {
|
||||
if !self.enabled {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
let extra_progress = delta.mul_f64(self.speed).as_secs_f64();
|
||||
let progress = self.progress + extra_progress;
|
||||
let completions = progress.floor();
|
||||
let progress = progress - completions;
|
||||
let currency = completions * self.factor;
|
||||
self.progress = progress - completions;
|
||||
|
||||
(Self { progress, ..*self }, currency)
|
||||
completions * self.productivity
|
||||
}
|
||||
}
|
||||
|
||||
impl Bar {
|
||||
pub fn draw<P: GridMut<bool>>(&self, bitmap: &mut P) {
|
||||
pub fn draw<C: GridMut<char>, P: GridMut<bool>>(&self, chars: &mut C, bitmap: &mut P) {
|
||||
if !self.enabled {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut bitmap = WindowMut::new(bitmap, 0, 0, bitmap.width() / 2, bitmap.height()).unwrap();
|
||||
let mut chars = WindowMut::new(
|
||||
chars,
|
||||
chars.width() / 2 + 1,
|
||||
0,
|
||||
chars.width() / 2 - 1,
|
||||
chars.height(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
chars.set_row_str(0, self.name).unwrap();
|
||||
bitmap.fill(false);
|
||||
|
||||
let margin = 1;
|
||||
|
|
|
|||
157
src/game.rs
157
src/game.rs
|
|
@ -1,92 +1,121 @@
|
|||
use crate::{
|
||||
bar::Bar,
|
||||
Currency,
|
||||
Progressable
|
||||
};
|
||||
use servicepoint::{Bitmap, CharGrid, CharGridMutExt, WindowMut, TILE_SIZE};
|
||||
use crate::upgrades::{Upgrade, get_upgrades};
|
||||
use crate::{Currency, Progressable, bar::Bar};
|
||||
use log::log;
|
||||
use servicepoint::{Bitmap, CharGrid, CharGridMutExt, TILE_SIZE, WindowMut};
|
||||
use std::collections::VecDeque;
|
||||
use std::time::Duration;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Game<const STEP_COUNT:usize=11> {
|
||||
#[derive(Debug)]
|
||||
pub struct Game<const STEP_COUNT: usize = 11> {
|
||||
pub(crate) currency: Currency,
|
||||
pub(crate) bars: [Bar; STEP_COUNT],
|
||||
pub(crate) names: [&'static str; STEP_COUNT],
|
||||
unlocks: usize,
|
||||
unlock_queue: VecDeque<Upgrade>,
|
||||
total_currency: Currency,
|
||||
pub(crate) global_speed: f64,
|
||||
pub(crate) global_productivity: f64,
|
||||
}
|
||||
|
||||
impl Game {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
currency: 0f64,
|
||||
total_currency: 0f64,
|
||||
global_speed: 1f64,
|
||||
global_productivity: 1f64,
|
||||
unlocks: 0,
|
||||
unlock_queue: get_upgrades(),
|
||||
bars: [
|
||||
Bar::new(1f64,1.0),
|
||||
Bar::new(2f64, 0.5),
|
||||
Bar::new(4f64, 0.25),
|
||||
Bar::new(8f64,0.125),
|
||||
Bar::new(16f64, 0.0625),
|
||||
Bar::new(32f64, 0.03125),
|
||||
Bar::new(64f64, 0.015625),
|
||||
Bar::new(128f64, 0.0078125),
|
||||
Bar::new(256f64, 0.00390625),
|
||||
Bar::new(512f64, 0.001953125),
|
||||
Bar::new(1024f64,0.000976562),
|
||||
],
|
||||
names: [
|
||||
"Powering infrastructure",
|
||||
"Dusting ServicePoint",
|
||||
"Activating colorful lights",
|
||||
"Dimming darkroom",
|
||||
"Refilling Matemat",
|
||||
"Pre-heating convectiomat",
|
||||
"Resetting chair heights",
|
||||
"Cleaning 'block chain'",
|
||||
"Refilling sticker box",
|
||||
"Setting room to public",
|
||||
"Welcoming creatures",
|
||||
Bar::new(1f64, 1.0, "Powering infrastructure"),
|
||||
Bar::new(2f64, 0.5, "Dusting ServicePoint"),
|
||||
Bar::new(4f64, 0.25, "Activating colorful lights"),
|
||||
Bar::new(8f64, 0.125, "Dimming darkroom"),
|
||||
Bar::new(16f64, 0.0625, "Refilling Matemat"),
|
||||
Bar::new(32f64, 0.03125, "Pre-heating convectiomat"),
|
||||
Bar::new(64f64, 0.015625, "Resetting chair heights"),
|
||||
Bar::new(128f64, 0.0078125, "Untangling 'block chain'"),
|
||||
Bar::new(256f64, 0.00390625, "Refilling sticker box"),
|
||||
Bar::new(512f64, 0.001953125, "Setting room to public"),
|
||||
Bar::new(1024f64, 0.000976562, "Welcoming creatures"),
|
||||
],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Progressable for Game {
|
||||
fn progress(&self, delta: Duration) -> (Self, Currency) {
|
||||
let mut currency = self.currency;
|
||||
let bars = self.bars.clone().map(|bar| {
|
||||
let (bar, curr) = bar.progress(delta);
|
||||
currency += curr;
|
||||
bar
|
||||
});
|
||||
pub(crate) fn progress(&mut self, delta: Duration) {
|
||||
let adjusted_delta = delta.mul_f64(self.global_speed);
|
||||
|
||||
(
|
||||
Self {
|
||||
currency,
|
||||
bars,
|
||||
names: self.names,
|
||||
},
|
||||
0f64,
|
||||
)
|
||||
self.currency += self.global_productivity
|
||||
* self
|
||||
.bars
|
||||
.iter_mut()
|
||||
.map(|bar| bar.progress(adjusted_delta))
|
||||
.sum::<Currency>();
|
||||
|
||||
if let Some(next_upgrade) = self.unlock_queue.front() {
|
||||
if next_upgrade.cost <= self.currency {
|
||||
log::info!("Applying upgrade {:?}", next_upgrade);
|
||||
let next_upgrade = self.unlock_queue.pop_front().unwrap();
|
||||
self.currency -= next_upgrade.cost;
|
||||
(next_upgrade.apply)(self);
|
||||
self.unlocks += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Game {
|
||||
pub fn draw(&self, text_layer: &mut WindowMut<char, CharGrid>, pixel_layer: &mut WindowMut<bool, Bitmap>) {
|
||||
text_layer.set_row_str(0, "Discordia Boot Procedure").unwrap();
|
||||
pub(crate) fn draw(
|
||||
&self,
|
||||
text_layer: &mut WindowMut<char, CharGrid>,
|
||||
pixel_layer: &mut WindowMut<bool, Bitmap>,
|
||||
) {
|
||||
text_layer
|
||||
.set_row_str(0, "Discordia Boot Procedure")
|
||||
.unwrap();
|
||||
let middle = text_layer.width() / 2;
|
||||
text_layer.window_mut( middle, 0, middle, 1)
|
||||
text_layer
|
||||
.window_mut(middle, 0, middle, 1)
|
||||
.unwrap()
|
||||
.set_row_str(0, &format!(" Cycles: {}", self.currency.floor()))
|
||||
.set_row_str(0, &format!(" Completions: {}", self.currency.floor()))
|
||||
.unwrap();
|
||||
|
||||
for (index, bar) in self.bars.iter().enumerate() {
|
||||
let row = 1 + index;
|
||||
let mut bar_window = pixel_layer.window_mut(0, row * TILE_SIZE, pixel_layer.width() / 2, TILE_SIZE).unwrap();
|
||||
let mut label_window = text_layer.window_mut(middle, row, middle, 1).unwrap();
|
||||
let row = 2 + index;
|
||||
let mut bar_window = pixel_layer
|
||||
.window_mut(0, row * TILE_SIZE, pixel_layer.width(), TILE_SIZE)
|
||||
.unwrap();
|
||||
let mut label_window = text_layer
|
||||
.window_mut(0, row, text_layer.width(), 1)
|
||||
.unwrap();
|
||||
bar.draw(&mut label_window, &mut bar_window);
|
||||
}
|
||||
|
||||
if !bar.is_enabled() {
|
||||
continue;
|
||||
}
|
||||
if let Some(next_upgrade) = self.unlock_queue.front() {
|
||||
text_layer
|
||||
.window_mut(0, text_layer.height() - 2, text_layer.width(), 1)
|
||||
.unwrap()
|
||||
.set_row_str(
|
||||
0,
|
||||
&format!("Next unlock: {} {}", next_upgrade.cost, next_upgrade.name),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
bar.draw(&mut bar_window);
|
||||
label_window.set_row_str(0, self.names[index]).unwrap();
|
||||
text_layer
|
||||
.window_mut(0, text_layer.height() - 1, text_layer.width() / 2, 1)
|
||||
.unwrap()
|
||||
.set_row_str(0, &format!("Score: {}", self.total_currency))
|
||||
.unwrap();
|
||||
|
||||
if self.unlocks > 0 {
|
||||
text_layer
|
||||
.window_mut(
|
||||
text_layer.width() / 2,
|
||||
text_layer.height() - 1,
|
||||
text_layer.width() / 2,
|
||||
1,
|
||||
)
|
||||
.unwrap()
|
||||
.set_row_str(0, &format!(" Unlocks: {}", self.unlocks))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
38
src/main.rs
38
src/main.rs
|
|
@ -1,13 +1,17 @@
|
|||
use game::Game;
|
||||
use servicepoint::{BinaryOperation, BitVecCommand, Bitmap, CharGrid, CharGridCommand, ClearCommand, CompressionCode, UdpSocketExt, FRAME_PACING, TILE_HEIGHT, TILE_WIDTH};
|
||||
use servicepoint::{
|
||||
BinaryOperation, BitVecCommand, Bitmap, CharGrid, CharGridCommand, ClearCommand,
|
||||
CompressionCode, FRAME_PACING, TILE_HEIGHT, TILE_WIDTH, UdpSocketExt,
|
||||
};
|
||||
use std::{
|
||||
net::UdpSocket,
|
||||
thread::sleep,
|
||||
time::{Duration, Instant}
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
mod bar;
|
||||
mod game;
|
||||
mod upgrades;
|
||||
|
||||
type Currency = f64;
|
||||
|
||||
|
|
@ -20,6 +24,8 @@ const DESTINATION: &str = "127.0.0.1:2342";
|
|||
//const DESTINATION: &str = "172.23.42.29:2342";
|
||||
|
||||
fn main() {
|
||||
env_logger::init();
|
||||
|
||||
let mut state = Game::new();
|
||||
let connection = UdpSocket::bind_connect(DESTINATION).unwrap();
|
||||
connection.send_command(ClearCommand);
|
||||
|
|
@ -33,22 +39,30 @@ fn main() {
|
|||
let delta = current_time - last_refresh;
|
||||
last_refresh = current_time;
|
||||
|
||||
(state, _) = state.progress(delta);
|
||||
state.progress(delta);
|
||||
|
||||
chars.fill(' ');
|
||||
pixels.fill(false);
|
||||
|
||||
let mut chars_view = chars.window_mut(0, 0, chars.width(), chars.height()).unwrap();
|
||||
let mut pixels_view = pixels.window_mut(0,0,pixels.width(), pixels.height()).unwrap();
|
||||
let mut chars_view = chars
|
||||
.window_mut(0, 0, chars.width(), chars.height())
|
||||
.unwrap();
|
||||
let mut pixels_view = pixels
|
||||
.window_mut(0, 0, pixels.width(), pixels.height())
|
||||
.unwrap();
|
||||
state.draw(&mut chars_view, &mut 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();
|
||||
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);
|
||||
}
|
||||
|
|
|
|||
123
src/upgrades.rs
Normal file
123
src/upgrades.rs
Normal file
|
|
@ -0,0 +1,123 @@
|
|||
use crate::Currency;
|
||||
use crate::game::Game;
|
||||
use std::collections::VecDeque;
|
||||
use std::fmt::{Debug, Formatter, Write};
|
||||
|
||||
pub(crate) struct Upgrade {
|
||||
pub(crate) name: &'static str,
|
||||
pub(crate) cost: Currency,
|
||||
pub(crate) apply: Box<dyn Fn(&mut Game)>,
|
||||
}
|
||||
|
||||
impl Debug for Upgrade {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.write_fmt(format_args!(
|
||||
"Upgrade {{ name: {:?}, cost: {:?} }}",
|
||||
self.name, self.cost
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn get_upgrades() -> VecDeque<Upgrade> {
|
||||
vec![
|
||||
Upgrade {
|
||||
name: "Start Powering infrastructure",
|
||||
cost: 0f64,
|
||||
apply: Box::new(|game| {
|
||||
game.bars[0].enabled = true;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "More power",
|
||||
cost: 10f64,
|
||||
apply: Box::new(|game| {
|
||||
game.bars[0].productivity *= 2.0;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "",
|
||||
cost: 23f64,
|
||||
apply: Box::new(|game| {
|
||||
game.global_productivity *= 1.1;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "The answer",
|
||||
cost: 42f64,
|
||||
apply: Box::new(|game| {
|
||||
game.global_speed *= 1.1;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "Start Dusting ServicePoint",
|
||||
cost: 64f64,
|
||||
apply: Box::new(|game| {
|
||||
game.bars[1].enabled = true;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "Start Activating colorful lights",
|
||||
cost: 256f64,
|
||||
apply: Box::new(|game| {
|
||||
game.bars[2].enabled = true;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "Start Dimming darkroom",
|
||||
cost: 1024f64,
|
||||
apply: Box::new(|game| {
|
||||
game.bars[3].enabled = true;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "Start Refilling Matemat",
|
||||
cost: 4096f64,
|
||||
apply: Box::new(|game| {
|
||||
game.bars[4].enabled = true;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "Start Pre-heating convectiomat",
|
||||
cost: 16384f64,
|
||||
apply: Box::new(|game| {
|
||||
game.bars[5].enabled = true;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "Start Resetting chair heights",
|
||||
cost: 65536f64,
|
||||
apply: Box::new(|game| {
|
||||
game.bars[6].enabled = true;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "Start Untangling 'block chain'",
|
||||
cost: 262144f64,
|
||||
apply: Box::new(|game| {
|
||||
game.bars[7].enabled = true;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "Start Refilling sticker box",
|
||||
cost: 1048576f64,
|
||||
apply: Box::new(|game| {
|
||||
game.bars[8].enabled = true;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "Start Setting room to public",
|
||||
cost: 4194304f64,
|
||||
apply: Box::new(|game| {
|
||||
game.bars[9].enabled = true;
|
||||
}),
|
||||
},
|
||||
Upgrade {
|
||||
name: "Start Welcoming creatures",
|
||||
cost: 16777216f64,
|
||||
apply: Box::new(|game| {
|
||||
game.bars[10].enabled = true;
|
||||
}),
|
||||
},
|
||||
]
|
||||
.into()
|
||||
}
|
||||
Loading…
Reference in a new issue