Skip to content

Commit 88bfc60

Browse files
authored
Merge pull request #75 from genonullfree/feature/buy-max
Feature/buy max
2 parents 37100f1 + c184923 commit 88bfc60

File tree

6 files changed

+190
-61
lines changed

6 files changed

+190
-61
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "idlecoin"
3-
version = "0.4.3"
3+
version = "0.4.4"
44
edition = "2021"
55

66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

README.md

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,7 @@ This is an idle game where the point is to open a netcat connection to the serve
1313

1414
The game has evolved to become semi-interactive, as there is now an element of purchasing upgrades to improve the performance of your miners, but this is entirely optional.
1515

16-
## Use
17-
18-
To start, run the `idlecoin` server:
19-
```rust
20-
cargo run --release
21-
```
16+
## Start Client Miner
2217

2318
To join a server, use `netcat` or `telnet` to connect to the server:
2419
```bash
@@ -28,9 +23,16 @@ nc 127.0.0.1 7654
2823
telnet localhost 7654
2924
```
3025

26+
## Start Server
27+
28+
To start, run the `idlecoin` server:
29+
```rust
30+
cargo run --release
31+
```
32+
3133
The stats are written out to a file `.idlecoin` in the working directory of the server upon exit. On start, `idlecoin` will attempt to open `.idlecoin` and ingest the stats file to allow loading of previous stats. The stats file will currently autosave every 5 minutes.
3234

33-
## Output
35+
## Client Output
3436

