@tool extends Sprite2D signal interacted # 0保卫科 1二楼内侧 @export_enum("保卫科", "二楼内侧") var id := 0 @export var enabled := true: set(val): enabled = val if is_node_ready(): sign_mark.enabled = val @export var unrevealed_sign_texture: Texture2D @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 tried_times: int: set(val): tried_times = val ground_archive.set_pair(name, "tried_times", val) 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", "") tried_times = ground_archive.get_value(name, "tried_times", 0) if holding_prop == "prop_弹珠": animated_sprite.play("小手_弹珠_idle") elif holding_prop == "prop_老虎钳": animated_sprite.play("小手_老虎钳_idle") elif is_holding_cup: animated_sprite.play("小手_纸杯_idle") elif tried_times > 0: animated_sprite.play("小手_show") 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 do_first_interact(immediatelly := false): if immediatelly: animated_sprite.play("小手_idle") else: animated_sprite.play("小手_show") _reset_sign_testure_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): if tried_times == 0: # 首次交互前 unrevealed sign_mark.sprite2d.texture = unrevealed_sign_texture return sign_mark.sprite2d.texture = matched_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 interacted.emit() tried_times += 1 if tried_times == 1: do_first_interact(false) return if holding_prop != "": # 手持物品时,交互直接给玩家物品 SceneManager.enable_prop_item(holding_prop) holding_prop = "" animated_sprite.play("小手_show") 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 SceneManager.get_player().animation_finished animated_sprite.visible = false # 7 拿起纸杯 8 监听纸杯 SceneManager.freeze_player(0, 7) 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 id == 1: # 叠成纸杯电话 animated_sprite.play("小手_锡箔_hide") is_holding_cup = true SceneManager.pop_debug_dialog_info("美术", "叠成纸杯: 小手_锡箔_hide + 小手_纸杯_show + 小手_纸杯_idle") await get_tree().create_timer(2).timeout # 稍等片刻再给小鞋子 SceneManager.enable_prop_item("prop_小鞋子1") ArchiveManager.set_global_entry("c02_mouse_follow_player", true) var node = get_node("../自动跟随的老鼠") as Node2D if node: node.visible = true else: printerr("小手已接受锡箔;自动跟随的老鼠节点不存在") else: # 丢下元宝 animated_sprite.play("小手_锡箔_drop") # 先设置允许 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 id == 0 and key == "prop_老虎钳" and pliers_to_ball: interacted_success = true SceneManager.disable_prop_item("prop_老虎钳") animated_sprite.play("小手_老虎钳_hide") SceneManager.pop_debug_dialog_info("美术", "小手_老虎钳_hide + 小手_弹珠_show + 小手_弹珠_idle") await get_tree().create_timer(1.5).timeout holding_prop = "prop_弹珠" elif id == 0 and key == "prop_弹珠" and not pliers_to_ball: interacted_success = true SceneManager.disable_prop_item("prop_弹珠") animated_sprite.play("小手_弹珠_hide") 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(matched_sign_texture, unmatched_sign_texture) SceneManager.release_player() interact_mutex.unlock()