feat(simulation): sprint 16 dialogue server — response handler, trust gossip, variety tracker
Move dialogue system registrations from BridgePlugin to NpcPlugin (#538): game logic that depends on NPC-layer resources now registers where it belongs. BridgePlugin retains only wire protocol concerns. Implement DialogueResponse verb handler (#539): new process_dialogue_response system runs the full D-028 four-layer pipeline to select follow-up lines when the player picks a dialogue option. Clears ActiveDialogue when no candidates remain. Fix latent schedule ambiguity — emit_observation_events now has explicit .before(advance_tick) constraint. Verify trust-gated gossip pipeline (#171): confirmed process_talk_interaction correctly passes KnowledgeConfidence through relationship_to_trust() per D-075. Added integration tests for Secret-tier access (Friendly+KnowsDetails) and Surface-only fallback (Friendly+Suspects). Wire DialogueCooldownTracker into selection (#338): added regression test confirming no line_id repeats within the 600-tick cooldown window across 10 consecutive Talk interactions. Closes #538, #539, #171, #338 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -280,6 +280,18 @@ pub fn process_player_input(
|
||||
PlayerAction::TeleportToHub => {
|
||||
handle_teleport_to_hub(&mut player_query, &mut commands);
|
||||
}
|
||||
PlayerAction::DialogueResponse {
|
||||
target_entity_id,
|
||||
ref response_id,
|
||||
} => {
|
||||
handle_dialogue_response(
|
||||
&mut commands,
|
||||
®istry,
|
||||
&player_query,
|
||||
target_entity_id,
|
||||
response_id,
|
||||
);
|
||||
}
|
||||
PlayerAction::UsePerceptionMode(ref mode) => {
|
||||
tracing::trace!("UsePerceptionMode({}) — no-op for Sprint 1", mode);
|
||||
}
|
||||
@@ -458,6 +470,44 @@ fn handle_talk(
|
||||
tracing::debug!(target_id, "Talk: TalkRequest marker set on player");
|
||||
}
|
||||
|
||||
/// Handle DialogueResponse action: set DialogueResponseRequest marker (#539).
|
||||
/// The follow-up dialogue pipeline runs in process_dialogue_response (dialogue.rs).
|
||||
#[allow(clippy::type_complexity)]
|
||||
fn handle_dialogue_response(
|
||||
commands: &mut Commands,
|
||||
registry: &EntityRegistry,
|
||||
player_query: &Query<
|
||||
(
|
||||
Entity,
|
||||
&TilePosition,
|
||||
Option<&mut Stance>,
|
||||
Option<&mut PlayerMoveCooldown>,
|
||||
),
|
||||
With<PlayerCharacter>,
|
||||
>,
|
||||
target_entity_id: u64,
|
||||
response_id: &str,
|
||||
) {
|
||||
let Ok((player_entity, _, _, _)) = player_query.single() else {
|
||||
return;
|
||||
};
|
||||
|
||||
let target_stable = StableId(target_entity_id);
|
||||
let Some(target_entity) = registry.to_entity(&target_stable) else {
|
||||
tracing::warn!(target_entity_id, "DialogueResponse: target entity not in registry");
|
||||
return;
|
||||
};
|
||||
|
||||
commands
|
||||
.entity(player_entity)
|
||||
.insert(crate::simulation::dialogue::DialogueResponseRequest {
|
||||
target: target_entity,
|
||||
response_id: response_id.to_string(),
|
||||
});
|
||||
|
||||
tracing::debug!(target_entity_id, response_id, "DialogueResponse: marker set on player");
|
||||
}
|
||||
|
||||
/// Handle Confront verb: set ConfrontationDelivered marker on the player entity (#520, D-063).
|
||||
/// The confrontation response system runs in process_confrontation_response (dialogue.rs).
|
||||
/// Server-side range check: Confront requires CLOSE_RANGE (same as Talk).
|
||||
@@ -741,7 +791,8 @@ fn handle_teleport_to_hub(
|
||||
.remove::<crate::simulation::dialogue::TalkRequest>()
|
||||
.remove::<crate::simulation::dialogue::ActiveDialogue>()
|
||||
.remove::<crate::simulation::dialogue::WalkAwayRequest>()
|
||||
.remove::<crate::simulation::dialogue::ConfrontationDelivered>();
|
||||
.remove::<crate::simulation::dialogue::ConfrontationDelivered>()
|
||||
.remove::<crate::simulation::dialogue::DialogueResponseRequest>();
|
||||
|
||||
tracing::info!(
|
||||
x = hub_spawn.x,
|
||||
|
||||
Reference in New Issue
Block a user