Use element names, hex colors for under

This commit is contained in:
2026-01-23 14:11:40 -08:00
parent 6d3de543fd
commit f59851e2be
2 changed files with 104 additions and 7 deletions
+67
View File
@@ -274,3 +274,70 @@ pub fn element_name(id: u8) -> String {
None => format!("unknown ({})", id),
}
}
/// Convert an element name back to its ID.
/// Handles "unknown_N" format for unknown element IDs.
pub fn element_id_from_name(name: &str) -> Option<u8> {
// Handle "unknown_N" format first
if let Some(suffix) = name.strip_prefix("unknown_") {
return suffix.parse().ok();
}
// Match all known element names to their IDs
match name {
"empty" => Some(0),
"board_edge" => Some(1),
"messenger" => Some(2),
"monitor" => Some(3),
"player" => Some(4),
"ammo" => Some(5),
"torch" => Some(6),
"gem" => Some(7),
"key" => Some(8),
"door" => Some(9),
"scroll" => Some(10),
"passage" => Some(11),
"duplicator" => Some(12),
"bomb" => Some(13),
"energizer" => Some(14),
"star" => Some(15),
"clockwise" => Some(16),
"counter" => Some(17),
"bullet" => Some(18),
"water" => Some(19),
"forest" => Some(20),
"solid" => Some(21),
"normal" => Some(22),
"breakable" => Some(23),
"boulder" => Some(24),
"sliderns" => Some(25),
"sliderew" => Some(26),
"fake" => Some(27),
"invisible" => Some(28),
"blinkwall" => Some(29),
"transporter" => Some(30),
"line" => Some(31),
"ricochet" => Some(32),
"blink_ray_h" => Some(33),
"bear" => Some(34),
"ruffian" => Some(35),
"object" => Some(36),
"slime" => Some(37),
"shark" => Some(38),
"spinninggun" => Some(39),
"pusher" => Some(40),
"lion" => Some(41),
"tiger" => Some(42),
"blink_ray_v" => Some(43),
"head" => Some(44),
"segment" => Some(45),
// 46 is unused
"text_blue" => Some(47),
"text_green" => Some(48),
"text_cyan" => Some(49),
"text_red" => Some(50),
"text_purple" => Some(51),
"text_brown" => Some(52),
"text_black" => Some(53),
_ => None,
}
}
+37 -7
View File
@@ -11,7 +11,7 @@ use nom::{
sequence::pair,
};
use super::elements::{Element, element_name, resolve_alias};
use super::elements::{Element, element_id_from_name, element_name, resolve_alias};
use super::error::ParseError;
use super::parse::{Board, Program, Stat, Tile, World};
@@ -206,10 +206,14 @@ fn write_stat(output: &mut String, index: usize, stat: &Stat, element: Option<u8
kv!(output, "y_step", stat.y_step, 0);
if stat.under.element != Element::Empty as u8 || stat.under.color != 0x0f {
let elem_name = match Element::from_u8(stat.under.element) {
Some(e) => e.name().to_string(),
None => format!("unknown_{}", stat.under.element),
};
writeln!(
output,
"under = ({}, {})",
stat.under.element, stat.under.color
"under = ({}, 0x{:02x})",
elem_name, stat.under.color
)
.unwrap();
}
@@ -374,18 +378,44 @@ fn boolean(input: &str) -> IResult<&str, bool> {
alt((value(true, tag("true")), value(false, tag("false")))).parse(input)
}
/// Parse a tuple like (element, color).
/// Parse a hex number like 0x0f or 0x1F.
fn hex_u8(input: &str) -> IResult<&str, u8> {
let (input, _) = tag("0x").parse(input)?;
let (input, hex_str) = take_while1(|c: char| c.is_ascii_hexdigit()).parse(input)?;
match u8::from_str_radix(hex_str, 16) {
Ok(n) => Ok((input, n)),
Err(_) => Err(nom::Err::Error(nom::error::Error::new(
input,
nom::error::ErrorKind::HexDigit,
))),
}
}
/// Parse a tuple like (element_name, 0xNN) or legacy (element_id, color).
/// Supports both new format: (empty, 0x0f) and legacy: (0, 15).
fn tuple2(input: &str) -> IResult<&str, (u8, u8)> {
let (input, _) = char('(').parse(input)?;
let (input, _) = multispace0.parse(input)?;
let (input, a) = map_res(digit1, |s: &str| s.parse::<u8>()).parse(input)?;
// First value: element name (identifier) or decimal number
let (input, element_id) = alt((
// Element name (identifier) -> convert to ID
map(identifier, |name| element_id_from_name(name).unwrap_or(0)),
// Legacy: decimal element ID
map_res(digit1, |s: &str| s.parse::<u8>()),
))
.parse(input)?;
let (input, _) = multispace0.parse(input)?;
let (input, _) = char(',').parse(input)?;
let (input, _) = multispace0.parse(input)?;
let (input, b) = map_res(digit1, |s: &str| s.parse::<u8>()).parse(input)?;
// Second value: hex color (0xNN) or decimal color
let (input, color) = alt((hex_u8, map_res(digit1, |s: &str| s.parse::<u8>()))).parse(input)?;
let (input, _) = multispace0.parse(input)?;
let (input, _) = char(')').parse(input)?;
Ok((input, (a, b)))
Ok((input, (element_id, color)))
}
/// Parse a string array like ["foo", "bar", ""].