All pastes #9WZZh4rCFa Raw Edit

text paste

public text v1 · immutable
#9WZZh4rCFa ·published 2026-06-09 02:48 UTC ·by Huanglingyun1106@gmail.com
rendered paste body
# 项目目录结构树

- **根目录**: `D:\godot project\aowoo_qiaoqiao_shouzhang`
- **导出时间**: 2026/06/09 周二 10:47:27.07

```text
aowoo_qiaoqiao_shouzhang/
├── .editorconfig
├── .gitattributes
├── .gitignore
├── GlobalInputHook.cs
├── GlobalInputHook.cs.uid
├── LICENSE
├── README.md
├── aowoo_qiaoqiao_shouzhang.csproj
├── aowoo_qiaoqiao_shouzhang.sln
├── assets
│   ├── audio
│   │   ├── ComfyUI_00033_.wav
│   │   ├── ComfyUI_00033_.wav.import
│   │   └── sfx
│   │       ├── Bell Church 2.wav
│   │       ├── Bell Church 2.wav.import
│   │       ├── Bubbles00.wav
│   │       └── Bubbles00.wav.import
│   ├── sprites
│   │   ├── environment
│   │   │   ├── house.png
│   │   │   ├── house.png.import
│   │   │   ├── plus_one.png
│   │   │   ├── plus_one.png.import
│   │   │   ├── prop_car.png
│   │   │   ├── prop_car.png.import
│   │   │   ├── prop_站立aowoo.png
│   │   │   ├── prop_站立aowoo.png.import
│   │   │   ├── 下层水.png
│   │   │   ├── 下层水.png.import
│   │   │   ├── 下层草.png
│   │   │   ├── 下层草.png.import
│   │   │   ├── 云1.png
│   │   │   ├── 云1.png.import
│   │   │   ├── 云10.png
│   │   │   ├── 云10.png.import
│   │   │   ├── 云2.png
│   │   │   ├── 云2.png.import
│   │   │   ├── 云3.png
│   │   │   ├── 云3.png.import
│   │   │   ├── 云4.png
│   │   │   ├── 云4.png.import
│   │   │   ├── 云5.png
│   │   │   ├── 云5.png.import
│   │   │   ├── 云6.png
│   │   │   ├── 云6.png.import
│   │   │   ├── 云7.png
│   │   │   ├── 云7.png.import
│   │   │   ├── 云8.png
│   │   │   ├── 云8.png.import
│   │   │   ├── 云9.png
│   │   │   ├── 云9.png.import
│   │   │   ├── 前景兔秋花01.png
│   │   │   ├── 前景兔秋花01.png.import
│   │   │   ├── 前景兔秋花02.png
│   │   │   ├── 前景兔秋花02.png.import
│   │   │   ├── 前景兔秋花03.png
│   │   │   ├── 前景兔秋花03.png.import
│   │   │   ├── 前景右01.png
│   │   │   ├── 前景右01.png.import
│   │   │   ├── 前景右02.png
│   │   │   ├── 前景右02.png.import
│   │   │   ├── 前景右03.png
│   │   │   ├── 前景右03.png.import
│   │   │   ├── 前景右04.png
│   │   │   ├── 前景右04.png.import
│   │   │   ├── 前景左01.png
│   │   │   ├── 前景左01.png.import
│   │   │   ├── 前景左02.png
│   │   │   ├── 前景左02.png.import
│   │   │   ├── 前景左03.png
│   │   │   ├── 前景左03.png.import
│   │   │   ├── 前景左04.png
│   │   │   ├── 前景左04.png.import
│   │   │   ├── 前景左05.png
│   │   │   ├── 前景左05.png.import
│   │   │   ├── 背景.png
│   │   │   ├── 背景.png.import
│   │   │   ├── 背景小树01.png
│   │   │   ├── 背景小树01.png.import
│   │   │   ├── 背景小树02.png
│   │   │   ├── 背景小树02.png.import
│   │   │   ├── 背景小树03.png
│   │   │   ├── 背景小树03.png.import
│   │   │   ├── 背景山.png
│   │   │   ├── 背景山.png.import
│   │   │   ├── 花洒.png
│   │   │   ├── 花洒.png.import
│   │   │   ├── 花花01.png
│   │   │   ├── 花花01.png.import
│   │   │   ├── 花花02.png
│   │   │   ├── 花花02.png.import
│   │   │   ├── 花花03.png
│   │   │   ├── 花花03.png.import
│   │   │   ├── 花花04.png
│   │   │   ├── 花花04.png.import
│   │   │   ├── 草坪.png
│   │   │   ├── 草坪.png.import
│   │   │   ├── 键盘定位.png
│   │   │   └── 键盘定位.png.import
│   │   ├── items
│   │   │   ├── theme_00_default
│   │   │   │   ├── crops
│   │   │   │   │   ├── chest
│   │   │   │   │   │   ├── chest_stage_0.png
│   │   │   │   │   │   ├── chest_stage_0.png.import
│   │   │   │   │   │   ├── chest_stage_1.png
│   │   │   │   │   │   ├── chest_stage_1.png.import
│   │   │   │   │   │   ├── chest_stage_2.png
│   │   │   │   │   │   ├── chest_stage_2.png.import
│   │   │   │   │   │   ├── chest_stage_3.png
│   │   │   │   │   │   ├── chest_stage_3.png.import
│   │   │   │   │   │   ├── chest_stage_4.png
│   │   │   │   │   │   ├── chest_stage_4.png.import
│   │   │   │   │   │   ├── chest_stage_5.png
│   │   │   │   │   │   └── chest_stage_5.png.import
│   │   │   │   │   ├── luobobo
│   │   │   │   │   │   ├── luobobo_stage_0.png
│   │   │   │   │   │   ├── luobobo_stage_0.png.import
│   │   │   │   │   │   ├── luobobo_stage_1.png
│   │   │   │   │   │   ├── luobobo_stage_1.png.import
│   │   │   │   │   │   ├── luobobo_stage_2.png
│   │   │   │   │   │   ├── luobobo_stage_2.png.import
│   │   │   │   │   │   ├── luobobo_stage_3.png
│   │   │   │   │   │   ├── luobobo_stage_3.png.import
│   │   │   │   │   │   ├── luobobo_stage_4.png
│   │   │   │   │   │   ├── luobobo_stage_4.png.import
│   │   │   │   │   │   ├── luobobo_stage_5.png
│   │   │   │   │   │   └── luobobo_stage_5.png.import
│   │   │   │   │   ├── tuqiuhua
│   │   │   │   │   │   ├── tuqiuhua_stage_0.png
│   │   │   │   │   │   ├── tuqiuhua_stage_0.png.import
│   │   │   │   │   │   ├── tuqiuhua_stage_1.png
│   │   │   │   │   │   ├── tuqiuhua_stage_1.png.import
│   │   │   │   │   │   ├── tuqiuhua_stage_2.png
│   │   │   │   │   │   ├── tuqiuhua_stage_2.png.import
│   │   │   │   │   │   ├── tuqiuhua_stage_3.png
│   │   │   │   │   │   ├── tuqiuhua_stage_3.png.import
│   │   │   │   │   │   ├── tuqiuhua_stage_4.png
│   │   │   │   │   │   ├── tuqiuhua_stage_4.png.import
│   │   │   │   │   │   ├── tuqiuhua_stage_5.png
│   │   │   │   │   │   └── tuqiuhua_stage_5.png.import
│   │   │   │   │   └── yayajun
│   │   │   │   │       ├── yayajun_stage_0.png
│   │   │   │   │       ├── yayajun_stage_0.png.import
│   │   │   │   │       ├── yayajun_stage_1.png
│   │   │   │   │       ├── yayajun_stage_1.png.import
│   │   │   │   │       ├── yayajun_stage_2.png
│   │   │   │   │       ├── yayajun_stage_2.png.import
│   │   │   │   │       ├── yayajun_stage_3.png
│   │   │   │   │       ├── yayajun_stage_3.png.import
│   │   │   │   │       ├── yayajun_stage_4.png
│   │   │   │   │       ├── yayajun_stage_4.png.import
│   │   │   │   │       ├── yayajun_stage_5.png
│   │   │   │   │       └── yayajun_stage_5.png.import
│   │   │   │   ├── pots
│   │   │   │   │   ├── pot_default_size_0.png
│   │   │   │   │   ├── pot_default_size_0.png.import
│   │   │   │   │   ├── pot_default_size_1.png
│   │   │   │   │   ├── pot_default_size_1.png.import
│   │   │   │   │   ├── pot_default_size_2.png
│   │   │   │   │   ├── pot_default_size_2.png.import
│   │   │   │   │   ├── pot_default_size_3.png
│   │   │   │   │   ├── pot_default_size_3.png.import
│   │   │   │   │   ├── pot_default_size_4.png
│   │   │   │   │   └── pot_default_size_4.png.import
│   │   │   │   └── stickers
│   │   │   ├── theme_01_spring
│   │   │   │   ├── crops
│   │   │   │   ├── pots
│   │   │   │   └── stickers
│   │   │   ├── theme_02_summer
│   │   │   │   ├── crops
│   │   │   │   ├── pots
│   │   │   │   └── stickers
│   │   │   ├── theme_03_autumn
│   │   │   │   ├── crops
│   │   │   │   ├── pots
│   │   │   │   └── stickers
│   │   │   └── theme_04_winter
│   │   │       ├── crops
│   │   │       ├── pots
│   │   │       └── stickers
│   │   ├── letters
│   │   │   ├── 0.png
│   │   │   ├── 0.png.import
│   │   │   ├── 1.png
│   │   │   ├── 1.png.import
│   │   │   ├── 2.png
│   │   │   ├── 2.png.import
│   │   │   ├── 3.png
│   │   │   ├── 3.png.import
│   │   │   ├── 4.png
│   │   │   ├── 4.png.import
│   │   │   ├── 5.png
│   │   │   ├── 5.png.import
│   │   │   ├── 6.png
│   │   │   ├── 6.png.import
│   │   │   ├── 7.png
│   │   │   ├── 7.png.import
│   │   │   ├── 8.png
│   │   │   ├── 8.png.import
│   │   │   ├── 9.png
│   │   │   ├── 9.png.import
│   │   │   ├── a.png
│   │   │   ├── a.png.import
│   │   │   ├── alt.png
│   │   │   ├── alt.png.import
│   │   │   ├── apostrophe.png
│   │   │   ├── apostrophe.png.import
│   │   │   ├── b.png
│   │   │   ├── b.png.import
│   │   │   ├── backslash.png
│   │   │   ├── backslash.png.import
│   │   │   ├── backspace.png
│   │   │   ├── backspace.png.import
│   │   │   ├── bracketleft.png
│   │   │   ├── bracketleft.png.import
│   │   │   ├── bracketright.png
│   │   │   ├── bracketright.png.import
│   │   │   ├── c.png
│   │   │   ├── c.png.import
│   │   │   ├── capslock.png
│   │   │   ├── capslock.png.import
│   │   │   ├── comma.png
│   │   │   ├── comma.png.import
│   │   │   ├── ctrl.png
│   │   │   ├── ctrl.png.import
│   │   │   ├── d.png
│   │   │   ├── d.png.import
│   │   │   ├── down.png
│   │   │   ├── down.png.import
│   │   │   ├── e.png
│   │   │   ├── e.png.import
│   │   │   ├── enter.png
│   │   │   ├── enter.png.import
│   │   │   ├── equal.png
│   │   │   ├── equal.png.import
│   │   │   ├── f.png
│   │   │   ├── f.png.import
│   │   │   ├── g.png
│   │   │   ├── g.png.import
│   │   │   ├── h.png
│   │   │   ├── h.png.import
│   │   │   ├── i.png
│   │   │   ├── i.png.import
│   │   │   ├── j.png
│   │   │   ├── j.png.import
│   │   │   ├── k.png
│   │   │   ├── k.png.import
│   │   │   ├── l.png
│   │   │   ├── l.png.import
│   │   │   ├── left.png
│   │   │   ├── left.png.import
│   │   │   ├── m.png
│   │   │   ├── m.png.import
│   │   │   ├── minus.png
│   │   │   ├── minus.png.import
│   │   │   ├── mouse.png
│   │   │   ├── mouse.png.import
│   │   │   ├── n.png
│   │   │   ├── n.png.import
│   │   │   ├── o.png
│   │   │   ├── o.png.import
│   │   │   ├── p.png
│   │   │   ├── p.png.import
│   │   │   ├── period.png
│   │   │   ├── period.png.import
│   │   │   ├── q.png
│   │   │   ├── q.png.import
│   │   │   ├── quoteleft.png
│   │   │   ├── quoteleft.png.import
│   │   │   ├── r.png
│   │   │   ├── r.png.import
│   │   │   ├── right.png
│   │   │   ├── right.png.import
│   │   │   ├── s.png
│   │   │   ├── s.png.import
│   │   │   ├── semicolon.png
│   │   │   ├── semicolon.png.import
│   │   │   ├── shift.png
│   │   │   ├── shift.png.import
│   │   │   ├── slash.png
│   │   │   ├── slash.png.import
│   │   │   ├── space.png
│   │   │   ├── space.png.import
│   │   │   ├── t.png
│   │   │   ├── t.png.import
│   │   │   ├── tab.png
│   │   │   ├── tab.png.import
│   │   │   ├── u.png
│   │   │   ├── u.png.import
│   │   │   ├── up.png
│   │   │   ├── up.png.import
│   │   │   ├── v.png
│   │   │   ├── v.png.import
│   │   │   ├── w.png
│   │   │   ├── w.png.import
│   │   │   ├── windows.png
│   │   │   ├── windows.png.import
│   │   │   ├── x.png
│   │   │   ├── x.png.import
│   │   │   ├── y.png
│   │   │   ├── y.png.import
│   │   │   ├── z.png
│   │   │   └── z.png.import
│   │   ├── ui
│   │   │   ├── icon_basket.png
│   │   │   ├── icon_basket.png.import
│   │   │   ├── icon_nav_journal.png
│   │   │   ├── icon_nav_journal.png.import
│   │   │   ├── icon_nav_keyboard.png
│   │   │   ├── icon_nav_keyboard.png.import
│   │   │   ├── icon_nav_settings.png
│   │   │   ├── icon_nav_settings.png.import
│   │   │   ├── journal_guide_bg.png
│   │   │   ├── journal_guide_bg.png.import
│   │   │   ├── journal_page_bg.png
│   │   │   ├── journal_page_bg.png.import
│   │   │   └── warehouse
│   │   │       ├── Gold_Bar.png
│   │   │       ├── Gold_Bar.png.import
│   │   │       ├── btn_sort_amount.png
│   │   │       ├── btn_sort_amount.png.import
│   │   │       ├── btn_sort_rarity.png
│   │   │       ├── btn_sort_rarity.png.import
│   │   │       ├── btn_sort_theme.png
│   │   │       ├── btn_sort_theme.png.import
│   │   │       ├── marketplace.png
│   │   │       ├── marketplace.png.import
│   │   │       ├── slider_grabber.png
│   │   │       ├── slider_grabber.png.import
│   │   │       ├── slot_rarity_0.png
│   │   │       ├── slot_rarity_0.png.import
│   │   │       ├── slot_rarity_1.png
│   │   │       ├── slot_rarity_1.png.import
│   │   │       ├── slot_rarity_2.png
│   │   │       ├── slot_rarity_2.png.import
│   │   │       ├── slot_rarity_3.png
│   │   │       ├── slot_rarity_3.png.import
│   │   │       ├── slot_sale.png
│   │   │       ├── slot_sale.png.import
│   │   │       ├── tab_category_crop.png
│   │   │       ├── tab_category_crop.png.import
│   │   │       ├── tab_category_pot.png
│   │   │       ├── tab_category_pot.png.import
│   │   │       ├── tab_category_sticker.png
│   │   │       ├── tab_category_sticker.png.import
│   │   │       ├── warehouse_bg.png
│   │   │       └── warehouse_bg.png.import
│   │   ├── 小怪兽键帽03.png
│   │   ├── 小怪兽键帽03.png.import
│   │   ├── 鳄鳄键帽04.png
│   │   └── 鳄鳄键帽04.png.import
│   ├── wave_noise.gdshader
│   └── wave_noise.gdshader.uid
├── export_presets.cfg
├── export_tree.py
├── main_keyboard.tscn
├── main_keyboard.tscn15041061776.tmp
├── pot_data.gd
├── pot_data.gd.uid
├── project.godot
├── resources
│   ├── base_item_data.gd
│   ├── base_item_data.gd.uid
│   ├── crop_master_database.tres
│   ├── crop_master_db.gd
│   ├── crop_master_db.gd.uid
│   ├── crop_weights.gd
│   ├── crop_weights.gd.uid
│   ├── default_weights.tres
│   └── pot_data_standard.tres
├── scenes
│   ├── game_prop.tscn
│   ├── global_warehouse.gd
│   ├── global_warehouse.gd.uid
│   ├── juice_jiggler.gd
│   ├── juice_jiggler.gd.uid
│   ├── key.gd
│   ├── key.gd.uid
│   ├── key.tscn
│   ├── main_keyboard.gd
│   ├── main_keyboard.gd.uid
│   └── ui
│       ├── inventory_slot.gd
│       ├── inventory_slot.gd.uid
│       ├── inventory_slot.tscn
│       ├── warehouse_window.gd
│       └── warehouse_window.gd.uid
├── warehouse_window.tscn
├── window_controller.gd
└── window_controller.gd.uid
```

-------------------
# File: res://GlobalInputHook.cs

using Godot;
using System;
using System.Runtime.InteropServices;

public partial class GlobalInputHook : Node
{
	// Win32 API 导入
	[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
	private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelProc lpfn, IntPtr hMod, uint dwThreadId);

	[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
	[return: MarshalAs(UnmanagedType.Bool)]
	private static extern bool UnhookWindowsHookEx(IntPtr hhk);

	[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
	private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

	[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
	private static extern IntPtr GetModuleHandle(string lpModuleName);

	// 钩子类型常量
	private const int WH_KEYBOARD_LL = 13;
	private const int WH_MOUSE_LL = 14;

	// 消息类型常量
	private const int WM_KEYDOWN = 0x0100;
	private const int WM_KEYUP = 0x0101;
	private const int WM_SYSKEYDOWN = 0x0104;
	private const int WM_SYSKEYUP = 0x0105;

	private const int WM_LBUTTONDOWN = 0x0201;
	private const int WM_LBUTTONUP = 0x0202;
	private const int WM_RBUTTONDOWN = 0x0204;
	private const int WM_RBUTTONUP = 0x0205;
	private const int WM_MBUTTONDOWN = 0x0206;
	private const int WM_MBUTTONUP = 0x0208;
	private const int WM_MOUSEWHEEL = 0x020A;

	// ==================== 核心新增:用于过滤长按自动重复的按键状态集合 ====================
	private System.Collections.Generic.HashSet<int> _pressedKeys = new System.Collections.Generic.HashSet<int>();

	[Signal]
	public delegate void GlobalKeyPressedEventHandler(int vkCode);
	[Signal]
	public delegate void GlobalMousePressedEventHandler(int buttonId, int x, int y);

	private delegate IntPtr LowLevelProc(int nCode, IntPtr wParam, IntPtr lParam);

	private LowLevelProc _keyboardProc;
	private LowLevelProc _mouseProc;
	private IntPtr _keyboardHookId = IntPtr.Zero;
	private IntPtr _mouseHookId = IntPtr.Zero;

	[StructLayout(LayoutKind.Sequential)]
	private struct POINT
	{
		public int x;
		public int y;
	}

	[StructLayout(LayoutKind.Sequential)]
	private struct MSLLHOOKSTRUCT
	{
		public POINT pt;
		public uint mouseData;
		public uint flags;
		public uint time;
		public IntPtr dwExtraInfo;
	}

	public override void _Ready()
	{
		// 保持委托引用,防止被垃圾回收
		_keyboardProc = LowLevelKeyboardProc;
		_mouseProc = LowLevelMouseProc;

		_keyboardHookId = SetHook(_keyboardProc, WH_KEYBOARD_LL);
		_mouseHookId = SetHook(_mouseProc, WH_MOUSE_LL);
	}

	public override void _ExitTree()
	{
		if (_keyboardHookId != IntPtr.Zero)
			UnhookWindowsHookEx(_keyboardHookId);
		if (_mouseHookId != IntPtr.Zero)
			UnhookWindowsHookEx(_mouseHookId);
	}

	private IntPtr SetHook(LowLevelProc proc, int hookType)
	{
		using (var curProcess = System.Diagnostics.Process.GetCurrentProcess())
		using (var curModule = curProcess.MainModule)
		{
			return SetWindowsHookEx(hookType, proc, GetModuleHandle(curModule.ModuleName), 0);
		}
	}

	// 键盘钩子回调函数
	private IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam)
	{
		if (nCode >= 0)
		{
			int vkCode = Marshal.ReadInt32(lParam);
			int message = (int)wParam;

			// ===== 过滤逻辑:判断是否为系统自动重复触发的连续 KEYDOWN =====
			if (message == WM_KEYDOWN || message == WM_SYSKEYDOWN)
			{
				// 如果 _pressedKeys 里还没有这个键,说明是玩家第一次真正“按下”
				if (!_pressedKeys.Contains(vkCode))
				{
					_pressedKeys.Add(vkCode); // 将按键记入集合,拦截随后的长按自动重复消息
					CallDeferred(MethodName.EmitSignal, SignalName.GlobalKeyPressed, vkCode);
				}
			}
			else if (message == WM_KEYUP || message == WM_SYSKEYUP)
			{
				// 玩家真正松开按键时,将按键从集合中移除,允许下一次点击
				_pressedKeys.Remove(vkCode);
			}
		}
		return CallNextHookEx(_keyboardHookId, nCode, wParam, lParam);
	}

	// 鼠标钩子回调函数
	private IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam)
	{
		if (nCode >= 0)
		{
			int message = (int)wParam;
			if (message == WM_LBUTTONDOWN || message == WM_RBUTTONDOWN || message == WM_MBUTTONDOWN)
			{
				MSLLHOOKSTRUCT hookStruct = Marshal.PtrToStructure<MSLLHOOKSTRUCT>(lParam);
				int buttonId = 0;
				if (message == WM_LBUTTONDOWN) buttonId = 1;
				else if (message == WM_RBUTTONDOWN) buttonId = 2;
				else if (message == WM_MBUTTONDOWN) buttonId = 3;

				CallDeferred(MethodName.EmitSignal, SignalName.GlobalMousePressed, buttonId, hookStruct.pt.x, hookStruct.pt.y);
			}
		}
		return CallNextHookEx(_mouseHookId, nCode, wParam, lParam);
	}
}

-------------------
# File: res://assets/wave_noise.gdshader

shader_type canvas_item;

// 💡 核心机制:直接向大世界索要全局共享的时间,确保全场景所有物体共享同一个噪声场
global uniform float global_noise_time;

// 🎛️ 暴露在面板上的 Blender 几何节点微调参数
// 🎛️ 💡 精准替换:完全按照你最新的截图数据同步锁定默认初始值,并取消了100的上限硬限制
uniform float wave_amplitude_x : hint_range(0.0, 0.2) = 0.01;   // Wave Amplitude X -> 默认 0.01
uniform float wave_amplitude_y : hint_range(0.0, 0.2) = 0.01;   // Wave Amplitude Y -> 默认 0.01
uniform float wave_frequency : hint_range(0.1, 20.0) = 1.915;   // Wave Frequency   -> 默认 0.836
uniform float noise_scale : hint_range(1.0, 1000.0, 0.1) = 206.6; // Noise Scale      -> 默认 100.0 (支持输入任意大数值)


// 💡 传送带变量:负责将 vertex 算好的世界坐标,安全合法地跨函数传递给 fragment 像素渲染
varying vec2 world_pos;

// 一种快速生成 2D 伪柏林噪波的经典数学函数(等同于 Blender 里的 Noise Texture 节点)
vec2 rand_noise(vec2 p) {
	p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
	return -1.0 + 2.0 * fract(sin(p) * 43758.5453123);
}

float perlin_noise(vec2 p) {
	vec2 i = floor(p);
	vec2 f = fract(p);
	vec2 u = f * f * (3.0 - 2.0 * f);
	return mix(mix(dot(rand_noise(i + vec2(0.0,0.0)), f - vec2(0.0,0.0)),
	               dot(rand_noise(i + vec2(1.0,0.0)), f - vec2(1.0,0.0)), u.x),
	           mix(dot(rand_noise(i + vec2(0.0,1.0)), f - vec2(0.0,1.0)),
	               dot(rand_noise(i + vec2(1.0,1.0)), f - vec2(1.0,1.0)), u.x), u.y);
}


void vertex() {
	// 💡 工业级强固方案:提取当前 Canvas 项在整个大世界大屏幕中的绝对像素坐标
	// 使用 MODEL_MATRIX 结合 CANVAS_MATRIX,彻底斩断任何父节点局部形变带来的干扰
	world_pos = (CANVAS_MATRIX * MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
}


void fragment() {
	// 计算噪波采样点:世界绝对坐标 / 噪波缩放 + 全局时间 * 频率速度
	vec2 noise_uv = world_pos / noise_scale + vec2(global_noise_time * wave_frequency);
	
	// 动态采样出当前坐标点在噪声纹理场里的扭曲位移量
	float noise_val_x = perlin_noise(noise_uv);
	float noise_val_y = perlin_noise(noise_uv + vec2(99.0)); // 偏移采样点防止XY完全等价连体扭曲
	
	// 将噪波偏移量等比叠加应用到物体原本的美术贴图 UV 上
	vec2 shifted_uv = UV;
	shifted_uv.x += noise_val_x * wave_amplitude_x;
	shifted_uv.y += noise_val_y * wave_amplitude_y;
	
	// 输出最终受到波浪噪波扭曲后的画面像素
	COLOR = texture(TEXTURE, shifted_uv);
}

-------------------
# File: res://main_keyboard.tscn

[gd_scene format=3 uid="uid://b5l7m6caa252b"]

[ext_resource type="PackedScene" uid="uid://c2n76yquwpiy2" path="res://scenes/key.tscn" id="1_kr6jc"]
[ext_resource type="Script" uid="uid://cxvuddquaminc" path="res://scenes/main_keyboard.gd" id="1_nk3ru"]
[ext_resource type="PackedScene" uid="uid://bpbanvymb1cmw" path="res://scenes/game_prop.tscn" id="2_t0ika"]
[ext_resource type="Texture2D" uid="uid://kkj0gfb337s3" path="res://assets/sprites/environment/背景.png" id="2_w6krq"]
[ext_resource type="Texture2D" uid="uid://cig1o0tdgbl5y" path="res://assets/sprites/items/theme_00_default/pots/pot_default_size_1.png" id="3_i4w03"]
[ext_resource type="Texture2D" uid="uid://ceakvpmwofvja" path="res://assets/sprites/environment/草坪.png" id="3_nk3ru"]
[ext_resource type="Texture2D" uid="uid://dbbeyxdom1t84" path="res://assets/sprites/items/theme_00_default/pots/pot_default_size_2.png" id="4_2kwox"]
[ext_resource type="Shader" uid="uid://bh0qpokppaj6p" path="res://assets/wave_noise.gdshader" id="4_cm383"]
[ext_resource type="Texture2D" uid="uid://csir761ao8o4k" path="res://assets/sprites/environment/背景山.png" id="4_nk78p"]
[ext_resource type="Texture2D" uid="uid://cxekr7is1l300" path="res://assets/sprites/environment/前景兔秋花02.png" id="5_8jng3"]
[ext_resource type="Texture2D" uid="uid://cnwuxhdopfau6" path="res://assets/sprites/environment/前景兔秋花01.png" id="5_23e38"]
[ext_resource type="Texture2D" uid="uid://tlqw75uui5wy" path="res://assets/sprites/environment/下层水.png" id="5_kr0tg"]
[ext_resource type="Texture2D" uid="uid://byvr3lv0k50wg" path="res://assets/sprites/environment/前景兔秋花03.png" id="6_gobuu"]
[ext_resource type="Texture2D" uid="uid://cpwb2dmfh7ho3" path="res://assets/sprites/environment/house.png" id="6_n443a"]
[ext_resource type="Texture2D" uid="uid://u31dw1uvmsrp" path="res://assets/sprites/environment/云1.png" id="6_pya6j"]
[ext_resource type="Texture2D" uid="uid://b3spkhu1d0yf4" path="res://assets/sprites/environment/prop_car.png" id="7_fqwq4"]
[ext_resource type="Texture2D" uid="uid://dlgfb1drowd0l" path="res://assets/sprites/environment/云3.png" id="9_8urr1"]
[ext_resource type="Texture2D" uid="uid://d3ltykpkcenhy" path="res://assets/sprites/environment/prop_站立aowoo.png" id="9_gq25e"]
[ext_resource type="Texture2D" uid="uid://bw1qw32020v83" path="res://assets/sprites/environment/花洒.png" id="10_57ie1"]
[ext_resource type="Texture2D" uid="uid://bvu08yk2prhvc" path="res://assets/sprites/environment/云2.png" id="10_43475"]
[ext_resource type="Texture2D" uid="uid://dthjeqnjtb5pa" path="res://assets/sprites/environment/云4.png" id="11_m81xy"]
[ext_resource type="Texture2D" uid="uid://bcdeajehlgevb" path="res://assets/sprites/environment/前景左05.png" id="11_wvmf6"]
[ext_resource type="Texture2D" uid="uid://dkv5im0nkss4e" path="res://assets/sprites/environment/云5.png" id="12_v116j"]
[ext_resource type="Texture2D" uid="uid://dkx10y6g5xr4m" path="res://assets/sprites/environment/云6.png" id="13_tlsoy"]
[ext_resource type="Texture2D" uid="uid://45qwqfw1jm7h" path="res://assets/sprites/letters/mouse.png" id="14_2uspe"]
[ext_resource type="Texture2D" uid="uid://c30hr4ixq3p1h" path="res://assets/sprites/environment/云7.png" id="14_h4gtp"]
[ext_resource type="Texture2D" uid="uid://ixptsvdlwo78" path="res://assets/sprites/小怪兽键帽03.png" id="15_8jng3"]
[ext_resource type="Texture2D" uid="uid://mdaeepeg346s" path="res://assets/sprites/鳄鳄键帽04.png" id="15_57ie1"]
[ext_resource type="Texture2D" uid="uid://cj0mhsvo5tcp2" path="res://assets/sprites/environment/云8.png" id="15_ufd0j"]
[ext_resource type="Texture2D" uid="uid://r8bx5q5fmtt5" path="res://assets/sprites/environment/云9.png" id="16_ee2ur"]
[ext_resource type="Texture2D" uid="uid://bcya33rs6dr1t" path="res://assets/sprites/environment/前景左04.png" id="16_owqlj"]
[ext_resource type="Texture2D" uid="uid://ki4td81gy8td" path="res://assets/sprites/environment/前景左03.png" id="17_gfwsj"]
[ext_resource type="Texture2D" uid="uid://cshj4xj7edh4g" path="res://assets/sprites/environment/下层草.png" id="17_mvx3b"]
[ext_resource type="Texture2D" uid="uid://bcuctuby31jio" path="res://assets/sprites/environment/云10.png" id="17_t184x"]
[ext_resource type="Texture2D" uid="uid://cms3acy043q34" path="res://assets/sprites/environment/花花01.png" id="24_v116j"]
[ext_resource type="Texture2D" uid="uid://cq05kqx7xv6n4" path="res://assets/sprites/environment/花花02.png" id="25_ufd0j"]
[ext_resource type="Texture2D" uid="uid://btxtsi2h27k0j" path="res://assets/sprites/environment/花花03.png" id="26_ee2ur"]
[ext_resource type="Texture2D" uid="uid://q3orph2io0h2" path="res://assets/sprites/environment/前景左02.png" id="26_fex6b"]
[ext_resource type="Texture2D" uid="uid://d3cecegydyve3" path="res://assets/sprites/environment/前景左01.png" id="27_sko6c"]
[ext_resource type="Texture2D" uid="uid://bhbmcectins34" path="res://assets/sprites/environment/花花04.png" id="27_t184x"]
[ext_resource type="Texture2D" uid="uid://cwy71ig1q4o63" path="res://assets/sprites/environment/背景小树01.png" id="28_ee2ur"]
[ext_resource type="Texture2D" uid="uid://crvoy72f50bhu" path="res://assets/sprites/environment/前景右04.png" id="28_sko6c"]
[ext_resource type="Texture2D" uid="uid://bhekru8ab5v2" path="res://assets/sprites/environment/前景右03.png" id="29_kr0tg"]
[ext_resource type="Texture2D" uid="uid://0spnj4rg8ixi" path="res://assets/sprites/environment/背景小树02.png" id="29_w6krq"]
[ext_resource type="Texture2D" uid="uid://dfknnxbf7dmn7" path="res://assets/sprites/environment/背景小树03.png" id="30_hmxrr"]
[ext_resource type="Texture2D" uid="uid://bvh423tes0nib" path="res://assets/sprites/environment/前景右02.png" id="30_mvx3b"]
[ext_resource type="Texture2D" uid="uid://bvd5q0pmtxpqq" path="res://assets/sprites/environment/前景右01.png" id="31_po3vl"]
[ext_resource type="Texture2D" uid="uid://c44fmo1eqqdoy" path="res://assets/sprites/ui/icon_nav_keyboard.png" id="34_po3vl"]
[ext_resource type="Texture2D" uid="uid://dh0yxi575caud" path="res://assets/sprites/ui/icon_nav_journal.png" id="35_1sb26"]
[ext_resource type="Texture2D" uid="uid://m673828me4py" path="res://assets/sprites/ui/icon_nav_settings.png" id="36_ledu6"]
[ext_resource type="Texture2D" uid="uid://dwlwo3bjx7h12" path="res://assets/sprites/ui/icon_basket.png" id="42_hmxrr"]

[sub_resource type="ShaderMaterial" id="ShaderMaterial_fqwq4"]
shader = ExtResource("4_cm383")
shader_parameter/wave_amplitude_x = 0.010000000475
shader_parameter/wave_amplitude_y = 0.010000000475
shader_parameter/wave_frequency = 0.80000003474012
shader_parameter/noise_scale = 371.5000055208946

[sub_resource type="ShaderMaterial" id="ShaderMaterial_n443a"]
shader = ExtResource("4_cm383")
shader_parameter/wave_amplitude_x = 0.002000000095
shader_parameter/wave_amplitude_y = 0.002000000095
shader_parameter/wave_frequency = 0.71700003079762
shader_parameter/noise_scale = 286.90000426025307

[sub_resource type="ShaderMaterial" id="ShaderMaterial_2uspe"]
shader = ExtResource("4_cm383")
shader_parameter/wave_amplitude_x = 0.010000000475
shader_parameter/wave_amplitude_y = 0.010000000475
shader_parameter/wave_frequency = 0.83600003645012
shader_parameter/noise_scale = 373.9000055566575

[sub_resource type="ShaderMaterial" id="ShaderMaterial_v116j"]
shader = ExtResource("4_cm383")
shader_parameter/wave_amplitude_x = 0.0210000009975
shader_parameter/wave_amplitude_y = 0.0210000009975
shader_parameter/wave_frequency = 1.99300009140762
shader_parameter/noise_scale = 229.60000340641432

[sub_resource type="ShaderMaterial" id="ShaderMaterial_hmxrr"]
shader = ExtResource("4_cm383")
shader_parameter/wave_amplitude_x = 0.010000000475
shader_parameter/wave_amplitude_y = 0.010000000475
shader_parameter/wave_frequency = 0.38000001479012
shader_parameter/noise_scale = 308.3000045791388

[node name="main_keyboard" type="Node2D" unique_id=135033407]
script = ExtResource("1_nk3ru")

[node name="_group_backgrounds" type="Node2D" parent="." unique_id=1296964689]
visible = false

[node name="CanvasLayer" type="CanvasLayer" parent="_group_backgrounds" unique_id=2100031870]
layer = -10
visible = false

[node name="TextureRect" type="TextureRect" parent="_group_backgrounds/CanvasLayer" unique_id=1442067626]
offset_right = 3840.0
offset_bottom = 2160.0
texture = ExtResource("2_w6krq")
stretch_mode = 2
metadata/_edit_lock_ = true

[node name="_group_props" type="Node2D" parent="." unique_id=595259724]

[node name="prop_down01" parent="_group_props" unique_id=1924461588 instance=ExtResource("2_t0ika")]
position = Vector2(1961.0001, 1967.0002)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_down01" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("5_kr0tg")
offset = Vector2(-20.835999, -8.245972)

[node name="prop_cloud03" parent="_group_props" unique_id=818559680 instance=ExtResource("2_t0ika")]
position = Vector2(3559.0002, 1192)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.02
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 2.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_cloud03" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("9_8urr1")
offset = Vector2(7.5792236, 0.4975586)

[node name="prop_cloud04" parent="_group_props" unique_id=2007690134 instance=ExtResource("2_t0ika")]
position = Vector2(563.00006, 818)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.02
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 2.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_cloud04" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("11_m81xy")
offset = Vector2(7.5792236, 0.4975586)

[node name="prop_cloud05" parent="_group_props" unique_id=276716972 instance=ExtResource("2_t0ika")]
position = Vector2(140, 1021.00006)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.02
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 2.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_cloud05" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("12_v116j")
offset = Vector2(7.5792236, 0.4975586)

[node name="prop_cloud06" parent="_group_props" unique_id=889473280 instance=ExtResource("2_t0ika")]
position = Vector2(124, 1230.0001)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.02
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 2.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_cloud06" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("13_tlsoy")
offset = Vector2(7.5792236, 0.4975586)

[node name="prop_cloud07" parent="_group_props" unique_id=659098496 instance=ExtResource("2_t0ika")]
position = Vector2(67.000015, 1705)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.02
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 2.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_cloud07" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("14_h4gtp")
offset = Vector2(7.5792236, 0.4975586)

[node name="prop_cloud08" parent="_group_props" unique_id=1517841495 instance=ExtResource("2_t0ika")]
position = Vector2(3522.9998, 864.00006)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.02
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 2.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_cloud08" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("15_ufd0j")
offset = Vector2(7.5792236, 0.4975586)

[node name="prop_cloud09" parent="_group_props" unique_id=1120739872 instance=ExtResource("2_t0ika")]
position = Vector2(3404, 1450)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.02
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 2.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_cloud09" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("16_ee2ur")
offset = Vector2(7.5792236, 0.4975586)

[node name="prop_cloud10" parent="_group_props" unique_id=1510477675 instance=ExtResource("2_t0ika")]
position = Vector2(3381, 1517)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.02
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 2.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_cloud10" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("17_t184x")
offset = Vector2(7.5792236, 0.4975586)

[node name="prop_cloud01" parent="_group_props" unique_id=668470827 instance=ExtResource("2_t0ika")]
position = Vector2(529, 571.0001)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.02
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_cloud01" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("6_pya6j")
offset = Vector2(7.5792236, 0.4975586)

[node name="prop_tuqiuhua02" parent="_group_props" unique_id=1578688765 instance=ExtResource("2_t0ika")]
position = Vector2(550, 1539.0001)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_tuqiuhua02" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("5_8jng3")
offset = Vector2(-100.61749, -316.4425)

[node name="prop_mountain" parent="_group_props" unique_id=1544944606 instance=ExtResource("2_t0ika")]
position = Vector2(1918, 1135)
scale = Vector2(1.21, 0.85)
squash_stretch_max_x = 1.0
squash_stretch_max_y = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_mountain" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_n443a")
position = Vector2(-31.168945, 757.5342)
texture = ExtResource("4_nk78p")
offset = Vector2(31.168945, -757.5342)

[node name="prop_house" parent="_group_props" unique_id=1242648082 instance=ExtResource("2_t0ika")]
position = Vector2(1020, 868)
scale = Vector2(0.95, 0.95)
squash_stretch_max_x = 1.01
squash_stretch_max_y = 1.02
juice_phase_offset = 0.985
juice_speed_override = 1.0
time_offset_override = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_house" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("6_n443a")
offset = Vector2(-11, -221.36084)

[node name="prop_car" parent="_group_props" unique_id=1124300276 instance=ExtResource("2_t0ika")]
position = Vector2(1658, 889)
scale = Vector2(0.94, 0.94)
squash_stretch_max_x = 1.002
squash_stretch_max_y = 1.005
juice_speed_override = 5.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_car" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("7_fqwq4")
offset = Vector2(-7.808511, -146.89276)

[node name="prop_grass" parent="_group_props" unique_id=1482026029 instance=ExtResource("2_t0ika")]
position = Vector2(1914, 1380)
scale = Vector2(1.25, 0.665)
squash_stretch_max_x = 1.0
squash_stretch_max_y = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_grass" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_2uspe")
position = Vector2(8, 744.36084)
texture = ExtResource("3_nk3ru")
offset = Vector2(-8, -744.36084)

[node name="prop_tuqiuhua03" parent="_group_props" unique_id=1629400034 instance=ExtResource("2_t0ika")]
position = Vector2(3484, 1831)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 3.395
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_tuqiuhua03" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("6_gobuu")
offset = Vector2(67.68817, -247.58997)

[node name="prop_tuqiuhua01" parent="_group_props" unique_id=1392977615 instance=ExtResource("2_t0ika")]
position = Vector2(398.00003, 1786.0001)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_tuqiuhua01" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("5_23e38")
offset = Vector2(-35.04373, -231.1969)

