Merge remote-tracking branch 'origin/demo'
This commit is contained in:
commit
7f8136784f
Binary file not shown.
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.1 KiB |
@ -147,19 +147,20 @@ c01_s08_书店工钱,这个月的工钱还没拿。,,,,,I haven't collected this
|
|||||||
mem_偷听对话,偷听对话,,,,,Eavesdropping
|
mem_偷听对话,偷听对话,,,,,Eavesdropping
|
||||||
mem_疯子看井,疯子看井,,,,,Madman Guards Well
|
mem_疯子看井,疯子看井,,,,,Madman Guards Well
|
||||||
c01_鸡毛掸子,这是鸡毛掸子吗?,,,,,Is this a feather duster?
|
c01_鸡毛掸子,这是鸡毛掸子吗?,,,,,Is this a feather duster?
|
||||||
c01_院长书桌,桌上放着一本《圣经》。{br}「得著生命的,將要失喪生命...」,,,,,There's a Bible on the desk.{br}'Whoever finds their life will lose it...'
|
c01_院长书桌,桌上放着一本《圣经》。{br}「凡要救自己生命的,必丧掉生命...」,,,,,"There's a Bible on the table.{br}'Whoever wants to save their life will lose it, but whoever loses their life for me will find it...'"
|
||||||
c01_院长床,这本书已经看过了。{br}...那些句子是什么意思呢?,,,,,I've already read this book.{br}...What do those sentences mean?
|
c01_院长床,这本书已经看过了。{br}...那些句子是什么意思呢?,,,,,I've already read this book.{br}...What do those sentences mean?
|
||||||
c01_院长座钟,这西洋钟没坏的时候,走针会咔哒、咔哒地响...{br}停在未时一刻不动了。,,,,,"When this Western clock wasn't broken, the hands would tick and tock...{br}It's stopped at a quarter past one in the afternoon."
|
c01_院长座钟,咦?这西洋钟为什么倒着走?,,,,,Huh? Why is this Western clock running backwards?
|
||||||
c01_倾斜的洋相片,哇啊,这张洋相片要掉下来了!{br}我得做点什么...,,,,,"Oh no, this Western photograph is about to fall!{br}I need to do something..."
|
c01_倾斜的洋相片,哇啊,这张洋相片要掉下来了!{br}我得做点什么...,,,,,"Oh no, this Western photograph is about to fall!{br}I need to do something..."
|
||||||
c01_摆正的洋相片,这是院长的儿子吗?,,,,,Is this the director's son?
|
c01_摆正的洋相片,这是院长的儿子吗?,,,,,Is this the director's son?
|
||||||
c01_s06_院长房间,这是院长的房间,,,,,This is the director's room
|
c01_s06_院长房间,这是院长的房间,,,,,This is the director's room
|
||||||
c01_s06_小朋友房间,这是其他小朋友的房间,,,,,This is the other children's room
|
c01_s06_小朋友房间,这是其他小朋友的房间,,,,,This is the other children's room
|
||||||
c01_s06_熟悉的墙画,墙上的画看起来好熟悉。{br}过去问问看吧,没准他们几个知道些什么。,,,,,The painting on the wall looks so familiar.{br}Let me go ask them. Maybe they know something.
|
c01_s06_熟悉的墙画,墙上的画看起来好熟悉。{br}过去问问看吧,没准他们几个知道些什么。,,,,,The painting on the wall looks so familiar.{br}Let me go ask them. Maybe they know something.
|
||||||
c01_s06_四小孩对话结束,怪人、花、门...{br}他在找什么东西,或是什么人?,,,,,"Strange man, flowers, door...{br}What is he looking for, or who?"
|
c01_s06_四小孩对话结束,怪人、花...{br}有时候真搞不懂他们在说些什么。,,,,,"Strange people, flowers...{br}Sometimes I really don't understand what they're talking about."
|
||||||
c01_s07_钱碗,碗里只有一枚铜钱。,,,,,There's only one copper coin in the bowl.
|
c01_s07_钱碗,碗里只有一枚铜钱。,,,,,There's only one copper coin in the bowl.
|
||||||
c01_s07_获得报纸,这是什么?,,,,,What is this?
|
c01_s07_获得报纸,这是什么?,,,,,What is this?
|
||||||
c01_s07_书店展柜,院长说,读一百本书,就可以成为无所不能的大人。{br}如果我再大一些,没准可以求店长把我留下,我会干很多活,也能吃苦...,,,,,"The director said that reading a hundred books would make me an all-capable adult.{br}If I were a bit older, maybe I could ask the shop owner to keep me. I'd work hard and endure hardship..."
|
c01_s07_书店展柜,院长说,读一百本书,就可以成为无所不能的大人。{br}如果我再大一些,没准可以求店长把我留下,我会干很多活,也能吃苦...,,,,,"The director said that reading a hundred books would make me an all-capable adult.{br}If I were a bit older, maybe I could ask the shop owner to keep me. I'd work hard and endure hardship..."
|
||||||
c01_s08_书架游戏完成,这些书都被老鼠啃坏了,连木头架子都没放过。,,,,,"These books have all been gnawed by mice, even the wooden shelves weren't spared."
|
c01_s08_书架游戏完成,?!{br}刚才那是什么?,,,,,?!{br}What was that just now?
|
||||||
|
c01_s08_书架游戏恢复记忆,...{br}这是...我之前工作的地方。{br}...{br}现在老板不在了,我也该走了...,,,,,"...{br}This is... where I used to work.{br}...{br}Now that the boss is gone, I should leave too..."
|
||||||
c01_s08_获得袁大头后,工钱还在老地方。,,,,,The wages are still in the usual place.
|
c01_s08_获得袁大头后,工钱还在老地方。,,,,,The wages are still in the usual place.
|
||||||
c02_海报_剪辫子侦探,剪辫悬梁上侦探奇闻,,,,,Detective Tales of the Queue-Cutting Mystery
|
c02_海报_剪辫子侦探,剪辫悬梁上侦探奇闻,,,,,Detective Tales of the Queue-Cutting Mystery
|
||||||
c02_海报_戏法班,朱连魁全班戏法——「各有幻女...演技新奇」,,,,,Zhu Liankui's Magic Troupe—'Each with enchanting women... performances most novel'
|
c02_海报_戏法班,朱连魁全班戏法——「各有幻女...演技新奇」,,,,,Zhu Liankui's Magic Troupe—'Each with enchanting women... performances most novel'
|
||||||
|
|
@ -204,9 +204,9 @@
|
|||||||
~ Notes_c01
|
~ Notes_c01
|
||||||
# c01-s05 院长房间
|
# c01-s05 院长房间
|
||||||
这是鸡毛掸子吗? [ID:c01_鸡毛掸子]
|
这是鸡毛掸子吗? [ID:c01_鸡毛掸子]
|
||||||
桌上放着一本《圣经》。{br}「得著生命的,將要失喪生命...」 [ID:c01_院长书桌]
|
桌上放着一本《圣经》。{br}「凡要救自己生命的,必丧掉生命...」 [ID:c01_院长书桌]
|
||||||
这本书已经看过了。{br}...那些句子是什么意思呢? [ID:c01_院长床]
|
这本书已经看过了。{br}...那些句子是什么意思呢? [ID:c01_院长床]
|
||||||
这西洋钟没坏的时候,走针会咔哒、咔哒地响...{br}停在未时一刻不动了。 [ID:c01_院长座钟]
|
咦?这西洋钟为什么倒着走? [ID:c01_院长座钟]
|
||||||
哇啊,这张洋相片要掉下来了!{br}我得做点什么... [ID:c01_倾斜的洋相片]
|
哇啊,这张洋相片要掉下来了!{br}我得做点什么... [ID:c01_倾斜的洋相片]
|
||||||
这是院长的儿子吗? [ID:c01_摆正的洋相片]
|
这是院长的儿子吗? [ID:c01_摆正的洋相片]
|
||||||
# c01-s06 院子
|
# c01-s06 院子
|
||||||
@ -214,13 +214,14 @@
|
|||||||
这是其他小朋友的房间 [ID:c01_s06_小朋友房间]
|
这是其他小朋友的房间 [ID:c01_s06_小朋友房间]
|
||||||
# 院子里四个小孩交谈结束后
|
# 院子里四个小孩交谈结束后
|
||||||
墙上的画看起来好熟悉。{br}过去问问看吧,没准他们几个知道些什么。 [ID:c01_s06_熟悉的墙画]
|
墙上的画看起来好熟悉。{br}过去问问看吧,没准他们几个知道些什么。 [ID:c01_s06_熟悉的墙画]
|
||||||
怪人、花、门...{br}他在找什么东西,或是什么人? [ID:c01_s06_四小孩对话结束]
|
怪人、花...{br}有时候真搞不懂他们在说些什么。 [ID:c01_s06_四小孩对话结束]
|
||||||
# c01-s07 书店外
|
# c01-s07 书店外
|
||||||
碗里只有一枚铜钱。 [ID:c01_s07_钱碗]
|
碗里只有一枚铜钱。 [ID:c01_s07_钱碗]
|
||||||
这是什么? [ID:c01_s07_获得报纸]
|
这是什么? [ID:c01_s07_获得报纸]
|
||||||
院长说,读一百本书,就可以成为无所不能的大人。{br}如果我再大一些,没准可以求店长把我留下,我会干很多活,也能吃苦... [ID:c01_s07_书店展柜]
|
院长说,读一百本书,就可以成为无所不能的大人。{br}如果我再大一些,没准可以求店长把我留下,我会干很多活,也能吃苦... [ID:c01_s07_书店展柜]
|
||||||
# c01-s08 书店
|
# c01-s08 书店
|
||||||
这些书都被老鼠啃坏了,连木头架子都没放过。 [ID:c01_s08_书架游戏完成]
|
?!{br}刚才那是什么? [ID:c01_s08_书架游戏完成]
|
||||||
|
...{br}这是...我之前工作的地方。{br}...{br}现在老板不在了,我也该走了... [ID:c01_s08_书架游戏恢复记忆]
|
||||||
工钱还在老地方。 [ID:c01_s08_获得袁大头后]
|
工钱还在老地方。 [ID:c01_s08_获得袁大头后]
|
||||||
=> END
|
=> END
|
||||||
|
|
||||||
|
@ -9,7 +9,7 @@ custom_features=""
|
|||||||
export_filter="all_resources"
|
export_filter="all_resources"
|
||||||
include_filter=""
|
include_filter=""
|
||||||
exclude_filter=""
|
exclude_filter=""
|
||||||
export_path="../demo0.5.2/xiandie.exe"
|
export_path="../demo0.5.3/xiandie.exe"
|
||||||
patches=PackedStringArray()
|
patches=PackedStringArray()
|
||||||
encryption_include_filters=""
|
encryption_include_filters=""
|
||||||
encryption_exclude_filters=""
|
encryption_exclude_filters=""
|
||||||
@ -37,8 +37,8 @@ application/modify_resources=true
|
|||||||
application/icon="uid://cxgwspjv16j7m"
|
application/icon="uid://cxgwspjv16j7m"
|
||||||
application/console_wrapper_icon="uid://cxgwspjv16j7m"
|
application/console_wrapper_icon="uid://cxgwspjv16j7m"
|
||||||
application/icon_interpolation=4
|
application/icon_interpolation=4
|
||||||
application/file_version="0.5.2.0"
|
application/file_version="0.5.3.0"
|
||||||
application/product_version="0.5.2.0"
|
application/product_version="0.5.3.0"
|
||||||
application/company_name="包包丁"
|
application/company_name="包包丁"
|
||||||
application/product_name="衔蝶"
|
application/product_name="衔蝶"
|
||||||
application/file_description="衔蝶"
|
application/file_description="衔蝶"
|
||||||
@ -97,8 +97,8 @@ application/icon_interpolation=4
|
|||||||
application/bundle_identifier="com.baobaoding.xiandie"
|
application/bundle_identifier="com.baobaoding.xiandie"
|
||||||
application/signature=""
|
application/signature=""
|
||||||
application/app_category="Games"
|
application/app_category="Games"
|
||||||
application/short_version="0.2.0"
|
application/short_version="0.5.3"
|
||||||
application/version="0.2.0"
|
application/version="0.5.3"
|
||||||
application/copyright="爆爆叮"
|
application/copyright="爆爆叮"
|
||||||
application/copyright_localized={}
|
application/copyright_localized={}
|
||||||
application/min_macos_version_x86_64="10.12"
|
application/min_macos_version_x86_64="10.12"
|
||||||
@ -586,7 +586,7 @@ storyboard/custom_bg_color=Color(0, 0, 0, 1)
|
|||||||
name="Android"
|
name="Android"
|
||||||
platform="Android"
|
platform="Android"
|
||||||
runnable=true
|
runnable=true
|
||||||
advanced_options=false
|
advanced_options=true
|
||||||
dedicated_server=false
|
dedicated_server=false
|
||||||
custom_features=""
|
custom_features=""
|
||||||
export_filter="all_resources"
|
export_filter="all_resources"
|
||||||
|
@ -20,10 +20,12 @@ const RES_FILE_FORMAT = ".tres"
|
|||||||
const CANVAS_LAYER_SETTINGS = 30
|
const CANVAS_LAYER_SETTINGS = 30
|
||||||
# note
|
# note
|
||||||
const CANVAS_LAYER_NOTE = 25
|
const CANVAS_LAYER_NOTE = 25
|
||||||
# dialog
|
|
||||||
const CANVAS_LAYER_DIALOG = 24
|
|
||||||
const CANVAS_LAYER_MEM_ITEM = 23
|
const CANVAS_LAYER_MEM_ITEM = 23
|
||||||
const CANVAS_LAYER_UX_PANEL = 22
|
const CANVAS_LAYER_UX_PANEL = 22
|
||||||
|
# dialog 在游戏场景中使用 CANVAS_LAYER_DIALOG
|
||||||
|
# 在回忆中使用 CANVAS_LAYER_DIALOG_MEM
|
||||||
|
const CANVAS_LAYER_DIALOG_MEM = 29
|
||||||
|
const CANVAS_LAYER_DIALOG = 22
|
||||||
# main 场景的 UI 层(prop hud、上下mask、notification)
|
# main 场景的 UI 层(prop hud、上下mask、notification)
|
||||||
const CANVAS_LAYER_UI = 21
|
const CANVAS_LAYER_UI = 21
|
||||||
# 道具 inspector(prop/local)
|
# 道具 inspector(prop/local)
|
||||||
@ -40,6 +42,8 @@ const CANVAS_LAYER_LITTLE_GAME = 5
|
|||||||
const CANVAS_LAYER_FG = 2
|
const CANVAS_LAYER_FG = 2
|
||||||
|
|
||||||
const DIALOG_IGNORE_INPUT = "ignore_input"
|
const DIALOG_IGNORE_INPUT = "ignore_input"
|
||||||
|
# memory layer: 30
|
||||||
|
const DIALOG_MEM_LAYER = "mem_layer"
|
||||||
|
|
||||||
const CHARACTER_COLOR_MAP = {
|
const CHARACTER_COLOR_MAP = {
|
||||||
"default": Color.LIGHT_SEA_GREEN,
|
"default": Color.LIGHT_SEA_GREEN,
|
||||||
|
@ -418,7 +418,8 @@ func quit_game() -> void:
|
|||||||
# DialogueManager.dialogue_ended.emit(null)
|
# DialogueManager.dialogue_ended.emit(null)
|
||||||
# get_player().os_finished.emit("")
|
# get_player().os_finished.emit("")
|
||||||
# get_player().animation_finished.emit()
|
# get_player().animation_finished.emit()
|
||||||
|
# 首先取消 paused
|
||||||
|
get_tree().paused = false
|
||||||
ArchiveManager.save_all()
|
ArchiveManager.save_all()
|
||||||
var ground_loader = get_ground_loader() as GroundLoader
|
var ground_loader = get_ground_loader() as GroundLoader
|
||||||
if ground_loader:
|
if ground_loader:
|
||||||
|
@ -153,6 +153,8 @@ func _notification(what: int) -> void:
|
|||||||
func start(
|
func start(
|
||||||
dialogue_resource: DialogueResource, title: String, extra_game_states: Array = []
|
dialogue_resource: DialogueResource, title: String, extra_game_states: Array = []
|
||||||
) -> void:
|
) -> void:
|
||||||
|
if extra_game_states.has(GlobalConfig.DIALOG_MEM_LAYER):
|
||||||
|
layer = GlobalConfig.CANVAS_LAYER_DIALOG_MEM
|
||||||
temporary_game_states = [self] + extra_game_states
|
temporary_game_states = [self] + extra_game_states
|
||||||
is_waiting_for_input = false
|
is_waiting_for_input = false
|
||||||
resource = dialogue_resource
|
resource = dialogue_resource
|
||||||
|
@ -10,7 +10,7 @@ func _ready() -> void:
|
|||||||
var tween: Tween
|
var tween: Tween
|
||||||
|
|
||||||
|
|
||||||
func dizzy(duration := 3.5, intensity := 1.5):
|
func dizzy(duration := 3.5, intensity := 1.5) -> void:
|
||||||
if duration < 0.6:
|
if duration < 0.6:
|
||||||
return
|
return
|
||||||
if tween and tween.is_valid():
|
if tween and tween.is_valid():
|
||||||
|
@ -2,10 +2,15 @@
|
|||||||
class_name Npc2D extends AnimatedSprite2D
|
class_name Npc2D extends AnimatedSprite2D
|
||||||
|
|
||||||
signal interacted
|
signal interacted
|
||||||
# 在 unlock player 之前发射
|
signal talk_finished # 在 unlock player 之前发射
|
||||||
signal talk_finished
|
|
||||||
|
|
||||||
# <0 means no walk to edge
|
# 常量定义
|
||||||
|
const SPEAKING_SIGN_FADE_DURATION := 0.3
|
||||||
|
const SPEAKING_SCALE_MULTIPLIER := 1.3
|
||||||
|
|
||||||
|
enum SpeakingSignMode { HIDDEN = 0, SILENT = 1, SPEAKING = 2 }
|
||||||
|
|
||||||
|
# 导出变量
|
||||||
@export var snap_to_edge := true
|
@export var snap_to_edge := true
|
||||||
@export var walk_to_edge_width := 25.0
|
@export var walk_to_edge_width := 25.0
|
||||||
@export var action_key := 4
|
@export var action_key := 4
|
||||||
@ -14,40 +19,46 @@ signal talk_finished
|
|||||||
enabled = val
|
enabled = val
|
||||||
if is_node_ready():
|
if is_node_ready():
|
||||||
_align_signs_status()
|
_align_signs_status()
|
||||||
|
|
||||||
@export var sign_mark_height := 10.0:
|
@export var sign_mark_height := 10.0:
|
||||||
set(val):
|
set(val):
|
||||||
sign_mark_height = val
|
sign_mark_height = val
|
||||||
if is_node_ready():
|
if is_node_ready() and sign_mark:
|
||||||
sign_mark.sign_mark_offset.y = -sign_mark_height
|
sign_mark.sign_mark_offset.y = -sign_mark_height
|
||||||
|
|
||||||
@export var speaking_sign_height := 60.0:
|
@export var speaking_sign_height := 60.0:
|
||||||
set(val):
|
set(val):
|
||||||
speaking_sign_height = val
|
speaking_sign_height = val
|
||||||
if is_node_ready():
|
if is_node_ready() and speaking_sign:
|
||||||
speaking_sign.position.y = -speaking_sign_height
|
speaking_sign.position.y = -speaking_sign_height
|
||||||
|
|
||||||
@export var sign_x_offset := 0.0:
|
@export var sign_x_offset := 0.0:
|
||||||
set(val):
|
set(val):
|
||||||
sign_x_offset = val
|
sign_x_offset = val
|
||||||
if is_node_ready():
|
if is_node_ready():
|
||||||
speaking_sign.position.x = sign_x_offset
|
_update_sign_x_positions()
|
||||||
sign_mark.position.x = sign_x_offset
|
|
||||||
@export var collision_width_and_x := Vector2(20.0, 0):
|
@export var collision_width_and_x := Vector2(20.0, 0):
|
||||||
set(val):
|
set(val):
|
||||||
collision_width_and_x = val
|
collision_width_and_x = val
|
||||||
if is_node_ready():
|
if is_node_ready():
|
||||||
var shape = area2d.get_node("CollisionShape2D").shape
|
_update_collision_shape()
|
||||||
shape.size.x = collision_width_and_x.x
|
|
||||||
area2d.position.x = collision_width_and_x.y
|
# 节点引用
|
||||||
@onready var speaking_animation = %SpeakingAnimationPlayer
|
@onready var speaking_animation = %SpeakingAnimationPlayer
|
||||||
@onready var speaking_sign = %SpeakingSign2D as Node2D
|
@onready var speaking_sign = %SpeakingSign2D as Node2D
|
||||||
@onready var sign_mark = %Sign as Sign
|
@onready var sign_mark = %Sign as Sign
|
||||||
@onready var sign_snapper = %SignSnapper as SignSnapper
|
@onready var sign_snapper = %SignSnapper as SignSnapper
|
||||||
@onready var area2d = %Area2D as Area2D
|
@onready var area2d = %Area2D as Area2D
|
||||||
|
|
||||||
|
# 内部变量
|
||||||
var ground_archive: GroundArchive
|
var ground_archive: GroundArchive
|
||||||
# 尝试互动的次数
|
|
||||||
var icount: int:
|
var icount: int:
|
||||||
set(val):
|
set(val):
|
||||||
|
if icount == val:
|
||||||
|
return
|
||||||
icount = val
|
icount = val
|
||||||
|
if ground_archive:
|
||||||
ground_archive.set_pair(name, "icount", val)
|
ground_archive.set_pair(name, "icount", val)
|
||||||
_align_signs_status()
|
_align_signs_status()
|
||||||
|
|
||||||
@ -56,107 +67,248 @@ var dialogue_res = preload("res://asset/dialogue/npc.dialogue")
|
|||||||
|
|
||||||
var base_scale := Vector2.ONE
|
var base_scale := Vector2.ONE
|
||||||
var base_mod := Color.WHITE_SMOKE
|
var base_mod := Color.WHITE_SMOKE
|
||||||
|
|
||||||
var speaking_sign_tween: Tween
|
var speaking_sign_tween: Tween
|
||||||
|
var speaking_sign_mode := SpeakingSignMode.HIDDEN:
|
||||||
# 0 hide; 1 silent; 2 speaking
|
|
||||||
var speaking_sign_mode := 0:
|
|
||||||
set(val):
|
set(val):
|
||||||
if speaking_sign_mode != val:
|
if speaking_sign_mode == val:
|
||||||
|
return
|
||||||
speaking_sign_mode = val
|
speaking_sign_mode = val
|
||||||
if speaking_sign_tween and speaking_sign_tween.is_valid():
|
_update_speaking_sign_mode()
|
||||||
speaking_sign_tween.kill()
|
|
||||||
speaking_sign_tween = create_tween()
|
# 强制播放状态管理
|
||||||
if val == 0:
|
var is_hooked := false
|
||||||
speaking_sign_tween.tween_property(speaking_sign, "modulate:a", 0.0, 0.3)
|
var hook_id := 0 # 用于追踪hook会话,避免异步问题
|
||||||
speaking_animation.stop()
|
|
||||||
elif val == 1:
|
|
||||||
speaking_sign_tween.tween_property(speaking_sign, "modulate", base_mod, 0.3)
|
|
||||||
speaking_sign_tween.parallel().tween_property(
|
|
||||||
speaking_sign, "scale", base_scale, 0.3
|
|
||||||
)
|
|
||||||
speaking_animation.play("speaking")
|
|
||||||
elif val == 2:
|
|
||||||
speaking_sign_tween.tween_property(speaking_sign, "modulate", Color.WHITE, 0.3)
|
|
||||||
speaking_sign_tween.parallel().tween_property(
|
|
||||||
speaking_sign, "scale", base_scale * 1.3, 0.3
|
|
||||||
)
|
|
||||||
speaking_animation.play("speaking")
|
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
# sign position
|
_initialize_components()
|
||||||
|
|
||||||
|
if Engine.is_editor_hint():
|
||||||
|
_setup_editor_preview()
|
||||||
|
return
|
||||||
|
|
||||||
|
_setup_game_mode()
|
||||||
|
_align_signs_status()
|
||||||
|
|
||||||
|
|
||||||
|
func _initialize_components() -> void:
|
||||||
|
# 设置标记位置
|
||||||
|
if sign_mark:
|
||||||
sign_mark.sign_mark_offset.y = -sign_mark_height
|
sign_mark.sign_mark_offset.y = -sign_mark_height
|
||||||
speaking_sign.position.y = -speaking_sign_height
|
|
||||||
sign_mark.position.x = sign_x_offset
|
sign_mark.position.x = sign_x_offset
|
||||||
|
|
||||||
|
if speaking_sign:
|
||||||
|
speaking_sign.position.y = -speaking_sign_height
|
||||||
speaking_sign.position.x = sign_x_offset
|
speaking_sign.position.x = sign_x_offset
|
||||||
# collisiong shape
|
|
||||||
var shape = area2d.get_node("CollisionShape2D").shape
|
|
||||||
shape.size.x = collision_width_and_x.x
|
|
||||||
area2d.position.x = collision_width_and_x.y
|
|
||||||
sign_snapper.action_on_arrived = action_key
|
|
||||||
sign_snapper.radius = walk_to_edge_width
|
|
||||||
sign_snapper.enabled = snap_to_edge
|
|
||||||
# 设置 speaking_sign 默认值
|
|
||||||
base_scale = speaking_sign.scale
|
base_scale = speaking_sign.scale
|
||||||
base_mod = speaking_sign.modulate
|
base_mod = speaking_sign.modulate
|
||||||
speaking_sign.modulate.a = 0.0
|
speaking_sign.modulate.a = 0.0
|
||||||
if Engine.is_editor_hint():
|
|
||||||
# editor 下都显示
|
# 设置碰撞形状
|
||||||
|
_update_collision_shape()
|
||||||
|
|
||||||
|
# 配置 sign_snapper
|
||||||
|
if sign_snapper:
|
||||||
|
sign_snapper.action_on_arrived = action_key
|
||||||
|
sign_snapper.radius = walk_to_edge_width
|
||||||
|
sign_snapper.enabled = snap_to_edge
|
||||||
|
|
||||||
|
|
||||||
|
func _setup_editor_preview() -> void:
|
||||||
|
if speaking_sign:
|
||||||
speaking_sign.visible = true
|
speaking_sign.visible = true
|
||||||
speaking_sign.modulate.a = 1.0
|
speaking_sign.modulate.a = 1.0
|
||||||
speaking_sign.get_node("Sprite2D").position.x = -60.0
|
var sprite = speaking_sign.get_node_or_null("Sprite2D")
|
||||||
speaking_sign.get_node("Sprite2D").frame = 2
|
if sprite:
|
||||||
|
sprite.position.x = -60.0
|
||||||
|
sprite.frame = 2
|
||||||
|
|
||||||
|
if sign_mark:
|
||||||
sign_mark.display_sign = true
|
sign_mark.display_sign = true
|
||||||
return
|
|
||||||
# setup default value
|
|
||||||
|
func _setup_game_mode() -> void:
|
||||||
|
# 获取存档数据
|
||||||
ground_archive = ArchiveManager.archive.ground_archive()
|
ground_archive = ArchiveManager.archive.ground_archive()
|
||||||
icount = ground_archive.get_value(name, "icount", 0)
|
icount = ground_archive.get_value(name, "icount", 0)
|
||||||
if snap_to_edge:
|
|
||||||
|
# 连接信号
|
||||||
|
if snap_to_edge and sign_snapper:
|
||||||
sign_snapper.arrived.connect(_on_interacted)
|
sign_snapper.arrived.connect(_on_interacted)
|
||||||
else:
|
elif sign_mark:
|
||||||
sign_mark.interacted.connect(_on_interacted)
|
sign_mark.interacted.connect(_on_interacted)
|
||||||
# sign_mark.cancel.connect(_stop_speaking)
|
|
||||||
|
if sign_mark:
|
||||||
sign_mark.toggle_active.connect(_on_toggle_active)
|
sign_mark.toggle_active.connect(_on_toggle_active)
|
||||||
|
|
||||||
visibility_changed.connect(_on_visibility_changed)
|
visibility_changed.connect(_on_visibility_changed)
|
||||||
|
|
||||||
|
# 开始动画
|
||||||
if sprite_frames and animation:
|
if sprite_frames and animation:
|
||||||
play()
|
play()
|
||||||
|
|
||||||
|
|
||||||
|
func _update_sign_x_positions() -> void:
|
||||||
|
if speaking_sign:
|
||||||
|
speaking_sign.position.x = sign_x_offset
|
||||||
|
if sign_mark:
|
||||||
|
sign_mark.position.x = sign_x_offset
|
||||||
|
|
||||||
|
|
||||||
|
func _update_collision_shape() -> void:
|
||||||
|
if not area2d:
|
||||||
|
return
|
||||||
|
|
||||||
|
var collision_shape = area2d.get_node_or_null("CollisionShape2D")
|
||||||
|
if collision_shape and collision_shape.shape:
|
||||||
|
collision_shape.shape.size.x = collision_width_and_x.x
|
||||||
|
area2d.position.x = collision_width_and_x.y
|
||||||
|
|
||||||
|
|
||||||
|
func _update_speaking_sign_mode() -> void:
|
||||||
|
if not speaking_sign:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 清理之前的补间动画
|
||||||
|
if speaking_sign_tween and speaking_sign_tween.is_valid():
|
||||||
|
speaking_sign_tween.kill()
|
||||||
|
|
||||||
|
speaking_sign_tween = create_tween()
|
||||||
|
|
||||||
|
match speaking_sign_mode:
|
||||||
|
SpeakingSignMode.HIDDEN:
|
||||||
|
speaking_sign_tween.tween_property(
|
||||||
|
speaking_sign, "modulate:a", 0.0, SPEAKING_SIGN_FADE_DURATION
|
||||||
|
)
|
||||||
|
if speaking_animation:
|
||||||
|
speaking_animation.stop()
|
||||||
|
|
||||||
|
SpeakingSignMode.SILENT:
|
||||||
|
speaking_sign_tween.tween_property(
|
||||||
|
speaking_sign, "modulate", base_mod, SPEAKING_SIGN_FADE_DURATION
|
||||||
|
)
|
||||||
|
speaking_sign_tween.parallel().tween_property(
|
||||||
|
speaking_sign, "scale", base_scale, SPEAKING_SIGN_FADE_DURATION
|
||||||
|
)
|
||||||
|
if speaking_animation:
|
||||||
|
speaking_animation.play("speaking")
|
||||||
|
|
||||||
|
SpeakingSignMode.SPEAKING:
|
||||||
|
speaking_sign_tween.tween_property(
|
||||||
|
speaking_sign, "modulate", Color.WHITE, SPEAKING_SIGN_FADE_DURATION
|
||||||
|
)
|
||||||
|
speaking_sign_tween.parallel().tween_property(
|
||||||
|
speaking_sign,
|
||||||
|
"scale",
|
||||||
|
base_scale * SPEAKING_SCALE_MULTIPLIER,
|
||||||
|
SPEAKING_SIGN_FADE_DURATION
|
||||||
|
)
|
||||||
|
if speaking_animation:
|
||||||
|
speaking_animation.play("speaking")
|
||||||
|
|
||||||
|
|
||||||
func _on_visibility_changed() -> void:
|
func _on_visibility_changed() -> void:
|
||||||
_align_signs_status()
|
_align_signs_status()
|
||||||
|
|
||||||
|
|
||||||
func _align_signs_status():
|
func _align_signs_status() -> void:
|
||||||
sign_mark.enabled = enabled and is_visible_in_tree()
|
if not is_node_ready():
|
||||||
|
return
|
||||||
|
var is_active = enabled and is_visible_in_tree()
|
||||||
|
if sign_mark:
|
||||||
|
sign_mark.enabled = is_active
|
||||||
sign_mark.display_sign = icount == 0
|
sign_mark.display_sign = icount == 0
|
||||||
speaking_sign.visible = enabled and icount > 0
|
if speaking_sign:
|
||||||
|
speaking_sign.visible = enabled and (icount > 0 or is_hooked)
|
||||||
|
|
||||||
|
|
||||||
func _on_toggle_active(activated: bool) -> void:
|
func _on_toggle_active(activated: bool) -> void:
|
||||||
|
# 如果处于hook状态,不响应正常的toggle
|
||||||
|
if is_hooked:
|
||||||
|
return
|
||||||
if not activated:
|
if not activated:
|
||||||
speaking_sign_mode = 0
|
speaking_sign_mode = SpeakingSignMode.HIDDEN
|
||||||
elif speaking_sign_mode == 0:
|
elif speaking_sign_mode == SpeakingSignMode.HIDDEN:
|
||||||
speaking_sign_mode = 1
|
speaking_sign_mode = SpeakingSignMode.SILENT
|
||||||
|
|
||||||
|
|
||||||
func _on_interacted() -> void:
|
func _on_interacted() -> void:
|
||||||
# play dialogue
|
if not dialogue_title:
|
||||||
if dialogue_title:
|
return
|
||||||
|
|
||||||
|
# 如果正在hook播放,先取消hook
|
||||||
|
if is_hooked:
|
||||||
|
_cancel_hook()
|
||||||
|
|
||||||
SceneManager.lock_player(0, action_key)
|
SceneManager.lock_player(0, action_key)
|
||||||
icount += 1
|
icount += 1
|
||||||
|
|
||||||
|
if ground_archive:
|
||||||
ground_archive.set_pair(name, "icount", icount)
|
ground_archive.set_pair(name, "icount", icount)
|
||||||
|
|
||||||
DialogueManager.show_dialogue_balloon(dialogue_res, dialogue_title)
|
DialogueManager.show_dialogue_balloon(dialogue_res, dialogue_title)
|
||||||
interacted.emit()
|
interacted.emit()
|
||||||
var out_of_range = speaking_sign_mode == 0
|
|
||||||
speaking_sign_mode = 2
|
var was_out_of_range = speaking_sign_mode == SpeakingSignMode.HIDDEN
|
||||||
|
speaking_sign_mode = SpeakingSignMode.SPEAKING
|
||||||
|
|
||||||
await DialogueManager.dialogue_ended
|
await DialogueManager.dialogue_ended
|
||||||
speaking_sign_mode = 0 if out_of_range else 1
|
|
||||||
# 在 unlock 之前发射
|
speaking_sign_mode = SpeakingSignMode.HIDDEN if was_out_of_range else SpeakingSignMode.SILENT
|
||||||
talk_finished.emit()
|
talk_finished.emit()
|
||||||
SceneManager.unlock_player()
|
SceneManager.unlock_player()
|
||||||
|
|
||||||
|
|
||||||
|
# 新增:强制播放说话动画
|
||||||
|
func hook_speaking() -> int:
|
||||||
|
# 强制显示说话气泡动画
|
||||||
|
# 返回值:hook会话ID,用于验证unhook的有效性
|
||||||
|
is_hooked = true
|
||||||
|
hook_id += 1
|
||||||
|
var current_hook_id = hook_id
|
||||||
|
|
||||||
|
# 确保speaking_sign可见
|
||||||
|
if speaking_sign and not speaking_sign.visible:
|
||||||
|
speaking_sign.visible = true
|
||||||
|
|
||||||
|
# 保存当前状态并切换到说话模式
|
||||||
|
speaking_sign_mode = SpeakingSignMode.SPEAKING
|
||||||
|
|
||||||
|
return current_hook_id
|
||||||
|
|
||||||
|
|
||||||
|
# 新增:退出强制播放
|
||||||
|
func unhook_speaking(session_id: int = -1) -> void:
|
||||||
|
# 退出强制播放模式
|
||||||
|
# 参数:
|
||||||
|
# session_id: hook会话ID,如果不匹配则忽略此次unhook
|
||||||
|
# 如果已经不在hook状态,或session_id不匹配,则忽略
|
||||||
|
if not is_hooked or (session_id != -1 and session_id != hook_id):
|
||||||
|
return
|
||||||
|
_cancel_hook()
|
||||||
|
|
||||||
|
|
||||||
|
# 新增:内部取消hook的方法
|
||||||
|
func _cancel_hook() -> void:
|
||||||
|
# 内部使用的取消hook方法
|
||||||
|
is_hooked = false
|
||||||
|
|
||||||
|
# 恢复到适当的状态
|
||||||
|
if sign_mark and sign_mark.activated:
|
||||||
|
speaking_sign_mode = SpeakingSignMode.SILENT
|
||||||
|
else:
|
||||||
|
speaking_sign_mode = SpeakingSignMode.HIDDEN
|
||||||
|
|
||||||
|
# 重新对齐显示状态
|
||||||
|
_align_signs_status()
|
||||||
|
|
||||||
|
|
||||||
|
# 新增:检查是否正在hook播放
|
||||||
|
func is_hook_speaking() -> bool:
|
||||||
|
"""返回当前是否处于强制播放状态"""
|
||||||
|
return is_hooked
|
||||||
|
|
||||||
|
|
||||||
func _get(property: StringName) -> Variant:
|
func _get(property: StringName) -> Variant:
|
||||||
if property == "dialogue_title":
|
if property == "dialogue_title":
|
||||||
return dialogue_title
|
return dialogue_title
|
||||||
@ -172,8 +324,9 @@ func _set(property: StringName, value: Variant) -> bool:
|
|||||||
|
|
||||||
func _get_property_list() -> Array[Dictionary]:
|
func _get_property_list() -> Array[Dictionary]:
|
||||||
var hint_str = ""
|
var hint_str = ""
|
||||||
if Engine.is_editor_hint():
|
if Engine.is_editor_hint() and dialogue_res:
|
||||||
hint_str = ",".join(dialogue_res.get_ordered_titles())
|
hint_str = ",".join(dialogue_res.get_ordered_titles())
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{
|
{
|
||||||
"name": "dialogue_title",
|
"name": "dialogue_title",
|
||||||
|
@ -94,8 +94,10 @@ func pre_game_intro():
|
|||||||
var p = $"../DeployLayer/四小孩画鬼差的对话ambush/FocusPoint"
|
var p = $"../DeployLayer/四小孩画鬼差的对话ambush/FocusPoint"
|
||||||
camera.focus_node(p, 3.0)
|
camera.focus_node(p, 3.0)
|
||||||
await Util.wait(2.0)
|
await Util.wait(2.0)
|
||||||
|
_hook_npc3_speaking()
|
||||||
DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_四个小孩画鬼差的对话")
|
DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_四个小孩画鬼差的对话")
|
||||||
await DialogueManager.dialogue_ended
|
await DialogueManager.dialogue_ended
|
||||||
|
_unhook_npc3_speaking()
|
||||||
# 重置镜头
|
# 重置镜头
|
||||||
SceneManager.focus_player_and_reset_zoom(2.5)
|
SceneManager.focus_player_and_reset_zoom(2.5)
|
||||||
await Util.wait(2.5)
|
await Util.wait(2.5)
|
||||||
@ -123,14 +125,17 @@ func game_intro() -> void:
|
|||||||
# DialogueManager.show_dialogue_balloon(
|
# DialogueManager.show_dialogue_balloon(
|
||||||
# dialogue_c01, "c01_s06_谈论鬼差与猫鼠游戏", [GlobalConfig.DIALOG_IGNORE_INPUT]
|
# dialogue_c01, "c01_s06_谈论鬼差与猫鼠游戏", [GlobalConfig.DIALOG_IGNORE_INPUT]
|
||||||
# )
|
# )
|
||||||
|
_hook_npc3_speaking()
|
||||||
DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_谈论鬼差与猫鼠游戏")
|
DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_谈论鬼差与猫鼠游戏")
|
||||||
DialogueManager.dialogue_ended.connect(_game_counting_down, CONNECT_ONE_SHOT)
|
await DialogueManager.dialogue_ended
|
||||||
|
_game_counting_down()
|
||||||
|
|
||||||
|
|
||||||
func _game_counting_down(_res = null):
|
func _game_counting_down(_res = null):
|
||||||
$"Sfx猫鼠游戏".play()
|
$"Sfx猫鼠游戏".play()
|
||||||
DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_猫鼠游戏BGM开始")
|
DialogueManager.show_dialogue_balloon(dialogue_c01, "c01_s06_猫鼠游戏BGM开始")
|
||||||
await DialogueManager.dialogue_ended
|
await DialogueManager.dialogue_ended
|
||||||
|
_unhook_npc3_speaking()
|
||||||
# 重置镜头
|
# 重置镜头
|
||||||
SceneManager.focus_player_and_reset_zoom(2.5)
|
SceneManager.focus_player_and_reset_zoom(2.5)
|
||||||
SceneManager.release_player()
|
SceneManager.release_player()
|
||||||
@ -145,6 +150,14 @@ func _game_counting_down(_res = null):
|
|||||||
cat.get_node("猫咪嘶吼音效").play()
|
cat.get_node("猫咪嘶吼音效").play()
|
||||||
|
|
||||||
|
|
||||||
|
func _hook_npc3_speaking(_res = null) -> void:
|
||||||
|
game_kid.get_node("Npc对话3").hook_speaking()
|
||||||
|
|
||||||
|
|
||||||
|
func _unhook_npc3_speaking(_res = null) -> void:
|
||||||
|
game_kid.get_node("Npc对话3").unhook_speaking()
|
||||||
|
|
||||||
|
|
||||||
# 玩家与三个小孩的互动计数
|
# 玩家与三个小孩的互动计数
|
||||||
func _on_talked(id: int):
|
func _on_talked(id: int):
|
||||||
#talk count
|
#talk count
|
||||||
|
@ -71,7 +71,7 @@ func _knock_door():
|
|||||||
await Util.wait(2.2)
|
await Util.wait(2.2)
|
||||||
$"敲门音效".play()
|
$"敲门音效".play()
|
||||||
await Util.wait(1.2)
|
await Util.wait(1.2)
|
||||||
var stream = preload("res://asset/audio/sfx/交互/序章/03_书店外黄昏_开门.ogg")
|
var stream = preload("uid://ehgd455wq8to")
|
||||||
AudioManager.play_sfx(stream)
|
AudioManager.play_sfx(stream)
|
||||||
|
|
||||||
|
|
||||||
@ -95,3 +95,16 @@ func seller_interacted():
|
|||||||
# 播放获得动画
|
# 播放获得动画
|
||||||
SceneManager.enable_prop_item("prop_信碎片2")
|
SceneManager.enable_prop_item("prop_信碎片2")
|
||||||
SceneManager.release_player()
|
SceneManager.release_player()
|
||||||
|
|
||||||
|
|
||||||
|
func jiandu_dialog_triggered() -> void:
|
||||||
|
var jiandu = $"../DeployLayer/举碗小孩/Npc监督小孩"
|
||||||
|
jiandu.hook_speaking()
|
||||||
|
SceneManager.hold_player()
|
||||||
|
DialogueManager.dialogue_ended.connect(_on_jiandu_dialog_ended, CONNECT_ONE_SHOT)
|
||||||
|
|
||||||
|
|
||||||
|
func _on_jiandu_dialog_ended(_res) -> void:
|
||||||
|
var jiandu = $"../DeployLayer/举碗小孩/Npc监督小孩"
|
||||||
|
jiandu.unhook_speaking()
|
||||||
|
SceneManager.unhold_player()
|
||||||
|
@ -203,12 +203,6 @@ sprite_frames = ExtResource("6_thm8f")
|
|||||||
animation = &"杂戏团黄昏-其余小孩"
|
animation = &"杂戏团黄昏-其余小孩"
|
||||||
autoplay = "杂戏团黄昏-其余小孩"
|
autoplay = "杂戏团黄昏-其余小孩"
|
||||||
|
|
||||||
[node name="Ambush监督小孩" parent="Ground/DeployLayer/其余小孩" instance=ExtResource("9_f61dl")]
|
|
||||||
position = Vector2(-688, 53)
|
|
||||||
cooldown_time = 0.1
|
|
||||||
lock_player_on_playing_dialogue = false
|
|
||||||
hook_dialogue_title = "c01_s07_监督小孩吉祥话"
|
|
||||||
|
|
||||||
[node name="Npc吉祥话1" parent="Ground/DeployLayer/其余小孩" instance=ExtResource("6_fw22n")]
|
[node name="Npc吉祥话1" parent="Ground/DeployLayer/其余小孩" instance=ExtResource("6_fw22n")]
|
||||||
position = Vector2(-44, 78)
|
position = Vector2(-44, 78)
|
||||||
sign_mark_height = 23.0
|
sign_mark_height = 23.0
|
||||||
@ -237,6 +231,20 @@ autoplay = "杂戏团黄昏_举碗小孩"
|
|||||||
position = Vector2(6, 57)
|
position = Vector2(6, 57)
|
||||||
note_key = "c01_s07_钱碗"
|
note_key = "c01_s07_钱碗"
|
||||||
|
|
||||||
|
[node name="Npc监督小孩" parent="Ground/DeployLayer/举碗小孩" instance=ExtResource("6_fw22n")]
|
||||||
|
position = Vector2(6, 72)
|
||||||
|
snap_to_edge = false
|
||||||
|
enabled = false
|
||||||
|
sign_mark_height = 11.0
|
||||||
|
speaking_sign_height = 54.0
|
||||||
|
|
||||||
|
[node name="Ambush监督小孩" parent="Ground/DeployLayer/举碗小孩" instance=ExtResource("9_f61dl")]
|
||||||
|
position = Vector2(-825, 53)
|
||||||
|
cooldown_time = 0.1
|
||||||
|
lock_player_on_playing_dialogue = false
|
||||||
|
hook_dialogue_title = "c01_s07_监督小孩吉祥话"
|
||||||
|
hook_method = "jiandu_dialog_triggered"
|
||||||
|
|
||||||
[node name="报童" parent="Ground/DeployLayer" index="10" instance=ExtResource("9_slaub")]
|
[node name="报童" parent="Ground/DeployLayer" index="10" instance=ExtResource("9_slaub")]
|
||||||
position = Vector2(2080, 6)
|
position = Vector2(2080, 6)
|
||||||
sprite_frames = ExtResource("6_thm8f")
|
sprite_frames = ExtResource("6_thm8f")
|
||||||
|
@ -33,6 +33,7 @@ var shelf_game_success = false
|
|||||||
var envelope_game_success = false
|
var envelope_game_success = false
|
||||||
var manager
|
var manager
|
||||||
var mice
|
var mice
|
||||||
|
var fall_off
|
||||||
|
|
||||||
|
|
||||||
func _on_ground_ready() -> void:
|
func _on_ground_ready() -> void:
|
||||||
@ -44,6 +45,7 @@ func _on_ground_ready() -> void:
|
|||||||
coin = $"../DeployLayer/Ambush银元"
|
coin = $"../DeployLayer/Ambush银元"
|
||||||
mice = $"../DeployLayer/自动跟随的老鼠"
|
mice = $"../DeployLayer/自动跟随的老鼠"
|
||||||
manager = $"../DeployLayer/老板"
|
manager = $"../DeployLayer/老板"
|
||||||
|
fall_off = $"../DeployLayer/小小蝶坠落"
|
||||||
# 首先放报纸,触发动画,领取任务
|
# 首先放报纸,触发动画,领取任务
|
||||||
if counter.interacted_times > 0:
|
if counter.interacted_times > 0:
|
||||||
ladder.enabled = true
|
ladder.enabled = true
|
||||||
@ -127,9 +129,6 @@ func _on_shelf_game_exiting() -> void:
|
|||||||
SceneManager.release_player()
|
SceneManager.release_player()
|
||||||
|
|
||||||
|
|
||||||
var fall_off
|
|
||||||
|
|
||||||
|
|
||||||
func _on_shelf_game_success() -> void:
|
func _on_shelf_game_success() -> void:
|
||||||
ArchiveManager.set_global_entry(&"c01_shelf_game_success", true)
|
ArchiveManager.set_global_entry(&"c01_shelf_game_success", true)
|
||||||
shelf_game_success = true
|
shelf_game_success = true
|
||||||
@ -143,7 +142,6 @@ func _on_shelf_game_success() -> void:
|
|||||||
# 相机抖动
|
# 相机抖动
|
||||||
SceneManager.get_camera_marker().shake_camera()
|
SceneManager.get_camera_marker().shake_camera()
|
||||||
# 播放小蝶从书架跌倒的动画
|
# 播放小蝶从书架跌倒的动画
|
||||||
fall_off = $"../DeployLayer/小小蝶坠落"
|
|
||||||
fall_off.visible = true
|
fall_off.visible = true
|
||||||
fall_off.play()
|
fall_off.play()
|
||||||
fall_off.animation_finished.connect(_on_fall_off_finished)
|
fall_off.animation_finished.connect(_on_fall_off_finished)
|
||||||
@ -154,11 +152,16 @@ func _on_shelf_game_success() -> void:
|
|||||||
|
|
||||||
func _on_fall_off_finished() -> void:
|
func _on_fall_off_finished() -> void:
|
||||||
fall_off.visible = false
|
fall_off.visible = false
|
||||||
|
SceneManager.get_player().hide_sprite = false
|
||||||
|
await Util.wait(0.3)
|
||||||
|
await SceneManager.pop_os_with_str("c01_s08_书架游戏完成")
|
||||||
|
# 耳鸣与眩晕
|
||||||
|
$"Sfx头痛耳鸣".play()
|
||||||
|
$"../DizzyShader".dizzy()
|
||||||
|
await Util.wait(2.5)
|
||||||
|
await SceneManager.pop_os_with_str("c01_s08_书架游戏恢复记忆")
|
||||||
# 最后释放玩家
|
# 最后释放玩家
|
||||||
SceneManager.release_player()
|
SceneManager.release_player()
|
||||||
SceneManager.get_player().hide_sprite = false
|
|
||||||
await Util.wait(1.2)
|
|
||||||
SceneManager.pop_os_with_str("c01_s08_书架游戏完成")
|
|
||||||
|
|
||||||
|
|
||||||
func _setup_weird_bookstore() -> void:
|
func _setup_weird_bookstore() -> void:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
[gd_scene load_steps=21 format=3 uid="uid://cwu4dhayra8pg"]
|
[gd_scene load_steps=23 format=3 uid="uid://cwu4dhayra8pg"]
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://dayyx4jerj7io" path="res://scene/ground/ground.tscn" id="1_b3cca"]
|
[ext_resource type="PackedScene" uid="uid://dayyx4jerj7io" path="res://scene/ground/ground.tscn" id="1_b3cca"]
|
||||||
[ext_resource type="Script" uid="uid://6q2pfbqsw10t" path="res://scene/ground/scene/c01/s08_书店.gd" id="2_0lque"]
|
[ext_resource type="Script" uid="uid://6q2pfbqsw10t" path="res://scene/ground/scene/c01/s08_书店.gd" id="2_0lque"]
|
||||||
@ -16,7 +16,9 @@
|
|||||||
[ext_resource type="AudioStream" uid="uid://bnjyw5v85s6qe" path="res://asset/audio/sfx/交互/序章/04_书店内_主角摔倒.ogg" id="8_p6k3c"]
|
[ext_resource type="AudioStream" uid="uid://bnjyw5v85s6qe" path="res://asset/audio/sfx/交互/序章/04_书店内_主角摔倒.ogg" id="8_p6k3c"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bho8xal4ha50l" path="res://asset/art/scene/c01/s08_书店/l_打光.png" id="9_i4dqp"]
|
[ext_resource type="Texture2D" uid="uid://bho8xal4ha50l" path="res://asset/art/scene/c01/s08_书店/l_打光.png" id="9_i4dqp"]
|
||||||
[ext_resource type="AudioStream" uid="uid://cniawn37n8888" path="res://asset/audio/sfx/交互/序章/04_书店内_递交报纸.ogg" id="9_lfr41"]
|
[ext_resource type="AudioStream" uid="uid://cniawn37n8888" path="res://asset/audio/sfx/交互/序章/04_书店内_递交报纸.ogg" id="9_lfr41"]
|
||||||
|
[ext_resource type="AudioStream" uid="uid://b8sbtn3l37uh" path="res://asset/audio/sfx/旧版/c02/红屏.ogg" id="9_srknn"]
|
||||||
[ext_resource type="Texture2D" uid="uid://bp4y3vujvsl7r" path="res://asset/art/scene/c01/s08_书店/fg_前景.png" id="10_4e3a1"]
|
[ext_resource type="Texture2D" uid="uid://bp4y3vujvsl7r" path="res://asset/art/scene/c01/s08_书店/fg_前景.png" id="10_4e3a1"]
|
||||||
|
[ext_resource type="PackedScene" uid="uid://decfqoe5v0y6n" path="res://scene/effect/dizzy_shader.tscn" id="18_wg16e"]
|
||||||
|
|
||||||
[sub_resource type="AnimationLibrary" id="AnimationLibrary_xqgjo"]
|
[sub_resource type="AnimationLibrary" id="AnimationLibrary_xqgjo"]
|
||||||
|
|
||||||
@ -81,6 +83,12 @@ bus = &"game_sfx"
|
|||||||
script = ExtResource("4_p6k3c")
|
script = ExtResource("4_p6k3c")
|
||||||
metadata/_custom_type_script = "uid://rq6w1vuhuq1m"
|
metadata/_custom_type_script = "uid://rq6w1vuhuq1m"
|
||||||
|
|
||||||
|
[node name="Sfx头痛耳鸣" type="AudioStreamPlayer" parent="Ground/AnimationPlayer" index="5"]
|
||||||
|
stream = ExtResource("9_srknn")
|
||||||
|
bus = &"game_sfx"
|
||||||
|
script = ExtResource("4_p6k3c")
|
||||||
|
metadata/_custom_type_script = "uid://rq6w1vuhuq1m"
|
||||||
|
|
||||||
[node name="BGSprite2D" parent="Ground" index="2"]
|
[node name="BGSprite2D" parent="Ground" index="2"]
|
||||||
material = SubResource("ShaderMaterial_ddd5v")
|
material = SubResource("ShaderMaterial_ddd5v")
|
||||||
texture = ExtResource("3_322m4")
|
texture = ExtResource("3_322m4")
|
||||||
@ -198,6 +206,8 @@ points = PackedVector2Array(22, 150, 545, 150)
|
|||||||
energy = 0.0
|
energy = 0.0
|
||||||
blend_mode = 1
|
blend_mode = 1
|
||||||
|
|
||||||
|
[node name="DizzyShader" parent="Ground" instance=ExtResource("18_wg16e")]
|
||||||
|
|
||||||
[node name="参考" type="Sprite2D" parent="."]
|
[node name="参考" type="Sprite2D" parent="."]
|
||||||
visible = false
|
visible = false
|
||||||
modulate = Color(1, 1, 1, 0.580392)
|
modulate = Color(1, 1, 1, 0.580392)
|
||||||
|
@ -58,7 +58,6 @@ func _on_ground_ready() -> void:
|
|||||||
counter.get_node("点燃").modulate.a = 1.0
|
counter.get_node("点燃").modulate.a = 1.0
|
||||||
$VibeSfx氛围.switch_to("c02_火灾")
|
$VibeSfx氛围.switch_to("c02_火灾")
|
||||||
$"../DirectionalLight2D".energy = 0
|
$"../DirectionalLight2D".energy = 0
|
||||||
|
|
||||||
eavesdrop_window = $"../DeployLayer/李氏赖子房间人影"
|
eavesdrop_window = $"../DeployLayer/李氏赖子房间人影"
|
||||||
madman_npc = $"../DeployLayer/Npc井边疯子"
|
madman_npc = $"../DeployLayer/Npc井边疯子"
|
||||||
madman_npc.visible = false
|
madman_npc.visible = false
|
||||||
@ -66,7 +65,7 @@ func _on_ground_ready() -> void:
|
|||||||
burning_layer = $"../DeployLayer/火灾"
|
burning_layer = $"../DeployLayer/火灾"
|
||||||
var closeup_well = $"../DeployLayer/Closeup井"
|
var closeup_well = $"../DeployLayer/Closeup井"
|
||||||
# 第一章霸凌阶段(弹珠游戏结束为开始)隐藏疯子与李癞偷听,第二章开始后显示
|
# 第一章霸凌阶段(弹珠游戏结束为开始)隐藏疯子与李癞偷听,第二章开始后显示
|
||||||
if EventManager.get_stage(&"c02_ball_game_stage") == 3 and EventManager.get_chapter_stage() <= 2:
|
if EventManager.get_stage(&"c02_ball_game_stage") >= 3 and EventManager.get_chapter_stage() <= 2:
|
||||||
_setup_bully_or_burning(true)
|
_setup_bully_or_burning(true)
|
||||||
# 弹珠游戏结束后就开始霸凌,此时禁止偷听。第一章结束后(火灾结束),第二章再偷听
|
# 弹珠游戏结束后就开始霸凌,此时禁止偷听。第一章结束后(火灾结束),第二章再偷听
|
||||||
$"../DeployLayer/Ambush偷听对话".enabled = false
|
$"../DeployLayer/Ambush偷听对话".enabled = false
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
[ext_resource type="AudioStream" uid="uid://b3b4a6nm8557i" path="res://asset/audio/专用/衔蝶_主菜单music剪辑人声版.wav" id="5_5oc6i"]
|
[ext_resource type="AudioStream" uid="uid://b3b4a6nm8557i" path="res://asset/audio/专用/衔蝶_主菜单music剪辑人声版.wav" id="5_5oc6i"]
|
||||||
[ext_resource type="Script" uid="uid://c63lrar71o17d" path="res://scene/index/启动入口.gd" id="7_1sxgt"]
|
[ext_resource type="Script" uid="uid://c63lrar71o17d" path="res://scene/index/启动入口.gd" id="7_1sxgt"]
|
||||||
[ext_resource type="AudioStream" uid="uid://b3b4a6nm8557i" path="res://asset/audio/专用/衔蝶_主菜单music剪辑人声版.ogg" id="5_5oc6i"]
|
[ext_resource type="AudioStream" uid="uid://b3b4a6nm8557i" path="res://asset/audio/专用/衔蝶_主菜单music剪辑人声版.ogg" id="5_5oc6i"]
|
||||||
|
[ext_resource type="FontFile" uid="uid://bjmhscwn1ixj1" path="res://asset/font/字体/ChillJinshuSongMedium.otf" id="7_1sxgt"]
|
||||||
|
|
||||||
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_gu56a"]
|
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_gu56a"]
|
||||||
content_margin_top = 4.0
|
content_margin_top = 4.0
|
||||||
@ -139,6 +140,18 @@ theme_override_styles/pressed = SubResource("StyleBoxFlat_scxsv")
|
|||||||
theme_override_styles/normal = SubResource("StyleBoxEmpty_vyh3d")
|
theme_override_styles/normal = SubResource("StyleBoxEmpty_vyh3d")
|
||||||
text = "index_退出游戏"
|
text = "index_退出游戏"
|
||||||
|
|
||||||
|
[node name="ButtonQuery" type="LinkButton" parent="."]
|
||||||
|
layout_mode = 0
|
||||||
|
offset_left = 439.0
|
||||||
|
offset_top = 27.0
|
||||||
|
offset_right = 535.0
|
||||||
|
offset_bottom = 67.0
|
||||||
|
theme_override_fonts/font = ExtResource("7_1sxgt")
|
||||||
|
theme_override_font_sizes/font_size = 12
|
||||||
|
text = "衔蝶内测反馈问卷"
|
||||||
|
underline = 2
|
||||||
|
uri = "https://wj.qq.com/s2/23189494/a237/"
|
||||||
|
|
||||||
[node name="Mask" type="ColorRect" parent="."]
|
[node name="Mask" type="ColorRect" parent="."]
|
||||||
visible = false
|
visible = false
|
||||||
layout_mode = 1
|
layout_mode = 1
|
||||||
|
@ -12,7 +12,7 @@ func run_clip(card_mode: bool):
|
|||||||
$"李氏赖子房间人影".play()
|
$"李氏赖子房间人影".play()
|
||||||
if not card_mode:
|
if not card_mode:
|
||||||
# 增加配音
|
# 增加配音
|
||||||
dialog_node = DialogueManager.show_dialogue_balloon(dialogue_c02, "c02_04_李氏癞子")
|
dialog_node = DialogueManager.show_dialogue_balloon(dialogue_c02, "c02_04_李氏癞子", [GlobalConfig.DIALOG_MEM_LAYER])
|
||||||
dialog_node.process_mode = Node.PROCESS_MODE_ALWAYS
|
dialog_node.process_mode = Node.PROCESS_MODE_ALWAYS
|
||||||
await DialogueManager.dialogue_ended
|
await DialogueManager.dialogue_ended
|
||||||
display_finished.emit()
|
display_finished.emit()
|
||||||
|
@ -13,7 +13,7 @@ func run_clip(card_mode: bool):
|
|||||||
if not card_mode:
|
if not card_mode:
|
||||||
await Util.wait(3.0)
|
await Util.wait(3.0)
|
||||||
# 增加配音
|
# 增加配音
|
||||||
dialog_node = DialogueManager.show_dialogue_balloon(dialogue_res, "c02_井边疯子对话")
|
dialog_node = DialogueManager.show_dialogue_balloon(dialogue_res, "c02_井边疯子对话", [GlobalConfig.DIALOG_MEM_LAYER])
|
||||||
dialog_node.process_mode = Node.PROCESS_MODE_ALWAYS
|
dialog_node.process_mode = Node.PROCESS_MODE_ALWAYS
|
||||||
await DialogueManager.dialogue_ended
|
await DialogueManager.dialogue_ended
|
||||||
display_finished.emit()
|
display_finished.emit()
|
||||||
|
@ -3,6 +3,14 @@ class_name PropHud extends Control
|
|||||||
|
|
||||||
signal current_item_changed(prop_key: String)
|
signal current_item_changed(prop_key: String)
|
||||||
|
|
||||||
|
# 常量定义
|
||||||
|
const PROP_CONTAINER_X = 130.0
|
||||||
|
const PROP_CONTROL_X = 110.0
|
||||||
|
const TWEEN_DURATION = 0.5
|
||||||
|
const SHAKE_FPS = 15.0
|
||||||
|
const SHAKE_DURATION = 0.8
|
||||||
|
const SHAKE_DELTA = 12.0
|
||||||
|
|
||||||
@export_group("DebugItem")
|
@export_group("DebugItem")
|
||||||
@export var enable_item := false:
|
@export var enable_item := false:
|
||||||
set(value):
|
set(value):
|
||||||
@ -10,12 +18,18 @@ signal current_item_changed(prop_key: String)
|
|||||||
enable_item = false
|
enable_item = false
|
||||||
enable_prop_item(item_key)
|
enable_prop_item(item_key)
|
||||||
@export var item_key: String
|
@export var item_key: String
|
||||||
|
|
||||||
@export_group("Inventory")
|
@export_group("Inventory")
|
||||||
@export var inventory: PropInventory:
|
@export var inventory: PropInventory:
|
||||||
set(value):
|
set(value):
|
||||||
|
if inventory == value:
|
||||||
|
return
|
||||||
|
if inventory and inventory.current_item_changed.is_connected(_emit_changed):
|
||||||
|
inventory.current_item_changed.disconnect(_emit_changed)
|
||||||
inventory = value
|
inventory = value
|
||||||
if inventory and not inventory.current_item_changed.is_connected(_emit_changed):
|
if inventory and not inventory.current_item_changed.is_connected(_emit_changed):
|
||||||
inventory.current_item_changed.connect(_emit_changed)
|
inventory.current_item_changed.connect(_emit_changed)
|
||||||
|
|
||||||
@export_group("UI-UX")
|
@export_group("UI-UX")
|
||||||
@export var display_time := 2.5 # 不包含渐入渐出(约 0.6s)的时长
|
@export var display_time := 2.5 # 不包含渐入渐出(约 0.6s)的时长
|
||||||
@export var locked := false
|
@export var locked := false
|
||||||
@ -35,14 +49,12 @@ signal current_item_changed(prop_key: String)
|
|||||||
@onready var props_bag_scroll = %PropsBagScroll as ScrollContainer
|
@onready var props_bag_scroll = %PropsBagScroll as ScrollContainer
|
||||||
@onready var props_bag = %PropsBag as HBoxContainer
|
@onready var props_bag = %PropsBag as HBoxContainer
|
||||||
@onready var select_mark = %SelectMark as TextureRect
|
@onready var select_mark = %SelectMark as TextureRect
|
||||||
var prop_containers = [] #CenterContainer
|
|
||||||
const PROP_CONTAINER_X = 130.0
|
|
||||||
const PROP_CONTROL_X = 110.0
|
|
||||||
|
|
||||||
|
var prop_containers: Array[CenterContainer] = []
|
||||||
var items_dict := {}
|
var items_dict := {}
|
||||||
var items_description_dict = {}
|
var items_description_dict = {}
|
||||||
# 从配置文件加载 prop items
|
# 从配置文件加载 prop items
|
||||||
var item_config_res = preload("res://asset/dialogue/item_description.dialogue")
|
var item_config_res = preload("uid://b1vwhxctfhl5d") #item_description.dialogue
|
||||||
var path_prefix = "res://asset/art/prop/"
|
var path_prefix = "res://asset/art/prop/"
|
||||||
var cached_inventory_textures := {}
|
var cached_inventory_textures := {}
|
||||||
|
|
||||||
@ -52,10 +64,16 @@ var displaying = false
|
|||||||
var timer := Timer.new()
|
var timer := Timer.new()
|
||||||
var display_tween: Tween
|
var display_tween: Tween
|
||||||
var container_tween: Tween
|
var container_tween: Tween
|
||||||
|
var prop_blink: Tween
|
||||||
|
var tween_scroll: Tween
|
||||||
|
var shake_tween: Tween
|
||||||
|
|
||||||
# hud 是否监听快捷键
|
# hud 是否监听快捷键
|
||||||
var listening_hotkey = true
|
var listening_hotkey = true
|
||||||
|
|
||||||
|
# 缓存的占位符纹理
|
||||||
|
var placeholder_texture: Texture2D
|
||||||
|
|
||||||
|
|
||||||
func _emit_changed(prop_key := ""):
|
func _emit_changed(prop_key := ""):
|
||||||
current_item_changed.emit(prop_key)
|
current_item_changed.emit(prop_key)
|
||||||
@ -64,33 +82,43 @@ func _emit_changed(prop_key := ""):
|
|||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
if Engine.is_editor_hint():
|
if Engine.is_editor_hint():
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 初始化占位符纹理 placeholder.png
|
||||||
|
placeholder_texture = preload("uid://djrfdhywg7uu2")
|
||||||
|
|
||||||
# read prop containers
|
# read prop containers
|
||||||
for id in range(props_bag.get_child_count()):
|
for id in range(props_bag.get_child_count()):
|
||||||
var container = props_bag.get_child(id)
|
var container = props_bag.get_child(id)
|
||||||
prop_containers.append(container)
|
prop_containers.append(container)
|
||||||
container.get_child(0).get_child(0).gui_input.connect(_on_prop_gui_input.bind(id))
|
var button = container.get_child(0).get_child(0)
|
||||||
|
if button:
|
||||||
|
button.gui_input.connect(_on_prop_gui_input.bind(id))
|
||||||
|
|
||||||
display_prop.gui_input.connect(_on_prop_gui_input.bind(-1))
|
display_prop.gui_input.connect(_on_prop_gui_input.bind(-1))
|
||||||
|
|
||||||
_load_items_config_to_dict("ImportantPropItems")
|
_load_items_config_to_dict("ImportantPropItems")
|
||||||
_load_items_config_to_dict("PropItems")
|
_load_items_config_to_dict("PropItems")
|
||||||
_reload_cache_and_realign_display()
|
_reload_cache_and_realign_display()
|
||||||
|
|
||||||
selecting_bg.modulate.a = 0.0
|
selecting_bg.modulate.a = 0.0
|
||||||
prop_scroll.scroll_horizontal = PROP_CONTAINER_X
|
prop_scroll.scroll_horizontal = PROP_CONTAINER_X
|
||||||
props_bag_scroll.scroll_horizontal = 0.0
|
props_bag_scroll.scroll_horizontal = 0.0
|
||||||
props_bag_scroll.custom_minimum_size.x = 0.0
|
props_bag_scroll.custom_minimum_size.x = 0.0
|
||||||
# focus_exited.connect(_on_focus_exited)
|
|
||||||
# 存档更新时,从存档加载 prop
|
# 存档更新时,从存档加载 prop
|
||||||
ArchiveManager.archive_loaded.connect(_reload_cache_and_realign_display)
|
ArchiveManager.archive_loaded.connect(_reload_cache_and_realign_display)
|
||||||
|
|
||||||
# tween timer
|
# tween timer
|
||||||
timer.wait_time = display_time
|
timer.wait_time = display_time
|
||||||
timer.one_shot = true
|
timer.one_shot = true
|
||||||
timer.autostart = false
|
timer.autostart = false
|
||||||
timer.timeout.connect(_on_timer_timeout)
|
timer.timeout.connect(_on_timer_timeout)
|
||||||
add_child(timer)
|
add_child(timer)
|
||||||
|
|
||||||
# connect signals
|
# connect signals
|
||||||
left_btn.pressed.connect(on_left_pressed)
|
left_btn.pressed.connect(on_left_pressed)
|
||||||
right_btn.pressed.connect(on_right_pressed)
|
right_btn.pressed.connect(on_right_pressed)
|
||||||
title_label.modulate.a = 0.0
|
title_label.modulate.a = 0.0
|
||||||
# _toggle_btn_ability(false)
|
|
||||||
left_btn.modulate.a = 0.5
|
left_btn.modulate.a = 0.5
|
||||||
right_btn.modulate.a = 0.5
|
right_btn.modulate.a = 0.5
|
||||||
mouse_entered.connect(_on_mouse_entered)
|
mouse_entered.connect(_on_mouse_entered)
|
||||||
@ -98,51 +126,36 @@ func _ready() -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _load_items_config_to_dict(title: String):
|
func _load_items_config_to_dict(title: String):
|
||||||
|
if not item_config_res or not item_config_res.titles.has(title):
|
||||||
|
return
|
||||||
|
|
||||||
var id = item_config_res.titles[title]
|
var id = item_config_res.titles[title]
|
||||||
var current_line = item_config_res.lines[id]
|
var current_line = item_config_res.lines.get(id)
|
||||||
|
|
||||||
while current_line:
|
while current_line:
|
||||||
if current_line.has("tags") and current_line.has("translation_key"):
|
if current_line.has("tags") and current_line.has("translation_key"):
|
||||||
var wrapped_texture := "texture="
|
|
||||||
var wrapped_inspect := "inspect="
|
|
||||||
var texture_path = ""
|
var texture_path = ""
|
||||||
var inspect_path = ""
|
var inspect_path = ""
|
||||||
for t in current_line.tags:
|
|
||||||
if t.begins_with(wrapped_texture):
|
for tag in current_line.tags:
|
||||||
texture_path = t.replace(wrapped_texture, "").strip_edges()
|
if tag.begins_with("texture="):
|
||||||
elif t.begins_with(wrapped_inspect):
|
texture_path = tag.substr(8).strip_edges()
|
||||||
inspect_path = t.replace(wrapped_inspect, "").strip_edges()
|
elif tag.begins_with("inspect="):
|
||||||
|
inspect_path = tag.substr(8).strip_edges()
|
||||||
|
|
||||||
var item = PropItem.new()
|
var item = PropItem.new()
|
||||||
item.key = current_line.translation_key
|
item.key = current_line.translation_key
|
||||||
if texture_path:
|
if texture_path:
|
||||||
item.texture_path = path_prefix + texture_path
|
item.texture_path = path_prefix + texture_path
|
||||||
if inspect_path:
|
if inspect_path:
|
||||||
item.inspect_path = path_prefix + inspect_path
|
item.inspect_path = path_prefix + inspect_path
|
||||||
|
|
||||||
items_dict[item.key] = item
|
items_dict[item.key] = item
|
||||||
# # 检查是否是重要物品,如果是,则添加到 items_description_dict
|
|
||||||
items_description_dict[item.key] = tr(item.key + "_说明").replace("{br}", "\n")
|
items_description_dict[item.key] = tr(item.key + "_说明").replace("{br}", "\n")
|
||||||
|
|
||||||
# if item_config_res.titles.has(item.key):
|
|
||||||
# var important_item_line_id = item_config_res.titles[item.key]
|
|
||||||
# items_description_dict[item.key] = get_import_item_content(important_item_line_id)
|
|
||||||
if not current_line.has("next_id") or current_line.next_id == "end":
|
if not current_line.has("next_id") or current_line.next_id == "end":
|
||||||
break
|
break
|
||||||
current_line = item_config_res.lines[current_line.next_id]
|
current_line = item_config_res.lines.get(current_line.next_id)
|
||||||
|
|
||||||
|
|
||||||
# func get_import_item_content(line_id) -> String:
|
|
||||||
# var current_line = item_config_res.lines[line_id]
|
|
||||||
# var content = ""
|
|
||||||
# while current_line:
|
|
||||||
# if current_line.has("text"):
|
|
||||||
# if current_line.has("translation_key"):
|
|
||||||
# content += tr(current_line.translation_key) + "\n"
|
|
||||||
# else:
|
|
||||||
# content += current_line.text + "\n"
|
|
||||||
# if not current_line.has("next_id") or current_line.next_id == "end":
|
|
||||||
# break
|
|
||||||
# current_line = item_config_res.lines[current_line.next_id]
|
|
||||||
# content.replace("{br}", "\n")
|
|
||||||
# return content
|
|
||||||
|
|
||||||
|
|
||||||
func _reload_cache_and_realign_display() -> void:
|
func _reload_cache_and_realign_display() -> void:
|
||||||
@ -161,57 +174,90 @@ func checkout_inventory(character: String) -> void:
|
|||||||
_reload_cache_and_realign_display()
|
_reload_cache_and_realign_display()
|
||||||
|
|
||||||
|
|
||||||
func hide_hud():
|
const HUD_FADE_DURATION = 0.3
|
||||||
# 隐藏 hud 并静音
|
|
||||||
hide()
|
# 在变量定义区域添加
|
||||||
|
var hud_visibility_tween: Tween
|
||||||
|
|
||||||
|
func hide_hud(duration: float = HUD_FADE_DURATION):
|
||||||
|
if not visible:
|
||||||
|
return
|
||||||
listening_hotkey = false
|
listening_hotkey = false
|
||||||
|
# 清理之前的补间动画
|
||||||
|
if hud_visibility_tween and hud_visibility_tween.is_running():
|
||||||
|
hud_visibility_tween.kill()
|
||||||
|
# 创建渐变动画
|
||||||
|
hud_visibility_tween = create_tween()
|
||||||
|
hud_visibility_tween.tween_property(self, "modulate:a", 0.0, duration)
|
||||||
|
hud_visibility_tween.tween_callback(hide)
|
||||||
|
|
||||||
|
|
||||||
func display_hud():
|
func display_hud(duration: float = HUD_FADE_DURATION):
|
||||||
# 显示 hud 并取消静音
|
if visible and modulate.a >= 1.0:
|
||||||
|
return
|
||||||
|
# 清理之前的补间动画
|
||||||
|
if hud_visibility_tween and hud_visibility_tween.is_running():
|
||||||
|
hud_visibility_tween.kill()
|
||||||
|
# 确保节点可见但透明
|
||||||
|
if not visible:
|
||||||
|
modulate.a = 0.0
|
||||||
show()
|
show()
|
||||||
listening_hotkey = true
|
# 创建渐变动画
|
||||||
|
hud_visibility_tween = create_tween()
|
||||||
|
hud_visibility_tween.tween_property(self, "modulate:a", 1.0, duration)
|
||||||
|
hud_visibility_tween.tween_callback(func(): listening_hotkey = true)
|
||||||
|
|
||||||
|
|
||||||
func _load_texture_cache() -> void:
|
func _load_texture_cache() -> void:
|
||||||
if not inventory:
|
if not inventory:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# 移除无效纹理
|
||||||
|
var keys_to_remove = []
|
||||||
for k in cached_inventory_textures:
|
for k in cached_inventory_textures:
|
||||||
# remove invalid textures
|
|
||||||
if not k in inventory.enabled_items:
|
if not k in inventory.enabled_items:
|
||||||
|
keys_to_remove.append(k)
|
||||||
|
|
||||||
|
for k in keys_to_remove:
|
||||||
cached_inventory_textures.erase(k)
|
cached_inventory_textures.erase(k)
|
||||||
|
|
||||||
|
# 加载新纹理
|
||||||
for key in inventory.enabled_items:
|
for key in inventory.enabled_items:
|
||||||
if cached_inventory_textures.has(key):
|
if cached_inventory_textures.has(key):
|
||||||
continue
|
continue
|
||||||
# 以 items_dict 为准,如果 enabled_items 中的 key 不存在,则删除
|
|
||||||
if not key in items_dict:
|
if not items_dict.has(key):
|
||||||
inventory.disable_item(key)
|
inventory.disable_item(key)
|
||||||
printerr(
|
printerr(
|
||||||
"PropHud _load_texture_cache: key not found in items_dict:", key, ". remove item."
|
"PropHud _load_texture_cache: key not found in items_dict:", key, ". remove item."
|
||||||
)
|
)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
var path = items_dict[key].texture_path
|
var path = items_dict[key].texture_path
|
||||||
if not path:
|
if not path:
|
||||||
var placeholder = preload("res://asset/art/ui/hud/placeholder.png")
|
cached_inventory_textures[key] = placeholder_texture
|
||||||
cached_inventory_textures[key] = placeholder
|
|
||||||
print("Cache load prop placeholder key=", key)
|
print("Cache load prop placeholder key=", key)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
var texture = load(path) as Texture2D
|
var texture = load(path) as Texture2D
|
||||||
if texture:
|
if texture:
|
||||||
if GlobalConfig.DEBUG:
|
if GlobalConfig.DEBUG:
|
||||||
print("Cache load prop texture key=", key)
|
print("Cache load prop texture key=", key)
|
||||||
cached_inventory_textures[key] = texture
|
cached_inventory_textures[key] = texture
|
||||||
|
|
||||||
# wrap index
|
# wrap index
|
||||||
|
if inventory.enabled_items.size() > 0:
|
||||||
inventory.current_index = wrapi(inventory.current_index, 0, inventory.enabled_items.size())
|
inventory.current_index = wrapi(inventory.current_index, 0, inventory.enabled_items.size())
|
||||||
|
|
||||||
|
|
||||||
func _update_prop_display_with_texture():
|
func _update_prop_display_with_texture():
|
||||||
if not inventory:
|
if not inventory:
|
||||||
return
|
return
|
||||||
|
|
||||||
var key = ""
|
var key = ""
|
||||||
# 在没有道具时,展示空手 placeholder
|
# 在没有道具时,展示空手 placeholder
|
||||||
if inventory.enabled_items.is_empty():
|
if inventory.enabled_items.is_empty():
|
||||||
display_prop.texture_normal = preload("res://asset/art/ui/hud/placeholder.png")
|
display_prop.texture_normal = placeholder_texture
|
||||||
display_prop.size = Vector2(PROP_CONTROL_X, PROP_CONTROL_X)
|
display_prop.size = Vector2(PROP_CONTROL_X, PROP_CONTROL_X)
|
||||||
display_prop.scale = Vector2(1.0, 1.0)
|
display_prop.scale = Vector2(1.0, 1.0)
|
||||||
title_label.text = tr("prop_空手")
|
title_label.text = tr("prop_空手")
|
||||||
@ -219,37 +265,50 @@ func _update_prop_display_with_texture():
|
|||||||
key = inventory.current_item_key()
|
key = inventory.current_item_key()
|
||||||
_display_texture_by_key(display_prop, key)
|
_display_texture_by_key(display_prop, key)
|
||||||
title_label.text = tr(key)
|
title_label.text = tr(key)
|
||||||
|
|
||||||
# 如果当前是 prop_小猫玩具完整,尝试点亮玩家的灯效;否则无需点亮
|
# 如果当前是 prop_小猫玩具完整,尝试点亮玩家的灯效;否则无需点亮
|
||||||
var player = SceneManager.get_player()
|
var player = SceneManager.get_player()
|
||||||
if player:
|
if player:
|
||||||
player.set_catty_light(key == "prop_小猫玩具完整")
|
player.set_catty_light(key == "prop_小猫玩具完整")
|
||||||
|
|
||||||
if GlobalConfig.DEBUG:
|
if GlobalConfig.DEBUG:
|
||||||
print("[PropHud] current display prop:", key)
|
print("[PropHud] current display prop:", key)
|
||||||
# 选中标记 select_mark; 如果被 free 掉,则重新创建
|
|
||||||
if select_mark and is_instance_valid(select_mark):
|
# 选中标记处理
|
||||||
var parent = select_mark.get_parent()
|
_update_select_mark()
|
||||||
if parent:
|
|
||||||
parent.remove_child(select_mark)
|
# bag更新
|
||||||
else:
|
|
||||||
select_mark = TextureRect.new()
|
|
||||||
select_mark.custom_minimum_size = Vector2(PROP_CONTAINER_X, PROP_CONTAINER_X)
|
|
||||||
select_mark.texture = preload("res://asset/art/ui/hud/select_mark.png")
|
|
||||||
# bag
|
|
||||||
for i in range(inventory.enabled_items.size()):
|
for i in range(inventory.enabled_items.size()):
|
||||||
var id = wrapi(i, 0, inventory.enabled_items.size())
|
var id = wrapi(i, 0, inventory.enabled_items.size())
|
||||||
var k = inventory.enabled_items[id]
|
var k = inventory.enabled_items[id]
|
||||||
var button = prop_containers[i].get_child(0).get_child(0) as TextureButton
|
var container = prop_containers[i]
|
||||||
|
var button = container.get_child(0).get_child(0) as TextureButton
|
||||||
_display_texture_by_key(button, k)
|
_display_texture_by_key(button, k)
|
||||||
if id == inventory.current_index:
|
if id == inventory.current_index:
|
||||||
prop_containers[i].get_child(0).add_child(select_mark)
|
container.get_child(0).add_child(select_mark)
|
||||||
|
|
||||||
prop_scroll.scroll_horizontal = PROP_CONTAINER_X
|
prop_scroll.scroll_horizontal = PROP_CONTAINER_X
|
||||||
# props_bag_scroll.scroll_horizontal = 0.0
|
|
||||||
|
|
||||||
|
|
||||||
func _display_texture_by_key(button, key) -> void:
|
func _update_select_mark():
|
||||||
if not key:
|
if not is_instance_valid(select_mark):
|
||||||
|
select_mark = TextureRect.new()
|
||||||
|
select_mark.custom_minimum_size = Vector2(PROP_CONTAINER_X, PROP_CONTAINER_X)
|
||||||
|
# select_mark
|
||||||
|
select_mark.texture = preload("uid://c0gjes4a8ou3b")
|
||||||
|
else:
|
||||||
|
var parent = select_mark.get_parent()
|
||||||
|
if parent:
|
||||||
|
parent.remove_child(select_mark)
|
||||||
|
|
||||||
|
|
||||||
|
func _display_texture_by_key(button: TextureButton, key: String) -> void:
|
||||||
|
if not key or not button:
|
||||||
|
if button:
|
||||||
button.texture_normal = null
|
button.texture_normal = null
|
||||||
return
|
return
|
||||||
|
if not items_dict.has(key):
|
||||||
|
return
|
||||||
var item = items_dict[key]
|
var item = items_dict[key]
|
||||||
var texture = cached_inventory_textures.get(item.key)
|
var texture = cached_inventory_textures.get(item.key)
|
||||||
if not texture:
|
if not texture:
|
||||||
@ -257,14 +316,15 @@ func _display_texture_by_key(button, key) -> void:
|
|||||||
texture = load(item.texture_path) as Texture2D
|
texture = load(item.texture_path) as Texture2D
|
||||||
if not texture:
|
if not texture:
|
||||||
printerr("PropHud _display_texture_by_key: No texture found for item:", item)
|
printerr("PropHud _display_texture_by_key: No texture found for item:", item)
|
||||||
|
return
|
||||||
else:
|
else:
|
||||||
cached_inventory_textures[item.key] = texture
|
cached_inventory_textures[item.key] = texture
|
||||||
button.texture_normal = texture
|
button.texture_normal = texture
|
||||||
var t_size = button.texture_normal.get_size()
|
var t_size = texture.get_size()
|
||||||
var max_x = max(t_size.x, t_size.y)
|
var max_dimension = max(t_size.x, t_size.y)
|
||||||
var p_scale = min(PROP_CONTROL_X / t_size.x, PROP_CONTROL_X / t_size.y)
|
var p_scale = min(PROP_CONTROL_X / t_size.x, PROP_CONTROL_X / t_size.y)
|
||||||
button.scale = Vector2(p_scale, p_scale)
|
button.scale = Vector2(p_scale, p_scale)
|
||||||
button.size = Vector2(max_x, max_x)
|
button.size = Vector2(max_dimension, max_dimension)
|
||||||
|
|
||||||
|
|
||||||
func on_left_pressed() -> void:
|
func on_left_pressed() -> void:
|
||||||
@ -290,34 +350,37 @@ func on_right_pressed() -> void:
|
|||||||
func _tween_container(left_to_right := true) -> void:
|
func _tween_container(left_to_right := true) -> void:
|
||||||
if container_tween and container_tween.is_running():
|
if container_tween and container_tween.is_running():
|
||||||
container_tween.kill()
|
container_tween.kill()
|
||||||
|
|
||||||
container_tween = create_tween()
|
container_tween = create_tween()
|
||||||
if left_to_right:
|
prop_scroll.scroll_horizontal = 2 * PROP_CONTAINER_X if left_to_right else 0.0
|
||||||
prop_scroll.scroll_horizontal = 2 * PROP_CONTAINER_X
|
|
||||||
else:
|
|
||||||
prop_scroll.scroll_horizontal = 0.0
|
|
||||||
# 通过 Head 与 Tail 占位符,实现滚动效果;否则会导致卡在边界上,无法滚动
|
|
||||||
container_tween.tween_property(prop_scroll, "scroll_horizontal", PROP_CONTAINER_X, 0.2)
|
container_tween.tween_property(prop_scroll, "scroll_horizontal", PROP_CONTAINER_X, 0.2)
|
||||||
|
|
||||||
|
|
||||||
func _on_prop_gui_input(event: InputEvent, id) -> void:
|
func _on_prop_gui_input(event: InputEvent, id: int) -> void:
|
||||||
if locked:
|
if locked or not event is InputEventMouseButton:
|
||||||
return
|
return
|
||||||
if event is InputEventMouseButton and event.is_pressed():
|
|
||||||
event = event as InputEventMouseButton
|
var mouse_event = event as InputEventMouseButton
|
||||||
if event.button_index == MOUSE_BUTTON_LEFT:
|
if not mouse_event.is_pressed():
|
||||||
|
return
|
||||||
|
|
||||||
|
match mouse_event.button_index:
|
||||||
|
MOUSE_BUTTON_LEFT:
|
||||||
_on_prop_pressed(id)
|
_on_prop_pressed(id)
|
||||||
elif event.button_index == MOUSE_BUTTON_RIGHT:
|
MOUSE_BUTTON_RIGHT:
|
||||||
_on_prop_inspected(id)
|
_on_prop_inspected(id)
|
||||||
|
|
||||||
|
|
||||||
func _on_prop_inspected(id := 0) -> void:
|
func _on_prop_inspected(id := 0) -> void:
|
||||||
if locked:
|
if locked:
|
||||||
return
|
return
|
||||||
|
|
||||||
var prop_key = ""
|
var prop_key = ""
|
||||||
if id >= 0:
|
if id >= 0 and id < inventory.enabled_items.size():
|
||||||
prop_key = inventory.enabled_items[id]
|
prop_key = inventory.enabled_items[id]
|
||||||
else:
|
else:
|
||||||
prop_key = inventory.current_item_key()
|
prop_key = inventory.current_item_key()
|
||||||
|
|
||||||
if prop_key:
|
if prop_key:
|
||||||
sfx_inspect.play()
|
sfx_inspect.play()
|
||||||
print("[PropHud] inspect prop:", prop_key)
|
print("[PropHud] inspect prop:", prop_key)
|
||||||
@ -327,36 +390,36 @@ func _on_prop_inspected(id := 0) -> void:
|
|||||||
func _on_prop_pressed(id := 0) -> void:
|
func _on_prop_pressed(id := 0) -> void:
|
||||||
if locked:
|
if locked:
|
||||||
return
|
return
|
||||||
|
|
||||||
sfx_click.play()
|
sfx_click.play()
|
||||||
if GlobalConfig.DEBUG:
|
if GlobalConfig.DEBUG:
|
||||||
print("PropHUD Panel pressed.")
|
print("PropHUD Panel pressed.")
|
||||||
|
|
||||||
focus_mode = FOCUS_ALL
|
focus_mode = FOCUS_ALL
|
||||||
grab_focus()
|
grab_focus()
|
||||||
if id >= 0:
|
|
||||||
|
if id >= 0 and id < inventory.enabled_items.size():
|
||||||
inventory.current_index = id
|
inventory.current_index = id
|
||||||
|
|
||||||
_update_prop_display_with_texture()
|
_update_prop_display_with_texture()
|
||||||
_mouse_moved_on_listening(true)
|
_mouse_moved_on_listening(true)
|
||||||
|
|
||||||
|
|
||||||
var prop_blink: Tween
|
|
||||||
var tween_scroll: Tween
|
|
||||||
|
|
||||||
|
|
||||||
func _toggle_scroll(fold := true) -> void:
|
func _toggle_scroll(fold := true) -> void:
|
||||||
if prop_blink and prop_blink.is_running():
|
if prop_blink and prop_blink.is_running():
|
||||||
prop_blink.kill()
|
prop_blink.kill()
|
||||||
if tween_scroll and tween_scroll.is_running():
|
if tween_scroll and tween_scroll.is_running():
|
||||||
tween_scroll.kill()
|
tween_scroll.kill()
|
||||||
# PROP_CONTAINER_X + 10. 为hud的两侧留出的空间
|
|
||||||
if fold:
|
if fold:
|
||||||
# kill blink
|
# kill blink
|
||||||
select_mark.modulate.a = 1.0
|
select_mark.modulate.a = 1.0
|
||||||
selecting_bg.modulate.a = 0.0
|
selecting_bg.modulate.a = 0.0
|
||||||
# fold
|
# fold
|
||||||
tween_scroll = create_tween()
|
tween_scroll = create_tween()
|
||||||
tween_scroll.tween_property(props_bag_scroll, "custom_minimum_size:x", 0.0, 0.5)
|
tween_scroll.tween_property(props_bag_scroll, "custom_minimum_size:x", 0.0, TWEEN_DURATION)
|
||||||
tween_scroll.parallel().tween_property(
|
tween_scroll.parallel().tween_property(
|
||||||
hud_rect, "custom_minimum_size:x", PROP_CONTAINER_X + 10., 0.5
|
hud_rect, "custom_minimum_size:x", PROP_CONTAINER_X + 10., TWEEN_DURATION
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
# blink
|
# blink
|
||||||
@ -372,12 +435,17 @@ func _toggle_scroll(fold := true) -> void:
|
|||||||
prop_blink.parallel().tween_property(selecting_bg, "modulate:a", .6, 1.).set_ease(
|
prop_blink.parallel().tween_property(selecting_bg, "modulate:a", .6, 1.).set_ease(
|
||||||
Tween.EASE_IN_OUT
|
Tween.EASE_IN_OUT
|
||||||
)
|
)
|
||||||
|
|
||||||
# unfold
|
# unfold
|
||||||
var bag_x = prop_containers.size() * PROP_CONTAINER_X
|
var bag_x = prop_containers.size() * PROP_CONTAINER_X
|
||||||
var hud_x = bag_x + PROP_CONTAINER_X + 10.
|
var hud_x = bag_x + PROP_CONTAINER_X + 10.
|
||||||
tween_scroll = create_tween()
|
tween_scroll = create_tween()
|
||||||
tween_scroll.tween_property(props_bag_scroll, "custom_minimum_size:x", bag_x, 0.5)
|
tween_scroll.tween_property(
|
||||||
tween_scroll.parallel().tween_property(hud_rect, "custom_minimum_size:x", hud_x, 0.5)
|
props_bag_scroll, "custom_minimum_size:x", bag_x, TWEEN_DURATION
|
||||||
|
)
|
||||||
|
tween_scroll.parallel().tween_property(
|
||||||
|
hud_rect, "custom_minimum_size:x", hud_x, TWEEN_DURATION
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
func _on_mouse_entered() -> void:
|
func _on_mouse_entered() -> void:
|
||||||
@ -394,9 +462,11 @@ func _on_mouse_exited() -> void:
|
|||||||
func _mouse_moved_on_listening(unfold_scroll := false) -> void:
|
func _mouse_moved_on_listening(unfold_scroll := false) -> void:
|
||||||
if unfold_scroll:
|
if unfold_scroll:
|
||||||
_toggle_scroll(false)
|
_toggle_scroll(false)
|
||||||
|
|
||||||
if not displaying:
|
if not displaying:
|
||||||
_toggle_details(true)
|
_toggle_details(true)
|
||||||
return
|
return
|
||||||
|
|
||||||
timer.start(display_time)
|
timer.start(display_time)
|
||||||
|
|
||||||
|
|
||||||
@ -408,6 +478,7 @@ func _on_timer_timeout() -> void:
|
|||||||
func _unhandled_input(event: InputEvent) -> void:
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
if locked or not listening_hotkey:
|
if locked or not listening_hotkey:
|
||||||
return
|
return
|
||||||
|
|
||||||
if event.is_action_pressed("prop_left"):
|
if event.is_action_pressed("prop_left"):
|
||||||
on_left_pressed()
|
on_left_pressed()
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
@ -415,10 +486,13 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||||||
on_right_pressed()
|
on_right_pressed()
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
elif event is InputEventMouseButton:
|
elif event is InputEventMouseButton:
|
||||||
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN and event.pressed:
|
var mouse_event = event as InputEventMouseButton
|
||||||
|
if mouse_event.pressed:
|
||||||
|
match mouse_event.button_index:
|
||||||
|
MOUSE_BUTTON_WHEEL_DOWN:
|
||||||
on_left_pressed()
|
on_left_pressed()
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
elif event.button_index == MOUSE_BUTTON_WHEEL_UP and event.pressed:
|
MOUSE_BUTTON_WHEEL_UP:
|
||||||
on_right_pressed()
|
on_right_pressed()
|
||||||
get_viewport().set_input_as_handled()
|
get_viewport().set_input_as_handled()
|
||||||
|
|
||||||
@ -426,6 +500,7 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||||||
func _input(event: InputEvent) -> void:
|
func _input(event: InputEvent) -> void:
|
||||||
if locked:
|
if locked:
|
||||||
return
|
return
|
||||||
|
|
||||||
if listen_mouse and (event is InputEventMouseMotion or event is InputEventScreenTouch):
|
if listen_mouse and (event is InputEventMouseMotion or event is InputEventScreenTouch):
|
||||||
_mouse_moved_on_listening()
|
_mouse_moved_on_listening()
|
||||||
|
|
||||||
@ -446,7 +521,6 @@ func _toggle_details(display := true) -> void:
|
|||||||
display_tween.parallel().tween_property(title_label, "modulate:a", 0.0, 0.6)
|
display_tween.parallel().tween_property(title_label, "modulate:a", 0.0, 0.6)
|
||||||
display_tween.parallel().tween_property(left_btn, "modulate:a", 0.5, 0.5)
|
display_tween.parallel().tween_property(left_btn, "modulate:a", 0.5, 0.5)
|
||||||
display_tween.parallel().tween_property(right_btn, "modulate:a", 0.5, 0.5)
|
display_tween.parallel().tween_property(right_btn, "modulate:a", 0.5, 0.5)
|
||||||
# display_tween.tween_callback(_toggle_btn_ability.bind(false))
|
|
||||||
timer.stop()
|
timer.stop()
|
||||||
|
|
||||||
|
|
||||||
@ -458,11 +532,14 @@ func _toggle_btn_ability(v: bool) -> void:
|
|||||||
func enable_important_item(prop_key: String, display_inspector: bool) -> void:
|
func enable_important_item(prop_key: String, display_inspector: bool) -> void:
|
||||||
if not inventory or not prop_key:
|
if not inventory or not prop_key:
|
||||||
return
|
return
|
||||||
|
|
||||||
if not items_dict.has(prop_key):
|
if not items_dict.has(prop_key):
|
||||||
push_error("ImportantPropItem not found! key=" + prop_key)
|
push_error("ImportantPropItem not found! key=" + prop_key)
|
||||||
return
|
return
|
||||||
|
|
||||||
inventory.enable_important_item(prop_key)
|
inventory.enable_important_item(prop_key)
|
||||||
SceneManager.pop_notification("ui_notify_important_item_update")
|
SceneManager.pop_notification("ui_notify_important_item_update")
|
||||||
|
|
||||||
if display_inspector:
|
if display_inspector:
|
||||||
sfx_inspect.play()
|
sfx_inspect.play()
|
||||||
inspect_item(prop_key, true, true)
|
inspect_item(prop_key, true, true)
|
||||||
@ -472,37 +549,39 @@ func enable_prop_item(prop_key: String, inspect := true) -> void:
|
|||||||
if not inventory or not prop_key:
|
if not inventory or not prop_key:
|
||||||
printerr("PropHUD Enable prop item: No inventory or prop_key provided.")
|
printerr("PropHUD Enable prop item: No inventory or prop_key provided.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if not items_dict.has(prop_key):
|
if not items_dict.has(prop_key):
|
||||||
push_error("PropItem not found! key=" + prop_key)
|
push_error("PropItem not found! key=" + prop_key)
|
||||||
return
|
return
|
||||||
|
|
||||||
inventory.enable_item(prop_key)
|
inventory.enable_item(prop_key)
|
||||||
_reload_cache_and_realign_display()
|
_reload_cache_and_realign_display()
|
||||||
|
|
||||||
if GlobalConfig.DEBUG:
|
if GlobalConfig.DEBUG:
|
||||||
print("PropHUD Enable prop item:", prop_key)
|
print("PropHUD Enable prop item:", prop_key)
|
||||||
|
|
||||||
if inspect:
|
if inspect:
|
||||||
sfx_new_prop.play()
|
sfx_new_prop.play()
|
||||||
inspect_item(prop_key)
|
inspect_item(prop_key)
|
||||||
|
|
||||||
|
|
||||||
func inspect_item(prop_key: String, display_obtained := true, as_important_item := false):
|
func inspect_item(prop_key: String, display_obtained := true, as_important_item := false):
|
||||||
var inspector = SceneManager.get_inspector()
|
var inspector = SceneManager.get_inspector() as PropInspector
|
||||||
if inspector:
|
if not inspector or not items_dict.has(prop_key):
|
||||||
var texture_path = items_dict[prop_key].texture_path
|
return
|
||||||
var inspect_path = items_dict[prop_key].inspect_path
|
var item = items_dict[prop_key]
|
||||||
# 是否有独立的 inspect 图片
|
var texture: Texture2D = null
|
||||||
if inspect_path:
|
# 检查是否有独立的 inspect 图片
|
||||||
var texture = load(inspect_path) as Texture2D
|
if item.inspect_path:
|
||||||
inspector.pop_prop_inspection(
|
texture = load(item.inspect_path) as Texture2D
|
||||||
prop_key, texture, display_obtained, as_important_item
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
var texture = cached_inventory_textures.get(prop_key)
|
texture = cached_inventory_textures.get(prop_key)
|
||||||
if not texture:
|
if not texture and item.texture_path:
|
||||||
texture = load(texture_path) as Texture2D
|
texture = load(item.texture_path) as Texture2D
|
||||||
if texture:
|
if texture:
|
||||||
cached_inventory_textures[prop_key] = texture
|
cached_inventory_textures[prop_key] = texture
|
||||||
else:
|
if not texture:
|
||||||
printerr("prophud inspect_item invalid texture_path:", texture_path)
|
printerr("prophud inspect_item invalid texture for key:", prop_key)
|
||||||
return
|
return
|
||||||
inspector.pop_prop_inspection(
|
inspector.pop_prop_inspection(
|
||||||
prop_key, texture, display_obtained, as_important_item
|
prop_key, texture, display_obtained, as_important_item
|
||||||
@ -517,16 +596,21 @@ func disable_prop_item(prop_key: String) -> void:
|
|||||||
|
|
||||||
|
|
||||||
func _align_container_size() -> void:
|
func _align_container_size() -> void:
|
||||||
# 判断是否需要添加新的 prop container
|
if not inventory:
|
||||||
|
return
|
||||||
|
|
||||||
|
# 添加新容器
|
||||||
while inventory.enabled_items.size() > prop_containers.size():
|
while inventory.enabled_items.size() > prop_containers.size():
|
||||||
append_prop_container()
|
append_prop_container()
|
||||||
# 判断是否需要删除 prop container,不保留余数
|
|
||||||
|
# 删除多余容器
|
||||||
while inventory.enabled_items.size() < prop_containers.size():
|
while inventory.enabled_items.size() < prop_containers.size():
|
||||||
remove_prop_container()
|
remove_prop_container()
|
||||||
|
|
||||||
if displaying:
|
if displaying:
|
||||||
_mouse_moved_on_listening()
|
_mouse_moved_on_listening()
|
||||||
# 如果正在展示,则更新 scroll 长度
|
# 如果正在展示,则更新 scroll 长度
|
||||||
if displaying and props_bag_scroll.custom_minimum_size.x > 0.0:
|
if props_bag_scroll.custom_minimum_size.x > 0.0:
|
||||||
_toggle_scroll(false)
|
_toggle_scroll(false)
|
||||||
|
|
||||||
|
|
||||||
@ -534,58 +618,65 @@ func append_prop_container() -> void:
|
|||||||
var container = CenterContainer.new()
|
var container = CenterContainer.new()
|
||||||
container.custom_minimum_size = Vector2(PROP_CONTAINER_X, PROP_CONTAINER_X)
|
container.custom_minimum_size = Vector2(PROP_CONTAINER_X, PROP_CONTAINER_X)
|
||||||
container.set_anchors_preset(Control.PRESET_FULL_RECT)
|
container.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
prop_containers.append(container)
|
|
||||||
var control = Control.new()
|
var control = Control.new()
|
||||||
control.custom_minimum_size = Vector2(PROP_CONTROL_X, PROP_CONTROL_X)
|
control.custom_minimum_size = Vector2(PROP_CONTROL_X, PROP_CONTROL_X)
|
||||||
control.set_anchors_preset(Control.PRESET_FULL_RECT)
|
control.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||||
container.add_child(control)
|
container.add_child(control)
|
||||||
|
|
||||||
var prop = TextureButton.new()
|
var prop = TextureButton.new()
|
||||||
prop.stretch_mode = TextureButton.STRETCH_KEEP_ASPECT_CENTERED
|
prop.stretch_mode = TextureButton.STRETCH_KEEP_ASPECT_CENTERED
|
||||||
control.add_child(prop)
|
control.add_child(prop)
|
||||||
# 添加到 hbox: container -> control -> prop
|
|
||||||
props_bag.add_child(container)
|
props_bag.add_child(container)
|
||||||
prop.gui_input.connect(_on_prop_gui_input.bind(prop_containers.size() - 1))
|
prop_containers.append(container)
|
||||||
|
|
||||||
|
var index = prop_containers.size() - 1
|
||||||
|
prop.gui_input.connect(_on_prop_gui_input.bind(index))
|
||||||
|
|
||||||
|
|
||||||
func remove_prop_container() -> void:
|
func remove_prop_container() -> void:
|
||||||
if prop_containers.size() == 0:
|
if prop_containers.is_empty():
|
||||||
return
|
return
|
||||||
|
|
||||||
var container = prop_containers.pop_back()
|
var container = prop_containers.pop_back()
|
||||||
|
if container and is_instance_valid(container):
|
||||||
props_bag.remove_child(container)
|
props_bag.remove_child(container)
|
||||||
container.queue_free()
|
container.queue_free()
|
||||||
|
|
||||||
|
|
||||||
var shake_tween
|
|
||||||
|
|
||||||
|
|
||||||
# 使用无效道具,抖动提示
|
|
||||||
func on_toggle_invalid_prop():
|
func on_toggle_invalid_prop():
|
||||||
if not inventory or not inventory.current_item_key():
|
if not inventory or not inventory.current_item_key():
|
||||||
return
|
return
|
||||||
|
|
||||||
if GlobalConfig.DEBUG:
|
if GlobalConfig.DEBUG:
|
||||||
print("使用无效道具. invalid_prop shake. current prop:", inventory.current_item_key())
|
print("使用无效道具. invalid_prop shake. current prop:", inventory.current_item_key())
|
||||||
if shake_tween:
|
|
||||||
|
if shake_tween and shake_tween.is_running():
|
||||||
shake_tween.kill()
|
shake_tween.kill()
|
||||||
# 抖动效果,逐渐减弱
|
|
||||||
|
# 抖动效果
|
||||||
shake_tween = create_tween()
|
shake_tween = create_tween()
|
||||||
var fps := 15.0
|
var count = int(SHAKE_DURATION * SHAKE_FPS)
|
||||||
var duration := 0.8
|
var delta_t = 1.0 / SHAKE_FPS
|
||||||
var delta := 12.0
|
|
||||||
var origin_pos = Vector2.ZERO
|
var origin_pos = Vector2.ZERO
|
||||||
var count = int(duration * fps)
|
|
||||||
var delta_t = 1.0 / fps
|
|
||||||
var prop = display_prop
|
var prop = display_prop
|
||||||
# var prop = prop_containers[0].get_child(0)
|
|
||||||
prop.modulate = Color(1.0, 0.6, 0.6, 1.0)
|
prop.modulate = Color(1.0, 0.6, 0.6, 1.0)
|
||||||
|
|
||||||
for i in range(count):
|
for i in range(count):
|
||||||
var offset = Vector2(randf_range(-delta, delta), randf_range(-delta, delta)) * exp(-i)
|
var decay = exp(-i)
|
||||||
|
var offset = Vector2(
|
||||||
|
randf_range(-SHAKE_DELTA, SHAKE_DELTA) * decay,
|
||||||
|
randf_range(-SHAKE_DELTA, SHAKE_DELTA) * decay
|
||||||
|
)
|
||||||
shake_tween.tween_property(prop, "position", origin_pos + offset, delta_t).set_trans(
|
shake_tween.tween_property(prop, "position", origin_pos + offset, delta_t).set_trans(
|
||||||
Tween.TRANS_CUBIC
|
Tween.TRANS_CUBIC
|
||||||
)
|
)
|
||||||
|
|
||||||
shake_tween.tween_callback(_reset_prop_modulate)
|
shake_tween.tween_callback(_reset_prop_modulate)
|
||||||
|
|
||||||
|
|
||||||
func _reset_prop_modulate():
|
func _reset_prop_modulate():
|
||||||
var prop = display_prop
|
if display_prop:
|
||||||
# var prop = prop_containers[0].get_child(0)
|
display_prop.modulate = Color.WHITE
|
||||||
prop.modulate = Color(1.0, 1.0, 1.0, 1.0)
|
|
||||||
|
Loading…
Reference in New Issue
Block a user