2025-01-21 13:49:37 +00:00
|
|
|
|
@tool
|
2025-01-20 13:45:47 +00:00
|
|
|
|
class_name Portal2D extends Sprite2D
|
2024-12-26 13:58:37 +00:00
|
|
|
|
|
2025-03-10 14:21:42 +00:00
|
|
|
|
signal before_pre_transport_wait
|
|
|
|
|
|
2025-01-30 04:50:52 +00:00
|
|
|
|
@export_multiline var debug_note: String = ""
|
2025-01-20 13:45:47 +00:00
|
|
|
|
@export var enabled := true:
|
|
|
|
|
set(val):
|
|
|
|
|
enabled = val
|
2025-01-30 04:50:52 +00:00
|
|
|
|
_check_sign_mark_and_texture()
|
2025-02-06 12:19:45 +00:00
|
|
|
|
@export var immediately := false
|
2024-12-27 13:32:12 +00:00
|
|
|
|
@export_enum("left", "right", "1", "2", "3", "4", "5", "6", "7", "8", "9") var portal_name := "left":
|
2024-12-26 13:58:37 +00:00
|
|
|
|
set(value):
|
2024-12-27 13:32:12 +00:00
|
|
|
|
#if portal_name:
|
|
|
|
|
#remove_from_group("portal_"+portal_name)
|
2024-12-26 13:58:37 +00:00
|
|
|
|
portal_name = value
|
2024-12-27 13:32:12 +00:00
|
|
|
|
#add_to_group("portal_"+value)
|
|
|
|
|
name = "portal_" + value
|
|
|
|
|
@export var target_scene := "c02_s00"
|
|
|
|
|
@export_enum("none", "left", "right", "1", "2", "3", "4", "5", "6", "7", "8", "9")
|
2025-01-20 13:45:47 +00:00
|
|
|
|
var target_portal := "none":
|
|
|
|
|
set(value):
|
|
|
|
|
target_portal = value
|
2025-01-30 04:50:52 +00:00
|
|
|
|
_check_sign_mark_and_texture()
|
|
|
|
|
@export_enum("default", "locked", "opened") var status := "default":
|
|
|
|
|
set(value):
|
|
|
|
|
status = value
|
|
|
|
|
# 只在编辑器模式下检查
|
|
|
|
|
if is_node_ready() and Engine.is_editor_hint():
|
|
|
|
|
_check_sign_mark_and_texture()
|
2025-03-10 14:21:42 +00:00
|
|
|
|
@export var pre_transport_wait_time := 0.0
|
2025-02-14 11:04:21 +00:00
|
|
|
|
# holding 意味着当前门禁用,不可传送,需要先完成某些条件
|
|
|
|
|
@export var holding := false
|
|
|
|
|
@export var holding_reason_key := ""
|
2025-01-12 11:36:41 +00:00
|
|
|
|
@export var default_texture: Texture2D
|
|
|
|
|
@export var opened_texture: Texture2D
|
2025-06-04 11:46:27 +00:00
|
|
|
|
@export var unrevealed_sign_texture: Texture2D
|
2025-01-30 04:50:52 +00:00
|
|
|
|
@export var default_sign_texture: Texture2D
|
|
|
|
|
@export var opened_sign_texture: Texture2D
|
|
|
|
|
@export var matched_sign_texture: Texture2D
|
2025-06-04 11:46:27 +00:00
|
|
|
|
@export var locked_sign_texture: Texture2D
|
|
|
|
|
|
2025-01-30 04:50:52 +00:00
|
|
|
|
var prop_key := ""
|
|
|
|
|
@export var disable_key_after_used := true
|
2024-12-26 13:58:37 +00:00
|
|
|
|
|
2025-01-30 04:50:52 +00:00
|
|
|
|
# 穿过通道的音效
|
|
|
|
|
@onready var sfx_default = %SfxDefault as Sfx
|
|
|
|
|
# 开锁的音效
|
|
|
|
|
@onready var sfx_open = %SfxOpen as Sfx
|
|
|
|
|
# 进门的音效
|
|
|
|
|
@onready var sfx_enter = %SfxEnter as Sfx
|
|
|
|
|
# 门被锁定,无法打开的音效
|
|
|
|
|
@onready var sfx_locked = %SfxLocked as Sfx
|
2025-01-08 00:51:09 +00:00
|
|
|
|
@onready var sign_mark = %Sign as Sign
|
2024-12-26 13:58:37 +00:00
|
|
|
|
@onready var area2d = %Area2D as Area2D
|
|
|
|
|
|
2024-12-27 13:32:12 +00:00
|
|
|
|
var activated := false
|
2025-01-30 04:50:52 +00:00
|
|
|
|
|
|
|
|
|
static var item_config_res = preload("res://asset/dialogue/item_description.dialogue")
|
|
|
|
|
var items: PackedStringArray
|
|
|
|
|
|
|
|
|
|
var ground_archive: GroundArchive
|
2024-12-27 13:32:12 +00:00
|
|
|
|
|
2025-06-04 11:46:27 +00:00
|
|
|
|
# 尝试互动的次数
|
|
|
|
|
var tried_times: int:
|
|
|
|
|
set(val):
|
|
|
|
|
tried_times = val
|
|
|
|
|
ground_archive.set_pair(name, "tried_times", val)
|
2024-12-26 13:58:37 +00:00
|
|
|
|
|
|
|
|
|
# Called when the node enters the scene tree for the first time.
|
|
|
|
|
func _ready() -> void:
|
2024-12-27 13:32:12 +00:00
|
|
|
|
name = "portal_" + portal_name
|
2025-01-12 11:36:41 +00:00
|
|
|
|
if Engine.is_editor_hint():
|
2025-01-30 04:50:52 +00:00
|
|
|
|
_check_sign_mark_and_texture()
|
|
|
|
|
_reload_items()
|
2025-01-12 11:36:41 +00:00
|
|
|
|
return
|
2025-01-30 04:50:52 +00:00
|
|
|
|
ground_archive = ArchiveManager.archive.ground_archive()
|
2025-06-04 11:46:27 +00:00
|
|
|
|
tried_times = ground_archive.get_value(name, "tried_times", 0)
|
2025-01-30 04:50:52 +00:00
|
|
|
|
status = ground_archive.get_value(name, "status", status)
|
|
|
|
|
if GlobalConfig.DEBUG:
|
|
|
|
|
print("Portal read status [", name, "] status=", status)
|
|
|
|
|
_check_sign_mark_and_texture()
|
2024-12-26 13:58:37 +00:00
|
|
|
|
area2d.body_entered.connect(_reset)
|
|
|
|
|
area2d.body_exited.connect(_on_cancel)
|
|
|
|
|
sign_mark.interacted.connect(_on_interacted)
|
|
|
|
|
sign_mark.cancel.connect(_on_cancel)
|
2024-12-27 13:32:12 +00:00
|
|
|
|
|
2025-01-30 04:50:52 +00:00
|
|
|
|
|
|
|
|
|
func _reload_items() -> void:
|
|
|
|
|
items.clear()
|
|
|
|
|
var id = item_config_res.titles["PropItems"]
|
|
|
|
|
var current_line = item_config_res.lines[id]
|
|
|
|
|
while current_line:
|
|
|
|
|
if current_line.has("translation_key"):
|
|
|
|
|
items.append(current_line.translation_key)
|
|
|
|
|
if not current_line.has("next_id") or current_line.next_id == "end":
|
|
|
|
|
break
|
|
|
|
|
current_line = item_config_res.lines[current_line.next_id]
|
|
|
|
|
notify_property_list_changed()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _check_sign_mark_and_texture():
|
2025-01-21 13:49:37 +00:00
|
|
|
|
if not is_node_ready():
|
|
|
|
|
return
|
2025-01-30 04:50:52 +00:00
|
|
|
|
if status == "opened" and opened_texture:
|
|
|
|
|
texture = opened_texture
|
|
|
|
|
elif default_texture:
|
|
|
|
|
texture = default_texture
|
2025-06-04 11:46:27 +00:00
|
|
|
|
if status == "default":
|
|
|
|
|
sign_mark.sprite2d.texture = default_sign_texture
|
|
|
|
|
else:
|
|
|
|
|
# holding 状态下,同样显示 unrevealed_sign_texture
|
|
|
|
|
if tried_times == 0 or holding:
|
|
|
|
|
sign_mark.sprite2d.texture = unrevealed_sign_texture
|
|
|
|
|
else:
|
|
|
|
|
match status:
|
|
|
|
|
"locked":
|
|
|
|
|
sign_mark.sprite2d.texture = locked_sign_texture
|
|
|
|
|
"opened":
|
|
|
|
|
sign_mark.sprite2d.texture = opened_sign_texture
|
2025-01-20 13:45:47 +00:00
|
|
|
|
if target_portal == "none" or not enabled:
|
|
|
|
|
sign_mark.enabled = false
|
|
|
|
|
else:
|
|
|
|
|
sign_mark.enabled = true
|
|
|
|
|
|
2025-01-30 04:50:52 +00:00
|
|
|
|
|
|
|
|
|
var interact_mutex = Mutex.new()
|
|
|
|
|
|
|
|
|
|
|
2024-12-26 13:58:37 +00:00
|
|
|
|
func _on_interacted() -> void:
|
2025-06-04 11:46:27 +00:00
|
|
|
|
tried_times += 1
|
2025-02-14 11:04:21 +00:00
|
|
|
|
if holding:
|
|
|
|
|
if holding_reason_key:
|
2025-06-07 09:04:08 +00:00
|
|
|
|
SceneManager.pop_os_with_str(holding_reason_key)
|
2025-02-14 11:04:21 +00:00
|
|
|
|
return
|
2025-01-30 04:50:52 +00:00
|
|
|
|
if target_portal == "none" or not enabled:
|
|
|
|
|
return
|
|
|
|
|
interact_mutex.lock()
|
|
|
|
|
if status == "locked":
|
|
|
|
|
# 检查是否有钥匙,尝试打开
|
|
|
|
|
var key = SceneManager.get_current_prop(false)
|
|
|
|
|
if prop_key and key == prop_key:
|
|
|
|
|
sfx_open.global_play()
|
|
|
|
|
status = "opened"
|
|
|
|
|
ground_archive.set_pair(name, "status", status)
|
|
|
|
|
if disable_key_after_used:
|
|
|
|
|
SceneManager.disable_prop_item(key)
|
|
|
|
|
else:
|
|
|
|
|
sfx_locked.global_play()
|
2025-06-04 11:46:27 +00:00
|
|
|
|
sign_mark.invalid_shake(locked_sign_texture, locked_sign_texture)
|
2025-01-30 04:50:52 +00:00
|
|
|
|
_check_sign_mark_and_texture()
|
|
|
|
|
interact_mutex.unlock()
|
|
|
|
|
# 开锁尝试后,哪怕开锁成功,也需要下次操作再进入,而不是立即传送
|
2024-12-27 13:32:12 +00:00
|
|
|
|
return
|
2025-01-14 00:56:51 +00:00
|
|
|
|
# 传送,queue free 导致 sfx 无法播放,使用全局声源
|
2025-01-30 04:50:52 +00:00
|
|
|
|
if status == "default":
|
|
|
|
|
sfx_default.global_play()
|
|
|
|
|
elif status == "opened":
|
|
|
|
|
sfx_enter.global_play()
|
|
|
|
|
else:
|
|
|
|
|
sfx_locked.global_play()
|
|
|
|
|
interact_mutex.unlock()
|
|
|
|
|
return
|
|
|
|
|
interact_mutex.unlock()
|
2025-03-10 14:21:42 +00:00
|
|
|
|
before_pre_transport_wait.emit()
|
|
|
|
|
if pre_transport_wait_time > 0.0:
|
|
|
|
|
await get_tree().create_timer(pre_transport_wait_time).timeout
|
2024-12-27 13:32:12 +00:00
|
|
|
|
if GlobalConfig.DEBUG:
|
2025-01-21 07:58:21 +00:00
|
|
|
|
print("传送前往", target_scene, target_portal, " immediately=", immediately)
|
2024-12-27 13:32:12 +00:00
|
|
|
|
var ground_loader = SceneManager.get_ground_loader() as GroundLoader
|
|
|
|
|
if ground_loader:
|
2025-02-04 13:30:43 +00:00
|
|
|
|
if immediately:
|
|
|
|
|
ground_loader.transition_to_scene(target_scene, target_portal, 0.0)
|
|
|
|
|
else:
|
|
|
|
|
ground_loader.transition_to_scene(target_scene, target_portal)
|
2024-12-27 13:32:12 +00:00
|
|
|
|
|
2024-12-26 13:58:37 +00:00
|
|
|
|
|
2024-12-27 07:56:45 +00:00
|
|
|
|
func _on_cancel(_body = null):
|
2024-12-27 13:32:12 +00:00
|
|
|
|
activated = false
|
2025-01-30 04:50:52 +00:00
|
|
|
|
# disconnect signal
|
|
|
|
|
var prop_hud = SceneManager.get_prop_hud() as PropHud
|
|
|
|
|
if prop_hud and prop_hud.current_item_changed.is_connected(_set_sign_texture_to_prop):
|
|
|
|
|
prop_hud.current_item_changed.disconnect(_set_sign_texture_to_prop)
|
2024-12-27 13:32:12 +00:00
|
|
|
|
|
2024-12-26 13:58:37 +00:00
|
|
|
|
|
2024-12-27 07:56:45 +00:00
|
|
|
|
func _reset(_body):
|
2025-01-30 04:50:52 +00:00
|
|
|
|
_check_sign_mark_and_texture()
|
2024-12-27 13:32:12 +00:00
|
|
|
|
activated = true
|
2025-01-30 04:50:52 +00:00
|
|
|
|
if status == "locked":
|
|
|
|
|
var key = SceneManager.get_current_prop(false)
|
|
|
|
|
if key:
|
|
|
|
|
_set_sign_texture_to_prop(key)
|
|
|
|
|
var prop_hud = SceneManager.get_prop_hud() as PropHud
|
|
|
|
|
if not prop_hud.current_item_changed.is_connected(_set_sign_texture_to_prop):
|
|
|
|
|
prop_hud.current_item_changed.connect(_set_sign_texture_to_prop)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# 根据当前 prop,调整 sign 所显示的 texture
|
|
|
|
|
func _set_sign_texture_to_prop(key):
|
2025-06-04 11:46:27 +00:00
|
|
|
|
# if not prop_key or prop_key == key:
|
|
|
|
|
# sign_mark.sprite2d.texture = matched_sign_texture
|
|
|
|
|
# else:
|
|
|
|
|
if tried_times:
|
|
|
|
|
sign_mark.sprite2d.texture = locked_sign_texture
|
2025-01-30 04:50:52 +00:00
|
|
|
|
else:
|
2025-06-04 11:46:27 +00:00
|
|
|
|
sign_mark.sprite2d.texture = unrevealed_sign_texture
|
2025-01-30 04:50:52 +00:00
|
|
|
|
|
2024-12-27 13:32:12 +00:00
|
|
|
|
|
2025-01-12 06:02:00 +00:00
|
|
|
|
# 暂时不启用自动传送
|
2025-01-30 04:50:52 +00:00
|
|
|
|
# var action_times := 0
|
2025-01-12 06:02:00 +00:00
|
|
|
|
# func _input(event: InputEvent) -> void:
|
|
|
|
|
# # 长按自动传送
|
|
|
|
|
# if activated:
|
|
|
|
|
# if portal_name == "left" and target_portal == "right":
|
|
|
|
|
# if event.is_action("left"):
|
|
|
|
|
# action_times += 1
|
|
|
|
|
# elif event.is_action("right"):
|
|
|
|
|
# action_times = 0
|
|
|
|
|
# if action_times >= 7:
|
|
|
|
|
# activated = false
|
|
|
|
|
# action_times = 0
|
|
|
|
|
# %Sfx.play()
|
|
|
|
|
# _on_interacted()
|
|
|
|
|
# if portal_name == "right" and target_portal == "left":
|
|
|
|
|
# if event.is_action("right"):
|
|
|
|
|
# action_times += 1
|
|
|
|
|
# elif event.is_action("left"):
|
|
|
|
|
# action_times = 0
|
|
|
|
|
# if action_times >= 7:
|
|
|
|
|
# activated = false
|
|
|
|
|
# action_times = 0
|
|
|
|
|
# %Sfx.play()
|
|
|
|
|
# _on_interacted()
|
2025-01-30 04:50:52 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _get_property_list() -> Array[Dictionary]:
|
|
|
|
|
return [
|
|
|
|
|
{
|
|
|
|
|
"name": "prop_key",
|
|
|
|
|
"type": TYPE_STRING,
|
|
|
|
|
"hint": PROPERTY_HINT_ENUM_SUGGESTION,
|
|
|
|
|
"hint_string": ",".join(items),
|
|
|
|
|
}
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _get(property: StringName) -> Variant:
|
|
|
|
|
if property == "prop_key":
|
|
|
|
|
return prop_key
|
|
|
|
|
return null
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _set(property: StringName, value: Variant) -> bool:
|
|
|
|
|
if property == "prop_key":
|
|
|
|
|
prop_key = value
|
|
|
|
|
return true
|
|
|
|
|
return false
|