[node name="prop_left05" parent="_group_props" unique_id=1819660 instance=ExtResource("2_t0ika")]
position = Vector2(399, 1957)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_left05" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("11_wvmf6")
offset = Vector2(-0.071014404, -110.97815)

[node name="prop_cloud02" parent="_group_props" unique_id=2115279233 instance=ExtResource("2_t0ika")]
position = Vector2(3277, 727)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.02
juice_phase_offset = 5.0
juice_speed_override = 0.5
time_offset_override = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_cloud02" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("10_43475")
offset = Vector2(7.5792236, 0.4975586)

[node name="prop_huahua01" parent="_group_props" unique_id=388333503 instance=ExtResource("2_t0ika")]
position = Vector2(1369, 898)
squash_stretch_max_x = 1.0
squash_stretch_max_y = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_huahua01" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_v116j")
texture = ExtResource("24_v116j")
offset = Vector2(-7, -0.36083984)

[node name="prop_huahua02" parent="_group_props" unique_id=119665447 instance=ExtResource("2_t0ika")]
position = Vector2(2698, 878)
squash_stretch_max_x = 1.0
squash_stretch_max_y = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_huahua02" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_v116j")
texture = ExtResource("25_ufd0j")
offset = Vector2(-7, -0.36083984)

[node name="prop_huahua03" parent="_group_props" unique_id=875513102 instance=ExtResource("2_t0ika")]
position = Vector2(1030, 1958)
squash_stretch_max_x = 1.0
squash_stretch_max_y = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_huahua03" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_v116j")
texture = ExtResource("26_ee2ur")
offset = Vector2(-7, -0.36083984)

[node name="prop_huahua04" parent="_group_props" unique_id=2101183212 instance=ExtResource("2_t0ika")]
position = Vector2(2875, 1945)
squash_stretch_max_x = 1.0
squash_stretch_max_y = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_huahua04" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_v116j")
texture = ExtResource("27_t184x")
offset = Vector2(-7, -0.36083984)

[node name="prop_tree01" parent="_group_props" unique_id=1521400257 instance=ExtResource("2_t0ika")]
position = Vector2(1358, 495)
squash_stretch_max_x = 1.0
squash_stretch_max_y = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_tree01" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_v116j")
texture = ExtResource("28_ee2ur")
offset = Vector2(-7, -0.36083984)

[node name="prop_tree02" parent="_group_props" unique_id=888885610 instance=ExtResource("2_t0ika")]
position = Vector2(2675, 460)
squash_stretch_max_x = 1.0
squash_stretch_max_y = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_tree02" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_v116j")
texture = ExtResource("29_w6krq")
offset = Vector2(-7, -0.36083984)

[node name="prop_tree03" parent="_group_props" unique_id=1295421271 instance=ExtResource("2_t0ika")]
position = Vector2(3043, 555)
squash_stretch_max_x = 1.0
squash_stretch_max_y = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_tree03" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_v116j")
texture = ExtResource("30_hmxrr")
offset = Vector2(-7, -0.36083984)

[node name="prop_down02" parent="_group_props" unique_id=2098158156 instance=ExtResource("2_t0ika")]
position = Vector2(1883.0001, 2059)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_down02" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("17_mvx3b")
offset = Vector2(-20.835999, -8.245972)

[node name="prop_left04" parent="_group_props" unique_id=1282373959 instance=ExtResource("2_t0ika")]
position = Vector2(610, 2008)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_left04" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("16_owqlj")
offset = Vector2(-25.207672, -36.661255)

[node name="prop_left03" parent="_group_props" unique_id=56561865 instance=ExtResource("2_t0ika")]
position = Vector2(385.00003, 1966)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 2.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_left03" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("17_gfwsj")
offset = Vector2(-30.672058, -72.72693)

[node name="prop_huasa" parent="_group_props" unique_id=1304154750 instance=ExtResource("2_t0ika")]
position = Vector2(2244, 954)
squash_stretch_max_x = 1.01
squash_stretch_max_y = 1.01
juice_phase_offset = 5.0
juice_speed_override = 3.0
time_offset_override = 9.635
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_huasa" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("10_57ie1")
offset = Vector2(-1.1639347, -47.590363)

[node name="prop_aowoo" parent="_group_props" unique_id=1834444511 instance=ExtResource("2_t0ika")]
position = Vector2(2453, 957)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.002
squash_stretch_max_y = 1.005
juice_phase_offset = 5.0
juice_speed_override = 1.0
time_offset_override = 9.675
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_aowoo" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("9_gq25e")
offset = Vector2(-11, -221.36084)

[node name="prop_left02" parent="_group_props" unique_id=1739137350 instance=ExtResource("2_t0ika")]
z_index = 1
position = Vector2(629, 1990.0001)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_left02" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("26_fex6b")
offset = Vector2(-30.672058, -72.72693)

[node name="prop_left01" parent="_group_props" unique_id=1016735187 instance=ExtResource("2_t0ika")]
position = Vector2(599, 1991)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_left01" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("27_sko6c")
offset = Vector2(-20.835999, -8.245972)

[node name="prop_right04" parent="_group_props" unique_id=1833064780 instance=ExtResource("2_t0ika")]
position = Vector2(3619.0002, 1876.0001)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_right04" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("28_sko6c")
offset = Vector2(-20.835999, -8.245972)

[node name="prop_right03" parent="_group_props" unique_id=376651383 instance=ExtResource("2_t0ika")]
position = Vector2(3305.0002, 1914)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_right03" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("29_kr0tg")
offset = Vector2(-20.835999, -8.245972)

[node name="prop_right02" parent="_group_props" unique_id=1807933103 instance=ExtResource("2_t0ika")]
z_index = 1
position = Vector2(3399, 1884.0001)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_right02" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("30_mvx3b")
offset = Vector2(-20.835999, -8.245972)

[node name="prop_right01" parent="_group_props" unique_id=1624386981 instance=ExtResource("2_t0ika")]
position = Vector2(3380.0002, 1963.0001)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 0.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_props/prop_right01" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("31_po3vl")
offset = Vector2(-20.835999, -8.245972)

[node name="_group_keys" type="Node2D" parent="." unique_id=1549740572]

[node name="Key_quoteleft" parent="_group_keys" unique_id=245655917 instance=ExtResource("1_kr6jc")]
position = Vector2(701, 1096)
trigger_keycode = 96
metadata/_edit_group_ = true

[node name="Key_1" parent="_group_keys" unique_id=1081271230 instance=ExtResource("1_kr6jc")]
position = Vector2(888, 1098)
trigger_keycode = 49
metadata/_edit_group_ = true

[node name="Key_2" parent="_group_keys" unique_id=87680295 instance=ExtResource("1_kr6jc")]
position = Vector2(1075, 1100)
trigger_keycode = 50
metadata/_edit_group_ = true

[node name="Key_3" parent="_group_keys" unique_id=258082773 instance=ExtResource("1_kr6jc")]
position = Vector2(1261, 1099)
trigger_keycode = 51
metadata/_edit_group_ = true

[node name="Key_4" parent="_group_keys" unique_id=1009311297 instance=ExtResource("1_kr6jc")]
position = Vector2(1450, 1097)
trigger_keycode = 52
metadata/_edit_group_ = true

[node name="Key_5" parent="_group_keys" unique_id=77171198 instance=ExtResource("1_kr6jc")]
position = Vector2(1635, 1099)
trigger_keycode = 53
metadata/_edit_group_ = true

[node name="Key_6" parent="_group_keys" unique_id=967583619 instance=ExtResource("1_kr6jc")]
position = Vector2(1823, 1100)
trigger_keycode = 54
metadata/_edit_group_ = true

[node name="Key_7" parent="_group_keys" unique_id=703521213 instance=ExtResource("1_kr6jc")]
position = Vector2(2010, 1099)
trigger_keycode = 55
metadata/_edit_group_ = true

[node name="Key_8" parent="_group_keys" unique_id=1082758035 instance=ExtResource("1_kr6jc")]
position = Vector2(2197, 1098)
trigger_keycode = 56
metadata/_edit_group_ = true

[node name="Key_9" parent="_group_keys" unique_id=1437049644 instance=ExtResource("1_kr6jc")]
position = Vector2(2382, 1098)
trigger_keycode = 57
metadata/_edit_group_ = true

[node name="Key_0" parent="_group_keys" unique_id=1416491498 instance=ExtResource("1_kr6jc")]
position = Vector2(2571, 1099)
trigger_keycode = 48
metadata/_edit_group_ = true

[node name="Key_minus" parent="_group_keys" unique_id=310069765 instance=ExtResource("1_kr6jc")]
position = Vector2(2757, 1098)
trigger_keycode = 45
metadata/_edit_group_ = true

[node name="Key_equal" parent="_group_keys" unique_id=596755751 instance=ExtResource("1_kr6jc")]
position = Vector2(2944, 1097)
trigger_keycode = 61
metadata/_edit_group_ = true

[node name="Key_backspace" parent="_group_keys" unique_id=730604625 instance=ExtResource("1_kr6jc")]
position = Vector2(3146, 1097)
trigger_keycode = 4194308
metadata/_edit_group_ = true

[node name="FlowerPot" parent="_group_keys/Key_backspace" index="0" unique_id=558943612]
texture = ExtResource("3_i4w03")

[node name="Key_w" parent="_group_keys" unique_id=171227285 instance=ExtResource("1_kr6jc")]
position = Vector2(1104, 1270)
trigger_keycode = 87
metadata/_edit_group_ = true

[node name="Key_tab" parent="_group_keys" unique_id=1868288919 instance=ExtResource("1_kr6jc")]
position = Vector2(717, 1267)
trigger_keycode = 4194306
metadata/_edit_group_ = true

[node name="FlowerPot" parent="_group_keys/Key_tab" index="0" unique_id=558943612]
texture = ExtResource("3_i4w03")

[node name="Key_q" parent="_group_keys" unique_id=213287225 instance=ExtResource("1_kr6jc")]
position = Vector2(917, 1268)
trigger_keycode = 81
metadata/_edit_group_ = true

[node name="Key_e" parent="_group_keys" unique_id=303514236 instance=ExtResource("1_kr6jc")]
position = Vector2(1293, 1270)
trigger_keycode = 69
metadata/_edit_group_ = true

[node name="Key_r" parent="_group_keys" unique_id=1159572304 instance=ExtResource("1_kr6jc")]
position = Vector2(1479, 1270)
trigger_keycode = 82
metadata/_edit_group_ = true

[node name="Key_t" parent="_group_keys" unique_id=486300965 instance=ExtResource("1_kr6jc")]
position = Vector2(1664, 1271)
trigger_keycode = 84
metadata/_edit_group_ = true

[node name="Key_y" parent="_group_keys" unique_id=57052073 instance=ExtResource("1_kr6jc")]
position = Vector2(1849, 1271)
trigger_keycode = 89
metadata/_edit_group_ = true

[node name="Key_u" parent="_group_keys" unique_id=731782878 instance=ExtResource("1_kr6jc")]
position = Vector2(2034, 1271)
trigger_keycode = 85
metadata/_edit_group_ = true

[node name="Key_i" parent="_group_keys" unique_id=91817080 instance=ExtResource("1_kr6jc")]
position = Vector2(2220, 1270)
trigger_keycode = 73
metadata/_edit_group_ = true

[node name="Key_o" parent="_group_keys" unique_id=632693816 instance=ExtResource("1_kr6jc")]
position = Vector2(2409, 1270)
trigger_keycode = 79
metadata/_edit_group_ = true

[node name="Key_p" parent="_group_keys" unique_id=122516468 instance=ExtResource("1_kr6jc")]
position = Vector2(2596, 1267)
trigger_keycode = 80
metadata/_edit_group_ = true

[node name="Key_bracketleft" parent="_group_keys" unique_id=1223124325 instance=ExtResource("1_kr6jc")]
position = Vector2(2783, 1269)
trigger_keycode = 91
metadata/_edit_group_ = true

[node name="Key_bracketright" parent="_group_keys" unique_id=1171410325 instance=ExtResource("1_kr6jc")]
position = Vector2(2970, 1268)
trigger_keycode = 93
metadata/_edit_group_ = true

[node name="Key_backslash" parent="_group_keys" unique_id=1802758610 instance=ExtResource("1_kr6jc")]
position = Vector2(3157, 1271)
trigger_keycode = 92
metadata/_edit_group_ = true

[node name="Key_capslock" parent="_group_keys" unique_id=1653389966 instance=ExtResource("1_kr6jc")]
position = Vector2(755, 1445)
trigger_keycode = 4194329
is_big_key = true
big_key_press_multiplier = 0.9

[node name="FlowerPot" parent="_group_keys/Key_capslock" index="0" unique_id=558943612]
texture = ExtResource("4_2kwox")

[node name="Key_a" parent="_group_keys" unique_id=1936597654 instance=ExtResource("1_kr6jc")]
position = Vector2(998, 1446)

[node name="Key_s" parent="_group_keys" unique_id=74336307 instance=ExtResource("1_kr6jc")]
position = Vector2(1186, 1448)
trigger_keycode = 83
metadata/_edit_group_ = true

[node name="Key_d" parent="_group_keys" unique_id=692742412 instance=ExtResource("1_kr6jc")]
position = Vector2(1372, 1447)
trigger_keycode = 68
metadata/_edit_group_ = true

[node name="Key_f" parent="_group_keys" unique_id=1452751855 instance=ExtResource("1_kr6jc")]
position = Vector2(1557, 1445)
trigger_keycode = 70
metadata/_edit_group_ = true

[node name="Key_g" parent="_group_keys" unique_id=666335527 instance=ExtResource("1_kr6jc")]
position = Vector2(1743, 1443)
trigger_keycode = 71
metadata/_edit_group_ = true

[node name="Key_h" parent="_group_keys" unique_id=1801077912 instance=ExtResource("1_kr6jc")]
position = Vector2(1928, 1446)
trigger_keycode = 72
metadata/_edit_group_ = true

[node name="Key_j" parent="_group_keys" unique_id=190039992 instance=ExtResource("1_kr6jc")]
position = Vector2(2117, 1445)
trigger_keycode = 74
metadata/_edit_group_ = true

[node name="Key_k" parent="_group_keys" unique_id=317756079 instance=ExtResource("1_kr6jc")]
position = Vector2(2302, 1445)
trigger_keycode = 75
metadata/_edit_group_ = true

[node name="Key_l" parent="_group_keys" unique_id=254085653 instance=ExtResource("1_kr6jc")]
position = Vector2(2488, 1445)
trigger_keycode = 76
metadata/_edit_group_ = true

[node name="Key_semicolon" parent="_group_keys" unique_id=1980350345 instance=ExtResource("1_kr6jc")]
position = Vector2(2675, 1444)
trigger_keycode = 59
metadata/_edit_group_ = true

[node name="Key_apostrophe" parent="_group_keys" unique_id=871482648 instance=ExtResource("1_kr6jc")]
position = Vector2(2863, 1445)
trigger_keycode = 39
metadata/_edit_group_ = true

[node name="Key_enter" parent="_group_keys" unique_id=517807502 instance=ExtResource("1_kr6jc")]
position = Vector2(3093, 1445)
trigger_keycode = 4194309
is_big_key = true
big_key_press_multiplier = 0.9
metadata/_edit_group_ = true

[node name="FlowerPot" parent="_group_keys/Key_enter" index="0" unique_id=558943612]
texture = ExtResource("4_2kwox")

[node name="Key_shift" parent="_group_keys" unique_id=58243440 instance=ExtResource("1_kr6jc")]
position = Vector2(794.00006, 1603)
scale = Vector2(0.835, 0.835)
trigger_keycode = 4194325
is_big_key = true
big_key_press_multiplier = 0.8
metadata/_edit_group_ = true

[node name="FlowerPot" parent="_group_keys/Key_shift" index="0" unique_id=558943612]
texture = ExtResource("15_8jng3")

[node name="Key_z" parent="_group_keys" unique_id=1017615829 instance=ExtResource("1_kr6jc")]
position = Vector2(1084, 1624)
trigger_keycode = 90
metadata/_edit_group_ = true

[node name="Key_x" parent="_group_keys" unique_id=1233212075 instance=ExtResource("1_kr6jc")]
position = Vector2(1272, 1621)
trigger_keycode = 88
metadata/_edit_group_ = true

[node name="Key_c" parent="_group_keys" unique_id=1421290090 instance=ExtResource("1_kr6jc")]
position = Vector2(1457, 1623)
trigger_keycode = 67
metadata/_edit_group_ = true

[node name="Key_v" parent="_group_keys" unique_id=1504695635 instance=ExtResource("1_kr6jc")]
position = Vector2(1644, 1621)
trigger_keycode = 86
metadata/_edit_group_ = true

[node name="Key_b" parent="_group_keys" unique_id=1466637927 instance=ExtResource("1_kr6jc")]
position = Vector2(1830, 1621)
trigger_keycode = 66
metadata/_edit_group_ = true

[node name="Key_n" parent="_group_keys" unique_id=284537359 instance=ExtResource("1_kr6jc")]
position = Vector2(2015, 1622)
trigger_keycode = 78
metadata/_edit_group_ = true

[node name="Key_m" parent="_group_keys" unique_id=788865391 instance=ExtResource("1_kr6jc")]
position = Vector2(2205, 1622)
trigger_keycode = 77
metadata/_edit_group_ = true

[node name="Key_comma" parent="_group_keys" unique_id=1018036177 instance=ExtResource("1_kr6jc")]
position = Vector2(2390, 1623)
trigger_keycode = 44
metadata/_edit_group_ = true

[node name="Key_period" parent="_group_keys" unique_id=1769734329 instance=ExtResource("1_kr6jc")]
position = Vector2(2575, 1623)
trigger_keycode = 46
metadata/_edit_group_ = true

[node name="Key_slash" parent="_group_keys" unique_id=79685727 instance=ExtResource("1_kr6jc")]
position = Vector2(2764, 1622)
trigger_keycode = 47
metadata/_edit_group_ = true

[node name="Key_ctrl" parent="_group_keys" unique_id=1482296527 instance=ExtResource("1_kr6jc")]
position = Vector2(703, 1789)
trigger_keycode = 4194326
metadata/_edit_group_ = true

[node name="Key_windows" parent="_group_keys" unique_id=13582433 instance=ExtResource("1_kr6jc")]
position = Vector2(889, 1789)
trigger_keycode = 4194327
metadata/_edit_group_ = true

[node name="Key_alt" parent="_group_keys" unique_id=1235268488 instance=ExtResource("1_kr6jc")]
position = Vector2(1074, 1790)
trigger_keycode = 4194328
metadata/_edit_group_ = true

[node name="Key_space" parent="_group_keys" unique_id=2083454545 instance=ExtResource("1_kr6jc")]
position = Vector2(1549.0001, 1832)
scale = Vector2(0.835, 0.835)
trigger_keycode = 32
is_big_key = true
big_key_press_multiplier = 0.5
metadata/_edit_group_ = true

[node name="FlowerPot" parent="_group_keys/Key_space" index="0" unique_id=558943612]
texture = ExtResource("15_57ie1")
offset = Vector2(0, -104.205635)

[node name="Key_mouse" parent="_group_keys" unique_id=257631760 instance=ExtResource("1_kr6jc")]
position = Vector2(2022, 1799)
trigger_keycode = 0
metadata/_edit_group_ = true

[node name="LetterSprite" parent="_group_keys/Key_mouse/FlowerPot" parent_id_path=PackedInt32Array(257631760, 558943612) index="0" unique_id=1176971840]
texture = ExtResource("14_2uspe")

[node name="Key_left2" parent="_group_keys" unique_id=1155209040 instance=ExtResource("1_kr6jc")]
position = Vector2(2208, 1801)
trigger_keycode = 4194319
metadata/_edit_group_ = true

[node name="Key_up" parent="_group_keys" unique_id=105452037 instance=ExtResource("1_kr6jc")]
position = Vector2(2397, 1800)
trigger_keycode = 4194320
metadata/_edit_group_ = true

[node name="Key_dwon" parent="_group_keys" unique_id=1011333952 instance=ExtResource("1_kr6jc")]
position = Vector2(2584, 1802)
trigger_keycode = 4194322
metadata/_edit_group_ = true

[node name="Key_right" parent="_group_keys" unique_id=560560694 instance=ExtResource("1_kr6jc")]
position = Vector2(2769, 1805)
trigger_keycode = 4194321
metadata/_edit_group_ = true

[node name="_group_ui" type="CanvasLayer" parent="." unique_id=1963499652]
layer = 0

[node name="WarehouseButton" parent="_group_ui" unique_id=1485830037 instance=ExtResource("2_t0ika")]
position = Vector2(3051, 1846)
scale = Vector2(0.95, 0.95)
squash_stretch_max_x = 1.01
squash_stretch_max_y = 1.01
juice_phase_offset = 0.985
juice_speed_override = 0.5
time_offset_override = 1.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_ui/WarehouseButton" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_hmxrr")
texture = ExtResource("42_hmxrr")
offset = Vector2(20.579102, -178.20264)

