140 lines
4.3 KiB
GDScript
140 lines
4.3 KiB
GDScript
class_name QuestJournalSystem
|
|
extends RefCounted
|
|
|
|
var _entries_by_id: Dictionary = {}
|
|
var _entry_id_by_situation: Dictionary = {}
|
|
var _next_entry_id := 0
|
|
|
|
|
|
func add_situation(
|
|
situation: SituationStateRecord,
|
|
definition: SituationDefinition,
|
|
alternative_id: StringName,
|
|
current_tick: int
|
|
) -> QuestJournalEntryStateRecord:
|
|
if (
|
|
situation == null
|
|
or definition == null
|
|
or not situation.is_active()
|
|
or situation.get_definition_id() != definition.situation_definition_id
|
|
or (not alternative_id.is_empty() and definition.get_alternative(alternative_id) == null)
|
|
or current_tick < situation.get_created_tick()
|
|
or _entry_id_by_situation.has(situation.get_situation_id())
|
|
):
|
|
return null
|
|
if not alternative_id.is_empty() and not situation.select_alternative(alternative_id):
|
|
return null
|
|
var entry := QuestJournalEntryStateRecord.create(
|
|
_next_entry_id,
|
|
situation.get_situation_id(),
|
|
definition.situation_definition_id,
|
|
current_tick,
|
|
alternative_id
|
|
)
|
|
_entries_by_id[_next_entry_id] = entry
|
|
_entry_id_by_situation[situation.get_situation_id()] = _next_entry_id
|
|
_next_entry_id += 1
|
|
return entry
|
|
|
|
|
|
func select_alternative(
|
|
situation: SituationStateRecord, definition: SituationDefinition, alternative_id: StringName
|
|
) -> bool:
|
|
if (
|
|
situation == null
|
|
or definition == null
|
|
or alternative_id.is_empty()
|
|
or situation.get_definition_id() != definition.situation_definition_id
|
|
or definition.get_alternative(alternative_id) == null
|
|
):
|
|
return false
|
|
var entry := get_for_situation(situation.get_situation_id())
|
|
if entry == null or not entry.is_active():
|
|
return false
|
|
return situation.select_alternative(alternative_id) and entry.select_alternative(alternative_id)
|
|
|
|
|
|
func synchronize(
|
|
situation: SituationStateRecord, current_tick: int
|
|
) -> QuestJournalEntryStateRecord:
|
|
if situation == null:
|
|
return null
|
|
var entry := get_for_situation(situation.get_situation_id())
|
|
if entry == null or not entry.is_active() or situation.is_active():
|
|
return null
|
|
var status := QuestJournalEntryStateRecord.STATUS_ARCHIVED
|
|
if situation.get_status() == SituationStateRecord.STATUS_RESOLVED:
|
|
status = QuestJournalEntryStateRecord.STATUS_COMPLETED
|
|
elif situation.get_status() == SituationStateRecord.STATUS_EXPIRED:
|
|
status = QuestJournalEntryStateRecord.STATUS_FAILED
|
|
return entry if entry.close(status, current_tick) else null
|
|
|
|
|
|
func derive_progress(
|
|
entry: QuestJournalEntryStateRecord,
|
|
situation_system: SituationSystem,
|
|
world_events: WorldEventStore,
|
|
state_facts: Dictionary
|
|
) -> SituationProgressSnapshot:
|
|
if entry == null or situation_system == null:
|
|
return SituationProgressSnapshot.new()
|
|
return situation_system.derive_progress(
|
|
situation_system.get_by_id(entry.get_situation_id()),
|
|
world_events,
|
|
state_facts,
|
|
entry.get_selected_alternative_id()
|
|
)
|
|
|
|
|
|
func restore(records: Array[QuestJournalEntryStateRecord], restored_next_id: int) -> bool:
|
|
var by_id: Dictionary = {}
|
|
var by_situation: Dictionary = {}
|
|
var next_id := maxi(restored_next_id, 0)
|
|
for record in records:
|
|
if (
|
|
record == null
|
|
or by_id.has(record.get_entry_id())
|
|
or by_situation.has(record.get_situation_id())
|
|
):
|
|
return false
|
|
by_id[record.get_entry_id()] = record
|
|
by_situation[record.get_situation_id()] = record.get_entry_id()
|
|
next_id = maxi(next_id, record.get_entry_id() + 1)
|
|
_entries_by_id = by_id
|
|
_entry_id_by_situation = by_situation
|
|
_next_entry_id = next_id
|
|
return true
|
|
|
|
|
|
func get_by_id(entry_id: int) -> QuestJournalEntryStateRecord:
|
|
return _entries_by_id.get(entry_id) as QuestJournalEntryStateRecord
|
|
|
|
|
|
func get_for_situation(situation_id: int) -> QuestJournalEntryStateRecord:
|
|
if not _entry_id_by_situation.has(situation_id):
|
|
return null
|
|
return get_by_id(int(_entry_id_by_situation[situation_id]))
|
|
|
|
|
|
func get_all_sorted() -> Array[QuestJournalEntryStateRecord]:
|
|
var records: Array[QuestJournalEntryStateRecord] = []
|
|
for record in _entries_by_id.values():
|
|
records.append(record)
|
|
records.sort_custom(
|
|
func(first: QuestJournalEntryStateRecord, second: QuestJournalEntryStateRecord) -> bool:
|
|
return first.get_entry_id() < second.get_entry_id()
|
|
)
|
|
return records
|
|
|
|
|
|
func get_active_sorted() -> Array[QuestJournalEntryStateRecord]:
|
|
var records: Array[QuestJournalEntryStateRecord] = []
|
|
for record in get_all_sorted():
|
|
if record.is_active():
|
|
records.append(record)
|
|
return records
|
|
|
|
|
|
func get_next_entry_id() -> int:
|
|
return _next_entry_id
|