Rework the gate: smaller, right at the border, locked until ready, Yes/No prompt

- 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.
This commit is contained in:
Jonas Reith 2026-08-26 21:38:27 +02:00
parent c20d71f043
commit b430d929c5
3 changed files with 28 additions and 15 deletions

View File

@ -27,6 +27,10 @@ func handle_selection(action: String) -> void:
InteractionUI.show_text("Du rastest eine Weile...\nDu fühlst dich erholt.") InteractionUI.show_text("Du rastest eine Weile...\nDu fühlst dich erholt.")
"close": "close":
close() close()
_:
# POI-spezifische Aktionen (z.B. Ja/Nein bei einem Portal)
if current_poi and current_poi.has_method("handle_interaction_action"):
current_poi.handle_interaction_action(action)
# Für POIs außerhalb des generischen Menüs (z.B. Portale): Panel mit reinem # Für POIs außerhalb des generischen Menüs (z.B. Portale): Panel mit reinem
# Info-Text öffnen, ohne die Erkunden/Ausruhen/Beenden-Optionen. # Info-Text öffnen, ohne die Erkunden/Ausruhen/Beenden-Optionen.

View File

@ -237,9 +237,9 @@ poi_name = "Ort 6"
marker_color = Color(0.7, 0.3, 0.9, 1) marker_color = Color(0.7, 0.3, 0.9, 1)
[node name="GateToCenter" parent="." instance=ExtResource("5_gate")] [node name="GateToCenter" parent="." instance=ExtResource("5_gate")]
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 14.72, 0.157, 8.5) transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 11.4315, 0.3, 6.6)
poi_name = "Tor zur Mitte" poi_name = "Tor zur Mitte"
target_position = Vector3(0, 0.5, 0) target_position = Vector3(9.959, 0.5, 5.75)
[node name="Node3D" type="Node3D" parent="." unique_id=597556846] [node name="Node3D" type="Node3D" parent="." unique_id=597556846]
transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 3.6214647, -0.23645921, 0.47627413) transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 3.6214647, -0.23645921, 0.47627413)

View File

@ -1,6 +1,7 @@
extends Area3D extends Area3D
@export var poi_name: String = "Tor zur Mitte" @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 marker_color: Color = Color(1.0, 0.9, 0.4)
@export var required_group: String = "region1_pois" @export var required_group: String = "region1_pois"
@export var target_position: Vector3 = Vector3.ZERO @export var target_position: Vector3 = Vector3.ZERO
@ -14,7 +15,6 @@ var player_nearby: bool = false
func _ready() -> void: func _ready() -> void:
prompt.visible = false prompt.visible = false
prompt.text = "[F] Interact" prompt.text = "[F] Interact"
name_label.text = poi_name
_update_visuals() _update_visuals()
body_entered.connect(_on_body_entered) body_entered.connect(_on_body_entered)
body_exited.connect(_on_body_exited) body_exited.connect(_on_body_exited)
@ -31,14 +31,17 @@ func _all_required_visited() -> bool:
func _update_visuals() -> void: func _update_visuals() -> void:
if _all_required_visited(): if _all_required_visited():
sprite.modulate = marker_color sprite.modulate = marker_color
name_label.text = poi_name
else: else:
sprite.modulate = marker_color * Color(0.4, 0.4, 0.4, 1.0) 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: func _on_body_entered(body: Node3D) -> void:
if body.is_in_group("player"): if body.is_in_group("player"):
player_nearby = true player_nearby = true
prompt.visible = true
_update_visuals() _update_visuals()
# Verschlossen: nicht ansprechbar, kein Prompt
prompt.visible = _all_required_visited()
func _on_body_exited(body: Node3D) -> void: func _on_body_exited(body: Node3D) -> void:
if body.is_in_group("player"): if body.is_in_group("player"):
@ -46,14 +49,20 @@ func _on_body_exited(body: Node3D) -> void:
prompt.visible = false prompt.visible = false
func _input(event: InputEvent) -> void: func _input(event: InputEvent) -> void:
if player_nearby and Input.is_action_just_pressed("interact"): if player_nearby and _all_required_visited() and Input.is_action_just_pressed("interact"):
_try_transition() InteractionManager.active = true
InteractionManager.current_poi = self
InteractionUI.show_menu("Durchgehen?", [
{ "label": "Ja", "action": "gate_yes" },
{ "label": "Nein", "action": "gate_no" },
])
func _try_transition() -> void: func handle_interaction_action(action: String) -> void:
if _all_required_visited(): match action:
InteractionManager.open_message(self, poi_name, "Du betrittst die Mitte der Insel.") "gate_yes":
var player := get_tree().get_first_node_in_group("player") var player := get_tree().get_first_node_in_group("player")
if player: if player:
player.global_position = target_position player.global_position = target_position
else: InteractionManager.close()
InteractionManager.open_message(self, poi_name, "Hier geht es noch nicht weiter.\nErst müssen alle sechs Orte dieser Region erkundet sein.") "gate_no":
InteractionManager.close()