Statistics with a chart at the end of a game, 64 achievements kept locally and on the server

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Richard ZinkandClaude Opus 5.5 committed 2026-11-05 23:36:19 +01:00
1 parent 193b199875
commit 9931ca9b54
37 files changed
+1833 -4

No files matched your search

+38 -3
View File
@@ -1334,7 +1334,10 @@ impl Ui {
}
lines.extend(wrap(para, tw));
}
let rows = 9 + lines.len() as i32;
// the chart of the game (gold, creatures, army) when there are a few samples
let chart = g.stats.samples.len() >= 3 && sh > CH() * (22.0 + lines.len() as f32);
let chart_rows = if chart { 10 } else { 0 };
let rows = 9 + lines.len() as i32 + chart_rows;
let x = grid_center(sw, cols as f32 * CW());
let y = grid_center_y(sh, rows as f32 * CH()).max(0.0);
let col = if win { GOLD } else { RED };
@@ -1347,6 +1350,38 @@ impl Ui {
}
let st = trf("end.stats", &[mmss(g.time), g.wave.to_string(), (g.army_value() as i32).to_string()]);
gfx.text(&st, grid_center(sw, gfx.measure(&st, S())), y + CH() * (4.5 + lines.len() as f32), S(), DIM);
if chart {
use crate::stats as k;
let cy = y + CH() * (6.0 + lines.len() as f32);
let c = &g.stats;
let line2 = trf("end.stats2", &[(c.get(k::HEROES) as i32).to_string(), (c.get(k::LOST) as i32).to_string(), (c.get(k::DUG) as i32).to_string(), (c.get(k::GOLD) as i32).to_string(), (c.get(k::WOOD) as i32).to_string()]);
gfx.text(&line2, grid_center(sw, gfx.measure(&line2, SMALL())), cy, SMALL(), DIM);
// three lines, each scaled to its own maximum
let (px, py, pw, ph) = (x + CW() * 3.0, cy + CH() * 1.2, (cols - 6) as f32 * CW(), CH() * 6.0);
draw_rectangle(px, py, pw, ph, Color::new(0.0, 0.0, 0.0, 0.35));
draw_rectangle_lines(px, py, pw, ph, 1.0, Color::new(0.4, 0.3, 0.2, 1.0));
let n = c.samples.len();
let t_end = c.samples[n - 1].0.max(1.0);
let series: [(Box<dyn Fn(&(f32, f32, u16, f32)) -> f32>, Color); 3] = [(Box::new(|s| s.1), GOLD), (Box::new(|s| s.2 as f32), GREEN), (Box::new(|s| s.3), RED)];
for (f, col) in series.iter() {
let max = c.samples.iter().map(|s| f(s)).fold(1.0f32, f32::max);
for w in c.samples.windows(2) {
let (a, b) = (&w[0], &w[1]);
let p = |s: &(f32, f32, u16, f32)| (px + pw * (s.0 / t_end), py + ph - ph * 0.92 * (f(s) / max));
let (x0, y0) = p(a);
let (x1, y1) = p(b);
draw_line(x0, y0, x1, y1, 2.0 * K(), *col);
}
}
let legend = format!("{} {} {}", tr("hud.gold"), tr("hud.creatures"), tr("hud.army"));
let lx = px + CW();
gfx.text(&tr("hud.gold"), lx, py + ph + CH() * 0.3, SMALL(), GOLD);
let w1 = gfx.measure(&format!("{} ", tr("hud.gold")), SMALL());
gfx.text(&tr("hud.creatures"), lx + w1, py + ph + CH() * 0.3, SMALL(), GREEN);
let w2 = gfx.measure(&format!("{} {} ", tr("hud.gold"), tr("hud.creatures")), SMALL());
gfx.text(&tr("hud.army"), lx + w2, py + ph + CH() * 0.3, SMALL(), RED);
let _ = legend;
}
// buttons: free game: new game; mission: next / again and back to the campaign
let labels: Vec<(String, u8)> = match (mission, self.coop_end) {
// an editor campaign in co-op: the host goes on for everybody, the others wait or leave
@@ -1359,10 +1394,10 @@ impl Ui {
if let Some((host, true, sent)) = self.coop_end {
if !host || sent {
let t = tr("net.coop_wait_host");
gfx.text(&t, grid_center(sw, gfx.measure(&t, SMALL())), y + CH() * (5.3 + lines.len() as f32), SMALL(), GOLD);
gfx.text(&t, grid_center(sw, gfx.measure(&t, SMALL())), y + CH() * (5.3 + lines.len() as f32 + chart_rows as f32), SMALL(), GOLD);
}
}
let by = y + CH() * (6.0 + lines.len() as f32);
let by = y + CH() * (6.0 + lines.len() as f32 + chart_rows as f32);
let widths: Vec<f32> = labels.iter().map(|(l, _)| gfx.measure(l, S()) + CW() * 4.0).collect();
let total: f32 = widths.iter().sum::<f32>() + CW() * 2.0 * (labels.len() as f32 - 1.0);
let mut bx = grid_center(sw, total);