[node name="ClickDetector" type="TextureButton" parent="_group_ui/WarehouseButton" unique_id=1956160058]
offset_left = -158.94748
offset_top = -334.73682
offset_right = 187.36844
offset_bottom = 5.2631836
focus_mode = 0

[node name="icon_keyboard" parent="_group_ui" unique_id=1516980508 instance=ExtResource("2_t0ika")]
position = Vector2(1564, 2063.0002)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 1.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_ui/icon_keyboard" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("34_po3vl")
offset = Vector2(8.672302, -88.02722)

[node name="icon_journal" parent="_group_ui" unique_id=1144165561 instance=ExtResource("2_t0ika")]
position = Vector2(1876.0001, 2067.0002)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 1.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_ui/icon_journal" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("35_1sb26")
offset = Vector2(8.672302, -88.02722)

[node name="icon_settings" parent="_group_ui" unique_id=629849824 instance=ExtResource("2_t0ika")]
position = Vector2(2189, 2075.0002)
scale = Vector2(0.915, 0.915)
squash_stretch_max_x = 1.02
squash_stretch_max_y = 1.03
juice_phase_offset = 5.0
juice_speed_override = 1.0
time_offset_override = 5.0
metadata/_edit_group_ = true

[node name="VisualSprite" parent="_group_ui/icon_settings" index="0" unique_id=1954305855]
material = SubResource("ShaderMaterial_fqwq4")
texture = ExtResource("36_ledu6")
offset = Vector2(8.672302, -88.02722)

[editable path="_group_props/prop_down01"]
[editable path="_group_props/prop_cloud03"]
[editable path="_group_props/prop_cloud04"]
[editable path="_group_props/prop_cloud05"]
[editable path="_group_props/prop_cloud06"]
[editable path="_group_props/prop_cloud07"]
[editable path="_group_props/prop_cloud08"]
[editable path="_group_props/prop_cloud09"]
[editable path="_group_props/prop_cloud10"]
[editable path="_group_props/prop_cloud01"]
[editable path="_group_props/prop_tuqiuhua02"]
[editable path="_group_props/prop_mountain"]
[editable path="_group_props/prop_house"]
[editable path="_group_props/prop_car"]
[editable path="_group_props/prop_grass"]
[editable path="_group_props/prop_tuqiuhua03"]
[editable path="_group_props/prop_tuqiuhua01"]
[editable path="_group_props/prop_left05"]
[editable path="_group_props/prop_cloud02"]
[editable path="_group_props/prop_huahua01"]
[editable path="_group_props/prop_huahua02"]
[editable path="_group_props/prop_huahua03"]
[editable path="_group_props/prop_huahua04"]
[editable path="_group_props/prop_tree01"]
[editable path="_group_props/prop_tree02"]
[editable path="_group_props/prop_tree03"]
[editable path="_group_props/prop_down02"]
[editable path="_group_props/prop_left04"]
[editable path="_group_props/prop_left03"]
[editable path="_group_props/prop_huasa"]
[editable path="_group_props/prop_aowoo"]
[editable path="_group_props/prop_left02"]
[editable path="_group_props/prop_left01"]
[editable path="_group_props/prop_right04"]
[editable path="_group_props/prop_right03"]
[editable path="_group_props/prop_right02"]
[editable path="_group_props/prop_right01"]
[editable path="_group_keys/Key_quoteleft"]
[editable path="_group_keys/Key_1"]
[editable path="_group_keys/Key_2"]
[editable path="_group_keys/Key_3"]
[editable path="_group_keys/Key_4"]
[editable path="_group_keys/Key_5"]
[editable path="_group_keys/Key_6"]
[editable path="_group_keys/Key_7"]
[editable path="_group_keys/Key_8"]
[editable path="_group_keys/Key_9"]
[editable path="_group_keys/Key_0"]
[editable path="_group_keys/Key_minus"]
[editable path="_group_keys/Key_equal"]
[editable path="_group_keys/Key_backspace"]
[editable path="_group_keys/Key_w"]
[editable path="_group_keys/Key_tab"]
[editable path="_group_keys/Key_q"]
[editable path="_group_keys/Key_e"]
[editable path="_group_keys/Key_r"]
[editable path="_group_keys/Key_t"]
[editable path="_group_keys/Key_y"]
[editable path="_group_keys/Key_u"]
[editable path="_group_keys/Key_i"]
[editable path="_group_keys/Key_o"]
[editable path="_group_keys/Key_p"]
[editable path="_group_keys/Key_bracketleft"]
[editable path="_group_keys/Key_bracketright"]
[editable path="_group_keys/Key_backslash"]
[editable path="_group_keys/Key_capslock"]
[editable path="_group_keys/Key_a"]
[editable path="_group_keys/Key_s"]
[editable path="_group_keys/Key_d"]
[editable path="_group_keys/Key_f"]
[editable path="_group_keys/Key_g"]
[editable path="_group_keys/Key_h"]
[editable path="_group_keys/Key_j"]
[editable path="_group_keys/Key_k"]
[editable path="_group_keys/Key_l"]
[editable path="_group_keys/Key_semicolon"]
[editable path="_group_keys/Key_apostrophe"]
[editable path="_group_keys/Key_enter"]
[editable path="_group_keys/Key_shift"]
[editable path="_group_keys/Key_z"]
[editable path="_group_keys/Key_x"]
[editable path="_group_keys/Key_c"]
[editable path="_group_keys/Key_v"]
[editable path="_group_keys/Key_b"]
[editable path="_group_keys/Key_n"]
[editable path="_group_keys/Key_m"]
[editable path="_group_keys/Key_comma"]
[editable path="_group_keys/Key_period"]
[editable path="_group_keys/Key_slash"]
[editable path="_group_keys/Key_ctrl"]
[editable path="_group_keys/Key_windows"]
[editable path="_group_keys/Key_alt"]
[editable path="_group_keys/Key_space"]
[editable path="_group_keys/Key_mouse"]
[editable path="_group_keys/Key_left2"]
[editable path="_group_keys/Key_up"]
[editable path="_group_keys/Key_dwon"]
[editable path="_group_keys/Key_right"]
[editable path="_group_ui/WarehouseButton"]
[editable path="_group_ui/icon_keyboard"]
[editable path="_group_ui/icon_journal"]
[editable path="_group_ui/icon_settings"]

-------------------
# File: res://pot_data.gd

# pot_config.gd
extends Resource
class_name PotConfig

@export_group("游戏机制")
@export var clicks_for_initial_seed: int = 1  # 💡 新增:第一颗种子(Stage 0)破土所需的独立敲击次数
@export var clicks_per_stage: int = 2
@export var max_stack_size: int = 99

@export_group("背景音乐配置")
@export_file("*.wav", "*.ogg", "*.mp3") var bgm_sound_path: String = "" # BGM 文件路径
@export_range(0.0, 1.0, 0.05) var bgm_volume: float = 0.8 # BGM 目标音量 (0.0~1.0)
@export var bgm_fade_time: float = 1.5 # 缓入缓出的过渡时间 (秒)

@export_file("*.wav", "*.ogg", "*.mp3") var harvest_sound_path: String = ""
@export_range(0.0, 1.0, 0.05) var harvest_volume: float = 1.0 # 💡 专门控制普通植物音量

@export_file("*.wav", "*.ogg", "*.mp3") var chest_harvest_sound_path: String = ""
@export_range(0.0, 1.0, 0.05) var chest_volume: float = 1.0  # 💡 专门控制宝箱音量

@export_group("花盆下压与回弹")
@export var press_offset_y: float = 30.0
@export var spring_speed: float = 3.0

@export_group("花盆Q弹-X轴独立配置")
@export var squash_stretch_min_x: float = 0.8
@export var squash_stretch_max_x: float = 1.2
@export var juice_frequency_x: float = 50.0

@export_group("花盆Q弹-Y轴独立配置")
@export var squash_stretch_min_y: float = 0.8
@export var squash_stretch_max_y: float = 1.3
@export var juice_frequency_y: float = -50.0

@export_group("花盆Q弹-时间、快慢与衰减")
@export var juice_decay_speed: float = 5.0
@export var juice_phase_offset: float = 1.57
@export var juice_speed_override: float = 0.7

@export_group("收获飞天特效-基础")
@export var harvest_fly_distance: float = 300.0
@export var harvest_duration: float = 0.8

@export_group("收获飞天特效-自动果冻数学函数控制")
@export var harvest_max_pop_scale: float = 1.2
@export var harvest_jiggle_frequency: float = 20.0
@export var harvest_jiggle_decay: float = 10.0


@export_group("收获+1叠加配置(全键盘共享)")
# 💡 核心升级:由原先死板的 String 文本路径类型,直接升级为标准的 Texture2D 资源槽位类型!
@export var plus_one_texture: Texture2D          # 面板可视化图片选择器
@export var plus_one_offset: Vector2 = Vector2(150, -360)
@export var plus_one_scale: Vector2 = Vector2(1.2, 1.2)
@export var plus_one_delay: float = 0.05        # +1 特效动作往后延迟的时间(秒),推荐 0.15 秒


@export_group("击键涟漪冲击波")
@export var impact_radius: float = 500.0       # 冲击波向外扩散的最大像素半径
@export var impact_force: float = 2.0         # 把四周作物向外推开的最大像素距离
@export var ripple_spring_speed: float = 1.0  # 四周作物被推开后,弹簧回弹的恢复速度
@export var ripple_expand_speed: float = 1500.0 # 💡 冲击波向外扩散的速度(像素/秒,值越大扩散越快,推荐 1500-2500)
@export var impact_force_down: float = 1.0    # 💡 冲击波纵向向下砸落/凹陷的最大强度(推荐 4.0 ~ 10.0,值越大下陷越深)

-------------------
# File: res://resources/base_item_data.gd

extends Resource
class_name BaseItemData

# 三大物品分类
enum ItemCategory { POT, CROP, STICKER }
# 四大稀有度等级
enum ItemRarity { COMMON, RARE, EPIC, LEGENDARY }

@export_group("基础核心属性")
@export var item_id: String = ""              # 唯一识别ID,必须与磁盘文件夹名(如 yayajun)严格对齐
@export var item_name: String = ""            # 游戏内显示的中文名称,如 "鸭鸭君"
@export var category: ItemCategory = ItemCategory.CROP
@export var rarity: ItemRarity = ItemRarity.COMMON # 秒切 4 色格子背景样式
@export var theme_id: String = "theme_00_default" # 所属主题文件夹名

@export_group("经济价值")
@export var price: int = 1                   # 单个物品在出货售卖区的单价(金币数)

-------------------
# File: res://resources/crop_master_database.tres

[gd_resource type="Resource" script_class="CropMasterDB" format=3 uid="uid://cxgesiep3eco5"]

[ext_resource type="Script" uid="uid://gb5nueu8mpfe" path="res://resources/crop_master_db.gd" id="1_7pscj"]
[ext_resource type="Script" uid="uid://b1csnp7vnmyhc" path="res://resources/base_item_data.gd" id="1_pcuco"]

[sub_resource type="Resource" id="Resource_kc5yy"]
script = ExtResource("1_pcuco")
item_id = "tuqiuhua"
item_name = "兔球花"
metadata/_custom_type_script = "uid://b1csnp7vnmyhc"

[sub_resource type="Resource" id="Resource_bfghb"]
script = ExtResource("1_pcuco")
item_id = "luobobo"
item_name = "萝卜卜"
rarity = 1
price = 2
metadata/_custom_type_script = "uid://b1csnp7vnmyhc"

[sub_resource type="Resource" id="Resource_mswa4"]
script = ExtResource("1_pcuco")
item_id = "yayajun"
item_name = "牙牙菌"
rarity = 2
price = 5
metadata/_custom_type_script = "uid://b1csnp7vnmyhc"

[sub_resource type="Resource" id="Resource_pcuco"]
script = ExtResource("1_pcuco")
item_id = "chest"
item_name = "宝箱"
rarity = 3
price = 500
metadata/_custom_type_script = "uid://b1csnp7vnmyhc"

[resource]
script = ExtResource("1_7pscj")
all_crops_registry = {
"chest": {
"data": SubResource("Resource_pcuco"),
"weight": 0.01
},
"luobobo": {
"data": SubResource("Resource_bfghb"),
"weight": 0.8
},
"tuqiuhua": {
"data": SubResource("Resource_kc5yy"),
"weight": 1.0
},
"yayajun": {
"data": SubResource("Resource_mswa4"),
"weight": 0.5
}
}
metadata/_custom_type_script = "uid://gb5nueu8mpfe"

-------------------
# File: res://resources/crop_master_db.gd

extends Resource
class_name CropMasterDB

@export_group("全局作物集散总谱数据大盘")
# 💡 【核心高阶设计】:这里是一个高级字典。
# 存储格式为:{ "作物英文ID": {"data": BaseItemData属性资源, "weight": 抽卡概率权重} }
# 这样不仅将名字、价格、稀有度,连带抽卡概率全部锁死合并在了同一个地方修改!
@export var all_crops_registry: Dictionary = {}

# 🛠️ 系统底层专用的高速缓存运行时字典(防止频繁进行外壳拆解,优化运行开销)
var _cached_weights_dict: Dictionary = {}

# 💡 官方标准的运行时高速路径初始化工具
func get_weights_dictionary() -> Dictionary:
	if not _cached_weights_dict.is_empty():
		return _cached_weights_dict
		
	# 全自动在内存中把注册表里的数据提取组装成抽卡算法需要的纯概率字典
	for crop_key in all_crops_registry:
		if all_crops_registry[crop_key].has("weight"):
			_cached_weights_dict[crop_key] = all_crops_registry[crop_key]["weight"]
			
	return _cached_weights_dict

-------------------
# File: res://resources/crop_weights.gd

# crop_weights.gd
extends Resource
class_name CropWeights

# 💡 核心设计:在这里写你的概率权重盘!普通概率写 1.0,1% 概率写 0.01。
# 未来有新的作物(如 CropGroup3、CropGroup4),直接在这个字典里点“添加键值对”填入即可。
# 💡 直接从单例常驻的 master_db 集中总谱里抓取实时组装好的纯概率字典大盘
var active_weights_pool: Dictionary = Warehouse.master_db.get_weights_dictionary() if Warehouse.master_db else {}

-------------------
# File: res://resources/default_weights.tres

[gd_resource type="Resource" script_class="CropWeights" format=3 uid="uid://cn73v14dqk6q0"]

[ext_resource type="Script" uid="uid://4xne2q1solyt" path="res://resources/crop_weights.gd" id="1_pstho"]

[resource]
script = ExtResource("1_pstho")
crop_weights = {
"CropGroup0": 1.0,
"CropGroup1": 1.0,
"CropGroup2": 1.0
}
metadata/_custom_type_script = "uid://4xne2q1solyt"

-------------------
# File: res://scenes/game_prop.tscn

[gd_scene format=3 uid="uid://bpbanvymb1cmw"]

[ext_resource type="Script" uid="uid://eupba3p6va3a" path="res://scenes/juice_jiggler.gd" id="1_ivo0o"]
[ext_resource type="Shader" uid="uid://bh0qpokppaj6p" path="res://assets/wave_noise.gdshader" id="2_45bw3"]

[sub_resource type="ShaderMaterial" id="ShaderMaterial_f3fra"]
shader = ExtResource("2_45bw3")
shader_parameter/wave_amplitude_x = 0.010000000475
shader_parameter/wave_amplitude_y = 0.010000000475
shader_parameter/wave_frequency = 0.83600003645012
shader_parameter/noise_scale = 100.0000014752188

[node name="game_prop" type="Node2D" unique_id=1924461588]
script = ExtResource("1_ivo0o")

[node name="VisualSprite" type="Sprite2D" parent="." unique_id=1954305855]
material = SubResource("ShaderMaterial_f3fra")

-------------------
# File: res://scenes/global_warehouse.gd

extends Node

signal warehouse_updated()                     
signal coins_changed(new_coins: int)          

var coins: int = 0:
	set(value):
		coins = max(0, value)
		coins_changed.emit(coins)

var inventory: Dictionary = {}

# 💡 全库最高核心指针:运行时自动加载并常驻您刚刚填好数据的集中总谱资源盘
var master_db: CropMasterDB = null


func _ready() -> void:
	coins = 0
	# 运行时动态全自动按需加载全局唯一集中数据总盘
	master_db = load("res://resources/crop_master_database.tres") as CropMasterDB


func add_crop(crop_id: String, amount: int = 1) -> void:
	if not inventory.has(crop_id):
		var target_item_data: BaseItemData = null
		
		# 💡 【100%数据驱动】:直接去您刚才捏好的总谱注册表里,抓取单体属性资源盘!
		if master_db and master_db.all_crops_registry.has(crop_id):
			target_item_data = master_db.all_crops_registry[crop_id]["data"]
			
		# 🦺 强大的防护安全网:如果你在总谱里还没来得及加它,启动自动化内存自适应兜底,绝对不报错崩溃
		if target_item_data == null:
			target_item_data = BaseItemData.new()
			target_item_data.item_id = crop_id
			target_item_data.item_name = crop_id
			target_item_data.category = BaseItemData.ItemCategory.CROP
			target_item_data.theme_id = "theme_00_default"
			target_item_data.rarity = BaseItemData.ItemRarity.COMMON
			target_item_data.price = 10
			
		inventory[crop_id] = {"amount": 0, "data": target_item_data}
		
	inventory[crop_id]["amount"] += amount
	warehouse_updated.emit()


func move_to_sell_queue(item_id: String, amount: int) -> BaseItemData:
	if not inventory.has(item_id) or inventory[item_id]["amount"] < amount:
		return null
	inventory[item_id]["amount"] -= amount
	var item_data: BaseItemData = inventory[item_id]["data"]
	coins += item_data.price * amount
	warehouse_updated.emit()
	return item_data


func refund_from_sell_queue(item_id: String, amount: int) -> void:
	if not inventory.has(item_id): return
	inventory[item_id]["amount"] += amount
	var item_data: BaseItemData = inventory[item_id]["data"]
	coins -= item_data.price * amount
	warehouse_updated.emit()

-------------------
# File: res://scenes/juice_jiggler.gd

# juice_jiggler.gd (场景永动装饰物控制器 - XY独立最大值版)
extends Node2D
class_name JuiceJiggler

@export_group("Q弹-形变幅度(基于1.0对称)")
@export var squash_stretch_max_x: float = 1.05  # 💡 X轴最大波峰(如1.05,自动对称出波谷0.95)
@export var squash_stretch_max_y: float = 1.05  # 💡 Y轴最大波峰(如1.05,自动对称出波谷0.95)

@export_group("Q弹-时间、快慢与错位")
@export var juice_phase_offset: float = 1.57   
@export var juice_speed_override: float = 0.1  
@export var time_offset_override: float = 0.0  

# 节点引用与内部时间
var target_sprite: Sprite2D
var base_sprite_scale: Vector2
var juice_time: float = 0.0

func _ready() -> void:
	for child in get_children():
		if child is Sprite2D:
			target_sprite = child
			break
			
	if target_sprite:
		base_sprite_scale = target_sprite.scale
		juice_time = time_offset_override

func _process(delta: float) -> void:
	if target_sprite == null: return
	
	# 💡 核心升级 1:速度线性倍率化
	# 速度填 1.0 就是基准速度(每秒摆动一个完整周期),填 2.0 速度就完美快一倍,填 0.5 慢一倍
	# 通过乘以 (PI * 2.0) 锁死一秒一周期,彻底斩断之前 100.0 倍率带来的失控感!
	juice_time += delta * juice_speed_override * (PI * 2.0)
	
	# 💡 核心升级 2:尺寸线性倍率化
	# 如果你填 2.0,代表放大一倍(增量为 1.0),填 1.1 代表放大 10%(增量为 0.1)
	# 允许你直接在面板输入任意倍率,代码在后台全自动计算单边振幅宽度
	var amplitude_x = max(0.0, squash_stretch_max_x - 1.0)
	var amplitude_y = max(0.0, squash_stretch_max_y - 1.0)
	
	# 计算包含干净时间偏移(time_offset_override 也同步对齐为纯秒数)的波形位置
	# 此时括号内部极其干净,只有纯粹弧度制,参数绝对平滑
	var wave_time = juice_time + (time_offset_override * juice_speed_override * PI * 2.0)
	
	var scale_offset_x = sin(wave_time + juice_phase_offset) * amplitude_x
	var scale_offset_y = sin(-wave_time) * amplitude_y
	
	# 实时无缝应用完美对称的全新形变
	target_sprite.scale = base_sprite_scale * (Vector2.ONE + Vector2(scale_offset_x, scale_offset_y))

-------------------
# File: res://scenes/key.gd

# =====================================================================
# 📄 完整覆盖替换 res://scenes/key.gd 最顶部的整个变量定义区(覆盖到 _ready 之前)
# =====================================================================
extends Node2D

