优化项目架构

This commit is contained in:
2025-09-15 19:10:37 +08:00
parent 4119ed3445
commit 26b856d74e
1361 changed files with 4 additions and 0 deletions

View File

@@ -0,0 +1,248 @@
extends Panel
@onready var user_name_input: Label = $VBox1/Grid/User_Name_Input #用户名/账号名
@onready var user_password_input: LineEdit = $VBox1/Grid/User_Password_Input#账号密码
@onready var player_name_input: LineEdit = $VBox1/Grid/Player_Name_Input #玩家昵称
@onready var farm_name_input: LineEdit = $VBox1/Grid/Farm_Name_Input #农场名称
@onready var personal_profile_input: LineEdit = $VBox1/Grid/Personal_Profile_Input#个人简介
@onready var remove_account_btn: Button = $VBox1/HBox2/Remove_Account_Btn #删除账号按钮
@onready var confirm_btn: Button = $VBox1/HBox2/Confirm_Btn #修改账号信息按钮
@onready var quit_button: Button = $QuitButton #关闭玩家信息面板按钮
@onready var refresh_button: Button = $RefreshButton#刷新玩家信息按钮
#预添加常用的面板和组件
@onready var main_game = get_node("/root/main")
@onready var accept_dialog: AcceptDialog = $'../../DiaLog/AcceptDialog'
@onready var tcp_network_manager_panel: Panel = $'../../BigPanel/TCPNetworkManagerPanel'
# 存储待执行的操作类型
var pending_action = ""
func _ready() -> void:
# 连接按钮信号
quit_button.pressed.connect(_on_quit_button_pressed)
refresh_button.pressed.connect(_on_refresh_button_pressed)
confirm_btn.pressed.connect(_on_confirm_btn_pressed)
remove_account_btn.pressed.connect(_on_remove_account_btn_pressed)
visibility_changed.connect(_on_visibility_changed)
# 初始显示界面数据
_refresh_player_info()
# 如果有网络连接,自动请求最新数据(延迟一秒等待初始化完成)
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("is_connected_to_server") and tcp_network_manager_panel.is_connected_to_server():
await get_tree().create_timer(1.0).timeout
_request_player_info_from_server()
#面板切换显示时
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
pass
else:
GlobalVariables.isZoomDisabled = false
pass
#关闭玩家信息面板按钮点击
func _on_quit_button_pressed() -> void:
self.hide()
#刷新玩家信息按钮点击
func _on_refresh_button_pressed() -> void:
# 向服务器请求最新的玩家数据
_request_player_info_from_server()
#向服务器请求玩家信息
func _request_player_info_from_server():
if not tcp_network_manager_panel:
_show_message("网络管理器不可用", Color.RED)
return
if not tcp_network_manager_panel.is_connected_to_server():
_show_message("未连接到服务器", Color.RED)
return
# 发送刷新请求到服务器
var message = {
"type": "refresh_player_info"
}
var success = tcp_network_manager_panel.send_message(message)
if success:
_show_message("正在刷新玩家信息...", Color.YELLOW)
else:
_show_message("发送刷新请求失败", Color.RED)
#确认修改按钮点击
func _on_confirm_btn_pressed() -> void:
# 显示二次确认对话框
pending_action = "modify_account"
if accept_dialog:
accept_dialog.dialog_text = "确认要修改账号信息吗?这些更改将立即生效。"
accept_dialog.title = "确认修改"
accept_dialog.show()
# 连接确认信号
if not accept_dialog.confirmed.is_connected(_on_accept_dialog_confirmed):
accept_dialog.confirmed.connect(_on_accept_dialog_confirmed)
#删除账号按钮点击
func _on_remove_account_btn_pressed() -> void:
# 显示二次确认对话框
pending_action = "delete_account"
if accept_dialog:
accept_dialog.dialog_text = "警告:删除账号将永久移除您的所有数据,包括农场、作物、背包等所有内容。\n此操作无法撤销,确认要删除账号吗?"
accept_dialog.title = "删除账号确认"
accept_dialog.show()
# 连接确认信号
if not accept_dialog.confirmed.is_connected(_on_accept_dialog_confirmed):
accept_dialog.confirmed.connect(_on_accept_dialog_confirmed)
#确认对话框的确认按钮被点击
func _on_accept_dialog_confirmed() -> void:
match pending_action:
"modify_account":
_modify_account_info()
"delete_account":
_delete_account()
# 重置待执行操作
pending_action = ""
# 断开信号连接
if accept_dialog and accept_dialog.confirmed.is_connected(_on_accept_dialog_confirmed):
accept_dialog.confirmed.disconnect(_on_accept_dialog_confirmed)
#修改账号信息
func _modify_account_info():
if not tcp_network_manager_panel:
_show_message("网络管理器不可用", Color.RED)
return
if not tcp_network_manager_panel.is_connected_to_server():
_show_message("未连接到服务器", Color.RED)
return
# 获取输入的信息
var new_password = user_password_input.text.strip_edges()
var new_player_name = player_name_input.text.strip_edges()
var new_farm_name = farm_name_input.text.strip_edges()
var new_personal_profile = personal_profile_input.text.strip_edges()
# 验证输入
if new_password == "":
_show_message("密码不能为空", Color.RED)
return
if new_player_name == "":
_show_message("玩家昵称不能为空", Color.RED)
return
if new_farm_name == "":
_show_message("农场名称不能为空", Color.RED)
return
# 发送修改请求到服务器
var message = {
"type": "modify_account_info",
"new_password": new_password,
"new_player_name": new_player_name,
"new_farm_name": new_farm_name,
"new_personal_profile": new_personal_profile
}
var success = tcp_network_manager_panel.send_message(message)
if success:
_show_message("正在更新账号信息...", Color.YELLOW)
else:
_show_message("发送修改请求失败", Color.RED)
#删除账号
func _delete_account():
if not tcp_network_manager_panel:
_show_message("网络管理器不可用", Color.RED)
return
if not tcp_network_manager_panel.is_connected_to_server():
_show_message("未连接到服务器", Color.RED)
return
# 发送删除账号请求到服务器
var message = {
"type": "delete_account"
}
var success =tcp_network_manager_panel.send_message(message)
if success:
_show_message("正在删除账号...", Color.YELLOW)
else:
_show_message("发送删除请求失败", Color.RED)
#刷新玩家信息显示(从本地数据)
func _refresh_player_info():
# 从主游戏获取当前玩家信息
user_name_input.text = main_game.user_name if main_game.user_name != "" else "未知"
user_password_input.text = main_game.user_password if main_game.user_password != "" else ""
# 优先从 login_data 获取数据,如果没有则从 data 获取
var player_data = main_game.login_data #if main_game.login_data.size() > 0 else main_game.data
player_name_input.text = player_data.get("玩家昵称", "")
farm_name_input.text = player_data.get("农场名称", "")
personal_profile_input.text = player_data.get("个人简介", "")
#显示消息提示
func _show_message(message: String, color: Color):
if main_game and main_game.has_method("show_message"):
main_game.show_message(message, color)
else:
pass
#处理服务器响应
func handle_account_response(response_data: Dictionary):
var message_type = response_data.get("type", "")
var success = response_data.get("success", false)
var message = response_data.get("message", "")
match message_type:
"modify_account_info_response":
if success:
_show_message(message, Color.GREEN)
# 更新本地数据
if response_data.has("updated_data"):
var updated_data = response_data["updated_data"]
if main_game:
if updated_data.has("玩家昵称"):
main_game.login_data["玩家昵称"] = updated_data["玩家昵称"]
if updated_data.has("农场名称"):
main_game.login_data["农场名称"] = updated_data["农场名称"]
if updated_data.has("个人简介"):
main_game.login_data["个人简介"] = updated_data["个人简介"]
if updated_data.has("玩家密码"):
main_game.user_password = updated_data["玩家密码"]
# 刷新显示
_refresh_player_info()
else:
_show_message(message, Color.RED)
"delete_account_response":
if success:
_show_message(message, Color.GREEN)
# 等待2秒后返回主菜单
await get_tree().create_timer(2.0).timeout
get_tree().change_scene_to_file("res://GUI/MainMenuPanel.tscn")
else:
_show_message(message, Color.RED)
"refresh_player_info_response":
if success:
# 主游戏已经更新了数据,直接刷新显示即可
_refresh_player_info()
_show_message("玩家信息已刷新", Color.GREEN)
else:
_show_message(message if message != "" else "刷新失败", Color.RED)

View File

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

View File

@@ -0,0 +1,215 @@
extends Panel
@onready var quit_button: Button = $QuitButton #关闭作物信息面板
@onready var crop_image: TextureRect = $VBox/CropImage #显示作物图片
@onready var crop_name: Label = $VBox/CropName #作物名称
@onready var crop_description: Label = $VBox/CropDescription #作物介绍
@onready var crop_price: Label = $VBox/CropPrice #作物价格
@onready var crop_quality: Label = $VBox/CropQuality #作物品质
@onready var sale_product: Button = $VBox/HBox/SaleProduct #直接出售
@onready var add_to_store: Button = $VBox/HBox/AddToStore #添加到小卖部
@onready var add_product_to_store_popup: PanelContainer = $'../../DiaLog/AddProductToStorePopup'
# 当前显示的作物信息
var current_crop_name: String = ""
var current_crop_count: int = 0
# 获取主游戏引用
@onready var main_game = get_node("/root/main")
func _ready():
# 连接按钮信号
quit_button.pressed.connect(_on_quit_button_pressed)
sale_product.pressed.connect(_on_sale_product_pressed)
add_to_store.pressed.connect(_on_add_to_store_pressed)
# 默认隐藏面板
self.hide()
# 显示作物信息
func show_crop_info(crop_name: String, crop_count: int):
current_crop_name = crop_name
current_crop_count = crop_count
# 更新作物信息显示
_update_crop_display()
# 显示面板
self.show()
self.move_to_front()
# 更新作物信息显示
func _update_crop_display():
if not main_game.can_planted_crop.has(current_crop_name):
crop_name.text = "作物名称:" + current_crop_name
crop_description.text = "描述:未知作物"
crop_price.text = "收购价:未知"
crop_quality.text = "品质:未知"
return
var crop_data = main_game.can_planted_crop[current_crop_name]
# 获取显示名称
var display_name = current_crop_name
var mature_name = crop_data.get("成熟物名称")
if mature_name != null and mature_name != "":
display_name = mature_name
else:
display_name = crop_data.get("作物名称", current_crop_name)
# 更新文本显示
crop_name.text = "作物名称:" + display_name + " (数量: " + str(current_crop_count) + ")"
crop_description.text = "描述:" + crop_data.get("描述", "美味的作物")
# 计算出售价格(基于收益)
var sell_price = crop_data.get("收益", 0)
crop_price.text = "收购价:" + str(sell_price) + " 元/个"
var quality = crop_data.get("品质", "普通")
crop_quality.text = "品质:" + quality
# 更新作物图片
_update_crop_image()
# 更新作物图片
func _update_crop_image():
var texture = _get_crop_harvest_texture(current_crop_name)
if texture:
crop_image.texture = texture
else:
# 使用默认图片
var default_texture = _get_crop_harvest_texture("默认")
if default_texture:
crop_image.texture = default_texture
# 获取作物的收获物图片
func _get_crop_harvest_texture(crop_name: String) -> Texture2D:
var crop_path = "res://assets/作物/" + crop_name + "/"
var harvest_texture_path = crop_path + "收获物.webp"
if ResourceLoader.exists(harvest_texture_path):
var texture = load(harvest_texture_path)
if texture:
return texture
# 如果没有找到,使用默认的收获物图片
var default_harvest_path = "res://assets/作物/默认/收获物.webp"
if ResourceLoader.exists(default_harvest_path):
var texture = load(default_harvest_path)
if texture:
return texture
return null
# 关闭面板
func _on_quit_button_pressed():
self.hide()
# 直接出售按钮处理
func _on_sale_product_pressed():
# 检查是否在访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法出售作物", Color.ORANGE, 2.0, 1.0)
return
# 获取批量出售弹窗
var batch_sell_popup = get_node_or_null("/root/main/UI/DiaLog/BatchSellPopup")
if batch_sell_popup and batch_sell_popup.has_method("show_sell_popup"):
# 获取作物数据以传递给出售弹窗
var crop_data = main_game.can_planted_crop.get(current_crop_name, {})
var sell_price = crop_data.get("收益", 0)
var description = crop_data.get("描述", "美味的作物")
# 显示批量出售弹窗
batch_sell_popup.show_sell_popup(
current_crop_name,
current_crop_count,
sell_price,
description,
_on_confirm_sell_crop,
_on_cancel_sell_crop
)
else:
Toast.show("批量出售功能暂未实现", Color.RED, 2.0, 1.0)
print("错误找不到BatchSellPopup或相关方法")
# 确认出售作物回调
func _on_confirm_sell_crop(crop_name: String, sell_count: int, unit_price: int):
# 发送出售请求到服务器
var tcp_network_manager = get_node_or_null("/root/main/UI/BigPanel/TCPNetworkManagerPanel")
if tcp_network_manager and tcp_network_manager.has_method("send_message"):
var message = {
"type": "sell_crop",
"crop_name": crop_name,
"sell_count": sell_count,
"unit_price": unit_price
}
tcp_network_manager.send_message(message)
# 关闭作物信息面板
self.hide()
Toast.show("出售请求已发送", Color.YELLOW, 2.0, 1.0)
else:
Toast.show("网络连接异常,无法出售", Color.RED, 2.0, 1.0)
# 取消出售作物回调
func _on_cancel_sell_crop():
# 不需要做任何事情,弹窗会自动关闭
pass
# 添加到小卖部按钮处理
func _on_add_to_store_pressed():
# 检查是否在访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法操作小卖部", Color.ORANGE, 2.0, 1.0)
return
# 获取添加商品到小卖部的弹窗
if add_product_to_store_popup and add_product_to_store_popup.has_method("show_add_product_popup"):
# 获取作物数据以传递给弹窗
var crop_data = main_game.can_planted_crop.get(current_crop_name, {})
var sell_price = crop_data.get("收益", 0)
var description = crop_data.get("描述", "美味的作物")
# 显示添加商品弹窗
add_product_to_store_popup.show_add_product_popup(
current_crop_name,
current_crop_count,
sell_price,
description,
_on_confirm_add_to_store,
_on_cancel_add_to_store
)
else:
print("错误找不到AddProduct2StorePopup或相关方法")
# 确认添加到小卖部回调
func _on_confirm_add_to_store(crop_name: String, add_count: int, unit_price: int):
# 发送添加商品到小卖部的请求到服务器
var tcp_network_manager = get_node_or_null("/root/main/UI/BigPanel/TCPNetworkManagerPanel")
if tcp_network_manager and tcp_network_manager.has_method("send_message"):
var message = {
"type": "add_product_to_store",
"product_type": "作物",
"product_name": crop_name,
"product_count": add_count,
"product_price": unit_price
}
tcp_network_manager.send_message(message)
# 关闭作物信息面板
self.hide()
Toast.show("添加商品请求已发送", Color.YELLOW, 2.0, 1.0)
else:
Toast.show("网络连接异常,无法添加商品", Color.RED, 2.0, 1.0)
# 取消添加到小卖部回调
func _on_cancel_add_to_store():
# 不需要做任何事情,弹窗会自动关闭
pass

View File

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

View File

