class_name PlayerQuestSystem extends RefCounted const PANTRY_STANDING_REWARD := 8.0 const WOOD_STANDING_REWARD := 8.0 var quests: Array[PlayerQuestRecord] = [] var next_quest_id := 0 var standing := PlayerStandingRecord.create() func consider_opportunity_opened( opportunity: OpportunityStateRecord, player_response: OpportunityPlayerResponseResult, current_tick: int ) -> PlayerQuestRecord: if ( opportunity == null or not opportunity.is_open() or player_response == null or current_tick < 0 ): return null if _find_open_quest_for_opportunity(opportunity.get_opportunity_id()) != null: return null var reward := _standing_reward_for(opportunity) if reward <= 0.0: return null var quest := PlayerQuestRecord.create( next_quest_id, opportunity.get_opportunity_id(), opportunity.get_interested_npc_id(), opportunity.get_opportunity_type(), opportunity.get_resource_id(), opportunity.get_target_id(), opportunity.get_target_amount(), current_tick, reward ) next_quest_id += 1 quests.append(quest) return quest func on_opportunity_resolved( opportunity: OpportunityStateRecord, resolution_event: EconomicEventRecord, current_tick: int ) -> Dictionary: var quest := _find_open_quest_for_opportunity(opportunity.get_opportunity_id()) if quest == null or resolution_event == null: return {} var event_id := int(resolution_event.data["event_id"]) var actor_id := int(resolution_event.data["actor_id"]) if actor_id < 0: if not quest.complete(event_id, current_tick): return {} standing.grant_standing(quest.get_standing_reward(), quest.get_requester_npc_id()) return {"quest": quest, "completed": true} if quest.expire(current_tick): return {"quest": quest, "completed": false} return {} func on_opportunity_invalidated( opportunity: OpportunityStateRecord, current_tick: int ) -> PlayerQuestRecord: var quest := _find_open_quest_for_opportunity(opportunity.get_opportunity_id()) if quest == null: return null if quest.expire(current_tick): return quest return null func get_active_quest() -> PlayerQuestRecord: for quest in quests: if quest.is_open(): return quest return null func get_all_sorted() -> Array[PlayerQuestRecord]: var sorted := quests.duplicate() sorted.sort_custom(_sort_by_id) return sorted func get_latest_for_requester(requester_npc_id: int) -> PlayerQuestRecord: for index in range(quests.size() - 1, -1, -1): var quest := quests[index] if quest.get_requester_npc_id() == requester_npc_id: return quest return null func restore( records: Array[PlayerQuestRecord], restored_next_id: int, standing_record: PlayerStandingRecord ) -> void: quests = records.duplicate() quests.sort_custom(_sort_by_id) next_quest_id = maxi(restored_next_id, 0) standing = standing_record if standing_record != null else PlayerStandingRecord.create() func _find_open_quest_for_opportunity(opportunity_id: int) -> PlayerQuestRecord: for quest in quests: if quest.is_open() and quest.get_opportunity_id() == opportunity_id: return quest return null func _standing_reward_for(opportunity: OpportunityStateRecord) -> float: match opportunity.get_opportunity_type(): SimulationIds.OPPORTUNITY_RESTOCK_EMPTY_PANTRY: return PANTRY_STANDING_REWARD SimulationIds.OPPORTUNITY_SUPPLY_MISSING_WOOD: return WOOD_STANDING_REWARD return 0.0 static func _sort_by_id(first: PlayerQuestRecord, second: PlayerQuestRecord) -> bool: return first.get_quest_id() < second.get_quest_id()