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:
Richard ZinkandClaude Opus 5.5 committed 2026-11-03 06:34:09 +01:00
1 parent 925be17e82
commit f710a19351
12 files changed
+588 -137

No files matched your search

+11 -11
View File
@@ -18,7 +18,7 @@ mod xm;
use game::{Game, Msg};
use gfx::Gfx;
use macroquad::prelude::*;
use map::{idx, inb, MH, MW};
use map::{idx, inb, mh, mw};
use menu::{Menu, MenuAction, Page};
use render3d::{Cam, Overlay, R3d};
use settings::{bindable_keys, Action, Settings};
@@ -53,8 +53,8 @@ struct Input {
minimap_drag: bool,
}
fn new_game(seed: u32) -> (Game, Cam) {
let g = Game::new(seed);
fn new_game(seed: u32, s: &Settings) -> (Game, Cam) {
let g = Game::new(seed, s.map_w, s.map_h);
let (cx, cy) = g.map.core;
let cam = Cam::new(cx as f32 + 1.5, cy as f32 + 1.5);
(g, cam)
@@ -82,7 +82,7 @@ impl MusicDirector {
fn update(&mut self, g: &Game, title: bool) {
use audio::Track;
const BUILD: [Track; 3] = [Track::Build1, Track::Build2, Track::Build3];
let gate_fight = g.time - g.gate_hit_t < 12.0 || g.ents.iter().any(|e| e.alive && e.guard);
let gate_fight = g.time - g.gate_hit_t < 12.0 || g.gate_defenders_alive();
let invasion = g.ents.iter().any(|e| e.alive && e.hero && !e.guard);
let want = if title {
Track::Title
@@ -193,7 +193,7 @@ async fn main() {
menu.has_autosave = platform::storage_get(save::AUTOSAVE_KEY).is_some();
let seed = (miniquad::date::now() * 1000.0) as u32 | 1;
let (game, cam) = new_game(seed);
let (game, cam) = new_game(seed, &settings);
let mut app = App { game, cam, settings, seed, status: None };
app.game.hints = app.settings.hints;
let mut inp = Input { ldown: None, rdown: None, rlast: (0.0, 0.0), rdrag: false, mlast: None, minimap_drag: false };
@@ -279,7 +279,7 @@ async fn main() {
}
if is_key_pressed(KeyCode::N) && app.game.state != 0 {
app.seed = next_seed(app.seed);
(app.game, app.cam) = new_game(app.seed);
(app.game, app.cam) = new_game(app.seed, &app.settings);
app.game.hints = app.settings.hints;
}
}
@@ -416,7 +416,7 @@ async fn main() {
MenuAction::Resume => {}
MenuAction::NewGame => {
app.seed = next_seed(app.seed);
(app.game, app.cam) = new_game(app.seed);
(app.game, app.cam) = new_game(app.seed, &app.settings);
app.game.hints = app.settings.hints;
menu.page = None;
ui.log.clear();
@@ -460,7 +460,7 @@ async fn main() {
}
UiAction::NewGame => {
app.seed = next_seed(app.seed);
(app.game, app.cam) = new_game(app.seed);
(app.game, app.cam) = new_game(app.seed, &app.settings);
app.game.hints = app.settings.hints;
}
UiAction::CloseHelp | UiAction::SelectLanguage(_) | UiAction::Consumed => {}
@@ -507,8 +507,8 @@ async fn main() {
}
}
}
app.cam.tx = app.cam.tx.clamp(0.0, MW as f32);
app.cam.tz = app.cam.tz.clamp(0.0, MH as f32);
app.cam.tx = app.cam.tx.clamp(0.0, mw() as f32);
app.cam.tz = app.cam.tz.clamp(0.0, mh() as f32);
if settings_changed {
apply_settings(&app.settings, &mut r3d);
@@ -571,7 +571,7 @@ fn draw_frame(app: &mut App, gfx: &Gfx, r3d: &mut R3d, ui: &mut Ui, menu: &mut M
};
let ov = Overlay {
hover: if over_ui { None } else { hover_tile.filter(|&(x, z)| inb(x, z)) },
rect: inp.ldown.and_then(|(sx, sy)| hover_tile.map(|(ex, ey)| (sx, sy, ex.clamp(0, MW as i32 - 1), ey.clamp(0, MH as i32 - 1)))),
rect: inp.ldown.and_then(|(sx, sy)| hover_tile.map(|(ex, ey)| (sx, sy, ex.clamp(0, mw() as i32 - 1), ey.clamp(0, mh() as i32 - 1)))),
color,
radius: if over_ui { None } else { radius },
high: ui.tool == Tool::Dig,