@export_group("核心动效数据盘")
@export var pot_config: Resource               # 绑定全键盘共享的 standard_pot_data.tres

@export_group("概率抽卡绑定")
@export var weights_config: Resource

@export_group("键盘独立按键映射")
@export var trigger_keycode: Key = KEY_A       # 允许面板自由分配为 KEY_B, KEY_SPACE 等


@export_group("特殊大件快捷控制 (无需新建文件)")
@export var is_big_key: bool = false           # 如果是空格/回车,在右侧面板勾选它
@export var big_key_press_multiplier: float = 1.5 # 大键的下压幅度倍率

# 节点引用与内部计数器
@onready var flower_pot: Sprite2D = $FlowerPot
@onready var letter_sprite: Sprite2D = $FlowerPot/LetterSprite 

# 纯数组缓存
var all_crop_nodes: Array = []

# 内部状态计算变量
var current_crop_idx: int = 0                  
var current_stage: int = -1                    
var click_count: int = 0

var anim_offset_y: float = 0.0
var anim_scale_offset: Vector2 = Vector2.ZERO

var base_pot_position: Vector2
var base_pot_scale: Vector2

var juice_time: float = 0.0
var juice_intensity: float = 0.0

# 🌊 【冲击波核心底层底座变量】
# 💡 必须严格死磕存放在最外层作用域,这样 _process 和 接收函数 才能同时认识它们!
var ripple_offset: Vector2 = Vector2.ZERO      # 涟漪冲击波带来的瞬时X/Y物理位移向量
var active_ripples: Array = []                 # 当前作用在自己身上的动态非线性波场列表



func _ready() -> void:
	randomize()
	
	base_pot_position = flower_pot.position
	base_pot_scale = flower_pot.scale
	
	# 全自动资产匹配:直接根据你选的键位,自动去加载对应名字的手手绘图片
	if letter_sprite:
		letter_sprite.z_index = 0
		letter_sprite.z_as_relative = true 
		
		# 自动化获取对应的标准英文图片名
		var key_name: String = OS.get_keycode_string(trigger_keycode).to_lower()
		var target_image_path: String = "res://assets/sprites/letters/" + key_name + ".png"
		
		if ResourceLoader.exists(target_image_path):
			letter_sprite.texture = load(target_image_path)
		else:
			print("【标准资产检查】未找到该键位贴图,请确认图片名是否为: ", key_name, ".png")
		
	scan_and_init_crops()
	hide_all_crops()
	
	# 💡 【涟漪核心监听】:将自己注册进大世界的击键分发网络中
	# 监听主场景抛出的统一震源信号(我们稍后会在主场景抛出它)
	var main_scene = get_tree().current_scene
	if main_scene and main_scene.has_signal("key_pressed_at_world_pos"):
		main_scene.connect("key_pressed_at_world_pos", _on_global_key_ripple_receive)





# =====================================================================
# 📄 面板动态控幅版:完整覆盖替换 res://scenes/key.gd 内的 _process 函数
# =====================================================================
func _process(delta: float) -> void:
	if pot_config == null: return
	
	# 💡 A. 【多维非线性曲线物理引擎】:实时采样作用在自己身上的每一个冲击波
	if not active_ripples.is_empty():
		var max_radius = pot_config.get("impact_radius") if "impact_radius" in pot_config else 500.0
		var max_force = pot_config.get("impact_force") if "impact_force" in pot_config else 10.0
		# 提取面板上新增的纵向下压力度参数(带安全兜底默认值 6.0)
		var max_force_down = pot_config.get("impact_force_down") if "impact_force_down" in pot_config else 6.0
		var i = active_ripples.size() - 1
		
		while i >= 0:
			var ripple = active_ripples[i]
			ripple["time_elapsed"] += delta
			
			# 计算当前的生命进度比例 (0.0 ~ 1.0)
			var progress = clamp(ripple["time_elapsed"] / ripple["total_life"], 0.0, 1.0)
			
			# 🧮 【先快后慢核心公式】:Quadratic Ease-Out 渐缓曲线
			var ease_out_factor = 1.0 - (1.0 - progress) * (1.0 - progress)
			
			# 计算当前冲击波环先快后慢膨胀出来的实时半径
			var current_wave_radius = max_radius * ease_out_factor
			
			# 🌊 触发检测:当波形圈的实时半径正好追上并越过了作物与圆心的距离
			if current_wave_radius >= ripple["distance"]:
				# 计算双重衰减:空间距离衰减 + 时间进度衰减,让远处的波纹极其柔和
				var distance_falloff = 1.0 - (ripple["distance"] / max_radius)
				var time_falloff = 1.0 - progress # 越往后能量越微弱
				
				# 基础能量衰减系数 (结合了距离和时间,保证多维位移手感高度统一)
				var energy_multiplier = distance_falloff * time_falloff * 5.0
				
				# 1. 计算原有的【横向向外推开力】基础向量
				var horizontal_push = ripple["push_dir"] * (max_force * energy_multiplier)
				
				# 2. 💡 【核心修改:完全面板可控的纵向向下凹陷力】
				# 严格尊崇面板上填入的最大下压系数,使其同步共享完全一样的非线性衰减曲线
				var vertical_drop_y = max_force_down * energy_multiplier
				
				# 3. 完美结合成高阶的多维 3D 物理偏移向量
				var final_3d_push = Vector2(horizontal_push.x, horizontal_push.y + vertical_drop_y)
				ripple_offset += final_3d_push
				
				# 该波纹已经对当前物体生效完毕,从当前物体的池子中安全移除
				active_ripples.remove_at(i)
			# 如果波纹超时仍未追上(安全边界保护),自动销毁任务
			elif progress >= 1.0:
				active_ripples.remove_at(i)
				
			i -= 1

	# B. 🎬 核心物理位移弹簧拉回计算
	# 基础敲击:Y 轴受压回弹
	anim_offset_y = move_toward(anim_offset_y, 0.0, pot_config.spring_speed * delta * 50.0)
	# 涟漪向外外推+向下凹陷向量:受您面板上的 Ripple Spring Speed (当前为 0.5) 控制同步回弹向 (0,0) 零点!
	var ripple_spring = pot_config.get("ripple_spring_speed") if "ripple_spring_speed" in pot_config else 0.5
	ripple_offset = ripple_offset.move_toward(Vector2.ZERO, ripple_spring * delta * 50.0)
	
	# C. 🧮 核心果冻 Q 弹缩放逻辑计算(保持不变)
	if juice_intensity > 0.01:
		juice_time += delta
		juice_intensity = move_toward(juice_intensity, 0.0, pot_config.juice_decay_speed * delta)
		
		var amplitude_x = (pot_config.squash_stretch_max_x - pot_config.squash_stretch_min_x) / 2.0
		var amplitude_y = (pot_config.squash_stretch_max_y - pot_config.squash_stretch_min_y) / 2.0
		
		var scale_offset_x = sin(juice_time * pot_config.juice_frequency_x * pot_config.juice_speed_override + pot_config.juice_phase_offset) * amplitude_x * juice_intensity
		var scale_offset_y = sin(juice_time * pot_config.juice_frequency_y * pot_config.juice_speed_override) * amplitude_y * juice_intensity
		
		anim_scale_offset.x = scale_offset_x
		anim_scale_offset.y = scale_offset_y
	else:
		anim_scale_offset = Vector2.ZERO
		juice_time = 0.0
		
	# D. 🖼️ 数据完美无缝叠加到节点上
	# 位置无缝融合:原本的 Y 轴下压 + 全新的先快后慢【3D立体水平外推与纵向下陷】复合涟漪位移向量
	flower_pot.position = base_pot_position + Vector2(0.0, anim_offset_y) + ripple_offset
	# 缩放无缝融合
	flower_pot.scale = base_pot_scale * (Vector2.ONE + anim_scale_offset)




func _input(event: InputEvent) -> void:
	if event is InputEventKey and event.pressed and not event.is_echo():
		if event.keycode == trigger_keycode:
			# 💡 涟漪发射点:按下的一瞬间,通过主场景向大世界发射包含自己世界坐标的震源信号!
			var main_scene = get_tree().current_scene
			if main_scene and main_scene.has_signal("key_pressed_at_world_pos"):
				main_scene.emit_signal("key_pressed_at_world_pos", global_position)
				
			trigger_press_displacement()
			advance_logic()

			
	# ----------------- 2. 💡 满足你的新要求:精准捕捉并吞下鼠标所有点击 -----------------
	# 如果你希望【全键盘只有这一个特定的按键】能吃鼠标,我们在面板上通过名字(比如叫 Key_Space)来锁死它。
	# 这里我帮你做了一个名字保护判断:只有当你在主场景里把这个按键重命名为 "Key_Space"(或者任何你想给鼠标的按键名字)时,它才会激活鼠标监听!
	if name == "Key_mouse" and event is InputEventMouseButton and event.pressed:
		# MOUSE_BUTTON_LEFT (左键), MOUSE_BUTTON_RIGHT (右键), MOUSE_BUTTON_MIDDLE (中键)
		if event.button_index == MOUSE_BUTTON_LEFT or event.button_index == MOUSE_BUTTON_RIGHT or event.button_index == MOUSE_BUTTON_MIDDLE:
			
			
			trigger_press_displacement()
			advance_logic()


func advance_logic() -> void:
	if pot_config == null: return
	click_count += 1
	
	# 💡 核心修正:无论第几次轮回,只要当前处于空盘(Stage -1),就必须死磕种子独立的敲击数
	var required_clicks: int = pot_config.clicks_per_stage
	if current_stage == -1:
		required_clicks = pot_config.get("clicks_for_initial_seed") if "clicks_for_initial_seed" in pot_config else pot_config.clicks_per_stage

	# 达到当前阶段的要求
	if click_count >= required_clicks:
		click_count = 0 # 计数器归零
		if current_stage == -1:
			# 从空盘进入 Stage 0
			current_crop_idx = select_random_crop_by_order()
			current_stage = 0
			update_visuals()
			trigger_juice_scale()
		else:
			# 后续正常生长
			current_stage += 1
			if current_stage == 4:
				update_visuals()
				spawn_harvest_effect()
				reset_to_empty() # 💡 这里触发重置后,current_stage 变回 -1,下一轮敲击会自动重新走上面 clicks_for_initial_seed 的次数
			else:
				update_visuals()
				trigger_juice_scale()


func scan_and_init_crops() -> void:
	all_crop_nodes.clear()
	for child in flower_pot.get_children():
		if child is Node2D and child.get_child_count() >= 5:
			var stages = []
			for i in range(5): stages.append(child.get_child(i))
			all_crop_nodes.append(stages)

func reset_to_empty() -> void:
	current_stage = -1
	click_count = 0
	hide_all_crops()
	trigger_juice_scale()

func hide_all_crops() -> void:
	for group in all_crop_nodes:
		for stage in group: if stage: stage.visible = false

func update_visuals() -> void:
	hide_all_crops()
	if current_stage >= 0 and current_stage < 5 and current_crop_idx < all_crop_nodes.size():
		var target_node = all_crop_nodes[current_crop_idx][current_stage] as Sprite2D
		if target_node: target_node.visible = true

func trigger_press_displacement() -> void:
	if pot_config == null: return
	anim_offset_y = pot_config.press_offset_y


func trigger_juice_scale() -> void:
	# 💡 核心修改:如果勾选了 Is Big Key,大键的果冻抖动强度会立刻乘以你截图里设定的 Big Key Press Multiplier 
	if is_big_key:
		juice_intensity = 1.0 * big_key_press_multiplier
	else:
		juice_intensity = 1.0
		
	juice_time = 0.0


func spawn_harvest_effect() -> void:
	if current_crop_idx >= all_crop_nodes.size() or pot_config == null: return
	
	# 💡 【核心修复】:先确保提取出来的是一个纯数组
	var current_stages_array = all_crop_nodes[current_crop_idx] as Array
	if current_stages_array.size() < 5: return
	
	# 💡 【终极解药】:不再使用 as 盲目强转数组,而是通过 [4] 直接精准抓取熟透期的那个 Sprite2D 实例!
	var target_stage_node = current_stages_array[4] as Sprite2D
	if target_stage_node == null or target_stage_node.texture == null: return
	
	var current_scene = get_tree().current_scene if (get_tree() and get_tree().current_scene) else self
	var crop_global_trans = target_stage_node.global_transform
	var crop_base_scale = target_stage_node.global_scale
	
	# 💡 动态提取当前作物节点的【真实英文名字本身】(如 tuqiuhua / yayajun),无缝递交集中总谱大盘
	var dynamic_crop_id: String = ""
	if target_stage_node.get_parent():
		dynamic_crop_id = target_stage_node.get_parent().name
		
	if dynamic_crop_id == "":
		dynamic_crop_id = "tuqiuhua"
		
	Warehouse.add_crop(dynamic_crop_id, 1)

	
	# 🎬 链路 A:农作物飞天动效
	var fx_crop = Sprite2D.new()
	fx_crop.texture = target_stage_node.texture
	fx_crop.centered = target_stage_node.centered
	fx_crop.offset = target_stage_node.offset
	fx_crop.global_transform = crop_global_trans
	fx_crop.scale = crop_base_scale
	current_scene.add_child(fx_crop)
	
	if pot_config.harvest_duration > 0.001:
		var tw_crop_fly = create_tween().set_parallel(true)
		tw_crop_fly.tween_property(fx_crop, "global_position:y", fx_crop.global_position.y - pot_config.harvest_fly_distance, pot_config.harvest_duration).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN)
		tw_crop_fly.tween_property(fx_crop, "modulate:a", 0.0, pot_config.harvest_duration / 2.0).set_delay(pot_config.harvest_duration / 2.0)
		
		var tw_crop_math = create_tween()
		tw_crop_math.tween_method(_on_harvest_jiggle_update.bind(fx_crop, crop_base_scale), 0.0, pot_config.harvest_duration, pot_config.harvest_duration).set_trans(Tween.TRANS_LINEAR)
		tw_crop_math.tween_callback(fx_crop.queue_free)
	else:
		fx_crop.queue_free()

	# 🎬 链路 B:延迟【+1】动效(完全回归内存对象指针无缝绑定)
	var p_tex = pot_config.get("plus_one_texture") if "plus_one_texture" in pot_config else null
	var delay_time: float = pot_config.get("plus_one_delay") if "plus_one_delay" in pot_config else 0.15

	if p_tex != null and p_tex is Texture2D:
		var fx_plus = Sprite2D.new()
		fx_plus.texture = p_tex 
		fx_plus.centered = true
		
		var p_offset = pot_config.get("plus_one_offset") if "plus_one_offset" in pot_config else Vector2(200, -200)
		var p_scale = pot_config.get("plus_one_scale") if "plus_one_scale" in pot_config else Vector2(0.8, 0.8)
		
		fx_plus.global_transform = crop_global_trans
		fx_plus.global_position += p_offset
		fx_plus.scale = crop_base_scale * p_scale
		
		fx_plus.modulate.a = 0.0
		current_scene.add_child(fx_plus)
		
		if pot_config.harvest_duration > 0.001:
			var tw_plus_fly = create_tween().set_parallel(true)
			tw_plus_fly.tween_property(fx_plus, "global_position:y", fx_plus.global_position.y - pot_config.harvest_fly_distance, pot_config.harvest_duration).set_trans(Tween.TRANS_QUAD).set_ease(Tween.EASE_IN).set_delay(delay_time)
			tw_plus_fly.tween_property(fx_plus, "modulate:a", 1.0, delay_time * 0.5).set_delay(delay_time)
			tw_plus_fly.tween_property(fx_plus, "modulate:a", 0.0, pot_config.harvest_duration / 2.0).set_delay(delay_time + pot_config.harvest_duration / 2.0)
			
			var tw_plus_math = create_tween()
			tw_plus_math.tween_method(_on_harvest_jiggle_update.bind(fx_plus, crop_base_scale * p_scale), 0.0, pot_config.harvest_duration, pot_config.harvest_duration).set_trans(Tween.TRANS_LINEAR).set_delay(delay_time)
			tw_plus_math.tween_callback(fx_plus.queue_free)
		else:
			fx_plus.queue_free()
			
	# 音频	# =====================================================================
	# 🎵 全自动音频分流与安全消音控制大盘(精准对齐面板数据)
	# =====================================================================
	# 💡 【核心修复点】:默认情况下,全游戏所有常规作物(如 tuqiuhua / luobobo / yayajun 等)统一打包托管加载普通音效
	var target_sound: String = pot_config.get("harvest_sound_path") if "harvest_sound_path" in pot_config else ""
	var target_vol: float = pot_config.get("harvest_volume") if "harvest_volume" in pot_config else 1.0
	
	# 💡 【真·100%去硬编码名字拦截】:抛弃脆弱的 current_crop_idx == 2 下标!
	# 有且只有当成熟作物的真实节点名字严格等于 "chest"(主题宝箱)时,才强行分流切换为专属的宝箱音效和独立音量大小!
	if dynamic_crop_id == "chest" and pot_config.get("chest_harvest_sound_path") != "":
		target_sound = pot_config.chest_harvest_sound_path
		target_vol = pot_config.get("chest_volume") if "chest_volume" in pot_config else 1.0

	# 执行运行时动态音频流加载,保障内存安全
	if target_sound != "" and ResourceLoader.exists(target_sound):
		var audio_player = AudioStreamPlayer.new()
		audio_player.stream = load(target_sound)
		current_scene.add_child(audio_player)
		
		# 🎚️ 工业级官方标准分贝值(dB)安全映射机制,完美消灭任何破音或闪退隐患
		if target_vol >= 0.99:
			audio_player.volume_db = 0.0 
		elif target_vol <= 0.01:
			audio_player.volume_db = -80.0 
		else:
			audio_player.volume_db = linear_to_db(target_vol)
		
		audio_player.play()
		audio_player.finished.connect(func(): audio_player.queue_free())





func _on_harvest_jiggle_update(elapsed_time: float, fx: Sprite2D, target_base_scale: Vector2) -> void:
	if not is_instance_valid(fx) or pot_config == null: return
	var max_amplitude = pot_config.harvest_max_pop_scale - 1.0
	var decay = exp(-pot_config.harvest_jiggle_decay * elapsed_time)
	var wave = cos(pot_config.harvest_jiggle_frequency * elapsed_time)
	var current_offset = max_amplitude * decay * wave
	fx.scale = target_base_scale * (1.0 + current_offset)
	


func _on_global_key_ripple_receive(source_global_pos: Vector2) -> void:
	if pot_config == null: return
	
	# 1. 震源是自己,直接弹回(由原生的下压逻辑接管)
	if source_global_pos.distance_to(global_position) < 5.0: return
	
	# 2. 计算当前作物与震源之间的绝对物理像素距离
	var distance = global_position.distance_to(source_global_pos)
	var max_radius = pot_config.get("impact_radius") if "impact_radius" in pot_config else 500.0
	
	# 3. 【轻量化阻断】:如果在最大圆圈半径之外,零算力浪费,直接弹回
	if distance > max_radius or distance < 0.01: return
	
	# 4. 计算扩散到我这里所需的总生命周期时长 (最大半径 / 基础扩散速度)
	var expand_speed = pot_config.get("ripple_expand_speed") if "ripple_expand_speed" in pot_config else 1800.0
	var total_lifetime = max_radius / expand_speed
	
	# 5. 计算从内向外的推开方向向量
	var push_direction = (global_position - source_global_pos).normalized()
	
	# 6. 将当前波纹源注入到自己的实时监测池中,记录当前存活时间(从0开始)和它的物理参数
	active_ripples.append({
		"center": source_global_pos,
		"time_elapsed": 0.0,
		"total_life": total_lifetime,
		"distance": distance,
		"push_dir": push_direction
	})

# 💡 【全新纯净抽卡内核】:完全读取万能集中总谱,严格阻断并遵守您的 1% 和平摊逻辑
func _pick_random_crop_id() -> String:
	var active_weights_pool: Dictionary = {}
	if Warehouse.master_db and Warehouse.master_db.has_method("get_weights_dictionary"):
		active_weights_pool = Warehouse.master_db.get_weights_dictionary()
		
	if active_weights_pool.is_empty():
		return ""
		
	# 两阶段绝对概率剥离算法内核
	var rare_items: Array = []
	var common_items: Array = []
	var total_rare_probability: float = 0.0
	
	for crop_id in active_weights_pool:
		var w: float = active_weights_pool[crop_id]
		if w <= 0.11: # 精准剥离 0.1 和 0.01 等绝对固定的稀有度限制项
			rare_items.append({"id": crop_id, "weight": w})
			total_rare_probability += w
		else:
			common_items.append(crop_id)
			
	var rolled_value: float = randf()
	
	# 第一阶段投掷:若随机数砸入绝对稀有区间,100% 吐出对应新植物字符串
	var rare_accumulator: float = 0.0
	for rare in rare_items:
		rare_accumulator += rare["weight"]
		if rolled_value <= rare_accumulator:
			return rare["id"]
			
	# 第二阶段投掷:常规作物按照 1.0 的平摊均分概率随机产生
	if common_items.is_empty():
		return ""
		
	var random_common_idx: int = randi() % common_items.size()
	return common_items[random_common_idx]

