feat: let the player talk to villagers and accept or decline personal requests
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
class_name PlayerNegotiationSystem
|
||||
extends RefCounted
|
||||
|
||||
var quest_system: PlayerQuestSystem
|
||||
var npc_lookup: Callable
|
||||
var opportunity_provider: Callable
|
||||
var player_response_provider: Callable
|
||||
var quest_opened_signal: Signal
|
||||
var quest_expired_signal: Signal
|
||||
var standing_changed_signal: Signal
|
||||
|
||||
|
||||
func configure(
|
||||
quests: PlayerQuestSystem,
|
||||
lookup: Callable,
|
||||
opportunity_source: Callable,
|
||||
response_source: Callable,
|
||||
opened: Signal,
|
||||
expired: Signal,
|
||||
standing: Signal
|
||||
) -> void:
|
||||
quest_system = quests
|
||||
npc_lookup = lookup
|
||||
opportunity_provider = opportunity_source
|
||||
player_response_provider = response_source
|
||||
quest_opened_signal = opened
|
||||
quest_expired_signal = expired
|
||||
standing_changed_signal = standing
|
||||
|
||||
|
||||
func get_talk(npc_id: int) -> PlayerTalkResult:
|
||||
var npc := npc_lookup.call(npc_id) as SimNPC
|
||||
if npc == null or npc.is_dead:
|
||||
return null
|
||||
return quest_system.get_talk_for_requester(npc.id, npc.npc_name, opportunity_provider.call())
|
||||
|
||||
|
||||
func accept_request(npc_id: int, current_tick: int) -> PlayerQuestRecord:
|
||||
var npc := npc_lookup.call(npc_id) as SimNPC
|
||||
if npc == null:
|
||||
return null
|
||||
var opportunity: OpportunityStateRecord = opportunity_provider.call()
|
||||
if opportunity == null or opportunity.get_interested_npc_id() != npc.id:
|
||||
return null
|
||||
var result: Dictionary = quest_system.accept_opportunity_quest(
|
||||
opportunity, player_response_provider.call(), current_tick
|
||||
)
|
||||
var quest := result.get("quest") as PlayerQuestRecord
|
||||
if quest != null and result.get("created", false) and not quest_opened_signal.is_null():
|
||||
quest_opened_signal.emit(quest)
|
||||
return quest
|
||||
|
||||
|
||||
func decline_request(npc_id: int, current_tick: int) -> PlayerQuestRecord:
|
||||
var npc := npc_lookup.call(npc_id) as SimNPC
|
||||
if npc == null:
|
||||
return null
|
||||
var opportunity: OpportunityStateRecord = opportunity_provider.call()
|
||||
if opportunity == null or opportunity.get_interested_npc_id() != npc.id:
|
||||
return null
|
||||
var quest := quest_system.decline_opportunity_quest(opportunity, current_tick)
|
||||
if quest != null:
|
||||
if not quest_expired_signal.is_null():
|
||||
quest_expired_signal.emit(quest)
|
||||
if not standing_changed_signal.is_null():
|
||||
standing_changed_signal.emit(quest_system.standing)
|
||||
return quest
|
||||
@@ -0,0 +1 @@
|
||||
uid://7oayv5ga327o
|
||||
@@ -135,6 +135,58 @@ func on_opportunity_resolved(
|
||||
return {}
|
||||
|
||||
|
||||
func get_talk_for_requester(
|
||||
requester_id: int, requester_name: String, opportunity: OpportunityStateRecord
|
||||
) -> PlayerTalkResult:
|
||||
var has_need := opportunity != null and opportunity.is_open()
|
||||
var need_text := ""
|
||||
if has_need:
|
||||
need_text = "I'm worried about the %s." % String(opportunity.get_resource_id()).capitalize()
|
||||
var quest := get_latest_for_requester(requester_id)
|
||||
var quest_available := quest != null and quest.is_open()
|
||||
var reward := quest.get_standing_reward() if quest_available else 0.0
|
||||
var can_accept := has_need and (quest_available or can_request_personally(opportunity))
|
||||
return PlayerTalkResult.new(
|
||||
requester_id,
|
||||
requester_name,
|
||||
"%s greets you." % requester_name,
|
||||
has_need,
|
||||
need_text,
|
||||
quest_available,
|
||||
reward,
|
||||
can_accept,
|
||||
has_need
|
||||
)
|
||||
|
||||
|
||||
func accept_opportunity_quest(
|
||||
opportunity: OpportunityStateRecord,
|
||||
player_response: OpportunityPlayerResponseResult,
|
||||
current_tick: int
|
||||
) -> Dictionary:
|
||||
var existing := _find_open_quest_for_opportunity(opportunity.get_opportunity_id())
|
||||
if existing != null:
|
||||
return {"quest": existing, "created": false}
|
||||
var created := consider_opportunity_opened(
|
||||
opportunity, player_response, current_tick, can_request_personally(opportunity)
|
||||
)
|
||||
return {"quest": created, "created": created != null}
|
||||
|
||||
|
||||
func decline_opportunity_quest(
|
||||
opportunity: OpportunityStateRecord, current_tick: int
|
||||
) -> PlayerQuestRecord:
|
||||
var quest := _find_open_quest_for_opportunity(opportunity.get_opportunity_id())
|
||||
if quest == null:
|
||||
return null
|
||||
if not quest.expire(current_tick):
|
||||
return null
|
||||
var requester_id := quest.get_requester_npc_id()
|
||||
var gratitude := standing.get_gratitude(requester_id)
|
||||
standing.data["gratitude"][requester_id] = maxf(gratitude - 0.1, 0.0)
|
||||
return quest
|
||||
|
||||
|
||||
func on_opportunity_invalidated(
|
||||
opportunity: OpportunityStateRecord, current_tick: int
|
||||
) -> PlayerQuestRecord:
|
||||
@@ -146,6 +198,34 @@ func on_opportunity_invalidated(
|
||||
return null
|
||||
|
||||
|
||||
func consider_animal_care_quests(
|
||||
animal_care: AnimalCareSystem,
|
||||
npcs: Array[SimNPC],
|
||||
pantry: StorageStateRecord,
|
||||
current_tick: int
|
||||
) -> Array[PlayerQuestRecord]:
|
||||
var opened: Array[PlayerQuestRecord] = []
|
||||
for animal_state in animal_care.get_all_states():
|
||||
var requester := _nearest_npc_id(animal_state.get_position(), npcs)
|
||||
var quest := consider_animal_care(animal_state, requester, current_tick, pantry)
|
||||
if quest != null:
|
||||
opened.append(quest)
|
||||
return opened
|
||||
|
||||
|
||||
static func _nearest_npc_id(from_position: Vector3, npcs: Array[SimNPC]) -> int:
|
||||
var nearest_id := -1
|
||||
var nearest_distance := INF
|
||||
for npc in npcs:
|
||||
if npc.is_dead:
|
||||
continue
|
||||
var distance := npc.position.distance_squared_to(from_position)
|
||||
if distance < nearest_distance:
|
||||
nearest_distance = distance
|
||||
nearest_id = npc.id
|
||||
return nearest_id
|
||||
|
||||
|
||||
func get_active_quest() -> PlayerQuestRecord:
|
||||
for quest in quests:
|
||||
if quest.is_open():
|
||||
|
||||
Reference in New Issue
Block a user