185 lines
6.3 KiB
GDScript
185 lines
6.3 KiB
GDScript
extends RefCounted
|
|
|
|
const AID_HUNGER_THRESHOLD := 80.0
|
|
const TRUSTED_HELP_THRESHOLD := 0.6
|
|
const FOOD_AID_TRUST_GAIN := 0.15
|
|
const SHARED_WORK_FAMILIARITY_GAIN := 0.1
|
|
|
|
var relationships: Dictionary = {}
|
|
|
|
|
|
func initialize_households(npcs: Array[SimNPC]) -> void:
|
|
relationships.clear()
|
|
for first_index in range(npcs.size()):
|
|
for second_index in range(first_index + 1, npcs.size()):
|
|
var first := npcs[first_index]
|
|
var second := npcs[second_index]
|
|
if first.home_position.distance_to(second.home_position) >= 4.0:
|
|
continue
|
|
_add(RelationshipStateRecord.create(first.id, second.id, 0.5))
|
|
_add(RelationshipStateRecord.create(second.id, first.id, 0.5))
|
|
|
|
|
|
func restore(records: Array[RelationshipStateRecord]) -> void:
|
|
relationships.clear()
|
|
for record in records:
|
|
_add(record)
|
|
|
|
|
|
func get_all_sorted() -> Array[RelationshipStateRecord]:
|
|
var records: Array[RelationshipStateRecord] = []
|
|
for record in relationships.values():
|
|
records.append(record)
|
|
records.sort_custom(_sort_relationships)
|
|
return records
|
|
|
|
|
|
func get_relationship(observer_id: int, subject_id: int) -> RelationshipStateRecord:
|
|
return relationships.get(_key(observer_id, subject_id)) as RelationshipStateRecord
|
|
|
|
|
|
func is_trusted_for_help(observer_id: int, subject_id: int) -> bool:
|
|
var relationship := get_relationship(observer_id, subject_id)
|
|
return (
|
|
relationship != null
|
|
and relationship.get_familiarity() > 0.0
|
|
and relationship.get_trust() >= TRUSTED_HELP_THRESHOLD
|
|
)
|
|
|
|
|
|
func increase_shared_work_familiarity(first_id: int, second_id: int) -> void:
|
|
var first_to_second := _get_or_create(first_id, second_id)
|
|
var second_to_first := _get_or_create(second_id, first_id)
|
|
first_to_second.increase_familiarity(SHARED_WORK_FAMILIARITY_GAIN)
|
|
second_to_first.increase_familiarity(SHARED_WORK_FAMILIARITY_GAIN)
|
|
|
|
|
|
func apply_event(
|
|
event: EconomicEventRecord, npcs: Array[SimNPC], knower_ids: Array[int]
|
|
) -> Array[RelationshipStateRecord]:
|
|
var changed: Array[RelationshipStateRecord] = []
|
|
if StringName(event.data["event_type"]) != SimulationIds.EVENT_STORAGE_DEPOSITED:
|
|
return changed
|
|
if StringName(event.data["item_id"]) != SimulationIds.RESOURCE_FOOD:
|
|
return changed
|
|
var contributor_id := int(event.data["actor_id"])
|
|
var event_id := int(event.data["event_id"])
|
|
if contributor_id < 0 or event_id < 0 or float(event.data["amount"]) <= 0.0:
|
|
return changed
|
|
for observer in npcs:
|
|
if observer.id == contributor_id or observer.is_dead:
|
|
continue
|
|
if observer.id not in knower_ids:
|
|
continue
|
|
if observer.hunger < AID_HUNGER_THRESHOLD:
|
|
continue
|
|
var relationship := get_relationship(observer.id, contributor_id)
|
|
if relationship == null or relationship.get_familiarity() <= 0.0:
|
|
continue
|
|
if event_id <= relationship.get_last_trust_cause_event_id():
|
|
continue
|
|
var applied := relationship.increase_trust(FOOD_AID_TRUST_GAIN, event_id)
|
|
if applied <= 0.0:
|
|
continue
|
|
changed.append(relationship)
|
|
return changed
|
|
|
|
|
|
func get_primary_relationship(observer_id: int) -> RelationshipStateRecord:
|
|
var best: RelationshipStateRecord
|
|
for relationship in relationships.values():
|
|
if relationship.get_observer_id() != observer_id:
|
|
continue
|
|
if best == null or _is_stronger(relationship, best):
|
|
best = relationship
|
|
return best
|
|
|
|
|
|
func get_most_familiar_living(
|
|
observer_id: int, npcs: Array[SimNPC], population_view: SimulationPopulationView = null
|
|
) -> SimNPC:
|
|
var effective_view := population_view
|
|
if effective_view == null:
|
|
effective_view = SimulationPopulationView.new(npcs)
|
|
var best_relationship: RelationshipStateRecord
|
|
for relationship in relationships.values():
|
|
if relationship.get_observer_id() != observer_id:
|
|
continue
|
|
if effective_view.get_living(relationship.get_subject_id()) == null:
|
|
continue
|
|
if (
|
|
best_relationship == null
|
|
or relationship.get_familiarity() > best_relationship.get_familiarity()
|
|
or (
|
|
is_equal_approx(relationship.get_familiarity(), best_relationship.get_familiarity())
|
|
and relationship.get_subject_id() < best_relationship.get_subject_id()
|
|
)
|
|
):
|
|
best_relationship = relationship
|
|
if best_relationship == null:
|
|
return null
|
|
return effective_view.get_living(best_relationship.get_subject_id())
|
|
|
|
|
|
func get_trusted_starving_subject(
|
|
observer_id: int, npcs: Array, population_view: SimulationPopulationView = null
|
|
) -> SimNPC:
|
|
var effective_view := population_view
|
|
if effective_view == null:
|
|
effective_view = SimulationPopulationView.new(npcs)
|
|
var best_relationship: RelationshipStateRecord
|
|
for relationship in relationships.values():
|
|
if relationship.get_observer_id() != observer_id:
|
|
continue
|
|
if relationship.get_trust() < TRUSTED_HELP_THRESHOLD:
|
|
continue
|
|
if effective_view.get_starving(relationship.get_subject_id()) == null:
|
|
continue
|
|
if (
|
|
best_relationship == null
|
|
or relationship.get_trust() > best_relationship.get_trust()
|
|
or (
|
|
is_equal_approx(relationship.get_trust(), best_relationship.get_trust())
|
|
and relationship.get_subject_id() < best_relationship.get_subject_id()
|
|
)
|
|
):
|
|
best_relationship = relationship
|
|
if best_relationship == null:
|
|
return null
|
|
return effective_view.get_starving(best_relationship.get_subject_id())
|
|
|
|
|
|
func _get_or_create(observer_id: int, subject_id: int) -> RelationshipStateRecord:
|
|
var relationship := get_relationship(observer_id, subject_id)
|
|
if relationship != null:
|
|
return relationship
|
|
relationship = RelationshipStateRecord.create(observer_id, subject_id, 0.0)
|
|
_add(relationship)
|
|
return relationship
|
|
|
|
|
|
func _add(relationship: RelationshipStateRecord) -> void:
|
|
relationships[_key(relationship.get_observer_id(), relationship.get_subject_id())] = relationship
|
|
|
|
|
|
static func _key(observer_id: int, subject_id: int) -> String:
|
|
return "%d:%d" % [observer_id, subject_id]
|
|
|
|
|
|
static func _sort_relationships(
|
|
first: RelationshipStateRecord, second: RelationshipStateRecord
|
|
) -> bool:
|
|
if first.get_observer_id() != second.get_observer_id():
|
|
return first.get_observer_id() < second.get_observer_id()
|
|
return first.get_subject_id() < second.get_subject_id()
|
|
|
|
|
|
static func _is_stronger(
|
|
candidate: RelationshipStateRecord, current: RelationshipStateRecord
|
|
) -> bool:
|
|
if not is_equal_approx(candidate.get_trust(), current.get_trust()):
|
|
return candidate.get_trust() > current.get_trust()
|
|
if not is_equal_approx(candidate.get_familiarity(), current.get_familiarity()):
|
|
return candidate.get_familiarity() > current.get_familiarity()
|
|
return candidate.get_subject_id() < current.get_subject_id()
|