Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
61f79c0
feat(tree): infinite procedural upgrade tree
flipbit03 May 15, 2026
72de9ae
fix(tree): SpawnRateMul polarity matches its name
flipbit03 May 15, 2026
030f252
fix(tree): harvest centers on the viewport, not the cursor
flipbit03 May 15, 2026
33009b6
feat(tree): replace 10-slot bookmarks with [0] root / [1] last bought
flipbit03 May 15, 2026
49ebb51
feat(tree): hover-fill the buy / refund button in the info pane
flipbit03 May 15, 2026
3675783
feat(tree): wire-energizing animation on buy
flipbit03 May 15, 2026
1720eb3
fix(tree): snake-game energize — dim ahead, lit behind the head
flipbit03 May 15, 2026
be0c8fb
tune(tree): snake wavefront at 20 cells/sec (50 ms per cell)
flipbit03 May 15, 2026
ff7acf2
tune(tree): snake wavefront at 40 cells/sec (2 cells/tick)
flipbit03 May 15, 2026
99c8d01
fix(tree): animate all edges + zero per-direction lag
flipbit03 May 15, 2026
4dd4367
fix(tree): canonical edge path so wave overlays the resting line
flipbit03 May 15, 2026
b8ad12b
polish(tree): tighter anchor info-pane copy
flipbit03 May 15, 2026
1107a80
tune(tree): NODE_COST_MULT 1.0 -> 5.0
flipbit03 May 15, 2026
234e2d5
tune(tree): NODE_COST_GROWTH knob + bump 1.45 -> 1.65
flipbit03 May 15, 2026
90eb8eb
test(tree): dump_cost_table diagnostic for ramp tuning
flipbit03 May 15, 2026
e8ccf72
tune(tree): NODE_COST_GROWTH 1.65 -> 1.75
flipbit03 May 15, 2026
1ae6e37
fix(tree): address full review findings
flipbit03 May 15, 2026
0d71bed
fix(tree): suppress diagonal edges that close orthogonal triangles
flipbit03 May 15, 2026
290bbdf
fix(tree): suppress triangles using anchor-only redundancy, not diago…
flipbit03 May 15, 2026
d6f036a
fix(tree): suppress orphan islands by walking anchor chain to origin
flipbit03 May 15, 2026
8507689
Revert "triangle suppression + orphan-island cleanup" series
flipbit03 May 15, 2026
f2b7f76
fix(tree): address adversarial review #2 findings
flipbit03 May 15, 2026
8a84b6e
fix(prestige): drop the 1M paper cap, keep only finite/non-negative g…
flipbit03 May 16, 2026
bb7e0d8
feat(prestige): two-step confirmation before reset
flipbit03 May 16, 2026
1a887f2
polish(prestige): drop underline + add row of breathing space between…
flipbit03 May 16, 2026
cf74546
fix(prestige): shorten confirm-warning so it fits without soft-wrap
flipbit03 May 16, 2026
1aa167a
fix(prestige): structural fix for click-rect off-by-one + cleanup
flipbit03 May 16, 2026
bb2a58b
polish(prestige): drop [r] reset & claim from help bar when unavailable
flipbit03 May 16, 2026
ee0b76e
fix(prestige): [r] only arms, never confirms — kill double-tap hazard
flipbit03 May 16, 2026
9d3f099
fix(prestige): drop bottom-left [r] reset & claim help-bar token
flipbit03 May 16, 2026
24baf90
fix(docs): escape `[X]` in rustdoc comments to dodge intra-doc-link p…
flipbit03 May 16, 2026
771f7a5
fix(wasm): hoist prestige_confirm_pending past split-borrow on web.ui
flipbit03 May 16, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 76 additions & 15 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ use crate::game::fingerer;
use crate::game::fingerer::FINGERERS;
use crate::game::powerup::{self, Powerup, PowerupKind};
use crate::game::state::{GameState, TICK_HZ};
use crate::game::upgrade::UPGRADES;
use crate::game::tree::coord::TreeCoord;
use crate::input::{
self, InputContext, InputEvent, KeyCode as InKeyCode, Modifiers, MouseButton as InMouseButton,
UiState, WheelDelta,
Expand Down Expand Up @@ -147,13 +147,23 @@ impl App {

let current = snapshot.load_full();
terminal.draw(|f| {
layout = ui::draw(f, &current, ui.mode, ui.zoom_idx, debug, ui.last_mouse_pos);
layout = ui::draw(
f,
&current,
ui.mode,
ui.zoom_idx,
debug,
ui.last_mouse_pos,
&mut ui.tree_render,
ui.prestige_confirm_pending,
);
})?;

// Hand fresh geometry to the sim. Ordering is preserved by mpsc,
// so the sim always uses the most recently drawn layout.
let _ = action_tx.send(Action::UpdateGeometry {
biscuit: layout.biscuit_rect,
powerups_paused: ui.mode == Mode::Tree,
});

if event::poll(Duration::from_millis(INPUT_POLL_MS))? {
Expand Down Expand Up @@ -334,14 +344,39 @@ fn demo_driver_tick(
}
}

// Every ~8s, buy the cheapest available upgrade.
// Every ~8s, try to buy a reachable affordable tree node. Walk the
// king-neighbor ring around every owned lot and pick the cheapest
// hit; gives the demo a steady visible tree-spread without needing
// to plan a route.
if t.is_multiple_of(160) {
let available = crate::game::upgrade::available_ids(state);
if let Some(&u_idx) = available
.iter()
.min_by(|&&a, &&b| UPGRADES[a].cost.partial_cmp(&UPGRADES[b].cost).unwrap())
{
state.buy_upgrade(u_idx);
let mut best: Option<(TreeCoord, f64)> = None;
for &owned in &state.tree.bought {
for n in crate::game::tree::node::neighbors_of(owned) {
if state.tree.bought.contains(&n) {
continue;
}
if !crate::game::tree::node::edge_exists(owned, n) {
continue;
}
if let Some(spec) = crate::game::tree::node::node_at(n.x, n.y)
&& state.affordable_cuques() >= spec.cost
{
let cost = spec.cost;
if best.map(|(_, c)| cost < c).unwrap_or(true) {
best = Some((n, cost));
}
}
}
}
// First buy: origin (no neighbors to walk).
if state.tree.bought.is_empty() {
if let Some(spec) = crate::game::tree::node::node_at(0, 0)
&& state.affordable_cuques() >= spec.cost
{
state.buy_tree_node(TreeCoord::ORIGIN);
}
} else if let Some((lot, _)) = best {
state.buy_tree_node(lot);
}
}

Expand All @@ -352,7 +387,7 @@ fn demo_driver_tick(
} else if phase == 140 {
Some(Mode::Achievements)
} else if phase == 180 {
Some(Mode::Upgrades)
Some(Mode::Tree)
} else if phase == 220 {
Some(Mode::Game)
} else {
Expand Down Expand Up @@ -395,6 +430,11 @@ fn translate_key_code(code: CtKeyCode) -> Option<InKeyCode> {
CtKeyCode::Char(c) => Some(InKeyCode::Char(c)),
CtKeyCode::Esc => Some(InKeyCode::Esc),
CtKeyCode::F(n) => Some(InKeyCode::F(n)),
CtKeyCode::Up => Some(InKeyCode::Up),
CtKeyCode::Down => Some(InKeyCode::Down),
CtKeyCode::Left => Some(InKeyCode::Left),
CtKeyCode::Right => Some(InKeyCode::Right),
CtKeyCode::Enter => Some(InKeyCode::Enter),
_ => None,
}
}
Expand Down Expand Up @@ -428,6 +468,11 @@ fn translate_mouse(m: CtMouseEvent) -> Option<InputEvent> {
button: translate_mouse_button(button)?,
mods,
}),
MouseEventKind::Up(button) => Some(InputEvent::MouseUp {
col: m.column,
row: m.row,
button: translate_mouse_button(button)?,
}),
MouseEventKind::ScrollUp => Some(InputEvent::Wheel {
col: m.column,
row: m.row,
Expand Down Expand Up @@ -493,11 +538,27 @@ pub fn build_demo_state() -> GameState {
s.fingerers_state.entry(f.id.to_string()).or_default().count = count;
}
}
// Take the first 10 upgrades from the catalog (deterministic regardless
// of how UPGRADES is reordered) — gives a spread of click + per-tier
// multipliers so the sidebar shows (xN) on several tiers.
for u in UPGRADES.iter().take(10) {
s.upgrades_earned.insert(u.id.to_string());
// Seed a small starter cluster of tree nodes around the origin so the
// demo HUD has the same "look how stacked I am" vibe the old upgrade
// grant gave. We do this through the live state's buy path (which
// folds the aggregate) but bypass the cost gate by zero-ing the cost
// — demo build_state is rich-by-construction, not by progression.
for lot in [
TreeCoord::ORIGIN,
TreeCoord::new(1, 0),
TreeCoord::new(0, 1),
TreeCoord::new(-1, 0),
TreeCoord::new(0, -1),
TreeCoord::new(1, 1),
TreeCoord::new(-1, -1),
] {
if let Some(spec) = crate::game::tree::node::node_at(lot.x, lot.y) {
// Connectivity guard relaxed for demo seeding — we want a
// tight cluster regardless of edge rolls. Manually add to
// `bought` + fold the aggregate.
s.tree.bought.insert(lot);
s.tree_aggregate.fold_in_node(&spec);
}
}
// First 6 achievements for visual variety in that panel.
for a in ACHIEVEMENTS.iter().take(6) {
Expand Down
2 changes: 1 addition & 1 deletion src/game/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ pub mod fingerer;
pub mod modifier;
pub mod powerup;
pub mod state;
pub mod upgrade;
pub mod tree;
Loading
Loading