@@ -0,0 +1,463 @@
extends Panel
## 调试面板 - 显示资源加载和设备性能信息
## 特别用于在移动设备上调试资源加载问题
@onready var debug_rich_text: RichTextLabel = $DebugRichText
@onready var copy_button: Button = null # 复制按钮引用
# 调试信息管理
var debug_messages: Array = []
var max_debug_messages: int = 50 # 最大保留消息数量
var update_timer: float = 0.0
var update_interval: float = 1.0 # 每秒更新一次
# 性能监控数据
var performance_data: Dictionary = {
"cpu_usage": 0.0,
"memory_usage": 0,
"memory_peak": 0,
"fps": 0.0,
"loading_progress": 0,
"loaded_textures": 0,
"failed_textures": 0,
"current_loading_item": "",
"device_info": {}
}
# 主游戏引用
var main_game = null
func _ready():
print("[DebugPanel] 调试面板已初始化")
# 获取主游戏引用
main_game = get_node("/root/main")
# 创建复制按钮
_create_copy_button()
# 初始化设备信息
_collect_device_info()
# 添加初始消息
add_debug_message("调试面板已启动", Color.GREEN)
add_debug_message("设备: " + OS.get_name(), Color.CYAN)
add_debug_message("CPU核心: " + str(OS.get_processor_count()), Color.CYAN)
func _process(delta):
update_timer += delta
if update_timer >= update_interval:
update_timer = 0.0
_update_performance_data()
_check_performance_warnings()
_update_debug_display()
## 检查性能警告
func _check_performance_warnings():
# 内存警告
var memory_mb = performance_data["memory_usage"] / (1024 * 1024)
if memory_mb > 800:
report_memory_warning(memory_mb)
# FPS警告
if performance_data["fps"] < 20 and performance_data["fps"] > 0:
report_performance_warning(performance_data["fps"])
# 加载失败警告
if performance_data["failed_textures"] > 10:
add_debug_message("⚠ 大量纹理加载失败: %d" % performance_data["failed_textures"], Color.RED)
## 收集设备基本信息
func _collect_device_info():
performance_data["device_info"] = {
"platform": OS.get_name(),
"processor_count": OS.get_processor_count(),
"processor_name": OS.get_processor_name(),
"memory_total": OS.get_static_memory_usage(),
"gpu_vendor": RenderingServer.get_video_adapter_vendor(),
"gpu_name": RenderingServer.get_video_adapter_name(),
"screen_size": DisplayServer.screen_get_size(),
"screen_dpi": DisplayServer.screen_get_dpi()
}
## 更新性能数据
func _update_performance_data():
# CPU使用率通过帧时间估算
var frame_time = Performance.get_monitor(Performance.TIME_PROCESS)
performance_data["cpu_usage"] = min(frame_time * 100.0, 100.0)
# 内存使用情况
var current_memory = OS.get_static_memory_usage()
performance_data["memory_usage"] = current_memory
if current_memory > performance_data["memory_peak"]:
performance_data["memory_peak"] = current_memory
# FPS
performance_data["fps"] = Engine.get_frames_per_second()
# 从主游戏获取加载信息
if main_game and main_game.crop_texture_manager:
var manager = main_game.crop_texture_manager
# 计算所有加载的纹理数量(新的三阶段系统)
var total_textures = 0
for crop_name in manager.texture_cache.keys():
total_textures += manager.texture_cache[crop_name].size()
total_textures += manager.default_textures.size()
performance_data["loaded_textures"] = total_textures
performance_data["failed_textures"] = manager.failed_resources.size()
# 加载进度
if manager.is_loading:
var total = manager.total_crops * 2 # 序列帧 + 成熟图片
var loaded = manager.loaded_crops
performance_data["loading_progress"] = int((float(loaded) / float(total)) * 100) if total > 0 else 0
else:
performance_data["loading_progress"] = 100
## 更新调试显示
func _update_debug_display():
if not debug_rich_text:
return
var text = ""
# 为复制按钮留出空间,添加一些空行
text += "\n\n"
# 快速摘要(最重要的信息)
text += "[color=yellow][b]=== 快速摘要 ===[/b][/color]\n"
var summary_memory_mb = performance_data["memory_usage"] / (1024 * 1024)
var status_color = "green"
if performance_data["failed_textures"] > 0 or summary_memory_mb > 500 or performance_data["fps"] < 30:
status_color = "red"
elif performance_data["loading_progress"] < 100:
status_color = "yellow"
text += "[color=" + status_color + "]状态: "
if performance_data["loading_progress"] < 100:
text += "加载中 " + str(performance_data["loading_progress"]) + "%"
elif performance_data["failed_textures"] > 0:
text += "" + str(performance_data["failed_textures"]) + " 个资源加载失败"
else:
text += "正常运行"
text += "[/color]\n"
text += "[color=cyan]内存: %.1fMB | FPS: %d | 纹理: %d[/color]\n\n" % [summary_memory_mb, performance_data["fps"], performance_data["loaded_textures"]]
# 设备信息标题
text += "[color=yellow][b]=== 设备信息 ===[/b][/color]\n"
var device = performance_data["device_info"]
text += "[color=cyan]平台:[/color] " + str(device.get("platform", "未知")) + "\n"
text += "[color=cyan]CPU:[/color] " + str(device.get("processor_name", "未知")) + " (" + str(device.get("processor_count", 0)) + "核)\n"
text += "[color=cyan]GPU:[/color] " + str(device.get("gpu_name", "未知")) + "\n"
text += "[color=cyan]屏幕:[/color] " + str(device.get("screen_size", Vector2.ZERO)) + " DPI:" + str(device.get("screen_dpi", 0)) + "\n"
# 性能监控标题
text += "\n[color=yellow][b]=== 性能监控 ===[/b][/color]\n"
# CPU使用率颜色编码
var cpu_color = "green"
if performance_data["cpu_usage"] > 70:
cpu_color = "red"
elif performance_data["cpu_usage"] > 50:
cpu_color = "yellow"
text += "[color=cyan]CPU使用率:[/color] [color=" + cpu_color + "]" + "%.1f%%" % performance_data["cpu_usage"] + "[/color]\n"
# 内存使用情况(颜色编码)
var memory_mb = performance_data["memory_usage"] / (1024 * 1024)
var memory_peak_mb = performance_data["memory_peak"] / (1024 * 1024)
var memory_color = "green"
if memory_mb > 800:
memory_color = "red"
elif memory_mb > 500:
memory_color = "yellow"
text += "[color=cyan]内存使用:[/color] [color=" + memory_color + "]%.1fMB[/color] (峰值: %.1fMB)\n" % [memory_mb, memory_peak_mb]
# FPS颜色编码
var fps_color = "green"
if performance_data["fps"] < 30:
fps_color = "red"
elif performance_data["fps"] < 50:
fps_color = "yellow"
text += "[color=cyan]FPS:[/color] [color=" + fps_color + "]" + str(performance_data["fps"]) + "[/color]\n"
# 资源加载状态标题
text += "\n[color=yellow][b]=== 资源加载状态 ===[/b][/color]\n"
# 加载进度(颜色编码)
var progress_color = "yellow"
if performance_data["loading_progress"] >= 100:
progress_color = "green"
elif performance_data["loading_progress"] < 50:
progress_color = "red"
text += "[color=cyan]加载进度:[/color] [color=" + progress_color + "]" + str(performance_data["loading_progress"]) + "%[/color]\n"
# 纹理统计
text += "[color=cyan]已加载纹理:[/color] " + str(performance_data["loaded_textures"]) + "\n"
# 失败纹理(突出显示)
if performance_data["failed_textures"] > 0:
text += "[color=cyan]失败纹理:[/color] [color=red]" + str(performance_data["failed_textures"]) + "[/color]\n"
else:
text += "[color=cyan]失败纹理:[/color] [color=green]0[/color]\n"
# 当前加载项目
if performance_data["current_loading_item"] != "":
text += "[color=cyan]当前加载:[/color] " + performance_data["current_loading_item"] + "\n"
# 线程信息
if main_game and main_game.crop_texture_manager:
var manager = main_game.crop_texture_manager
text += "[color=cyan]工作线程:[/color] " + str(manager.max_threads) + "\n"
if manager.is_loading:
text += "[color=cyan]队列任务:[/color] " + str(manager.loading_queue.size()) + "\n"
# 调试消息标题
text += "\n[color=yellow][b]=== 调试日志 ===[/b][/color]\n"
# 显示最近的调试消息
var recent_messages = debug_messages.slice(-15) # 显示最近15条消息
for message in recent_messages:
text += message + "\n"
# 更新显示
debug_rich_text.text = text
# 自动滚动到底部
debug_rich_text.scroll_to_line(debug_rich_text.get_line_count())
## 添加调试消息
func add_debug_message(message: String, color: Color = Color.WHITE):
var timestamp = Time.get_datetime_string_from_system()
var time_parts = timestamp.split(" ")
var time_str = ""
# 安全地获取时间部分
if time_parts.size() >= 2:
time_str = time_parts[1].substr(0, 8) # 只要时间部分
else:
# 如果分割失败,使用当前时间
var time_dict = Time.get_time_dict_from_system()
time_str = "%02d:%02d:%02d" % [time_dict.hour, time_dict.minute, time_dict.second]
var color_name = _color_to_name(color)
var formatted_message = "[color=gray]%s[/color] [color=%s]%s[/color]" % [time_str, color_name, message]
debug_messages.append(formatted_message)
# 限制消息数量
if debug_messages.size() > max_debug_messages:
debug_messages = debug_messages.slice(-max_debug_messages)
# 同时输出到控制台
print("[DebugPanel] " + message)
## 颜色转换为名称
func _color_to_name(color: Color) -> String:
if color == Color.RED:
return "red"
elif color == Color.GREEN:
return "green"
elif color == Color.BLUE:
return "blue"
elif color == Color.YELLOW:
return "yellow"
elif color == Color.CYAN:
return "cyan"
elif color == Color.MAGENTA:
return "magenta"
elif color == Color.ORANGE:
return "orange"
elif color == Color.PINK:
return "pink"
else:
return "white"
## 设置当前加载项目
func set_current_loading_item(item_name: String):
performance_data["current_loading_item"] = item_name
if item_name != "":
add_debug_message("正在加载: " + item_name, Color.CYAN)
## 报告加载成功
func report_loading_success(item_name: String):
add_debug_message("✓ 加载成功: " + item_name, Color.GREEN)
## 报告加载失败
func report_loading_failure(item_name: String, reason: String = ""):
var message = "✗ 加载失败: " + item_name
if reason != "":
message += " (" + reason + ")"
add_debug_message(message, Color.RED)
## 报告内存警告
func report_memory_warning(memory_mb: float):
add_debug_message("⚠ 内存使用过高: %.1fMB" % memory_mb, Color.ORANGE)
## 报告性能警告
func report_performance_warning(fps: float):
add_debug_message("⚠ 性能下降: FPS=" + str(fps), Color.ORANGE)
## 清理调试信息
func clear_debug_log():
debug_messages.clear()
add_debug_message("调试日志已清理", Color.YELLOW)
## 导出调试信息到文件
func export_debug_log():
var datetime = Time.get_datetime_dict_from_system()
var filename = "debug_log_%04d%02d%02d_%02d%02d%02d.txt" % [
datetime.year, datetime.month, datetime.day,
datetime.hour, datetime.minute, datetime.second
]
var file_path = OS.get_user_data_dir() + "/" + filename
var file = FileAccess.open(file_path, FileAccess.WRITE)
if file:
file.store_string("=== 萌芽农场调试日志 ===\n\n")
file.store_string("设备信息:\n")
for key in performance_data["device_info"]:
file.store_string(" %s: %s\n" % [key, str(performance_data["device_info"][key])])
file.store_string("\n性能数据:\n")
file.store_string(" CPU使用率: %.1f%%\n" % performance_data["cpu_usage"])
file.store_string(" 内存使用: %.1fMB\n" % (performance_data["memory_usage"] / (1024 * 1024)))
file.store_string(" FPS: %d\n" % performance_data["fps"])
file.store_string(" 已加载纹理: %d\n" % performance_data["loaded_textures"])
file.store_string(" 失败纹理: %d\n" % performance_data["failed_textures"])
file.store_string("\n调试日志:\n")
for message in debug_messages:
# 移除BBCode标签
var clean_message = message.replace("[color=gray]", "").replace("[/color]", "")
clean_message = clean_message.replace("[color=red]", "").replace("[color=green]", "")
clean_message = clean_message.replace("[color=cyan]", "").replace("[color=yellow]", "")
clean_message = clean_message.replace("[color=orange]", "")
file.store_string(clean_message + "\n")
file.close()
add_debug_message("调试日志已导出到: " + filename, Color.GREEN)
return file_path
else:
add_debug_message("导出调试日志失败", Color.RED)
return ""
## 创建复制按钮
func _create_copy_button():
# 复制按钮
copy_button = Button.new()
copy_button.text = "复制调试信息"
copy_button.size = Vector2(140, 35)
copy_button.position = Vector2(10, 10) # 左上角位置
# 设置按钮样式
copy_button.modulate = Color(1.0, 0.8, 0.6, 0.9) # 淡橙色
# 连接点击信号
copy_button.pressed.connect(_on_copy_button_pressed)
# 添加到面板
add_child(copy_button)
# 清理日志按钮
var clear_button = Button.new()
clear_button.text = "清理日志"
clear_button.size = Vector2(100, 35)
clear_button.position = Vector2(160, 10) # 复制按钮右边
# 设置按钮样式
clear_button.modulate = Color(1.0, 0.6, 0.6, 0.9) # 淡红色
# 连接点击信号
clear_button.pressed.connect(_on_clear_button_pressed)
# 添加到面板
add_child(clear_button)
print("[DebugPanel] 复制和清理按钮已创建")
## 清理按钮点击处理
func _on_clear_button_pressed():
clear_debug_log()
print("[DebugPanel] 调试日志已清理")
## 复制按钮点击处理
func _on_copy_button_pressed():
var debug_text = _generate_debug_text_for_copy()
DisplayServer.clipboard_set(debug_text)
add_debug_message("调试信息已复制到剪贴板", Color.GREEN)
print("[DebugPanel] 调试信息已复制到剪贴板")
## 生成用于复制的调试文本(纯文本格式)
func _generate_debug_text_for_copy() -> String:
var text = "=== 萌芽农场调试信息 ===\n\n"
# 设备信息
text += "=== 设备信息 ===\n"
var device = performance_data["device_info"]
text += "平台: " + str(device.get("platform", "未知")) + "\n"
text += "CPU: " + str(device.get("processor_name", "未知")) + " (" + str(device.get("processor_count", 0)) + "核)\n"
text += "GPU: " + str(device.get("gpu_name", "未知")) + "\n"
text += "屏幕: " + str(device.get("screen_size", Vector2.ZERO)) + " DPI:" + str(device.get("screen_dpi", 0)) + "\n"
# 性能监控
text += "\n=== 性能监控 ===\n"
text += "CPU使用率: %.1f%%\n" % performance_data["cpu_usage"]
var memory_mb = performance_data["memory_usage"] / (1024 * 1024)
var memory_peak_mb = performance_data["memory_peak"] / (1024 * 1024)
text += "内存使用: %.1fMB (峰值: %.1fMB)\n" % [memory_mb, memory_peak_mb]
text += "FPS: %d\n" % performance_data["fps"]
# 资源加载状态
text += "\n=== 资源加载状态 ===\n"
text += "加载进度: %d%%\n" % performance_data["loading_progress"]
text += "已加载纹理: %d\n" % performance_data["loaded_textures"]
text += "失败纹理: %d\n" % performance_data["failed_textures"]
if performance_data["current_loading_item"] != "":
text += "当前加载: " + performance_data["current_loading_item"] + "\n"
# 线程信息
if main_game and main_game.crop_texture_manager:
var manager = main_game.crop_texture_manager
text += "工作线程: %d\n" % manager.max_threads
if manager.is_loading:
text += "队列任务: %d\n" % manager.loading_queue.size()
# 调试日志
text += "\n=== 调试日志 ===\n"
for message in debug_messages:
# 移除BBCode标签
var clean_message = _remove_bbcode_tags(message)
text += clean_message + "\n"
return text
## 移除BBCode标签
func _remove_bbcode_tags(text: String) -> String:
var clean_text = text
# 移除所有颜色标签
var color_regex = RegEx.new()
color_regex.compile("\\[color=[^\\]]*\\]|\\[/color\\]")
clean_text = color_regex.sub(clean_text, "", true)
# 移除粗体标签
clean_text = clean_text.replace("[b]", "").replace("[/b]", "")
return clean_text
## 获取当前性能摘要
func get_performance_summary() -> String:
return "CPU:%.1f%% 内存:%.1fMB FPS:%d 纹理:%d/%d" % [
performance_data["cpu_usage"],
performance_data["memory_usage"] / (1024 * 1024),
performance_data["fps"],
performance_data["loaded_textures"],
performance_data["failed_textures"]
]
func _on_quit_button_pressed() -> void:
self.hide()
pass

View File

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

View File

