Added names to objects

This commit is contained in:
2026-06-08 19:50:43 -05:00
parent 04415211c3
commit f5ed8f2edf
7 changed files with 149 additions and 3 deletions
@@ -1,6 +1,23 @@
use crate::archetype::Archetype;
use super::{load_board, map_3x1, obj_palette};
#[test]
fn duplicate_name_clears_second_but_keeps_both_objects() {
// Two objects share the name "gate": first keeps it, second is cleared.
// Both objects still appear on the board; the map is flagged invalid.
let objs = format!(
"{}\n{}",
"[[objects]]\nx = 0\ny = 0\ntile = 64\nfg = \"#ffffff\"\nbg = \"#000000\"\nname = \"gate\"\n",
"[[objects]]\nx = 1\ny = 0\ntile = 64\nfg = \"#ffffff\"\nbg = \"#000000\"\nname = \"gate\"\nsolid = false\n",
);
let board = load_board(&map_3x1("...", &objs));
assert_eq!(board.objects.len(), 2, "both objects survive");
// First object (id 1) keeps the name; second (id 2) is cleared.
assert_eq!(board.objects[&1].name.as_deref(), Some("gate"));
assert_eq!(board.objects[&2].name, None);
assert!(!board.is_valid(), "duplicate name is a nonfatal load error");
}
#[test]
fn palette_placement_puts_object_on_empty_floor() {
// `G` appears once, isn't a palette key → object lands there, cell is Empty.
+27 -1
View File
@@ -2,7 +2,7 @@ use color::Rgba8;
use crate::board::Board;
use crate::glyph::Glyph;
use crate::map_file::{MapFile, parse_color};
use super::load_board;
use super::{load_board, map_3x1, obj_palette};
#[test]
fn object_glyph_round_trips_through_toml() {
@@ -128,6 +128,32 @@ bg = "#000000"
assert!(!toml_out.contains("tags"), "empty tags must not appear in TOML output");
}
#[test]
fn object_name_round_trips_through_toml() {
// A named object must survive a save→load cycle with its name intact.
let board = load_board(&map_3x1("G..", &obj_palette("G", "name = \"beacon\"\n")));
assert_eq!(board.objects[&1].name.as_deref(), Some("beacon"));
let toml_out = toml::to_string_pretty(&MapFile::from(&board)).unwrap();
assert!(toml_out.contains("\"beacon\""), "name must appear in saved TOML");
let board2 = load_board(&toml_out);
assert_eq!(board2.objects[&1].name.as_deref(), Some("beacon"));
}
#[test]
fn unnamed_object_omits_name_from_toml() {
// An unnamed object must not emit a `name` key in TOML; check via the parsed
// value so the map header's `name = "Test"` doesn't produce a false positive.
let board = load_board(&map_3x1("G..", &obj_palette("G", "")));
let toml_out = toml::to_string_pretty(&MapFile::from(&board)).unwrap();
let val: toml::Value = toml_out.parse().unwrap();
let objects = val["objects"].as_array().unwrap();
assert!(
!objects[0].as_table().unwrap().contains_key("name"),
"unnamed object must not emit name key"
);
}
#[test]
fn floor_spec_round_trips_through_toml() {
// A 2×2 board with a grid floor (a generator and a fixed glyph) must survive
+49
View File
@@ -191,6 +191,55 @@ fn objects_with_tag_returns_matching_ids() {
assert_eq!(texts[1], "2"); // obj2 is id 2
}
#[test]
fn my_name_returns_name_or_empty_string() {
// An object with a name set on its ObjectDef should see it via my_name().
let mut board = board_with_object(
Some("n"),
&[("n", r#"fn init() { log(my_name()); }"#)],
);
board.objects.get_mut(&1).unwrap().name = Some("beacon".to_string());
let mut game = GameState::new(board);
game.run_init();
assert_eq!(log_texts(&game), vec!["beacon"]);
// An unnamed object should get an empty string.
let board2 = board_with_object(
Some("n"),
&[("n", r#"fn init() { log(my_name()); }"#)],
);
let mut game2 = GameState::new(board2);
game2.run_init();
assert_eq!(log_texts(&game2), vec![""]);
}
#[test]
fn object_id_for_name_finds_by_name() {
// A board with two objects; one is named. The querying object uses
// object_id_for_name to find the named one and logs its id.
let obj1 = scripted_object(0, 0, "q");
let mut obj2 = scripted_object(1, 0, "none");
obj2.name = Some("target".to_string());
let board = open_board(
5,
1,
(4, 0),
vec![obj1, obj2],
&[
("q", r#"fn init() {
log(object_id_for_name("target").to_string());
log(object_id_for_name("missing").to_string());
}"#),
("none", ""),
],
);
let mut game = GameState::new(board);
game.run_init();
let texts = log_texts(&game);
assert_eq!(texts[0], "2"); // obj2 is id 2
assert_eq!(texts[1], "0"); // 0 = not found
}
// Ensure try_move from the player side also triggers scripted bump
#[test]
fn player_bump_fires_with_negative_one() {