- Moved GateToCenter to sit right on the region-1/center table-edge border (angle 30° bisector, radius ~13.2, where that edge's chord actually sits) instead of a few units inside the region, and scaled the instance down to 0.5x. - target_position now lands just past the border on the table side (radius ~11.5 at the same angle) instead of teleporting to the absolute island center — "you walked through the gate," not "you warped across the map." - Gate is now genuinely non-interactive while locked: no prompt shown, _input() doesn't even check for the key press, and the marker shows "Verschlossen" instead of its real name (mirrors poi.gd's existing "???" pattern for undiscovered POIs). - Once unlocked, interacting opens a "Durchgehen?" Ja/Nein menu instead of teleporting immediately. Added InteractionManager.handle_interaction_action() delegation so POIs can own custom menu actions without hardcoding them into the shared manager. Verified headless: locked state hides the prompt and shows "Verschlossen"; unlocking (all 6 region1_pois visited) restores the real name and prompt; "Nein" leaves the player position untouched; "Ja" moves the player to exactly target_position.
69 lines
2.0 KiB
GDScript
69 lines
2.0 KiB
GDScript
extends Area3D
|
|
|
|
@export var poi_name: String = "Tor zur Mitte"
|
|
@export var locked_name: String = "Verschlossen"
|
|
@export var marker_color: Color = Color(1.0, 0.9, 0.4)
|
|
@export var required_group: String = "region1_pois"
|
|
@export var target_position: Vector3 = Vector3.ZERO
|
|
|
|
@onready var sprite: AnimatedSprite3D = $AnimatedSprite3D
|
|
@onready var name_label: Label3D = $Billboard/NameLabel
|
|
@onready var prompt: Label3D = $Billboard/InteractionPrompt
|
|
|
|
var player_nearby: bool = false
|
|
|
|
func _ready() -> void:
|
|
prompt.visible = false
|
|
prompt.text = "[F] Interact"
|
|
_update_visuals()
|
|
body_entered.connect(_on_body_entered)
|
|
body_exited.connect(_on_body_exited)
|
|
|
|
func _all_required_visited() -> bool:
|
|
var pois := get_tree().get_nodes_in_group(required_group)
|
|
if pois.is_empty():
|
|
return false
|
|
for poi in pois:
|
|
if not poi.visited:
|
|
return false
|
|
return true
|
|
|
|
func _update_visuals() -> void:
|
|
if _all_required_visited():
|
|
sprite.modulate = marker_color
|
|
name_label.text = poi_name
|
|
else:
|
|
sprite.modulate = marker_color * Color(0.35, 0.35, 0.35, 1.0)
|
|
name_label.text = locked_name
|
|
|
|
func _on_body_entered(body: Node3D) -> void:
|
|
if body.is_in_group("player"):
|
|
player_nearby = true
|
|
_update_visuals()
|
|
# Verschlossen: nicht ansprechbar, kein Prompt
|
|
prompt.visible = _all_required_visited()
|
|
|
|
func _on_body_exited(body: Node3D) -> void:
|
|
if body.is_in_group("player"):
|
|
player_nearby = false
|
|
prompt.visible = false
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if player_nearby and _all_required_visited() and Input.is_action_just_pressed("interact"):
|
|
InteractionManager.active = true
|
|
InteractionManager.current_poi = self
|
|
InteractionUI.show_menu("Durchgehen?", [
|
|
{ "label": "Ja", "action": "gate_yes" },
|
|
{ "label": "Nein", "action": "gate_no" },
|
|
])
|
|
|
|
func handle_interaction_action(action: String) -> void:
|
|
match action:
|
|
"gate_yes":
|
|
var player := get_tree().get_first_node_in_group("player")
|
|
if player:
|
|
player.global_position = target_position
|
|
InteractionManager.close()
|
|
"gate_no":
|
|
InteractionManager.close()
|