# 💡 【老项目函数名无缝适配连线总闸 - 100%全自动化零写死且带整型返回版】
func select_random_crop_by_order() -> int:
	# 1. 触发我们在第一步写好的抽卡内核,拿到本次随机摇出来的作物英文ID(如 tuqiuhua / yayajun)
	var next_crop_id: String = _pick_random_crop_id()
	
	# 🦺 路径安全防护网:如果总谱没加载好,默认返回 0(种第一种作物),确保 100% 不崩溃
	if next_crop_id == "": 
		return 0
	
	# 2. 🧮 【全自动运行时下标反向推算算法】:
	# 彻底告别 if next_crop_id == "xxx" 的硬编码名字!
	# 代码会全自动去遍历当前花盆底下的 all_crop_nodes 数组,寻找名字能和 next_crop_id 100% 对齐的层级
	for idx in range(all_crop_nodes.size()):
		var stage_array = all_crop_nodes[idx] as Array
		if stage_array.size() > 0:
			var first_stage_node = stage_array[0] as Sprite2D
			if first_stage_node and first_stage_node.get_parent():
				var parent_node_name: String = first_stage_node.get_parent().name
				
				# 当场景树节点名与总谱抽出来的 ID 100% 稳固咬合对齐时:
				if parent_node_name == next_crop_id:
					# 直接将这个算好的整型下标数字 return 抛回去给第 207 行进行无脑赋值!
					return idx
					
	# 🦺 最终防御兜底:如果场景树节点名字拼写错了导致没对上,默认返回当前的 current_crop_idx 保持原样
	print("【数据驱动抽卡提示】抽出了资产 [", next_crop_id, "],但当前花盆场景树上没有拼装同名的作物节点组!")
	return current_crop_idx

-------------------
# File: res://scenes/key.tscn

[gd_scene format=3 uid="uid://c2n76yquwpiy2"]

[ext_resource type="Script" uid="uid://dlc4ksnjw0cf7" path="res://scenes/key.gd" id="1_6y7fx"]
[ext_resource type="Resource" uid="uid://cn73v14dqk6q0" path="res://resources/default_weights.tres" id="2_htl1e"]
[ext_resource type="Texture2D" uid="uid://d3bh0qacljprp" path="res://assets/sprites/items/theme_00_default/crops/tuqiuhua/tuqiuhua_stage_0.png" id="2_krfvd"]
[ext_resource type="Resource" uid="uid://exmkmdcimin7" path="res://resources/pot_data_standard.tres" id="3_g6wqb"]
[ext_resource type="Texture2D" uid="uid://bejqg822xduqg" path="res://assets/sprites/items/theme_00_default/pots/pot_default_size_0.png" id="4_htl1e"]
[ext_resource type="Shader" uid="uid://bh0qpokppaj6p" path="res://assets/wave_noise.gdshader" id="5_xrs3s"]
[ext_resource type="Texture2D" uid="uid://c8visbdabsqe8" path="res://assets/sprites/items/theme_00_default/crops/tuqiuhua/tuqiuhua_stage_1.png" id="6_lchjj"]
[ext_resource type="Texture2D" uid="uid://c4epe1weodblk" path="res://assets/sprites/items/theme_00_default/crops/tuqiuhua/tuqiuhua_stage_2.png" id="7_q4r3n"]
[ext_resource type="Texture2D" uid="uid://ljvnt7bgbd1v" path="res://assets/sprites/items/theme_00_default/crops/tuqiuhua/tuqiuhua_stage_3.png" id="8_o04q6"]
[ext_resource type="Texture2D" uid="uid://nx57l3wiygnm" path="res://assets/sprites/items/theme_00_default/crops/tuqiuhua/tuqiuhua_stage_4.png" id="9_21j0w"]
[ext_resource type="Texture2D" uid="uid://xf4ej3orysao" path="res://assets/sprites/items/theme_00_default/crops/luobobo/luobobo_stage_0.png" id="10_e6e4t"]
[ext_resource type="Texture2D" uid="uid://dwls73a7tc038" path="res://assets/sprites/items/theme_00_default/crops/luobobo/luobobo_stage_1.png" id="11_kx4t7"]
[ext_resource type="Texture2D" uid="uid://cldjqphhw7732" path="res://assets/sprites/items/theme_00_default/crops/luobobo/luobobo_stage_2.png" id="12_qif7y"]
[ext_resource type="Texture2D" uid="uid://drnn70xv2wn7e" path="res://assets/sprites/items/theme_00_default/crops/luobobo/luobobo_stage_3.png" id="13_vkf0s"]
[ext_resource type="Texture2D" uid="uid://bne1rj0yjqlh0" path="res://assets/sprites/items/theme_00_default/crops/luobobo/luobobo_stage_4.png" id="14_eqd53"]
[ext_resource type="Texture2D" uid="uid://dhsvl1p0unhtt" path="res://assets/sprites/items/theme_00_default/crops/chest/chest_stage_0.png" id="15_sen5w"]
[ext_resource type="Texture2D" uid="uid://ba30onffn6gvl" path="res://assets/sprites/items/theme_00_default/crops/chest/chest_stage_1.png" id="16_tku3k"]
[ext_resource type="Texture2D" uid="uid://l7y47v0fg4x6" path="res://assets/sprites/items/theme_00_default/crops/chest/chest_stage_2.png" id="17_57odb"]
[ext_resource type="Texture2D" uid="uid://cbuwtmnb3v1bp" path="res://assets/sprites/items/theme_00_default/crops/chest/chest_stage_3.png" id="18_oil3b"]
[ext_resource type="Texture2D" uid="uid://bw3lrf2e10uwn" path="res://assets/sprites/items/theme_00_default/crops/chest/chest_stage_4.png" id="19_htl1e"]
[ext_resource type="Texture2D" uid="uid://c6770nycfadw7" path="res://assets/sprites/items/theme_00_default/crops/yayajun/yayajun_stage_0.png" id="21_bmwd0"]
[ext_resource type="Texture2D" uid="uid://dasatqmngtp6" path="res://assets/sprites/items/theme_00_default/crops/yayajun/yayajun_stage_1.png" id="22_tbsev"]
[ext_resource type="Texture2D" uid="uid://dqx30wg1nqrbg" path="res://assets/sprites/items/theme_00_default/crops/yayajun/yayajun_stage_2.png" id="23_c562q"]
[ext_resource type="Texture2D" uid="uid://ddh3lp4lay6eb" path="res://assets/sprites/items/theme_00_default/crops/yayajun/yayajun_stage_3.png" id="24_4j6cc"]
[ext_resource type="Texture2D" uid="uid://15ym6f0p38mb" path="res://assets/sprites/items/theme_00_default/crops/yayajun/yayajun_stage_4.png" id="25_f82af"]

[sub_resource type="ShaderMaterial" id="ShaderMaterial_aqh0b"]
shader = ExtResource("5_xrs3s")
shader_parameter/wave_amplitude_x = 0.010000000475
shader_parameter/wave_amplitude_y = 0.010000000475
shader_parameter/wave_frequency = 1.915
shader_parameter/noise_scale = 206.6

[sub_resource type="ShaderMaterial" id="ShaderMaterial_fw5uf"]
shader = ExtResource("5_xrs3s")
shader_parameter/wave_amplitude_x = 0.01
shader_parameter/wave_amplitude_y = 0.01
shader_parameter/wave_frequency = 1.915
shader_parameter/noise_scale = 206.6

[sub_resource type="ShaderMaterial" id="ShaderMaterial_obeno"]
shader = ExtResource("5_xrs3s")
shader_parameter/wave_amplitude_x = 0.01
shader_parameter/wave_amplitude_y = 0.01
shader_parameter/wave_frequency = 1.915
shader_parameter/noise_scale = 206.6

[sub_resource type="ShaderMaterial" id="ShaderMaterial_xrs3s"]
shader = ExtResource("5_xrs3s")
shader_parameter/wave_amplitude_x = 0.01
shader_parameter/wave_amplitude_y = 0.01
shader_parameter/wave_frequency = 1.915
shader_parameter/noise_scale = 206.6

[sub_resource type="ShaderMaterial" id="ShaderMaterial_udwwn"]
shader = ExtResource("5_xrs3s")
shader_parameter/wave_amplitude_x = 0.01
shader_parameter/wave_amplitude_y = 0.01
shader_parameter/wave_frequency = 1.915
shader_parameter/noise_scale = 206.6

[sub_resource type="ShaderMaterial" id="ShaderMaterial_bmwd0"]
shader = ExtResource("5_xrs3s")
shader_parameter/wave_amplitude_x = 0.01
shader_parameter/wave_amplitude_y = 0.01
shader_parameter/wave_frequency = 1.915
shader_parameter/noise_scale = 206.6

[sub_resource type="ShaderMaterial" id="ShaderMaterial_tbsev"]
shader = ExtResource("5_xrs3s")
shader_parameter/wave_amplitude_x = 0.01
shader_parameter/wave_amplitude_y = 0.01
shader_parameter/wave_frequency = 1.915
shader_parameter/noise_scale = 206.6

[sub_resource type="ShaderMaterial" id="ShaderMaterial_c562q"]
shader = ExtResource("5_xrs3s")
shader_parameter/wave_amplitude_x = 0.01
shader_parameter/wave_amplitude_y = 0.01
shader_parameter/wave_frequency = 1.915
shader_parameter/noise_scale = 206.6

[sub_resource type="ShaderMaterial" id="ShaderMaterial_4j6cc"]
shader = ExtResource("5_xrs3s")
shader_parameter/wave_amplitude_x = 0.01
shader_parameter/wave_amplitude_y = 0.01
shader_parameter/wave_frequency = 1.915
shader_parameter/noise_scale = 206.6

[sub_resource type="ShaderMaterial" id="ShaderMaterial_f82af"]
shader = ExtResource("5_xrs3s")
shader_parameter/wave_amplitude_x = 0.01
shader_parameter/wave_amplitude_y = 0.01
shader_parameter/wave_frequency = 1.915
shader_parameter/noise_scale = 206.6

[sub_resource type="ShaderMaterial" id="ShaderMaterial_iqk5x"]
shader = ExtResource("5_xrs3s")
shader_parameter/wave_amplitude_x = 0.01
shader_parameter/wave_amplitude_y = 0.01
shader_parameter/wave_frequency = 1.915
shader_parameter/noise_scale = 206.6

[sub_resource type="ShaderMaterial" id="ShaderMaterial_28oxv"]
shader = ExtResource("5_xrs3s")
shader_parameter/wave_amplitude_x = 0.01
shader_parameter/wave_amplitude_y = 0.01
shader_parameter/wave_frequency = 1.915
shader_parameter/noise_scale = 206.6

[node name="Key" type="Node2D" unique_id=245655917]
script = ExtResource("1_6y7fx")
pot_config = ExtResource("3_g6wqb")
weights_config = ExtResource("2_htl1e")

[node name="FlowerPot" type="Sprite2D" parent="." unique_id=558943612]
texture = ExtResource("4_htl1e")
offset = Vector2(0, -41.93)

[node name="LetterSprite" type="Sprite2D" parent="FlowerPot" unique_id=1176971840]
modulate = Color(1, 1, 1, 0.46666667)

[node name="tuqiuhua" type="Node2D" parent="FlowerPot" unique_id=1450575067]

[node name="Stage0" type="Sprite2D" parent="FlowerPot/tuqiuhua" unique_id=1533235797]
material = SubResource("ShaderMaterial_aqh0b")
texture = ExtResource("2_krfvd")
offset = Vector2(0, -96.36)

[node name="Stage1" type="Sprite2D" parent="FlowerPot/tuqiuhua" unique_id=305618491]
material = SubResource("ShaderMaterial_fw5uf")
texture = ExtResource("6_lchjj")
offset = Vector2(0, -149.24)

[node name="Stage2" type="Sprite2D" parent="FlowerPot/tuqiuhua" unique_id=1391986623]
material = SubResource("ShaderMaterial_obeno")
texture = ExtResource("7_q4r3n")
offset = Vector2(0, -167.86)

[node name="Stage3" type="Sprite2D" parent="FlowerPot/tuqiuhua" unique_id=1619652737]
material = SubResource("ShaderMaterial_xrs3s")
texture = ExtResource("8_o04q6")
offset = Vector2(0, -214.04)

[node name="Stage4" type="Sprite2D" parent="FlowerPot/tuqiuhua" unique_id=1775454154]
scale = Vector2(0.435, 0.435)
texture = ExtResource("9_21j0w")
offset = Vector2(0, -654.26)

[node name="luobobo" type="Node2D" parent="FlowerPot" unique_id=561093510]

[node name="Stage0" type="Sprite2D" parent="FlowerPot/luobobo" unique_id=410906889]
material = SubResource("ShaderMaterial_udwwn")
texture = ExtResource("10_e6e4t")
offset = Vector2(0, -96.995)

[node name="Stage1" type="Sprite2D" parent="FlowerPot/luobobo" unique_id=2111706793]
material = SubResource("ShaderMaterial_bmwd0")
texture = ExtResource("11_kx4t7")
offset = Vector2(0, -118.78)

[node name="Stage2" type="Sprite2D" parent="FlowerPot/luobobo" unique_id=2009713370]
material = SubResource("ShaderMaterial_tbsev")
texture = ExtResource("12_qif7y")
offset = Vector2(0, -152.665)

[node name="Stage3" type="Sprite2D" parent="FlowerPot/luobobo" unique_id=1064223927]
material = SubResource("ShaderMaterial_c562q")
texture = ExtResource("13_vkf0s")
offset = Vector2(0, -172.06)

[node name="Stage4" type="Sprite2D" parent="FlowerPot/luobobo" unique_id=1288124573]
scale = Vector2(0.445, 0.445)
texture = ExtResource("14_eqd53")
offset = Vector2(0, -582.91)

[node name="yayajun" type="Node2D" parent="FlowerPot" unique_id=1542722619]

[node name="Stage0" type="Sprite2D" parent="FlowerPot/yayajun" unique_id=1936009865]
material = SubResource("ShaderMaterial_4j6cc")
position = Vector2(0, -97)
texture = ExtResource("21_bmwd0")

[node name="Stage1" type="Sprite2D" parent="FlowerPot/yayajun" unique_id=142667007]
material = SubResource("ShaderMaterial_f82af")
position = Vector2(-2, -95)
texture = ExtResource("22_tbsev")
offset = Vector2(1, -34)

[node name="Stage2" type="Sprite2D" parent="FlowerPot/yayajun" unique_id=1180342351]
material = SubResource("ShaderMaterial_iqk5x")
position = Vector2(0, -92)
texture = ExtResource("23_c562q")
offset = Vector2(0, -71)

[node name="Stage3" type="Sprite2D" parent="FlowerPot/yayajun" unique_id=1911909795]
material = SubResource("ShaderMaterial_28oxv")
position = Vector2(0, -94)
texture = ExtResource("24_4j6cc")
offset = Vector2(-12, -84)

[node name="Stage4" type="Sprite2D" parent="FlowerPot/yayajun" unique_id=287330915]
scale = Vector2(0.465, 0.465)
texture = ExtResource("25_f82af")
offset = Vector2(0, -500)

[node name="chest" type="Node2D" parent="FlowerPot" unique_id=127599925]

[node name="Stage0" type="Sprite2D" parent="FlowerPot/chest" unique_id=152828852]
material = SubResource("ShaderMaterial_4j6cc")
texture = ExtResource("15_sen5w")
offset = Vector2(0, -99.53)

[node name="Stage1" type="Sprite2D" parent="FlowerPot/chest" unique_id=1025611889]
material = SubResource("ShaderMaterial_f82af")
texture = ExtResource("16_tku3k")
offset = Vector2(0, -116.07)

[node name="Stage2" type="Sprite2D" parent="FlowerPot/chest" unique_id=2040750977]
material = SubResource("ShaderMaterial_iqk5x")
texture = ExtResource("17_57odb")
offset = Vector2(0, -125.62)

[node name="Stage3" type="Sprite2D" parent="FlowerPot/chest" unique_id=1911150715]
material = SubResource("ShaderMaterial_28oxv")
texture = ExtResource("18_oil3b")
offset = Vector2(0, -146.63)

[node name="Stage4" type="Sprite2D" parent="FlowerPot/chest" unique_id=270493958]
scale = Vector2(0.465, 0.465)
texture = ExtResource("19_htl1e")
offset = Vector2(0, -500)

-------------------
# File: res://scenes/main_keyboard.gd


extends Node2D  # 100% 恢复为您最初的 Node 地基,彻底解决层级偏移导致的点击失效!

const WAREHOUSE_WINDOW_SCENE = preload("res://warehouse_window.tscn") # 请确保路径与你实际的 tscn 文件路径一致

# =====================================================================
# 💾 【新增安全织入】:大仓库UI配置与信号总线定义盘(完全不破坏原有骨架)
# =====================================================================
@warning_ignore("unused_signal")
signal key_pressed_at_world_pos(source_global_pos: Vector2)

@export_group("大仓库UI配置总盘")
# 💡 【核心可视化槽位】:在右侧检查器面板开辟一个槽位,允许你直接把写好的大仓库子场景拖进来!
@export var warehouse_window_scene: PackedScene

# 💡 【核心新增】:暴露给最右侧检查器面板的垂直位移微调输入框
# 输入 0 代表绝对居中,输入负数(如 -100)代表向上提,输入正数(如 100)代表向下沉
@export var warehouse_popup_vertical_offset: float = -160.0

# 记录当前在屏幕上已经弹出的仓库窗口实例指针(如果为 null 代表仓库此时是关闭的)
var _active_warehouse_node: Control = null


# --- 原生场景组件与路径挂载 (完美连通) ---
@onready var _group_keys: Node2D = $_group_keys


func _ready() -> void:
	# 重置 Windows 的鼠标物理穿透阻挡,确保操作系统把所有点击权完整还给游戏本身
	DisplayServer.window_set_mouse_passthrough(PackedVector2Array())
	
	print("【系统重置成功】主键盘骨架已完美恢复!游戏前台的原生 TextureButton 点击链已安全解封。")

	# =================================================================
	# 💡 【新增安全织入】:启动背景音乐丝滑缓入
	# =================================================================
	setup_background_music()

	# =================================================================
	# 💡 【新增安全织入】:常驻果冻篮子前台鼠标点击信号直连通车
	# =================================================================
	var real_click_trigger = get_node_or_null("_group_ui/WarehouseButton/ClickDetector")
	if real_click_trigger and real_click_trigger is TextureButton:
		# 强制确保按钮自身处于 Stop 模式,不被任何外界因素吞掉点击
		real_click_trigger.mouse_filter = Control.MOUSE_FILTER_STOP
		if not real_click_trigger.pressed.is_connected(toggle_warehouse_window):
			real_click_trigger.pressed.connect(toggle_warehouse_window)
		print("【大仓库系统】常驻篮子按钮底座透明检测器已成功连线通车!")
	else:
		print("【大仓库系统提示】未在篮子底下找到 ClickDetector,请确认名字和层级是否完全一致!")

	# =================================================================
	# 2. 信号桥接:自动连通来自 C# 的系统底层跨窗口全局后台无焦点键鼠信号
	# =================================================================
	if Engine.has_singleton("GlobalInputHook") or has_node("/root/GlobalInputHook"):
		var global_hook = get_node("/root/GlobalInputHook")
		global_hook.connect("GlobalKeyPressed", Callable(self, "_on_global_key_pressed"))
		global_hook.connect("GlobalMousePressed", Callable(self, "_on_global_mouse_pressed"))


func _process(_delta: float) -> void:
	# 💡 【新增安全织入】:实时把大世界的时间推给全局着色器参数盘,驱动所有噪声波浪运动(Shader用)
	RenderingServer.global_shader_parameter_set("global_noise_time", Time.get_ticks_msec() / 1000.0)


