221 lines
8.3 KiB
GDScript
221 lines
8.3 KiB
GDScript
extends GutTest
|
|
|
|
const RelationshipSystemScript := preload("res://simulation/relationships/RelationshipSystem.gd")
|
|
|
|
const CORE_EVENT_TYPE_IDS: Array[StringName] = [
|
|
SimulationIds.EVENT_RESOURCE_EXTRACTED,
|
|
SimulationIds.EVENT_STORAGE_DEPOSITED,
|
|
SimulationIds.EVENT_STORAGE_WITHDRAWN,
|
|
SimulationIds.EVENT_ITEM_CONSUMED,
|
|
SimulationIds.EVENT_NPC_SLEPT,
|
|
SimulationIds.EVENT_NPC_DIED,
|
|
SimulationIds.EVENT_TASK_STARTED,
|
|
SimulationIds.EVENT_TASK_BLOCKED,
|
|
SimulationIds.EVENT_RESOURCE_DEPLETED,
|
|
SimulationIds.EVENT_ANIMAL_FED,
|
|
SimulationIds.EVENT_VILLAGER_WEAK,
|
|
SimulationIds.EVENT_HOME_DAMAGED,
|
|
SimulationIds.EVENT_COMMITMENT_ACCEPTED,
|
|
SimulationIds.EVENT_COMMITMENT_FULFILLED,
|
|
SimulationIds.EVENT_COMMITMENT_BROKEN,
|
|
SimulationIds.EVENT_COMMITMENT_RELEASED,
|
|
SimulationIds.EVENT_COMMITMENT_SUPERSEDED,
|
|
SimulationIds.EVENT_COMBATANT_HURT,
|
|
SimulationIds.EVENT_COMBATANT_KILLED,
|
|
SimulationIds.EVENT_RAID_STARTED,
|
|
SimulationIds.EVENT_WAR_RESOLVED,
|
|
SimulationIds.EVENT_WAR_ABORTED,
|
|
SimulationIds.EVENT_WOLF_HUNT,
|
|
]
|
|
const CORE_SOCIAL_CONSEQUENCE_IDS: Array[StringName] = [
|
|
&"commitment_accepted_obligation",
|
|
&"commitment_broken_hostility",
|
|
&"commitment_broken_obligation",
|
|
&"commitment_broken_trust",
|
|
&"commitment_fulfilled_obligation",
|
|
&"commitment_fulfilled_trust",
|
|
&"commitment_released_obligation",
|
|
&"commitment_superseded_obligation",
|
|
&"player_food_aid_trust",
|
|
&"storage_food_aid_trust",
|
|
]
|
|
|
|
|
|
func test_core_catalog_authors_every_canonical_event_and_existing_social_effect() -> void:
|
|
var catalog := ContentCatalog.create_core()
|
|
assert_true(catalog.is_valid(), "%s" % [catalog.get_errors()])
|
|
assert_eq(_event_ids(catalog.get_event_types()), _sorted(CORE_EVENT_TYPE_IDS))
|
|
assert_eq(
|
|
_consequence_ids(catalog.get_social_consequences()), _sorted(CORE_SOCIAL_CONSEQUENCE_IDS)
|
|
)
|
|
for consequence in catalog.get_social_consequences():
|
|
assert_not_null(catalog.get_event_type(consequence.event_type_id))
|
|
assert_has(RelationshipStateRecord.DIMENSIONS, consequence.relationship_dimension_id)
|
|
assert_true(consequence.validate().is_empty(), "%s" % [consequence.validate()])
|
|
|
|
assert_eq(
|
|
float(catalog.get_social_consequence(&"storage_food_aid_trust").parameters["delta"]),
|
|
RelationshipSystemScript.FOOD_AID_TRUST_GAIN
|
|
)
|
|
assert_eq(
|
|
float(catalog.get_social_consequence(&"player_food_aid_trust").parameters["delta"]),
|
|
RelationshipSystemScript.FOOD_AID_TRUST_GAIN
|
|
)
|
|
assert_eq(
|
|
float(
|
|
(
|
|
catalog
|
|
. get_social_consequence(&"commitment_accepted_obligation")
|
|
. parameters["fallback_delta"]
|
|
)
|
|
),
|
|
CommitmentLifecycleService.ACCEPTED_OBLIGATION
|
|
)
|
|
assert_eq(
|
|
float(catalog.get_social_consequence(&"commitment_fulfilled_trust").parameters["delta"]),
|
|
CommitmentLifecycleService.FULFILLED_TRUST
|
|
)
|
|
assert_eq(
|
|
float(catalog.get_social_consequence(&"commitment_broken_trust").parameters["delta"]),
|
|
CommitmentLifecycleService.BROKEN_TRUST
|
|
)
|
|
assert_eq(
|
|
float(catalog.get_social_consequence(&"commitment_broken_hostility").parameters["delta"]),
|
|
CommitmentLifecycleService.BROKEN_HOSTILITY
|
|
)
|
|
var report := catalog.get_authoring_report()
|
|
assert_eq(report["event_types"], _event_ids(catalog.get_event_types()))
|
|
assert_eq(report["social_consequences"], _consequence_ids(catalog.get_social_consequences()))
|
|
|
|
|
|
func test_addon_event_and_consequence_are_data_only_and_order_independent() -> void:
|
|
var core := load(ContentCatalog.CORE_PACK_PATH) as SimulationContentPack
|
|
var addon := _pack(&"festival_addon")
|
|
addon.required_pack_ids = [&"core"]
|
|
var event := _event(&"festival_shared_meal", "Festival Shared Meal")
|
|
event.category = String(EventTypeDefinition.CATEGORY_SOCIAL)
|
|
event.parameters = {"public": true, "salience": 0.5, "topic": &"festival"}
|
|
var consequence := _consequence(
|
|
&"festival_shared_meal_affection",
|
|
event.event_type_id,
|
|
RelationshipStateRecord.DIMENSION_AFFECTION
|
|
)
|
|
consequence.parameters = {"delta": 0.05, "observer_role": "guest"}
|
|
addon.event_types = [event]
|
|
addon.social_consequences = [consequence]
|
|
|
|
var first := ContentCatalog.new()
|
|
var first_packs: Array[SimulationContentPack] = [addon, core]
|
|
assert_true(first.rebuild(first_packs).is_empty(), "%s" % [first.get_errors()])
|
|
assert_same(first.get_event_type(event.event_type_id), event)
|
|
assert_same(first.get_social_consequence(consequence.consequence_id), consequence)
|
|
|
|
var second := ContentCatalog.new()
|
|
var second_packs: Array[SimulationContentPack] = [core, addon]
|
|
assert_true(second.rebuild(second_packs).is_empty(), "%s" % [second.get_errors()])
|
|
assert_eq(first.get_authoring_report(), second.get_authoring_report())
|
|
assert_eq(_event_ids(first.get_event_types()), _sorted(_event_ids(first.get_event_types())))
|
|
assert_eq(
|
|
_consequence_ids(first.get_social_consequences()),
|
|
_sorted(_consequence_ids(first.get_social_consequences()))
|
|
)
|
|
|
|
|
|
func test_invalid_event_and_consequence_pack_publishes_nothing() -> void:
|
|
var core := load(ContentCatalog.CORE_PACK_PATH) as SimulationContentPack
|
|
var broken := _pack(&"broken_event_content")
|
|
broken.required_pack_ids = [&"core"]
|
|
var invalid_event := _event(&"invalid_event", "Invalid Event")
|
|
invalid_event.parameters = {"nested": {"not": "primitive"}}
|
|
broken.event_types = [core.event_types[0], invalid_event]
|
|
var predicate := SituationPredicate.new()
|
|
predicate.predicate_id = &"missing_event_predicate"
|
|
predicate.evaluator_id = &"event_type"
|
|
predicate.parameters = {"event_type": "missing_situation_event"}
|
|
var situation := SituationDefinition.new()
|
|
situation.situation_definition_id = &"missing_event_situation"
|
|
situation.display_name = "Missing event situation"
|
|
situation.trigger_predicates = [predicate]
|
|
broken.situations = [situation]
|
|
var invalid_consequence := _consequence(&"invalid_consequence", &"missing_event", &"rumour")
|
|
invalid_consequence.parameters = {"weights": [0.1, 0.2]}
|
|
broken.social_consequences = [core.social_consequences[0], invalid_consequence]
|
|
|
|
var catalog := ContentCatalog.create_core()
|
|
assert_true(catalog.is_valid())
|
|
var packs: Array[SimulationContentPack] = [broken, core]
|
|
var errors := catalog.rebuild(packs)
|
|
for expected in [
|
|
"Duplicate event_type_id",
|
|
"Duplicate social consequence_id",
|
|
"references unknown relationship dimension 'rumour'",
|
|
"references unknown event type 'missing_event'",
|
|
"references unknown event type 'missing_situation_event'",
|
|
"parameter 'nested' must be primitive",
|
|
"parameter 'weights' must be primitive",
|
|
]:
|
|
assert_true(_has_error(errors, expected), "%s missing from %s" % [expected, errors])
|
|
assert_false(catalog.is_valid())
|
|
assert_true(catalog.get_packs().is_empty())
|
|
assert_true(catalog.get_actions().is_empty())
|
|
assert_true(catalog.get_event_types().is_empty())
|
|
assert_true(catalog.get_social_consequences().is_empty())
|
|
assert_null(catalog.get_event_type(&"invalid_event"))
|
|
assert_null(catalog.get_social_consequence(&"invalid_consequence"))
|
|
|
|
|
|
func _pack(pack_id: StringName) -> SimulationContentPack:
|
|
var pack := SimulationContentPack.new()
|
|
pack.pack_id = pack_id
|
|
pack.display_name = String(pack_id).capitalize()
|
|
return pack
|
|
|
|
|
|
func _event(event_type_id: StringName, display_name: String) -> EventTypeDefinition:
|
|
var definition := EventTypeDefinition.new()
|
|
definition.event_type_id = event_type_id
|
|
definition.display_name = display_name
|
|
return definition
|
|
|
|
|
|
func _consequence(
|
|
consequence_id: StringName, event_type_id: StringName, dimension_id: StringName
|
|
) -> SocialConsequenceDefinition:
|
|
var definition := SocialConsequenceDefinition.new()
|
|
definition.consequence_id = consequence_id
|
|
definition.display_name = String(consequence_id).capitalize()
|
|
definition.event_type_id = event_type_id
|
|
definition.relationship_dimension_id = dimension_id
|
|
return definition
|
|
|
|
|
|
func _event_ids(definitions: Array[EventTypeDefinition]) -> Array[StringName]:
|
|
var ids: Array[StringName] = []
|
|
for definition in definitions:
|
|
ids.append(definition.event_type_id)
|
|
return ids
|
|
|
|
|
|
func _consequence_ids(
|
|
definitions: Array[SocialConsequenceDefinition],
|
|
) -> Array[StringName]:
|
|
var ids: Array[StringName] = []
|
|
for definition in definitions:
|
|
ids.append(definition.consequence_id)
|
|
return ids
|
|
|
|
|
|
func _sorted(ids: Array[StringName]) -> Array[StringName]:
|
|
var result := ids.duplicate()
|
|
result.sort_custom(
|
|
func(left: StringName, right: StringName) -> bool: return String(left) < String(right)
|
|
)
|
|
return result
|
|
|
|
|
|
func _has_error(errors: Array[String], fragment: String) -> bool:
|
|
for error in errors:
|
|
if fragment in error:
|
|
return true
|
|
return false
|