完善 event 的 memo 机制,从 event_stage.dialogue 配置 stages 名,使用自定义 inspector 显示 stages 并关联 tooltip

This commit is contained in:
cakipaul 2025-07-07 23:59:22 +08:00
parent 6e093d3bfc
commit 510550b4a4
24 changed files with 374 additions and 48 deletions

View File

@ -122,6 +122,24 @@ func _parse_node(ground_node, node:Node, existing_vars:Dictionary, code_lines:Pa
## 线索笔记说明 ## 线索笔记说明
1. Aseprite 中编辑 slice 区域,配置区域名: c02_slices.ase
2. aseprite_slice_to_atlas.tscn 自动生成切图
3. 在 ux_note.tscn 中使用切图
4. 多语言本地化使用 c02_slices.ase 的不同图层导出,如 c02_slices.png 与 c02_slices_en.png
## Event 系统说明
1. 事件阶段管理event_stage.dialogue
2. 事件绑定EventBinder
- 通过事件阶段,控制父节点的显示/启用状态
- 订阅父节点交互 signal ,更新事件阶段
3. 复杂事件集合Event2D
- 自动生成并绑定脚本,用脚本更灵活地控制子节点状态
- 配合 ProAnimatedSprite 节点,可在编辑器直接预览小动画
4. memo 备忘系统:
- 自动读取 event_stage.dialogue 的信息,写入到 EventBinder/Event2D 的 memo 中
- EventBinder/Event2D 的阶段 Checkbox 的 tooltip 提示文本可以看到序号所对应的阶段名
## 存档结构 ## 存档结构
@ -164,3 +182,4 @@ current_scene 是通过 GroundLoader 加载的,在 ground loader 加载 ground
- 转场 process 机制优化:暂停 & AnimationPlayer 保持运行 - 转场 process 机制优化:暂停 & AnimationPlayer 保持运行
- EventManager 控制事件,使用 Event2D 控制绑定关系 - EventManager 控制事件,使用 Event2D 控制绑定关系
- Vibe Control 控制氛围情绪音乐 - Vibe Control 控制氛围情绪音乐

View File

@ -1,3 +1,4 @@
@tool
extends Node extends Node
const DialogueResource = preload("./dialogue_resource.gd") const DialogueResource = preload("./dialogue_resource.gd")

View File

@ -30,7 +30,7 @@ const DialogueLine = preload("./dialogue_line.gd")
## be a title string or a stringified line number). Runs any mutations along the way and then returns ## be a title string or a stringified line number). Runs any mutations along the way and then returns
## the first dialogue line encountered. ## the first dialogue line encountered.
func get_next_dialogue_line(title: String = "", extra_game_states: Array = [], mutation_behaviour: DMConstants.MutationBehaviour = DMConstants.MutationBehaviour.Wait) -> DialogueLine: func get_next_dialogue_line(title: String = "", extra_game_states: Array = [], mutation_behaviour: DMConstants.MutationBehaviour = DMConstants.MutationBehaviour.Wait) -> DialogueLine:
return await Engine.get_singleton("DialogueManager").get_next_dialogue_line(self, title, extra_game_states, mutation_behaviour) return await DialogueManager.get_next_dialogue_line(self, title, extra_game_states, mutation_behaviour)
## Get the list of any titles found in the file. ## Get the list of any titles found in the file.

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dhan4svvxtqwd"
path="res://.godot/imported/checked.png-cb94f802c96994b2840cade9448d51ae.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/property-inspector/event_2d/checked.png"
dest_files=["res://.godot/imported/checked.png-cb94f802c96994b2840cade9448d51ae.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://rq4dsxooay2"
path="res://.godot/imported/radio_checked.png-e28720cbc9fafadcb0954b33d0f47b82.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/property-inspector/event_2d/radio_checked.png"
dest_files=["res://.godot/imported/radio_checked.png-e28720cbc9fafadcb0954b33d0f47b82.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View File

@ -0,0 +1,85 @@
extends EditorProperty
var h_box: HBoxContainer = HBoxContainer.new()
var stage_nodes := []
var updating = false
var property_name: String
func _init(p_name) -> void:
property_name = p_name
add_child(h_box)
func _get_property() -> Array[Dictionary]:
return get_edited_object()[property_name]
func _update_property() -> void:
# Clear the control.
for s in stage_nodes:
s.queue_free()
stage_nodes.clear()
_reload_stages()
var box_checked_texture = preload("res://addons/property-inspector/event_2d/checked.png")
var box_unchecked_texture = preload("res://addons/property-inspector/event_2d/unchecked.png")
func _make_unique_and_sort(arr: Array[int]) -> void:
var unique_arr: Array[int] = []
for element in arr:
if not element in unique_arr:
unique_arr.append(element)
unique_arr.sort()
arr.assign(unique_arr)
func _reload_stages():
var obj = get_edited_object()
if obj == null:
printerr("obj is null")
return
var stages = obj[property_name] as Array[int]
var event_name
if property_name == "pre_event_stages":
event_name = obj["pre_event_name"]
elif property_name == "event_stages":
event_name = obj["event_name"]
elif property_name == "updater_stages":
event_name = obj["updater_event"]
var stages_name: PackedStringArray = await EventManager.get_event_stage_map_array(event_name)
# print("stages:", stages)
h_box.add_theme_constant_override("separation", 1)
for i in 7:
# make the text inside the box
var container := AspectRatioContainer.new()
container.set_anchors_preset(PRESET_FULL_RECT)
var box: CheckBox = CheckBox.new() as CheckBox
box.button_pressed = i in stages
box.toggled.connect(_on_toggle_checkbox.bind(i))
box.add_theme_icon_override("checked", box_checked_texture)
box.add_theme_icon_override("unchecked", box_unchecked_texture)
container.add_child(box)
var label := Label.new()
label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER
container.add_child(label)
label.text = str(i)
h_box.add_child(container)
stage_nodes.append(container)
if stages_name.size() > i:
box.tooltip_text = stages_name[i]
func _on_toggle_checkbox(on: bool, id: int):
# 防止 read-only 所以 duplicate
var arr = get_edited_object()[property_name].duplicate()
if on:
arr.append(id)
else:
arr.erase(id)
_make_unique_and_sort(arr)
emit_changed(property_name, arr)
get_edited_object()._auto_memo()

View File

@ -0,0 +1 @@
uid://bjsrudsa3cpyx

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 B

View File

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://c8un06r0tg2ur"
path="res://.godot/imported/unchecked.png-ec639bca865e24a176cd170b2f702f9a.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://addons/property-inspector/event_2d/unchecked.png"
dest_files=["res://.godot/imported/unchecked.png-ec639bca865e24a176cd170b2f702f9a.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

View File

@ -2,10 +2,11 @@ extends EditorInspectorPlugin
var move_editor = preload("pro_animation_sprite2d/pro_animation_move_editor.gd") var move_editor = preload("pro_animation_sprite2d/pro_animation_move_editor.gd")
var action_editor = preload("pro_animation_sprite2d/pro_animation_action_editor.gd") var action_editor = preload("pro_animation_sprite2d/pro_animation_action_editor.gd")
var stages_editor = preload("event_2d/stages_editor.gd")
func _can_handle(object): func _can_handle(object):
return object is ProAnimatedSprite2D return object is ProAnimatedSprite2D or object is Event2D or object is EventBinder
func _parse_property(object, type, name, hint_type, hint_string, usage_flags, wide): func _parse_property(object, type, name, hint_type, hint_string, usage_flags, wide):
@ -17,5 +18,7 @@ func _parse_property(object, type, name, hint_type, hint_string, usage_flags, wi
elif name == "action_configs": elif name == "action_configs":
add_property_editor(name, action_editor.new()) add_property_editor(name, action_editor.new())
return true return true
else: elif name == "pre_event_stages" or name == "event_stages" or name == "updater_stages":
add_property_editor(name, stages_editor.new(name))
return true
return false return false

View File

@ -1,19 +1,23 @@
~ EventStage ~ EventStage_c00
# 0demo 1release release_stage: 0:demo 1:release
release_stage
# 0:关闭 1:打开 2:放入小蝉人偶 3:全部放置正确_可摇手柄 4:已播放完成
c02_musicbox_stage
# 1:已交互疯子 2小鞋已掉落
c02_madman_interacted_stage
# 0:默认 1:寻找弹珠_老虎钳可以换弹珠 2:给出弹珠 3:游戏结束_小猫纸片 4:游戏结束_小猫离开
c02_ball_game_stage
# c03 第二章
# 0未开始 1邀请 2完成
c03_invite_xchan_supper
=> END => END
~ ArchiveStage ~ EventStage_c02
c02_musicbox_stage: 0:初始化_关闭 1:打开 2:放入小蝉人偶 3:全部放置正确_可摇手柄 4:已播放完成
c02_madman_interacted_stage: 0:初始化 1:已交互疯子 2小鞋已掉落
c02_ball_game_stage: 0:初始化 1:寻找弹珠_老虎钳可以换弹珠 2:给出弹珠 3:游戏结束_小猫纸片 4:游戏结束_小猫离开
=> END
~ EventStage_c03
c03_s01_meat_put: 0:初始化 1:已放肉
c03_invite_xchan_supper: 0:初始化 1:已偷听_需邀请 2:已完成邀请
=> END
~ EventStage_c04
=> END
~ EventStage_c05
=> END
~ EventStage_c06
=> END => END

View File

@ -45,6 +45,7 @@ func _ready() -> void:
# if event_name != &"": # if event_name != &"":
# name = "Event_" + event_name # name = "Event_" + event_name
if Engine.is_editor_hint(): if Engine.is_editor_hint():
_auto_memo()
return return
if event_name != "": if event_name != "":
stage = EventManager.get_stage(event_name) stage = EventManager.get_stage(event_name)
@ -150,17 +151,20 @@ func _copy_getter():
func _auto_memo() -> void: func _auto_memo() -> void:
var memo_str := "" var memo_str := ""
# if EventManager
if pre_event_name != &"" and pre_event_mode != "none": if pre_event_name != &"" and pre_event_mode != "none":
memo_str += "当前置事件[" memo_str += "当前置事件["
memo_str += pre_event_name memo_str += pre_event_name
memo_str += "=" if pre_event_mode == "show" else "!=" memo_str += "=" if pre_event_mode == "show" else "!="
memo_str += "|".join(pre_event_stages) + "]" var stages = await EventManager.map_event_stages(pre_event_name, pre_event_stages)
memo_str += "|".join(stages) + "]"
if event_name != &"" and event_mode != "none": if event_name != &"" and event_mode != "none":
memo_str += "" if memo_str.is_empty() else "\n并且" memo_str += "" if memo_str.is_empty() else "\n并且"
memo_str += "当事件[" memo_str += "当事件["
memo_str += event_name memo_str += event_name
memo_str += "=" if event_mode == "show" else "!=" memo_str += "=" if event_mode == "show" else "!="
memo_str += "|".join(event_stages) + "]时" var stages = await EventManager.map_event_stages(event_name, event_stages)
memo_str += "|".join(stages) + "]时"
memo_str += "" if memo_str.is_empty() else "显示该节点" memo_str += "" if memo_str.is_empty() else "显示该节点"
var existing_lines = event_memo.split("\n") var existing_lines = event_memo.split("\n")
# 保留 # 开头的 line # 保留 # 开头的 line

View File

@ -169,12 +169,14 @@ func _auto_memo() -> void:
if updater_event != "": if updater_event != "":
memo_str = updater_event memo_str = updater_event
memo_str += "=" if updater_stage_mode == "include" else "!=" memo_str += "=" if updater_stage_mode == "include" else "!="
memo_str += "|".join(updater_stages) + " 时," var stages = await EventManager.map_event_stages(updater_event, updater_stages)
memo_str += "[" + "|".join(stages) + "] 时,"
memo_str += "显示" if updater_mode == "shower" else "启用" memo_str += "显示" if updater_mode == "shower" else "启用"
memo_str += ": [" + parent_name + "]\n" memo_str += ": [" + parent_name + "]\n"
if trigger_event != "" and trigger_mode != "none": if trigger_event != "" and trigger_mode != "none":
memo_str += "[" + parent_name + "] " + trigger_mode + " 时: " memo_str += "[" + parent_name + "] " + trigger_mode + " 时: "
memo_str += trigger_event + "=" + str(trigger_stage) var stages = await EventManager.map_event_stages(trigger_event, [trigger_stage])
memo_str += trigger_event + "=" + str(stages[0])
memo_str += "(greater)" if trigger_set_stage_if_greater else "(any)" memo_str += "(greater)" if trigger_set_stage_if_greater else "(any)"
var existing_lines = memo.split("\n") var existing_lines = memo.split("\n")
# 保留 # 开头的 line # 保留 # 开头的 line

View File

@ -1,9 +1,12 @@
@tool
extends Node extends Node
signal stage_updated(event_name: StringName, stage: int) signal stage_updated(event_name: StringName, stage: int)
func _ready() -> void: func _ready() -> void:
if Engine.is_editor_hint():
return
# 0demo 1release # 0demo 1release
set_stage("release_stage", GlobalConfig.RELEASE_STAGE) set_stage("release_stage", GlobalConfig.RELEASE_STAGE)
@ -67,3 +70,67 @@ func next_staged(event_name: StringName, stage_max := 99999) -> void:
func prop_interacted(e_name, prop_key, interacted_times) -> void: func prop_interacted(e_name, prop_key, interacted_times) -> void:
print("Event: %s interacted with %s. total times: %s" % [e_name, prop_key, interacted_times]) print("Event: %s interacted with %s. total times: %s" % [e_name, prop_key, interacted_times])
##### TOOL 方法
# event_name -> {stages:PackedStringArray, update_time:int}
var _debug_event_stage_dict := {}
# return: stages
func get_event_stage_map_array(event_name: StringName) -> PackedStringArray:
if not Engine.is_editor_hint():
return PackedStringArray()
var current_dict = _debug_event_stage_dict.get(event_name)
var time_msec = Time.get_ticks_msec()
# 3秒更新
if current_dict and time_msec - current_dict["update_time"] < 3000:
return current_dict["stages"]
# 文件: res://asset/dialogue/event_stage.dialogue
var event_stage_resource = load("uid://dohpsb4jttuv1") as DialogueResource
for title in event_stage_resource.get_titles():
var lines = await Util.get_lines(event_stage_resource, title)
for line in lines:
var line_text = line.text.strip_edges()
var e_name = line.character
if line_text.begins_with("#"):
continue
#c03_invite_xchan_supper: 0:未开始 1:已偷听,需邀请 2:已完成邀请
var parts = line_text.split(" ")
var stages = PackedStringArray()
for id in range(0, len(parts)):
var tuple = parts[id].split(":")
if len(tuple) == 2:
var event_stage = int(tuple[0])
if stages.size() < event_stage + 1:
stages.resize(event_stage + 1)
stages[event_stage] = tuple[1]
for id in len(stages):
if stages[id] == "":
stages[id] = str(id)
_debug_event_stage_dict[e_name] = {
"stages": stages,
"update_time": time_msec,
}
if _debug_event_stage_dict.has(event_name):
prints("reload", event_name, "stages:", _debug_event_stage_dict[event_name]["stages"])
return _debug_event_stage_dict[event_name]["stages"]
return PackedStringArray()
# map stage_id->name, 必定保持相同长度的数组
func map_event_stages(
event_name: StringName, stages: Array, including_id := true
) -> PackedStringArray:
var result = PackedStringArray()
result.resize(stages.size())
var dict = await get_event_stage_map_array(event_name)
for id in range(stages.size()):
var stage = stages[id]
if dict.size() > stage:
if including_id:
result[id] = str(stage) + ":" + dict[stage]
else:
result[id] = str(stage)
return result

View File

@ -206,9 +206,7 @@ func enable_prop_item(prop_key: String) -> void:
func enable_important_item(prop_key: String, display_inspector = true) -> void: func enable_important_item(prop_key: String, display_inspector = true) -> void:
var prop_hud = get_prop_hud() var prop_hud = get_prop_hud()
if prop_hud: if prop_hud:
prop_hud.inventory.enable_important_item(prop_key) prop_hud.enable_important_item(prop_key, display_inspector)
# if display_inspector:
# prop_hud.display_inspector(prop_key)
else: else:
printerr("enable_important_item PropHud node not found") printerr("enable_important_item PropHud node not found")

View File

@ -1,4 +1,4 @@
[gd_scene load_steps=66 format=3 uid="uid://cootarwb44vvh"] [gd_scene load_steps=67 format=3 uid="uid://cootarwb44vvh"]
[ext_resource type="PackedScene" uid="uid://dayyx4jerj7io" path="res://scene/ground/ground.tscn" id="1_qkymk"] [ext_resource type="PackedScene" uid="uid://dayyx4jerj7io" path="res://scene/ground/ground.tscn" id="1_qkymk"]
[ext_resource type="Script" uid="uid://cbt0ubygchxvv" path="res://scene/ground/scene/c02/s06_二楼.gd" id="2_4dg6u"] [ext_resource type="Script" uid="uid://cbt0ubygchxvv" path="res://scene/ground/scene/c02/s06_二楼.gd" id="2_4dg6u"]
@ -46,6 +46,7 @@
[ext_resource type="Texture2D" uid="uid://b5kolhax7pf4u" path="res://asset/art/scene/c02/s06_二楼楼道/小猫纸条.png" id="37_rjlld"] [ext_resource type="Texture2D" uid="uid://b5kolhax7pf4u" path="res://asset/art/scene/c02/s06_二楼楼道/小猫纸条.png" id="37_rjlld"]
[ext_resource type="Script" uid="uid://bnm8wuspfx303" path="res://scene/ground/script/c02/event_2d_xchan_run_away.gd" id="39_t5e0j"] [ext_resource type="Script" uid="uid://bnm8wuspfx303" path="res://scene/ground/script/c02/event_2d_xchan_run_away.gd" id="39_t5e0j"]
[ext_resource type="SpriteFrames" uid="uid://di43shn22n5ph" path="res://asset/art/gif/c00_通用动作/c00_通用动作_frames.tres" id="40_7i4w0"] [ext_resource type="SpriteFrames" uid="uid://di43shn22n5ph" path="res://asset/art/gif/c00_通用动作/c00_通用动作_frames.tres" id="40_7i4w0"]
[ext_resource type="Script" uid="uid://n56a07gyjq1u" path="res://scene/ground/script/c03/s02_event_2d偷听陆仁小蝶对话后.gd" id="46_sqio2"]
[sub_resource type="Animation" id="Animation_k01ve"] [sub_resource type="Animation" id="Animation_k01ve"]
length = 0.001 length = 0.001
@ -971,6 +972,8 @@ prop_key = "prop_不存在的钥匙"
[node name="EventBinder开门" type="Node" parent="Ground/DeployLayer/portal_5"] [node name="EventBinder开门" type="Node" parent="Ground/DeployLayer/portal_5"]
script = ExtResource("10_0k27j") script = ExtResource("10_0k27j")
memo = "current_chapter_stage!=1|2 时,启用: [_5]
"
updater_event = &"current_chapter_stage" updater_event = &"current_chapter_stage"
updater_stage_mode = "exclude" updater_stage_mode = "exclude"
updater_stages = Array[int]([1, 2]) updater_stages = Array[int]([1, 2])
@ -1307,6 +1310,7 @@ position = Vector2(164, 42)
script = ExtResource("35_h3h1a") script = ExtResource("35_h3h1a")
pre_event_name = &"c02_ball_game_stage" pre_event_name = &"c02_ball_game_stage"
pre_event_stages = Array[int]([3]) pre_event_stages = Array[int]([3])
event_memo = "当前置事件[c02_ball_game_stage=0]显示该节点"
metadata/_custom_type_script = "uid://bkkiyk5jkdw4d" metadata/_custom_type_script = "uid://bkkiyk5jkdw4d"
[node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="Ground/DeployLayer/Event_小猫纸条"] [node name="AnimatedSprite2D" type="AnimatedSprite2D" parent="Ground/DeployLayer/Event_小猫纸条"]
@ -1331,6 +1335,7 @@ position = Vector2(9, -4)
script = ExtResource("39_t5e0j") script = ExtResource("39_t5e0j")
event_name = &"c02_2f_xchan_run_away" event_name = &"c02_2f_xchan_run_away"
event_stages = Array[int]([1]) event_stages = Array[int]([1])
event_memo = "当事件[c02_2f_xchan_run_away=0]时显示该节点"
metadata/_custom_type_script = "uid://bkkiyk5jkdw4d" metadata/_custom_type_script = "uid://bkkiyk5jkdw4d"
[node name="Ambush走到尽头后小蝉跑" parent="Ground/DeployLayer/Event2D_xchan_run_away" instance=ExtResource("14_k01ve")] [node name="Ambush走到尽头后小蝉跑" parent="Ground/DeployLayer/Event2D_xchan_run_away" instance=ExtResource("14_k01ve")]
@ -1352,6 +1357,13 @@ move_configs = Array[Dictionary]([{
}]) }])
debug_mov_animation = "c00_头套小婵_run" debug_mov_animation = "c00_头套小婵_run"
[node name="Event2D偷听陆仁对话后" type="Node2D" parent="Ground/DeployLayer" index="24"]
script = ExtResource("46_sqio2")
event_name = &"c03_invite_xchan_supper"
event_stages = Array[int]([2])
event_memo = "当事件[c03_invite_xchan_supper=2:已完成邀请]时显示该节点"
metadata/_custom_type_script = "uid://bkkiyk5jkdw4d"
[node name="MainPlayer" parent="Ground" index="5"] [node name="MainPlayer" parent="Ground" index="5"]
position = Vector2(63, 95) position = Vector2(63, 95)
catty_light_energy = 0.5 catty_light_energy = 0.5

View File

@ -216,7 +216,7 @@ prop_key = "prop_奇怪的肉"
[node name="EventBinder" type="Node" parent="Ground/DeployLayer/Interactable放肉处"] [node name="EventBinder" type="Node" parent="Ground/DeployLayer/Interactable放肉处"]
script = ExtResource("6_yaa68") script = ExtResource("6_yaa68")
memo = "[放肉处] interacted时c03_s01_meat_put=1(greater)" memo = "[放肉处] interacted : c03_s01_meat_put=1:已放肉(greater)"
trigger_event = &"c03_s01_meat_put" trigger_event = &"c03_s01_meat_put"
trigger_mode = "interacted" trigger_mode = "interacted"
metadata/_custom_type_script = "uid://0wjaho6qkg6s" metadata/_custom_type_script = "uid://0wjaho6qkg6s"
@ -225,7 +225,7 @@ metadata/_custom_type_script = "uid://0wjaho6qkg6s"
script = ExtResource("7_obrgj") script = ExtResource("7_obrgj")
event_name = &"c03_s01_meat_put" event_name = &"c03_s01_meat_put"
event_stages = Array[int]([1]) event_stages = Array[int]([1])
event_memo = "c03_s01_meat_put=0|2" event_memo = "当事件[c03_s01_meat_put=1:已放肉]时显示该节点"
metadata/_custom_type_script = "uid://bkkiyk5jkdw4d" metadata/_custom_type_script = "uid://bkkiyk5jkdw4d"
[node name="窗口闪动" type="AnimatedSprite2D" parent="Ground/DeployLayer/Event2D放肉后"] [node name="窗口闪动" type="AnimatedSprite2D" parent="Ground/DeployLayer/Event2D放肉后"]
@ -247,7 +247,7 @@ packed_scene = ExtResource("7_d27sg")
[node name="EventBinder" type="Node" parent="Ground/DeployLayer/Event2D放肉后/CloseupDemo公告"] [node name="EventBinder" type="Node" parent="Ground/DeployLayer/Event2D放肉后/CloseupDemo公告"]
script = ExtResource("6_yaa68") script = ExtResource("6_yaa68")
memo = "release_stage=0 时,显示: [公告] memo = "release_stage=[0:demo] 时,显示: [公告]
" "
updater_event = &"release_stage" updater_event = &"release_stage"
updater_mode = "shower" updater_mode = "shower"
@ -358,10 +358,10 @@ hook_method = "eavesdrop_luren"
[node name="EventBinder" type="Node" parent="Ground/DeployLayer/Ambush偷听陆仁"] [node name="EventBinder" type="Node" parent="Ground/DeployLayer/Ambush偷听陆仁"]
script = ExtResource("6_yaa68") script = ExtResource("6_yaa68")
memo = "c03_s01_meat_put=1 时,启用: [偷听陆仁] memo = "c03_s01_meat_put=[1:已放肉] 时,启用: [偷听陆仁]
[偷听陆仁] triggered 时: c03_偷听并邀请小蝶=1(greater)" [偷听陆仁] triggered 时: c03_invite_xchan_supper=1:已偷听_需邀请(greater)"
updater_event = &"c03_s01_meat_put" updater_event = &"c03_s01_meat_put"
trigger_event = &"c03_偷听并邀请小蝶" trigger_event = &"c03_invite_xchan_supper"
trigger_mode = "triggered" trigger_mode = "triggered"
metadata/_custom_type_script = "uid://0wjaho6qkg6s" metadata/_custom_type_script = "uid://0wjaho6qkg6s"

View File

@ -1,7 +1,7 @@
[gd_scene load_steps=17 format=3 uid="uid://ctwy1ubhm68la"] [gd_scene load_steps=17 format=3 uid="uid://ctwy1ubhm68la"]
[ext_resource type="PackedScene" uid="uid://dayyx4jerj7io" path="res://scene/ground/ground.tscn" id="1_jad6f"] [ext_resource type="PackedScene" uid="uid://dayyx4jerj7io" path="res://scene/ground/ground.tscn" id="1_jad6f"]
[ext_resource type="Script" path="res://scene/ground/scene/c03/s02_瞎子新卧室.gd" id="2_y504i"] [ext_resource type="Script" uid="uid://tk4wg0i4payx" path="res://scene/ground/scene/c03/s02_瞎子新卧室.gd" id="2_y504i"]
[ext_resource type="Script" uid="uid://cpejxlfni6n52" path="res://manager/audio_manager/vibe_sfx.gd" id="3_kchgf"] [ext_resource type="Script" uid="uid://cpejxlfni6n52" path="res://manager/audio_manager/vibe_sfx.gd" id="3_kchgf"]
[ext_resource type="Texture2D" uid="uid://vc2hn6t5bedg" path="res://asset/art/scene/c03/s02_瞎子新卧室/bg_瞎子新卧室.png" id="4_hehhg"] [ext_resource type="Texture2D" uid="uid://vc2hn6t5bedg" path="res://asset/art/scene/c03/s02_瞎子新卧室/bg_瞎子新卧室.png" id="4_hehhg"]
[ext_resource type="Texture2D" uid="uid://7ay1ttob8qwm" path="res://asset/art/scene/c02/s08_瞎子卧室/e_床板.png" id="5_xifhb"] [ext_resource type="Texture2D" uid="uid://7ay1ttob8qwm" path="res://asset/art/scene/c02/s08_瞎子卧室/e_床板.png" id="5_xifhb"]
@ -179,19 +179,25 @@ texture = ExtResource("7_u55tr")
[node name="Event2D偷听陆仁对话后" type="Node2D" parent="Ground/DeployLayer" index="4"] [node name="Event2D偷听陆仁对话后" type="Node2D" parent="Ground/DeployLayer" index="4"]
script = ExtResource("8_pixqd") script = ExtResource("8_pixqd")
event_name = &"c03_偷听并邀请小蝶" event_name = &"c03_invite_xchan_supper"
event_stages = Array[int]([1]) event_stages = Array[int]([1])
event_memo = "当事件[c03_偷听并邀请小蝶=1]时显示该节点" event_memo = "当事件[c03_invite_xchan_supper=1:已偷听_需邀请]时显示该节点"
metadata/_custom_type_script = "uid://bkkiyk5jkdw4d" metadata/_custom_type_script = "uid://bkkiyk5jkdw4d"
[node name="瞎子抽烟" parent="Ground/DeployLayer/Event2D偷听陆仁对话后" instance=ExtResource("10_jad6f")] [node name="瞎子抽烟" parent="Ground/DeployLayer/Event2D偷听陆仁对话后" instance=ExtResource("10_jad6f")]
position = Vector2(229, 39) position = Vector2(229, 39)
sprite_frames = ExtResource("10_2hv3f") sprite_frames = ExtResource("10_2hv3f")
animation = &"瞎子_咳嗽吐血" animation = &"瞎子_咳嗽吐血"
frame = 28
action_configs = Array[Dictionary]([{ action_configs = Array[Dictionary]([{
&"animation_intro": "瞎子_抽烟", &"animation_intro": "瞎子_抽烟",
&"animation_next": "瞎子_坐拿烟_左呼吸" &"animation_next": "瞎子_坐拿烟_左呼吸",
"animation_wait_time": 0.0,
"intro_loop": 1
}, {
"animation_intro": "瞎子_咳嗽吐血",
&"animation_next": "瞎子_坐拿烟_左呼吸",
"animation_wait_time": 0.0,
"intro_loop": 1
}]) }])
[node name="MainPlayer" parent="Ground" index="5"] [node name="MainPlayer" parent="Ground" index="5"]

View File

@ -16,9 +16,15 @@ func _on_global_stage_updated(e: StringName, s: int):
func _on_ground_ready(ground: Ground2D): func _on_ground_ready(ground: Ground2D):
if stage == 0:
# 邀请小蝉晚饭 # 邀请小蝉晚饭
EventManager.set_stage(event_name, 1) if stage == 1:
var the_blind = $"瞎子抽烟" as AnimatedSprite2D
the_blind.play("瞎子_抽烟")
await the_blind.animation_finished
the_blind.play("瞎子_咳嗽吐血")
await the_blind.animation_finished
# 邀请成功
EventManager.set_stage(event_name, 2)
func _on_pre_stage_updated(): func _on_pre_stage_updated():

View File

@ -460,6 +460,18 @@ func _toggle_btn_ability(v: bool) -> void:
right_btn.disabled = !v right_btn.disabled = !v
func enable_important_item(prop_key: String, display_inspector: bool) -> void:
if not inventory or not prop_key:
return
if not items_dict.has(prop_key):
push_error("ImportantPropItem not found! key=" + prop_key)
return
inventory.enable_important_item(prop_key)
SceneManager.pop_notification("ui_notify_important_item_update")
if display_inspector:
inspect_item(prop_key)
func enable_prop_item(prop_key: String, inspect := true) -> void: func enable_prop_item(prop_key: String, inspect := true) -> void:
if not inventory or not prop_key: if not inventory or not prop_key:
return return
@ -480,13 +492,17 @@ func enable_prop_item(prop_key: String, inspect := true) -> void:
func inspect_item(prop_key: String, display_words_only := false): func inspect_item(prop_key: String, display_words_only := false):
var inspector = SceneManager.get_inspector() var inspector = SceneManager.get_inspector()
if inspector: if inspector:
var texture_path = items_dict[prop_key].texture_path
var inspect_path = items_dict[prop_key].inspect_path var inspect_path = items_dict[prop_key].inspect_path
# 是否有独立的 inspect 图片 # 是否有独立的 inspect 图片
if inspect_path: if inspect_path:
var texture = load(inspect_path) as Texture2D var texture = load(inspect_path) as Texture2D
inspector.pop_prop_inspection(prop_key, texture, false, display_words_only) inspector.pop_prop_inspection(prop_key, texture, false, display_words_only)
else: else:
var texture = cached_inventory_textures[prop_key] var texture = cached_inventory_textures.get(prop_key)
if not texture:
texture = load(texture_path) as Texture2D
cached_inventory_textures[prop_key] = texture
inspector.pop_prop_inspection(prop_key, texture, true, display_words_only) inspector.pop_prop_inspection(prop_key, texture, true, display_words_only)

View File

@ -20,7 +20,6 @@ signal quit_and_hidden
@onready var content_label = %ContentLabel as Label @onready var content_label = %ContentLabel as Label
@onready var tip_label = %TipLabel as Label @onready var tip_label = %TipLabel as Label
var tip_cover = "Q: " + tr("ui_退出") + " " + "E: " + tr("ui_阅读") var tip_cover = "Q: " + tr("ui_退出") + " " + "E: " + tr("ui_阅读")
var tip_notes = "Q: " + tr("ui_退出") + " " + "E: " + tr("ui_收起") var tip_notes = "Q: " + tr("ui_退出") + " " + "E: " + tr("ui_收起")
var texture_cover: Texture2D var texture_cover: Texture2D
@ -162,8 +161,10 @@ func pop_prop_inspection(
if not display_words_only: if not display_words_only:
text += obtain_str + ": " + prop_title + "[#item]\n" text += obtain_str + ": " + prop_title + "[#item]\n"
# 道具的一句话说明 # 道具的一句话说明
text += tr(prop_key + "_说明").replace("{br}", "\n").strip_edges() + "\n" var original_word_lines = tr(prop_key + "_说明").replace("{br}", "\n").split("\n")
text += "=> END" # 缩略只要第一行
text += original_word_lines[0] + ("..." if len(original_word_lines) > 1 else "")
text += "\n=> END"
var current_prop_res = DialogueManager.create_resource_from_text(text) var current_prop_res = DialogueManager.create_resource_from_text(text)
# 手动跳过的同时显示下一句 # 手动跳过的同时显示下一句
if is_instance_valid(balloon): if is_instance_valid(balloon):

View File

@ -41,7 +41,6 @@ func enable_important_item(prop_key: String) -> void:
if not important_items.has(prop_key): if not important_items.has(prop_key):
important_items.append(prop_key) important_items.append(prop_key)
unviewed_important_items.append(prop_key) unviewed_important_items.append(prop_key)
SceneManager.pop_notification("ui_notify_important_item_update")
func has_prop(prop_key: String) -> bool: func has_prop(prop_key: String) -> bool:

View File

@ -1,6 +1,6 @@
@tool
extends Node extends Node
#### Timer #### Timer
func wait(duration: float) -> void: func wait(duration: float) -> void:
if duration <= 0: if duration <= 0: