feat: let the player talk to villagers and accept or decline personal requests

This commit is contained in:
2026-08-09 00:10:36 +02:00
parent 5e6c963d23
commit 0936ae6450
10 changed files with 520 additions and 36 deletions
+78
View File
@@ -72,6 +72,8 @@ func try_interact() -> void:
_execute_resource_interaction(context)
PlayerInteractionResult.KIND_DEPOSIT:
_execute_deposit_interaction(context)
PlayerInteractionResult.KIND_TALK:
_execute_talk_interaction(context)
PlayerInteractionResult.KIND_GUARD:
simulation_manager.add_safety(3.0)
interaction_feedback.emit(
@@ -131,9 +133,53 @@ func get_interaction_context() -> PlayerInteractionResult:
)
if is_near_storage(pantry_storage):
return _build_pantry_context()
var talk_npc := _find_talk_villager()
if talk_npc != null:
return _build_talk_context(talk_npc)
return null
func _find_talk_villager() -> SimNPC:
if (
simulation_manager == null
or world_view_manager == null
or not world_view_manager.has_method("find_nearest_active_npc_id")
):
return null
var npc_id: int = world_view_manager.find_nearest_active_npc_id(
global_position, interaction_range
)
if npc_id < 0:
return null
var npc := _find_npc(npc_id)
if npc == null or npc.is_dead:
return null
return npc
func _build_talk_context(npc: SimNPC) -> PlayerInteractionResult:
var talk: PlayerTalkResult = simulation_manager.get_villager_talk(npc.id)
if talk == null or not talk.has_need:
return null
var prompt := "Talk to %s" % npc.npc_name
if talk.quest_available:
prompt = "Accept %s's request" % npc.npc_name
elif talk.can_accept:
prompt = "Offer to help %s" % npc.npc_name
var detail := talk.need_text
if talk.quest_available:
detail = "Help +%.0f Standing" % talk.quest_reward
return PlayerInteractionResult.new(
PlayerInteractionResult.KIND_TALK,
SimulationIds.ACTION_IDLE,
SimulationIds.npc_inventory_id(npc.id),
npc.npc_name,
prompt,
detail,
null
)
func get_nearby_villager_inspection() -> VillagerInspectionResult:
if (
simulation_manager == null
@@ -437,6 +483,38 @@ func _execute_deposit_interaction(context: PlayerInteractionResult) -> void:
)
func _execute_talk_interaction(context: PlayerInteractionResult) -> void:
var npc_id := _talk_npc_id_from_target(context.target_id)
if npc_id < 0:
return
var quest: PlayerQuestRecord = simulation_manager.accept_villager_request(npc_id)
if quest == null:
interaction_feedback.emit(
"%s declines" % context.display_name,
"They have no request you can accept right now.",
false
)
return
interaction_feedback.emit(
"Request accepted",
(
"%s asked you for help · +%.0f Standing on completion"
% [context.display_name, quest.get_standing_reward()]
),
true
)
func _talk_npc_id_from_target(target_id: StringName) -> int:
var prefix := "npc_"
var suffix := "_inventory"
var raw := String(target_id)
if not raw.begins_with(prefix) or not raw.ends_with(suffix):
return -1
var id_text := raw.trim_prefix(prefix).trim_suffix(suffix)
return id_text.to_int()
func _execute_pantry_interaction(context: PlayerInteractionResult) -> void:
if not context.is_available():
interaction_feedback.emit("The pantry is empty", context.blocked_reason, false)