refactor(simulation): split the input.rs and dialogue.rs dispatchers (T-1062)
input.rs 2,739 → 858 lines: per-domain action handlers moved to their owning modules (inventory, movement, stance, examine, follow, interaction, save_io, settings, bridge::debug, economy, vision_cone, bookmark, test_world reset + new teleport.rs); input.rs keeps the queue, the thin dispatch table, and pause/cooldown glue. All 9 type_complexity allows dissolved via one PlayerInputQuery alias. dialogue.rs → dialogue/ directory module: selection (631), response (1,473), confrontation (714), mod.rs (226, shared session components + re-exports — public paths preserved). Documented seam deviation: process_walk_away lives with confrontation (D-064/D-063 share the same world-response shape). Mechanical, zero behavior change: determinism + golden_suite byte-identical (independently re-verified); 1,504 lib tests unchanged — 23 input tests moved with their subjects, 53 dialogue tests redistributed, zero deleted. System scheduling registrations untouched (input_plugin.rs 0-line diff). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -239,6 +239,58 @@ pub fn update_follow_state(
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle Follow verb: designate an NPC as follow target (#241).
|
||||
/// Sets FollowTarget on the player entity. Replaces any existing follow target.
|
||||
/// Server-side range check: Follow requires CLOSE_RANGE (same as Talk).
|
||||
pub fn handle_follow(
|
||||
commands: &mut Commands,
|
||||
registry: &crate::knowledge::EntityRegistry,
|
||||
player_query: &crate::simulation::input::PlayerInputQuery,
|
||||
all_positions: &Query<&TilePosition>,
|
||||
target_entity_id: Option<u64>,
|
||||
current_tick: u64,
|
||||
) {
|
||||
let Some(target_id) = target_entity_id else {
|
||||
tracing::warn!("Follow verb without target_entity_id");
|
||||
return;
|
||||
};
|
||||
|
||||
let Ok((player_entity, player_pos, _, _)) = player_query.single() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let target_stable = crate::knowledge::StableId(target_id);
|
||||
let Some(target_entity) = registry.to_entity(&target_stable) else {
|
||||
tracing::warn!(target_id, "Follow: target entity not in registry");
|
||||
return;
|
||||
};
|
||||
|
||||
// Server-side range check: reject Follow if target is beyond close range
|
||||
if let Ok(target_pos) = all_positions.get(target_entity) {
|
||||
let distance = player_pos
|
||||
.manhattan_distance(target_pos)
|
||||
.unwrap_or(u32::MAX);
|
||||
if distance > crate::simulation::interaction::CLOSE_RANGE {
|
||||
tracing::info!(
|
||||
target_id,
|
||||
distance,
|
||||
"Follow: target out of range (max {})",
|
||||
crate::simulation::interaction::CLOSE_RANGE,
|
||||
);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
commands.entity(player_entity).insert(FollowTarget {
|
||||
target: target_entity,
|
||||
started_tick: current_tick,
|
||||
proximity_ticks: 0,
|
||||
los_lost_ticks: 0,
|
||||
});
|
||||
|
||||
tracing::debug!(target_id, "Follow: FollowTarget set on player");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tests
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user