xiandie/scene/entity/ambush.gd

178 lines
4.7 KiB
GDScript

@tool
class_name Ambush2D extends Node2D
signal triggered
@export var enabled := true:
set(val):
enabled = val
if is_node_ready():
sign_mark.enabled = val
_check_sign_display()
@export_enum("enter", "interact") var trigger_mode := "enter":
set(val):
trigger_mode = val
if is_node_ready():
_check_sign_display()
@export var one_shot := true
# 首次进入 tree 就直接启用
@export var on_first_enter_tree := false
@export var freeze_time := 5.0
var hook_animation = ""
@export var lock_player_on_playing_dialogue = true
@export_enum("c01", "c02") var hook_dialogue_res = "c01":
set(val):
hook_dialogue_res = val
match val:
"c01":
dialogue_res = dialogue_c01
"c02":
dialogue_res = dialogue_c02
if is_node_ready() and Engine.is_editor_hint():
notify_property_list_changed()
var hook_dialogue_title = ""
var dialogue_c01 = preload("res://asset/dialogue/c01.dialogue")
var dialogue_c02 = preload("res://asset/dialogue/c02.dialogue")
var dialogue_res = dialogue_c01
var played_time := 0.0
# var played := false:
# set(val):
# if played != val and ground_archive:
# ground_archive.set_pair(name, "played", played)
# played = val
@onready var sign_mark := %Sign as Sign
@onready var area := %Area2D as Area2D
var ground_archive: GroundArchive
var played: bool:
set(val):
played = val
ground_archive.set_pair(name, "played", played)
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
if Engine.is_editor_hint():
var animation_player = _get_animation_player()
# 更新 hook_animation 的可选项
if animation_player:
animation_player.animation_libraries_updated.connect(notify_property_list_changed)
return
_check_sign_display()
if one_shot and played:
if GlobalConfig.DEBUG:
print("Ambush already played, name=", name)
return
if on_first_enter_tree:
_entered(null)
sign_mark.interacted.connect(_interacted)
area.body_entered.connect(_entered)
sign_mark.enabled = enabled
# setup default value
ground_archive = ArchiveManager.archive.ground_archive()
played = ground_archive.get_value(name, "played", false)
func _check_sign_display():
sign_mark.display_sign = trigger_mode == "interact" and (not one_shot or not played)
func _get_animation_player() -> AnimationPlayer:
return get_node_or_null("../../AnimationPlayer") as AnimationPlayer
var enter_mutex = Mutex.new()
func _interacted():
if enabled and trigger_mode == "interact":
_do_trigger()
func _entered(_body = null):
if enabled and trigger_mode == "enter":
_do_trigger()
func _do_trigger():
var time = Time.get_ticks_msec()
# 确保只有一个线程进入该逻辑,因为有时 player 碰撞和首次进入 tree 都会触发该方法
if not enter_mutex.try_lock():
return
if not one_shot and freeze_time > 0:
var time_left = freeze_time - (time - played_time) * 0.001
if time_left > 0:
if GlobalConfig.DEBUG:
print("Ambush freeze time not reached, time left=", time_left)
enter_mutex.unlock()
return
if one_shot and played:
enter_mutex.unlock()
return
played_time = time
played = true
# hook_animation
if hook_animation:
var animation_player = _get_animation_player()
if animation_player:
animation_player.play(hook_animation)
# hook_dialogue
if hook_dialogue_title:
if lock_player_on_playing_dialogue:
SceneManager.freeze_player(0.0)
DialogueManager.show_dialogue_balloon(dialogue_res, hook_dialogue_title)
DialogueManager.dialogue_ended.connect(_on_dialogue_ended, CONNECT_ONE_SHOT)
triggered.emit()
if GlobalConfig.DEBUG:
print("ambush body_entered!")
enter_mutex.unlock()
_check_sign_display()
func _on_dialogue_ended(_res):
if GlobalConfig.DEBUG:
print("Ambush dialogue ended")
if lock_player_on_playing_dialogue:
SceneManager.release_player()
func _get(property: StringName) -> Variant:
if property == "hook_dialogue_title":
return hook_dialogue_title
elif property == "hook_animation":
return hook_animation
return null
func _set(property: StringName, value: Variant) -> bool:
if property == "hook_dialogue_title":
hook_dialogue_title = value
return true
elif property == "hook_animation":
hook_animation = value
return true
return false
func _get_property_list() -> Array[Dictionary]:
var animation_list: PackedStringArray
var animation_player = _get_animation_player()
if animation_player:
animation_list = animation_player.get_animation_list()
return [
{
"name": "hook_dialogue_title",
"type": TYPE_STRING,
"hint": PROPERTY_HINT_ENUM_SUGGESTION,
"hint_string": ",".join(dialogue_res.get_ordered_titles())
},
{
"name": "hook_animation",
"type": TYPE_STRING,
"hint": PROPERTY_HINT_ENUM_SUGGESTION,
"hint_string": ",".join(animation_list)
}
]