Configurable map size (64-256, non-square), one portal per 64x64 tiles, guarded treasure caves, glowing dig-mark blocks
- New Game dialog with map width/height (steps of 32), remembered in settings - map dimensions are per game; renderer chunks, minimap and camera follow them - content scales with area; grace period grows with the distance to the Hero Gate - treasure caves with rich gold, guarded by hero squads that hold their post - marked blocks: translucent yellow box with outline on all edges - savegame v2: packed run-length encoded tiles (256x256 map ~320 KB), v1 still loads - tests: savegame round trip on 96x128, 256x256 generation/simulation/save Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
925be17e82
commit
f710a19351
12 files changed
+588
-137
No files matched your search
+56
-2
@@ -3,6 +3,7 @@
|
||||
|
||||
use crate::gfx::*;
|
||||
use crate::i18n::{languages, tr, trf};
|
||||
use crate::map::{MAX_SIZE, MIN_SIZE};
|
||||
use crate::settings::{all_actions, key_name, Action, Settings};
|
||||
use crate::ui::{tool_info, CH, CW, DIM, FRAME, FRAME_HI, GOLD, S, TOOLS, TXT};
|
||||
use macroquad::prelude::*;
|
||||
@@ -12,6 +13,7 @@ pub enum Page {
|
||||
Title,
|
||||
Pause,
|
||||
Settings { tab: usize, from_title: bool },
|
||||
NewGame,
|
||||
KeyCapture { action: usize, from_title: bool },
|
||||
}
|
||||
|
||||
@@ -150,6 +152,9 @@ enum Btn {
|
||||
Back,
|
||||
Tab(usize),
|
||||
Change(usize, i32),
|
||||
MapW(i32),
|
||||
MapH(i32),
|
||||
Start,
|
||||
Key(usize),
|
||||
ResetKeys,
|
||||
}
|
||||
@@ -159,7 +164,7 @@ pub enum MenuAction {
|
||||
Consumed,
|
||||
Continue, // load the autosave
|
||||
Resume,
|
||||
NewGame,
|
||||
NewGame, // start a new game with the chosen map size
|
||||
Load,
|
||||
Save,
|
||||
Help,
|
||||
@@ -195,6 +200,7 @@ impl Menu {
|
||||
Some(Page::KeyCapture { from_title, .. }) => Some(Page::Settings { tab: 4, from_title }),
|
||||
Some(Page::Settings { from_title: true, .. }) => Some(Page::Title),
|
||||
Some(Page::Settings { from_title: false, .. }) => Some(Page::Pause),
|
||||
Some(Page::NewGame) => Some(Page::Title),
|
||||
Some(Page::Pause) => None,
|
||||
Some(Page::Title) => Some(Page::Title),
|
||||
None => Some(Page::Pause),
|
||||
@@ -227,7 +233,19 @@ impl Menu {
|
||||
self.page = None;
|
||||
MenuAction::Resume
|
||||
}
|
||||
Some(Btn::New) => MenuAction::NewGame,
|
||||
Some(Btn::New) => {
|
||||
self.page = Some(Page::NewGame);
|
||||
MenuAction::Consumed
|
||||
}
|
||||
Some(Btn::Start) => MenuAction::NewGame,
|
||||
Some(Btn::MapW(d)) => {
|
||||
settings.map_w = (settings.map_w as i32 + d * 32).clamp(MIN_SIZE as i32, MAX_SIZE as i32) as usize;
|
||||
MenuAction::SettingsChanged
|
||||
}
|
||||
Some(Btn::MapH(d)) => {
|
||||
settings.map_h = (settings.map_h as i32 + d * 32).clamp(MIN_SIZE as i32, MAX_SIZE as i32) as usize;
|
||||
MenuAction::SettingsChanged
|
||||
}
|
||||
Some(Btn::Load) => MenuAction::Load,
|
||||
Some(Btn::Save) => MenuAction::Save,
|
||||
Some(Btn::Help) => MenuAction::Help,
|
||||
@@ -273,6 +291,7 @@ impl Menu {
|
||||
match page {
|
||||
Page::Title => self.draw_title(gfx),
|
||||
Page::Pause => self.draw_pause(gfx),
|
||||
Page::NewGame => self.draw_new_game(gfx, settings),
|
||||
Page::Settings { tab, .. } => self.draw_settings(gfx, settings, tab),
|
||||
Page::KeyCapture { action, .. } => {
|
||||
self.draw_settings(gfx, settings, 4);
|
||||
@@ -334,6 +353,41 @@ impl Menu {
|
||||
gfx.text(&credit, (sw - gfx.measure(&credit, (S() / 2.0).max(1.0))) * 0.5, sh - CH() * 6.5, (S() / 2.0).max(1.0), DIM);
|
||||
}
|
||||
|
||||
// New game: choose the map size (width and height separately)
|
||||
fn draw_new_game(&mut self, gfx: &Gfx, s: &Settings) {
|
||||
let sw = screen_width();
|
||||
let sh = screen_height();
|
||||
let (mx, my) = mouse_position();
|
||||
let cols = 44;
|
||||
let rows = 17;
|
||||
let x = (sw - cols as f32 * CW()) * 0.5;
|
||||
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), &tr("menu.new"), FRAME_HI);
|
||||
let lines = [("newgame.width", s.map_w, 0), ("newgame.height", s.map_h, 1)];
|
||||
for (k, &(key, val, which)) in lines.iter().enumerate() {
|
||||
let by = y + CH() * (2.0 + k as f32 * 2.5);
|
||||
gfx.text(&tr(key), x + CW() * 3.0, by + CH() * 0.4, S(), TXT);
|
||||
let vw = 14.0 * CW();
|
||||
let vx = x + cols as f32 * CW() - vw - CW() * 3.0;
|
||||
let left = Rect::new(vx, by, CW() * 2.5, CH() * 1.8);
|
||||
let right = Rect::new(vx + vw - CW() * 2.5, by, CW() * 2.5, CH() * 1.8);
|
||||
button(gfx, left, "<", left.contains(vec2(mx, my)), FRAME);
|
||||
button(gfx, right, ">", right.contains(vec2(mx, my)), FRAME);
|
||||
let v = val.to_string();
|
||||
gfx.text(&v, vx + (vw - gfx.measure(&v, S())) * 0.5, by + CH() * 0.4, S(), GOLD);
|
||||
let (l, r) = if which == 0 { (Btn::MapW(-1), Btn::MapW(1)) } else { (Btn::MapH(-1), Btn::MapH(1)) };
|
||||
self.buttons.push((left, l));
|
||||
self.buttons.push((right, r));
|
||||
}
|
||||
// what the size means for the game
|
||||
let area = (s.map_w * s.map_h) as f32 / 4096.0;
|
||||
let portals = (area.round() as usize).max(1);
|
||||
let info = trf("newgame.info", &[portals.to_string(), (portals - 1).to_string()]);
|
||||
gfx.text(&info, x + CW() * 3.0, y + CH() * 7.5, S(), DIM);
|
||||
let w = (cols - 6) as f32 * CW();
|
||||
self.column(gfx, x + CW() * 3.0, y + CH() * 9.5, w, &[(Btn::Start, tr("newgame.start")), (Btn::Back, tr("menu.back"))]);
|
||||
}
|
||||
|
||||
fn draw_pause(&mut self, gfx: &Gfx) {
|
||||
let sw = screen_width();
|
||||
let sh = screen_height();
|
||||
|
||||
Reference in new issue
Block a user