# =====================================================================
# 🏛️ 【新增功能段落】:教常驻篮子如何一点击就把仓库完美弹出与关闭!
# =====================================================================
func toggle_warehouse_window() -> void:
	# 1. 如果当前大仓库已经是打开状态 -> 第二次点击触发,直接销毁收起!
	if is_instance_valid(_active_warehouse_node):
		_active_warehouse_node.queue_free()
		_active_warehouse_node = null
		print("【大仓库系统】大屋子面板已安全收起。")
		return
		
	# 2. 如果当前仓库是关闭状态 -> 第一次点击触发,动态实例化克隆弹窗!
	if warehouse_window_scene != null:
		var new_window = warehouse_window_scene.instantiate()
		
		# 将其精准扔进常驻 UI 层
		var ui_layer = get_node_or_null("_group_ui")
		if ui_layer:
			ui_layer.add_child(new_window)
		else:
			add_child(new_window)
			
		# A. 先让窗口执行官方标准的屏幕正中央几何对齐
		new_window.set_anchors_and_offsets_preset(Control.PRESET_CENTER, Control.PRESET_MODE_MINSIZE)
		
		# B. 💡 【全自动化动态位置微调核心公式】:
		# 100% 尊重您在右侧属性栏里手敲的数值,实时对窗口的全局 Y 轴坐标实施叠加偏移修正!
		new_window.global_position.y += warehouse_popup_vertical_offset
		
		_active_warehouse_node = new_window
		print("【大仓库系统】大屋子面板已成功弹出,当前垂直位移修正量为: ", warehouse_popup_vertical_offset)


# =====================================================================
# 🎵 【新增功能段落】:全局背景音乐播放与丝滑缓入
# =====================================================================
func setup_background_music() -> void:
	var config_path = "res://resources/pot_data_standard.tres" 
	if not ResourceLoader.exists(config_path): return
	var pot_config = load(config_path)
	var bgm_path = pot_config.get("bgm_sound_path") if "bgm_sound_path" in pot_config else ""
	
	if bgm_path != "" and ResourceLoader.exists(bgm_path):
		var bgm_player = AudioStreamPlayer.new()
		bgm_player.stream = load(bgm_path)
		add_child(bgm_player)
		bgm_player.finished.connect(func(): if is_instance_valid(bgm_player): bgm_player.play())
		
		var target_vol = pot_config.get("bgm_volume") if "bgm_volume" in pot_config else 0.8
		var target_db = linear_to_db(target_vol)
		var fade_time = pot_config.get("bgm_fade_time") if "bgm_fade_time" in pot_config else 1.5
		
		if fade_time > 0.0:
			bgm_player.volume_db = -80.0
			bgm_player.play()
			var tween = create_tween()
			tween.tween_property(bgm_player, "volume_db", target_db, fade_time).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
		else:
			bgm_player.volume_db = target_db
			bgm_player.play()


# =================================================================
# 3. 【核心跨层联动】1:1 原汁原味完美保留您失去焦点时的全局跨窗口键鼠输入响应
# =================================================================

# 接收失去焦点时的全局键盘事件
func _on_global_key_pressed(vk_code: int) -> void:
	if DisplayServer.window_is_focused():
		return # 前台运行时由引擎默认输入处理,后台运行时由本钩子接管

	var godot_key: int = KEY_NONE
	if vk_code >= 65 and vk_code <= 90:    godot_key = vk_code
	elif vk_code >= 48 and vk_code <= 57:  godot_key = vk_code
	elif vk_code >= 96 and vk_code <= 105: godot_key = KEY_KP_0 + (vk_code - 96)
	elif vk_code == 20:  godot_key = KEY_CAPSLOCK
	elif vk_code == 16 or vk_code == 160 or vk_code == 161: godot_key = KEY_SHIFT
	elif vk_code == 17 or vk_code == 162 or vk_code == 163: godot_key = KEY_CTRL
	elif vk_code == 18 or vk_code == 164 or vk_code == 165: godot_key = KEY_ALT
	elif vk_code == 91 or vk_code == 92:                    godot_key = KEY_META
	elif vk_code == 37:  godot_key = KEY_LEFT
	elif vk_code == 38:  godot_key = KEY_UP
	elif vk_code == 39:  godot_key = KEY_RIGHT
	elif vk_code == 40:  godot_key = KEY_DOWN
	elif vk_code == 32:  godot_key = KEY_SPACE
	elif vk_code == 13:  godot_key = KEY_ENTER
	elif vk_code == 8:   godot_key = KEY_BACKSPACE
	elif vk_code == 9:   godot_key = KEY_TAB
	elif vk_code == 27:  godot_key = KEY_ESCAPE
	elif vk_code == 186: godot_key = KEY_SEMICOLON
	elif vk_code == 187: godot_key = KEY_EQUAL
	elif vk_code == 188: godot_key = KEY_COMMA
	elif vk_code == 189: godot_key = KEY_MINUS
	elif vk_code == 190: godot_key = KEY_PERIOD
	elif vk_code == 191: godot_key = KEY_SLASH
	elif vk_code == 192: godot_key = KEY_QUOTELEFT
	elif vk_code == 219: godot_key = KEY_BRACKETLEFT
	elif vk_code == 220: godot_key = KEY_BACKSLASH
	elif vk_code == 221: godot_key = KEY_BRACKETRIGHT
	elif vk_code == 222: godot_key = KEY_APOSTROPHE

	if godot_key == KEY_NONE:
		return

	var global_key_name = OS.get_keycode_string(godot_key).to_lower()

	if _group_keys:
		for key_node in _group_keys.get_children():
			if key_node.has_method("advance_logic"):
				var key_node_name = OS.get_keycode_string(key_node.trigger_keycode).to_lower()
				if key_node_name == global_key_name:
					key_node.trigger_press_displacement()
					key_node.advance_logic()
					break


# ==================== 底层规避:多键位独立穿透广播功能段落 ====================
func _on_global_mouse_pressed(button_index: int, _screen_x: int, _screen_y: int) -> void:
	var mouse_canvas_pos = get_viewport().get_mouse_position()
	var btn = $_group_ui/WarehouseButton/ClickDetector
	var btn_canvas_rect = Rect2(btn.global_position, btn.size)
	
	# 1. 优先判定:如果是左键点击,且刚好点到了篮子区域,只处理仓库开关,绝对不广播任何输入
	if button_index == MOUSE_BUTTON_LEFT and btn_canvas_rect.has_point(mouse_canvas_pos):
		print("成功点击到了篮子区域!开始切换仓库显示状态...")
		var ui_group = $_group_ui
		var window = ui_group.find_child("warehouse_window", true, false)
		
		if not window:
			window = WAREHOUSE_WINDOW_SCENE.instantiate()
			window.name = "warehouse_window"
			ui_group.add_child(window)
			if window is Control:
				window.custom_minimum_size = window.size
			var screen_size = get_viewport().get_visible_rect().size
			var window_size = window.size if (window is Control and window.size > Vector2.ZERO) else Vector2(600, 400)
			var target_x = (screen_size.x - window_size.x) / 2.0
			var target_y = ((screen_size.y - window_size.y) / 2.0) - 200.0
			window.global_position = Vector2(target_x, target_y)
			ui_group.move_child(window, -1)
			window.show()
		else:
			if window.visible:
				window.hide()
				print("仓库窗口已隐藏")
			else:
				ui_group.move_child(window, -1) 
				window.show()
				print("仓库窗口已重新显示")
				
	# 2. 局外判定:点的是篮子以外的区域,或者是右键/滚轮,则通过底层专用的推流方式,只把点击传给游戏世界和作物,对 UI 隐形
	else:
		if button_index in [MOUSE_BUTTON_LEFT, MOUSE_BUTTON_RIGHT, MOUSE_BUTTON_MIDDLE, MOUSE_BUTTON_WHEEL_UP, MOUSE_BUTTON_WHEEL_DOWN]:
			var raw_event = InputEventMouseButton.new()
			raw_event.button_index = button_index
			raw_event.pressed = true
			# 底层防错:将坐标直接打入当前视口,避免大范围坐标错位
			raw_event.position = mouse_canvas_pos
			raw_event.global_position = mouse_canvas_pos
			
			# 【从底层规避粘连的核心修改】:使用推流将点击事件定点发送给主视口输入通道。
			# 这样做能绕过全局输入捕获(避免窗口认为鼠标被按住),直接送去触发作物和农田。
			get_viewport().push_input(raw_event) 
# ==============================================================================

-------------------
# File: res://scenes/ui/inventory_slot.gd

# =====================================================================
extends Control

# 自定义信号:当该小格子被右键点击时触发,通知大窗口将本格全部数量快速闪击分流到出货区
signal slot_right_clicked(item_id: String, slot_amount: int)

# =====================================================================
# 🎛️ 📥 100% 全可视化资源槽位区(全部自己选图片,彻底斩断硬路径!)
# =====================================================================
@export_group("4色稀有度基础背景自选槽位")
@export var bg_rarity_0_common: Texture2D       # 稀有度 0 (普通 -> 无/白色背景)
@export var bg_rarity_1_rare: Texture2D         # 稀有度 1 (稀有 -> 浅蓝背景)
@export var bg_rarity_2_epic: Texture2D         # 稀有度 2 (史诗 -> 紫色背景)
@export var bg_rarity_3_legendary: Texture2D    # 稀有度 3 (传说 -> 金色背景)

# ⚙️ 内部节点高速底层指针引用
@onready var bg_rect: TextureRect = $BackgroundSprite
@onready var icon_rect: TextureRect = $IconSprite
@onready var count_label: Label = $AmountLabel

# 本格当前承载的动态运行时物品数据镜像
var bound_item_data: BaseItemData = null
var current_slot_count: int = 0

func _ready() -> void:
	# 强固开启鼠标过滤模式:Stop 代表吃掉事件,优先响应格子点击,绝不让点格子时连带把大屋子移动走!
	mouse_filter = Control.MOUSE_FILTER_STOP



func set_slot_data(item_data: BaseItemData, amount: int) -> void:
	bound_item_data = item_data
	current_slot_count = amount
	
	# 1. 🪙 堆叠数量标签刷新
	if count_label:
		count_label.text = str(amount)
		count_label.visible = (amount > 1)
		
	# 2. 🌾 【全自动化名字自适应抓取引擎 - 精准对齐截图文件名版】
	# 初始基础拼装前缀:res://assets/sprites/items/主题名/
	var base_folder_path: String = "res://assets/sprites/items/" + item_data.theme_id + "/"
	var final_icon_load_path: String = ""
	
	if item_data.category == BaseItemData.ItemCategory.POT:
		# 🏺 花盆类型规则:对齐截图中的 "pot_default_size_0.png" 格式
		# 主题路径 + pots/ + pot_ + 花盆名 + _size_0.png
		final_icon_load_path = base_folder_path + "pots/pot_" + item_data.item_id + "_size_0.png"
		
	elif item_data.category == BaseItemData.ItemCategory.CROP:
		# 🌾 作物与箱子类型规则:对齐截图中的 "tuqiuhua_stage_5.png"、"chest_stage_5.png" 格式
		# 主题路径 + crops/ + 作物名/ + 作物名 + _stage_5.png
		final_icon_load_path = base_folder_path + "crops/" + item_data.item_id + "/" + item_data.item_id + "_stage_5.png"
		
	elif item_data.category == BaseItemData.ItemCategory.STICKER:
		# 🏷️ 贴纸类型规则(未来手账预留):贴纸名_inv_icon.png
		final_icon_load_path = base_folder_path + "stickers/" + item_data.item_id + "/" + item_data.item_id + "_inv_icon.png"

	# 运行时强固磁盘路径检测:只有当该图片在文件系统中真实存在时,才进行动态 load()
	if final_icon_load_path != "" and ResourceLoader.exists(final_icon_load_path):
		if icon_rect:
			icon_rect.texture = load(final_icon_load_path) as Texture2D
			icon_rect.visible = true
	else:
		# 如果路径没对齐,图标自动隐去作为安全保护,并在控制台给出极其清晰的官方排查路径提示
		if icon_rect: icon_rect.visible = false
		print("【资产全自动抓取提示】未找到该切片,请核对磁盘上是否存在该文件: ", final_icon_load_path)
		
	# 3. 🎴 4色稀有度全自动无if-else换装大盘(保持不变)
	if bg_rect:
		match item_data.rarity:
			0: bg_rect.texture = bg_rarity_0_common
			1: bg_rect.texture = bg_rarity_1_rare
			2: bg_rect.texture = bg_rarity_2_epic
			3: bg_rect.texture = bg_rarity_3_legendary



# =====================================================================
# 📦 出货售卖格样式强制强制重写替换(供大面板_update_sale_bar_visuals反射调用)
# =====================================================================
func force_set_sale_style(sale_bg_texture: Texture2D) -> void:
	# 彻底屏蔽原生的稀有度背景,换为您在窗口上填入的、画好的专用售卖正方形底图 `slot_sale_bg.png`
	if bg_rect and sale_bg_texture != null:
		bg_rect.texture = sale_bg_texture


# =====================================================================
# 🖱️ 鼠标高频高级交互事件拦截总网闸
# =====================================================================
func _gui_input(event: InputEvent) -> void:
	if event is InputEventMouseButton and event.pressed:
		# 💡 【核心交互:鼠标右键点击一键全量闪击出货】
		if event.button_index == MOUSE_BUTTON_RIGHT and bound_item_data != null:
			# 发射信号给大窗口总控制器,把当前的 item_id 和格子内的全量堆叠数直接装车送走!
			slot_right_clicked.emit(bound_item_data.item_id, current_slot_count)



func _get_drag_data(_at_position: Vector2) -> Variant:
	if bound_item_data == null or current_slot_count <= 0: return null
	
	# 💡 【彻底精简】:移除任何半透明与缩放特效,直接使用最干净的原生图片作为抓取影子
	var drag_preview = TextureRect.new()
	drag_preview.texture = icon_rect.texture
	drag_preview.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
	drag_preview.stretch_mode = TextureRect.STRETCH_KEEP_CENTERED
	drag_preview.size = size 
	
	set_drag_preview(drag_preview)
	
	# 传递单例大字典绝对认得的原始大主键
	var drag_payload = {
		"type": "warehouse_item",
		"item_id": bound_item_data.item_id,
		"slot_amount": current_slot_count
	}
	return drag_payload


# 💡 【全放行核心解药】:让每一个小格子面对拖拽时全部亮起绿灯,100% 根除任何红圈禁止符号!
# =====================================================================
# 📄 彻底净化版:完整覆盖替换 res://scenes/ui/inventory_slot.gd 最末尾
# =====================================================================
func _can_drop_data(_at_position: Vector2, data: Variant) -> bool:
	if data is Dictionary and data.has("type") and data["type"] == "warehouse_item":
		return true
	return false

func _drop_data(_at_position: Vector2, data: Variant) -> void:
	# 💡 【解药 1】:格子本身绝不处理任何复杂的空间分流逻辑!
	# 当玩家把货松手在底部的任何一个售卖格子上时,格子全自动把球踢给大窗口的根节点去统一处理
	var warehouse_root = get_node_or_null("../../")
	if warehouse_root == null or not warehouse_root.has_method("_drop_data"):
		warehouse_root = get_node_or_null("../../../../")
		
	if warehouse_root and warehouse_root.has_method("_drop_data"):
		# 强行调用大窗口总控的官方接收函数,并将当前鼠标在【全游戏大屏幕上的全局绝对像素坐标】直接拍过去!
		warehouse_root._drop_data(warehouse_root.get_global_mouse_position(), data)

-------------------
# File: res://scenes/ui/inventory_slot.tscn

[gd_scene format=3 uid="uid://b17bdqxu1eliy"]

[ext_resource type="Script" uid="uid://betqtenxik6jo" path="res://scenes/ui/inventory_slot.gd" id="1_uda2d"]
[ext_resource type="Texture2D" uid="uid://c1rl8bou4btud" path="res://assets/sprites/ui/warehouse/slot_rarity_0.png" id="2_hytmx"]
[ext_resource type="Texture2D" uid="uid://dvel8418s71me" path="res://assets/sprites/ui/warehouse/slot_rarity_1.png" id="3_gd4e4"]
[ext_resource type="Texture2D" uid="uid://blc8fkm4isae5" path="res://assets/sprites/ui/warehouse/slot_rarity_2.png" id="4_wmsr3"]
[ext_resource type="Texture2D" uid="uid://dorf11025tpkk" path="res://assets/sprites/ui/warehouse/slot_rarity_3.png" id="5_onxkp"]

[node name="inventory_slot" type="AspectRatioContainer" unique_id=895664333]
custom_minimum_size = Vector2(205, 205)
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
alignment_horizontal = 0
alignment_vertical = 0
script = ExtResource("1_uda2d")
bg_rarity_0_common = ExtResource("2_hytmx")
bg_rarity_1_rare = ExtResource("3_gd4e4")
bg_rarity_2_epic = ExtResource("4_wmsr3")
bg_rarity_3_legendary = ExtResource("5_onxkp")

[node name="BackgroundSprite" type="TextureRect" parent="." unique_id=220160541]
layout_mode = 2
expand_mode = 1

[node name="IconSprite" type="TextureRect" parent="." unique_id=695285752]
layout_mode = 2
mouse_filter = 2
expand_mode = 1
stretch_mode = 5

[node name="AmountLabel" type="Label" parent="." unique_id=1315788424]
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 0
theme_override_colors/font_color = Color(18.892157, 18.892157, 18.892157, 0.92941177)
theme_override_colors/font_outline_color = Color(0, 0, 0, 0.5058824)
theme_override_constants/outline_size = 15
theme_override_font_sizes/font_size = 65
horizontal_alignment = 2

-------------------
# File: res://scenes/ui/warehouse_window.gd

extends Control

const INVENTORY_SLOT_SCENE = preload("res://scenes/ui/inventory_slot.tscn")

@export_group("大仓库专用可视化资源槽位")
@export var sale_slot_background: Texture2D     

@onready var grid_container: GridContainer = $PanelContainer_Main/ScrollContainer_Grid/GridContainer_Items
@onready var scroll_container: ScrollContainer = $PanelContainer_Main/ScrollContainer_Grid
@onready var coin_label: Label = $PanelContainer_Main/GoldBarBG/CoinDisplayLabel
@onready var sale_hbox: HBoxContainer = $PanelContainer_Main/SaleBarBG/HBoxContainer_Sale

var current_category: int = 1           
var current_sort_type: String = "theme" 

var sort_ascending_theme: bool = false
var sort_ascending_rarity: bool = false
var sort_ascending_amount: bool = false

var is_dragging: bool = false
var drag_position: Vector2 = Vector2.ZERO

var sell_queue: Array = []


func _ready() -> void:
	scroll_container.vertical_scroll_mode = ScrollContainer.SCROLL_MODE_SHOW_ALWAYS
	scroll_container.horizontal_scroll_mode = ScrollContainer.SCROLL_MODE_DISABLED
	
	# 确保大仓库根节点吸收背景点击,防止穿透
	mouse_filter = Control.MOUSE_FILTER_STOP
	
	# 💡 【核心通车对齐】:强行开启中间格子区的鼠标透传,让拖拽放手电信号毫无阻挡直达底盘
	grid_container.mouse_filter = Control.MOUSE_FILTER_PASS
	scroll_container.mouse_filter = Control.MOUSE_FILTER_PASS
	
	Warehouse.warehouse_updated.connect(refresh_warehouse_view)
	Warehouse.coins_changed.connect(_on_global_coins_changed)
	
	_setup_ui_buttons_signals()
	
	_on_global_coins_changed(Warehouse.coins)
	refresh_warehouse_view()


func _process(_delta: float) -> void:
	if grid_container.get_child_count() <= 24:
		scroll_container.scroll_vertical = 0


# =====================================================================
# 🧮 核心前端渲染引擎:数据驱动拆格与正倒序复合排序
# =====================================================================
func refresh_warehouse_view() -> void:
	for child in grid_container.get_children():
		child.queue_free()
		
	var raw_display_list: Array = []
	for key_id in Warehouse.inventory:
		var item_node = Warehouse.inventory[key_id]
		if item_node.data.category == current_category and item_node.amount > 0:
			item_node["_dict_key_id"] = key_id
			raw_display_list.append(item_node)
			
	raw_display_list.sort_custom(func(a, b):
		if current_sort_type == "rarity":
			if a.data.rarity != b.data.rarity:
				return a.data.rarity < b.data.rarity if sort_ascending_rarity else a.data.rarity > b.data.rarity
		elif current_sort_type == "amount":
			if a.amount != b.amount:
				return a.amount < b.amount if sort_ascending_amount else a.amount > b.amount
		if a.data.theme_id != b.data.theme_id:
			return a.data.theme_id > b.data.theme_id if sort_ascending_theme else a.data.theme_id < b.data.theme_id
		return a.amount > b.amount
	)
	
	var stack_limit: int = 999
	var p_config = load("res://resources/pot_data_standard.tres")
	if p_config and "max_stack_size" in p_config:
		stack_limit = max(1, p_config.max_stack_size)

	for item_node in raw_display_list:
		var total_count: int = item_node.amount
		var item_data: BaseItemData = item_node.data
		var current_dict_key: String = item_node["_dict_key_id"]
		
				# 💡 【整除警告修复】:擦除冗余的 floor(),直接使用官方标准的 / 整数除法,黄标警告一秒熄灭
		var full_slots_count = total_count / stack_limit
		var remainder_count = total_count % stack_limit
		
		for k in range(full_slots_count):
			_instantiate_and_render_slot(item_data, stack_limit)
			
		if remainder_count > 0:
			_instantiate_and_render_slot(item_data, remainder_count)

			
	_update_sale_bar_visuals()