@@ -0,0 +1,290 @@
extends Panel
@onready var message_contents: RichTextLabel = $MessageContents #显示历史消息
@onready var input_message: LineEdit = $HBox/InputMessage #输入要发送的消息
@onready var send_message_button: Button = $HBox/SendMessageButton #发送消息按钮
@onready var quit_button: Button = $QuitButton
@onready var watch_more_button: Button = $WatchMoreButton
# 获取主游戏和网络管理器的引用
@onready var main_game = get_node("/root/main")
@onready var tcp_network_manager_panel = get_node("/root/main/UI/BigPanel/TCPNetworkManagerPanel")
# 消息历史记录
var message_history: Array = []
var max_message_history: int = 100 # 最大消息历史记录数量
# 历史消息加载状态
var current_load_days: int = 3 # 当前加载的天数
var max_load_days: int = 30 # 最大加载30天的历史
func _ready() -> void:
# 连接按钮信号
quit_button.pressed.connect(on_quit_button_pressed)
send_message_button.pressed.connect(on_send_message_button_pressed)
watch_more_button.pressed.connect(on_watch_more_button_pressed)
# 连接输入框回车信号
input_message.text_submitted.connect(on_input_message_submitted)
# 连接面板显示隐藏信号
visibility_changed.connect(_on_visibility_changed)
# 初始化消息显示
message_contents.bbcode_enabled = true
message_contents.scroll_following = true
# 隐藏面板
self.hide()
# 退出按钮点击事件
func on_quit_button_pressed():
self.hide()
# 发送消息按钮点击事件
func on_send_message_button_pressed():
send_broadcast_message()
# 查看更多消息按钮点击事件
func on_watch_more_button_pressed():
load_more_history()
# 输入框回车事件
func on_input_message_submitted(text: String):
send_broadcast_message()
# 发送全服大喇叭消息
func send_broadcast_message():
var message_text = input_message.text.strip_edges()
# 检查消息是否为空
if message_text.is_empty():
Toast.show("消息不能为空", Color.RED, 2.0, 1.0)
return
# 检查消息长度
if message_text.length() > 200:
Toast.show("消息长度不能超过200字符", Color.RED, 2.0, 1.0)
return
# 检查网络连接
if not tcp_network_manager_panel or not tcp_network_manager_panel.is_connected_to_server():
Toast.show("未连接服务器,无法发送消息", Color.RED, 2.0, 1.0)
return
# 发送消息到服务器
var success = tcp_network_manager_panel.send_message({
"type": "global_broadcast",
"content": message_text,
"timestamp": Time.get_unix_time_from_system()
})
if success:
# 清空输入框
input_message.text = ""
Toast.show("消息发送成功", Color.GREEN, 2.0, 1.0)
else:
Toast.show("消息发送失败", Color.RED, 2.0, 1.0)
# 统一的消息处理函数
func _add_message_to_history(data: Dictionary):
var username = data.get("username", "匿名")
var player_name = data.get("玩家昵称", "")
var content = data.get("content", "")
var timestamp = data.get("timestamp", Time.get_unix_time_from_system())
# 如果有玩家昵称,优先显示昵称
var display_name = player_name if player_name != "" else username
# 格式化时间 - 确保timestamp是整数类型
var timestamp_int = int(timestamp) if typeof(timestamp) == TYPE_STRING else timestamp
var datetime = Time.get_datetime_dict_from_unix_time(timestamp_int)
var time_str = "%04d%02d%02d%02d:%02d:%02d" % [datetime.year, datetime.month, datetime.day, datetime.hour, datetime.minute, datetime.second]
# 创建消息记录
var message_record = {
"username": username,
"玩家昵称": player_name,
"content": content,
"timestamp": timestamp,
"time_str": time_str,
"display_name": display_name
}
message_history.append(message_record)
# 接收全服大喇叭消息
func receive_broadcast_message(data: Dictionary):
# 使用统一的处理函数
_add_message_to_history(data)
# 保持消息历史记录在限制范围内
if message_history.size() > max_message_history:
message_history.pop_front()
# 如果面板当前可见,立即更新显示
if visible:
update_message_display()
# 保存到本地
save_chat_history()
# 更新消息显示
func update_message_display():
var display_text = ""
for message in message_history:
var username = message.get("username", "匿名")
var display_name = message.get("display_name", username)
var content = message.get("content", "")
var time_str = message.get("time_str", "") + ""
# 使用BBCode格式化消息
var formatted_message = "[color=#FFD700][b]%s[/b][/color] [color=#87CEEB](%s)[/color] [color=#FFA500]%s[/color][color=#FFFFFF]%s[/color]\n\n" % [
display_name, username, time_str, content
]
display_text += formatted_message
# 更新显示
message_contents.text = display_text
# 滚动到底部
call_deferred("scroll_to_bottom")
# 滚动到底部
func scroll_to_bottom():
if message_contents.get_v_scroll_bar():
message_contents.get_v_scroll_bar().value = message_contents.get_v_scroll_bar().max_value
# 加载聊天历史记录
func load_chat_history():
# 请求服务器加载最近3天的历史消息
request_history_from_server(current_load_days)
# 从服务器请求历史消息
func request_history_from_server(days: int):
if not tcp_network_manager_panel or not tcp_network_manager_panel.is_connected_to_server():
# 如果没有连接服务器,从本地文件加载
load_local_chat_history()
return
# 向服务器请求历史消息
var success = tcp_network_manager_panel.send_message({
"type": "request_broadcast_history",
"days": days,
"timestamp": Time.get_unix_time_from_system()
})
if not success:
Toast.show("请求历史消息失败", Color.RED, 2.0, 1.0)
load_local_chat_history()
# 从本地文件加载历史消息
func load_local_chat_history():
var file_path = "user://chat_history.json"
if FileAccess.file_exists(file_path):
var file = FileAccess.open(file_path, FileAccess.READ)
if file:
var json_string = file.get_as_text()
file.close()
var json = JSON.new()
var parse_result = json.parse(json_string)
if parse_result == OK:
var data = json.data
if data is Array:
message_history = data
# 按时间戳排序消息历史(从旧到新)
message_history.sort_custom(func(a, b): return a.get("timestamp", 0) < b.get("timestamp", 0))
update_message_display()
# 加载更多历史消息
func load_more_history():
if current_load_days >= max_load_days:
Toast.show("已经加载了最多30天的历史消息", Color.YELLOW, 2.0, 1.0)
return
# 增加加载天数
current_load_days += 7 # 每次多加载7天
if current_load_days > max_load_days:
current_load_days = max_load_days
# 请求更多历史消息
request_history_from_server(current_load_days)
Toast.show("正在加载更多历史消息...", Color.YELLOW, 2.0, 1.0)
# 接收服务器返回的历史消息
func receive_history_messages(data: Dictionary):
var messages = data.get("messages", [])
print("大喇叭面板收到历史消息: ", messages.size(), "")
if messages.size() > 0:
# 清空当前历史记录,重新加载
message_history.clear()
# 处理每条消息
for msg in messages:
_add_message_to_history(msg)
# 按时间戳排序
message_history.sort_custom(func(a, b): return a.get("timestamp", 0) < b.get("timestamp", 0))
# 保持消息历史记录在限制范围内
if message_history.size() > max_message_history:
message_history = message_history.slice(-max_message_history)
# 更新显示
update_message_display()
# 保存到本地
save_chat_history()
Toast.show("历史消息加载完成,共%d条消息" % messages.size(), Color.GREEN, 2.0, 1.0)
else:
Toast.show("没有找到历史消息", Color.YELLOW, 2.0, 1.0)
# 保存聊天历史记录
func save_chat_history():
var file_path = "user://chat_history.json"
var file = FileAccess.open(file_path, FileAccess.WRITE)
if file:
var json_string = JSON.stringify(message_history)
file.store_string(json_string)
file.close()
# 面板显示与隐藏切换处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
# 面板显示时,重新加载历史消息
current_load_days = 3 # 重置为3天
load_chat_history()
# 滚动到底部
call_deferred("scroll_to_bottom")
else:
GlobalVariables.isZoomDisabled = false
# 面板隐藏时,保存聊天历史
save_chat_history()
# 清空消息历史
func clear_message_history():
message_history.clear()
update_message_display()
save_chat_history()
Toast.show("消息历史已清空", Color.YELLOW, 2.0, 1.0)
# 获取最新消息用于主界面显示
func get_latest_message() -> String:
print("get_latest_message 被调用,消息历史大小: ", message_history.size())
if message_history.size() > 0:
# 确保消息按时间排序
message_history.sort_custom(func(a, b): return a.get("timestamp", 0) < b.get("timestamp", 0))
var latest = message_history[-1]
var result = latest.get("display_name", "匿名") + ": " + latest.get("content", "")
print("返回最新消息: ", result)
return result
print("没有消息历史,返回'暂无消息'")
return "暂无消息"

View File

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

View File

