From efbb86d15d4675395f30cd7a5747a0ad6a706a12 Mon Sep 17 00:00:00 2001 From: cakipaul Date: Sat, 28 Jun 2025 21:42:20 +0800 Subject: [PATCH] =?UTF-8?q?ambush=20cooldown=5Ftime;=20sign=20debug=20?= =?UTF-8?q?=E5=BD=A9=E8=89=B2=E8=BE=93=E5=87=BA=E7=8A=B6=E6=80=81=EF=BC=9B?= =?UTF-8?q?config=20=E5=8F=AF=E5=BC=80=E5=90=AF=20debug=20/=20skip=20trail?= =?UTF-8?q?er?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- manager/archive_manager/archive_manager.gd | 2 +- manager/config_manager/global_config.gd | 6 +- .../config_manager/global_config_manager.gd | 3 + manager/scene/scene_manager.gd | 5 +- scene/character/main_player.tscn | 1 + scene/character/reenter_lock.gd | 25 ++- scene/entity/ambush.gd | 41 ++-- scene/entity/closeup.gd | 6 +- scene/entity/inspectable.gd | 3 +- scene/entity/interactable.gd | 8 +- scene/entity/npc.gd | 10 +- scene/entity/pickable.gd | 14 +- scene/entity/ux/sign.gd | 201 ++++++++++-------- .../ground/scene/c01/s06_孤儿院长廊围墙.tscn | 17 +- scene/ground/scene/c01/s07_书店外.tscn | 5 +- scene/ground/scene/c01/s08_书店.tscn | 4 +- scene/ground/scene/c01/s09_公寓楼外.tscn | 2 +- scene/ground/scene/c01/s11_黄包车演出.tscn | 2 +- scene/ground/scene/c01/s12_书店外_诡异版.tscn | 4 +- scene/ground/scene/c02/s02_过道.tscn | 6 +- scene/ground/scene/c02/s03_院子.gd | 2 +- scene/ground/scene/c02/s03_院子.tscn | 2 +- scene/ground/scene/c02/s06_二楼.tscn | 2 +- scene/ground/scene/c02/s10_空房间.tscn | 2 +- scene/ground/scene/c02/s13_盒子猫二楼.tscn | 6 +- .../ground/scene/c02/s16_盒子猫三楼内侧.tscn | 2 +- scene/ground/scene/c02/s17_盒子猫三楼.tscn | 2 +- scene/ground/scene/c02/s18_盒子猫一楼.tscn | 8 +- scene/ground/script/c02/s00_煤油灯.gd | 4 +- scene/trailer.gd | 3 + 30 files changed, 212 insertions(+), 186 deletions(-) diff --git a/manager/archive_manager/archive_manager.gd b/manager/archive_manager/archive_manager.gd index 139def59..8fdc4582 100644 --- a/manager/archive_manager/archive_manager.gd +++ b/manager/archive_manager/archive_manager.gd @@ -14,7 +14,7 @@ static var user_root_dir := "user://data/" # must end with "/" static var archive_dir := "user://data/archives/" static var archive_prefix := "save" -const CURRENT_VERSION = 4 +const CURRENT_VERSION = 5 var archives := {} var autosave_timer := Timer.new() diff --git a/manager/config_manager/global_config.gd b/manager/config_manager/global_config.gd index ab814657..55ecb038 100644 --- a/manager/config_manager/global_config.gd +++ b/manager/config_manager/global_config.gd @@ -51,6 +51,8 @@ signal current_selected_archive_id_changed signal auto_save_enabled_changed signal auto_save_seconds_changed +@export var debug_mode := false # 开启 debug 模式 +@export var skip_trailer := false # 跳过 trailer @export var version: int #存档版本 @export var game_total_seconds := 0 # 游戏总时长 @export var game_rounds := 1 # 当前周目数 @@ -62,8 +64,8 @@ signal auto_save_seconds_changed set(val): auto_save_enabled = val auto_save_enabled_changed.emit() -# 默认 30s 保存一次 -@export var auto_save_seconds := 30: +# 默认 60s 保存一次 +@export var auto_save_seconds := 60: set(val): auto_save_seconds = val auto_save_seconds_changed.emit() diff --git a/manager/config_manager/global_config_manager.gd b/manager/config_manager/global_config_manager.gd index 31a3ce4d..1cb8b351 100644 --- a/manager/config_manager/global_config_manager.gd +++ b/manager/config_manager/global_config_manager.gd @@ -19,6 +19,9 @@ func _set_config(val: GlobalConfig) -> void: config = val if Engine.is_editor_hint(): return + if config.debug_mode: + GlobalConfig.DEBUG = true + print_rich("[color=orange]Debug mode enabled[/color]") # set up window if config.window_fullscreen: get_window().mode = Window.MODE_FULLSCREEN diff --git a/manager/scene/scene_manager.gd b/manager/scene/scene_manager.gd index c705bbe9..8e51161e 100644 --- a/manager/scene/scene_manager.gd +++ b/manager/scene/scene_manager.gd @@ -74,7 +74,10 @@ func focus_player_and_reset_zoom(duration := 1.2) -> void: func get_lock() -> PlayerReenterLock: var ground = get_ground() if ground: - return ground.reenter_lock + if ground.reenter_lock: + # 允许访问 lock + return ground.reenter_lock + return ground.get_node_or_null("PlayerReenterLock") as PlayerReenterLock printerr("get_lock: Ground node not found. return new detached lock") # 允许访问 lock return PlayerReenterLock.new() diff --git a/scene/character/main_player.tscn b/scene/character/main_player.tscn index aec9d652..bda69cc4 100644 --- a/scene/character/main_player.tscn +++ b/scene/character/main_player.tscn @@ -99,6 +99,7 @@ mouse_filter = 2 [node name="PanelContainer" type="PanelContainer" parent="OSPivot/MarginContainer"] unique_name_in_owner = true +modulate = Color(1, 1, 1, 0) light_mask = 16 layout_mode = 2 size_flags_vertical = 8 diff --git a/scene/character/reenter_lock.gd b/scene/character/reenter_lock.gd index bb6509f7..9802eb52 100644 --- a/scene/character/reenter_lock.gd +++ b/scene/character/reenter_lock.gd @@ -22,18 +22,21 @@ signal hold_changed(count: int, is_add: bool) var _freeze_requests: int = 0 var _hold_requests: int = 0 - +func _ready() -> void: + process_mode = Node.PROCESS_MODE_PAUSABLE + + func _exit_tree() -> void: if _freeze_requests > 0: if GlobalConfig.DEBUG: push_warning( - "[ReenterLock] Remains %d freeze requests on exit_tree. parent=" % _freeze_requests, + "[Lock] Remains %d freeze requests on exit_tree. parent=" % _freeze_requests, get_parent() ) if _hold_requests > 0: if GlobalConfig.DEBUG: print( - "[ReenterLock] Remains %d hold requests on exit_tree. parent=" % _hold_requests, + "[Lock] Remains %d hold requests on exit_tree. parent=" % _hold_requests, get_parent() ) @@ -49,7 +52,7 @@ func freeze(duration := 0.0) -> void: _create_timer(duration, release) _freeze_requests += 1 if GlobalConfig.DEBUG: - print("[ReenterLock] Freeze applied: ", _freeze_requests) + print("[Lock] Freeze applied: ", _freeze_requests) freeze_changed.emit(_freeze_requests, true) @@ -57,14 +60,14 @@ func release() -> void: if _freeze_requests <= 0: push_warning( ( - "[ReenterLock] Attempting to release more times than frozen! Current local count: %d" + "[Lock] Attempting to release more times than frozen! Current local count: %d" % _freeze_requests ) ) return _freeze_requests -= 1 if GlobalConfig.DEBUG: - print("[ReenterLock] Release applied: ", _freeze_requests) + print("[Lock] Release applied: ", _freeze_requests) freeze_changed.emit(_freeze_requests, false) @@ -74,7 +77,7 @@ func hold(duration := 0.0) -> void: _create_timer(duration, unhold) _hold_requests += 1 if GlobalConfig.DEBUG: - print("[ReenterLock] Hold applied: ", _hold_requests) + print("[Lock] Hold applied: ", _hold_requests) hold_changed.emit(_hold_requests, true) @@ -82,14 +85,14 @@ func unhold() -> void: if _hold_requests <= 0: push_warning( ( - "[ReenterLock] Attempting to unhold more times than held! Current local count: %d" + "[Lock] Attempting to unhold more times than held! Current local count: %d" % _hold_requests ) ) return _hold_requests -= 1 if GlobalConfig.DEBUG: - print("[ReenterLock] Unhold applied: ", _hold_requests) + print("[Lock] Unhold applied: ", _hold_requests) hold_changed.emit(_hold_requests, false) @@ -117,7 +120,7 @@ func lock_all(duration := 0.0) -> void: _hold_requests += 1 _freeze_requests += 1 if GlobalConfig.DEBUG: - prints("[ReenterLock] LockAll applied (hold, freeze): ", _hold_requests, _freeze_requests) + prints("[Lock] LockAll applied (hold, freeze): ", _hold_requests, _freeze_requests) hold_changed.emit(_hold_requests, true) freeze_changed.emit(_freeze_requests, true) @@ -128,4 +131,4 @@ func unlock_all() -> void: func _to_string() -> String: - return "[ReenterLock] Freeze: %d, Hold: %d" % [_freeze_requests, _hold_requests] + return "[Lock] Freeze: %d, Hold: %d" % [_freeze_requests, _hold_requests] diff --git a/scene/entity/ambush.gd b/scene/entity/ambush.gd index a830f056..da163811 100644 --- a/scene/entity/ambush.gd +++ b/scene/entity/ambush.gd @@ -14,12 +14,12 @@ signal sign_mark_offset_updated set(val): enabled = val if is_node_ready(): - _check_sign_display() + _check_sign_status() @export_enum("enter", "area_enter", "interact") var trigger_mode := "enter": set(val): trigger_mode = val if is_node_ready(): - _check_sign_display() + _check_sign_status() @export var collision_width_and_x := Vector2(20.0, 0): set(val): collision_width_and_x = val @@ -31,9 +31,8 @@ signal sign_mark_offset_updated @export var one_shot := true # 首次进入 tree 就直接启用 @export var on_first_enter_tree := false -@export var freeze_time := 0.5 +@export var cooldown_time := 0.5 var hook_animation = "" -@export var lock_player_on_playing_dialogue = true @export var hook_os_key := "" @export_enum("c01", "c02", "c03", "c04", "c05", "c06") var hook_dialogue_res = "c01": set(val): @@ -103,7 +102,7 @@ func _ready() -> void: ground_archive = ArchiveManager.archive.ground_archive() played = ground_archive.get_value(name, "played", false) played_time = 0.0 - _check_sign_display() + _check_sign_status() if played: if GlobalConfig.DEBUG: print("Ambush has played, name=", name, " one_shot=", one_shot) @@ -118,7 +117,7 @@ func _ready() -> void: _do_trigger.call_deferred() -func _check_sign_display(): +func _check_sign_status(): sign_mark.enabled = enabled and (not played or not one_shot) sign_mark.display_sign = trigger_mode == "interact" @@ -150,18 +149,18 @@ func _area_entered(_area = null): _do_trigger() -func _do_trigger() -> bool: +func _do_trigger(): var time = Time.get_ticks_msec() # 确保只有一个线程进入该逻辑,因为有时 player 碰撞和首次进入 tree 都会触发该方法 if not trigger_mutex.try_lock(): print("Ambush trigger mutex lock fail, name=", name) return false print("Ambush trigger mutex locked, name=", name) - if not one_shot and freeze_time > 0: - var time_left = freeze_time - (time - played_time) * 0.001 + if not one_shot and cooldown_time > 0: + var time_left = cooldown_time - (time - played_time) * 0.001 if time_left > 0: if GlobalConfig.DEBUG: - print("Ambush freeze time not reached, time left=", time_left) + print("Ambush cooldown_time has not reached, time left=", time_left) trigger_mutex.unlock() return false if one_shot and played: @@ -175,12 +174,6 @@ func _do_trigger() -> bool: 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) # hook_os if hook_os_key: SceneManager.pop_os_with_str(hook_os_key) @@ -193,15 +186,13 @@ func _do_trigger() -> bool: triggered.emit() if GlobalConfig.DEBUG: print("ambush triggered! name=", name) - _check_sign_display() - return true - - -func _on_dialogue_ended(_res): - if GlobalConfig.DEBUG: - print("Ambush dialogue ended") - if lock_player_on_playing_dialogue: - SceneManager.release_player() + _check_sign_status() + # hook_dialogue, await to end + if hook_dialogue_title: + SceneManager.lock_player(0.0) + DialogueManager.show_dialogue_balloon(dialogue_res, hook_dialogue_title) + await DialogueManager.dialogue_ended + SceneManager.unlock_player() func _get(property: StringName) -> Variant: diff --git a/scene/entity/closeup.gd b/scene/entity/closeup.gd index f57121c9..35e64238 100644 --- a/scene/entity/closeup.gd +++ b/scene/entity/closeup.gd @@ -24,7 +24,8 @@ func display() -> void: # 先退出 _exit() if packed_scene: - SceneManager.freeze_player(0, action_key) + printraw("[" + name + "] call ") + SceneManager.lock_player(0, action_key) # 展示时,禁用 sign_mark 的输入 sign_mark.pass_unhandled_input = true current_child = packed_scene.instantiate() @@ -37,7 +38,8 @@ func display() -> void: func _exit(arg = null): if current_child: - SceneManager.release_player() + printraw("[" + name + "] call ") + SceneManager.unlock_player() current_child.queue_free() exit.emit(arg) # 退出时,恢复 sign_mark 的输入 diff --git a/scene/entity/inspectable.gd b/scene/entity/inspectable.gd index 56510d3e..cda5023b 100644 --- a/scene/entity/inspectable.gd +++ b/scene/entity/inspectable.gd @@ -14,7 +14,7 @@ enum { STATUS_NORAML, STATUS_TRANSITIONING, STATUS_INSPECTING_COVER, STATUS_INSP @export var enabled := true: set(val): enabled = val - if is_node_ready() and not Engine.is_editor_hint(): + if is_node_ready(): sign_mark.enabled = val # sign_mark 节点在 ready 时会直接读取 @export var sign_mark_offset := Vector2.ZERO: @@ -125,6 +125,7 @@ func _on_interacted() -> void: func _do_action() -> void: if status == STATUS_NORAML: + # 不使用 lock, 因为需要用 sign 进行继续交互 SceneManager.freeze_player(0, action_key) status = STATUS_TRANSITIONING tried_times += 1 diff --git a/scene/entity/interactable.gd b/scene/entity/interactable.gd index 96bf414b..08a134c1 100644 --- a/scene/entity/interactable.gd +++ b/scene/entity/interactable.gd @@ -18,7 +18,7 @@ signal sign_mark_offset_updated set(val): enabled = val if is_node_ready(): - _check_sign_display() + _check_sign_status() @export var enable_snapper := true @export var action_key := 4 @export var collision_width_and_x := Vector2(20.0, 0): @@ -87,10 +87,10 @@ func _ready() -> void: interacted_times = ground_archive.get_value(name, "interacted_times", 0) if interacted_times and interacted_texture: texture = interacted_texture - _check_sign_display() + _check_sign_status() -func _check_sign_display(): +func _check_sign_status(): sign_mark.enabled = enabled and (not one_shot or interacted_times < one_shot_max_times) @@ -180,7 +180,7 @@ func _on_interacted() -> void: EventManager.prop_interacted(name, key, interacted_times) # print("%s interacted with %s. total times: %s" % [name, key, interacted_times]) interact_mutex.unlock() - _check_sign_display() + _check_sign_status() _reset_sign_testure_to_prop() diff --git a/scene/entity/npc.gd b/scene/entity/npc.gd index 57d80787..bac700c8 100644 --- a/scene/entity/npc.gd +++ b/scene/entity/npc.gd @@ -11,7 +11,7 @@ signal interacted set(val): enabled = val if is_node_ready(): - _check_sign_mark_enable() + _align_enabled_status() @export var height := 60.0: set(val): height = val @@ -62,19 +62,19 @@ func _ready() -> void: sign_mark.interacted.connect(_on_interacted) # sign_mark.cancel.connect(_stop_speaking) sign_mark.toggle_active.connect(_on_toggle_active) - _check_sign_mark_enable() + _align_enabled_status() visibility_changed.connect(_on_visibility_changed) if sprite_frames and animation: play() func _on_visibility_changed() -> void: - _check_sign_mark_enable() + _align_enabled_status() -func _check_sign_mark_enable(): +func _align_enabled_status(): speaking_sign.visible = enabled - sign_mark.enabled = enabled and visible + sign_mark.enabled = enabled func _on_entered(_body = null) -> void: diff --git a/scene/entity/pickable.gd b/scene/entity/pickable.gd index b2c08737..8ba6b829 100644 --- a/scene/entity/pickable.gd +++ b/scene/entity/pickable.gd @@ -14,7 +14,7 @@ signal sign_mark_offset_updated set(val): enabled = val if is_node_ready(): - _check_sign_display() + sign_mark.enabled = enabled @export var action_key := 4 # 除了 picked 必然隐藏,其他情况下跟随 enabled 状态 @export var visible_follow_enabled := true @@ -43,7 +43,7 @@ var picked: bool: func reset() -> void: if picked: picked = false - _check_sign_display() + _check_display() # 渐渐浮现 @@ -69,20 +69,20 @@ func _ready() -> void: # setup default value ground_archive = ArchiveManager.archive.ground_archive() picked = ground_archive.get_value(name, "picked", false) - sign_mark.enabled = enabled - _check_sign_display() if picked: if GlobalConfig.DEBUG: print("Prop has picked, name=", name, " key=", prop_key) sign_snapper.arrived.connect(_interacted) + sign_mark.enabled = enabled + _check_display() -func _check_sign_display(): +func _check_display(): if picked: visible = false elif visible_follow_enabled: visible = enabled - sign_mark.enabled = visible and enabled + sign_mark.enabled = enabled func _get_animation_player() -> AnimationPlayer: @@ -111,7 +111,7 @@ func _interacted(): triggered.emit() if GlobalConfig.DEBUG: print("pickable triggered! name=", name) - _check_sign_display() + _check_display() static var item_config_res = preload("res://asset/dialogue/item_description.dialogue") diff --git a/scene/entity/ux/sign.gd b/scene/entity/ux/sign.gd index 8e3cf9d9..ca8b614d 100644 --- a/scene/entity/ux/sign.gd +++ b/scene/entity/ux/sign.gd @@ -15,15 +15,7 @@ signal toggle_active(activated: bool) set(val): if enabled == val: return - enabled = val - if enabled and player_touching and not activated: - activate(null) - if not enabled and activated: - disactivate(null) - # 保持 player_touching 为 true,避免在 enable 时无法激活 - player_touching = true - if is_node_ready(): - _check_sign_display() + _align_activation() @export var display_sign := true: set(val): if display_sign != val: @@ -47,14 +39,17 @@ static var _pending_activate_sign: Array[NodePath] = [] static var mutex = Mutex.new() var tween: Tween -var player_touching := false +var player_touching := false: + set(val): + if player_touching != val: + player_touching = val + _align_activation() var activated = false: set(val): if activated != val: activated = val + _check_sign_display() toggle_active.emit(activated) - # queue_redraw() -# var sprite2d = Sprite2D.new() var base_scale = Vector2.ONE @@ -69,55 +64,114 @@ func _ready() -> void: _check_sign_display() if Engine.is_editor_hint(): return - # layer = GlobalConfig.CANVAS_LAYER_FG # var point_light = get_node_or_null("../PointLight2D") # if point_light: # point_light.energy = 0.0 var area2d = get_node_or_null("../Area2D") if area2d: - area2d.body_entered.connect(activate) - area2d.body_exited.connect(disactivate) + area2d.body_entered.connect(_on_body_entered) + area2d.body_exited.connect(_on_body_exited) visibility_changed.connect(_on_visibility_changed) + # 关注 lock 的状态变化 + SceneManager.get_lock().hold_changed.connect(_on_lock_hold_changed) + + +func is_hold() -> bool: + return SceneManager.get_lock().is_held() + + +func _on_lock_hold_changed(count: int, is_add: bool): + if count == 0 or (count == 1 and is_add): + _align_activation() func _on_visibility_changed() -> void: - if is_visible_in_tree(): - if player_touching and not activated and enabled: - activate(null) - else: - if activated: - disactivate(null) - player_touching = true + _align_activation() +# activition/display mode 变化时 _check_sign_display func _check_sign_display(): if Engine.is_editor_hint(): - # 在编辑器中始终显示 - if display_sign: + # 在编辑器中与 display_sign & enabled 状态保持一致 + if display_sign and enabled: sprite2d.modulate.a = 1.0 else: sprite2d.modulate.a = 0.0 return - if not enabled or not display_sign or not activated: + if not display_sign or not activated: sprite2d.modulate.a = 0.0 - elif sprite2d.modulate.a == 0.0 and activated: + elif sprite2d.modulate.a == 0.0: sprite2d.modulate.a = 1.0 -func activate(_body: Node2D) -> bool: +func _on_body_entered(_body: Node2D) -> void: + player_touching = true + + +func _on_body_exited(_body: Node2D) -> void: + player_touching = false + + +# 四种参数变化时调用 align: 1 enable 2 hold 3 visibility 4 touching +func _align_activation() -> bool: + if Engine.is_editor_hint(): + return activated + var ideal_status := enabled and player_touching and not is_hold() and is_visible_in_tree() + if activated != ideal_status: + if ideal_status: + _try_activate() + else: + _try_disactivate() + if GlobalConfig.DEBUG: + var activated_color = "cyan" if activated else "brown" + print_rich( + "[b]", + get_parent().name, + "[/b] activated=[color=", + activated_color, + "]", + activated, + "[/color]", + " occupied:[color=khaki]", + _get_name_from_path(occupied), + "[/color] pending:[color=coral]", + _get_name_from_paths(_pending_activate_sign), + "[/color]" + ) + return activated + + +func _try_disactivate() -> void: + mutex.lock() + if activated: + activated = false + occupied = NodePath(&"") + # 转移 active 状态给下一个节点 + while _pending_activate_sign.size() > 0: + var path = _pending_activate_sign.pop_front() + var _sign = get_node_or_null(path) as Sign + if _sign and _sign._align_activation(): + break + else: + # make sure the sign is not in the pending list + _pending_activate_sign.erase(get_path()) + mutex.unlock() + # point_light.energy = 0.0 + if tween and tween.is_valid(): + tween.kill() + if sprite2d.modulate.a > 0.0: + tween = create_tween() + tween.tween_property(sprite2d, "modulate:a", 0.0, 0.2) + + +func _try_activate() -> bool: # point_light.energy = 1.0 - # print("activate:", get_path()) var path := get_path() mutex.lock() - player_touching = true - if not enabled or not is_visible_in_tree(): - mutex.unlock() - return false + # 若 lock 为 hold 状态则直接跳过 if occupied and occupied != path: if not _pending_activate_sign.has(path): _pending_activate_sign.append(path) - mutex.unlock() - return false else: occupied = path activated = true @@ -130,58 +184,29 @@ func activate(_body: Node2D) -> bool: var p_tween = tween.parallel() p_tween.tween_property(sprite2d, "scale", base_scale * Vector2(1.2, 1.2), 0.3) p_tween.tween_property(sprite2d, "scale", base_scale, 0.1) - return true - # if activated: - # focus_mode = FOCUS_ALL - # grab_focus() + return activated -# 绘制 prop 图标 -# func _draw() -> void: -# if draw_shadow and sprite2d.texture: -# var texture_x = sprite2d.texture.get_size().x -# # var radius = max(36.0, min(texture_x * 0.5, 48.0)) -# var radius = 46.0 -# var rect = Rect2(-radius, -radius, radius * 2, radius * 2) -# draw_texture_rect(shadow_texture, rect, false) -# # 比 2.0 略小,选择使用 1.6 -# var texture_scale = min(radius * 1.6 / texture_x, 1.1) -# sprite2d.scale = Vector2(texture_scale, texture_scale) -# # var texture_radius = shadow_texture.x * 0.5 -# # draw_circle(Vector2.ZERO, radius, Color(0.8, 0.8, 0.8, 0.8), false, 6.0, true) -# # radius -= 6.0 -# # if radius > 0: -# # draw_circle(Vector2.ZERO, radius, Color(0.3, 0.3, 0.3, 0.3)) -# else: -# sprite2d.scale = Vector2.ONE - - -func disactivate(_body: Node2D) -> void: - # release_focus() - mutex.lock() - player_touching = false - if activated: - activated = false - occupied = NodePath("") - # 转移 active 状态给下一个节点 - while _pending_activate_sign.size() > 0: - var path = _pending_activate_sign.pop_front() - var _sign = get_node_or_null(path) as Sign - if _sign and _sign.player_touching and _sign.activate(null): - break +func _get_name_from_path(path: NodePath) -> String: + if not path: + return "" + # return -2 idx + var parts = path.get_concatenated_names().split("/") + if parts.size() >= 2: + return parts[parts.size() - 2] + elif parts.size() >= 1: + return parts[parts.size() - 1] else: - # make sure the sign is not in the pending list - _pending_activate_sign.erase(get_path()) - # double check. because the sign may be activated by other body - if activated: - disactivate(_body) - mutex.unlock() - # point_light.energy = 0.0 - if tween and tween.is_valid(): - tween.kill() - if sprite2d.modulate.a > 0.0: - tween = create_tween() - tween.tween_property(sprite2d, "modulate:a", 0.0, 0.2) + return "" + + +func _get_name_from_paths(paths: Array[NodePath]) -> String: + if len(paths) == 0: + return "" + var names = [] + for path in paths: + names.append(_get_name_from_path(path)) + return ", ".join(names) func _unhandled_input(event: InputEvent) -> void: @@ -193,6 +218,7 @@ func _unhandled_input(event: InputEvent) -> void: return if activated: if event.is_action_pressed("interact"): + get_viewport().set_input_as_handled() if GlobalConfig.DEBUG: print("Sign interacted:", get_parent().name) interacted.emit() @@ -201,21 +227,14 @@ func _unhandled_input(event: InputEvent) -> void: # 传送时会导致 is_inside_tree 为 false,此时也无需与 prop hud 抢占 focus focus_mode = FOCUS_ALL grab_focus() - _set_handled() elif event.is_action_pressed("cancel"): + get_viewport().set_input_as_handled() if GlobalConfig.DEBUG: print("Sign cancel:", get_parent().name) cancel.emit() - _set_handled() release_focus() -func _set_handled(): - var viewport = get_viewport() - if viewport: - viewport.set_input_as_handled() - - var shake_tween diff --git a/scene/ground/scene/c01/s06_孤儿院长廊围墙.tscn b/scene/ground/scene/c01/s06_孤儿院长廊围墙.tscn index 6a3abd69..48010acb 100644 --- a/scene/ground/scene/c01/s06_孤儿院长廊围墙.tscn +++ b/scene/ground/scene/c01/s06_孤儿院长廊围墙.tscn @@ -222,14 +222,13 @@ note_key = "c01_s06_小朋友房间" [node name="门口对话ambush" parent="Ground/DeployLayer" index="4" instance=ExtResource("11_tudob")] position = Vector2(295, 43) -freeze_time = 1.0 -lock_player_on_playing_dialogue = false +cooldown_time = 1.0 hook_dialogue_title = "c01_s06_走廊前对话" [node name="门口ambush" parent="Ground/DeployLayer" index="5" instance=ExtResource("11_tudob")] position = Vector2(308, 43) one_shot = false -freeze_time = 3.0 +cooldown_time = 3.0 hook_animation = "门口_观望" [node name="踢球男孩" parent="Ground/DeployLayer" index="6" instance=ExtResource("5_erliv")] @@ -284,7 +283,7 @@ metadata/_custom_type_script = "uid://wapo47a1oddf" [node name="四小孩画鬼差的对话ambush" parent="Ground/DeployLayer" index="9" instance=ExtResource("11_tudob")] position = Vector2(1413, 66) -freeze_time = 1.0 +cooldown_time = 1.0 hook_method = "pre_game_intro" [node name="FocusPoint" type="Node2D" parent="Ground/DeployLayer/四小孩画鬼差的对话ambush"] @@ -444,7 +443,7 @@ shape = SubResource("RectangleShape2D_7cdhx") [node name="对话1ambush" parent="Ground/DeployLayer/【站立小孩-1】" instance=ExtResource("11_tudob")] position = Vector2(0, 51) trigger_mode = "interact" -freeze_time = 1.0 +cooldown_time = 1.0 hook_dialogue_title = "c01_s06_四个小孩_对话1" hook_method = "talk1" @@ -498,7 +497,7 @@ shape = SubResource("RectangleShape2D_ceat6") position = Vector2(2, 39) sign_mark_offset = Vector2(0, -3.86) trigger_mode = "interact" -freeze_time = 1.0 +cooldown_time = 1.0 hook_dialogue_title = "c01_s06_四个小孩_对话2" hook_method = "talk2" @@ -526,7 +525,7 @@ bus = &"game_sfx" [node name="猫鼠游戏开始ambush" parent="Ground/DeployLayer" index="17" instance=ExtResource("11_tudob")] position = Vector2(1809, 56) one_shot = false -freeze_time = 1.0 +cooldown_time = 1.0 hook_method = "game_intro" [node name="【胖小孩背着残疾小孩】" parent="Ground/DeployLayer" index="18" instance=ExtResource("8_ouldg")] @@ -618,14 +617,14 @@ shape = SubResource("RectangleShape2D_7cdhx") [node name="对话3ambush" parent="Ground/DeployLayer/【胖小孩背着残疾小孩】" instance=ExtResource("11_tudob")] position = Vector2(-2, 37) trigger_mode = "interact" -freeze_time = 1.0 +cooldown_time = 1.0 hook_dialogue_title = "c01_s06_四个小孩_对话3" hook_method = "talk3" [node name="猫鼠游戏胜利ambush" parent="Ground/DeployLayer" index="19" instance=ExtResource("11_tudob")] position = Vector2(4546, 45) one_shot = false -freeze_time = 0.1 +cooldown_time = 0.1 hook_method = "game_succeed" [node name="Fog" parent="Ground/DeployLayer/猫鼠游戏胜利ambush" instance=ExtResource("14_d5def")] diff --git a/scene/ground/scene/c01/s07_书店外.tscn b/scene/ground/scene/c01/s07_书店外.tscn index 5c01e977..8971cf67 100644 --- a/scene/ground/scene/c01/s07_书店外.tscn +++ b/scene/ground/scene/c01/s07_书店外.tscn @@ -219,8 +219,7 @@ autoplay = "杂戏团黄昏-其余小孩" [node name="Ambush监督小孩" parent="Ground/DeployLayer/其余小孩" instance=ExtResource("9_f61dl")] position = Vector2(-688, 53) -freeze_time = 0.1 -lock_player_on_playing_dialogue = false +cooldown_time = 0.1 hook_dialogue_title = "c01_s07_监督小孩吉祥话" hook_method = "greetings_ambush" @@ -262,7 +261,7 @@ action_configs = Array[Dictionary]([{ [node name="Ambush报童" parent="Ground/DeployLayer/报童" instance=ExtResource("9_f61dl")] position = Vector2(-11, 53) trigger_mode = "interact" -freeze_time = 1.0 +cooldown_time = 1.0 hook_method = "seller_interacted" [node name="Note橱柜" parent="Ground/DeployLayer" index="10" instance=ExtResource("5_3pha1")] diff --git a/scene/ground/scene/c01/s08_书店.tscn b/scene/ground/scene/c01/s08_书店.tscn index 4e8c4818..8737dae7 100644 --- a/scene/ground/scene/c01/s08_书店.tscn +++ b/scene/ground/scene/c01/s08_书店.tscn @@ -130,7 +130,7 @@ position = Vector2(431, 18) texture = ExtResource("5_tnrke") trigger_mode = "interact" one_shot = false -freeze_time = 1.0 +cooldown_time = 1.0 hook_method = "play_shelf_game" [node name="Interactable信件书桌" parent="Ground/DeployLayer" index="3" instance=ExtResource("7_fue0t")] @@ -173,7 +173,7 @@ shape = SubResource("RectangleShape2D_0x288") position = Vector2(537, 21) enabled = false trigger_mode = "interact" -freeze_time = 1.0 +cooldown_time = 1.0 hook_method = "pay_off_wage" [node name="老板" type="AnimatedSprite2D" parent="Ground/DeployLayer" index="8"] diff --git a/scene/ground/scene/c01/s09_公寓楼外.tscn b/scene/ground/scene/c01/s09_公寓楼外.tscn index 69dbe518..b4847fbf 100644 --- a/scene/ground/scene/c01/s09_公寓楼外.tscn +++ b/scene/ground/scene/c01/s09_公寓楼外.tscn @@ -147,7 +147,7 @@ position = Vector2(-119, 13) [node name="Ambush玩家擦肩而过" parent="Ground/DeployLayer/Ghost" instance=ExtResource("5_pssh2")] position = Vector2(96, 20) one_shot = false -freeze_time = 0.1 +cooldown_time = 0.1 hook_method = "player_been_passed" [node name="脚步声2D" type="AudioStreamPlayer2D" parent="Ground/DeployLayer/Ghost"] diff --git a/scene/ground/scene/c01/s11_黄包车演出.tscn b/scene/ground/scene/c01/s11_黄包车演出.tscn index f6d5b788..e467f9f7 100644 --- a/scene/ground/scene/c01/s11_黄包车演出.tscn +++ b/scene/ground/scene/c01/s11_黄包车演出.tscn @@ -217,7 +217,7 @@ animation = &"c00_吕萍_记笔记_right" position = Vector2(1365, 4) trigger_mode = "area_enter" one_shot = false -freeze_time = 1.0 +cooldown_time = 1.0 hook_method = "pop_title_1" [node name="ambush_title2" parent="Ground/DeployLayer" index="5" instance=ExtResource("6_3k8jj")] diff --git a/scene/ground/scene/c01/s12_书店外_诡异版.tscn b/scene/ground/scene/c01/s12_书店外_诡异版.tscn index f37092c6..2fe62f8a 100644 --- a/scene/ground/scene/c01/s12_书店外_诡异版.tscn +++ b/scene/ground/scene/c01/s12_书店外_诡异版.tscn @@ -158,7 +158,7 @@ position = Vector2(1127, 28) [node name="Ambush玩家被抓" parent="Ground/DeployLayer/Ghost" instance=ExtResource("9_nqlku")] enabled = false one_shot = false -freeze_time = 0.1 +cooldown_time = 0.1 hook_method = "player_been_catched" [node name="脚步声2D" type="AudioStreamPlayer2D" parent="Ground/DeployLayer/Ghost"] @@ -246,7 +246,7 @@ frame = 0 position = Vector2(0, 92) enabled = false one_shot = false -freeze_time = 1.0 +cooldown_time = 1.0 hook_method = "player_run_away" [node name="Light" parent="Ground/AmbientLayer" index="0" instance=ExtResource("5_kywnm")] diff --git a/scene/ground/scene/c02/s02_过道.tscn b/scene/ground/scene/c02/s02_过道.tscn index 78b07851..32c99a65 100644 --- a/scene/ground/scene/c02/s02_过道.tscn +++ b/scene/ground/scene/c02/s02_过道.tscn @@ -146,7 +146,7 @@ sign_mark_offset = Vector2(-18.52, -55.96) enabled = false trigger_mode = "interact" one_shot = false -freeze_time = 0.0 +cooldown_time = 0.0 [node name="wall" type="StaticBody2D" parent="Ground/DeployLayer/Ambush纸人"] position = Vector2(3, 4) @@ -168,7 +168,7 @@ script = ExtResource("14_jg8g0") position = Vector2(358, 50) trigger_mode = "interact" collision_width_and_x = Vector2(23.86, 0) -freeze_time = 1.0 +cooldown_time = 1.0 hook_method = "lumber_interacted" [node name="杂物眨眼睛" type="AnimatedSprite2D" parent="Ground/DeployLayer" index="11"] @@ -209,7 +209,7 @@ mute_when_interacted = true [node name="Ambush推小鞋子" parent="Ground/DeployLayer" index="16" instance=ExtResource("8_52as8")] position = Vector2(525, 61) one_shot = false -freeze_time = 1.0 +cooldown_time = 1.0 hook_method = "check_if_show_shoes" [node name="煤油灯" parent="Ground/DeployLayer" index="17" instance=ExtResource("17_mpkj1")] diff --git a/scene/ground/scene/c02/s03_院子.gd b/scene/ground/scene/c02/s03_院子.gd index e23a3773..1f449dc7 100644 --- a/scene/ground/scene/c02/s03_院子.gd +++ b/scene/ground/scene/c02/s03_院子.gd @@ -82,7 +82,7 @@ func _on_ground_ready() -> void: small_shoe = $"../DeployLayer/Pickable小鞋子" as Pickable2D - # 1: 交互; 2:已掉落 + # 1: 已交互疯子; 2:小鞋已掉落 if EventManager.get_stage("c02_madman_interacted") == 1: SceneManager.lock_player(0) # 等待转场 diff --git a/scene/ground/scene/c02/s03_院子.tscn b/scene/ground/scene/c02/s03_院子.tscn index d7c59101..f7ae5cc7 100644 --- a/scene/ground/scene/c02/s03_院子.tscn +++ b/scene/ground/scene/c02/s03_院子.tscn @@ -698,7 +698,7 @@ autoplay = "霸凌3" position = Vector2(-116, -13) enabled = false one_shot = false -freeze_time = 4.0 +cooldown_time = 4.0 hook_method = "block_right_move" [node name="wall" type="StaticBody2D" parent="Ground/DeployLayer/霸凌"] diff --git a/scene/ground/scene/c02/s06_二楼.tscn b/scene/ground/scene/c02/s06_二楼.tscn index 3131756a..41c3d6ef 100644 --- a/scene/ground/scene/c02/s06_二楼.tscn +++ b/scene/ground/scene/c02/s06_二楼.tscn @@ -1020,7 +1020,7 @@ position = Vector2(167, 38) enabled = false trigger_mode = "interact" one_shot = false -freeze_time = 0.1 +cooldown_time = 0.1 hook_method = "boys_ball_game" [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="Ground/DeployLayer/Ambush三男孩"] diff --git a/scene/ground/scene/c02/s10_空房间.tscn b/scene/ground/scene/c02/s10_空房间.tscn index b74d6dbe..e4775798 100644 --- a/scene/ground/scene/c02/s10_空房间.tscn +++ b/scene/ground/scene/c02/s10_空房间.tscn @@ -241,7 +241,7 @@ texture = ExtResource("15_e24j0") [node name="Ambush首次进入血脚印" parent="Ground/DeployLayer" index="13" instance=ExtResource("14_3ftnp")] position = Vector2(192, 38.4517) -freeze_time = 0.1 +cooldown_time = 0.1 hook_method = "first_enter_ambush" [node name="PointLight2D" type="PointLight2D" parent="Ground/AmbientLayer" index="0"] diff --git a/scene/ground/scene/c02/s13_盒子猫二楼.tscn b/scene/ground/scene/c02/s13_盒子猫二楼.tscn index 1a691f0e..5d782d84 100644 --- a/scene/ground/scene/c02/s13_盒子猫二楼.tscn +++ b/scene/ground/scene/c02/s13_盒子猫二楼.tscn @@ -78,21 +78,21 @@ hook_method = "knock_light_door" position = Vector2(103, 6) trigger_mode = "interact" one_shot = false -freeze_time = 1.5 +cooldown_time = 1.5 global_method = "c02_cat_play_with_door" [node name="Ambush猫咪敲门互动2" parent="Ground/DeployLayer" index="6" instance=ExtResource("9_yywsi")] position = Vector2(539, 6) trigger_mode = "interact" one_shot = false -freeze_time = 1.5 +cooldown_time = 1.5 global_method = "c02_cat_play_with_door" [node name="Ambush猫咪敲门互动3" parent="Ground/DeployLayer" index="7" instance=ExtResource("9_yywsi")] position = Vector2(663, 5) trigger_mode = "interact" one_shot = false -freeze_time = 1.5 +cooldown_time = 1.5 global_method = "c02_cat_play_with_door" [node name="追猫猪头怪_左侧" parent="Ground/DeployLayer" index="8" instance=ExtResource("10_kmk38")] diff --git a/scene/ground/scene/c02/s16_盒子猫三楼内侧.tscn b/scene/ground/scene/c02/s16_盒子猫三楼内侧.tscn index 1c141b34..67a0fbd5 100644 --- a/scene/ground/scene/c02/s16_盒子猫三楼内侧.tscn +++ b/scene/ground/scene/c02/s16_盒子猫三楼内侧.tscn @@ -48,7 +48,7 @@ target_portal = "left" position = Vector2(105, 16) trigger_mode = "interact" one_shot = false -freeze_time = 1.5 +cooldown_time = 1.5 global_method = "c02_cat_play_with_door" [node name="追猫猪头怪" parent="Ground/DeployLayer" index="4" instance=ExtResource("6_fjtlb")] diff --git a/scene/ground/scene/c02/s17_盒子猫三楼.tscn b/scene/ground/scene/c02/s17_盒子猫三楼.tscn index 3dbfd6a5..e8c06e75 100644 --- a/scene/ground/scene/c02/s17_盒子猫三楼.tscn +++ b/scene/ground/scene/c02/s17_盒子猫三楼.tscn @@ -51,7 +51,7 @@ target_portal = "left" position = Vector2(106, 6) trigger_mode = "interact" one_shot = false -freeze_time = 1.5 +cooldown_time = 1.5 global_method = "c02_cat_play_with_door" [node name="追猫猪头怪" parent="Ground/DeployLayer" index="4" instance=ExtResource("6_pfgbg")] diff --git a/scene/ground/scene/c02/s18_盒子猫一楼.tscn b/scene/ground/scene/c02/s18_盒子猫一楼.tscn index 12e81622..7b007885 100644 --- a/scene/ground/scene/c02/s18_盒子猫一楼.tscn +++ b/scene/ground/scene/c02/s18_盒子猫一楼.tscn @@ -43,28 +43,28 @@ target_portal = "right" position = Vector2(661, 6) trigger_mode = "interact" one_shot = false -freeze_time = 1.5 +cooldown_time = 1.5 global_method = "c02_cat_play_with_door" [node name="Ambush猫咪敲门互动3" parent="Ground/DeployLayer" index="3" instance=ExtResource("5_emyx1")] position = Vector2(538, 6) trigger_mode = "interact" one_shot = false -freeze_time = 1.5 +cooldown_time = 1.5 global_method = "c02_cat_play_with_door" [node name="Ambush猫咪敲门互动2" parent="Ground/DeployLayer" index="4" instance=ExtResource("5_emyx1")] position = Vector2(104, 6) trigger_mode = "interact" one_shot = false -freeze_time = 1.5 +cooldown_time = 1.5 global_method = "c02_cat_play_with_door" [node name="Ambush猫咪敲门互动4" parent="Ground/DeployLayer" index="5" instance=ExtResource("5_emyx1")] position = Vector2(219, 6) trigger_mode = "interact" one_shot = false -freeze_time = 1.5 +cooldown_time = 1.5 global_method = "c02_cat_play_with_door" [node name="追猫猪头怪" parent="Ground/DeployLayer" index="6" instance=ExtResource("6_xoyld")] diff --git a/scene/ground/script/c02/s00_煤油灯.gd b/scene/ground/script/c02/s00_煤油灯.gd index 51656de6..48bcc29c 100644 --- a/scene/ground/script/c02/s00_煤油灯.gd +++ b/scene/ground/script/c02/s00_煤油灯.gd @@ -89,7 +89,7 @@ func turn_on(gradually := true): # 保存打开次数 interacted_times = 1 _switch_gaslight(true, gradually) - _check_sign_display() + _check_sign_status() func _switch_gaslight(state := true, gradually := false): @@ -123,7 +123,7 @@ func _switch_gaslight(state := true, gradually := false): point_light_ground.energy = engrgy2 light_sprite2d.modulate.a = 1.0 ) - _check_sign_display() + _check_sign_status() diff --git a/scene/trailer.gd b/scene/trailer.gd index e72a9894..bd8b923d 100644 --- a/scene/trailer.gd +++ b/scene/trailer.gd @@ -8,6 +8,9 @@ var packed_index_page := preload("res://scene/index_page.tscn") func _ready() -> void: + if GlobalConfigManager.config and GlobalConfigManager.config.skip_trailer: + SceneManager.checkout_index_page(false) + return video_player.play() await video_player.finished mask.visible = true