func _instantiate_and_render_slot(item_data: BaseItemData, display_amount: int) -> void:
	var slot_instance = INVENTORY_SLOT_SCENE.instantiate()
	grid_container.add_child(slot_instance)
	
	if slot_instance.has_method("set_slot_data"):
		slot_instance.set_slot_data(item_data, display_amount)
		
	if slot_instance.has_signal("slot_right_clicked"):
		# 💡 【未使用参数警告修复】:在前面精准补齐下划线修改为 _ignored_id,编译器一秒变清爽
		slot_instance.connect("slot_right_clicked", func(_ignored_id, slot_amt):
			push_into_sell_queue(item_data.item_id, slot_amt)
		)



# =====================================================================
# 💰 智能出货临时售卖队列(先进先出与即时财富回溯)
# =====================================================================
func push_into_sell_queue(item_id: String, sell_amount: int) -> void:
	# 1. 提取数据并即时从单例总背包内扣减,金币账户立刻即时财富加钱入账
	var fetched_data = Warehouse.move_to_sell_queue(item_id, sell_amount)
	if fetched_data == null: return
	
	# 2. 动态读取您面板截图上设定的 max_stack_size 堆叠上限
	var stack_limit: int = 999
	var p_config = load("res://resources/pot_data_standard.tres")
	if p_config and "max_stack_size" in p_config:
		stack_limit = max(1, p_config.max_stack_size)
		
	# 3. 🧮 【售卖区堆叠分格拆分算法】:将当前塞入的数量放入售卖缓冲池中
	# 改变以往的直接追加模式,改成先寻找末尾未满额的同种物品格进行合并,或者新开满额格
	var remaining_to_push = sell_amount
	
	# 3.1 尝试优先填满原本处于 sell_queue 末尾、且尚未达到 stack_limit 的同种物资零头格
	for queued_item in sell_queue:
		if queued_item["item_id"] == item_id and queued_item["amount"] < stack_limit:
			var room_left = stack_limit - queued_item["amount"]
			var add_to_this = min(remaining_to_push, room_left)
			queued_item["amount"] += add_to_this
			remaining_to_push -= add_to_this
			if remaining_to_push <= 0:
				break
				
	# 3.2 如果还有多出来的数量(或者根本没有零头格),全自动按照 stack_limit 拆分并产生新售卖格单元
	while remaining_to_push > 0:
		var this_slot_amount = min(remaining_to_push, stack_limit)
		sell_queue.append({
			"item_id": item_id,
			"amount": this_slot_amount,
			"data": fetched_data
		})
		remaining_to_push -= this_slot_amount
		
	# 4. 💡 【强固先进先出 FIFO 爆仓拦截闸】:死磕出货缓冲带长度最大只能为 6 格!
	# 由于开启了底部堆叠拆格,如果一次性拽入或右键闪击了大量物资导致底部格数爆发超过 6
	# 循环执行 pop_front() 清理,直到刚好留下最后装车的 6 格物资
	while sell_queue.size() > 6:
		var popped_trash = sell_queue.pop_front()
		print("【FIFO售卖区爆仓】出货条超过6格上限!最老物品格子 [", popped_trash["data"].item_name, " x", popped_trash["amount"], "] 已被永久打包运走!")
		
	refresh_warehouse_view()


func pop_out_from_sell_queue_index(index: int) -> void:
	if index < 0 or index >= sell_queue.size(): return
	var target_refund = sell_queue[index]
	
	Warehouse.refund_from_sell_queue(target_refund["item_id"], target_refund["amount"])
	sell_queue.remove_at(index)
	refresh_warehouse_view()


func _update_sale_bar_visuals() -> void:
	for child in sale_hbox.get_children():
		child.queue_free()
		
	# 强制固定渲染 6 个底座
	for i in range(6):
		var sale_slot = INVENTORY_SLOT_SCENE.instantiate()
		sale_hbox.add_child(sale_slot)
		
		# 强制将小格子的基础背景图重置替换为您在面板上选中的专用 `slot_sale_bg.png`
		if sale_slot.has_method("force_set_sale_style") and sale_slot_background != null:
			sale_slot.force_set_sale_style(sale_slot_background)
			
		# 💡 由于现在 sell_queue 在上游已经被算法自动拆分成了一个个完全符合 Max Stack Size 限制的独立元素项
		# 此处直接读取对应的数组元素进行无脑平铺展现即可,逻辑完美无缝对齐!
		if i < sell_queue.size():
			var item_info = sell_queue[i]
			if sale_slot.has_method("set_slot_data"):
				sale_slot.set_slot_data(item_info["data"], item_info["amount"])
			
			var current_index = i
			sale_slot.gui_input.connect(func(event):
				if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
					pop_out_from_sell_queue_index(current_index)
			)

# =====================================================================
# 🕹️ 鼠标高级交互总网闸与 100% 强固 DND 接收端
# =====================================================================
func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventMouseButton and event.pressed and event.button_index == MOUSE_BUTTON_LEFT:
		var panel_rect: Rect2 = $PanelContainer_Main.get_global_rect()
		var click_pos: Vector2 = get_global_mouse_position()
		
		if not panel_rect.has_point(click_pos):
			var main_scene = get_tree().current_scene
			if main_scene and main_scene.has_method("toggle_warehouse_window"):
				get_viewport().set_input_as_handled()
				main_scene.toggle_warehouse_window()


func _gui_input(event: InputEvent) -> void:
	if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
		if event.pressed:
			is_dragging = true
			drag_position = get_global_mouse_position() - global_position
		else:
			is_dragging = false
			
	if event is InputEventMouseMotion and is_dragging:
		global_position = get_global_mouse_position() - drag_position


# 💡 【全大盘唯一最高准入总网闸】:完全合并净化,彻底抹平重复命名冲突!
func _can_drop_data(_at_position: Vector2, data: Variant) -> bool:
	if data is Dictionary and data.has("type") and data["type"] == "warehouse_item":
		return true
	return false


# 💡 【全局屏幕绝对像素坐标撞击算法】:无论窗口怎么移动,松手一瞬间精准捕获!
func _drop_data(_at_position: Vector2, data: Variant) -> void:
	# 抓取鼠标此时在全显示器屏幕上的绝对物理像素坐标点
	var mouse_global_pos: Vector2 = get_global_mouse_position()
	
	# 精准锁定你在编辑器中摆好的售卖区大横条底图节点
	var sale_bar_node = get_node_or_null("PanelContainer_Main/SaleBarBG")
	if sale_bar_node == null: return
	
	# 提取该节点此时在全屏幕上的绝对矩形物理范围(完美无视任何下方子格子的信号吞噬和拦截!)
	var sale_global_rect: Rect2 = sale_bar_node.get_global_rect()
	
	var item_id: String = data["item_id"]
	var available_amount: int = data["slot_amount"]
	
	# 🌊 如果松手时鼠标指针【正好落在这个大横条的物理边界内部】
	if sale_global_rect.has_point(mouse_global_pos):
		push_into_sell_queue(item_id, available_amount)
	else:
		# 如果松手在外面(拽回背包),执行反悔回溯
		var found_index: int = -1
		for idx in range(sell_queue.size()):
			if sell_queue[idx]["item_id"] == item_id:
				found_index = idx
				break
				
		if found_index != -1:
			pop_out_from_sell_queue_index(found_index)


func _on_global_coins_changed(new_coins: int) -> void:
	coin_label.text = str(new_coins)


func _setup_ui_buttons_signals() -> void:
	var cat_pot = get_node_or_null("PanelContainer_Main/TabCategory_Pot")
	var cat_crop = get_node_or_null("PanelContainer_Main/TabCategory_Crop")
	var cat_stk = get_node_or_null("PanelContainer_Main/TabCategory_Sticker")
	
	if cat_pot: cat_pot.pressed.connect(func(): current_category = 0; refresh_warehouse_view())
	if cat_crop: cat_crop.pressed.connect(func(): current_category = 1; refresh_warehouse_view())
	if cat_stk: cat_stk.pressed.connect(func(): current_category = 2; refresh_warehouse_view())
	
	var sort_theme = get_node_or_null("PanelContainer_Main/BtnSort_Theme")
	var sort_rarity = get_node_or_null("PanelContainer_Main/BtnSort_Rarity")
	var sort_amt = get_node_or_null("PanelContainer_Main/BtnSort_Amount")
	
	if sort_theme: sort_theme.pressed.connect(func(): if current_sort_type == "theme": sort_ascending_theme = not sort_ascending_theme else: current_sort_type = "theme"; refresh_warehouse_view())
	if sort_rarity: sort_rarity.pressed.connect(func(): if current_sort_type == "rarity": sort_ascending_rarity = not sort_ascending_rarity else: current_sort_type = "rarity"; refresh_warehouse_view())
	if sort_amt: sort_amt.pressed.connect(func(): if current_sort_type == "amount": sort_ascending_amount = not sort_ascending_amount else: current_sort_type = "amount"; refresh_warehouse_view())

-------------------
# File: res://warehouse_window.tscn

[gd_scene format=3 uid="uid://hcq7jw51ihgt"]

[ext_resource type="Script" uid="uid://bxc13kux7m5t0" path="res://scenes/ui/warehouse_window.gd" id="1_noxtk"]
[ext_resource type="Texture2D" uid="uid://crx43u65uqk1s" path="res://assets/sprites/ui/warehouse/slot_sale.png" id="2_3bc7t"]
[ext_resource type="Texture2D" uid="uid://bknluwhan41g0" path="res://assets/sprites/ui/warehouse/warehouse_bg.png" id="2_qg72l"]
[ext_resource type="Texture2D" uid="uid://ds8r630ytd5f3" path="res://assets/sprites/ui/warehouse/tab_category_pot.png" id="3_ay6kt"]
[ext_resource type="Texture2D" uid="uid://b2bmx5u8e81gu" path="res://assets/sprites/ui/warehouse/tab_category_crop.png" id="4_3bc7t"]
[ext_resource type="Texture2D" uid="uid://b15h5ce6crupj" path="res://assets/sprites/ui/warehouse/tab_category_sticker.png" id="5_50gng"]
[ext_resource type="Texture2D" uid="uid://dvedhp7xr3dq5" path="res://assets/sprites/ui/warehouse/btn_sort_theme.png" id="6_hhl8r"]
[ext_resource type="Texture2D" uid="uid://cdaylcm36i805" path="res://assets/sprites/ui/warehouse/btn_sort_rarity.png" id="7_k224d"]
[ext_resource type="Texture2D" uid="uid://ie6gg67a4ig7" path="res://assets/sprites/ui/warehouse/btn_sort_amount.png" id="8_l51yn"]
[ext_resource type="Texture2D" uid="uid://dyvc87mnvkmeh" path="res://assets/sprites/ui/warehouse/marketplace.png" id="9_ay6kt"]
[ext_resource type="Texture2D" uid="uid://h52foqiqjc3x" path="res://assets/sprites/ui/warehouse/Gold_Bar.png" id="9_qg72l"]

[node name="warehouse_window" type="Control" unique_id=1883350495]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_noxtk")
sale_slot_background = ExtResource("2_3bc7t")

[node name="InvisibleCloseOverlay" type="Control" parent="." unique_id=614560863]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

[node name="PanelContainer_Main" type="TextureRect" parent="." unique_id=808524561]
layout_mode = 1
anchors_preset = -1
anchor_left = 0.492
anchor_top = 0.409
anchor_right = 0.492
anchor_bottom = 0.409
offset_left = -783.28
offset_top = -780.44
offset_right = 779.72
offset_bottom = 782.56
texture = ExtResource("2_qg72l")
expand_mode = 1

[node name="TabCategory_Pot" type="TextureButton" parent="PanelContainer_Main" unique_id=1447388443]
layout_mode = 1
anchors_preset = -1
anchor_left = -0.017
anchor_top = 0.51000005
anchor_right = -0.017
anchor_bottom = 0.51000005
offset_left = -82.429
offset_top = -84.130066
offset_right = 83.571
offset_bottom = 84.869934
texture_normal = ExtResource("3_ay6kt")

[node name="TabCategory_Crop" type="TextureButton" parent="PanelContainer_Main" unique_id=292850791]
layout_mode = 1
anchors_preset = -1
anchor_left = -0.015000001
anchor_top = 0.63600004
anchor_right = -0.015000001
anchor_bottom = 0.63600004
offset_left = -83.555
offset_top = -85.068054
offset_right = 82.445
offset_bottom = 83.931946
texture_normal = ExtResource("4_3bc7t")

[node name="TabCategory_Sticker" type="TextureButton" parent="PanelContainer_Main" unique_id=970198712]
layout_mode = 1
anchors_preset = -1
anchor_left = -0.013
anchor_top = 0.76100004
anchor_right = -0.013
anchor_bottom = 0.76100004
offset_left = -83.681
offset_top = -84.443115
offset_right = 82.319
offset_bottom = 84.556885
texture_normal = ExtResource("5_50gng")

[node name="BtnSort_Theme" type="TextureButton" parent="PanelContainer_Main" unique_id=1259571941]
layout_mode = 1
anchors_preset = -1
anchor_left = 1.026
anchor_top = 0.512
anchor_right = 1.026
anchor_bottom = 0.512
offset_left = -82.63806
offset_top = -84.25604
offset_right = 83.36194
offset_bottom = 84.74396
texture_normal = ExtResource("6_hhl8r")

[node name="BtnSort_Rarity" type="TextureButton" parent="PanelContainer_Main" unique_id=253163872]
layout_mode = 1
anchors_preset = -1
anchor_left = 1.028
anchor_top = 0.638
anchor_right = 1.028
anchor_bottom = 0.638
offset_left = -83.76404
offset_top = -85.19403
offset_right = 82.23596
offset_bottom = 83.80597
texture_normal = ExtResource("7_k224d")

[node name="BtnSort_Amount" type="TextureButton" parent="PanelContainer_Main" unique_id=1567327281]
layout_mode = 1
anchors_preset = -1
anchor_left = 1.029
anchor_top = 0.763
anchor_right = 1.029
anchor_bottom = 0.763
offset_left = -82.32703
offset_top = -84.56897
offset_right = 83.67297
offset_bottom = 84.43103
texture_normal = ExtResource("8_l51yn")

[node name="ScrollContainer_Grid" type="ScrollContainer" parent="PanelContainer_Main" unique_id=1571021461]
layout_mode = 1
anchors_preset = -1
anchor_left = 0.497
anchor_top = 0.66800004
anchor_right = 0.497
anchor_bottom = 0.66800004
offset_left = -631.81104
offset_top = -452.0841
offset_right = 680.18896
offset_bottom = 448.9159

[node name="GridContainer_Items" type="GridContainer" parent="PanelContainer_Main/ScrollContainer_Grid" unique_id=585543618]
layout_mode = 2
theme_override_constants/h_separation = 5
theme_override_constants/v_separation = 5
columns = 6

[node name="GoldBarBG" type="TextureRect" parent="PanelContainer_Main" unique_id=1033860893]
layout_mode = 0
offset_left = 68.0
offset_top = 1520.0
offset_right = 1503.0
offset_bottom = 1709.0
texture = ExtResource("9_qg72l")

[node name="CoinDisplayLabel" type="Label" parent="PanelContainer_Main/GoldBarBG" unique_id=740216695]
layout_mode = 1
anchors_preset = -1
anchor_left = 0.148
anchor_top = 0.5
anchor_right = 0.148
anchor_bottom = 0.5
offset_left = 0.6199951
offset_top = -51.5
offset_right = 1106.62
offset_bottom = 52.5
theme_override_colors/font_color = Color(0, 0, 0, 0.6745098)
theme_override_font_sizes/font_size = 76

[node name="SaleBarBG" type="TextureRect" parent="PanelContainer_Main" unique_id=956835255]
layout_mode = 0
offset_left = 51.0
offset_top = 1672.0
offset_right = 1535.0
offset_bottom = 1943.0
texture = ExtResource("9_ay6kt")
expand_mode = 1

[node name="HBoxContainer_Sale" type="HBoxContainer" parent="PanelContainer_Main/SaleBarBG" unique_id=1443989732]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
offset_left = 96.0
offset_top = 31.0
offset_right = -107.0
offset_bottom = -28.0
grow_horizontal = 2
grow_vertical = 2

-------------------
# File: res://resources/pot_data_standard.tres

[gd_resource type="Resource" script_class="PotConfig" format=3 uid="uid://exmkmdcimin7"]

[ext_resource type="Script" uid="uid://drdur516kovcw" path="res://pot_data.gd" id="1_g65sj"]
[ext_resource type="Texture2D" uid="uid://dk44nhapwq5cp" path="res://assets/sprites/environment/plus_one.png" id="1_gpd3o"]

[resource]
script = ExtResource("1_g65sj")
bgm_sound_path = "uid://n4tx43g0q48t"
bgm_volume = 1.0
bgm_fade_time = 0.2
harvest_sound_path = "uid://bky6cfot3f2k5"
harvest_volume = 0.8
chest_harvest_sound_path = "uid://b0snoue8bxhgc"
plus_one_texture = ExtResource("1_gpd3o")
metadata/_custom_type_script = "uid://drdur516kovcw"

-------------------
# File: res://window_controller.gd

# ==========================================
# 独立组件:游戏窗口拖拽与滚轮缩放控制器 (最终完美版)
# 核心哲学:零渲染开销,全穿透不拦截,防抖动缩放
# ==========================================
extends Node

@export_group("缩放配置")
@export var min_scale: float = 0.1
@export var max_scale: float = 1.0
@export var scale_step: float = 0.05

var _is_dragging: bool = false
var _drag_start_mouse_pos: Vector2i = Vector2i.ZERO
var _drag_start_window_pos: Vector2i = Vector2i.ZERO

@onready var _base_size: Vector2i = Vector2i(
	ProjectSettings.get_setting("display/window/size/viewport_width"),
	ProjectSettings.get_setting("display/window/size/viewport_height")
)
var _current_scale: float = 1.0

func _ready() -> void:
	# 优先采用你的覆盖分辨率作为基准尺寸来计算初始缩放比
	var current_size: Vector2i = DisplayServer.window_get_size()
	_current_scale = float(current_size.x) / float(_base_size.x)

# ... 保持原有类定义和 _ready、_input 不变 ...

func _process(_delta: float) -> void:
	# 1. 检查鼠标左键状态
	var is_left_pressed: bool = Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT)
	
	if is_left_pressed:
		if not _is_dragging:
			# 【核心优化 1】:规避 UI 交互
			# 检查鼠标当前是否悬停在游戏内的 UI 控件(Control节点,如仓库、按钮)上方
			var hovered_control: Control = get_viewport().gui_get_hovered_control()
			if hovered_control != null:
				# 如果点在了 UI 上,直接拒绝这次拖拽,让点击事件交由游戏 UI 或仓库处理
				return
				
			# 刚按下的一瞬间,记录初始绝对坐标
			_is_dragging = true
			_drag_start_mouse_pos = DisplayServer.mouse_get_position()
			_drag_start_window_pos = DisplayServer.window_get_position()
		else:
			# 【核心优化 2】:加入微小的拖拽位移死区限制(防止开启/关闭UI时的微小晃动误触发)
			var current_mouse_pos: Vector2i = DisplayServer.mouse_get_position()
			var delta: Vector2i = current_mouse_pos - _drag_start_mouse_pos
			
			# 如果鼠标累计移动超过 3 个像素,才真正判定为“玩家想要搬移游戏窗口”
			if delta.length() > 3:
				DisplayServer.window_set_position(_drag_start_window_pos + delta)
	else:
		_is_dragging = false


func _input(event: InputEvent) -> void:
	# 将滚轮事件放回 _input 中,利用操作系统的单次事件驱动,防止单帧内连续缩放过快
	if event is InputEventMouseButton and event.pressed:
		var scale_changed: bool = false
		if event.button_index == MOUSE_BUTTON_WHEEL_UP:
			_current_scale = min(_current_scale + scale_step, max_scale)
			scale_changed = true
		elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN:
			_current_scale = max(_current_scale - scale_step, min_scale)
			scale_changed = true
			
		if scale_changed:
			var old_size: Vector2i = DisplayServer.window_get_size()
			var target_size: Vector2i = Vector2i(
				roundi(_base_size.x * _current_scale),
				roundi(_base_size.y * _current_scale)
			)
			
			# 核心优化:计算尺寸差值,让窗口在缩放时保持原位平滑过渡,不发生瞬移
			var size_diff: Vector2i = target_size - old_size
			var current_pos: Vector2i = DisplayServer.window_get_position()
			
			DisplayServer.window_set_size(target_size)
			# 可选:如果你希望缩放时窗口以中心点向外扩张,可以取消注释下面这行
			# DisplayServer.window_set_position(current_pos - size_diff / 2)