show solutions with no matching level under a 'missing levels' chapter

This commit is contained in:
Crispy 2025-04-13 01:11:17 +02:00
parent 522a027f7a
commit 563c819900
4 changed files with 49 additions and 4 deletions

View file

@ -3,6 +3,7 @@ Game store page: https://crispypin.itch.io/marble-machinations
## [unreleased]
### added
- create "missing levels" section allowing access to solutions to levels that are no longer available
- click to collapse chapters in level list
### fixed
- When two input bindings had the same trigger but one has a strict subset of the others modifiers, both would activate when the one with more modifiers was pressed. For example (Ctrl+S -> Save) would also trigger (S -> Wire Tool). Now, Shift+S will still trigger Wire Tool, unless Shift+S (or eg. Shift+Ctrl+S) is bound to something else.

View file

@ -21,7 +21,6 @@ logic mostly like https://git.crispypin.cc/CrispyPin/marble
- UI layout engine
- global scale setting
#### unspecified
- show orphaned solutions
- comments
- editing
- add to all intro levels

View file

@ -49,6 +49,20 @@ impl IOData {
}
impl Level {
pub fn new_orphan(id: &str) -> Self {
Self {
id: id.to_owned(),
name: id.to_owned(),
description: String::from(
"No level with this id was found, but there are saved solutions pointing to it.\n
Because input values and expected output is not available, this functions as a sandbox.\n
This allows you to recover any machines you have built here.",
),
init_board: None,
stages: Vec::new(),
}
}
pub fn id(&self) -> &str {
&self.id
}

View file

@ -10,7 +10,7 @@ use marble_machinations::*;
use config::Config;
use editor::{Editor, ExitState};
use level::Chapter;
use level::{Chapter, Level};
use solution::Solution;
use theme::*;
use ui::{simple_option_button, tex32_button, text_button, text_input, ShapedText, Tooltip};
@ -46,8 +46,11 @@ fn main() {
impl Game {
fn new(rl: &mut RaylibHandle, thread: &RaylibThread) -> Self {
let chapters = get_chapters();
let mut chapters = get_chapters();
let solutions = get_solutions();
if let Some(orphans) = find_orphans(&chapters, &solutions) {
chapters.push(orphans);
}
Self {
chapters,
@ -407,9 +410,37 @@ fn get_solutions() -> HashMap<String, Vec<Solution>> {
}
solutions.sort_unstable_by_key(Solution::id);
}
by_level.insert(level_name, solutions);
if !solutions.is_empty() {
by_level.insert(level_name, solutions);
}
}
}
}
by_level
}
fn find_orphans(
chapters: &[Chapter],
solutions: &HashMap<String, Vec<Solution>>,
) -> Option<Chapter> {
let mut orphan_levels = Vec::new();
'outer: for id in solutions.keys() {
for c in chapters {
for l in &c.levels {
if l.id() == id {
continue 'outer;
}
}
}
orphan_levels.push(Level::new_orphan(id))
}
if orphan_levels.is_empty() {
None
} else {
Some(Chapter {
title: "Missing levels".into(),
levels: orphan_levels,
visible: false,
})
}
}