@tool extends Sprite2D @export var accept_tin_coin := false @export var accept_ball_or_plier := false @export var enabled := true: set(val): enabled = val if is_node_ready(): sign_mark.enabled = val @export var unmatched_sign_texture: Texture2D @export var matched_sign_texture: Texture2D @onready var sfx_invalid = $SfxInvalid as Sfx @onready var sfx_success = $SfxSuccess as Sfx @onready var sfx_bgm = $SfxBgm as AudioStreamPlayer @onready var sign_mark = %Sign as Sign @onready var area2d = %Area2D as Area2D @onready var animated_sprite = $"小手" as AnimatedSprite2D var ground_archive: GroundArchive static var item_config_res = preload("res://asset/dialogue/item_description.dialogue") # 当前小手手持的 prop var holding_prop = "": set(val): holding_prop = val ground_archive.set_pair(name, "holding_prop", val) # 是否手持纸杯电话 var is_holding_cup = false: set(val): is_holding_cup = val ground_archive.set_pair(name, "is_holding_cup", val) # 锡纸是否在地上 var tin_coin_drop = false: set(val): tin_coin_drop = val ground_archive.set_pair(name, "tin_coin_drop", tin_coin_drop) if is_node_ready(): coin.enabled = val if tin_coin_drop: coin.reset() var coin: Pickable2D func _ready() -> void: if Engine.is_editor_hint(): return area2d.body_entered.connect(_reset) area2d.body_exited.connect(_on_exit) sign_mark.interacted.connect(_on_interacted) sign_mark.cancel.connect(_on_cancel) sign_mark.base_scale = sign_mark.scale sign_mark.enabled = enabled # setup default value ground_archive = ArchiveManager.archive.ground_archive() as GroundArchive is_holding_cup = ground_archive.get_value(name, "is_holding_cup", false) holding_prop = ground_archive.get_value(name, "holding_prop", "") if holding_prop == "prop_弹珠": animated_sprite.play("小手_弹珠_idle") elif holding_prop == "prop_老虎钳": animated_sprite.play("小手_老虎钳_idle") elif is_holding_cup: animated_sprite.play("小手_纸杯_idle") coin = get_node("Pickable元宝") tin_coin_drop = ground_archive.get_value(name, "tin_coin_drop", false) coin.triggered.connect(func(): tin_coin_drop = false) func _reset(_body = null) -> void: _reset_sign_testure_to_prop() 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) func _reset_sign_testure_to_prop(): var key = SceneManager.get_current_prop(false) _set_sign_texture_to_prop(key) # 根据当前 prop,调整 sign 所显示的 texture func _set_sign_texture_to_prop(key): var interactable = false if holding_prop != "" or is_holding_cup: # 手持物品/纸杯电话时,允许交互,获得物品/对话 interactable = true if key == "prop_锡箔元宝": interactable = true elif accept_ball_or_plier and key == "prop_老虎钳": interactable = ArchiveManager.get_global_value("c02_pliers_to_ball", false) elif accept_ball_or_plier and key == "prop_弹珠": interactable = not ArchiveManager.get_global_value("c02_pliers_to_ball", false) if interactable: sign_mark.sprite2d.texture = matched_sign_texture else: sign_mark.sprite2d.texture = unmatched_sign_texture func _on_exit(_body = null) -> void: # 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 _on_cancel(_body = null) -> void: if communicating: _quit_communicating() return func _quit_communicating() -> void: sfx_bgm.stop() if sfx_bgm.finished.is_connected(_quit_communicating): sfx_bgm.finished.disconnect(_quit_communicating) communicating = false SceneManager.release_player() # 重置动画 SceneManager.get_player().set_facing_direction(Vector2.ONE) animated_sprite.visible = true var interact_mutex = Mutex.new() var communicating = false func _on_interacted() -> void: if not interact_mutex.try_lock(): return if holding_prop != "": # 手持物品时,交互直接给玩家物品 SceneManager.enable_prop_item(holding_prop) holding_prop = "" animated_sprite.play("小手_idle") interact_mutex.unlock() return if is_holding_cup: # 对话 if not communicating: communicating = true # # 走到指定地点 # SceneManager.get_player().walk_to(Vector2(225, 98.0), 1.5) # await get_tree().create_timer(1.6).timeout animated_sprite.visible = false # 7 拿起纸杯 8 监听纸杯 SceneManager.freeze_player(0, 7) await SceneManager.get_player().animation_finished SceneManager.get_player().force_play_animation("c00_吕萍_听纸杯") SceneManager.pop_debug_dialog_info("音效", "纸杯电话童谣") sfx_bgm.play() # 交互时,已经在对话中 sfx_bgm.finished.connect(_quit_communicating, CONNECT_ONE_SHOT) else: _quit_communicating() interact_mutex.unlock() return var key = SceneManager.get_current_prop(false) var interacted_success = false SceneManager.freeze_player(0) # accept_tin_coin if key == "prop_锡箔元宝": interacted_success = true SceneManager.disable_prop_item("prop_锡箔元宝") if accept_tin_coin: # 叠成纸杯电话 animated_sprite.play("小手_锡箔_hide") is_holding_cup = true # TODO SceneManager.pop_debug_dialog_info("美术", "叠成纸杯: 小手_锡箔_hide + 小手_纸杯_show + 小手_纸杯_idle") await get_tree().create_timer(1.5).timeout SceneManager.enable_prop_item("prop_小鞋子1") ArchiveManager.set_global_entry("c02_mouse_follow_player", true) # 稍等后显示小老鼠 await get_tree().create_timer(0.5).timeout SceneManager.pop_debug_dialog_info("美术", "触发⼩⽼⿏跟在玩家身后") var node = get_node("../自动跟随的老鼠") as Node2D if node: node.visible = true else: printerr("小手已接受锡箔;自动跟随的老鼠节点不存在") else: # 丢下元宝 animated_sprite.play("小手_锡箔_drop") # TODO SceneManager.pop_debug_dialog_info("美术", "丢下元宝: 小手_锡箔_drop + 小手_idle + 落地后的锡箔贴图") # 先设置允许 pickable,然后再设置可见性,等待动画播完再显示 tin_coin_drop = true coin.visible = false await get_tree().create_timer(1.5).timeout coin.visible = true # 是否允许老虎钳换弹珠 var pliers_to_ball = ArchiveManager.get_global_value("c02_pliers_to_ball", false) if accept_ball_or_plier and key == "prop_老虎钳" and pliers_to_ball: interacted_success = true SceneManager.disable_prop_item("prop_老虎钳") animated_sprite.play("小手_老虎钳_hide") # TODO SceneManager.pop_debug_dialog_info("美术", "小手_老虎钳_hide + 小手_弹珠_show + 小手_弹珠_idle") await get_tree().create_timer(1.5).timeout holding_prop = "prop_弹珠" elif accept_ball_or_plier and key == "prop_弹珠" and not pliers_to_ball: interacted_success = true SceneManager.disable_prop_item("prop_弹珠") animated_sprite.play("小手_弹珠_hide") # TODO SceneManager.pop_debug_dialog_info("美术", "小手_弹珠_hide + 小手_老虎钳_show + 小手_老虎钳_idle") await get_tree().create_timer(1.5).timeout holding_prop = "prop_老虎钳" if interacted_success: # sfx_success.play() EventManager.prop_interacted(name, key, 1) _reset_sign_testure_to_prop() else: sfx_invalid.play() sign_mark.invalid_shake() SceneManager.release_player() interact_mutex.unlock()