@@ -0,0 +1,637 @@
extends Panel
#获取玩家要操作的地块序号
var selected_lot_index = 0
#预添加常用的面板
@onready var main_game = get_node("/root/main")
@onready var lucky_draw_panel: LuckyDrawPanel = $'../../BigPanel/LuckyDrawPanel'
@onready var daily_check_in_panel: DailyCheckInPanel = $'../../BigPanel/DailyCheckInPanel'
@onready var tcp_network_manager_panel: Panel = $'../../BigPanel/TCPNetworkManagerPanel'
@onready var item_store_panel: Panel = $'../../BigPanel/ItemStorePanel'
@onready var item_bag_panel: Panel = $'../../BigPanel/ItemBagPanel'
@onready var player_bag_panel: Panel = $'../../BigPanel/PlayerBagPanel'
@onready var crop_warehouse_panel: Panel = $'../../BigPanel/CropWarehousePanel'
@onready var crop_store_panel: Panel = $'../../BigPanel/CropStorePanel'
@onready var player_ranking_panel: Panel = $'../../BigPanel/PlayerRankingPanel'
@onready var login_panel: PanelContainer = $'../../BigPanel/LoginPanel'
#土地面板功能
@onready var quit_button :Button = $Quit_Button
@onready var dig_button: Button = $GroundFunctionGrid/Dig_Button
@onready var plant_button: Button = $GroundFunctionGrid/Plant_Button
@onready var harvest_button: Button = $GroundFunctionGrid/Harvest_Button
@onready var upgrade_button: Button = $GroundFunctionGrid/Upgrade_Button
#展示被点击土地上的作物信息如果没有作物就隐藏crop_inform_v_box
@onready var crop_inform_v_box: VBoxContainer = $InformVBox/CropInformVBox
@onready var progress_bar: ProgressBar = $InformVBox/CropInformVBox/ProgressBar #作物生长进度
@onready var cost: Label = $InformVBox/CropInformVBox/HBox1/cost #作物购买花费
@onready var earn: Label = $InformVBox/CropInformVBox/HBox1/earn #作物收益
@onready var growthtime: Label = $InformVBox/CropInformVBox/HBox1/growthtime #作物生长时间精确到天时分秒
@onready var experience: Label = $InformVBox/CropInformVBox/HBox1/experience #作物收获经验
@onready var canbuy: Label = $InformVBox/CropInformVBox/HBox2/canbuy #作物能否在商店购买
@onready var quality: Label = $InformVBox/CropInformVBox/HBox2/quality #作物品质
@onready var weatherability: Label = $InformVBox/CropInformVBox/HBox2/weatherability #作物耐候性
@onready var level: Label = $InformVBox/CropInformVBox/HBox2/level #作物等级
@onready var description: Label = $InformVBox/CropInformVBox/HBox3/description #作物描述
@onready var crop_texture_rect: TextureRect = $CropImageVBox/CropTextureRect #作物当前图片
#展示被点击土地的地块信息
@onready var ground_level: Label = $InformVBox/GroundInformVBox/GroundLevel #土地等级
@onready var ground_function: Label = $InformVBox/GroundInformVBox/GroundFunction #土地功能
func _ready():
self.hide()
dig_button.pressed.connect(self._on_dig_button_pressed)
upgrade_button.pressed.connect(self._on_upgrade_button_pressed)
plant_button.pressed.connect(self._on_plant_button_pressed)
harvest_button.pressed.connect(self._on_harvest_button_pressed)
upgrade_button.visible = true
_update_button_texts()
# 显示面板时更新按钮状态
func show_panel():
self.show()
_update_button_texts()
_update_button_availability()
_update_panel_information() # 添加更新面板信息
# 更新按钮可用性
func _update_button_availability():
if main_game.is_visiting_mode:
# 访问模式下禁用一些按钮
dig_button.hide()
upgrade_button.hide()
plant_button.hide()
# 启用允许的按钮
harvest_button.show()
else:
# 自己农场模式下启用所有按钮
dig_button.show()
upgrade_button.show()
plant_button.show()
harvest_button.show()
# 更新按钮文本
func _update_button_texts():
# 根据是否访问模式显示不同的按钮文本
if main_game.is_visiting_mode:
harvest_button.text = "偷菜"
else:
dig_button.text = "开垦"+"\n"+str(main_game.dig_money)
# 升级按钮动态显示
_update_upgrade_button_text()
harvest_button.text = "收获"
# 更新升级按钮文本
func _update_upgrade_button_text():
if not main_game or not main_game.farm_lots:
upgrade_button.text = "升级\n¥1000"
return
if selected_lot_index >= 0 and selected_lot_index < main_game.farm_lots.size():
var lot = main_game.farm_lots[selected_lot_index]
var current_level = int(lot.get("土地等级", 0)) # 确保是整数
var upgrade_config = {
0: {"cost": 1000, "name": "黄土地"},
1: {"cost": 2000, "name": "红土地"},
2: {"cost": 4000, "name": "紫土地"},
3: {"cost": 8000, "name": "黑土地"}
}
if current_level >= 4:
upgrade_button.text = "已满级"
elif upgrade_config.has(current_level):
var config = upgrade_config[current_level]
upgrade_button.text = "升级到\n" + config["name"] + "\n" + str(config["cost"])
else:
upgrade_button.text = "等级异常\n" + str(current_level)
else:
upgrade_button.text = "选择地块"
#开垦
func _on_dig_button_pressed():
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法开垦土地", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 检查玩家金钱是否足够
var dig_cost = main_game.dig_money
if main_game.money < dig_cost:
Toast.show("金钱不足,开垦土地需要 " + str(dig_cost) + " 金钱", Color.RED, 2.0, 1.0)
self.hide()
return
# 检查地块是否已经开垦
var lot = main_game.farm_lots[selected_lot_index]
if lot.get("is_diged", false):
Toast.show("此地块已经开垦过了", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 发送开垦土地请求到服务器
if tcp_network_manager_panel and tcp_network_manager_panel.is_connected_to_server():
if tcp_network_manager_panel.sendDigGround(selected_lot_index):
self.hide()
else:
Toast.show("发送开垦请求失败", Color.RED, 2.0, 1.0)
self.hide()
else:
Toast.show("网络未连接,无法开垦土地", Color.RED, 2.0, 1.0)
self.hide()
#浇水
func _on_water_button_pressed():
# 检查玩家金钱是否足够(无论是否访问模式都检查自己的钱)
var water_cost = 50
var my_money = main_game.money
# 如果是访问模式,需要检查自己的原始金钱数据
if main_game.is_visiting_mode:
my_money = main_game.original_player_data.get("钱币", 0)
if my_money < water_cost:
var action_text = "帮助浇水" if main_game.is_visiting_mode else "浇水"
Toast.show("金钱不足," + action_text + "需要 " + str(water_cost) + " 金钱", Color.RED, 2.0, 1.0)
self.hide()
return
# 检查地块状态
var lot = main_game.farm_lots[selected_lot_index]
if not lot.get("is_planted", false) or lot.get("crop_type", "") == "":
Toast.show("此地块没有种植作物", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 检查作物是否已死亡
if lot.get("is_dead", false):
Toast.show("死亡的作物无法浇水", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 检查是否已经成熟
if lot.get("grow_time", 0) >= lot.get("max_grow_time", 1):
Toast.show("作物已经成熟,无需浇水", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 检查是否已经浇过水
var current_time = Time.get_unix_time_from_system()
var last_water_time = lot.get("浇水时间", 0)
var water_cooldown = 3600 # 1小时冷却时间
if current_time - last_water_time < water_cooldown:
var remaining_time = water_cooldown - (current_time - last_water_time)
var remaining_minutes = int(remaining_time / 60)
var remaining_seconds = int(remaining_time) % 60
Toast.show("浇水冷却中,还需等待 " + str(remaining_minutes) + " 分钟 " + str(remaining_seconds) + "", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 发送浇水请求到服务器
var target_username = ""
if main_game.is_visiting_mode:
target_username = main_game.visited_player_data.get("玩家账号", "")
if tcp_network_manager_panel and tcp_network_manager_panel.is_connected_to_server():
if tcp_network_manager_panel.sendWaterCrop(selected_lot_index, target_username):
self.hide()
else:
Toast.show("发送浇水请求失败", Color.RED, 2.0, 1.0)
self.hide()
else:
var action_text = "帮助浇水" if main_game.is_visiting_mode else "浇水"
Toast.show("网络未连接,无法" + action_text, Color.RED, 2.0, 1.0)
self.hide()
#施肥
func _on_fertilize_button_pressed():
# 检查玩家金钱是否足够(无论是否访问模式都检查自己的钱)
var fertilize_cost = 150
var my_money = main_game.money
# 如果是访问模式,需要检查自己的原始金钱数据
if main_game.is_visiting_mode:
my_money = main_game.original_player_data.get("钱币", 0)
if my_money < fertilize_cost:
var action_text = "帮助施肥" if main_game.is_visiting_mode else "施肥"
Toast.show("金钱不足," + action_text + "需要 " + str(fertilize_cost) + " 金钱", Color.RED, 2.0, 1.0)
self.hide()
return
# 检查地块状态
var lot = main_game.farm_lots[selected_lot_index]
if not lot.get("is_planted", false) or lot.get("crop_type", "") == "":
Toast.show("此地块没有种植作物", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 检查作物是否已死亡
if lot.get("is_dead", false):
Toast.show("死亡的作物无法施肥", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 检查是否已经成熟
if lot.get("grow_time", 0) >= lot.get("max_grow_time", 1):
Toast.show("作物已经成熟,无需施肥", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 检查是否已经施过肥
if lot.get("已施肥", false):
Toast.show("此作物已经施过肥了", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 发送施肥请求到服务器
var target_username = ""
if main_game.is_visiting_mode:
target_username = main_game.visited_player_data.get("玩家账号", "")
if tcp_network_manager_panel and tcp_network_manager_panel.is_connected_to_server():
if tcp_network_manager_panel.sendFertilizeCrop(selected_lot_index, target_username):
self.hide()
else:
Toast.show("发送施肥请求失败", Color.RED, 2.0, 1.0)
self.hide()
else:
var action_text = "帮助施肥" if main_game.is_visiting_mode else "施肥"
Toast.show("网络未连接,无法" + action_text, Color.RED, 2.0, 1.0)
self.hide()
#升级
func _on_upgrade_button_pressed():
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法升级", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 检查地块索引是否有效
if selected_lot_index < 0 or selected_lot_index >= main_game.farm_lots.size():
Toast.show("无效的地块选择", Color.RED, 2.0, 1.0)
self.hide()
return
# 获取地块数据
var lot = main_game.farm_lots[selected_lot_index]
# 检查地块是否已开垦
if not lot.get("is_diged", false):
Toast.show("此地块尚未开垦", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 获取当前土地等级和升级配置
var current_level = int(lot.get("土地等级", 0)) # 确保是整数
print("当前选择地块索引: ", selected_lot_index)
print("当前土地等级: ", current_level, " (类型: ", typeof(current_level), ")")
var upgrade_config = {
0: {"cost": 1000, "name": "黄土地", "speed": "2倍"},
1: {"cost": 2000, "name": "红土地", "speed": "4倍"},
2: {"cost": 4000, "name": "紫土地", "speed": "6倍"},
3: {"cost": 8000, "name": "黑土地", "speed": "10倍"}
}
# 检查是否已达到最高等级
if current_level >= 4:
Toast.show("此土地已达到最高等级(黑土地)", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 检查土地等级是否有效
if not upgrade_config.has(current_level):
Toast.show("土地等级数据异常,当前等级: " + str(current_level), Color.RED, 2.0, 1.0)
print("土地等级异常,当前等级: ", current_level, ",可用等级: ", upgrade_config.keys())
self.hide()
return
var config = upgrade_config[current_level]
var upgrade_cost = config["cost"]
var next_name = config["name"]
var speed_info = config["speed"]
# 检查玩家金钱是否足够
if main_game.money < upgrade_cost:
Toast.show("金钱不足,升级到" + next_name + "需要 " + str(upgrade_cost) + " 金钱", Color.RED, 2.0, 1.0)
self.hide()
return
# 发送升级请求到服务器
if tcp_network_manager_panel and tcp_network_manager_panel.is_connected_to_server():
print("发送升级请求,地块索引: ", selected_lot_index, ",当前等级: ", current_level)
if tcp_network_manager_panel.sendUpgradeLand(selected_lot_index):
self.hide()
else:
Toast.show("发送升级请求失败", Color.RED, 2.0, 1.0)
self.hide()
else:
Toast.show("网络未连接,无法升级土地", Color.RED, 2.0, 1.0)
self.hide()
#种植
func _on_plant_button_pressed():
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法种植", Color.ORANGE, 2.0, 1.0)
self.hide()
return
player_bag_panel.show()
self.hide()
pass
#铲除
func _on_remove_button_pressed():
# 检查是否处于访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法铲除作物", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 检查玩家金钱是否足够
var removal_cost = 500
if main_game.money < removal_cost:
Toast.show("金钱不足,铲除作物需要 " + str(removal_cost) + " 金钱", Color.RED, 2.0, 1.0)
self.hide()
return
# 检查地块是否有作物
var lot = main_game.farm_lots[selected_lot_index]
if not lot.get("is_planted", false) or lot.get("crop_type", "") == "":
Toast.show("此地块没有种植作物", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 发送铲除作物请求到服务器
if tcp_network_manager_panel and tcp_network_manager_panel.is_connected_to_server():
if tcp_network_manager_panel.sendRemoveCrop(selected_lot_index):
self.hide()
else:
Toast.show("发送铲除请求失败", Color.RED, 2.0, 1.0)
self.hide()
else:
Toast.show("网络未连接,无法铲除作物", Color.RED, 2.0, 1.0)
self.hide()
pass
#收获
func _on_harvest_button_pressed():
# 检查地块状态
var lot = main_game.farm_lots[selected_lot_index]
if not lot.get("is_planted", false) or lot.get("crop_type", "") == "":
Toast.show("此地块没有种植作物", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 检查作物是否成熟
if lot.get("grow_time", 0) < lot.get("max_grow_time", 1) and not lot.get("is_dead", false):
Toast.show("作物尚未成熟", Color.ORANGE, 2.0, 1.0)
self.hide()
return
# 发送收获请求到服务器
var target_username = ""
if main_game.is_visiting_mode:
target_username = main_game.visited_player_data.get("玩家账号", "")
if tcp_network_manager_panel and tcp_network_manager_panel.is_connected_to_server():
if tcp_network_manager_panel.sendHarvestCrop(selected_lot_index, target_username):
self.hide()
else:
Toast.show("发送收获请求失败", Color.RED, 2.0, 1.0)
self.hide()
else:
var action_text = "偷菜" if main_game.is_visiting_mode else "收获"
Toast.show("网络未连接,无法" + action_text, Color.RED, 2.0, 1.0)
self.hide()
pass
#===================面板通用函数==========================
#退出
func _on_quit_button_pressed():
self.hide()
pass
#刷新面板信息
func _on_refresh_button_pressed() -> void:
_update_panel_information()
Toast.show("面板信息已刷新", Color.GREEN, 1.5, 1.0)
#面板显示与隐藏切换处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
pass
else:
GlobalVariables.isZoomDisabled = false
pass
#===================面板通用函数==========================
# 更新面板信息显示
func _update_panel_information():
if selected_lot_index < 0 or selected_lot_index >= main_game.farm_lots.size():
print("无效的地块索引:", selected_lot_index)
return
var lot = main_game.farm_lots[selected_lot_index]
# 更新土地信息
_update_ground_information(lot)
# 检查是否有作物
if lot.get("is_planted", false) and lot.get("crop_type", "") != "":
# 有作物,显示作物信息
crop_inform_v_box.show()
_update_crop_information(lot)
_update_crop_texture(lot)
else:
# 没有作物,隐藏作物信息框
crop_inform_v_box.hide()
crop_texture_rect.hide()
# 更新作物信息
func _update_crop_information(lot: Dictionary):
var crop_name = lot.get("crop_type", "")
var grow_time = float(lot.get("grow_time", 0))
var max_grow_time = float(lot.get("max_grow_time", 1))
var is_dead = lot.get("is_dead", false)
var is_watered = lot.get("已浇水", false)
var is_fertilized = lot.get("已施肥", false)
# 从作物数据中获取详细信息
if main_game.can_planted_crop.has(crop_name):
var crop_data = main_game.can_planted_crop[crop_name]
# 更新作物基本信息
cost.text = "花费:" + str(crop_data.get("花费", 0)) + ""
earn.text = "收益:" + str(crop_data.get("收益", 0)) + ""
experience.text = "经验:" + str(crop_data.get("经验", 0)) + ""
quality.text = "品质:" + str(crop_data.get("品质", "未知"))
weatherability.text = "耐候性:" + str(crop_data.get("耐候性", 0))
level.text = "等级:" + str(crop_data.get("等级", 1))
description.text = "描述:" + str(crop_data.get("描述", "无描述"))
# 更新生长时间显示
var total_seconds = int(crop_data.get("生长时间", 0))
var time_str = _format_time_display(total_seconds)
growthtime.text = "生长时间:" + time_str
# 更新能否购买
var can_buy = crop_data.get("能否购买", false)
canbuy.text = "可购买:" + ("" if can_buy else "")
else:
# 作物数据不存在,显示基本信息
cost.text = "花费:未知"
earn.text = "收益:未知"
experience.text = "经验:未知"
quality.text = "品质:未知"
weatherability.text = "耐候性:未知"
level.text = "等级:未知"
description.text = "描述:作物数据未找到"
growthtime.text = "生长时间:未知"
canbuy.text = "可购买:未知"
# 更新生长进度条
if is_dead:
progress_bar.value = 0
progress_bar.modulate = Color.RED
progress_bar.show()
elif max_grow_time > 0:
var progress = clamp(grow_time / max_grow_time, 0.0, 1.0) * 100
progress_bar.value = progress
# 根据生长状态设置进度条颜色
if progress >= 100:
progress_bar.modulate = Color.GREEN # 成熟
elif is_fertilized:
progress_bar.modulate = Color.YELLOW # 已施肥
elif is_watered:
progress_bar.modulate = Color.CYAN # 已浇水
else:
progress_bar.modulate = Color.WHITE # 正常生长
progress_bar.show()
else:
progress_bar.hide()
# 更新作物图片
func _update_crop_texture(lot: Dictionary):
var crop_name = lot.get("crop_type", "")
var grow_time = float(lot.get("grow_time", 0))
var max_grow_time = float(lot.get("max_grow_time", 1))
var is_dead = lot.get("is_dead", false)
if crop_name == "":
crop_texture_rect.hide()
return
crop_texture_rect.show()
# 如果作物已死亡,显示死亡状态
if is_dead:
crop_texture_rect.modulate = Color.GRAY
# 可以在这里设置死亡图片,暂时使用灰色调
else:
crop_texture_rect.modulate = Color.WHITE
# 计算生长进度
var progress = 0.0
if max_grow_time > 0:
progress = clamp(grow_time / max_grow_time, 0.0, 1.0)
# 获取对应的作物图片
var texture: Texture2D = null
if main_game.crop_texture_manager:
texture = main_game.crop_texture_manager.get_texture_by_progress(crop_name, progress)
if texture:
crop_texture_rect.texture = texture
else:
# 如果没有找到图片,尝试加载默认图片
var default_path = "res://assets/作物/默认/0.webp"
if ResourceLoader.exists(default_path):
crop_texture_rect.texture = load(default_path)
else:
crop_texture_rect.hide()
# 更新土地信息
func _update_ground_information(lot: Dictionary):
var land_level = int(lot.get("土地等级", 0))
var is_diged = lot.get("is_diged", false)
# 土地等级配置
var level_config = {
0: {"name": "普通土地", "color": Color.WHITE, "speed": "1倍"},
1: {"name": "黄土地", "color": Color(1.0, 1.0, 0.0), "speed": "2倍"},
2: {"name": "红土地", "color": Color(1.0, 0.41, 0.0), "speed": "4倍"},
3: {"name": "紫土地", "color": Color(0.55, 0.29, 0.97), "speed": "6倍"},
4: {"name": "黑土地", "color": Color(0.33, 0.4, 0.59), "speed": "10倍"}
}
if is_diged:
if level_config.has(land_level):
var config = level_config[land_level]
ground_level.text = "土地等级:" + config["name"] + " (Lv." + str(land_level) + ")"
ground_function.text = "生长速度:" + config["speed"]
ground_level.modulate = config["color"]
else:
ground_level.text = "土地等级:未知等级 (Lv." + str(land_level) + ")"
ground_function.text = "生长速度:未知"
ground_level.modulate = Color.WHITE
else:
ground_level.text = "土地状态:未开垦"
ground_function.text = "功能:需要开垦后才能使用"
ground_level.modulate = Color.GRAY
# 格式化时间显示
func _format_time_display(total_seconds: int) -> String:
var time_str = ""
# 定义时间单位换算
var SECONDS_PER_MINUTE = 60
var SECONDS_PER_HOUR = 3600
var SECONDS_PER_DAY = 86400
# 计算各时间单位
var days = total_seconds / SECONDS_PER_DAY
total_seconds %= SECONDS_PER_DAY
var hours = total_seconds / SECONDS_PER_HOUR
total_seconds %= SECONDS_PER_HOUR
var minutes = total_seconds / SECONDS_PER_MINUTE
var seconds = total_seconds % SECONDS_PER_MINUTE
# 构建时间字符串(只显示有值的单位)
if days > 0:
time_str += str(days) + ""
if hours > 0:
time_str += str(hours) + "小时"
if minutes > 0:
time_str += str(minutes) + "分钟"
if seconds > 0:
time_str += str(seconds) + ""
return time_str if time_str != "" else "0秒"

View File

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

View File

@@ -0,0 +1,620 @@
extends Panel
#一键种植面板
#通过不断地调用土地面板的种植功能来实现一键种植,减少玩家重复性工作
#执行间隔为0.25秒
#目前分为
#全屏种植从序列号0开始依次种植玩家选定植物直到玩家种子用完为止或者完成种植
#行种植:需要玩家点击某个地块,然后从该行从左到右依次种植
#列种植:需要玩家点击某个地块,然后从该列从上到下依次种植
#九宫格种植:需要玩家点击某个地块,然后从该地块上下左右四周九个方向各自种植一个植物
#十字法种植:需要玩家点击某个地块,然后从上下左右四个方向各自种植一个植物
#注意,无论点击的是已经种植的地块,未开垦地块还是空地地块都不影响,因为点击只是为了确认一个具体位置
#然后在一键种植过程中,如果遇到已种植地块,未开垦地块,还是这个方向根本就没有地块等非法操作,没有关系直接跳过即可
#为了方便你确认位置和方向我的客户端地块排列是10行4-8列目前是但不确定以后会不会更改排布你最好留个接口
#你可以参考一下一键收获功能的原理实现
#注意注意,以上操作都是在客户端完成,服务端不要添加什么操作
#默认一键种植收费为种植作物的总和价格的20%+基础费用500
#注意钱不够的问题
@onready var full_screen_plant_btn: Button = $Grid/FullScreenPlantBtn #全屏种植
@onready var one_row_plant_btn: Button = $Grid/OneRowPlantBtn #行种植
@onready var one_column_plant_btn: Button = $Grid/OneColumnPlantBtn #列种植
@onready var nine_square_plant_btn: Button = $Grid/NineSquarePlantBtn #九宫格种植
@onready var cross_plant_btn: Button = $Grid/CrossPlantBtn #十字法种植
@onready var random_plant_btn: Button = $Grid/RandomPlantBtn #随机种植
# 引用主游戏和其他面板
@onready var main_game = get_node("/root/main")
@onready var lucky_draw_panel: LuckyDrawPanel = $'../../BigPanel/LuckyDrawPanel'
@onready var daily_check_in_panel: DailyCheckInPanel = $'../../BigPanel/DailyCheckInPanel'
@onready var tcp_network_manager_panel: Panel = $'../../BigPanel/TCPNetworkManagerPanel'
@onready var item_store_panel: Panel = $'../../BigPanel/ItemStorePanel'
@onready var item_bag_panel: Panel = $'../../BigPanel/ItemBagPanel'
@onready var player_bag_panel: Panel = $'../../BigPanel/PlayerBagPanel'
@onready var crop_warehouse_panel: Panel = $'../../BigPanel/CropWarehousePanel'
@onready var crop_store_panel: Panel = $'../../BigPanel/CropStorePanel'
@onready var player_ranking_panel: Panel = $'../../BigPanel/PlayerRankingPanel'
@onready var login_panel: PanelContainer = $'../../BigPanel/LoginPanel'
# 种植配置
# 注意:地块的实际布局可能与代码设想的不同,这里提供可配置的接口
const GRID_COLUMNS = 10 # 地块列数配置接口,可根据需要调整
const GRID_ROWS_MIN = 4 # 最小行数
const GRID_ROWS_MAX = 8 # 最大行数
const BASE_COST = 500 # 基础费用
const COST_RATE = 0.2 # 种植成本比例20%
const PLANT_INTERVAL = 0.25 # 种植间隔时间
# 种植状态变量
var is_planting = false
var selected_crop_name = ""
var selected_crop_count = 0
var plant_timer = 0.0
var plant_queue = [] # 种植队列,存储要种植的地块索引
var current_plant_index = 0
# 等待用户点击地块的状态
var is_waiting_for_lot_selection = false
var pending_plant_type = ""
#==================基础函数=====================
func _ready():
self.hide()
# 连接可见性改变信号
visibility_changed.connect(_on_visibility_changed)
# 连接按钮信号
full_screen_plant_btn.pressed.connect(_on_full_screen_plant_pressed)
one_row_plant_btn.pressed.connect(_on_one_row_plant_pressed)
one_column_plant_btn.pressed.connect(_on_one_column_plant_pressed)
nine_square_plant_btn.pressed.connect(_on_nine_square_plant_pressed)
cross_plant_btn.pressed.connect(_on_cross_plant_pressed)
random_plant_btn.pressed.connect(_on_random_plant_pressed)
# 设置按钮提示文本
_setup_button_tooltips()
func _process(delta):
if is_planting:
plant_timer += delta
if plant_timer >= PLANT_INTERVAL:
plant_timer = 0.0
_process_plant_queue()
#==================基础函数=====================
#=================================一键种植模式=========================================
# 全屏种植按钮处理
func _on_full_screen_plant_pressed():
_request_crop_selection("全屏种植", "选择要种植的作物进行全屏种植")
# 行种植按钮处理
func _on_one_row_plant_pressed():
_start_lot_selection_mode("行种植")
# 列种植按钮处理
func _on_one_column_plant_pressed():
_start_lot_selection_mode("列种植")
# 九宫格种植按钮处理
func _on_nine_square_plant_pressed():
_start_lot_selection_mode("九宫格种植")
# 十字法种植按钮处理
func _on_cross_plant_pressed():
_start_lot_selection_mode("十字法种植")
# 随机种植按钮处理
func _on_random_plant_pressed():
_prepare_random_plant()
# 准备全屏种植
func _prepare_full_screen_plant():
plant_queue.clear()
# 从序列号0开始依次添加可种植的地块
for i in range(len(main_game.farm_lots)):
if _can_plant_at_index(i):
plant_queue.append(i)
_start_planting("全屏种植")
# 准备行种植
func _prepare_row_plant():
plant_queue.clear()
var target_row = _get_row_from_index(main_game.selected_lot_index)
# 添加同一行的所有可种植地块(从左到右)
for i in range(len(main_game.farm_lots)):
if _get_row_from_index(i) == target_row and _can_plant_at_index(i):
plant_queue.append(i)
_start_planting("行种植")
# 准备列种植
func _prepare_column_plant():
plant_queue.clear()
var target_column = _get_column_from_index(main_game.selected_lot_index)
# 添加同一列的所有可种植地块(从上到下)
for i in range(len(main_game.farm_lots)):
if _get_column_from_index(i) == target_column and _can_plant_at_index(i):
plant_queue.append(i)
_start_planting("列种植")
# 准备九宫格种植
func _prepare_nine_square_plant():
plant_queue.clear()
var center_row = _get_row_from_index(main_game.selected_lot_index)
var center_column = _get_column_from_index(main_game.selected_lot_index)
# 九宫格的相对位置偏移
var offsets = [
[-1, -1], [-1, 0], [-1, 1],
[0, -1], [0, 0], [0, 1],
[1, -1], [1, 0], [1, 1]
]
for offset in offsets:
var row = center_row + offset[0]
var column = center_column + offset[1]
var index = _get_index_from_row_column(row, column)
if index != -1 and _can_plant_at_index(index):
plant_queue.append(index)
_start_planting("九宫格种植")
# 准备十字法种植
func _prepare_cross_plant():
plant_queue.clear()
var center_row = _get_row_from_index(main_game.selected_lot_index)
var center_column = _get_column_from_index(main_game.selected_lot_index)
# 十字法的相对位置偏移
var offsets = [
[0, 0], # 中心
[-1, 0], # 上
[1, 0], # 下
[0, -1], # 左
[0, 1] # 右
]
for offset in offsets:
var row = center_row + offset[0]
var column = center_column + offset[1]
var index = _get_index_from_row_column(row, column)
if index != -1 and _can_plant_at_index(index):
plant_queue.append(index)
_start_planting("十字法种植")
# 准备随机种植
func _prepare_random_plant():
# 检查背包是否有种子
if main_game.player_bag.size() == 0:
Toast.show("背包中没有种子,请先去商店购买", Color.RED)
return
# 获取背包中所有的种子类型和数量
var available_seeds = []
for item in main_game.player_bag:
if item["count"] > 0:
# 根据种子数量添加多个相同种子到列表中
for i in range(item["count"]):
available_seeds.append(item["name"])
if available_seeds.size() == 0:
Toast.show("背包中没有可用的种子", Color.RED)
return
# 打乱种子列表
available_seeds.shuffle()
# 获取所有可种植的地块
var available_lots = []
for i in range(len(main_game.farm_lots)):
if _can_plant_at_index(i):
available_lots.append(i)
if available_lots.size() == 0:
Toast.show("没有可种植的地块", Color.YELLOW)
return
# 根据种子数量和可种植地块数量确定实际种植数量
var plant_count = min(available_seeds.size(), available_lots.size())
# 准备种植队列,每个元素包含地块索引和对应的种子名称
plant_queue.clear()
var random_plant_data = [] # 存储地块索引和对应种子的映射
for i in range(plant_count):
var lot_index = available_lots[i]
var seed_name = available_seeds[i]
plant_queue.append(lot_index)
random_plant_data.append({"lot_index": lot_index, "seed_name": seed_name})
# 存储随机种植数据到全局变量,供种植过程使用
if not has_meta("random_plant_data"):
set_meta("random_plant_data", random_plant_data)
else:
set_meta("random_plant_data", random_plant_data)
# 计算总费用(基于所有要种植的种子)
var total_crop_cost = 0
for data in random_plant_data:
var crop_data = main_game.can_planted_crop.get(data["seed_name"], {})
var crop_price = crop_data.get("花费", 0)
total_crop_cost += crop_price
var service_fee = int(total_crop_cost * COST_RATE) + BASE_COST
print("随机种植费用计算:")
var seed_names = []
for data in random_plant_data:
seed_names.append(data["seed_name"])
print(" 将要种植的种子:%s" % str(seed_names))
print(" 种植数量:%d 个地块" % plant_count)
print(" 作物总成本:%d" % total_crop_cost)
print(" 服务费率:%.1f%%" % (COST_RATE * 100))
print(" 基础费用:%d" % BASE_COST)
print(" 总服务费:%d" % service_fee)
print(" 玩家当前金钱:%d" % main_game.money)
# 检查金钱是否足够支付服务费
if main_game.money < service_fee:
Toast.show("金钱不足!随机种植需要服务费 %d 元(当前:%d 元)" % [service_fee, main_game.money], Color.RED)
return
# 扣除服务费
main_game.money -= service_fee
main_game._update_ui()
# 开始种植
is_planting = true
current_plant_index = 0
plant_timer = 0.0
# 更新按钮状态为种植中
_update_buttons_planting_state(true)
# 计算不同种子的数量
var unique_seeds = {}
for data in random_plant_data:
unique_seeds[data["seed_name"]] = true
var unique_seed_count = unique_seeds.size()
Toast.show("开始随机种植,预计种植 %d 个地块,使用 %d 种不同种子,服务费 %d" % [plant_count, unique_seed_count, service_fee], Color.GREEN)
#=================================一键种植模式=========================================
# 开始地块选择模式
func _start_lot_selection_mode(plant_type: String):
is_waiting_for_lot_selection = true
pending_plant_type = plant_type
# 隐藏一键种植面板
self.hide()
# 显示提示信息
var tip_message = ""
match plant_type:
"行种植":
tip_message = "请点击一个地块来确定要种植的行"
"列种植":
tip_message = "请点击一个地块来确定要种植的列"
"九宫格种植":
tip_message = "请点击一个地块来确定九宫格种植的中心位置"
"十字法种植":
tip_message = "请点击一个地块来确定十字法种植的中心位置"
_:
tip_message = "请点击一个地块"
Toast.show(tip_message + "按ESC键取消", Color.CYAN)
print("进入地块选择模式:%s" % plant_type)
# 处理地块选择从MainGame调用
func on_lot_selected(lot_index: int):
if not is_waiting_for_lot_selection:
return false # 不是等待地块选择状态返回false让MainGame正常处理
# 退出地块选择模式
is_waiting_for_lot_selection = false
# 设置选择的地块索引
main_game.selected_lot_index = lot_index
# 开始作物选择
_request_crop_selection(pending_plant_type, "选择要种植的作物进行" + pending_plant_type)
# 清空待处理的种植类型
pending_plant_type = ""
return true # 返回true表示已处理了地块选择
# 请求作物选择
func _request_crop_selection(plant_type: String, tip_message: String):
# 检查背包是否有种子
if main_game.player_bag.size() == 0:
Toast.show("背包中没有种子,请先去商店购买", Color.RED)
return
var has_seeds = false
for item in main_game.player_bag:
if item["count"] > 0:
has_seeds = true
break
if not has_seeds:
Toast.show("背包中没有可用的种子", Color.RED)
return
Toast.show(tip_message, Color.CYAN)
self.hide()
# 设置背包面板的种植模式回调
player_bag_panel.set_planting_mode(plant_type, self)
player_bag_panel.show()
# 背包选择作物回调函数
func on_crop_selected(crop_name: String, plant_type: String):
selected_crop_name = crop_name
# 检查背包中的作物数量
selected_crop_count = _get_crop_count_in_bag(crop_name)
if selected_crop_count <= 0:
Toast.show("背包中没有 " + crop_name + " 种子", Color.RED)
return
# 根据种植类型生成种植队列
match plant_type:
"全屏种植":
_prepare_full_screen_plant()
"行种植":
_prepare_row_plant()
"列种植":
_prepare_column_plant()
"九宫格种植":
_prepare_nine_square_plant()
"十字法种植":
_prepare_cross_plant()
_:
Toast.show("未知的种植模式:" + plant_type, Color.RED)
print("错误:未知的种植模式:%s" % plant_type)
# 获取背包中指定作物的数量
func _get_crop_count_in_bag(crop_name: String) -> int:
for item in main_game.player_bag:
if item["name"] == crop_name:
return item["count"]
return 0
# 开始种植
func _start_planting(plant_type: String):
if plant_queue.size() == 0:
Toast.show("没有可种植的地块", Color.YELLOW)
return
# 限制种植数量不超过背包中的种子数量
var max_plantable = min(plant_queue.size(), selected_crop_count)
if max_plantable < plant_queue.size():
plant_queue = plant_queue.slice(0, max_plantable)
# 计算总费用
var crop_data = main_game.can_planted_crop.get(selected_crop_name, {})
var crop_price = crop_data.get("花费", 0)
var total_crop_cost = crop_price * plant_queue.size()
var service_fee = int(total_crop_cost * COST_RATE) + BASE_COST
var total_cost = service_fee # 只收取服务费,种子费用由种植时扣除
print("一键种植费用计算:")
print(" 作物:%s,单价:%d" % [selected_crop_name, crop_price])
print(" 种植数量:%d 个地块" % plant_queue.size())
print(" 作物总成本:%d" % total_crop_cost)
print(" 服务费率:%.1f%%" % (COST_RATE * 100))
print(" 基础费用:%d" % BASE_COST)
print(" 总服务费:%d" % total_cost)
print(" 玩家当前金钱:%d" % main_game.money)
# 检查金钱是否足够支付服务费
if main_game.money < total_cost:
Toast.show("金钱不足!%s需要服务费 %d 元(当前:%d 元)" % [plant_type, total_cost, main_game.money], Color.RED)
return
# 扣除服务费
main_game.money -= total_cost
main_game._update_ui()
# 开始种植
is_planting = true
current_plant_index = 0
plant_timer = 0.0
# 更新按钮状态为种植中
_update_buttons_planting_state(true)
Toast.show("开始%s,预计种植 %d 个地块,服务费 %d" % [plant_type, plant_queue.size(), total_cost], Color.GREEN)
# 处理种植队列
func _process_plant_queue():
if current_plant_index >= plant_queue.size():
# 种植完成
_finish_planting()
return
var lot_index = plant_queue[current_plant_index]
# 检查是否是随机种植模式
if has_meta("random_plant_data"):
# 随机种植模式:每个地块种植不同的种子
var random_plant_data = get_meta("random_plant_data")
if current_plant_index < random_plant_data.size():
var plant_data = random_plant_data[current_plant_index]
var seed_name = plant_data["seed_name"]
# 检查是否还有该种子和该地块是否仍可种植
if _get_crop_count_in_bag(seed_name) > 0 and _can_plant_at_index(lot_index):
# 执行随机种植
_plant_at_index_with_seed(lot_index, seed_name)
else:
# 普通种植模式:所有地块种植相同的种子
# 检查是否还有种子和该地块是否仍可种植
if _get_crop_count_in_bag(selected_crop_name) > 0 and _can_plant_at_index(lot_index):
# 执行种植
_plant_at_index(lot_index)
current_plant_index += 1
# 完成种植
func _finish_planting():
is_planting = false
# 恢复按钮状态
_update_buttons_planting_state(false)
# 清空队列
plant_queue.clear()
current_plant_index = 0
# 清理随机种植的元数据
if has_meta("random_plant_data"):
remove_meta("random_plant_data")
# 在指定索引处种植
func _plant_at_index(lot_index: int):
if tcp_network_manager_panel and tcp_network_manager_panel.sendPlantCrop(lot_index, selected_crop_name):
pass
else:
print("发送种植请求失败:地块 %d" % lot_index)
# 在指定索引处种植指定种子(用于随机种植)
func _plant_at_index_with_seed(lot_index: int, seed_name: String):
if tcp_network_manager_panel and tcp_network_manager_panel.sendPlantCrop(lot_index, seed_name):
pass
else:
print("发送种植请求失败:地块 %d,种子 %s" % [lot_index, seed_name])
# 检查指定索引的地块是否可以种植
func _can_plant_at_index(index: int) -> bool:
if index < 0 or index >= len(main_game.farm_lots):
return false
var lot = main_game.farm_lots[index]
# 必须是已开垦且未种植的地块
return lot.get("is_diged", false) and not lot.get("is_planted", false)
# 根据索引获取行号
func _get_row_from_index(index: int) -> int:
if index < 0:
return -1
return index / GRID_COLUMNS
# 根据索引获取列号
func _get_column_from_index(index: int) -> int:
if index < 0:
return -1
return index % GRID_COLUMNS
# 根据行列号获取索引
func _get_index_from_row_column(row: int, column: int) -> int:
if row < 0 or column < 0 or column >= GRID_COLUMNS:
return -1
var index = row * GRID_COLUMNS + column
if index >= len(main_game.farm_lots):
return -1
return index
# 设置按钮提示文本
func _setup_button_tooltips():
full_screen_plant_btn.tooltip_text = "从第一个地块开始依次种植选定作物,直到种子用完或地块种完\n费用种植总成本的20% + 500元基础费"
one_row_plant_btn.tooltip_text = "在选定地块所在的行中从左到右依次种植\n点击此按钮后,再点击农场中的任意地块确定行位置\n费用种植总成本的20% + 500元基础费"
one_column_plant_btn.tooltip_text = "在选定地块所在的列中从上到下依次种植\n点击此按钮后,再点击农场中的任意地块确定列位置\n费用种植总成本的20% + 500元基础费"
nine_square_plant_btn.tooltip_text = "以选定地块为中心的3x3九宫格范围内种植\n点击此按钮后,再点击农场中的任意地块确定中心位置\n费用种植总成本的20% + 500元基础费"
cross_plant_btn.tooltip_text = "以选定地块为中心的十字形(上下左右+中心)种植\n点击此按钮后,再点击农场中的任意地块确定中心位置\n费用种植总成本的20% + 500元基础费"
random_plant_btn.tooltip_text = "获取背包中所有种子并打乱后随机种植到所有空地块\n自动使用背包中的各种种子,每个地块种植不同种子\n费用种植总成本的20% + 500元基础费"
# 更新按钮状态
func _update_buttons_planting_state(planting: bool):
if planting:
# 种植中,禁用所有种植按钮
full_screen_plant_btn.disabled = true
one_row_plant_btn.disabled = true
one_column_plant_btn.disabled = true
nine_square_plant_btn.disabled = true
cross_plant_btn.disabled = true
random_plant_btn.disabled = true
full_screen_plant_btn.text = "种植中..."
one_row_plant_btn.text = "种植中..."
one_column_plant_btn.text = "种植中..."
nine_square_plant_btn.text = "种植中..."
cross_plant_btn.text = "种植中..."
random_plant_btn.text = "种植中..."
else:
# 种植完成,恢复按钮状态
full_screen_plant_btn.disabled = false
one_row_plant_btn.disabled = false
one_column_plant_btn.disabled = false
nine_square_plant_btn.disabled = false
cross_plant_btn.disabled = false
random_plant_btn.disabled = false
full_screen_plant_btn.text = "全屏种植"
one_row_plant_btn.text = "行种植"
one_column_plant_btn.text = "列种植"
nine_square_plant_btn.text = "九宫格\n种植"
cross_plant_btn.text = "十字法\n种植"
random_plant_btn.text = "随机\n种植"
# 取消地块选择模式
func cancel_lot_selection():
if is_waiting_for_lot_selection:
is_waiting_for_lot_selection = false
pending_plant_type = ""
Toast.show("已取消地块选择", Color.YELLOW)
# 重新显示一键种植面板
self.show()
# 停止当前种植过程
func stop_planting():
if is_planting:
is_planting = false
Toast.show("一键种植已停止", Color.YELLOW)
_finish_planting()
#======================通用面板处理=====================
#关闭一键种植面板
func _on_quit_button_pressed() -> void:
# 如果正在种植,先停止种植
if is_planting:
stop_planting()
# 如果正在等待地块选择,取消选择
elif is_waiting_for_lot_selection:
cancel_lot_selection()
return
self.hide()
pass
#面板显示切换处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
pass
else:
GlobalVariables.isZoomDisabled = false
pass
#======================通用面板处理=====================

View File

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

View File

@@ -0,0 +1,207 @@
extends Panel
@onready var one_minute: Button = $Grid/OneMinute
@onready var three_minutes: Button = $Grid/ThreeMinutes
@onready var five_minutes: Button = $Grid/FiveMinutes
@onready var ten_minutes: Button = $Grid/TenMinutes
@onready var thirty_minutes: Button = $Grid/ThirtyMinutes
@onready var one_hour: Button = $Grid/OneHour
@onready var three_hours: Button = $Grid/ThreeHours
@onready var five_hours: Button = $Grid/FiveHours
@onready var lucky_draw_panel: LuckyDrawPanel = $'../../BigPanel/LuckyDrawPanel'
@onready var daily_check_in_panel: DailyCheckInPanel = $'../../BigPanel/DailyCheckInPanel'
@onready var tcp_network_manager_panel: Panel = $'../../BigPanel/TCPNetworkManagerPanel'
@onready var item_store_panel: Panel = $'../../BigPanel/ItemStorePanel'
@onready var item_bag_panel: Panel = $'../../BigPanel/ItemBagPanel'
@onready var player_bag_panel: Panel = $'../../BigPanel/PlayerBagPanel'
@onready var crop_warehouse_panel: Panel = $'../../BigPanel/CropWarehousePanel'
@onready var crop_store_panel: Panel = $'../../BigPanel/CropStorePanel'
@onready var player_ranking_panel: Panel = $'../../BigPanel/PlayerRankingPanel'
@onready var login_panel: PanelContainer = $'../../BigPanel/LoginPanel'
# 在线礼包配置(从服务器动态获取)
var online_gift_config = {}
var gift_time_config = {
"1分钟": 60,
"3分钟": 180,
"5分钟": 300,
"10分钟": 600,
"30分钟": 1800,
"1小时": 3600,
"3小时": 10800,
"5小时": 18000
}
# 按钮映射
var button_mapping = {}
# 礼包领取状态
var gift_claimed_status = {}
# 在线开始时间
var online_start_time: float = 0
# 当前在线时长
var current_online_duration: float = 0
func _ready():
# 初始化按钮映射
button_mapping = {
"1分钟": one_minute,
"3分钟": three_minutes,
"5分钟": five_minutes,
"10分钟": ten_minutes,
"30分钟": thirty_minutes,
"1小时": one_hour,
"3小时": three_hours,
"5小时": five_hours
}
# 连接可见性改变信号
visibility_changed.connect(_on_visibility_changed)
# 连接按钮信号
for gift_name in button_mapping.keys():
var button = button_mapping[gift_name]
if button:
button.pressed.connect(_on_gift_button_pressed.bind(gift_name))
# 初始化时禁用所有按钮
disable_all_buttons()
#显示面板并请求最新数据
func show_panel_and_request_data():
show()
move_to_front()
request_online_gift_data()
#禁用所有礼包按钮
func disable_all_buttons():
for button in button_mapping.values():
if button:
button.disabled = true
#更新按钮状态
func update_button_status():
for gift_name in gift_time_config.keys():
var button = button_mapping.get(gift_name)
if not button:
continue
var required_time = gift_time_config[gift_name]
var is_claimed = gift_claimed_status.get(gift_name, false)
if is_claimed:
# 已领取
button.disabled = true
button.text = gift_name + "\n(已领取)"
elif current_online_duration >= required_time:
# 可以领取
button.disabled = false
button.text = gift_name + "\n(可领取)"
else:
# 时间未到
button.disabled = true
var remaining_time = required_time - current_online_duration
button.text = gift_name + "\n(" + format_time(remaining_time) + ")"
#格式化时间显示
func format_time(seconds: float) -> String:
var hours = int(seconds / 3600)
var minutes = int(int(seconds) % 3600 / 60)
var secs = int(int(seconds) % 60)
if hours > 0:
return "%d:%02d:%02d" % [hours, minutes, secs]
else:
return "%02d:%02d" % [minutes, secs]
#处理礼包按钮点击
func _on_gift_button_pressed(gift_name: String):
if gift_claimed_status.get(gift_name, false):
Toast.show("该礼包已经领取过了!", Color.RED)
return
# 发送领取请求到服务器
request_claim_online_gift(gift_name)
#请求在线礼包数据
func request_online_gift_data():
tcp_network_manager_panel.sendGetOnlineGiftData()
#请求领取在线礼包
func request_claim_online_gift(gift_name: String):
tcp_network_manager_panel.sendClaimOnlineGift(gift_name)
#处理在线礼包数据响应
func handle_online_gift_data_response(data: Dictionary):
if data.has("claimed_gifts"):
gift_claimed_status = data["claimed_gifts"]
if data.has("online_start_time"):
online_start_time = data["online_start_time"]
# 直接使用服务端计算的在线时长
if data.has("current_online_duration"):
current_online_duration = data["current_online_duration"]
# 更新按钮状态
update_button_status()
#处理领取在线礼包响应
func handle_claim_online_gift_response(data: Dictionary):
var success = data.get("success", false)
var message = data.get("message", "")
var gift_name = data.get("gift_name", "")
if success:
# 标记为已领取
gift_claimed_status[gift_name] = true
# 显示奖励信息
var rewards = data.get("rewards", {})
var reward_text = "获得奖励: "
# 处理中文配置格式的奖励
if rewards.has("金币"):
reward_text += "金币+" + str(rewards["金币"]) + " "
if rewards.has("经验"):
reward_text += "经验+" + str(rewards["经验"]) + " "
if rewards.has("种子"):
for seed in rewards["种子"]:
reward_text += seed["名称"] + "x" + str(seed["数量"]) + " "
# 兼容老格式
if rewards.has("钱币"):
reward_text += "金币+" + str(rewards["钱币"]) + " "
if rewards.has("经验值"):
reward_text += "经验+" + str(rewards["经验值"]) + " "
if rewards.has("seeds"):
for seed in rewards["seeds"]:
reward_text += seed["name"] + "x" + str(seed["count"]) + " "
Toast.show(reward_text, Color.GOLD)
Toast.show(message, Color.GREEN)
# 更新按钮状态
update_button_status()
else:
Toast.show(message, Color.RED)
#================通用面板处理==================
#关闭在线礼包面板
func _on_quit_button_pressed() -> void:
self.hide()
# 面板显示时的处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
pass
else:
GlobalVariables.isZoomDisabled = false
pass
#================通用面板处理==================

View File

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

View File

@@ -0,0 +1,653 @@
extends Panel
@onready var pet_image: TextureRect = $PetImage #显示宠物图片
@onready var pet_name_edit: LineEdit = $InformScroll/VBox/PetNameHBox/PetNameEdit #编辑宠物名字
@onready var pet_inform: RichTextLabel = $InformScroll/VBox/PetInform #显示宠物其他信息
@onready var quit_button: Button = $QuitButton
@onready var refresh_button: Button = $RefreshButton
@onready var edit_inform_button: Button = $ButtonHBox/EditInformButton
@onready var feed_button: Button = $ButtonHBox/FeedButton #宠物喂食
@onready var use_item_button: Button = $ButtonHBox/UseItemButton #宠物使用道具
@onready var patro_button: Button = $ButtonHBox/PatroButton #宠物农场巡逻
@onready var battle_button: Button = $ButtonHBox/BattleButton #宠物设置为出战
# 当前显示的宠物数据
var current_pet_data: Dictionary = {}
var current_pet_name: String = ""
# 游戏节点引用
@onready var main_game = get_node("/root/main")
@onready var tcp_network_manager_panel: Panel = $'../../BigPanel/TCPNetworkManagerPanel'
@onready var lucky_draw_panel: LuckyDrawPanel = $'../../BigPanel/LuckyDrawPanel'
@onready var daily_check_in_panel: DailyCheckInPanel = $'../../BigPanel/DailyCheckInPanel'
@onready var player_ranking_panel: Panel = $'../../BigPanel/PlayerRankingPanel'
@onready var item_store_panel: Panel = $'../../BigPanel/ItemStorePanel'
@onready var crop_warehouse_panel: Panel = $'../../BigPanel/CropWarehousePanel'
@onready var login_panel: PanelContainer = $'../../BigPanel/LoginPanel'
@onready var player_bag_panel: Panel = $'../../BigPanel/PlayerBagPanel'
@onready var crop_store_panel: Panel = $'../../BigPanel/CropStorePanel'
@onready var item_bag_panel: Panel = $'../../BigPanel/ItemBagPanel'
@onready var pet_store_panel: Panel = $'../../BigPanel/PetStorePanel'
@onready var pet_bag_panel: Panel = $'../../BigPanel/PetBagPanel'
func _ready() -> void:
quit_button.pressed.connect(self.on_quit_button_pressed)
refresh_button.pressed.connect(self.on_refresh_button_pressed)
edit_inform_button.pressed.connect(self.on_edit_inform_button_pressed)
feed_button.pressed.connect(self.on_feed_button_pressed)
use_item_button.pressed.connect(self.on_use_item_button_pressed)
patro_button.pressed.connect(self._on_patrol_button_pressed)
battle_button.pressed.connect(self._on_battle_button_pressed)
# 启用bbcode支持
pet_inform.bbcode_enabled = true
# 默认隐藏面板
self.hide()
# 显示宠物信息的主函数
func show_pet_info(pet_name: String, pet_data: Dictionary):
current_pet_name = pet_name
current_pet_data = pet_data
# 设置宠物图片
_set_pet_image(pet_name)
# 设置宠物名称新格式直接从pet_name字段获取
var pet_owner_name = pet_data.get("pet_name", pet_name)
pet_name_edit.text = pet_owner_name
# 设置宠物详细信息
_set_pet_detailed_info(pet_name, pet_data)
# 刷新巡逻按钮状态
_refresh_patrol_button()
# 刷新出战按钮状态
_refresh_battle_button()
# 设置宠物图片
func _set_pet_image(pet_name: String):
var texture = _get_pet_texture(pet_name)
if texture:
pet_image.texture = texture
pet_image.visible = true
else:
pet_image.visible = false
# 获取宠物纹理
func _get_pet_texture(pet_name: String) -> Texture2D:
# 从服务器的宠物配置获取场景路径
var pet_config = main_game.pet_config # 使用服务器返回的宠物配置
if pet_config.has(pet_name):
var pet_info = pet_config[pet_name]
var scene_path = pet_info.get("pet_image", "") # 使用服务器数据的pet_image字段
print("宠物信息面板 ", pet_name, " 的图片路径:", scene_path)
if scene_path != "" and ResourceLoader.exists(scene_path):
print("宠物信息面板开始加载宠物场景:", scene_path)
var pet_scene = load(scene_path)
if pet_scene:
var pet_instance = pet_scene.instantiate()
# 直接使用实例化的场景根节点因为根节点就是PetImage
if pet_instance and pet_instance.sprite_frames:
var animation_names = pet_instance.sprite_frames.get_animation_names()
if animation_names.size() > 0:
var default_animation = animation_names[0]
var frame_count = pet_instance.sprite_frames.get_frame_count(default_animation)
if frame_count > 0:
var texture = pet_instance.sprite_frames.get_frame_texture(default_animation, 0)
print("宠物信息面板成功获取宠物纹理:", pet_name)
pet_instance.queue_free()
return texture
else:
print("宠物信息面板场景没有动画:", pet_name)
else:
print("宠物信息面板场景没有PetImage节点或sprite_frames", pet_name)
pet_instance.queue_free()
else:
print("宠物信息面板无法加载宠物场景:", scene_path)
else:
print("宠物信息面板图片路径无效或文件不存在:", scene_path)
else:
print("宠物信息面板配置中没有找到:", pet_name)
return null
# 加载宠物配置数据
func _load_pet_config() -> Dictionary:
var file = FileAccess.open("res://Data/pet_data.json", FileAccess.READ)
if file == null:
return {}
var json = JSON.new()
var json_string = file.get_as_text()
file.close()
var parse_result = json.parse(json_string)
if parse_result != OK:
return {}
return json.data
# 设置宠物详细信息使用bbcode美化- 新格式
func _set_pet_detailed_info(pet_name: String, pet_data: Dictionary):
# 计算宠物年龄
var pet_birthday = pet_data.get("pet_birthday", "")
var pet_age = 0
if pet_birthday != "":
pet_age = _calculate_pet_age(pet_birthday)
# 使用bbcode美化显示
var info_text = ""
# 基本信息
info_text += "[color=pink][b]🐾 基本信息[/b][/color]\n"
info_text += "宠物类型:[color=yellow]" + str(pet_data.get("pet_type", "未知")) + "[/color]\n"
info_text += "宠物编号:[color=gray]" + str(pet_data.get("pet_id", "")) + "[/color]\n"
info_text += "性格特点:[color=cyan]" + str(pet_data.get("pet_temperament", "活泼")) + "[/color]\n"
info_text += "出生日期:[color=green]" + str(pet_birthday) + "[/color]\n"
info_text += "年龄天数:[color=orange]" + str(pet_age) + " 天[/color]\n"
info_text += "爱好:[color=magenta]" + str(pet_data.get("pet_hobby", "")) + "[/color]\n"
info_text += "介绍:[color=lime]" + str(pet_data.get("pet_introduction", "")) + "[/color]\n\n"
# 等级经验
info_text += "[color=gold][b]⭐ 等级经验[/b][/color]\n"
info_text += "当前等级:[color=yellow]" + str(pet_data.get("pet_level", 1)) + " 级[/color]\n"
info_text += "经验值:[color=cyan]" + str(pet_data.get("pet_experience", 0)) + "/" + str(pet_data.get("pet_max_experience", 1000)) + "[/color]\n"
info_text += "亲密度:[color=pink]" + str(pet_data.get("pet_intimacy", 0)) + "/" + str(pet_data.get("pet_max_intimacy", 1000)) + "[/color]\n\n"
# 生命与防御
info_text += "[color=red][b]❤️ 生命与防御[/b][/color]\n"
info_text += "生命值:[color=red]" + str(pet_data.get("pet_current_health", pet_data.get("max_health", 100))) + "/" + str(pet_data.get("max_health", 100)) + "[/color]\n"
info_text += "护甲值:[color=blue]" + str(pet_data.get("pet_current_armor", pet_data.get("max_armor", 0))) + "/" + str(pet_data.get("max_armor", 0)) + "[/color]\n"
info_text += "护盾值:[color=cyan]" + str(pet_data.get("pet_current_shield", pet_data.get("max_shield", 0))) + "/" + str(pet_data.get("max_shield", 0)) + "[/color]\n"
info_text += "生命恢复:[color=lime]" + str(pet_data.get("health_regen", 0)) + "/秒[/color]\n"
info_text += "护盾恢复:[color=cyan]" + str(pet_data.get("shield_regen", 0)) + "/秒[/color]\n\n"
# 攻击属性
info_text += "[color=orange][b]⚔️ 攻击属性[/b][/color]\n"
info_text += "攻击伤害:[color=red]" + str(pet_data.get("base_attack_damage", 0)) + " 点[/color]\n"
info_text += "暴击几率:[color=purple]" + str(pet_data.get("crit_rate", 0) * 100) + "%[/color]\n"
info_text += "暴击倍数:[color=purple]" + str(pet_data.get("crit_damage", 1.0)) + " 倍[/color]\n"
info_text += "护甲穿透:[color=orange]" + str(pet_data.get("armor_penetration", 0)) + " 点[/color]\n"
info_text += "左手武器:[color=yellow]" + str(pet_data.get("left_weapon", "")) + "[/color]\n"
info_text += "右手武器:[color=yellow]" + str(pet_data.get("right_weapon", "")) + "[/color]\n\n"
# 移动与闪避
info_text += "[color=green][b]🏃 移动与闪避[/b][/color]\n"
info_text += "移动速度:[color=cyan]" + str(pet_data.get("move_speed", 0)) + " 像素/秒[/color]\n"
info_text += "闪避几率:[color=yellow]" + str(pet_data.get("dodge_rate", 0) * 100) + "%[/color]\n\n"
# 元素属性
info_text += "[color=purple][b]🔥 元素属性[/b][/color]\n"
info_text += "元素类型:[color=yellow]" + _get_element_name(str(pet_data.get("element_type", "NONE"))) + "[/color]\n"
info_text += "元素伤害:[color=orange]" + str(pet_data.get("element_damage_bonus", 0)) + " 点[/color]\n\n"
# 技能系统
info_text += "[color=gold][b]✨ 技能系统[/b][/color]\n"
if pet_data.get("enable_multi_projectile_skill", false):
info_text += "多重弹射:[color=green]已激活[/color] (延迟: " + str(pet_data.get("multi_projectile_delay", 0)) + "秒)\n"
if pet_data.get("enable_berserker_skill", false):
info_text += "狂暴技能:[color=red]已激活[/color] (倍数: " + str(pet_data.get("berserker_bonus", 1.0)) + ", 持续: " + str(pet_data.get("berserker_duration", 0)) + "秒)\n"
if pet_data.get("enable_self_destruct_skill", false):
info_text += "自爆技能:[color=orange]已激活[/color]\n"
if pet_data.get("enable_summon_pet_skill", false):
info_text += "召唤技能:[color=cyan]已激活[/color] (数量: " + str(pet_data.get("summon_count", 0)) + ", 缩放: " + str(pet_data.get("summon_scale", 1.0)) + ")\n"
if pet_data.get("enable_death_respawn_skill", false):
info_text += "死亡重生:[color=purple]已激活[/color] (生命: " + str(pet_data.get("respawn_health_percentage", 0) * 100) + "%)\n"
if pet_data.get("enable_damage_reflection_skill", false):
info_text += "伤害反弹:[color=yellow]已激活[/color] (荆棘护甲)\n"
info_text += "\n"
# 设置文本
pet_inform.text = info_text
# 获取攻击类型名称
func _get_attack_type_name(attack_type: String) -> String:
match attack_type:
"MELEE":
return "近战攻击"
"RANGED":
return "远程攻击"
"MAGIC":
return "魔法攻击"
_:
return attack_type
# 获取元素类型名称
func _get_element_name(element_type: String) -> String:
match element_type:
"NONE":
return "无元素"
"FIRE":
return "火元素"
"WATER":
return "水元素"
"EARTH":
return "土元素"
"AIR":
return "风元素"
"LIGHT":
return "光元素"
"DARK":
return "暗元素"
_:
return element_type
# 计算宠物年龄(以天为单位)
func _calculate_pet_age(birthday: String) -> int:
if birthday == "":
return 0
# 解析生日字符串格式2025年7月5日10时7分25秒
var birthday_parts = birthday.split("")
if birthday_parts.size() < 2:
return 0
var year = int(birthday_parts[0])
var rest = birthday_parts[1]
var month_parts = rest.split("")
if month_parts.size() < 2:
return 0
var month = int(month_parts[0])
var rest2 = month_parts[1]
var day_parts = rest2.split("")
if day_parts.size() < 2:
return 0
var day = int(day_parts[0])
var rest3 = day_parts[1]
var hour_parts = rest3.split("")
if hour_parts.size() < 2:
return 0
var hour = int(hour_parts[0])
var rest4 = hour_parts[1]
var minute_parts = rest4.split("")
if minute_parts.size() < 2:
return 0
var minute = int(minute_parts[0])
var rest5 = minute_parts[1]
var second_parts = rest5.split("")
if second_parts.size() < 1:
return 0
var second = int(second_parts[0])
# 将生日转换为Unix时间戳
var birthday_dict = {
"year": year,
"month": month,
"day": day,
"hour": hour,
"minute": minute,
"second": second
}
var birthday_timestamp = Time.get_unix_time_from_datetime_dict(birthday_dict)
var current_timestamp = Time.get_unix_time_from_system()
# 计算天数差
var age_seconds = current_timestamp - birthday_timestamp
var age_days = int(age_seconds / (24 * 3600))
return max(0, age_days)
func on_quit_button_pressed():
self.hide()
#刷新面板
func on_refresh_button_pressed():
if current_pet_name != "" and current_pet_data.size() > 0:
show_pet_info(current_pet_name, current_pet_data)
#编辑宠物信息按钮(目前就只有宠物名字)
func on_edit_inform_button_pressed():
if current_pet_data.is_empty():
Toast.show("没有选择宠物", Color.RED, 2.0, 1.0)
return
# 获取输入框中的新名字
var new_pet_name = pet_name_edit.text.strip_edges()
# 检查名字是否为空
if new_pet_name == "":
Toast.show("宠物名字不能为空", Color.RED, 2.0, 1.0)
return
# 检查名字长度
if new_pet_name.length() > 20:
Toast.show("宠物名字太长最多20个字符", Color.RED, 2.0, 1.0)
return
# 获取当前宠物名字(新格式)
var current_name = current_pet_data.get("pet_name", "")
# 检查名字是否有变化
if new_pet_name == current_name:
Toast.show("宠物名字没有变化", Color.YELLOW, 2.0, 1.0)
return
# 显示确认对话框
_show_rename_confirmation_dialog(new_pet_name, current_name)
# 显示重命名确认对话框
func _show_rename_confirmation_dialog(new_name: String, old_name: String):
var confirm_dialog = AcceptDialog.new()
confirm_dialog.dialog_text = str(
"确认修改宠物名字?\n\n" +
"原名字:" + old_name + "\n" +
"新名字:" + new_name + "\n\n" +
"修改后将无法撤销!"
)
confirm_dialog.title = "宠物重命名确认"
confirm_dialog.ok_button_text = "确认修改"
confirm_dialog.add_cancel_button("取消")
# 添加到场景
add_child(confirm_dialog)
# 连接信号
confirm_dialog.confirmed.connect(_on_confirm_rename_pet.bind(new_name, confirm_dialog))
confirm_dialog.canceled.connect(_on_cancel_rename_pet.bind(confirm_dialog))
# 显示对话框
confirm_dialog.popup_centered()
# 确认重命名宠物
func _on_confirm_rename_pet(new_name: String, dialog: AcceptDialog):
# 发送重命名请求到服务器
_send_rename_pet_request(new_name)
dialog.queue_free()
# 取消重命名宠物
func _on_cancel_rename_pet(dialog: AcceptDialog):
# 恢复原名字(新格式)
var original_name = current_pet_data.get("pet_name", "")
pet_name_edit.text = original_name
dialog.queue_free()
# 发送重命名宠物请求
func _send_rename_pet_request(new_name: String):
if not tcp_network_manager_panel or not tcp_network_manager_panel.has_method("sendRenamePet"):
Toast.show("网络功能不可用", Color.RED, 2.0, 1.0)
return
# 获取宠物ID新格式
var pet_id = current_pet_data.get("pet_id", "")
if pet_id == "":
Toast.show("宠物ID无效", Color.RED, 2.0, 1.0)
return
# 发送重命名请求
if tcp_network_manager_panel.sendRenamePet(pet_id, new_name):
pass
else:
Toast.show("重命名请求发送失败", Color.RED, 2.0, 1.0)
# 处理重命名成功的响应(从宠物背包或其他地方调用)
func on_rename_pet_success(pet_id: String, new_name: String):
# 更新当前宠物数据(新格式)
if current_pet_data.get("pet_id", "") == pet_id:
current_pet_data["pet_name"] = new_name
pet_name_edit.text = new_name
Toast.show("宠物名字修改成功!", Color.GREEN, 2.0, 1.0)
# 刷新显示
show_pet_info(current_pet_name, current_pet_data)
#喂养宠物
func on_feed_button_pressed():
if current_pet_data.is_empty():
Toast.show("没有选择宠物", Color.RED, 2.0, 1.0)
return
# 检查是否为访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法喂养宠物", Color.ORANGE, 2.0, 1.0)
return
if crop_warehouse_panel:
# 设置为宠物喂食模式
crop_warehouse_panel.set_pet_feeding_mode(true, current_pet_data)
crop_warehouse_panel.show()
pet_bag_panel.hide()
self.hide()
else:
Toast.show("无法找到作物仓库面板", Color.RED, 2.0, 1.0)
#对宠物使用道具
func on_use_item_button_pressed():
# 检查是否有选择的宠物
if current_pet_data.is_empty():
Toast.show("请先选择一个宠物", Color.RED, 2.0, 1.0)
return
# 检查是否为访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法使用道具", Color.ORANGE, 2.0, 1.0)
return
if item_bag_panel:
# 设置道具背包面板为宠物使用道具模式
item_bag_panel.set_pet_item_mode(true, current_pet_data)
item_bag_panel.show()
# 隐藏宠物信息面板
self.hide()
pet_bag_panel.hide()
Toast.show("请选择要使用的宠物道具", Color.CYAN, 3.0, 1.0)
else:
Toast.show("无法找到道具背包面板", Color.RED, 2.0, 1.0)
# 巡逻按钮点击事件
func _on_patrol_button_pressed():
if current_pet_data.is_empty():
Toast.show("没有选择宠物", Color.RED, 2.0, 1.0)
return
# 检查是否为访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法设置巡逻宠物", Color.ORANGE, 2.0, 1.0)
return
# 获取宠物ID
var pet_id = current_pet_data.get("pet_id", "")
if pet_id == "":
Toast.show("宠物ID无效", Color.RED, 2.0, 1.0)
return
# 检查是否已经在巡逻
var is_patrolling = _is_pet_patrolling(pet_id)
if is_patrolling:
# 取消巡逻 - 发送到服务器
_send_patrol_request(pet_id, false)
var pet_name = current_pet_data.get("pet_name", "宠物")
Toast.show("正在取消 " + pet_name + " 的巡逻...", Color.YELLOW, 2.0, 1.0)
else:
# 检查巡逻宠物数量限制
if main_game.patrol_pet_instances.size() >= 4:
Toast.show("最多只能设置4个巡逻宠物", Color.RED, 2.0, 1.0)
return
# 开始巡逻 - 发送到服务器
_send_patrol_request(pet_id, true)
var pet_name = current_pet_data.get("pet_name", "宠物")
#Toast.show("正在设置 " + pet_name + " 为巡逻宠物...", Color.GREEN, 2.0, 1.0)
# 发送巡逻请求到服务器
func _send_patrol_request(pet_id: String, is_patrolling: bool):
var message = {
"type": "set_patrol_pet",
"pet_id": pet_id,
"is_patrolling": is_patrolling
}
tcp_network_manager_panel.client.send_data(message)
# 检查宠物是否在巡逻
func _is_pet_patrolling(pet_id: String) -> bool:
# 检查本地 patrol_pet_instances 数组
for pet_instance in main_game.patrol_pet_instances:
if pet_instance and is_instance_valid(pet_instance):
if pet_instance.pet_id == pet_id:
return true
return false
# 移除巡逻宠物
func _remove_patrol_pet(pet_id: String):
# 查找并移除对应的巡逻宠物实例
for pet_instance in main_game.patrol_pet_instances:
if pet_instance and is_instance_valid(pet_instance):
# 检查是否是对应的巡逻宠物
if pet_instance.pet_id == pet_id:
pet_instance.queue_free()
main_game.patrol_pet_instances.erase(pet_instance)
print("移除巡逻宠物实例: " + pet_instance.pet_name)
return
print("未找到对应的巡逻宠物实例: " + pet_id)
# 更新巡逻按钮文本
func _update_patrol_button_text(is_patrolling: bool):
if is_patrolling:
patro_button.text = "取消巡逻"
patro_button.modulate = Color.ORANGE
else:
patro_button.text = "设置巡逻"
patro_button.modulate = Color.GREEN
# 刷新巡逻按钮状态(在显示宠物信息时调用)
func _refresh_patrol_button():
if current_pet_data.is_empty():
return
var pet_id = current_pet_data.get("pet_id", "")
if pet_id == "":
return
var is_patrolling = _is_pet_patrolling(pet_id)
_update_patrol_button_text(is_patrolling)
# 出战按钮点击事件
func _on_battle_button_pressed():
if current_pet_data.is_empty():
Toast.show("没有选择宠物", Color.RED, 2.0, 1.0)
return
# 检查是否为访问模式
if main_game.is_visiting_mode:
Toast.show("访问模式下无法设置出战宠物", Color.ORANGE, 2.0, 1.0)
return
# 获取宠物ID新格式
var pet_id = current_pet_data.get("pet_id", "")
if pet_id == "":
Toast.show("宠物ID无效", Color.RED, 2.0, 1.0)
return
# 检查当前宠物是否已在出战
var is_currently_battling = _is_pet_battling(pet_id)
if is_currently_battling:
# 取消出战
_remove_from_battle(pet_id)
else:
# 添加到出战
_add_to_battle(pet_id)
# 检查宠物是否正在出战(基于服务器数据)
func _is_pet_battling(pet_id: String) -> bool:
# 检查服务器的出战宠物数据
if main_game.battle_pets == null or main_game.battle_pets.size() == 0:
return false
# 遍历出战宠物列表查找匹配的ID新格式
for battle_pet in main_game.battle_pets:
var battle_pet_id = battle_pet.get("pet_id", "")
if battle_pet_id == pet_id:
return true
return false
# 添加到出战新的基于ID的逻辑
func _add_to_battle(pet_id: String):
# 检查出战宠物数量限制目前服务器设置最多4个
if main_game.battle_pets != null and main_game.battle_pets.size() >= 4:
Toast.show("最多只能设置4个出战宠物", Color.ORANGE, 3.0, 1.0)
return
# 检查是否在巡逻中(出战宠物不能是巡逻宠物)
if _is_pet_patrolling(pet_id):
Toast.show("该宠物正在巡逻,不能同时设置为出战宠物", Color.ORANGE, 3.0, 1.0)
return
# 如果不是访问模式,则发送到服务器保存
if not main_game.is_visiting_mode:
# 发送到服务器保存
tcp_network_manager_panel.sendSetBattlePet(pet_id, true)
var pet_name = current_pet_data.get("pet_name", "未知")
Toast.show("正在设置 " + pet_name + " 为出战宠物...", Color.YELLOW, 2.0, 1.0)
else:
Toast.show("访问模式下无法设置出战宠物", Color.ORANGE, 2.0, 1.0)
# 从出战中移除新的基于ID的逻辑
func _remove_from_battle(pet_id: String):
# 如果不是访问模式,则发送到服务器保存
if not main_game.is_visiting_mode:
# 发送到服务器移除
tcp_network_manager_panel.sendSetBattlePet(pet_id, false)
pass
else:
Toast.show("访问模式下无法取消出战宠物", Color.ORANGE, 2.0, 1.0)
# 更新出战按钮文本
func _update_battle_button_text(is_battling: bool):
if is_battling:
battle_button.text = "取消出战"
battle_button.modulate = Color.ORANGE
else:
battle_button.text = "设置出战"
battle_button.modulate = Color.GREEN
# 刷新出战按钮状态(在显示宠物信息时调用)
func _refresh_battle_button():
if current_pet_data.is_empty():
return
var pet_id = current_pet_data.get("pet_id", "")
if pet_id == "":
return
var is_battling = _is_pet_battling(pet_id)
_update_battle_button_text(is_battling)
#面板显示与隐藏切换处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
pass
else:
GlobalVariables.isZoomDisabled = false
pass

View File

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

View File

@@ -0,0 +1,257 @@
extends Panel
@onready var scare_crow_1: Button = $BuyScareCrowHbox/ScareCrow1 #稻草人类型1
@onready var scare_crow_2: Button = $BuyScareCrowHbox/ScareCrow2 #稻草人类型2
@onready var scare_crow_3: Button = $BuyScareCrowHbox/ScareCrow3 #稻草人类型3
@onready var scare_crow_input: LineEdit = $HBox/ScareCrowInput #稻草人的昵称
@onready var scare_crow_name_color_input: ColorPickerButton = $HBox/ScareCrowNameColorInput #稻草人昵称的颜色
@onready var talk_1: LineEdit = $ScareCrowTalksGrid/Talk1 #稻草人展示的第一句话
@onready var talk_2: LineEdit = $ScareCrowTalksGrid/Talk2 #稻草人展示的第二句话
@onready var talk_3: LineEdit = $ScareCrowTalksGrid/Talk3 #稻草人展示的第三句话
@onready var talk_4: LineEdit = $ScareCrowTalksGrid/Talk4 #稻草人展示的第四句话
@onready var quit_button: Button = $QuitButton #关闭面板按钮
@onready var sure_button: Button = $HBox2/SureButton #确认修改按钮
@onready var color_picker_button_1: ColorPickerButton = $ScareCrowTalksColorGrid/ColorPickerButton1 #第一句话颜色
@onready var color_picker_button_2: ColorPickerButton = $ScareCrowTalksColorGrid/ColorPickerButton2 #第二句话颜色
@onready var color_picker_button_3: ColorPickerButton = $ScareCrowTalksColorGrid/ColorPickerButton3 #第三句话颜色
@onready var color_picker_button_4: ColorPickerButton = $ScareCrowTalksColorGrid/ColorPickerButton4 #第四句话颜色
# 引用主游戏和网络管理器
@onready var main_game = get_node("/root/main")
@onready var tcp_network_manager_panel: Panel = $'../../BigPanel/TCPNetworkManagerPanel'
# 稻草人配置数据
var scare_crow_config = {}
var player_scare_crow_config = {}
# 稻草人按钮数组
var scare_crow_buttons = []
func _ready():
# 初始化按钮数组
scare_crow_buttons = [scare_crow_1, scare_crow_2, scare_crow_3]
# 连接信号
scare_crow_1.pressed.connect(_on_scare_crow_1_pressed)
scare_crow_2.pressed.connect(_on_scare_crow_2_pressed)
scare_crow_3.pressed.connect(_on_scare_crow_3_pressed)
quit_button.pressed.connect(_on_quit_button_pressed)
sure_button.pressed.connect(_on_sure_button_pressed)
# 连接可见性改变信号
visibility_changed.connect(_on_visibility_changed)
# 加载稻草人配置
load_scare_crow_config()
# 初始化UI
update_ui()
# 加载稻草人配置
func load_scare_crow_config():
var file = FileAccess.open("res://Server/config/scare_crow_config.json", FileAccess.READ)
if file:
var json_text = file.get_as_text()
file.close()
var json = JSON.new()
var parse_result = json.parse(json_text)
if parse_result == OK:
scare_crow_config = json.get_data()
print("稻草人配置加载成功")
else:
print("稻草人配置JSON解析失败")
else:
print("无法读取稻草人配置文件")
# 更新UI显示
func update_ui():
if not scare_crow_config.has("稻草人类型"):
return
# 更新稻草人按钮
var scare_crow_types = scare_crow_config["稻草人类型"]
var type_names = ["稻草人1", "稻草人2", "稻草人3"]
for i in range(min(3, scare_crow_buttons.size())):
var button = scare_crow_buttons[i]
var type_name = type_names[i]
if scare_crow_types.has(type_name):
var price = scare_crow_types[type_name]["价格"]
var is_owned = player_scare_crow_config.get("已拥有稻草人类型", []).has(type_name)
if is_owned:
button.text = type_name + " (已拥有)"
button.disabled = false
button.modulate = Color.GREEN
else:
button.text = type_name + " (" + str(price) + "金币)"
button.disabled = false
button.modulate = Color.WHITE
else:
button.text = "未知类型"
button.disabled = true
# 更新当前稻草人配置
if player_scare_crow_config.has("稻草人昵称"):
scare_crow_input.text = player_scare_crow_config["稻草人昵称"]
# 更新昵称颜色
if player_scare_crow_config.has("稻草人昵称颜色"):
scare_crow_name_color_input.color = Color(player_scare_crow_config["稻草人昵称颜色"])
if player_scare_crow_config.has("稻草人说的话"):
var talks = player_scare_crow_config["稻草人说的话"]
if talks.has("第一句话"):
talk_1.text = talks["第一句话"]["内容"]
color_picker_button_1.color = Color(talks["第一句话"]["颜色"])
if talks.has("第二句话"):
talk_2.text = talks["第二句话"]["内容"]
color_picker_button_2.color = Color(talks["第二句话"]["颜色"])
if talks.has("第三句话"):
talk_3.text = talks["第三句话"]["内容"]
color_picker_button_3.color = Color(talks["第三句话"]["颜色"])
if talks.has("第四句话"):
talk_4.text = talks["第四句话"]["内容"]
color_picker_button_4.color = Color(talks["第四句话"]["颜色"])
# 设置玩家稻草人配置
func set_player_scare_crow_config(config: Dictionary):
player_scare_crow_config = config
update_ui()
# 购买/选择稻草人1
func _on_scare_crow_1_pressed():
handle_scare_crow_selection("稻草人1")
# 购买/选择稻草人2
func _on_scare_crow_2_pressed():
handle_scare_crow_selection("稻草人2")
# 购买/选择稻草人3
func _on_scare_crow_3_pressed():
handle_scare_crow_selection("稻草人3")
# 处理稻草人选择
func handle_scare_crow_selection(type_name: String):
var owned_types = player_scare_crow_config.get("已拥有稻草人类型", [])
if owned_types.has(type_name):
# 已拥有,选择为当前展示类型
# 发送修改请求到服务器保存展示类型
var config_data = {
"稻草人展示类型": type_name
}
# 发送修改请求(不需要费用,只是切换展示类型)
tcp_network_manager_panel.send_modify_scare_crow_config(config_data, 0)
Toast.show("正在切换到" + type_name + "...", Color.CYAN)
else:
# 未拥有,购买
var price = scare_crow_config["稻草人类型"][type_name]["价格"]
if main_game.money >= price:
# 发送购买请求
tcp_network_manager_panel.send_buy_scare_crow(type_name, price)
else:
Toast.show("金币不足,需要" + str(price) + "金币", Color.RED)
# 确认修改按钮
func _on_sure_button_pressed():
# 检查网络连接
if not tcp_network_manager_panel.is_connected_to_server():
Toast.show("未连接到服务器", Color.RED)
return
# 获取修改费用
var modify_cost = scare_crow_config.get("修改稻草人配置花费", 300)
# 检查金币是否足够
if main_game.money < modify_cost:
Toast.show("金币不足,修改配置需要" + str(modify_cost) + "金币", Color.RED)
return
# 准备配置数据
var config_data = {
"稻草人昵称": scare_crow_input.text,
"稻草人昵称颜色": scare_crow_name_color_input.color.to_html(),
"稻草人说的话": {
"第一句话": {
"内容": talk_1.text,
"颜色": color_picker_button_1.color.to_html()
},
"第二句话": {
"内容": talk_2.text,
"颜色": color_picker_button_2.color.to_html()
},
"第三句话": {
"内容": talk_3.text,
"颜色": color_picker_button_3.color.to_html()
},
"第四句话": {
"内容": talk_4.text,
"颜色": color_picker_button_4.color.to_html()
}
}
}
# 发送修改请求
tcp_network_manager_panel.send_modify_scare_crow_config(config_data, modify_cost)
# 关闭面板按钮
func _on_quit_button_pressed():
hide()
# 处理购买稻草人响应
func handle_buy_scare_crow_response(success: bool, message: String, updated_data: Dictionary):
if success:
Toast.show(message, Color.GREEN)
# 更新玩家数据
if updated_data.has("钱币"):
main_game.money = updated_data["钱币"]
if updated_data.has("稻草人配置"):
player_scare_crow_config = updated_data["稻草人配置"]
# 更新UI
main_game._update_ui()
update_ui()
# 更新主游戏中的稻草人显示
if main_game.has_method("update_scare_crow_display"):
main_game.update_scare_crow_display()
else:
Toast.show(message, Color.RED)
# 处理修改稻草人配置响应
func handle_modify_scare_crow_config_response(success: bool, message: String, updated_data: Dictionary):
if success:
Toast.show(message, Color.GREEN)
# 更新玩家数据
if updated_data.has("钱币"):
main_game.money = updated_data["钱币"]
if updated_data.has("稻草人配置"):
player_scare_crow_config = updated_data["稻草人配置"]
# 更新UI
main_game._update_ui()
update_ui()
# 更新主游戏中的稻草人显示
if main_game.has_method("update_scare_crow_display"):
main_game.update_scare_crow_display()
else:
Toast.show(message, Color.RED)
# 面板显示时的处理
func _on_visibility_changed():
if visible:
# 请求最新的稻草人配置
if tcp_network_manager_panel.is_connected_to_server():
tcp_network_manager_panel.send_get_scare_crow_config()
GlobalVariables.isZoomDisabled = true
else:
GlobalVariables.isZoomDisabled = false

View File

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

View File

@@ -0,0 +1,123 @@
extends PanelContainer
@onready var start_button: Button = $VBox/StartButton #开始占卜
@onready var quit_button: Button = $VBox/QuitButton #关闭面板
@onready var contents: RichTextLabel = $VBox/Scroll/Contents #显示占卜内容 用bbcode美化一下
@onready var tcp_network_manager_panel: Panel = $'../../BigPanel/TCPNetworkManagerPanel'
# 占卜状态
var is_divining: bool = false
var today_divination_data: Dictionary = {}
func _ready() -> void:
self.hide()
visibility_changed.connect(_on_visibility_changed)
# 连接按钮信号
start_button.pressed.connect(_on_start_button_pressed)
quit_button.pressed.connect(_on_quit_button_pressed)
#关闭面板
func _on_quit_button_pressed() -> void:
self.hide()
#开始占卜
func _on_start_button_pressed() -> void:
if is_divining:
return
# 检查今日是否已经占卜过
var today_date = Time.get_date_string_from_system()
if today_divination_data.get("占卜日期", "") == today_date:
Toast.show("今日已经占卜过了,明日再来吧!", Color.ORANGE)
return
# 开始占卜
is_divining = true
start_button.disabled = true
start_button.text = "占卜中..."
# 显示占卜进行中的内容
contents.text = "[center][color=gold]正在为您占卜中...[/color]\n\n[color=cyan]天机不可泄露,请稍候...[/color][/center]"
# 3秒后显示占卜结果
await get_tree().create_timer(3.0).timeout
# 发送占卜请求到服务器
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("sendDivinationRequest"):
tcp_network_manager_panel.sendDivinationRequest()
else:
Toast.show("网络连接异常,无法进行占卜", Color.RED)
_reset_divination_state()
# 处理占卜响应
func handle_divination_response(success: bool, message: String, divination_data: Dictionary = {}):
if success:
# 更新本地占卜数据
today_divination_data = divination_data.get("今日占卜对象", {})
# 显示占卜结果
_display_divination_result(today_divination_data)
Toast.show("占卜完成!", Color.GREEN)
else:
contents.text = "[center][color=red]占卜失败:" + message + "[/color][/center]"
Toast.show(message, Color.RED)
_reset_divination_state()
# 显示占卜结果
func _display_divination_result(divination_data: Dictionary):
var divination_date = divination_data.get("占卜日期", "")
var divination_result = divination_data.get("占卜结果", "")
var divination_level = divination_data.get("占卜等级", "")
var divination_hexagram = divination_data.get("卦象", "")
var divination_advice = divination_data.get("建议", "")
var result_text = "[center][color=gold]═══ 今日占卜结果 ═══[/color]\n\n"
result_text += "[color=cyan]占卜日期:[/color]" + divination_date + "\n\n"
result_text += "[color=yellow]占卜等级:[/color]" + divination_level + "\n\n"
result_text += "[color=purple]卦象:[/color]" + divination_hexagram + "\n\n"
result_text += "[color=blue]占卜结果:[/color]\n" + divination_result + "\n\n"
result_text += "[color=green]建议:[/color]\n" + divination_advice + "\n\n"
result_text += "[color=gold]═══════════════[/color][/center]"
contents.text = result_text
# 重置占卜状态
func _reset_divination_state():
is_divining = false
start_button.disabled = false
start_button.text = "开始占卜"
# 面板显示时的处理
func _on_visibility_changed():
if visible:
# 面板显示时自动刷新数据
_refresh_divination_data()
GlobalVariables.isZoomDisabled = true
else:
GlobalVariables.isZoomDisabled = false
# 刷新占卜数据
func _refresh_divination_data():
# 从主游戏获取占卜数据
var main_game = get_node("/root/main")
if main_game and main_game.has_method("get_player_divination_data"):
today_divination_data = main_game.get_player_divination_data()
# 检查今日是否已经占卜过
var today_date = Time.get_date_string_from_system()
if today_divination_data.get("占卜日期", "") == today_date:
# 显示今日占卜结果
_display_divination_result(today_divination_data)
start_button.text = "今日已占卜"
start_button.disabled = true
else:
# 显示默认内容
contents.text = "[center][color=gold]═══ 今日占卜 ═══[/color]\n\n[color=cyan]点击下方按钮开始今日占卜\n\n占卜将为您揭示今日运势\n结合易经八卦为您指点迷津[/color]\n\n[color=orange]每日仅可占卜一次[/color][/center]"
start_button.text = "开始占卜"
start_button.disabled = false
else:
# 显示默认内容
contents.text = "[center][color=gold]═══ 今日占卜 ═══[/color]\n\n[color=cyan]点击下方按钮开始今日占卜\n\n占卜将为您揭示今日运势\n结合易经八卦为您指点迷津[/color]\n\n[color=orange]每日仅可占卜一次[/color][/center]"

View File

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

View File

@@ -0,0 +1,316 @@
extends Panel
@onready var water_button: Button = $HBox/WaterButton #给智慧树浇水
@onready var fertilize_button: Button = $HBox/FertilizeButton #给智慧树施肥
@onready var play_music_button: Button = $HBox/PlayMusicButton #给智慧树放音乐
@onready var kill_bug_button: Button = $HBox/KillBugButton #给智慧树杀虫
@onready var kill_grass_button: Button = $HBox/KillGrassButton #给智慧树除草
@onready var revive_button: Button = $HBox/ReviveButton #智慧树死亡后需点击此处复活花费1000元
@onready var talk_input: LineEdit = $VBox/HBox/TalkInput #输入要发送给陌生人的一句话
@onready var send_button: Button = $VBox/HBox/SendButton #发送按钮
@onready var level: Label = $Grid/Level #玩家智慧树等级
@onready var health: Label = $Grid/Health #玩家智慧树生命值
@onready var experience: Label = $Grid/Experience #玩家智慧树经验值
@onready var height: Label = $Grid/Height #玩家智慧树高度
@onready var quit_button: Button = $QuitButton #退出按钮
@onready var tcp_network_manager_panel: Panel = $'../../BigPanel/TCPNetworkManagerPanel' #客户端与服务端通信核心
@onready var login_panel: PanelContainer = $'../../BigPanel/LoginPanel' #登录时要加载玩家智慧树状态
@onready var accept_dialog: AcceptDialog = $'../../DiaLog/AcceptDialog'
# 主游戏节点引用
@onready var main_game = get_node("/root/main")
# 智慧树配置数据
var wisdom_tree_config = {
"智慧树显示的话": "",
"等级": 1,
"当前经验值": 0,
"最大经验值": 100,
"当前生命值": 100,
"最大生命值": 100,
"高度": 20
}
# 智慧树升级经验计算函数(使用动态公式)
func calculate_wisdom_tree_max_exp(level):
if level <= 1:
return 100
# 使用指数增长公式:基础经验 * (等级^1.5) * 1.2
var base_exp = 50
var exp_multiplier = 1.2
var level_factor = pow(level, 1.5)
var max_exp = int(base_exp * level_factor * exp_multiplier)
return max_exp
# 确保智慧树配置格式正确,兼容旧格式
func _ensure_config_format():
# 如果是旧格式,转换为新格式
if wisdom_tree_config.has("生命值") and not wisdom_tree_config.has("当前生命值"):
var old_health = wisdom_tree_config.get("生命值", 100)
wisdom_tree_config["当前生命值"] = old_health
wisdom_tree_config["最大生命值"] = 100
wisdom_tree_config.erase("生命值")
if wisdom_tree_config.has("经验") and not wisdom_tree_config.has("当前经验值"):
var old_exp = wisdom_tree_config.get("经验", 0)
wisdom_tree_config["当前经验值"] = old_exp
var level = wisdom_tree_config.get("等级", 1)
wisdom_tree_config["最大经验值"] = calculate_wisdom_tree_max_exp(level)
wisdom_tree_config.erase("经验")
# 确保所有必需字段存在
if not wisdom_tree_config.has("当前生命值"):
wisdom_tree_config["当前生命值"] = 100
if not wisdom_tree_config.has("最大生命值"):
wisdom_tree_config["最大生命值"] = 100
if not wisdom_tree_config.has("当前经验值"):
wisdom_tree_config["当前经验值"] = 0
if not wisdom_tree_config.has("最大经验值"):
var level = wisdom_tree_config.get("等级", 1)
wisdom_tree_config["最大经验值"] = calculate_wisdom_tree_max_exp(level)
if not wisdom_tree_config.has("等级"):
wisdom_tree_config["等级"] = 1
if not wisdom_tree_config.has("高度"):
wisdom_tree_config["高度"] = 20
if not wisdom_tree_config.has("智慧树显示的话"):
wisdom_tree_config["智慧树显示的话"] = ""
func _ready() -> void:
self.hide()
# 连接按钮信号
water_button.pressed.connect(_on_water_button_pressed)
fertilize_button.pressed.connect(_on_fertilize_button_pressed)
play_music_button.pressed.connect(_on_play_music_button_pressed)
kill_bug_button.pressed.connect(_on_kill_bug_button_pressed)
kill_grass_button.pressed.connect(_on_kill_grass_button_pressed)
revive_button.pressed.connect(_on_revive_button_pressed)
send_button.pressed.connect(_on_send_button_pressed)
quit_button.pressed.connect(_on_quit_button_pressed)
visibility_changed.connect(_on_visibility_changed)
# 加载智慧树数据
load_wisdom_tree_data()
# 更新UI显示
update_ui()
# 加载智慧树数据
func load_wisdom_tree_data():
if main_game and main_game.login_data.has("智慧树配置"):
wisdom_tree_config = main_game.login_data["智慧树配置"]
# 更新UI显示
func update_ui():
# 确保配置数据格式正确,兼容旧格式
_ensure_config_format()
level.text = "等级: " + str(wisdom_tree_config["等级"])
var current_health = wisdom_tree_config["当前生命值"]
var max_health = wisdom_tree_config["最大生命值"]
health.text = "生命值: " + str(current_health) + "/" + str(max_health)
var current_exp = wisdom_tree_config["当前经验值"]
var max_exp = wisdom_tree_config["最大经验值"]
experience.text = "经验: " + str(current_exp) + "/" + str(max_exp)
height.text = "高度: " + str(wisdom_tree_config["高度"]) + "cm"
# 根据生命值设置颜色
if current_health <= 0:
health.modulate = Color.RED
revive_button.show()
# 智慧树死亡时禁用其他按钮
_set_buttons_enabled(false)
elif current_health <= max_health * 0.3: # 生命值低于30%
health.modulate = Color.ORANGE
revive_button.hide()
else:
health.modulate = Color.GREEN
revive_button.hide()
talk_input.editable = true
talk_input.placeholder_text = "在这里输入(*´∀ ˋ*)"
send_button.disabled = false
send_button.text = "发送"
# 获取下一等级需要的经验
func get_next_level_experience() -> int:
var current_level = wisdom_tree_config["等级"]
if current_level >= 20:
return 99999 # 最大等级
return calculate_wisdom_tree_max_exp(current_level + 1)
# 设置按钮启用状态
func _set_buttons_enabled(enabled: bool):
water_button.disabled = !enabled
fertilize_button.disabled = !enabled
play_music_button.disabled = !enabled
kill_bug_button.disabled = !enabled
kill_grass_button.disabled = !enabled
send_button.disabled = !enabled
# 显示操作确认弹窗
func show_operation_confirm(operation_type: String, cost: int, description: String):
if accept_dialog:
accept_dialog.set_dialog_title("确认操作")
accept_dialog.set_dialog_content("确定要" + description + "吗?\n费用:" + str(cost) + "金币")
accept_dialog.show()
# 连接确认信号
if not accept_dialog.confirmed.is_connected(_on_operation_confirmed):
accept_dialog.confirmed.connect(_on_operation_confirmed.bind(operation_type))
else:
# 断开之前的连接,重新连接
accept_dialog.confirmed.disconnect(_on_operation_confirmed)
accept_dialog.confirmed.connect(_on_operation_confirmed.bind(operation_type))
# 操作确认回调
func _on_operation_confirmed(operation_type: String):
# 发送操作请求到服务器
tcp_network_manager_panel.send_wisdom_tree_operation(operation_type)
# 浇水按钮
func _on_water_button_pressed():
show_operation_confirm("water", 100, "给智慧树浇水")
# 施肥按钮
func _on_fertilize_button_pressed():
show_operation_confirm("fertilize", 200, "给智慧树施肥")
# 除草按钮
func _on_kill_grass_button_pressed():
show_operation_confirm("kill_grass", 150, "给智慧树除草")
# 杀虫按钮
func _on_kill_bug_button_pressed():
show_operation_confirm("kill_bug", 150, "给智慧树杀虫")
# 放音乐按钮
func _on_play_music_button_pressed():
show_operation_confirm("play_music", 100, "给智慧树放音乐")
# 复活按钮
func _on_revive_button_pressed():
show_operation_confirm("revive", 1000, "复活智慧树")
# 发送消息按钮
func _on_send_button_pressed():
var message = talk_input.text.strip_edges()
if message.is_empty():
Toast.show("请输入要发送的消息!", Color.YELLOW)
return
if message.length() > 50:
Toast.show("消息长度不能超过50个字符", Color.RED)
return
# 发送消息到服务器
tcp_network_manager_panel.send_wisdom_tree_message(message)
# 清空输入框
talk_input.text = ""
# 退出按钮
func _on_quit_button_pressed():
self.hide()
# 处理智慧树操作响应
func handle_wisdom_tree_operation_response(success: bool, message: String, operation_type: String, updated_data: Dictionary):
if success:
# 更新智慧树配置
if updated_data.has("智慧树配置"):
wisdom_tree_config = updated_data["智慧树配置"]
# 同步更新MainGame中的智慧树配置
if main_game and main_game.login_data:
main_game.login_data["智慧树配置"] = wisdom_tree_config
# 更新玩家数据
if updated_data.has("钱币"):
main_game.money = updated_data["钱币"]
main_game._update_ui()
# 更新智慧树设置面板UI
update_ui()
# 同步更新MainGame中的智慧树显示
if main_game.has_method("update_wisdom_tree_display"):
main_game.update_wisdom_tree_display()
# 根据操作类型显示不同的提示
match operation_type:
"water":
#Toast.show("浇水成功!" + message, Color.CYAN)
pass
"fertilize":
#Toast.show("施肥成功!" + message, Color.PURPLE)
pass
"kill_grass":
#Toast.show("除草成功!" + message, Color.GREEN)
pass
"kill_bug":
#Toast.show("杀虫成功!" + message, Color.GREEN)
pass
"play_music":
#Toast.show("放音乐成功!" + message, Color.MAGENTA)
pass
# 放音乐时可能获得随机消息,需要特殊处理
if updated_data.has("random_message"):
var random_message = updated_data["random_message"]
if random_message != "":
# 更新智慧树显示的话
wisdom_tree_config["智慧树显示的话"] = random_message
if main_game and main_game.login_data:
main_game.login_data["智慧树配置"]["智慧树显示的话"] = random_message
# 再次更新MainGame显示
if main_game.has_method("update_wisdom_tree_display"):
main_game.update_wisdom_tree_display()
"revive":
Toast.show("智慧树复活成功!", Color.GOLD)
"get_random_message":
# 获取随机消息操作
if updated_data.has("random_message"):
var random_message = updated_data["random_message"]
if random_message != "":
# 更新智慧树显示的话
wisdom_tree_config["智慧树显示的话"] = random_message
if main_game and main_game.login_data:
main_game.login_data["智慧树配置"]["智慧树显示的话"] = random_message
# 更新MainGame显示
if main_game.has_method("update_wisdom_tree_display"):
main_game.update_wisdom_tree_display()
Toast.show("获得了新的智慧树消息!", Color.MAGENTA)
else:
Toast.show(message, Color.RED)
# 处理智慧树消息发送响应
func handle_wisdom_tree_message_response(success: bool, message: String, updated_data: Dictionary = {}):
if success:
# 更新玩家金钱
if updated_data.has("钱币"):
main_game.money = updated_data["钱币"]
main_game._update_ui()
#Toast.show("消息发送成功!", Color.GREEN)
else:
Toast.show(message, Color.RED)
# 面板显示与隐藏切换处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
# 面板打开时主动请求最新的智慧树配置
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("send_get_wisdom_tree_config"):
tcp_network_manager_panel.send_get_wisdom_tree_config()
load_wisdom_tree_data()
update_ui()
else:
GlobalVariables.isZoomDisabled = false

View File

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