redoing bump

This commit is contained in:
2026-07-08 13:21:27 -05:00
parent f407b5d9a6
commit e545395ac6
12 changed files with 243 additions and 90 deletions
+5 -4
View File
@@ -18,11 +18,11 @@ fn collision_priority_resolves_in_array_order_and_bumps() {
scripts_from(&[
(
"e",
"fn init(m) { move(East); } fn bump(m,id) { log(`o0 by ${id}`); }",
"fn init(m) { move(East); } fn bump(m,dir) { log(`o0 from ${dir}`); }",
),
(
"w",
"fn init(m) { move(West); } fn bump(m,id) { log(`o1 by ${id}`); }",
"fn init(m) { move(West); } fn bump(m,dir) { log(`o1 from ${dir}`); }",
),
]),
);
@@ -36,6 +36,7 @@ fn collision_priority_resolves_in_array_order_and_bumps() {
assert_eq!((b.objects[&2].x, b.objects[&2].y), (2, 0)); // obj1 blocked
}
let logs = log_texts(&game);
assert!(logs.iter().any(|t| t == "o0 by 2")); // obj0 bumped by obj1
assert!(!logs.iter().any(|t| t.starts_with("o1 by"))); // obj1 not bumped
// obj1 moved West into obj0, so the bump arrives from the East side of obj0.
assert!(logs.iter().any(|t| t == "o0 from East")); // obj0 bumped by obj1
assert!(!logs.iter().any(|t| t.starts_with("o1 from"))); // obj1 not bumped
}
+43 -5
View File
@@ -56,9 +56,9 @@ fn bumping_a_transporter_drops_you_on_its_far_side() {
#[test]
fn a_blocked_far_side_transports_out_of_the_paired_transporter() {
// Player, east transporter, a wall blocking its far side, the free entrance
// cell, then the paired west transporter. The player should pop out at the
// west transporter's entrance (the cell just before it), across the wall.
// Player, east transporter, a wall blocking its far side, a gap, the paired
// west transporter, then a free cell. The player should pop out on the paired
// transporter's far side (the cell just past it), across the wall.
let board = load_board(&map(
6,
1,
@@ -81,11 +81,49 @@ fn a_blocked_far_side_transports_out_of_the_paired_transporter() {
let b = game.board();
assert_eq!(
(b.player.x, b.player.y),
(3, 0),
"transported to the paired transporter's entrance",
(5, 0),
"transported past the paired transporter",
);
}
#[test]
fn a_pushed_crate_is_transported_through() {
// Player, a crate, an east transporter, then a free cell. Pushing the crate
// east into the transporter bumps it (through the crate chain); the transporter
// moves the crate — a plain terrain solid, no object id — out its far side.
let board = load_board(&map(
4,
1,
&[layer(
"@oT ",
&[
("@", "kind = \"player\""),
("o", "kind = \"crate\""),
("T", "kind = \"transporter_east\""),
],
)],
));
let mut game = GameState::new(board);
game.run_init();
// Push east into the crate: the crate can't move (the transporter blocks it),
// but the transporter is bumped from the West and teleports the crate to (3,0).
game.try_move(Direction::East);
game.tick(Duration::from_secs_f64(0.1));
{
let b = game.board();
assert!(b.solid_at(3, 0).is_some(), "crate transported to the far side");
assert!(b.is_passable(1, 0), "crate's old cell is now empty");
assert_eq!((b.player.x, b.player.y), (0, 0), "player didn't move yet");
}
// With the crate gone, a second push walks the player onto the vacated cell.
game.try_move(Direction::East);
game.tick(Duration::from_secs_f64(0.1));
let b = game.board();
assert_eq!((b.player.x, b.player.y), (1, 0), "player follows into the gap");
}
#[test]
fn transporter_round_trips_to_its_keyword() {
let board = load_board(&map(
+28 -8
View File
@@ -245,20 +245,40 @@ fn object_id_for_name_finds_by_name() {
// Ensure try_move from the player side also triggers scripted bump
#[test]
fn player_bump_fires_with_negative_one() {
// The player walks into a solid scripted object; the object is bumped with -1
// and the player does not move onto it.
fn player_bump_reports_the_direction_it_came_from() {
// The player walks East into a solid scripted object; the object is bumped from
// the West side (opposite the player's travel) and the player does not move onto it.
let board = open_board(3, 1, (0, 0), vec![scripted_object(1, 0, "b")]);
let mut game = GameState::with_scripts(
board,
scripts_from(&[("b", "fn bump(m,id) { log(`bumped by ${id}`); }")]),
scripts_from(&[("b", "fn bump(m,dir) { log(`bumped from ${dir}`); }")]),
);
game.run_init();
game.try_move(Direction::East);
assert_eq!((game.board().player.x, game.board().player.y), (0, 0)); // blocked
// bump's log is emitted into the object's queue; a tick flushes it.
game.tick(Duration::from_millis(16));
assert!(log_texts(&game).iter().any(|t| t == "bumped by -1"));
assert!(log_texts(&game).iter().any(|t| t == "bumped from West"));
}
// A bump handler can compare the direction and read its `dx`/`dy` offset to
// locate the bumper's cell.
#[test]
fn bump_direction_supports_comparison_and_offset() {
let board = open_board(3, 1, (0, 0), vec![scripted_object(1, 0, "b")]);
let mut game = GameState::with_scripts(
board,
scripts_from(&[(
"b",
// Player bumps from the West, so `dir == West` and the bumper sits at
// (me.x + dir.dx) = 1 + (-1) = 0.
"fn bump(m,dir) { if dir == West { log(`bumper at ${m.x + dir.dx}`); } }",
)]),
);
game.run_init();
game.try_move(Direction::East);
game.tick(Duration::from_millis(16));
assert!(log_texts(&game).iter().any(|t| t == "bumper at 0"));
}
#[test]
@@ -271,7 +291,7 @@ fn scroll_opens_on_player_bump() {
board,
scripts_from(&[(
"s",
r#"fn bump(m,id) { scroll(["Hello world", ["eat", "Eat it"]]); }"#,
r#"fn bump(m,dir) { scroll(["Hello world", ["eat", "Eat it"]]); }"#,
)]),
);
game.run_init();
@@ -295,7 +315,7 @@ fn handle_scroll_without_choice_clears_it() {
let board = open_board(3, 1, (0, 0), vec![scripted_object(1, 0, "s")]);
let mut game = GameState::with_scripts(
board,
scripts_from(&[("s", r#"fn bump(m,id) { scroll(["Hello"]); }"#)]),
scripts_from(&[("s", r#"fn bump(m,dir) { scroll(["Hello"]); }"#)]),
);
game.run_init();
game.try_move(Direction::East);
@@ -317,7 +337,7 @@ fn handle_scroll_with_choice_dispatches_send_to_source() {
scripts_from(&[(
"s",
r#"
fn bump(m,id) { scroll(["Muffin?", ["eat", "Eat it"]]); }
fn bump(m,dir) { scroll(["Muffin?", ["eat", "Eat it"]]); }
fn eat() { log("eaten"); }
"#,
)]),