feat: unify authored activity commands

This commit is contained in:
Rijad Zuzo
2026-08-13 00:08:30 +02:00
parent e5aecee0de
commit b3b98c6456
36 changed files with 3013 additions and 96 deletions
+15 -4
View File
@@ -5,8 +5,7 @@ const KIND_ANIMAL := &"animal"
const KIND_RESOURCE := &"resource"
const KIND_PANTRY := &"pantry"
const KIND_STORAGE_DEPOSIT := &"storage_deposit"
const KIND_GUARD := &"guard"
const KIND_STUDY := &"study"
const KIND_ACTIVITY := &"activity"
const KIND_DIALOGUE := &"dialogue"
var kind: StringName
@@ -17,6 +16,10 @@ var prompt_text: String
var detail_text: String
var blocked_reason: String
var target_node: Node
var expected_state_revision: int
var target_generation: int
var target_context_id: StringName
var target_registry_instance_id: int
func _init(
@@ -27,7 +30,7 @@ func _init(
interaction_prompt_text: String,
interaction_detail_text: String,
interaction_target_node: Node,
interaction_blocked_reason := ""
metadata: Dictionary = {}
) -> void:
kind = interaction_kind
action_id = interaction_action_id
@@ -36,7 +39,11 @@ func _init(
prompt_text = interaction_prompt_text
detail_text = interaction_detail_text
target_node = interaction_target_node
blocked_reason = interaction_blocked_reason
blocked_reason = String(metadata.get("blocked_reason", ""))
expected_state_revision = int(metadata.get("expected_state_revision", -1))
target_generation = int(metadata.get("target_generation", -1))
target_context_id = StringName(metadata.get("target_context_id", &""))
target_registry_instance_id = int(metadata.get("target_registry_instance_id", 0))
func is_available() -> bool:
@@ -54,6 +61,10 @@ func cache_key() -> String:
prompt_text,
detail_text,
blocked_reason,
str(expected_state_revision),
str(target_generation),
String(target_context_id),
str(target_registry_instance_id),
]
)
)
+68 -31
View File
@@ -117,16 +117,8 @@ func try_interact() -> void:
_execute_animal_interaction(context)
PlayerInteractionResult.KIND_RESOURCE:
_execute_resource_interaction(context)
PlayerInteractionResult.KIND_GUARD:
simulation_manager.add_safety(3.0)
interaction_feedback.emit(
"Village guarded", "Safety increased through real guard-post work.", true
)
PlayerInteractionResult.KIND_STUDY:
simulation_manager.add_knowledge(2.0)
interaction_feedback.emit(
"Knowledge shared", "Village knowledge increased at the study desk.", true
)
PlayerInteractionResult.KIND_ACTIVITY:
_execute_activity_interaction(context)
PlayerInteractionResult.KIND_PANTRY:
_execute_pantry_interaction(context)
PlayerInteractionResult.KIND_STORAGE_DEPOSIT:
@@ -153,26 +145,34 @@ func get_interaction_context() -> PlayerInteractionResult:
var resource := _find_resource_node()
if resource != null:
return _build_resource_context(resource)
if is_near_activity_site(guard_site):
return PlayerInteractionResult.new(
PlayerInteractionResult.KIND_GUARD,
SimulationIds.ACTION_PATROL,
guard_site.site_id,
guard_site.display_name,
"Help guard the village",
"Work here · +3 safety",
guard_site
)
if is_near_activity_site(study_site):
return PlayerInteractionResult.new(
PlayerInteractionResult.KIND_STUDY,
SimulationIds.ACTION_STUDY,
study_site.site_id,
study_site.display_name,
"Share knowledge",
"Work here · +2 knowledge",
study_site
if simulation_manager.has_method("get_player_activity_offer"):
var activity_offer: Dictionary = simulation_manager.call(
"get_player_activity_offer", global_position, interaction_range
)
if not activity_offer.is_empty():
var effect: Dictionary = activity_offer.get("effect", {})
var amount := float(effect.get("amount", 0.0))
var metric_name := String(effect.get("metric_id", "benefit")).capitalize()
return (
PlayerInteractionResult
. new(
PlayerInteractionResult.KIND_ACTIVITY,
StringName(activity_offer["action_id"]),
StringName(activity_offer["target_id"]),
String(activity_offer["display_name"]),
String(activity_offer["action_name"]),
"Work here · +%.1f %s" % [amount, metric_name.to_lower()],
null,
{
"blocked_reason": String(activity_offer.get("blocked_reason", "")),
"expected_state_revision": int(activity_offer.get("state_revision", -1)),
"target_generation": int(activity_offer.get("target_generation", -1)),
"target_context_id": String(activity_offer.get("target_context_id", "")),
"target_registry_instance_id":
int(activity_offer.get("target_registry_instance_id", 0)),
}
)
)
if is_near_storage(pantry_storage):
if _get_carried_food() > 0.0:
return _build_deposit_context(SimulationIds.RESOURCE_FOOD, pantry_storage)
@@ -429,7 +429,7 @@ func _build_animal_context(node: AnimalNode) -> PlayerInteractionResult:
"Feed %s" % node.display_name,
detail,
node,
blocked_reason
{"blocked_reason": blocked_reason}
)
@@ -469,7 +469,7 @@ func _build_pantry_context() -> PlayerInteractionResult:
"Eat from the pantry",
detail,
pantry_storage,
blocked_reason
{"blocked_reason": blocked_reason}
)
@@ -545,6 +545,43 @@ func _execute_resource_interaction(context: PlayerInteractionResult) -> void:
)
func _execute_activity_interaction(context: PlayerInteractionResult) -> void:
if not context.is_available():
interaction_feedback.emit(
"%s unavailable" % context.display_name, context.blocked_reason, false
)
return
if not simulation_manager.has_method("execute_player_activity_action"):
push_error("Player: SimulationManager cannot execute authored activity actions")
return
if simulation_manager.has_method("update_player_combatant"):
simulation_manager.call("update_player_combatant", global_position)
var result := (
simulation_manager.call(
"execute_player_activity_action",
context.action_id,
context.target_id,
context.expected_state_revision,
context.target_generation,
context.target_context_id,
context.target_registry_instance_id
)
as ActionResult
)
if result == null or not result.did_succeed():
var reason := result.get_message() if result != null else "Activity service unavailable."
interaction_feedback.emit("%s unavailable" % context.display_name, reason, false)
return
var payload := result.get_payload()
var amount := float(payload.get("amount", 0.0))
var metric_name := String(payload.get("metric_id", "benefit")).capitalize()
interaction_feedback.emit(
String(context.action_id).capitalize(),
"%s increased by %.1f through authoritative work." % [metric_name, amount],
true
)
func _execute_pantry_interaction(context: PlayerInteractionResult) -> void:
if not context.is_available():
interaction_feedback.emit("The pantry is empty", context.blocked_reason, false)