228 lines
6.5 KiB
GDScript
228 lines
6.5 KiB
GDScript
@tool
|
||
class_name Portal2D extends Sprite2D
|
||
|
||
@export_multiline var debug_note: String = ""
|
||
@export var enabled := true:
|
||
set(val):
|
||
enabled = val
|
||
_check_sign_mark_and_texture()
|
||
@export var immediately := true
|
||
@export_enum("left", "right", "1", "2", "3", "4", "5", "6", "7", "8", "9") var portal_name := "left":
|
||
set(value):
|
||
#if portal_name:
|
||
#remove_from_group("portal_"+portal_name)
|
||
portal_name = value
|
||
#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")
|
||
var target_portal := "none":
|
||
set(value):
|
||
target_portal = value
|
||
_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()
|
||
@export var default_texture: Texture2D
|
||
@export var opened_texture: Texture2D
|
||
@export var default_sign_texture: Texture2D
|
||
@export var opened_sign_texture: Texture2D
|
||
@export var matched_sign_texture: Texture2D
|
||
@export var closed_sign_texture: Texture2D
|
||
var prop_key := ""
|
||
@export var disable_key_after_used := true
|
||
|
||
# 穿过通道的音效
|
||
@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
|
||
@onready var sign_mark = %Sign as Sign
|
||
@onready var area2d = %Area2D as Area2D
|
||
|
||
var activated := false
|
||
|
||
static var item_config_res = preload("res://asset/dialogue/item_description.dialogue")
|
||
var items: PackedStringArray
|
||
|
||
var ground_archive: GroundArchive
|
||
|
||
|
||
# Called when the node enters the scene tree for the first time.
|
||
func _ready() -> void:
|
||
name = "portal_" + portal_name
|
||
if Engine.is_editor_hint():
|
||
_check_sign_mark_and_texture()
|
||
_reload_items()
|
||
return
|
||
ground_archive = ArchiveManager.archive.ground_archive()
|
||
status = ground_archive.get_value(name, "status", status)
|
||
if GlobalConfig.DEBUG:
|
||
print("Portal read status [", name, "] status=", status)
|
||
_check_sign_mark_and_texture()
|
||
area2d.body_entered.connect(_reset)
|
||
area2d.body_exited.connect(_on_cancel)
|
||
sign_mark.interacted.connect(_on_interacted)
|
||
sign_mark.cancel.connect(_on_cancel)
|
||
|
||
|
||
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():
|
||
if not is_node_ready():
|
||
return
|
||
if status == "opened" and opened_texture:
|
||
texture = opened_texture
|
||
elif default_texture:
|
||
texture = default_texture
|
||
match status:
|
||
"locked":
|
||
sign_mark.sprite2d.texture = closed_sign_texture
|
||
"opened":
|
||
sign_mark.sprite2d.texture = opened_sign_texture
|
||
"default":
|
||
sign_mark.sprite2d.texture = default_sign_texture
|
||
if target_portal == "none" or not enabled:
|
||
sign_mark.enabled = false
|
||
else:
|
||
sign_mark.enabled = true
|
||
|
||
|
||
var interact_mutex = Mutex.new()
|
||
|
||
|
||
func _on_interacted() -> void:
|
||
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()
|
||
sign_mark.invalid_shake()
|
||
_check_sign_mark_and_texture()
|
||
interact_mutex.unlock()
|
||
# 开锁尝试后,哪怕开锁成功,也需要下次操作再进入,而不是立即传送
|
||
return
|
||
# 传送,queue free 导致 sfx 无法播放,使用全局声源
|
||
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()
|
||
if GlobalConfig.DEBUG:
|
||
print("传送前往", target_scene, target_portal, " immediately=", immediately)
|
||
var ground_loader = SceneManager.get_ground_loader() as GroundLoader
|
||
if ground_loader:
|
||
if immediately:
|
||
ground_loader.transition_to_scene(target_scene, target_portal, 0.0)
|
||
else:
|
||
ground_loader.transition_to_scene(target_scene, target_portal)
|
||
|
||
|
||
func _on_cancel(_body = null):
|
||
activated = false
|
||
# 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)
|
||
|
||
|
||
func _reset(_body):
|
||
_check_sign_mark_and_texture()
|
||
activated = true
|
||
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):
|
||
if not prop_key or prop_key == key:
|
||
sign_mark.sprite2d.texture = matched_sign_texture
|
||
else:
|
||
sign_mark.sprite2d.texture = closed_sign_texture
|
||
|
||
|
||
# 暂时不启用自动传送
|
||
# var action_times := 0
|
||
# 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()
|
||
|
||
|
||
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
|