3537
```
3638
[007] Wallet 0x9d75d7d276240c38 Miner Licenses: 5 Chronocoin: 8850 Randocoin: 208 Coins: 0:24436823427358 Total Cps: 10
@@ -103,9 +105,9 @@ These events are newest on top, and only the most recent 5 are displayed.
103105

104106
These events can be a mix of users purchasing upgrades for their miners or special random events that can happen:
105107

106-
1. Gain 10% CPS -- 0.01% chance
107-
1. Gain 1 Level -- 0.02% chance
108-
1. Lose 1 Level -- 0.01% chance
108+
1. Gain 10% CPS -- 0.001% chance
109+
1. Gain 1 Level -- 0.002% chance
110+
1. Lose 1 Level -- 0.001% chance
109111
1. IRS auditing -- 0.00000006430041152263% chance
110112

111113
### Purchasing Upgrades

src/commands.rs

Lines changed: 149 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use crate::*;
22
use std::collections::HashMap;
3+
use std::ops::AddAssign;
34

45
#[derive(PartialEq, Eq, Hash)]
56
enum PurchaseType {
@@ -14,6 +15,21 @@ struct Purchase {
1415
cost: u128,
1516
}
1617

18+
impl Purchase {
19+
fn new() -> Self {
20+
Purchase { bought: 0, cost: 0 }
21+
}
22+
}
23+
24+
impl AddAssign for Purchase {
25+
fn add_assign(&mut self, other: Self) {
26+
*self = Self {
27+
bought: self.bought + other.bought,
28+
cost: self.cost + other.cost,
29+
};
30+
}
31+
}
32+
1733
pub fn read_inputs(
1834
connections: &Arc<Mutex<Vec<Connection>>>,
1935
wallets: &Arc<Mutex<Vec<Wallet>>>,
@@ -46,54 +62,51 @@ pub fn read_inputs(
4662
let new = match *i {
4763
b'b' => {
4864
// Purchase boost
49-
let cost = match buy_boost(c, w) {
50-
Ok(c) => c,
65+
match buy_boost(c, w) {
66+
Ok(c) => Some(c),
5167
Err(e) => {
5268
if !c.updates.iter().any(|u| *u == e.to_string()) {
5369
c.updates.push(e.to_string());
5470
}
5571
continue;
5672
}
57-
};
58-
let new = Purchase {
59-
bought: 128,
60-
cost: cost as u128,
61-
};
62-
Some((PurchaseType::Boost, new))
73+
}
74+
}
75+
b'B' => {
76+
// Purchase MAX boost
77+
buy_max_boost(c, w)
6378
}
6479
b'm' => {
6580
// Purchase miner licenses
66-
let cost = match buy_miner(w) {
67-
Ok(c) => c,
81+
match buy_miner(w) {
82+
Ok(c) => Some(c),
6883
Err(e) => {
6984
if !c.updates.iter().any(|u| *u == e.to_string()) {
7085
c.updates.push(e.to_string());
7186
}
7287
continue;
7388
}
74-
};
75-
let new = Purchase {
76-
bought: 1,
77-
cost: cost as u128,
78-
};
79-
Some((PurchaseType::Miner, new))
89+
}
90+
}
91+
b'M' => {
92+
// Purchase MAX miners
93+
buy_max_miner(w)
8094
}
8195
b'c' => {
8296
// Purchase time travel
83-
let cost = match buy_time(c, w) {
84-
Ok(c) => c,
97+
match buy_time(c, w) {
98+
Ok(c) => Some(c),
8599
Err(e) => {
86100
if !c.updates.iter().any(|u| *u == e.to_string()) {
87101
c.updates.push(e.to_string());
88102
}
89103
continue;
90104
}
91-
};
92-
let new = Purchase {
93-
bought: 1,
94-
cost: cost as u128,
95-
};
96-
Some((PurchaseType::Chrono, new))
105+
}
106+
}
107+
b'C' => {
108+
// Purchase MAX time travel
109+
buy_max_time(c, w)
97110
}
98111
_ => None,
99112
};
@@ -108,6 +121,12 @@ pub fn read_inputs(
108121
// Purchase notification updates
109122
for (k, p) in upgrades.iter() {
110123
let t: DateTime<Local> = Local::now();
124+
125+
// Skip if nothing was purchased
126+
if p.cost == 0 {
127+
continue;
128+
}
129+
111130
match k {
112131
PurchaseType::Boost => msg.insert(
113132
0,
@@ -152,8 +171,7 @@ fn update_upgrade_list(
152171
Some(n) => *n,
153172
None => Purchase { bought: 0, cost: 0 },
154173
};
155-
node.bought += p.bought;
156-
node.cost += p.cost;
174+
node += p;
157175
map.insert(p_type, node);
158176
}
159177

@@ -162,14 +180,23 @@ pub fn boost_cost(cps: u64) -> u64 {
162180
1u64.checked_shl(v).unwrap_or(0)
163181
}
164182

165-
fn buy_boost(connection: &mut Connection, wallet: &mut Wallet) -> Result<u64, Error> {
183+
pub fn boost_max_cost(cps: u64, boost: u64) -> u64 {
184+
let cost = boost_cost(cps);
185+
let left = (u16::MAX as u64 - boost) / 128;
186+
cost * left
187+
}
188+
189+
fn buy_boost(
190+
connection: &mut Connection,
191+
wallet: &mut Wallet,
192+
) -> Result<(PurchaseType, Purchase), Error> {
166193
if connection.miner.cps < 1024 {
167194
return Err(Error::new(
168195
ErrorKind::InvalidData,
169196
"You need at least 1024 Cps to be able to purchase boost\n",
170197
));
171198
}
172-
if connection.miner.boost > u16::MAX as u64 {
199+
if connection.miner.boost >= u16::MAX as u64 - 128 {
173200
return Err(Error::new(
174201
ErrorKind::InvalidData,
175202
"You cannot purchase any more boost right now\n",
@@ -182,9 +209,35 @@ fn buy_boost(connection: &mut Connection, wallet: &mut Wallet) -> Result<u64, Er
182209
format!("You need {} idlecoins to purchase boost\n", cost),
183210
));
184211
}
185-
connection.miner.boost = connection.miner.boost.saturating_add(128);
212+
let bought: usize = 128;
213+
connection.miner.boost = connection.miner.boost.saturating_add(bought as u64);
214+
if connection.miner.boost > u16::MAX as u64 {
215+
connection.miner.boost = u16::MAX as u64;
216+
}
186217

187-
Ok(cost)
218+
Ok((
219+
PurchaseType::Boost,
220+
Purchase {
221+
bought,
222+
cost: cost as u128,
223+
},
224+
))
225+
}
226+
227+
fn buy_max_boost(
228+
connection: &mut Connection,
229+
wallet: &mut Wallet,
230+
) -> Option<(PurchaseType, Purchase)> {
231+
let mut totals = Purchase::new();
232+
233+
loop {
234+
let (_, p) = match buy_boost(connection, wallet) {
235+
Ok(b) => b,
236+
Err(_) => return Some((PurchaseType::Boost, totals)),
237+
};
238+
239+
totals += p;
240+
}
188241
}
189242

190243
pub fn miner_cost(max_miners: u64) -> u64 {
@@ -195,7 +248,21 @@ pub fn miner_cost(max_miners: u64) -> u64 {
195248
}
196249
}
197250

198-
fn buy_miner(mut wallet: &mut Wallet) -> Result<u64, Error> {
251+
pub fn miner_max_cost(max_miners: u64) -> u128 {
252+
let mut max = max_miners;
253+
let mut cost = 0u128;
254+
loop {
255+
if max <= ABS_MAX_MINERS {
256+
cost += miner_cost(max) as u128;
257+
max += 1;
258+
} else {
259+
break;
260+
}
261+
}
262+
cost
263+
}
264+
265+
fn buy_miner(mut wallet: &mut Wallet) -> Result<(PurchaseType, Purchase), Error> {
199266
if wallet.max_miners >= ABS_MAX_MINERS {
200267
return Err(Error::new(
201268
ErrorKind::InvalidData,
@@ -212,14 +279,40 @@ fn buy_miner(mut wallet: &mut Wallet) -> Result<u64, Error> {
212279
};
213280
wallet.max_miners += 1;
214281

215-
Ok(cost)
282+
Ok((
283+
PurchaseType::Miner,
284+
Purchase {
285+
bought: 1,
286+
cost: cost as u128,
287+
},
288+
))
289+
}
290+
291+
fn buy_max_miner(wallet: &mut Wallet) -> Option<(PurchaseType, Purchase)> {
292+
let mut totals = Purchase::new();
293+
294+
loop {
295+
let (_, p) = match buy_miner(wallet) {
296+
Ok(m) => m,
297+
Err(_) => return Some((PurchaseType::Miner, totals)),
298+
};
299+
300+
totals += p;
301+
}
216302
}
217303

218304
pub fn time_cost() -> u64 {
219305
1000
220306
}
221307

222-
fn buy_time(connection: &mut Connection, wallet: &mut Wallet) -> Result<u64, Error> {
308+
pub fn time_max_cost(chrono: u64) -> u64 {
309+
(chrono / 1000) * 1000
310+
}
311+
312+
fn buy_time(
313+
connection: &mut Connection,
314+
wallet: &mut Wallet,
315+
) -> Result<(PurchaseType, Purchase), Error> {
223316
if wallet.sub_chronocoins(time_cost()).is_err() {
224317
return Err(Error::new(
225318
ErrorKind::InvalidData,
@@ -236,5 +329,27 @@ fn buy_time(connection: &mut Connection, wallet: &mut Wallet) -> Result<u64, Err
236329
}
237330
}
238331

239-
Ok(time_cost())
332+
Ok((
333+
PurchaseType::Chrono,
334+
Purchase {
335+
bought: 1,
336+
cost: time_cost() as u128,
337+
},
338+
))
339+
}
340+
341+
fn buy_max_time(
342+
connection: &mut Connection,
343+
wallet: &mut Wallet,
344+
) -> Option<(PurchaseType, Purchase)> {
345+
let mut totals = Purchase::new();
346+
347+
loop {
348+
let (_, p) = match buy_time(connection, wallet) {
349+
Ok(t) => t,
350+
Err(_) => return Some((PurchaseType::Chrono, totals)),
351+
};
352+
353+
totals += p;
354+
}
240355
}

src/main.rs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ fn main() -> Result<(), Error> {
150150
}
151151
};
152152

153+
// Set write timeout
154+
match s.set_write_timeout(Some(Duration::from_millis(500))) {
155+
Ok(_) => (),
156+
Err(e) => {
157+
println!("Unable to set write timeout: {e}");
158+
continue;
159+
}
160+
};
161+
153162
let updates = vec![format!(
154163
"\nLogged in as Wallet: {}0x{:016x}{} Miner: {}0x{:08x}{}\n",
155164
PURPLE, miner.wallet_id, RST, BLUE, miner.miner_id, RST
@@ -386,8 +395,11 @@ fn print_wallets(
386395
if c.miner.cps > 1024 {
387396
c.purchases.push(
388397
format!(
389-
"'b'<enter>\tPurchase 128 seconds of Miner Boost for {} idlecoin\n",
390-
commands::boost_cost(c.miner.cps)
398+
"{}b{}: Purchase 128 seconds of Miner Boost for {} idlecoin / {}B{}: Purchase Max for {} idlecoin\n",
399+
RED, RST,
400+
commands::boost_cost(c.miner.cps),
401+
RED, RST,
402+
commands::boost_max_cost(c.miner.cps, c.miner.boost),
391403
)
392404
.to_string(),
393405
);
@@ -396,13 +408,13 @@ fn print_wallets(
396408
if g.max_miners < ABS_MAX_MINERS && (g.idlecoin > miner_cost || g.supercoin > 1)
397409
{
398410
c.purchases.push(format!(
399-
"'m'<enter>\tPurchase 1 Miner License for {} idlecoin\n",
400-
miner_cost
411+
"{}m{}: Purchase 1 Miner License for {} idlecoin\n",
412+
RED, RST, miner_cost
401413
));
402414
}
403415
}
404416
if g.chronocoin > commands::time_cost() {
405-
c.purchases.push(format!("'c'<enter>\tPurchase 60m of time travel for this miner for {} chronocoins\n", commands::time_cost()));
417+
c.purchases.push(format!("{}c{}: Purchase 1 hour of time travel for this miner for {} chronocoin / {}C{}: Purchase Max for {} chronocoin\n", RED, RST,commands::time_cost(), RED, RST,commands::time_max_cost(g.chronocoin)));
406418
}
407419

408420
// Build miner display

0 commit comments

Comments
 (0)