Title screen, pause menu, settings dialog and savegames
- title screen (continue/new/load/settings/help) and Esc pause menu - settings: language & sound, camera, graphics, game, rebindable keys; stored in localStorage and in every savegame (always applied on load) - savegames as JSON (.dcsave): download, load via file picker or drag & drop - autosave to localStorage every 2 minutes and when the tab is hidden/closed - configurable wall detail, light count, interface size, game speed, hints - audio behind a cargo feature so native tests run (cargo test --no-default-features) - savegame round-trip test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
fbf6f223fc
commit
fb7dab3683
17 files changed
+1742
-345
No files matched your search
@@ -6,12 +6,34 @@ use crate::gfx::*;
|
||||
use crate::i18n::{languages, tr, trf};
|
||||
use crate::map::*;
|
||||
use crate::render3d::{minimap_color, Cam};
|
||||
use crate::settings::{key_name, Action, Settings};
|
||||
use crate::sound::SoundBank;
|
||||
use macroquad::prelude::*;
|
||||
|
||||
pub const S: f32 = 2.0; // UI font scale
|
||||
pub const CW: f32 = GW * S; // character width in px
|
||||
pub const CH: f32 = GH * S; // character height in px
|
||||
// UI font scale (setting: 2 = normal, 3 = large); character cell size follows it
|
||||
thread_local! {
|
||||
static UI_SCALE: std::cell::Cell<f32> = std::cell::Cell::new(2.0);
|
||||
}
|
||||
pub fn set_ui_scale(s: f32) {
|
||||
UI_SCALE.with(|c| c.set(s));
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
pub fn S() -> f32 {
|
||||
UI_SCALE.with(|c| c.get())
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
pub fn CW() -> f32 {
|
||||
GW * S()
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
pub fn CH() -> f32 {
|
||||
GH * S()
|
||||
}
|
||||
// factor relative to the normal scale, for pixel sizes such as buttons and icons
|
||||
#[allow(non_snake_case)]
|
||||
pub fn K() -> f32 {
|
||||
S() / 2.0
|
||||
}
|
||||
|
||||
pub const FRAME: Color = Color::new(0.62, 0.52, 0.36, 1.0);
|
||||
pub const FRAME_HI: Color = Color::new(0.95, 0.8, 0.4, 1.0);
|
||||
@@ -51,7 +73,6 @@ pub const TOOLS: [Tool; 12] = [
|
||||
Tool::Summon,
|
||||
];
|
||||
|
||||
pub const TOOL_KEYS: [&str; 12] = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "X", "V"];
|
||||
|
||||
pub struct ToolInfo {
|
||||
pub label: String,
|
||||
@@ -216,42 +237,43 @@ impl Ui {
|
||||
UiAction::None
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, g: &Game, gfx: &Gfx, cam: &Cam, snd: &SoundBank, info: &[(String, Color)], now: f64) {
|
||||
pub fn draw(&mut self, g: &Game, gfx: &Gfx, cam: &Cam, snd: &SoundBank, settings: &Settings, info: &[(String, Color)], now: f64) {
|
||||
self.rects.clear();
|
||||
let keys: Vec<String> = (0..TOOLS.len()).map(|i| key_name(settings.key(Action::Tool(i)))).collect();
|
||||
let sw = screen_width();
|
||||
let sh = screen_height();
|
||||
let (mx, my) = mouse_position();
|
||||
|
||||
// ---------------- top bar
|
||||
let cols = (sw / CW).ceil() as i32;
|
||||
gfx.window(0.0, 0.0, cols, 3, S, false, FRAME, BG);
|
||||
self.rects.push(Rect::new(0.0, 0.0, sw, 3.0 * CH));
|
||||
let y = CH;
|
||||
let mut x = CW * 2.0;
|
||||
let cols = (sw / CW()).ceil() as i32;
|
||||
gfx.window(0.0, 0.0, cols, 3, S(), false, FRAME, BG);
|
||||
self.rects.push(Rect::new(0.0, 0.0, sw, 3.0 * CH()));
|
||||
let y = CH();
|
||||
let mut x = CW() * 2.0;
|
||||
let seg = |label: &str, lc: Color, value: &str, vc: Color, x: &mut f32| {
|
||||
gfx.text(label, *x, y, S, lc);
|
||||
*x += gfx.measure(label, S) + CW;
|
||||
gfx.text(value, *x, y, S, vc);
|
||||
*x += gfx.measure(value, S) + CW * 2.0;
|
||||
gfx.text(label, *x, y, S(), lc);
|
||||
*x += gfx.measure(label, S()) + CW();
|
||||
gfx.text(value, *x, y, S(), vc);
|
||||
*x += gfx.measure(value, S()) + CW() * 2.0;
|
||||
};
|
||||
seg(&tr("hud.gold"), GOLD, &format!("{}/{}", g.gold as i32, g.gold_cap() as i32), TXT, &mut x);
|
||||
let mana = tr("hud.mana");
|
||||
gfx.text(&mana, x, y, S, MANA);
|
||||
x += gfx.measure(&mana, S) + CW * 0.5;
|
||||
gfx.text(&mana, x, y, S(), MANA);
|
||||
x += gfx.measure(&mana, S()) + CW() * 0.5;
|
||||
bar(x, y + 3.0, 70.0, 10.0, g.mana / MANA_MAX, MANA);
|
||||
x += 70.0 + CW * 0.5;
|
||||
gfx.text(&format!("{}", g.mana as i32), x, y, S, TXT);
|
||||
x += CW * 5.0;
|
||||
x += 70.0 + CW() * 0.5;
|
||||
gfx.text(&format!("{}", g.mana as i32), x, y, S(), TXT);
|
||||
x += CW() * 5.0;
|
||||
let core = tr("hud.core");
|
||||
gfx.text(&core, x, y, S, RED);
|
||||
x += gfx.measure(&core, S) + CW * 0.5;
|
||||
gfx.text(&core, x, y, S(), RED);
|
||||
x += gfx.measure(&core, S()) + CW() * 0.5;
|
||||
bar(x, y + 3.0, 70.0, 10.0, g.core_hp / CORE_HP, RED);
|
||||
x += 70.0 + CW * 1.5;
|
||||
x += 70.0 + CW() * 1.5;
|
||||
let gate = tr("hud.gate");
|
||||
gfx.text(&gate, x, y, S, BLUE);
|
||||
x += gfx.measure(&gate, S) + CW * 0.5;
|
||||
gfx.text(&gate, x, y, S(), BLUE);
|
||||
x += gfx.measure(&gate, S()) + CW() * 0.5;
|
||||
bar(x, y + 3.0, 70.0, 10.0, g.gate_hp / GATE_HP, BLUE);
|
||||
x += 70.0 + CW * 1.5;
|
||||
x += 70.0 + CW() * 1.5;
|
||||
let cap = g.counts[1].min(30);
|
||||
seg(&tr("hud.creatures"), TXT, &format!("{}/{}", g.creature_count(), cap), TXT, &mut x);
|
||||
seg(&tr("hud.workers"), TXT, &format!("{}", g.worker_count()), TXT, &mut x);
|
||||
@@ -259,20 +281,23 @@ impl Ui {
|
||||
seg(&trf("hud.wave", &[(g.wave + 1).to_string()]), wave_col, &mmss(g.wave_timer), wave_col, &mut x);
|
||||
seg(&tr("hud.army"), TXT, &format!("{}", g.army_value() as i32), TXT, &mut x);
|
||||
let vol = if snd.muted { tr("hud.off") } else { format!("{}%", (snd.volume * 100.0).round() as i32) };
|
||||
seg("♪", DIM, &vol, DIM, &mut x);
|
||||
// volume only if it still fits into the bar
|
||||
if x + gfx.measure(&format!("♪ {}", vol), S()) < sw - CW() * 2.0 {
|
||||
seg("♪", DIM, &vol, DIM, &mut x);
|
||||
}
|
||||
|
||||
// ---------------- toolbar
|
||||
let tb_rows = 5;
|
||||
let tb_y = sh - tb_rows as f32 * CH;
|
||||
gfx.window(0.0, tb_y, cols, tb_rows, S, false, FRAME, BG);
|
||||
self.rects.push(Rect::new(0.0, tb_y, sw, tb_rows as f32 * CH));
|
||||
let tb_y = sh - tb_rows as f32 * CH();
|
||||
gfx.window(0.0, tb_y, cols, tb_rows, S(), false, FRAME, BG);
|
||||
self.rects.push(Rect::new(0.0, tb_y, sw, tb_rows as f32 * CH()));
|
||||
self.tool_rects.clear();
|
||||
let bw = 80.0;
|
||||
let bw = 80.0 * K();
|
||||
let mut hover_tool = None;
|
||||
for (i, &t) in TOOLS.iter().enumerate() {
|
||||
let bx = CW + i as f32 * (bw + 4.0);
|
||||
let by = tb_y + CH * 0.75;
|
||||
let r = Rect::new(bx, by, bw, CH * 3.5);
|
||||
let bx = CW() + i as f32 * (bw + 4.0 * K());
|
||||
let by = tb_y + CH() * 0.75;
|
||||
let r = Rect::new(bx, by, bw, CH() * 3.5);
|
||||
self.tool_rects.push(r);
|
||||
let hovered = r.contains(vec2(mx, my));
|
||||
if hovered {
|
||||
@@ -282,19 +307,21 @@ impl Ui {
|
||||
draw_rectangle(r.x, r.y, r.w, r.h, if sel { Color::new(0.35, 0.22, 0.1, 1.0) } else if hovered { Color::new(0.18, 0.13, 0.1, 1.0) } else { Color::new(0.1, 0.07, 0.07, 1.0) });
|
||||
draw_rectangle_lines(r.x, r.y, r.w, r.h, 2.0, if sel { FRAME_HI } else { Color::new(0.35, 0.28, 0.2, 1.0) });
|
||||
let ti = tool_info(t);
|
||||
gfx.draw_cell(ti.icon, bx + (bw - 32.0) * 0.5, by + 4.0, 32.0, 32.0, WHITE);
|
||||
gfx.text(TOOL_KEYS[i], bx + 3.0, by + 3.0, 1.0, if sel { FRAME_HI } else { DIM });
|
||||
let lw = gfx.measure(&ti.label, 1.0);
|
||||
gfx.text(&ti.label, bx + (bw - lw) * 0.5, by + 42.0, 1.0, if sel { FRAME_HI } else { TXT });
|
||||
let icon = 32.0 * K();
|
||||
let small = (S() / 2.0).floor().max(1.0);
|
||||
gfx.draw_cell(ti.icon, bx + (bw - icon) * 0.5, by + 4.0 * K(), icon, icon, WHITE);
|
||||
gfx.text(&keys[i], bx + 3.0, by + 3.0, small, if sel { FRAME_HI } else { DIM });
|
||||
let lw = gfx.measure(&ti.label, small);
|
||||
gfx.text(&ti.label, bx + (bw - lw) * 0.5, by + 42.0 * K(), small, if sel { FRAME_HI } else { TXT });
|
||||
}
|
||||
// hand contents
|
||||
let hx = CW + TOOLS.len() as f32 * (bw + 4.0) + CW;
|
||||
let hx = CW() + TOOLS.len() as f32 * (bw + 4.0 * K()) + CW();
|
||||
if hx + 120.0 < sw - 200.0 {
|
||||
gfx.text(&tr("hud.hand"), hx, tb_y + CH, S, TXT);
|
||||
gfx.text(&tr("hud.hand"), hx, tb_y + CH(), S(), TXT);
|
||||
for (k, id) in g.hand.iter().enumerate() {
|
||||
if let Some(e) = g.ents.iter().find(|e| e.id == *id) {
|
||||
let sx = hx + (k % 4) as f32 * 26.0;
|
||||
let sy = tb_y + CH * 2.2 + (k / 4) as f32 * 24.0;
|
||||
let sy = tb_y + CH() * 2.2 + (k / 4) as f32 * 24.0;
|
||||
draw_texture_ex(
|
||||
&gfx.sprites,
|
||||
sx,
|
||||
@@ -305,18 +332,18 @@ impl Ui {
|
||||
}
|
||||
}
|
||||
if g.hand.is_empty() {
|
||||
gfx.text(&tr("hud.empty"), hx, tb_y + CH * 2.5, 1.0, DIM);
|
||||
gfx.text(&tr("hud.empty"), hx, tb_y + CH() * 2.5, 1.0, DIM);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- minimap
|
||||
let mm_cols = 16;
|
||||
let mm_rows = 12;
|
||||
let mm_w = mm_cols as f32 * CW;
|
||||
let mm_h = mm_rows as f32 * CH;
|
||||
let mm_w = mm_cols as f32 * CW();
|
||||
let mm_h = mm_rows as f32 * CH();
|
||||
let mm_x = sw - mm_w;
|
||||
let mm_y = tb_y - mm_h;
|
||||
gfx.window_titled(mm_x, mm_y, mm_cols, mm_rows, S, false, FRAME, BG, &tr("ui.map"), FRAME_HI);
|
||||
gfx.window_titled(mm_x, mm_y, mm_cols, mm_rows, S(), false, FRAME, BG, &tr("ui.map"), FRAME_HI);
|
||||
self.rects.push(Rect::new(mm_x, mm_y, mm_w, mm_h));
|
||||
if now - self.minimap_t > 0.25 {
|
||||
self.minimap_t = now;
|
||||
@@ -330,9 +357,9 @@ impl Ui {
|
||||
}
|
||||
self.minimap_tex.update(&self.minimap_img);
|
||||
}
|
||||
let map_px = (mm_w - CW * 2.0).min(mm_h - CH * 2.0);
|
||||
let map_px = (mm_w - CW() * 2.0).min(mm_h - CH() * 2.0);
|
||||
let mrx = mm_x + (mm_w - map_px) * 0.5;
|
||||
let mry = mm_y + CH + (mm_h - CH * 2.0 - map_px) * 0.5;
|
||||
let mry = mm_y + CH() + (mm_h - CH() * 2.0 - map_px) * 0.5;
|
||||
self.minimap_rect = Rect::new(mrx, mry, map_px, map_px);
|
||||
draw_texture_ex(&self.minimap_tex, mrx, mry, WHITE, DrawTextureParams { dest_size: Some(vec2(map_px, map_px)), ..Default::default() });
|
||||
let ms = map_px / MW as f32;
|
||||
@@ -366,18 +393,18 @@ impl Ui {
|
||||
}
|
||||
}
|
||||
let irows = lines.len() as i32 + 2;
|
||||
let ix = sw - icols as f32 * CW;
|
||||
let iy = 3.0 * CH;
|
||||
gfx.window_titled(ix, iy, icols, irows, S, false, FRAME, BG, &info[0].0, info[0].1);
|
||||
let ix = sw - icols as f32 * CW();
|
||||
let iy = 3.0 * CH();
|
||||
gfx.window_titled(ix, iy, icols, irows, S(), false, FRAME, BG, &info[0].0, info[0].1);
|
||||
for (k, (l, c)) in lines.iter().enumerate() {
|
||||
gfx.text(l, ix + CW * 2.0, iy + CH * (k as f32 + 1.0), S, *c);
|
||||
gfx.text(l, ix + CW() * 2.0, iy + CH() * (k as f32 + 1.0), S(), *c);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- messages (translated at display time, so a language switch applies at once)
|
||||
let recent: Vec<&(Msg, f64)> = self.log.iter().filter(|(_, t)| now - t < 14.0).collect();
|
||||
if !recent.is_empty() {
|
||||
let mcols = (((sw - mm_w) / CW) as i32 - 2).clamp(20, 70);
|
||||
let mcols = (((sw - mm_w) / CW()) as i32 - 2).clamp(20, 70);
|
||||
let mut lines: Vec<(String, f32)> = Vec::new();
|
||||
for (m, t) in recent.iter().rev().take(5).rev() {
|
||||
let a = (1.0 - ((now - t) as f32 - 11.0) / 3.0).clamp(0.2, 1.0);
|
||||
@@ -386,11 +413,11 @@ impl Ui {
|
||||
}
|
||||
}
|
||||
let mrows = lines.len() as i32 + 2;
|
||||
let my0 = tb_y - mrows as f32 * CH;
|
||||
gfx.window(0.0, my0, mcols, mrows, S, false, FRAME, Color::new(0.06, 0.04, 0.05, 0.75));
|
||||
self.rects.push(Rect::new(0.0, my0, mcols as f32 * CW, mrows as f32 * CH));
|
||||
let my0 = tb_y - mrows as f32 * CH();
|
||||
gfx.window(0.0, my0, mcols, mrows, S(), false, FRAME, Color::new(0.06, 0.04, 0.05, 0.75));
|
||||
self.rects.push(Rect::new(0.0, my0, mcols as f32 * CW(), mrows as f32 * CH()));
|
||||
for (k, (l, a)) in lines.iter().enumerate() {
|
||||
gfx.text(l, CW * 2.0, my0 + CH * (k as f32 + 1.0), S, Color::new(TXT.r, TXT.g, TXT.b, *a));
|
||||
gfx.text(l, CW() * 2.0, my0 + CH() * (k as f32 + 1.0), S(), Color::new(TXT.r, TXT.g, TXT.b, *a));
|
||||
}
|
||||
}
|
||||
if self.log.len() > 100 {
|
||||
@@ -407,17 +434,22 @@ impl Ui {
|
||||
if !cost.is_empty() {
|
||||
lines.push((trf("ui.cost", &[cost]), GOLD));
|
||||
}
|
||||
lines.push((trf("ui.key", &[TOOL_KEYS[i].to_string()]), DIM));
|
||||
lines.push((trf("ui.key", &[keys[i].clone()]), DIM));
|
||||
let rows = lines.len() as i32 + 2;
|
||||
let tx = (mx - tcols as f32 * CW * 0.5).clamp(0.0, sw - tcols as f32 * CW);
|
||||
let ty = tb_y - rows as f32 * CH - 4.0;
|
||||
gfx.window_titled(tx, ty, tcols as i32, rows, S, false, FRAME_HI, BG, &ti.name, FRAME_HI);
|
||||
let tx = (mx - tcols as f32 * CW() * 0.5).clamp(0.0, sw - tcols as f32 * CW());
|
||||
let ty = tb_y - rows as f32 * CH() - 4.0;
|
||||
gfx.window_titled(tx, ty, tcols as i32, rows, S(), false, FRAME_HI, BG, &ti.name, FRAME_HI);
|
||||
for (k, (l, c)) in lines.iter().enumerate() {
|
||||
gfx.text(l, tx + CW * 2.0, ty + CH * (k as f32 + 1.0), S, *c);
|
||||
gfx.text(l, tx + CW() * 2.0, ty + CH() * (k as f32 + 1.0), S(), *c);
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------- dialogs
|
||||
}
|
||||
|
||||
// Dialogs on top of everything (help, language selection, end screen, pause)
|
||||
pub fn draw_dialogs(&mut self, g: &Game, gfx: &Gfx) {
|
||||
let sw = screen_width();
|
||||
let sh = screen_height();
|
||||
if self.show_langsel {
|
||||
self.draw_langsel(gfx);
|
||||
} else if g.state != 0 {
|
||||
@@ -426,13 +458,13 @@ impl Ui {
|
||||
self.draw_help(gfx);
|
||||
} else if g.paused {
|
||||
let w = 24;
|
||||
let x = (sw - w as f32 * CW) * 0.5;
|
||||
let x = (sw - w as f32 * CW()) * 0.5;
|
||||
let y = sh * 0.35;
|
||||
gfx.window(x, y, w, 5, S, true, FRAME_HI, BG);
|
||||
gfx.window(x, y, w, 5, S(), true, FRAME_HI, BG);
|
||||
let t = tr("ui.pause");
|
||||
gfx.text(&t, (sw - gfx.measure(&t, 3.0)) * 0.5, y + CH, 3.0, FRAME_HI);
|
||||
gfx.text(&t, (sw - gfx.measure(&t, 3.0)) * 0.5, y + CH(), 3.0, FRAME_HI);
|
||||
let t2 = tr("ui.pause_hint");
|
||||
gfx.text(&t2, (sw - gfx.measure(&t2, S)) * 0.5, y + CH * 3.0, S, DIM);
|
||||
gfx.text(&t2, (sw - gfx.measure(&t2, S())) * 0.5, y + CH() * 3.0, S(), DIM);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,11 +496,11 @@ impl Ui {
|
||||
let rows = lines.len() as i32 + 4;
|
||||
let sw = screen_width();
|
||||
let sh = screen_height();
|
||||
let x = ((sw - cols as f32 * CW) * 0.5).max(0.0);
|
||||
let y = ((sh - rows as f32 * CH) * 0.5).max(0.0);
|
||||
gfx.window_titled(x, y, cols, rows, S, true, FRAME_HI, Color::new(0.05, 0.03, 0.04, 0.97), "DungeonCraft", FRAME_HI);
|
||||
let x = ((sw - cols as f32 * CW()) * 0.5).max(0.0);
|
||||
let y = ((sh - rows as f32 * CH()) * 0.5).max(0.0);
|
||||
gfx.window_titled(x, y, cols, rows, S(), true, FRAME_HI, Color::new(0.05, 0.03, 0.04, 0.97), "DungeonCraft", FRAME_HI);
|
||||
for (k, (l, c)) in lines.iter().enumerate() {
|
||||
gfx.text(l, x + CW * 3.0, y + CH * (k as f32 + 2.0), S, *c);
|
||||
gfx.text(l, x + CW() * 3.0, y + CH() * (k as f32 + 2.0), S(), *c);
|
||||
}
|
||||
self.rects.push(Rect::new(0.0, 0.0, sw, sh));
|
||||
}
|
||||
@@ -481,28 +513,28 @@ impl Ui {
|
||||
let langs = languages();
|
||||
let cols = 50;
|
||||
let rows = 6 + langs.len() as i32 * 3;
|
||||
let x = ((sw - cols as f32 * CW) * 0.5).max(0.0);
|
||||
let y = ((sh - rows as f32 * CH) * 0.5).max(0.0);
|
||||
let x = ((sw - cols as f32 * CW()) * 0.5).max(0.0);
|
||||
let y = ((sh - rows as f32 * CH()) * 0.5).max(0.0);
|
||||
// the title shows all language names, since no language is chosen yet
|
||||
let title = langs.iter().map(|(c, _)| crate::i18n::tr_in(c, "langsel.title")).collect::<Vec<_>>().join(" / ");
|
||||
gfx.window_titled(x, y, cols, rows, S, true, FRAME_HI, Color::new(0.05, 0.03, 0.04, 0.97), &title, FRAME_HI);
|
||||
gfx.window_titled(x, y, cols, rows, S(), true, FRAME_HI, Color::new(0.05, 0.03, 0.04, 0.97), &title, FRAME_HI);
|
||||
self.lang_rects.clear();
|
||||
let (mx, my) = mouse_position();
|
||||
for (k, (code, name)) in langs.iter().enumerate() {
|
||||
let bw = 24.0 * CW;
|
||||
let bw = 24.0 * CW();
|
||||
let bx = (sw - bw) * 0.5;
|
||||
let by = y + CH * (2.0 + k as f32 * 3.0);
|
||||
let r = Rect::new(bx, by, bw, CH * 2.0);
|
||||
let by = y + CH() * (2.0 + k as f32 * 3.0);
|
||||
let r = Rect::new(bx, by, bw, CH() * 2.0);
|
||||
let hov = r.contains(vec2(mx, my));
|
||||
draw_rectangle(r.x, r.y, r.w, r.h, if hov { Color::new(0.35, 0.22, 0.1, 1.0) } else { Color::new(0.15, 0.1, 0.08, 1.0) });
|
||||
draw_rectangle_lines(r.x, r.y, r.w, r.h, 2.0, if hov { FRAME_HI } else { FRAME });
|
||||
gfx.text(name, bx + (bw - gfx.measure(name, S)) * 0.5, by + CH * 0.5, S, TXT);
|
||||
gfx.text(name, bx + (bw - gfx.measure(name, S())) * 0.5, by + CH() * 0.5, S(), TXT);
|
||||
self.lang_rects.push((r, code.clone()));
|
||||
}
|
||||
let hint_y = y + CH * (2.0 + langs.len() as f32 * 3.0 + 0.5);
|
||||
let hint_y = y + CH() * (2.0 + langs.len() as f32 * 3.0 + 0.5);
|
||||
for (k, (c, _)) in langs.iter().enumerate() {
|
||||
let h = crate::i18n::tr_in(c, "langsel.hint");
|
||||
gfx.text(&h, x + CW * 2.0, hint_y + CH * k as f32, 1.0, DIM);
|
||||
gfx.text(&h, x + CW() * 2.0, hint_y + CH() * k as f32, 1.0, DIM);
|
||||
}
|
||||
self.rects.push(Rect::new(0.0, 0.0, sw, sh));
|
||||
}
|
||||
@@ -514,27 +546,27 @@ impl Ui {
|
||||
let win = g.state == 1;
|
||||
let cols = 44;
|
||||
let rows = 11;
|
||||
let x = (sw - cols as f32 * CW) * 0.5;
|
||||
let y = (sh - rows as f32 * CH) * 0.5;
|
||||
let x = (sw - cols as f32 * CW()) * 0.5;
|
||||
let y = (sh - rows as f32 * CH()) * 0.5;
|
||||
let col = if win { GOLD } else { RED };
|
||||
gfx.window(x, y, cols, rows, S, true, col, Color::new(0.05, 0.03, 0.04, 0.97));
|
||||
gfx.window(x, y, cols, rows, S(), true, col, Color::new(0.05, 0.03, 0.04, 0.97));
|
||||
let title = tr(if win { "end.victory" } else { "end.defeat" });
|
||||
gfx.text(&title, (sw - gfx.measure(&title, 4.0)) * 0.5, y + CH * 1.5, 4.0, col);
|
||||
gfx.text(&title, (sw - gfx.measure(&title, 4.0)) * 0.5, y + CH() * 1.5, 4.0, col);
|
||||
let sub = tr(if win { "end.victory_sub" } else { "end.defeat_sub" });
|
||||
gfx.text(&sub, (sw - gfx.measure(&sub, S)) * 0.5, y + CH * 4.5, S, TXT);
|
||||
gfx.text(&sub, (sw - gfx.measure(&sub, S())) * 0.5, y + CH() * 4.5, S(), TXT);
|
||||
let st = trf("end.stats", &[mmss(g.time), g.wave.to_string(), (g.army_value() as i32).to_string()]);
|
||||
gfx.text(&st, (sw - gfx.measure(&st, S)) * 0.5, y + CH * 6.0, S, DIM);
|
||||
gfx.text(&st, (sw - gfx.measure(&st, S())) * 0.5, y + CH() * 6.0, S(), DIM);
|
||||
let b = format!(" {} ", tr("end.new"));
|
||||
let b = b.as_str();
|
||||
let bw = gfx.measure(b, S) + CW * 2.0;
|
||||
let bw = gfx.measure(b, S()) + CW() * 2.0;
|
||||
let bx = (sw - bw) * 0.5;
|
||||
let by = y + CH * 7.75;
|
||||
self.end_button = Rect::new(bx, by, bw, CH * 2.0);
|
||||
let by = y + CH() * 7.75;
|
||||
self.end_button = Rect::new(bx, by, bw, CH() * 2.0);
|
||||
let (mx, my) = mouse_position();
|
||||
let hov = self.end_button.contains(vec2(mx, my));
|
||||
draw_rectangle(bx, by, bw, CH * 2.0, if hov { Color::new(0.35, 0.22, 0.1, 1.0) } else { Color::new(0.15, 0.1, 0.08, 1.0) });
|
||||
draw_rectangle_lines(bx, by, bw, CH * 2.0, 2.0, col);
|
||||
gfx.text(b, bx + CW, by + CH * 0.5, S, TXT);
|
||||
draw_rectangle(bx, by, bw, CH() * 2.0, if hov { Color::new(0.35, 0.22, 0.1, 1.0) } else { Color::new(0.15, 0.1, 0.08, 1.0) });
|
||||
draw_rectangle_lines(bx, by, bw, CH() * 2.0, 2.0, col);
|
||||
gfx.text(b, bx + CW(), by + CH() * 0.5, S(), TXT);
|
||||
self.rects.push(Rect::new(0.0, 0.0, sw, sh));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user