240 lines
7.3 KiB
GDScript
240 lines
7.3 KiB
GDScript
@tool
|
||
extends Sprite2D
|
||
|
||
signal start_inspecting
|
||
signal quit_inspecting
|
||
signal sign_mark_offset_updated
|
||
|
||
# @export var entity_config: EntityConfig:
|
||
# set(value):
|
||
# entity_config = value
|
||
|
||
enum { STATUS_NORAML, STATUS_TRANSITIONING, STATUS_INSPECTING_COVER, STATUS_INSPECTING_NOTES }
|
||
|
||
@export var enabled := true:
|
||
set(val):
|
||
enabled = val
|
||
if is_node_ready() and not Engine.is_editor_hint():
|
||
sign_mark.enabled = val
|
||
# sign_mark 节点在 ready 时会直接读取
|
||
@export var sign_mark_offset := Vector2.ZERO:
|
||
set(val):
|
||
sign_mark_offset = val
|
||
sign_mark_offset_updated.emit(val)
|
||
# @export var entity_name: String = ""
|
||
# 第一次交互时的气泡文字(unrevealed -> revealed) 如果为空则跳过
|
||
@export var first_interact_os_key := ""
|
||
@export var content_centered: bool = false
|
||
@export var action_key := 4
|
||
@export var collision_width_and_x := Vector2(20.0, 0):
|
||
set(val):
|
||
collision_width_and_x = val
|
||
if is_node_ready():
|
||
var shape = area2d.get_node("CollisionShape2D").shape
|
||
shape.size.x = collision_width_and_x.x
|
||
area2d.position.x = collision_width_and_x.y
|
||
@export var texture_cover: Texture2D
|
||
@export var note_sign_texture: Texture2D
|
||
@export_enum("none", "c01", "c02", "c03", "c04", "c05", "c06") var editor_filter := "none":
|
||
set(val):
|
||
editor_filter = val
|
||
if is_node_ready() and Engine.is_editor_hint():
|
||
notify_property_list_changed()
|
||
var content_key: String = ""
|
||
|
||
@onready var sign_mark = %Sign as Sign
|
||
@onready var sign_snapper = %SignSnapper as SignSnapper
|
||
@onready var area2d = %Area2D as Area2D
|
||
|
||
@onready var sfx = %Sfx
|
||
@onready var container = %Container
|
||
@onready var cover_rect = %Cover as TextureRect
|
||
@onready var content_label = %ContentLabel as Label
|
||
@onready var tip_label = %TipLabel as Label
|
||
|
||
var tip_cover_hide_notes = "Q: " + tr("ui_退出") + " " + "E: " + tr("ui_阅读")
|
||
var tip_cover_without_notes = "Q: " + tr("ui_退出") + " " + "E: " + tr("ui_检阅")
|
||
var tip_notes = "Q: " + tr("ui_退出") + " " + "E: " + tr("ui_收起")
|
||
|
||
static var content_dialogue = (
|
||
preload("res://asset/dialogue/inspect_content.dialogue") as DialogueResource
|
||
)
|
||
|
||
var status := STATUS_NORAML
|
||
var blinking_tween: Tween
|
||
|
||
var ground_archive: GroundArchive
|
||
# 尝试互动的次数
|
||
var tried_times: int:
|
||
set(val):
|
||
tried_times = val
|
||
ground_archive.set_pair(name, "tried_times", val)
|
||
if tried_times >= 1 and sign_mark:
|
||
sign_mark.sprite2d.texture = note_sign_texture
|
||
|
||
|
||
func _ready() -> void:
|
||
$InspectLayer.layer = GlobalConfig.CANVAS_LAYER_PROP_INSPECTOR
|
||
var shape = area2d.get_node("CollisionShape2D").shape
|
||
shape.size.x = collision_width_and_x.x
|
||
area2d.position.x = collision_width_and_x.y
|
||
container.modulate.a = 0.0
|
||
content_label.modulate.a = 0.0
|
||
content_label.text = _get_tr_content()
|
||
tip_label.text = tip_cover_hide_notes
|
||
cover_rect.texture = texture_cover
|
||
if Engine.is_editor_hint():
|
||
return
|
||
sign_mark.enabled = enabled
|
||
# setup default value
|
||
ground_archive = ArchiveManager.archive.ground_archive()
|
||
tried_times = ground_archive.get_value(name, "tried_times", 0)
|
||
|
||
if content_centered:
|
||
content_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
|
||
# sign_mark.interacted.connect(_on_interacted)
|
||
sign_snapper.arrived.connect(_on_interacted)
|
||
sign_mark.cancel.connect(_on_cancel)
|
||
|
||
|
||
func _get_tr_content():
|
||
if content_key == "":
|
||
return ""
|
||
var inspection_note = ""
|
||
# get note content
|
||
var line_id = content_dialogue.titles.get(content_key)
|
||
while line_id and line_id != "end":
|
||
var line = content_dialogue.lines[line_id]
|
||
if line.has("text"):
|
||
inspection_note += tr(line.get("text")) + "\n"
|
||
line_id = line.get("next_id")
|
||
return inspection_note
|
||
|
||
|
||
func _on_interacted() -> void:
|
||
if STATUS_TRANSITIONING == status:
|
||
return
|
||
if tried_times == 0 and first_interact_os_key:
|
||
SceneManager.freeze_player(0, action_key)
|
||
sign_mark.display_sign = false
|
||
var tween = await SceneManager.pop_os_with_str(first_interact_os_key)
|
||
tween.tween_callback(_do_action)
|
||
tween.tween_callback(func(): sign_mark.display_sign = true)
|
||
else:
|
||
SceneManager.freeze_player(0, action_key)
|
||
_do_action()
|
||
|
||
|
||
func _do_action() -> void:
|
||
if STATUS_TRANSITIONING == status:
|
||
return
|
||
if status == STATUS_NORAML:
|
||
tried_times += 1
|
||
sfx.play()
|
||
SceneManager.focus_node(self)
|
||
SceneManager.get_camera_marker().tween_zoom(2.0)
|
||
status = STATUS_TRANSITIONING
|
||
var tween = create_tween()
|
||
tween.tween_interval(0.8)
|
||
tween.tween_property(container, "modulate:a", 1.0, 0.7)
|
||
tween.tween_callback(func(): status = STATUS_INSPECTING_COVER)
|
||
# 改变信号源
|
||
sign_mark.interacted.connect(_on_interacted)
|
||
sign_snapper.arrived.disconnect(_on_interacted)
|
||
sign_mark.display_sign = false
|
||
|
||
SceneManager.freeze_player(0.0, action_key)
|
||
cover_rect.texture = texture_cover
|
||
if content_key == "":
|
||
tip_label.text = tip_cover_without_notes
|
||
else:
|
||
tip_label.text = tip_cover_hide_notes
|
||
_blink_label(true)
|
||
start_inspecting.emit()
|
||
elif status == STATUS_INSPECTING_COVER:
|
||
sfx.play()
|
||
status = STATUS_INSPECTING_NOTES
|
||
tip_label.text = tip_notes
|
||
create_tween().tween_property(content_label, "modulate:a", 1.0, 0.15)
|
||
elif status == STATUS_INSPECTING_NOTES:
|
||
sfx.play()
|
||
status = STATUS_INSPECTING_COVER
|
||
if content_key == "":
|
||
tip_label.text = tip_cover_without_notes
|
||
else:
|
||
tip_label.text = tip_cover_hide_notes
|
||
create_tween().tween_property(content_label, "modulate:a", 0.0, 0.15)
|
||
|
||
|
||
func _blink_label(init := true):
|
||
if status == STATUS_NORAML:
|
||
return
|
||
blinking_tween = create_tween()
|
||
if init:
|
||
blinking_tween.tween_property(tip_label, "modulate:a", 0.8, 2.0)
|
||
blinking_tween.tween_callback(_blink_label.bind(false))
|
||
else:
|
||
blinking_tween.tween_property(tip_label, "modulate:a", 0.5, 1.0)
|
||
blinking_tween.tween_callback(_blink_label.bind(true))
|
||
|
||
|
||
func _on_cancel(_body = null):
|
||
if STATUS_TRANSITIONING == status:
|
||
return
|
||
if status != STATUS_NORAML:
|
||
quit_inspecting.emit()
|
||
status = STATUS_TRANSITIONING
|
||
var tween = create_tween()
|
||
tween.tween_property(container, "modulate:a", 0.0, 0.15)
|
||
if blinking_tween and blinking_tween.is_running():
|
||
blinking_tween.kill()
|
||
tween.parallel().tween_property(tip_label, "modulate:a", 0.0, 0.15)
|
||
tween.tween_interval(1.0)
|
||
tween.tween_callback(func(): status = STATUS_NORAML)
|
||
tween.tween_callback(func(): content_label.modulate.a = 0.0)
|
||
SceneManager.focus_player_and_reset_zoom()
|
||
SceneManager.release_player()
|
||
sign_mark.display_sign = true
|
||
# 改变信号源
|
||
sign_mark.interacted.disconnect(_on_interacted)
|
||
sign_snapper.arrived.connect(_on_interacted)
|
||
|
||
|
||
func _set(property: StringName, value: Variant) -> bool:
|
||
if property == "content_key":
|
||
content_key = value
|
||
content_label.text = _get_tr_content()
|
||
return true
|
||
return false
|
||
|
||
|
||
func _get(property: StringName) -> Variant:
|
||
if property == "content_key":
|
||
return content_key
|
||
return null
|
||
|
||
|
||
func _get_property_list() -> Array[Dictionary]:
|
||
var titles = ""
|
||
# only show notes_ properties in editor
|
||
if Engine.is_editor_hint():
|
||
var ordered_titles = content_dialogue.get_ordered_titles()
|
||
if editor_filter and editor_filter != "none":
|
||
var filted_titles = ordered_titles.filter(_filter_property)
|
||
if filted_titles.size() > 0:
|
||
titles = ",".join(filted_titles)
|
||
else:
|
||
titles = ",".join(ordered_titles)
|
||
return [
|
||
{
|
||
"name": "content_key",
|
||
"type": TYPE_STRING,
|
||
"hint": PROPERTY_HINT_ENUM_SUGGESTION,
|
||
"hint_string": titles
|
||
}
|
||
]
|
||
|
||
|
||
func _filter_property(property: StringName) -> bool:
|
||
return property.find(editor_filter) >= 0
|