优化项目架构
This commit is contained in:
853
SproutFarm-Frontend/Script/BigPanel/CropStorePanel.gd
Normal file
853
SproutFarm-Frontend/Script/BigPanel/CropStorePanel.gd
Normal file
@@ -0,0 +1,853 @@
|
||||
extends Panel
|
||||
|
||||
#种子商店面板
|
||||
#种子商店格子
|
||||
@onready var crop_grid_container : GridContainer = $ScrollContainer/Crop_Grid
|
||||
@onready var quit_button : Button = $QuitButton
|
||||
@onready var refresh_button : Button = $RefreshButton
|
||||
|
||||
#各种排序过滤按钮
|
||||
@onready var sort_all_button : Button = $SortContainer/Sort_All#全部
|
||||
@onready var sort_common_button : Button = $SortContainer/Sort_Common#普通
|
||||
@onready var sort_superior_button : Button = $SortContainer/Sort_Superior#优良
|
||||
@onready var sort_rare_button : Button = $SortContainer/Sort_Rare#稀有
|
||||
@onready var sort_epic_button : Button = $SortContainer/Sort_Epic#史诗
|
||||
@onready var sort_legendary_button : Button = $SortContainer/Sort_Legendary#传奇
|
||||
@onready var sort_price_button : Button = $SortContainer/Sort_Price#价格
|
||||
@onready var sort_growtime_button : Button = $SortContainer/Sort_GrowTime#生长时间
|
||||
@onready var sort_profit_button : Button = $SortContainer/Sort_Profit#收益
|
||||
@onready var sort_level_button : Button = $SortContainer/Sort_Level#等级
|
||||
|
||||
#预添加常用的面板
|
||||
@onready var main_game = get_node("/root/main")
|
||||
|
||||
@onready var lucky_draw_panel: LuckyDrawPanel = $'../LuckyDrawPanel'
|
||||
@onready var daily_check_in_panel: DailyCheckInPanel = $'../DailyCheckInPanel'
|
||||
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
|
||||
@onready var item_store_panel: Panel = $'../ItemStorePanel'
|
||||
@onready var item_bag_panel: Panel = $'../ItemBagPanel'
|
||||
@onready var player_bag_panel: Panel = $'../PlayerBagPanel'
|
||||
@onready var crop_warehouse_panel: Panel = $'../CropWarehousePanel'
|
||||
@onready var player_ranking_panel: Panel = $'../PlayerRankingPanel'
|
||||
@onready var login_panel: PanelContainer = $'../LoginPanel'
|
||||
@onready var batch_buy_popup: PanelContainer = $'../../DiaLog/BatchBuyPopup'
|
||||
|
||||
|
||||
|
||||
# 作物图片缓存(复用主游戏的缓存系统)
|
||||
var crop_textures_cache : Dictionary = {}
|
||||
var crop_frame_counts : Dictionary = {}
|
||||
|
||||
# 当前过滤和排序设置
|
||||
var current_filter_quality = ""
|
||||
var current_sort_key = ""
|
||||
var current_sort_ascending = true
|
||||
|
||||
# 库存系统
|
||||
var crop_stock_data : Dictionary = {} # 存储每个作物的库存数量
|
||||
var stock_file_path : String = "" # 库存数据文件路径(根据用户名动态设置)
|
||||
var last_refresh_date : String = "" # 上次刷新库存的日期
|
||||
|
||||
# 准备函数
|
||||
func _ready():
|
||||
# 连接按钮信号
|
||||
_connect_buttons()
|
||||
|
||||
# 连接可见性改变信号
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 初始化库存系统
|
||||
_init_stock_system()
|
||||
|
||||
# 隐藏面板(初始默认隐藏)
|
||||
self.hide()
|
||||
|
||||
|
||||
|
||||
# 连接所有按钮信号
|
||||
func _connect_buttons():
|
||||
# 关闭按钮
|
||||
quit_button.pressed.connect(self._on_quit_button_pressed)
|
||||
# 刷新按钮
|
||||
refresh_button.pressed.connect(self._on_refresh_button_pressed)
|
||||
|
||||
# 过滤按钮
|
||||
sort_all_button.pressed.connect(func(): _filter_by_quality(""))
|
||||
sort_common_button.pressed.connect(func(): _filter_by_quality("普通"))
|
||||
sort_superior_button.pressed.connect(func(): _filter_by_quality("优良"))
|
||||
sort_rare_button.pressed.connect(func(): _filter_by_quality("稀有"))
|
||||
sort_epic_button.pressed.connect(func(): _filter_by_quality("史诗"))
|
||||
sort_legendary_button.pressed.connect(func(): _filter_by_quality("传奇"))
|
||||
|
||||
# 排序按钮
|
||||
sort_price_button.pressed.connect(func(): _sort_by("花费"))
|
||||
sort_growtime_button.pressed.connect(func(): _sort_by("生长时间"))
|
||||
sort_profit_button.pressed.connect(func(): _sort_by("收益"))
|
||||
sort_level_button.pressed.connect(func(): _sort_by("等级"))
|
||||
|
||||
# 初始化商店
|
||||
func init_store():
|
||||
|
||||
# 重新初始化库存系统(确保用户名正确)
|
||||
_init_stock_system()
|
||||
|
||||
# 清空已有的作物按钮
|
||||
for child in crop_grid_container.get_children():
|
||||
child.queue_free()
|
||||
|
||||
# 检查并刷新库存(如果需要)
|
||||
_check_daily_refresh()
|
||||
|
||||
# 获取玩家当前等级,确定可解锁的格子数量
|
||||
var player_level = main_game.level
|
||||
var max_unlocked_slots = player_level # 玩家等级 = 可解锁的格子数量
|
||||
|
||||
# 收集符合条件的作物
|
||||
var available_crops = []
|
||||
for crop_name in main_game.can_planted_crop:
|
||||
var crop = main_game.can_planted_crop[crop_name]
|
||||
|
||||
# 检查是否可以购买
|
||||
if not crop.get("能否购买", true):
|
||||
continue
|
||||
|
||||
# 只显示当前等级可以种植的作物
|
||||
if crop["等级"] <= main_game.level:
|
||||
available_crops.append({"name": crop_name, "data": crop})
|
||||
|
||||
# 根据等级限制显示的格子数量
|
||||
var slots_to_show = min(available_crops.size(), max_unlocked_slots)
|
||||
|
||||
# 添加可显示的作物按钮
|
||||
for i in range(slots_to_show):
|
||||
var crop_info = available_crops[i]
|
||||
var store_btn = _create_store_button(crop_info["name"], crop_info["data"]["品质"])
|
||||
crop_grid_container.add_child(store_btn)
|
||||
|
||||
# 添加锁定的格子(如果有剩余的可用作物但等级不够解锁)
|
||||
var remaining_crops = available_crops.size() - slots_to_show
|
||||
if remaining_crops > 0:
|
||||
# 创建锁定格子提示
|
||||
var locked_slots = min(remaining_crops, 5) # 最多显示5个锁定格子作为提示
|
||||
for i in range(locked_slots):
|
||||
var locked_btn = _create_locked_slot_button(player_level + 1)
|
||||
crop_grid_container.add_child(locked_btn)
|
||||
|
||||
print("商店初始化完成,玩家等级: ", player_level, ", 解锁格子: ", slots_to_show, ", 可用作物: ", available_crops.size())
|
||||
|
||||
# 更新金钱显示
|
||||
_update_money_display()
|
||||
|
||||
# 显示等级限制提示
|
||||
_show_level_restriction_info(player_level, available_crops.size(), slots_to_show)
|
||||
|
||||
# 创建商店按钮
|
||||
func _create_store_button(crop_name: String, crop_quality: String) -> Button:
|
||||
# 根据品质选择相应的按钮
|
||||
var button = main_game.item_button.duplicate()
|
||||
|
||||
var crop = main_game.can_planted_crop[crop_name]
|
||||
|
||||
# 获取当前库存
|
||||
var current_stock = _get_crop_stock(crop_name)
|
||||
var is_sold_out = current_stock <= 0
|
||||
|
||||
# 设置按钮状态
|
||||
button.visible = true
|
||||
button.disabled = is_sold_out
|
||||
button.focus_mode = Control.FOCUS_ALL
|
||||
|
||||
# 设置按钮文本,显示价格和库存
|
||||
var display_name = crop.get("作物名称", crop_name)
|
||||
var stock_text = "库存: " + str(current_stock) if not is_sold_out else "已售罄"
|
||||
var price_text = "价格: ¥" + str(crop["花费"])
|
||||
|
||||
if is_sold_out:
|
||||
button.text = str(crop_quality + "-" + display_name + "\n" + price_text + "\n" + stock_text)
|
||||
button.modulate = Color(0.6, 0.6, 0.6, 0.8) # 灰色半透明效果
|
||||
else:
|
||||
button.text = str(crop_quality + "-" + display_name + "\n" + price_text + "\n" + stock_text)
|
||||
button.modulate = Color.WHITE # 正常颜色
|
||||
|
||||
# 将成熟时间从秒转换为天时分秒格式
|
||||
var total_seconds = int(crop["生长时间"])
|
||||
|
||||
# 定义时间单位换算
|
||||
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
|
||||
|
||||
# 构建时间字符串(只显示有值的单位)
|
||||
var time_str = ""
|
||||
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) + "秒"
|
||||
|
||||
# 添加库存信息到tooltip
|
||||
var stock_tooltip = "\n库存: " + str(current_stock) + " 个" if not is_sold_out else "\n状态: 已售罄"
|
||||
|
||||
button.tooltip_text = str(
|
||||
"作物: " + display_name + "\n" +
|
||||
"品质: " + crop_quality + "\n" +
|
||||
"价格: " + str(crop["花费"]) + "元\n" +
|
||||
"成熟时间: " + time_str + "\n" +
|
||||
"收获收益: " + str(crop["收益"]) + "元\n" +
|
||||
"需求等级: " + str(crop["等级"]) + "\n" +
|
||||
"耐候性: " + str(crop["耐候性"]) + "\n" +
|
||||
"经验: " + str(crop["经验"]) + "点" + stock_tooltip + "\n" +
|
||||
"描述: " + str(crop["描述"])
|
||||
)
|
||||
|
||||
# 添加按钮事件
|
||||
button.pressed.connect(func(): _on_store_buy_pressed(crop_name))
|
||||
|
||||
# 更新按钮的作物图片
|
||||
_update_button_crop_image(button, crop_name)
|
||||
|
||||
# 如果按钮有标题标签,设置标题
|
||||
if button.has_node("Title"):
|
||||
match crop_quality:
|
||||
"普通":
|
||||
button.get_node("Title").modulate = Color.HONEYDEW#白色
|
||||
"优良":
|
||||
button.get_node("Title").modulate =Color.DODGER_BLUE#深蓝色
|
||||
"稀有":
|
||||
button.get_node("Title").modulate =Color.HOT_PINK#品红色
|
||||
"史诗":
|
||||
button.get_node("Title").modulate =Color.YELLOW#黄色
|
||||
"传奇":
|
||||
button.get_node("Title").modulate =Color.ORANGE_RED#红色
|
||||
|
||||
return button
|
||||
|
||||
# 购买种子事件处理
|
||||
func _on_store_buy_pressed(crop_name: String):
|
||||
var crop = main_game.can_planted_crop[crop_name]
|
||||
|
||||
# 检查库存
|
||||
if not _is_crop_in_stock(crop_name):
|
||||
Toast.show("该种子已售罄,请等待明日刷新", Color.RED)
|
||||
return
|
||||
|
||||
# 检查等级要求
|
||||
if main_game.level < crop["等级"]:
|
||||
Toast.show("等级不足,无法购买此种子", Color.RED)
|
||||
return
|
||||
|
||||
# 检查金钱是否足够(至少能买1个)
|
||||
if main_game.money < crop["花费"]:
|
||||
Toast.show("金钱不足,无法购买种子", Color.RED)
|
||||
return
|
||||
|
||||
# 显示批量购买弹窗
|
||||
if batch_buy_popup:
|
||||
var crop_desc = crop.get("描述", "暂无描述")
|
||||
var max_stock = _get_crop_stock(crop_name)
|
||||
batch_buy_popup.show_buy_popup(
|
||||
crop_name,
|
||||
crop["花费"],
|
||||
crop_desc,
|
||||
"seed",
|
||||
_on_confirm_buy_seed,
|
||||
_on_cancel_buy_seed,
|
||||
max_stock # 传递最大库存限制
|
||||
)
|
||||
else:
|
||||
print("批量购买弹窗未找到")
|
||||
|
||||
# 确认购买种子回调
|
||||
func _on_confirm_buy_seed(crop_name: String, unit_cost: int, quantity: int, buy_type: String):
|
||||
var total_cost = unit_cost * quantity
|
||||
|
||||
# 再次检查库存是否足够
|
||||
var current_stock = _get_crop_stock(crop_name)
|
||||
if current_stock < quantity:
|
||||
Toast.show("库存不足!当前库存: " + str(current_stock) + ",需要: " + str(quantity), Color.RED, 3.0, 1.0)
|
||||
return
|
||||
|
||||
# 再次检查金钱是否足够
|
||||
if main_game.money < total_cost:
|
||||
Toast.show("金钱不足!需要 " + str(total_cost) + " 元,当前只有 " + str(main_game.money) + " 元", Color.RED, 3.0, 1.0)
|
||||
return
|
||||
|
||||
# 发送批量购买请求到服务器
|
||||
_send_batch_buy_seed_request(crop_name, quantity)
|
||||
|
||||
# 取消购买种子回调
|
||||
func _on_cancel_buy_seed():
|
||||
print("取消购买种子")
|
||||
|
||||
# 发送批量购买种子请求
|
||||
func _send_batch_buy_seed_request(crop_name: String, quantity: int):
|
||||
# 发送批量购买请求到服务器
|
||||
if tcp_network_manager_panel and tcp_network_manager_panel.sendBuySeed(crop_name, quantity):
|
||||
# 服务器会处理批量购买逻辑,客户端等待响应
|
||||
print("已发送批量购买种子请求:", crop_name, " 数量:", quantity)
|
||||
|
||||
# 购买成功后扣减库存
|
||||
if _reduce_crop_stock(crop_name, quantity):
|
||||
print("库存扣减成功:", crop_name, " 扣减数量:", quantity)
|
||||
# 刷新商店显示
|
||||
_apply_filter_and_sort()
|
||||
Toast.show("购买成功!剩余库存: " + str(_get_crop_stock(crop_name)), Color.GREEN, 2.0, 1.0)
|
||||
else:
|
||||
Toast.show("库存扣减失败", Color.RED, 2.0, 1.0)
|
||||
else:
|
||||
Toast.show("购买请求发送失败", Color.RED, 2.0, 1.0)
|
||||
|
||||
|
||||
# 按品质过滤作物
|
||||
func _filter_by_quality(quality: String):
|
||||
current_filter_quality = quality
|
||||
_apply_filter_and_sort()
|
||||
|
||||
# 按指定键排序
|
||||
func _sort_by(sort_key: String):
|
||||
# 切换排序方向或设置新排序键
|
||||
if current_sort_key == sort_key:
|
||||
current_sort_ascending = !current_sort_ascending
|
||||
else:
|
||||
current_sort_key = sort_key
|
||||
current_sort_ascending = true
|
||||
|
||||
_apply_filter_and_sort()
|
||||
|
||||
# 应用过滤和排序
|
||||
func _apply_filter_and_sort():
|
||||
# 清空现有按钮
|
||||
for child in crop_grid_container.get_children():
|
||||
child.queue_free()
|
||||
|
||||
# 获取玩家当前等级,确定可解锁的格子数量
|
||||
var player_level = main_game.level
|
||||
var max_unlocked_slots = player_level
|
||||
|
||||
# 收集符合条件的作物
|
||||
var filtered_crops = []
|
||||
for crop_name in main_game.can_planted_crop:
|
||||
var crop = main_game.can_planted_crop[crop_name]
|
||||
|
||||
# 检查是否可以购买
|
||||
if not crop.get("能否购买", true):
|
||||
continue
|
||||
|
||||
# 检查等级和品质过滤
|
||||
if crop["等级"] > main_game.level:
|
||||
continue
|
||||
|
||||
if current_filter_quality != "" and crop["品质"] != current_filter_quality:
|
||||
continue
|
||||
|
||||
# 添加到过滤后的列表
|
||||
filtered_crops.append({
|
||||
"name": crop_name,
|
||||
"data": crop
|
||||
})
|
||||
|
||||
# 如果有排序条件,进行排序
|
||||
if current_sort_key != "":
|
||||
filtered_crops.sort_custom(Callable(self, "_sort_crop_items"))
|
||||
|
||||
# 根据等级限制显示的格子数量
|
||||
var slots_to_show = min(filtered_crops.size(), max_unlocked_slots)
|
||||
|
||||
# 添加可显示的作物按钮
|
||||
for i in range(slots_to_show):
|
||||
var crop = filtered_crops[i]
|
||||
var store_btn = _create_store_button(crop["name"], crop["data"]["品质"])
|
||||
crop_grid_container.add_child(store_btn)
|
||||
|
||||
# 添加锁定的格子(如果有剩余的可用作物但等级不够解锁)
|
||||
var remaining_crops = filtered_crops.size() - slots_to_show
|
||||
if remaining_crops > 0:
|
||||
# 创建锁定格子提示
|
||||
var locked_slots = min(remaining_crops, 5) # 最多显示5个锁定格子作为提示
|
||||
for i in range(locked_slots):
|
||||
var locked_btn = _create_locked_slot_button(player_level + 1)
|
||||
crop_grid_container.add_child(locked_btn)
|
||||
|
||||
# 更新金钱显示
|
||||
_update_money_display()
|
||||
|
||||
# 显示等级限制提示
|
||||
_show_level_restriction_info(player_level, filtered_crops.size(), slots_to_show)
|
||||
|
||||
# 自定义排序函数
|
||||
func _sort_crop_items(a, b):
|
||||
# 安全地获取排序值,并进行类型转换
|
||||
var value_a = a["data"].get(current_sort_key, 0)
|
||||
var value_b = b["data"].get(current_sort_key, 0)
|
||||
|
||||
# 如果是数值类型的字段,确保转换为数值进行比较
|
||||
if current_sort_key in ["花费", "生长时间", "收益", "等级", "经验", "耐候性"]:
|
||||
# 转换为数值,如果转换失败则使用0
|
||||
if typeof(value_a) == TYPE_STRING:
|
||||
value_a = int(value_a) if value_a.is_valid_int() else 0
|
||||
if typeof(value_b) == TYPE_STRING:
|
||||
value_b = int(value_b) if value_b.is_valid_int() else 0
|
||||
|
||||
# 执行排序比较
|
||||
if current_sort_ascending:
|
||||
return value_a < value_b
|
||||
else:
|
||||
return value_a > value_b
|
||||
|
||||
# 更新金钱显示
|
||||
func _update_money_display():
|
||||
var money_label = get_node_or_null("MoneyLabel")
|
||||
if money_label == null:
|
||||
# 创建金钱显示标签
|
||||
money_label = Label.new()
|
||||
money_label.name = "MoneyLabel"
|
||||
money_label.position = Vector2(10, 10)
|
||||
money_label.size = Vector2(300, 45)
|
||||
|
||||
# 设置标签样式
|
||||
money_label.add_theme_color_override("font_color", Color(1, 0.647, 0, 1)) # 橙色
|
||||
money_label.add_theme_font_size_override("font_size", 24)
|
||||
|
||||
add_child(money_label)
|
||||
|
||||
# 更新金钱显示
|
||||
money_label.text = "当前金钱:" + str(main_game.money) + " 元"
|
||||
|
||||
# 刷新商店内容,可以在金钱变化或等级提升后调用
|
||||
func refresh_store():
|
||||
# 清空并重新创建商店按钮
|
||||
init_store()
|
||||
# 尝试创建过滤按钮(如果商店面板中没有这些按钮)
|
||||
_create_filter_buttons_if_needed()
|
||||
|
||||
# 如果需要,动态创建过滤按钮
|
||||
func _create_filter_buttons_if_needed():
|
||||
# 检查是否已存在过滤器容器
|
||||
var filter_container = get_node_or_null("FilterContainer")
|
||||
if filter_container == null:
|
||||
# 创建过滤器容器
|
||||
filter_container = HBoxContainer.new()
|
||||
filter_container.name = "FilterContainer"
|
||||
|
||||
# 设置容器位置和大小
|
||||
filter_container.position = Vector2(320, 10)
|
||||
filter_container.size = Vector2(770, 45)
|
||||
|
||||
add_child(filter_container)
|
||||
|
||||
# 添加过滤按钮
|
||||
_add_filter_button(filter_container, "全部", func(): _filter_by_quality(""))
|
||||
_add_filter_button(filter_container, "普通", func(): _filter_by_quality("普通"))
|
||||
_add_filter_button(filter_container, "优良", func(): _filter_by_quality("优良"))
|
||||
_add_filter_button(filter_container, "稀有", func(): _filter_by_quality("稀有"))
|
||||
_add_filter_button(filter_container, "史诗", func(): _filter_by_quality("史诗"))
|
||||
_add_filter_button(filter_container, "传奇", func(): _filter_by_quality("传奇"))
|
||||
|
||||
# 检查是否已存在排序容器
|
||||
var sort_container = get_node_or_null("SortContainer")
|
||||
if sort_container == null:
|
||||
# 创建排序容器
|
||||
sort_container = HBoxContainer.new()
|
||||
sort_container.name = "SortContainer"
|
||||
|
||||
# 设置容器位置和大小
|
||||
sort_container.position = Vector2(320, 55)
|
||||
sort_container.size = Vector2(770, 30)
|
||||
|
||||
add_child(sort_container)
|
||||
|
||||
# 添加排序按钮
|
||||
_add_filter_button(sort_container, "按价格", func(): _sort_by("花费"))
|
||||
_add_filter_button(sort_container, "按生长时间", func(): _sort_by("生长时间"))
|
||||
_add_filter_button(sort_container, "按收益", func(): _sort_by("收益"))
|
||||
_add_filter_button(sort_container, "按等级", func(): _sort_by("等级"))
|
||||
|
||||
# 添加过滤按钮
|
||||
func _add_filter_button(container, text, callback):
|
||||
var button = Button.new()
|
||||
button.text = text
|
||||
button.custom_minimum_size = Vector2(100, 0)
|
||||
button.size_flags_horizontal = Control.SIZE_EXPAND_FILL
|
||||
container.add_child(button)
|
||||
button.pressed.connect(callback)
|
||||
|
||||
# 获取作物的成熟图片(用于商店显示)
|
||||
func _get_crop_final_texture(crop_name: String) -> Texture2D:
|
||||
# 优先从主游戏的缓存中获取成熟图片
|
||||
if main_game and main_game.crop_mature_textures_cache.has(crop_name):
|
||||
return main_game.crop_mature_textures_cache[crop_name]
|
||||
|
||||
# 如果缓存中没有,再尝试加载"成熟.webp"图片
|
||||
var crop_path = "res://assets/作物/" + crop_name + "/"
|
||||
var mature_texture_path = crop_path + "成熟.webp"
|
||||
|
||||
if ResourceLoader.exists(mature_texture_path):
|
||||
var texture = load(mature_texture_path)
|
||||
if texture:
|
||||
print("商店加载作物成熟图片:", crop_name)
|
||||
# 如果主游戏存在,也缓存到主游戏中
|
||||
if main_game:
|
||||
main_game.crop_mature_textures_cache[crop_name] = texture
|
||||
return texture
|
||||
|
||||
# 如果没有找到作物的成熟图片,使用默认的成熟图片
|
||||
if main_game and main_game.crop_mature_textures_cache.has("默认"):
|
||||
var default_texture = main_game.crop_mature_textures_cache["默认"]
|
||||
# 缓存给这个作物
|
||||
main_game.crop_mature_textures_cache[crop_name] = default_texture
|
||||
return default_texture
|
||||
|
||||
# 最后尝试直接加载默认成熟图片
|
||||
var default_mature_path = "res://assets/作物/默认/成熟.webp"
|
||||
if ResourceLoader.exists(default_mature_path):
|
||||
var texture = load(default_mature_path)
|
||||
if texture:
|
||||
print("商店使用默认成熟图片:", crop_name)
|
||||
# 缓存到主游戏
|
||||
if main_game:
|
||||
main_game.crop_mature_textures_cache["默认"] = texture
|
||||
main_game.crop_mature_textures_cache[crop_name] = texture
|
||||
return texture
|
||||
|
||||
return null
|
||||
|
||||
# 加载作物图片序列帧(复用主游戏的逻辑)
|
||||
func _load_crop_textures(crop_name: String) -> Array:
|
||||
if crop_textures_cache.has(crop_name):
|
||||
return crop_textures_cache[crop_name]
|
||||
|
||||
var textures = []
|
||||
var crop_path = "res://assets/作物/" + crop_name + "/"
|
||||
var default_path = "res://assets/作物/默认/"
|
||||
|
||||
# 检查作物文件夹是否存在
|
||||
if DirAccess.dir_exists_absolute(crop_path):
|
||||
# 尝试加载作物的序列帧(从0开始)
|
||||
var frame_index = 0
|
||||
while true:
|
||||
var texture_path = crop_path + str(frame_index) + ".webp"
|
||||
if ResourceLoader.exists(texture_path):
|
||||
var texture = load(texture_path)
|
||||
if texture:
|
||||
textures.append(texture)
|
||||
frame_index += 1
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
if textures.size() > 0:
|
||||
pass
|
||||
else:
|
||||
textures = _load_default_textures()
|
||||
else:
|
||||
print("商店:作物 ", crop_name, " 的文件夹不存在,使用默认图片")
|
||||
textures = _load_default_textures()
|
||||
|
||||
# 缓存结果
|
||||
crop_textures_cache[crop_name] = textures
|
||||
crop_frame_counts[crop_name] = textures.size()
|
||||
|
||||
return textures
|
||||
|
||||
# 加载默认图片
|
||||
func _load_default_textures() -> Array:
|
||||
if crop_textures_cache.has("默认"):
|
||||
return crop_textures_cache["默认"]
|
||||
|
||||
var textures = []
|
||||
var default_path = "res://assets/作物/默认/"
|
||||
|
||||
# 尝试加载默认图片序列帧
|
||||
var frame_index = 0
|
||||
while true:
|
||||
var texture_path = default_path + str(frame_index) + ".webp"
|
||||
if ResourceLoader.exists(texture_path):
|
||||
var texture = load(texture_path)
|
||||
if texture:
|
||||
textures.append(texture)
|
||||
frame_index += 1
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
# 如果没有找到序列帧,尝试加载单个默认图片
|
||||
if textures.size() == 0:
|
||||
var single_texture_path = default_path + "0.webp"
|
||||
if ResourceLoader.exists(single_texture_path):
|
||||
var texture = load(single_texture_path)
|
||||
if texture:
|
||||
textures.append(texture)
|
||||
|
||||
# 缓存默认图片
|
||||
crop_textures_cache["默认"] = textures
|
||||
crop_frame_counts["默认"] = textures.size()
|
||||
|
||||
return textures
|
||||
|
||||
# 更新按钮的作物图片
|
||||
func _update_button_crop_image(button: Button, crop_name: String):
|
||||
# 检查按钮是否有CropImage节点
|
||||
var crop_image = button.get_node_or_null("CropImage")
|
||||
if not crop_image:
|
||||
print("商店按钮没有找到CropImage节点:", button.name)
|
||||
return
|
||||
|
||||
# 获取作物的最后一帧图片
|
||||
var texture = _get_crop_final_texture(crop_name)
|
||||
|
||||
if texture:
|
||||
# CropImage是Sprite2D,直接设置texture属性
|
||||
crop_image.texture = texture
|
||||
crop_image.visible = true
|
||||
print("商店更新作物图片:", crop_name)
|
||||
else:
|
||||
crop_image.visible = false
|
||||
print("商店无法获取作物图片:", crop_name)
|
||||
|
||||
# 兼容MainGame.gd中的调用,转发到_on_store_buy_pressed
|
||||
func _on_crop_selected(crop_name: String):
|
||||
_on_store_buy_pressed(crop_name)
|
||||
|
||||
#=========================库存系统=========================
|
||||
|
||||
# 初始化库存系统
|
||||
func _init_stock_system():
|
||||
# 根据用户名设置库存文件路径,实现账号隔离
|
||||
var user_name = main_game.user_name if main_game.user_name != "" else "default_user"
|
||||
stock_file_path = "user://crop_stock_" + user_name + ".json"
|
||||
print("库存系统初始化,用户:", user_name, ",文件路径:", stock_file_path)
|
||||
|
||||
_load_stock_data()
|
||||
_check_daily_refresh()
|
||||
|
||||
# 加载库存数据
|
||||
func _load_stock_data():
|
||||
print("尝试加载库存数据,文件路径:", stock_file_path)
|
||||
|
||||
if FileAccess.file_exists(stock_file_path):
|
||||
var file = FileAccess.open(stock_file_path, FileAccess.READ)
|
||||
if file:
|
||||
var json_string = file.get_as_text()
|
||||
file.close()
|
||||
print("读取到的JSON数据:", json_string)
|
||||
|
||||
var json = JSON.new()
|
||||
var parse_result = json.parse(json_string)
|
||||
if parse_result == OK:
|
||||
var data = json.data
|
||||
crop_stock_data = data.get("stock", {})
|
||||
last_refresh_date = data.get("last_refresh_date", "")
|
||||
print("库存数据加载成功,库存条目数:", crop_stock_data.size())
|
||||
print("加载的库存数据:", crop_stock_data)
|
||||
print("上次刷新日期:", last_refresh_date)
|
||||
|
||||
# 如果库存数据为空,重新生成
|
||||
if crop_stock_data.is_empty():
|
||||
print("库存数据为空,重新生成")
|
||||
_generate_initial_stock()
|
||||
else:
|
||||
print("库存数据解析失败,错误:", parse_result, ",重新生成")
|
||||
_generate_initial_stock()
|
||||
else:
|
||||
print("无法打开库存文件,重新生成")
|
||||
_generate_initial_stock()
|
||||
else:
|
||||
print("库存文件不存在,生成初始库存")
|
||||
_generate_initial_stock()
|
||||
|
||||
# 保存库存数据
|
||||
func _save_stock_data():
|
||||
var data = {
|
||||
"stock": crop_stock_data,
|
||||
"last_refresh_date": last_refresh_date
|
||||
}
|
||||
|
||||
print("准备保存库存数据到:", stock_file_path)
|
||||
print("保存的数据:", data)
|
||||
|
||||
var file = FileAccess.open(stock_file_path, FileAccess.WRITE)
|
||||
if file:
|
||||
var json_string = JSON.stringify(data)
|
||||
file.store_string(json_string)
|
||||
file.close()
|
||||
print("库存数据保存成功,JSON字符串:", json_string)
|
||||
else:
|
||||
print("无法保存库存数据,文件打开失败")
|
||||
|
||||
# 生成初始库存
|
||||
func _generate_initial_stock():
|
||||
crop_stock_data.clear()
|
||||
|
||||
# 确保main_game和can_planted_crop存在
|
||||
if not main_game or not main_game.can_planted_crop:
|
||||
print("错误:无法访问主游戏数据,无法生成库存")
|
||||
return
|
||||
|
||||
var generated_count = 0
|
||||
for crop_name in main_game.can_planted_crop:
|
||||
var crop = main_game.can_planted_crop[crop_name]
|
||||
|
||||
# 检查是否可以购买
|
||||
if not crop.get("能否购买", true):
|
||||
continue
|
||||
|
||||
# 根据品质设置库存范围
|
||||
var stock_amount = _get_stock_amount_by_quality(crop["品质"])
|
||||
crop_stock_data[crop_name] = stock_amount
|
||||
generated_count += 1
|
||||
print("生成库存:", crop_name, " - ", crop["品质"], " - ", stock_amount, "个")
|
||||
|
||||
# 设置当前日期为刷新日期
|
||||
last_refresh_date = _get_current_date()
|
||||
_save_stock_data()
|
||||
print("初始库存生成完成,共生成", generated_count, "种作物的库存")
|
||||
print("当前库存数据:", crop_stock_data)
|
||||
|
||||
# 根据品质获取库存数量
|
||||
func _get_stock_amount_by_quality(quality: String) -> int:
|
||||
var min_stock: int
|
||||
var max_stock: int
|
||||
|
||||
match quality:
|
||||
"传奇":
|
||||
min_stock = 10
|
||||
max_stock = 30
|
||||
"史诗":
|
||||
min_stock = 20
|
||||
max_stock = 50
|
||||
"稀有":
|
||||
min_stock = 40
|
||||
max_stock = 80
|
||||
"优良":
|
||||
min_stock = 80
|
||||
max_stock = 150
|
||||
"普通":
|
||||
min_stock = 150
|
||||
max_stock = 300
|
||||
_:
|
||||
min_stock = 100
|
||||
max_stock = 200
|
||||
|
||||
return randi_range(min_stock, max_stock)
|
||||
|
||||
# 获取当前日期字符串
|
||||
func _get_current_date() -> String:
|
||||
var datetime = Time.get_datetime_dict_from_system()
|
||||
return str(datetime.year) + "-" + str(datetime.month).pad_zeros(2) + "-" + str(datetime.day).pad_zeros(2)
|
||||
|
||||
# 检查是否需要每日刷新
|
||||
func _check_daily_refresh():
|
||||
var current_date = _get_current_date()
|
||||
if last_refresh_date != current_date:
|
||||
print("检测到新的一天,刷新库存")
|
||||
_refresh_daily_stock()
|
||||
|
||||
# 每日刷新库存
|
||||
func _refresh_daily_stock():
|
||||
_generate_initial_stock()
|
||||
Toast.show("种子商店库存已刷新!", Color.GREEN, 3.0, 1.0)
|
||||
|
||||
# 获取作物当前库存
|
||||
func _get_crop_stock(crop_name: String) -> int:
|
||||
return crop_stock_data.get(crop_name, 0)
|
||||
|
||||
# 减少作物库存
|
||||
func _reduce_crop_stock(crop_name: String, amount: int) -> bool:
|
||||
var current_stock = _get_crop_stock(crop_name)
|
||||
if current_stock >= amount:
|
||||
crop_stock_data[crop_name] = current_stock - amount
|
||||
_save_stock_data()
|
||||
return true
|
||||
return false
|
||||
|
||||
# 检查作物是否有库存
|
||||
func _is_crop_in_stock(crop_name: String) -> bool:
|
||||
return _get_crop_stock(crop_name) > 0
|
||||
|
||||
|
||||
# 创建锁定格子按钮
|
||||
func _create_locked_slot_button(required_level: int) -> Button:
|
||||
var button = main_game.item_button.duplicate()
|
||||
|
||||
# 设置按钮为禁用状态
|
||||
button.disabled = true
|
||||
button.modulate = Color(0.5, 0.5, 0.5, 0.8) # 灰色半透明效果
|
||||
|
||||
# 设置按钮文本
|
||||
button.text = "🔒 锁定\n需要等级: " + str(required_level)
|
||||
button.tooltip_text = "此格子已锁定,需要达到等级 " + str(required_level) + " 才能解锁"
|
||||
|
||||
# 隐藏作物图片
|
||||
var crop_image = button.get_node_or_null("CropImage")
|
||||
if crop_image:
|
||||
crop_image.visible = false
|
||||
|
||||
# 设置标题颜色为灰色
|
||||
if button.has_node("Title"):
|
||||
button.get_node("Title").modulate = Color.GRAY
|
||||
|
||||
return button
|
||||
|
||||
# 显示等级限制信息
|
||||
func _show_level_restriction_info(player_level: int, total_crops: int, unlocked_slots: int):
|
||||
# 查找或创建信息标签
|
||||
var info_label = get_node_or_null("LevelInfoLabel")
|
||||
if info_label == null:
|
||||
info_label = Label.new()
|
||||
info_label.name = "LevelInfoLabel"
|
||||
info_label.position = Vector2(10, 55)
|
||||
info_label.size = Vector2(300, 30)
|
||||
|
||||
# 设置标签样式
|
||||
info_label.add_theme_color_override("font_color", Color(0.8, 0.8, 1.0, 1.0)) # 淡蓝色
|
||||
info_label.add_theme_font_size_override("font_size", 18)
|
||||
|
||||
add_child(info_label)
|
||||
|
||||
# 更新信息显示
|
||||
var locked_crops = total_crops - unlocked_slots
|
||||
if locked_crops > 0:
|
||||
info_label.text = "等级 " + str(player_level) + " | 已解锁: " + str(unlocked_slots) + "/" + str(total_crops) + " 个格子"
|
||||
info_label.modulate = Color.YELLOW
|
||||
else:
|
||||
info_label.text = "等级 " + str(player_level) + " | 所有格子已解锁 (" + str(unlocked_slots) + "/" + str(total_crops) + ")"
|
||||
info_label.modulate = Color.GREEN
|
||||
|
||||
|
||||
#=========================面板通用处理=========================
|
||||
#手动刷新种子商店面板
|
||||
func _on_refresh_button_pressed() -> void:
|
||||
# 重新初始化种子商店
|
||||
init_store()
|
||||
Toast.show("种子商店已刷新", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
#关闭种子商店面板
|
||||
func _on_quit_button_pressed():
|
||||
self.hide()
|
||||
|
||||
# 面板显示时的处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
# 面板显示时自动刷新数据
|
||||
init_store()
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
pass
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
pass
|
||||
#=========================面板通用处理=========================
|
||||
@@ -0,0 +1 @@
|
||||
uid://mtfp0ct42nrx
|
||||
594
SproutFarm-Frontend/Script/BigPanel/CropWarehousePanel.gd
Normal file
594
SproutFarm-Frontend/Script/BigPanel/CropWarehousePanel.gd
Normal file
@@ -0,0 +1,594 @@
|
||||
extends Panel
|
||||
#这是作物仓库面板 用来显示玩家收获的作物的成熟品 比如各种果实和花朵
|
||||
|
||||
# 作物仓库格子容器
|
||||
@onready var crop_warehouse_grid_container : GridContainer = $ScrollContainer/Warehouse_Grid
|
||||
@onready var quit_button : Button = $QuitButton
|
||||
@onready var refresh_button : Button = $RefreshButton
|
||||
|
||||
#各种排序过滤按钮
|
||||
@onready var sort_all_button : Button = $SortContainer/Sort_All#全部
|
||||
@onready var sort_common_button : Button = $SortContainer/Sort_Common#普通
|
||||
@onready var sort_superior_button : Button = $SortContainer/Sort_Superior#优良
|
||||
@onready var sort_rare_button : Button = $SortContainer/Sort_Rare#稀有
|
||||
@onready var sort_epic_button : Button = $SortContainer/Sort_Epic#史诗
|
||||
@onready var sort_legendary_button : Button = $SortContainer/Sort_Legendary#传奇
|
||||
@onready var sort_price_button : Button = $SortContainer/Sort_Price#价格
|
||||
@onready var sort_growtime_button : Button = $SortContainer/Sort_GrowTime#生长时间
|
||||
@onready var sort_profit_button : Button = $SortContainer/Sort_Profit#收益
|
||||
@onready var sort_level_button : Button = $SortContainer/Sort_Level#等级
|
||||
|
||||
#预添加常用的面板
|
||||
@onready var main_game = get_node("/root/main")
|
||||
|
||||
@onready var lucky_draw_panel: LuckyDrawPanel = $'../LuckyDrawPanel'
|
||||
@onready var daily_check_in_panel: DailyCheckInPanel = $'../DailyCheckInPanel'
|
||||
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
|
||||
@onready var item_store_panel: Panel = $'../ItemStorePanel'
|
||||
@onready var item_bag_panel: Panel = $'../ItemBagPanel'
|
||||
@onready var player_bag_panel: Panel = $'../PlayerBagPanel'
|
||||
@onready var crop_store_panel: Panel = $'../CropStorePanel'
|
||||
@onready var player_ranking_panel: Panel = $'../PlayerRankingPanel'
|
||||
@onready var login_panel: PanelContainer = $'../LoginPanel'
|
||||
|
||||
|
||||
# 注意:作物图片现在使用主游戏的CropTextureManager缓存系统
|
||||
# 不再需要本地缓存变量
|
||||
|
||||
# 当前过滤和排序设置
|
||||
var current_filter_quality = ""
|
||||
var current_sort_key = ""
|
||||
var current_sort_ascending = true
|
||||
|
||||
# 宠物喂食模式相关变量
|
||||
var is_pet_feeding_mode = false
|
||||
var current_pet_data = {}
|
||||
|
||||
# 准备函数
|
||||
func _ready():
|
||||
# 连接按钮信号
|
||||
_connect_buttons()
|
||||
|
||||
# 连接可见性改变信号
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 隐藏面板(初始默认隐藏)
|
||||
self.hide()
|
||||
|
||||
|
||||
# 连接所有按钮信号
|
||||
func _connect_buttons():
|
||||
quit_button.pressed.connect(self._on_quit_button_pressed)
|
||||
refresh_button.pressed.connect(self._on_refresh_button_pressed)
|
||||
|
||||
# 过滤按钮
|
||||
sort_all_button.pressed.connect(func(): _filter_by_quality(""))
|
||||
sort_common_button.pressed.connect(func(): _filter_by_quality("普通"))
|
||||
sort_superior_button.pressed.connect(func(): _filter_by_quality("优良"))
|
||||
sort_rare_button.pressed.connect(func(): _filter_by_quality("稀有"))
|
||||
sort_epic_button.pressed.connect(func(): _filter_by_quality("史诗"))
|
||||
sort_legendary_button.pressed.connect(func(): _filter_by_quality("传奇"))
|
||||
|
||||
# 排序按钮
|
||||
sort_price_button.pressed.connect(func(): _sort_by("花费"))
|
||||
sort_growtime_button.pressed.connect(func(): _sort_by("生长时间"))
|
||||
sort_profit_button.pressed.connect(func(): _sort_by("收益"))
|
||||
sort_level_button.pressed.connect(func(): _sort_by("等级"))
|
||||
|
||||
# 设置宠物喂食模式
|
||||
func set_pet_feeding_mode(feeding_mode: bool, pet_data: Dictionary = {}):
|
||||
is_pet_feeding_mode = feeding_mode
|
||||
current_pet_data = pet_data
|
||||
|
||||
# 更新UI以反映当前模式
|
||||
if is_pet_feeding_mode:
|
||||
# 宠物喂食模式下,只显示有喂养效果的作物
|
||||
var pet_name = pet_data.get("pet_name", "未知宠物")
|
||||
Toast.show("宠物喂食模式:选择要喂给 " + pet_name + " 的作物", Color.CYAN, 3.0, 1.0)
|
||||
else:
|
||||
# 普通模式
|
||||
Toast.show("普通模式:查看作物仓库", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
# 刷新UI
|
||||
update_crop_warehouse_ui()
|
||||
|
||||
# 初始化作物仓库
|
||||
func init_crop_warehouse():
|
||||
# 清空作物仓库格子
|
||||
for child in crop_warehouse_grid_container.get_children():
|
||||
child.queue_free()
|
||||
# 显示仓库中的成熟物
|
||||
update_crop_warehouse_ui()
|
||||
|
||||
# 更新作物仓库UI
|
||||
func update_crop_warehouse_ui():
|
||||
# 清空作物仓库格子
|
||||
for child in crop_warehouse_grid_container.get_children():
|
||||
child.queue_free()
|
||||
|
||||
# 应用过滤和排序
|
||||
var filtered_crops = _get_filtered_and_sorted_crops()
|
||||
|
||||
# 为仓库中的每个过滤后的成熟物创建按钮
|
||||
for crop_item in filtered_crops:
|
||||
var crop_name = crop_item["name"]
|
||||
var crop_quality = crop_item["quality"]
|
||||
var crop_count = crop_item["count"]
|
||||
# 创建成熟物按钮
|
||||
var button = _create_crop_button(crop_name, crop_quality)
|
||||
|
||||
# 更新按钮文本显示数量
|
||||
if is_pet_feeding_mode:
|
||||
# 宠物喂食模式下显示喂养效果
|
||||
var crop_data = main_game.can_planted_crop.get(crop_name, {})
|
||||
var feed_effects = crop_data.get("喂养效果", {})
|
||||
|
||||
# 构建效果描述
|
||||
var effect_descriptions = []
|
||||
for effect_name in feed_effects:
|
||||
var effect_value = feed_effects[effect_name]
|
||||
if effect_value > 0:
|
||||
effect_descriptions.append(effect_name + "+" + str(effect_value))
|
||||
|
||||
var effect_text = " ".join(effect_descriptions) if effect_descriptions.size() > 0 else "无效果"
|
||||
var display_name = crop_name
|
||||
if main_game.can_planted_crop.has(crop_name):
|
||||
var mature_name = main_game.can_planted_crop[crop_name].get("成熟物名称")
|
||||
if mature_name != null and mature_name != "":
|
||||
display_name = mature_name
|
||||
else:
|
||||
display_name = main_game.can_planted_crop[crop_name].get("作物名称", crop_name)
|
||||
button.text = str(crop_quality + "-" + display_name + "\n数量:" + str(crop_count) )
|
||||
button.pressed.connect(func(): _on_crop_feed_selected(crop_name, crop_count))
|
||||
else:
|
||||
var display_name = crop_name
|
||||
if main_game.can_planted_crop.has(crop_name):
|
||||
var mature_name = main_game.can_planted_crop[crop_name].get("成熟物名称")
|
||||
if mature_name != null and mature_name != "":
|
||||
display_name = mature_name
|
||||
else:
|
||||
display_name = main_game.can_planted_crop[crop_name].get("作物名称", crop_name)
|
||||
button.text = str(crop_quality + "-" + display_name + "\n数量:" + str(crop_count))
|
||||
button.pressed.connect(func(): _on_crop_selected(crop_name, crop_count))
|
||||
|
||||
crop_warehouse_grid_container.add_child(button)
|
||||
print("作物仓库初始化完成,共添加按钮: " + str(crop_warehouse_grid_container.get_child_count()) + "个")
|
||||
|
||||
# 获取过滤和排序后的成熟物列表
|
||||
func _get_filtered_and_sorted_crops():
|
||||
var filtered_crops = []
|
||||
|
||||
# 收集符合条件的成熟物
|
||||
for crop_item in main_game.crop_warehouse:
|
||||
# 从crop_data中获取品质信息
|
||||
var item_quality = "普通"
|
||||
if main_game.can_planted_crop.has(crop_item["name"]):
|
||||
item_quality = main_game.can_planted_crop[crop_item["name"]].get("品质", "普通")
|
||||
|
||||
# 品质过滤
|
||||
if current_filter_quality != "" and item_quality != current_filter_quality:
|
||||
continue
|
||||
|
||||
# 获取成熟物对应的作物数据
|
||||
var crop_data = null
|
||||
if main_game.can_planted_crop.has(crop_item["name"]):
|
||||
crop_data = main_game.can_planted_crop[crop_item["name"]]
|
||||
|
||||
# 宠物喂食模式过滤:只显示有喂养效果的作物
|
||||
if is_pet_feeding_mode:
|
||||
if crop_data == null or not crop_data.has("喂养效果"):
|
||||
continue
|
||||
|
||||
# 添加到过滤后的列表
|
||||
filtered_crops.append({
|
||||
"name": crop_item["name"],
|
||||
"quality": item_quality,
|
||||
"count": crop_item["count"],
|
||||
"data": crop_data
|
||||
})
|
||||
|
||||
# 如果有排序条件且数据可用,进行排序
|
||||
if current_sort_key != "":
|
||||
filtered_crops.sort_custom(Callable(self, "_sort_crop_items"))
|
||||
|
||||
return filtered_crops
|
||||
|
||||
# 自定义排序函数
|
||||
func _sort_crop_items(a, b):
|
||||
# 检查是否有有效数据用于排序
|
||||
if a["data"] == null or b["data"] == null:
|
||||
# 如果某一项没有数据,将其排在后面
|
||||
if a["data"] == null and b["data"] != null:
|
||||
return false
|
||||
if a["data"] != null and b["data"] == null:
|
||||
return true
|
||||
# 如果都没有数据,按名称排序
|
||||
return a["name"] < b["name"]
|
||||
|
||||
# 确保排序键存在于数据中
|
||||
if !a["data"].has(current_sort_key) or !b["data"].has(current_sort_key):
|
||||
print("警告: 排序键 ", current_sort_key, " 在某些成熟物数据中不存在")
|
||||
return false
|
||||
|
||||
# 安全地获取排序值,并进行类型转换
|
||||
var value_a = a["data"].get(current_sort_key, 0)
|
||||
var value_b = b["data"].get(current_sort_key, 0)
|
||||
|
||||
# 如果是数值类型的字段,确保转换为数值进行比较
|
||||
if current_sort_key in ["花费", "生长时间", "收益", "等级", "经验", "耐候性"]:
|
||||
# 转换为数值,如果转换失败则使用0
|
||||
if typeof(value_a) == TYPE_STRING:
|
||||
value_a = int(value_a) if value_a.is_valid_int() else 0
|
||||
if typeof(value_b) == TYPE_STRING:
|
||||
value_b = int(value_b) if value_b.is_valid_int() else 0
|
||||
|
||||
# 执行排序比较
|
||||
if current_sort_ascending:
|
||||
return value_a < value_b
|
||||
else:
|
||||
return value_a > value_b
|
||||
|
||||
# 按品质过滤成熟物
|
||||
func _filter_by_quality(quality: String):
|
||||
current_filter_quality = quality
|
||||
update_crop_warehouse_ui()
|
||||
|
||||
# 按指定键排序
|
||||
func _sort_by(sort_key: String):
|
||||
# 切换排序方向或设置新排序键
|
||||
if current_sort_key == sort_key:
|
||||
current_sort_ascending = !current_sort_ascending
|
||||
else:
|
||||
current_sort_key = sort_key
|
||||
current_sort_ascending = true
|
||||
|
||||
update_crop_warehouse_ui()
|
||||
|
||||
# 创建作物按钮
|
||||
func _create_crop_button(crop_name: String, crop_quality: String) -> Button:
|
||||
# 根据品质选择相应的进度条
|
||||
var button = main_game.item_button.duplicate()
|
||||
|
||||
# 确保按钮可见并可点击
|
||||
button.visible = true
|
||||
button.disabled = false
|
||||
button.focus_mode = Control.FOCUS_ALL
|
||||
|
||||
# 设置按钮文本
|
||||
var display_name = crop_name
|
||||
if main_game.can_planted_crop.has(crop_name):
|
||||
var mature_name = main_game.can_planted_crop[crop_name].get("成熟物名称")
|
||||
if mature_name != null and mature_name != "":
|
||||
display_name = mature_name
|
||||
else:
|
||||
display_name = main_game.can_planted_crop[crop_name].get("作物名称", crop_name)
|
||||
button.text = str(crop_quality + "-" + display_name)
|
||||
|
||||
# 添加工具提示 (tooltip)
|
||||
if main_game.can_planted_crop.has(crop_name):
|
||||
var crop = main_game.can_planted_crop[crop_name]
|
||||
|
||||
# 将成熟时间从秒转换为天时分秒格式
|
||||
var total_seconds = int(crop["生长时间"])
|
||||
|
||||
# 定义时间单位换算
|
||||
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
|
||||
|
||||
# 构建时间字符串(只显示有值的单位)
|
||||
var time_str = ""
|
||||
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) + "秒"
|
||||
|
||||
button.tooltip_text = str(
|
||||
"作物: " + display_name + "\n" +
|
||||
"品质: " + crop_quality + "\n" +
|
||||
"原价格: " + str(crop["花费"]) + "元\n" +
|
||||
"成熟时间: " + time_str + "\n" +
|
||||
"原收益: " + str(crop["收益"]) + "元\n" +
|
||||
"需求等级: " + str(crop["等级"]) + "\n" +
|
||||
"耐候性: " + str(crop["耐候性"]) + "\n" +
|
||||
"经验: " + str(crop["经验"]) + "点\n" +
|
||||
"描述: " + str(crop["描述"])
|
||||
)
|
||||
|
||||
# 如果按钮有标题标签,设置标题
|
||||
if button.has_node("Title"):
|
||||
button.get_node("Title").text = crop_quality
|
||||
match crop_quality:
|
||||
"普通":
|
||||
button.get_node("Title").modulate = Color.HONEYDEW#白色
|
||||
"优良":
|
||||
button.get_node("Title").modulate =Color.DODGER_BLUE#深蓝色
|
||||
"稀有":
|
||||
button.get_node("Title").modulate =Color.HOT_PINK#品红色
|
||||
"史诗":
|
||||
button.get_node("Title").modulate =Color.YELLOW#黄色
|
||||
"传奇":
|
||||
button.get_node("Title").modulate =Color.ORANGE_RED#红色
|
||||
|
||||
# 更新按钮的作物图片(使用收获物.webp)
|
||||
_update_button_crop_image(button, crop_name)
|
||||
|
||||
return button
|
||||
|
||||
# 正常模式下的成熟物点击处理
|
||||
func _on_crop_selected(crop_name, crop_count):
|
||||
# 获取作物信息面板的引用
|
||||
var crop_inform_panel = get_node("/root/main/UI/SmallPanel/CropInformPanel")
|
||||
if crop_inform_panel and crop_inform_panel.has_method("show_crop_info"):
|
||||
# 打开作物信息面板并传递作物数据
|
||||
crop_inform_panel.show_crop_info(crop_name, crop_count)
|
||||
else:
|
||||
# 如果作物信息面板不可用,显示Toast作为后备方案
|
||||
var info_text = ""
|
||||
|
||||
if main_game.can_planted_crop.has(crop_name):
|
||||
var crop = main_game.can_planted_crop[crop_name]
|
||||
var display_name = crop_name
|
||||
var mature_name = crop.get("成熟物名称")
|
||||
if mature_name != null and mature_name != "":
|
||||
display_name = mature_name
|
||||
else:
|
||||
display_name = crop.get("作物名称", crop_name)
|
||||
var quality = crop.get("品质", "未知")
|
||||
var price = crop.get("花费", 0)
|
||||
var grow_time = crop.get("生长时间", 0)
|
||||
var profit = crop.get("收益", 0)
|
||||
var level_req = crop.get("等级", 1)
|
||||
|
||||
# 将成熟时间转换为可读格式
|
||||
var time_str = ""
|
||||
var total_seconds = int(grow_time)
|
||||
var hours = total_seconds / 3600
|
||||
var minutes = (total_seconds % 3600) / 60
|
||||
var seconds = total_seconds % 60
|
||||
|
||||
if hours > 0:
|
||||
time_str += str(hours) + "小时"
|
||||
if minutes > 0:
|
||||
time_str += str(minutes) + "分钟"
|
||||
if seconds > 0:
|
||||
time_str += str(seconds) + "秒"
|
||||
|
||||
info_text = quality + "-" + display_name + " (数量: " + str(crop_count) + ")\n"
|
||||
info_text += "原价格: " + str(price) + "元, 原收益: " + str(profit) + "元\n"
|
||||
info_text += "成熟时间: " + time_str + ", 需求等级: " + str(level_req) + "\n"
|
||||
info_text += "这是收获的成熟品,可以用于出售或其他用途"
|
||||
else:
|
||||
info_text = crop_name + " (数量: " + str(crop_count) + ")"
|
||||
|
||||
Toast.show(info_text, Color.GOLD, 3.0, 1.0)
|
||||
|
||||
# 访问模式下的成熟物点击处理
|
||||
func _on_visit_crop_selected(crop_name, crop_count):
|
||||
# 显示成熟物信息
|
||||
var info_text = ""
|
||||
|
||||
if main_game.can_planted_crop.has(crop_name):
|
||||
var crop = main_game.can_planted_crop[crop_name]
|
||||
var display_name = crop_name
|
||||
var mature_name = crop.get("成熟物名称")
|
||||
if mature_name != null and mature_name != "":
|
||||
display_name = mature_name
|
||||
else:
|
||||
display_name = crop.get("作物名称", crop_name)
|
||||
var quality = crop.get("品质", "未知")
|
||||
var price = crop.get("花费", 0)
|
||||
var grow_time = crop.get("生长时间", 0)
|
||||
var profit = crop.get("收益", 0)
|
||||
var level_req = crop.get("等级", 1)
|
||||
|
||||
# 将成熟时间转换为可读格式
|
||||
var time_str = ""
|
||||
var total_seconds = int(grow_time)
|
||||
var hours = total_seconds / 3600
|
||||
var minutes = (total_seconds % 3600) / 60
|
||||
var seconds = total_seconds % 60
|
||||
|
||||
if hours > 0:
|
||||
time_str += str(hours) + "小时"
|
||||
if minutes > 0:
|
||||
time_str += str(minutes) + "分钟"
|
||||
if seconds > 0:
|
||||
time_str += str(seconds) + "秒"
|
||||
|
||||
info_text = quality + "-" + display_name + " (数量: " + str(crop_count) + ")\n"
|
||||
info_text += "原价格: " + str(price) + "元, 原收益: " + str(profit) + "元\n"
|
||||
info_text += "成熟时间: " + time_str + ", 需求等级: " + str(level_req)
|
||||
else:
|
||||
info_text = crop_name + " (数量: " + str(crop_count) + ")"
|
||||
|
||||
Toast.show(info_text, Color.CYAN, 3.0, 1.0)
|
||||
|
||||
# 宠物喂食模式下的作物选择处理
|
||||
func _on_crop_feed_selected(crop_name: String, crop_count: int):
|
||||
if not is_pet_feeding_mode or current_pet_data.is_empty():
|
||||
Toast.show("当前不在宠物喂食模式", Color.RED, 2.0, 1.0)
|
||||
return
|
||||
|
||||
# 检查作物是否有喂养效果
|
||||
var crop_data = main_game.can_planted_crop.get(crop_name, {})
|
||||
if not crop_data.has("喂养效果"):
|
||||
Toast.show("该作物没有喂养效果", Color.RED, 2.0, 1.0)
|
||||
return
|
||||
|
||||
# 获取喂养效果
|
||||
var feed_effects = crop_data.get("喂养效果", {})
|
||||
|
||||
# 获取宠物信息
|
||||
var pet_name = current_pet_data.get("pet_name", "未知宠物")
|
||||
var pet_id = current_pet_data.get("pet_id", "")
|
||||
|
||||
if pet_id == "":
|
||||
Toast.show("宠物ID无效", Color.RED, 2.0, 1.0)
|
||||
return
|
||||
|
||||
# 构建效果描述
|
||||
var effect_descriptions = []
|
||||
for effect_name in feed_effects:
|
||||
var effect_value = feed_effects[effect_name]
|
||||
if effect_value > 0:
|
||||
effect_descriptions.append(effect_name + "+" + str(effect_value))
|
||||
|
||||
var effect_text = ",".join(effect_descriptions) if effect_descriptions.size() > 0 else "无效果"
|
||||
|
||||
# 获取显示名称
|
||||
var display_name = crop_name
|
||||
if main_game.can_planted_crop.has(crop_name):
|
||||
var mature_name = main_game.can_planted_crop[crop_name].get("成熟物名称")
|
||||
if mature_name != null and mature_name != "":
|
||||
display_name = mature_name
|
||||
else:
|
||||
display_name = main_game.can_planted_crop[crop_name].get("作物名称", crop_name)
|
||||
|
||||
# 显示确认对话框
|
||||
var confirm_text = str(
|
||||
"确认喂食 " + pet_name + " 吗?\n\n" +
|
||||
"作物:" + display_name + "\n" +
|
||||
"效果:" + effect_text + "\n\n" +
|
||||
"确认后将消耗1个" + display_name
|
||||
)
|
||||
|
||||
_show_feed_confirmation_dialog(confirm_text, crop_name, pet_id, feed_effects)
|
||||
|
||||
# 显示喂食确认对话框
|
||||
func _show_feed_confirmation_dialog(confirm_text: String, crop_name: String, pet_id: String, feed_effects: Dictionary):
|
||||
var confirm_dialog = AcceptDialog.new()
|
||||
confirm_dialog.dialog_text = confirm_text
|
||||
confirm_dialog.title = "宠物喂食确认"
|
||||
confirm_dialog.ok_button_text = "确认喂食"
|
||||
confirm_dialog.add_cancel_button("取消")
|
||||
|
||||
# 添加到场景
|
||||
add_child(confirm_dialog)
|
||||
|
||||
# 连接信号
|
||||
confirm_dialog.confirmed.connect(_on_confirm_feed_pet.bind(crop_name, pet_id, feed_effects, confirm_dialog))
|
||||
confirm_dialog.canceled.connect(_on_cancel_feed_pet.bind(confirm_dialog))
|
||||
|
||||
# 显示对话框
|
||||
confirm_dialog.popup_centered()
|
||||
|
||||
# 确认喂食宠物
|
||||
func _on_confirm_feed_pet(crop_name: String, pet_id: String, feed_effects: Dictionary, dialog: AcceptDialog):
|
||||
# 发送喂食请求到服务器
|
||||
_send_feed_pet_request(crop_name, pet_id, feed_effects)
|
||||
dialog.queue_free()
|
||||
|
||||
# 取消喂食宠物
|
||||
func _on_cancel_feed_pet(dialog: AcceptDialog):
|
||||
dialog.queue_free()
|
||||
|
||||
# 发送喂食宠物请求
|
||||
func _send_feed_pet_request(crop_name: String, pet_id: String, feed_effects: Dictionary):
|
||||
if not tcp_network_manager_panel or not tcp_network_manager_panel.has_method("send_message"):
|
||||
Toast.show("网络功能不可用", Color.RED, 2.0, 1.0)
|
||||
return
|
||||
|
||||
# 构建喂食请求消息
|
||||
var message = {
|
||||
"type": "feed_pet",
|
||||
"pet_id": pet_id,
|
||||
"crop_name": crop_name,
|
||||
"feed_effects": feed_effects
|
||||
}
|
||||
|
||||
# 发送请求
|
||||
tcp_network_manager_panel.send_message(message)
|
||||
|
||||
# 退出喂食模式
|
||||
set_pet_feeding_mode(false)
|
||||
self.hide()
|
||||
|
||||
|
||||
|
||||
# 获取作物的收获物图片(用于仓库显示)
|
||||
func _get_crop_harvest_texture(crop_name: String) -> Texture2D:
|
||||
# 使用作物键名(而不是成熟物名称)来构建图片路径
|
||||
# crop_name 是作物的键名,如"可可豆"、"向日葵"等
|
||||
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:
|
||||
print("仓库加载作物收获物图片:", crop_name)
|
||||
return texture
|
||||
|
||||
# 如果没有找到,使用默认的收获物图片
|
||||
var default_harvest_path = "res://assets/作物/默认/收获物.webp"
|
||||
if ResourceLoader.exists(default_harvest_path):
|
||||
var texture = load(default_harvest_path)
|
||||
if texture:
|
||||
print("仓库使用默认收获物图片:", crop_name)
|
||||
return texture
|
||||
|
||||
return null
|
||||
|
||||
# 更新按钮的作物图片
|
||||
func _update_button_crop_image(button: Button, crop_name: String):
|
||||
# 检查按钮是否有CropImage节点
|
||||
var crop_image = button.get_node_or_null("CropImage")
|
||||
if not crop_image:
|
||||
print("仓库按钮没有找到CropImage节点:", button.name)
|
||||
return
|
||||
|
||||
# 获取作物的收获物图片
|
||||
var texture = _get_crop_harvest_texture(crop_name)
|
||||
|
||||
if texture:
|
||||
# CropImage是Sprite2D,直接设置texture属性
|
||||
crop_image.texture = texture
|
||||
crop_image.visible = true
|
||||
else:
|
||||
crop_image.visible = false
|
||||
print("仓库无法获取作物收获物图片:", crop_name)
|
||||
|
||||
|
||||
#=========================面板通用处理=========================
|
||||
#手动刷新作物仓库面板
|
||||
func _on_refresh_button_pressed() -> void:
|
||||
# 刷新作物仓库UI
|
||||
update_crop_warehouse_ui()
|
||||
Toast.show("作物仓库已刷新", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
# 关闭作物仓库面板
|
||||
func _on_quit_button_pressed():
|
||||
|
||||
# 如果是宠物喂食模式,退出该模式
|
||||
if is_pet_feeding_mode:
|
||||
set_pet_feeding_mode(false)
|
||||
|
||||
self.hide()
|
||||
|
||||
#面板显示与隐藏切换处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
# 面板显示时请求同步最新的背包数据
|
||||
tcp_network_manager_panel.send_sync_bag_data_request()
|
||||
update_crop_warehouse_ui()
|
||||
pass
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
pass
|
||||
|
||||
#=========================面板通用处理=========================
|
||||
@@ -0,0 +1 @@
|
||||
uid://ptdj0qmobihd
|
||||
225
SproutFarm-Frontend/Script/BigPanel/DailyCheckInPanel.gd
Normal file
225
SproutFarm-Frontend/Script/BigPanel/DailyCheckInPanel.gd
Normal file
@@ -0,0 +1,225 @@
|
||||
extends Panel
|
||||
class_name DailyCheckInPanel
|
||||
|
||||
signal check_in_completed(rewards: Dictionary)
|
||||
signal check_in_failed(error_message: String)
|
||||
|
||||
@onready var daily_check_in_history: RichTextLabel = $Scroll/DailyCheckInHistory
|
||||
@onready var daily_check_in_reward: RichTextLabel = $DailyCheckInReward
|
||||
@onready var daily_check_in_button: Button = $DailyCheckInButton
|
||||
@onready var main_game = get_node("/root/main")
|
||||
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
|
||||
|
||||
@onready var confirm_dialog: ConfirmationDialog = $ConfirmDialog #确认弹窗
|
||||
|
||||
|
||||
var check_in_history: Dictionary = {}
|
||||
var consecutive_days: int = 0
|
||||
var has_checked_in_today: bool = false
|
||||
|
||||
func _ready() -> void:
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
_initialize_system()
|
||||
|
||||
func _initialize_system() -> void:
|
||||
daily_check_in_reward.hide()
|
||||
_update_display()
|
||||
_check_daily_status()
|
||||
|
||||
if tcp_network_manager_panel and tcp_network_manager_panel.is_connected_to_server():
|
||||
tcp_network_manager_panel.sendGetCheckInData()
|
||||
|
||||
func handle_daily_check_in_response(response: Dictionary) -> void:
|
||||
var success = response.get("success", false)
|
||||
var message = response.get("message", "")
|
||||
|
||||
if success:
|
||||
var rewards = response.get("rewards", {})
|
||||
consecutive_days = response.get("consecutive_days", 0)
|
||||
has_checked_in_today = true
|
||||
|
||||
# 显示奖励内容
|
||||
_show_reward_content(rewards)
|
||||
|
||||
_set_button_state(false, "已签到", Color(0.7, 0.7, 0.7, 1))
|
||||
|
||||
check_in_completed.emit(rewards)
|
||||
Toast.show(message, Color.GREEN)
|
||||
else:
|
||||
has_checked_in_today = response.get("has_checked_in", false)
|
||||
_set_button_state(false, "已签到", Color(0.7, 0.7, 0.7, 1)) if has_checked_in_today else _set_button_state(true, "签到", Color(1, 1, 0.52549, 1))
|
||||
check_in_failed.emit(message)
|
||||
Toast.show(message, Color.RED)
|
||||
|
||||
func handle_check_in_data_response(response: Dictionary) -> void:
|
||||
var success = response.get("success", false)
|
||||
|
||||
if success:
|
||||
check_in_history = response.get("check_in_data", {})
|
||||
consecutive_days = response.get("consecutive_days", 0)
|
||||
has_checked_in_today = response.get("has_checked_in_today", false)
|
||||
|
||||
_update_display()
|
||||
_check_daily_status()
|
||||
|
||||
func _check_daily_status() -> void:
|
||||
if has_checked_in_today:
|
||||
_set_button_state(false, "已签到", Color(0.7, 0.7, 0.7, 1))
|
||||
else:
|
||||
_set_button_state(true, "签到", Color(1, 1, 0.52549, 1))
|
||||
|
||||
func _set_button_state(enabled: bool, text: String, color: Color) -> void:
|
||||
daily_check_in_button.disabled = not enabled
|
||||
daily_check_in_button.text = text
|
||||
daily_check_in_button.modulate = color
|
||||
|
||||
func execute_check_in() -> void:
|
||||
if has_checked_in_today:
|
||||
Toast.show("今日已签到,请明日再来", Color.ORANGE)
|
||||
return
|
||||
|
||||
if not tcp_network_manager_panel or not tcp_network_manager_panel.is_connected_to_server():
|
||||
Toast.show("未连接到服务器,无法签到", Color.RED)
|
||||
return
|
||||
|
||||
tcp_network_manager_panel.sendDailyCheckIn()
|
||||
daily_check_in_button.disabled = true
|
||||
daily_check_in_button.text = "签到中..."
|
||||
|
||||
await get_tree().create_timer(3.0).timeout
|
||||
if daily_check_in_button.disabled and daily_check_in_button.text == "签到中...":
|
||||
daily_check_in_button.disabled = false
|
||||
daily_check_in_button.text = "签到"
|
||||
|
||||
|
||||
func _format_reward_text(rewards: Dictionary) -> String:
|
||||
var text = ""
|
||||
|
||||
text += "[center][color=#FF69B4]🔥 连续签到第%d天 🔥[/color][/center]\n" % consecutive_days
|
||||
if consecutive_days > 1:
|
||||
var multiplier = 1.0 + (consecutive_days - 1) * 0.1
|
||||
multiplier = min(multiplier, 3.0)
|
||||
text += "[center][color=#90EE90]奖励倍数: %.1fx[/color][/center]\n\n" % multiplier
|
||||
else:
|
||||
text += "\n"
|
||||
|
||||
if rewards.has("coins"):
|
||||
text += "[color=#FFD700]💰 +%d 金币[/color]\n" % rewards.coins
|
||||
|
||||
if rewards.has("exp"):
|
||||
text += "[color=#00BFFF]⭐ +%d 经验[/color]\n" % rewards.exp
|
||||
|
||||
if rewards.has("seeds") and rewards.seeds.size() > 0:
|
||||
for seed_reward in rewards.seeds:
|
||||
var seed_name = seed_reward.name
|
||||
var quantity = seed_reward.quantity
|
||||
var quality = seed_reward.quality
|
||||
var rarity_color = _get_rarity_color(quality)
|
||||
|
||||
text += "[color=%s]🌱 %s x%d[/color] [color=%s](%s)[/color]\n" % [
|
||||
rarity_color, seed_name, quantity, rarity_color, quality
|
||||
]
|
||||
|
||||
if rewards.has("bonus_coins"):
|
||||
text += "\n[color=#FFD700]🎁 连续签到奖励:[/color]\n"
|
||||
text += "[color=#FFD700]💰 +%d 额外金币[/color] [color=#FFD700]✨[/color]\n" % rewards.bonus_coins
|
||||
|
||||
if rewards.has("bonus_exp"):
|
||||
if not rewards.has("bonus_coins"):
|
||||
text += "\n[color=#FFD700]🎁 连续签到奖励:[/color]\n"
|
||||
text += "[color=#00BFFF]⭐ +%d 额外经验[/color] [color=#FFD700]✨[/color]\n" % rewards.bonus_exp
|
||||
|
||||
var next_bonus_day = 0
|
||||
if consecutive_days < 3:
|
||||
next_bonus_day = 3
|
||||
elif consecutive_days < 7:
|
||||
next_bonus_day = 7
|
||||
elif consecutive_days < 14:
|
||||
next_bonus_day = 14
|
||||
elif consecutive_days < 21:
|
||||
next_bonus_day = 21
|
||||
elif consecutive_days < 30:
|
||||
next_bonus_day = 30
|
||||
|
||||
if next_bonus_day > 0:
|
||||
var days_needed = next_bonus_day - consecutive_days
|
||||
text += "\n[center][color=#87CEEB]再签到%d天可获得特殊奖励![/color][/center]" % days_needed
|
||||
|
||||
return text
|
||||
|
||||
func _get_rarity_color(rarity: String) -> String:
|
||||
match rarity:
|
||||
"普通": return "#90EE90"
|
||||
"优良": return "#87CEEB"
|
||||
"稀有": return "#DDA0DD"
|
||||
"史诗": return "#9932CC"
|
||||
"传奇": return "#FF8C00"
|
||||
_: return "#FFFFFF"
|
||||
|
||||
func _show_reward_content(rewards: Dictionary) -> void:
|
||||
var reward_text = _format_reward_text(rewards)
|
||||
daily_check_in_reward.text = reward_text
|
||||
daily_check_in_reward.show()
|
||||
|
||||
func _update_display() -> void:
|
||||
var history_text = "[center][color=#FFB6C1]📋 签到历史[/color][/center]\n"
|
||||
|
||||
if consecutive_days > 0:
|
||||
history_text += "[center][color=#FF69B4]🔥 当前连续签到: %d天[/color][/center]\n" % consecutive_days
|
||||
if consecutive_days >= 30:
|
||||
history_text += "[center][color=#FFD700]⭐ 已达到最高连击等级! ⭐[/color][/center]\n"
|
||||
else:
|
||||
history_text += "[center][color=#DDDDDD]还未开始连续签到[/color][/center]\n"
|
||||
|
||||
history_text += "\n"
|
||||
|
||||
if check_in_history.size() == 0:
|
||||
history_text += "[center][color=#DDDDDD]暂无签到记录[/color][/center]"
|
||||
else:
|
||||
# 按时间排序显示历史记录
|
||||
var sorted_times = check_in_history.keys()
|
||||
sorted_times.sort()
|
||||
sorted_times.reverse()
|
||||
|
||||
for time_key in sorted_times:
|
||||
var reward_text = check_in_history[time_key]
|
||||
history_text += "[color=#87CEEB]%s[/color] [color=#90EE90]%s[/color]\n" % [time_key, reward_text]
|
||||
history_text += "---------------------------------------------\n"
|
||||
|
||||
daily_check_in_history.text = history_text
|
||||
|
||||
# 事件处理
|
||||
func _on_quit_button_pressed() -> void:
|
||||
self.hide()
|
||||
|
||||
func _on_daily_check_in_button_pressed() -> void:
|
||||
# 显示确认弹窗
|
||||
confirm_dialog.title = "每日签到确认"
|
||||
confirm_dialog.dialog_text = "确定要进行今日签到吗?\n签到可获得金币、经验和种子奖励!"
|
||||
confirm_dialog.popup_centered()
|
||||
|
||||
# 连接确认信号(如果还没连接的话)
|
||||
if not confirm_dialog.confirmed.is_connected(_on_confirm_check_in):
|
||||
confirm_dialog.confirmed.connect(_on_confirm_check_in)
|
||||
|
||||
func _on_confirm_check_in() -> void:
|
||||
execute_check_in()
|
||||
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
|
||||
# 公共接口
|
||||
func refresh_check_in_data() -> void:
|
||||
if tcp_network_manager_panel and tcp_network_manager_panel.is_connected_to_server():
|
||||
tcp_network_manager_panel.sendGetCheckInData()
|
||||
|
||||
func get_check_in_status() -> Dictionary:
|
||||
return {
|
||||
"has_checked_in_today": has_checked_in_today,
|
||||
"consecutive_days": consecutive_days
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
uid://c0jfbtkh0mj5b
|
||||
571
SproutFarm-Frontend/Script/BigPanel/ItemBagPanel.gd
Normal file
571
SproutFarm-Frontend/Script/BigPanel/ItemBagPanel.gd
Normal file
@@ -0,0 +1,571 @@
|
||||
extends Panel
|
||||
# 这是道具背包面板,用来显示玩家获得的道具
|
||||
|
||||
# 道具背包格子容器
|
||||
@onready var bag_grid: GridContainer = $ScrollContainer/Bag_Grid
|
||||
@onready var quit_button : Button = $QuitButton
|
||||
@onready var refresh_button : Button = $RefreshButton
|
||||
|
||||
# 预添加常用的面板
|
||||
@onready var main_game = get_node("/root/main")
|
||||
|
||||
@onready var lucky_draw_panel: LuckyDrawPanel = $'../LuckyDrawPanel'
|
||||
@onready var daily_check_in_panel: DailyCheckInPanel = $'../DailyCheckInPanel'
|
||||
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
|
||||
@onready var item_store_panel: Panel = $'../ItemStorePanel'
|
||||
@onready var player_bag_panel: Panel = $'../PlayerBagPanel'
|
||||
@onready var crop_warehouse_panel: Panel = $'../CropWarehousePanel'
|
||||
@onready var crop_store_panel: Panel = $'../CropStorePanel'
|
||||
@onready var player_ranking_panel: Panel = $'../PlayerRankingPanel'
|
||||
@onready var login_panel: PanelContainer = $'../LoginPanel'
|
||||
|
||||
|
||||
# 道具使用状态
|
||||
var selected_item_name: String = ""
|
||||
var selected_item_button: Button = null
|
||||
var is_item_selected: bool = false
|
||||
|
||||
# 宠物使用道具模式
|
||||
var is_pet_item_mode: bool = false
|
||||
var current_pet_data: Dictionary = {}
|
||||
|
||||
# 准备函数
|
||||
func _ready():
|
||||
# 连接可见性改变信号
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
# 隐藏面板(初始默认隐藏)
|
||||
self.hide()
|
||||
|
||||
|
||||
# 异步更新道具背包UI
|
||||
func _update_item_bag_ui_async():
|
||||
# 清空道具背包格子
|
||||
for child in bag_grid.get_children():
|
||||
child.queue_free()
|
||||
|
||||
# 等待一帧确保子节点被清理
|
||||
await get_tree().process_frame
|
||||
|
||||
# 为背包中的每个道具创建按钮
|
||||
for item_data in main_game.item_bag:
|
||||
var item_name = item_data["name"]
|
||||
var item_count = item_data["count"]
|
||||
|
||||
# 创建道具按钮
|
||||
var button = _create_item_button(item_name)
|
||||
|
||||
# 更新按钮文本显示数量
|
||||
button.text = str(item_name + "\n数量:" + str(item_count))
|
||||
|
||||
# 根据是否处于访问模式连接不同的事件
|
||||
if main_game.is_visiting_mode:
|
||||
# 访问模式下,点击道具只显示信息,不能使用
|
||||
button.pressed.connect(func(): _on_visit_item_selected(item_name, item_count))
|
||||
else:
|
||||
# 正常模式下,连接道具选择事件
|
||||
button.pressed.connect(func(): _on_item_selected(item_name, item_count, button))
|
||||
|
||||
bag_grid.add_child(button)
|
||||
|
||||
# 初始化道具背包
|
||||
func init_item_bag():
|
||||
# 清空道具背包格子
|
||||
for child in bag_grid.get_children():
|
||||
child.queue_free()
|
||||
|
||||
# 重置筛选状态为显示全部
|
||||
current_filter_type = "全部"
|
||||
# 显示背包中的道具
|
||||
update_item_bag_ui()
|
||||
|
||||
# 更新道具背包UI(同步版本,用于刷新按钮)
|
||||
func update_item_bag_ui():
|
||||
# 清空道具背包格子
|
||||
for child in bag_grid.get_children():
|
||||
child.queue_free()
|
||||
|
||||
# 获取过滤后的道具列表
|
||||
var filtered_items = _get_filtered_items()
|
||||
|
||||
# 输出筛选统计信息
|
||||
print("道具背包筛选结果: ", current_filter_type, " - 共 ", filtered_items.size(), " 个道具")
|
||||
|
||||
# 为背包中的每个道具创建按钮
|
||||
for item_data in filtered_items:
|
||||
var item_name = item_data["name"]
|
||||
var item_count = item_data["count"]
|
||||
|
||||
# 创建道具按钮
|
||||
var button = _create_item_button(item_name)
|
||||
|
||||
# 更新按钮文本显示数量
|
||||
button.text = str(item_name + "\n数量:" + str(item_count))
|
||||
|
||||
# 根据模式连接不同的事件
|
||||
if main_game.is_visiting_mode:
|
||||
# 访问模式下,点击道具只显示信息,不能使用
|
||||
button.pressed.connect(func(): _on_visit_item_selected(item_name, item_count))
|
||||
elif is_pet_item_mode:
|
||||
# 宠物使用道具模式下,连接宠物道具选择事件
|
||||
button.pressed.connect(func(): _on_pet_item_selected(item_name, item_count))
|
||||
else:
|
||||
# 正常模式下,连接道具选择事件
|
||||
button.pressed.connect(func(): _on_item_selected(item_name, item_count, button))
|
||||
|
||||
bag_grid.add_child(button)
|
||||
|
||||
# 创建道具按钮
|
||||
func _create_item_button(item_name: String) -> Button:
|
||||
# 使用绿色按钮作为道具按钮的默认样式
|
||||
var button = main_game.item_button.duplicate()
|
||||
|
||||
# 确保按钮可见并可点击
|
||||
button.visible = true
|
||||
button.disabled = false
|
||||
button.focus_mode = Control.FOCUS_ALL
|
||||
|
||||
# 设置按钮文本
|
||||
button.text = item_name
|
||||
|
||||
# 添加工具提示,从item_config.json获取道具信息
|
||||
var item_config = _load_item_config()
|
||||
if item_config and item_config.has(item_name):
|
||||
var item_info = item_config[item_name]
|
||||
var description = item_info.get("描述", "暂无描述")
|
||||
var cost = item_info.get("花费", 0)
|
||||
|
||||
button.tooltip_text = str(
|
||||
"道具: " + item_name + "\n" +
|
||||
"价格: " + str(cost) + "元\n" +
|
||||
"描述: " + description + "\n" +
|
||||
"点击选择道具,然后对地块使用"
|
||||
)
|
||||
else:
|
||||
button.tooltip_text = str("道具: " + item_name + "\n描述: 暂无信息")
|
||||
|
||||
# 如果按钮有标题标签,设置标题
|
||||
if button.has_node("Title"):
|
||||
button.get_node("Title").text = "道具"
|
||||
button.get_node("Title").modulate = Color.CYAN # 道具标题使用青色
|
||||
|
||||
# 更新按钮的道具图片
|
||||
_update_button_item_image(button, item_name)
|
||||
|
||||
return button
|
||||
|
||||
# 从主游戏脚本获取道具配置数据
|
||||
func _load_item_config() -> Dictionary:
|
||||
# 从主游戏脚本的全局变量获取道具配置数据
|
||||
if main_game.item_config_data.size() > 0:
|
||||
return main_game.item_config_data
|
||||
else:
|
||||
print("道具背包:主游戏脚本中没有道具配置数据")
|
||||
return {}
|
||||
|
||||
# 设置宠物使用道具模式
|
||||
func set_pet_item_mode(enabled: bool, pet_data: Dictionary = {}):
|
||||
is_pet_item_mode = enabled
|
||||
current_pet_data = pet_data
|
||||
|
||||
# 刷新UI以应用新的模式
|
||||
update_item_bag_ui()
|
||||
|
||||
# 获取过滤后的道具列表
|
||||
func _get_filtered_items() -> Array:
|
||||
var filtered_items = []
|
||||
|
||||
for item_data in main_game.item_bag:
|
||||
var item_name = item_data["name"]
|
||||
|
||||
# 如果是宠物使用道具模式,只显示宠物道具
|
||||
if is_pet_item_mode:
|
||||
if _is_pet_item(item_name):
|
||||
filtered_items.append(item_data)
|
||||
else:
|
||||
# 正常模式下,应用筛选条件
|
||||
if _is_item_match_filter(item_name):
|
||||
filtered_items.append(item_data)
|
||||
|
||||
return filtered_items
|
||||
|
||||
# 检查是否为宠物道具
|
||||
func _is_pet_item(item_name: String) -> bool:
|
||||
var item_config = _load_item_config()
|
||||
if item_config and item_config.has(item_name):
|
||||
var item_info = item_config[item_name]
|
||||
var item_type = item_info.get("类型", "")
|
||||
return item_type == "宠物道具"
|
||||
return false
|
||||
|
||||
|
||||
# 正常模式下的道具点击处理 - 选择道具
|
||||
func _on_item_selected(item_name: String, item_count: int, button: Button):
|
||||
# 检查道具是否可以使用
|
||||
if not _is_item_usable(item_name):
|
||||
# 显示道具信息
|
||||
_show_item_info(item_name, item_count)
|
||||
return
|
||||
|
||||
# 检查是否为农场道具(直接使用类型)
|
||||
if _is_farm_item(item_name):
|
||||
# 农场道具直接使用,显示确认对话框
|
||||
_show_farm_item_confirmation_dialog(item_name, item_count)
|
||||
return
|
||||
|
||||
# 取消之前选择的道具
|
||||
if selected_item_button and selected_item_button != button:
|
||||
_deselect_item()
|
||||
|
||||
if selected_item_name == item_name:
|
||||
# 如果点击的是已选择的道具,取消选择
|
||||
_deselect_item()
|
||||
Toast.show("已取消选择道具", Color.YELLOW, 2.0, 1.0)
|
||||
else:
|
||||
# 选择新道具
|
||||
_select_item(item_name, button)
|
||||
#点击后关闭玩家道具面板
|
||||
_on_quit_button_pressed()
|
||||
Toast.show("已选择 " + item_name + ",点击地块使用道具", Color.CYAN, 3.0, 1.0)
|
||||
|
||||
# 选择道具
|
||||
func _select_item(item_name: String, button: Button):
|
||||
selected_item_name = item_name
|
||||
selected_item_button = button
|
||||
is_item_selected = true
|
||||
|
||||
# 设置全局选择状态
|
||||
main_game.selected_item_name = item_name
|
||||
main_game.is_item_selected = true
|
||||
|
||||
# 更改按钮样式表示选中
|
||||
if button.has_node("Title"):
|
||||
button.get_node("Title").modulate = Color.YELLOW # 选中时使用黄色
|
||||
|
||||
# 取消选择道具
|
||||
func _deselect_item():
|
||||
selected_item_name = ""
|
||||
is_item_selected = false
|
||||
|
||||
# 清除全局选择状态
|
||||
main_game.selected_item_name = ""
|
||||
main_game.is_item_selected = false
|
||||
|
||||
# 恢复按钮样式
|
||||
if selected_item_button and selected_item_button.has_node("Title"):
|
||||
selected_item_button.get_node("Title").modulate = Color.CYAN
|
||||
|
||||
selected_item_button = null
|
||||
|
||||
# 检查道具是否可以使用
|
||||
func _is_item_usable(item_name: String) -> bool:
|
||||
# 根据道具类型判断是否可以使用
|
||||
match item_name:
|
||||
"农家肥", "金坷垃", "生长素":
|
||||
return true # 施肥道具
|
||||
"水壶", "水桶":
|
||||
return true # 浇水道具
|
||||
"铲子","除草剂":
|
||||
return true # 铲除道具
|
||||
"精准采集锄", "时运锄":
|
||||
return true # 采集道具
|
||||
"小额经验卡", "小额金币卡":
|
||||
return true # 农场道具(直接使用)
|
||||
"杀虫剂":
|
||||
return false # 其他道具(暂不实现)
|
||||
_:
|
||||
return false
|
||||
|
||||
# 检查道具是否为农场道具(直接使用类型)
|
||||
func _is_farm_item(item_name: String) -> bool:
|
||||
var item_config = _load_item_config()
|
||||
if item_config and item_config.has(item_name):
|
||||
var item_info = item_config[item_name]
|
||||
var item_type = item_info.get("类型", "")
|
||||
return item_type == "农场道具"
|
||||
return false
|
||||
|
||||
# 显示道具信息
|
||||
func _show_item_info(item_name: String, item_count: int):
|
||||
var info_text = ""
|
||||
|
||||
var item_config = _load_item_config()
|
||||
if item_config and item_config.has(item_name):
|
||||
var item_info = item_config[item_name]
|
||||
var description = item_info.get("描述", "暂无描述")
|
||||
var cost = item_info.get("花费", 0)
|
||||
|
||||
info_text = item_name + " (数量: " + str(item_count) + ")\n"
|
||||
info_text += "价格: " + str(cost) + "元\n"
|
||||
info_text += "描述: " + description
|
||||
|
||||
if not _is_item_usable(item_name):
|
||||
pass
|
||||
else:
|
||||
info_text = item_name + " (数量: " + str(item_count) + ")\n描述: 暂无信息"
|
||||
|
||||
Toast.show(info_text, Color.CYAN, 3.0, 1.0)
|
||||
|
||||
# 访问模式下的道具点击处理
|
||||
func _on_visit_item_selected(item_name: String, item_count: int):
|
||||
# 显示道具信息
|
||||
_show_item_info(item_name, item_count)
|
||||
|
||||
# 宠物使用道具模式下的道具选择处理
|
||||
func _on_pet_item_selected(item_name: String, item_count: int):
|
||||
# 显示确认对话框
|
||||
_show_pet_item_confirmation_dialog(item_name, item_count)
|
||||
|
||||
# 显示农场道具确认对话框
|
||||
func _show_farm_item_confirmation_dialog(item_name: String, item_count: int):
|
||||
# 获取道具信息
|
||||
var item_config = _load_item_config()
|
||||
var item_description = "未知效果"
|
||||
if item_config and item_config.has(item_name):
|
||||
var item_info = item_config[item_name]
|
||||
item_description = item_info.get("描述", "未知效果")
|
||||
|
||||
var confirmation_text = str(
|
||||
"确定要使用道具 " + item_name + " 吗?\n\n" +
|
||||
"道具效果:" + item_description + "\n\n" +
|
||||
"使用后道具数量将减少1个"
|
||||
)
|
||||
|
||||
# 使用自定义的AcceptDialog
|
||||
var dialog = preload("res://Script/Dialog/AcceptDialog.gd").new()
|
||||
|
||||
# 添加到场景(这会触发_ready函数)
|
||||
add_child(dialog)
|
||||
|
||||
# 在_ready执行后设置内容
|
||||
dialog.set_dialog_title("确认使用道具")
|
||||
dialog.set_dialog_content(confirmation_text)
|
||||
dialog.set_ok_text("确认使用")
|
||||
dialog.set_cancel_text("取消")
|
||||
|
||||
# 连接信号
|
||||
dialog.confirmed.connect(_on_confirm_farm_item_use.bind(item_name, dialog))
|
||||
dialog.canceled.connect(_on_cancel_farm_item_use.bind(dialog))
|
||||
|
||||
# 显示对话框
|
||||
dialog.popup_centered()
|
||||
|
||||
# 确认使用农场道具
|
||||
func _on_confirm_farm_item_use(item_name: String, dialog: AcceptDialog):
|
||||
_send_farm_item_use_request(item_name)
|
||||
dialog.queue_free()
|
||||
self.hide()
|
||||
|
||||
# 取消使用农场道具
|
||||
func _on_cancel_farm_item_use(dialog: AcceptDialog):
|
||||
dialog.queue_free()
|
||||
|
||||
# 发送农场道具使用请求
|
||||
func _send_farm_item_use_request(item_name: String):
|
||||
var message = {
|
||||
"type": "use_farm_item",
|
||||
"item_name": item_name
|
||||
}
|
||||
|
||||
# 发送请求
|
||||
tcp_network_manager_panel.send_message(message)
|
||||
|
||||
#Toast.show("正在使用道具...", Color.BLUE, 2.0, 1.0)
|
||||
|
||||
# 显示宠物使用道具确认对话框
|
||||
func _show_pet_item_confirmation_dialog(item_name: String, item_count: int):
|
||||
if current_pet_data.is_empty():
|
||||
Toast.show("宠物数据丢失,请重新选择宠物", Color.RED, 2.0, 1.0)
|
||||
return
|
||||
|
||||
var pet_name = current_pet_data.get("pet_name", "未知宠物")
|
||||
var pet_id = current_pet_data.get("pet_id", "")
|
||||
|
||||
# 获取道具信息
|
||||
var item_config = _load_item_config()
|
||||
var item_description = "未知效果"
|
||||
if item_config and item_config.has(item_name):
|
||||
var item_info = item_config[item_name]
|
||||
item_description = item_info.get("描述", "未知效果")
|
||||
|
||||
var confirmation_text = str(
|
||||
"确定要对宠物 " + pet_name + " 使用道具 " + item_name + " 吗?\n\n" +
|
||||
"道具效果:" + item_description + "\n\n" +
|
||||
"使用后道具数量将减少1个"
|
||||
)
|
||||
|
||||
# 使用自定义的AcceptDialog
|
||||
var dialog = preload("res://Script/Dialog/AcceptDialog.gd").new()
|
||||
|
||||
# 添加到场景(这会触发_ready函数)
|
||||
add_child(dialog)
|
||||
|
||||
# 在_ready执行后设置内容
|
||||
dialog.set_dialog_title("确认使用道具")
|
||||
dialog.set_dialog_content(confirmation_text)
|
||||
dialog.set_ok_text("确认使用")
|
||||
dialog.set_cancel_text("取消")
|
||||
|
||||
# 连接信号
|
||||
dialog.confirmed.connect(_on_confirm_pet_item_use.bind(item_name, pet_id, dialog))
|
||||
dialog.canceled.connect(_on_cancel_pet_item_use.bind(dialog))
|
||||
|
||||
# 显示对话框
|
||||
dialog.popup_centered()
|
||||
|
||||
# 确认使用宠物道具
|
||||
func _on_confirm_pet_item_use(item_name: String, pet_id: String, dialog: AcceptDialog):
|
||||
_send_pet_item_use_request(item_name, pet_id)
|
||||
dialog.queue_free()
|
||||
self.hide()
|
||||
|
||||
# 取消使用宠物道具
|
||||
func _on_cancel_pet_item_use(dialog: AcceptDialog):
|
||||
dialog.queue_free()
|
||||
self.hide()
|
||||
|
||||
# 发送宠物使用道具请求
|
||||
func _send_pet_item_use_request(item_name: String, pet_id: String):
|
||||
var message = {
|
||||
"type": "use_pet_item",
|
||||
"item_name": item_name,
|
||||
"pet_id": pet_id
|
||||
}
|
||||
|
||||
# 发送请求
|
||||
tcp_network_manager_panel.send_message(message)
|
||||
|
||||
# 退出宠物使用道具模式
|
||||
_exit_pet_item_mode()
|
||||
|
||||
#Toast.show("正在使用道具...", Color.BLUE, 2.0, 1.0)
|
||||
|
||||
# 退出宠物使用道具模式
|
||||
func _exit_pet_item_mode():
|
||||
is_pet_item_mode = false
|
||||
current_pet_data = {}
|
||||
# 刷新UI
|
||||
update_item_bag_ui()
|
||||
|
||||
# 更新按钮的道具图片
|
||||
func _update_button_item_image(button: Button, item_name: String):
|
||||
# 检查按钮是否有CropImage节点
|
||||
var item_image = button.get_node_or_null("CropImage")
|
||||
if not item_image:
|
||||
return
|
||||
|
||||
# 从配置文件获取道具图片路径
|
||||
var item_config = _load_item_config()
|
||||
var texture = null
|
||||
|
||||
if item_config and item_config.has(item_name):
|
||||
var item_info = item_config[item_name]
|
||||
var image_path = item_info.get("道具图片", "")
|
||||
|
||||
if image_path != "" and ResourceLoader.exists(image_path):
|
||||
# 尝试加载道具图片
|
||||
texture = load(image_path)
|
||||
if texture:
|
||||
pass
|
||||
else:
|
||||
print("加载道具图片失败:", item_name, " -> ", image_path)
|
||||
else:
|
||||
print("道具图片路径无效或不存在:", item_name, " -> ", image_path)
|
||||
|
||||
# 如果没有找到道具图片,尝试使用默认道具图片
|
||||
if not texture:
|
||||
var default_item_path = "res://assets/道具图片/默认道具.webp"
|
||||
if ResourceLoader.exists(default_item_path):
|
||||
texture = load(default_item_path)
|
||||
if texture:
|
||||
print("使用默认道具图片:", item_name)
|
||||
|
||||
# 设置图片
|
||||
if texture:
|
||||
# CropImage是Sprite2D,直接设置texture属性
|
||||
item_image.texture = texture
|
||||
item_image.visible = true
|
||||
else:
|
||||
# 如果没有图片,隐藏图片节点
|
||||
item_image.visible = false
|
||||
|
||||
#=========================面板通用处理=========================
|
||||
# 关闭道具背包面板
|
||||
func _on_quit_button_pressed() -> void:
|
||||
# 如果是宠物使用道具模式,退出该模式
|
||||
if is_pet_item_mode:
|
||||
_exit_pet_item_mode()
|
||||
|
||||
self.hide()
|
||||
|
||||
#手动刷新道具背包面板
|
||||
func _on_refresh_button_pressed() -> void:
|
||||
# 刷新道具背包UI
|
||||
update_item_bag_ui()
|
||||
#Toast.show("道具背包已刷新", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
#面板显示与隐藏切换处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
# 面板显示时请求同步最新的背包数据
|
||||
tcp_network_manager_panel.send_sync_bag_data_request()
|
||||
update_item_bag_ui()
|
||||
pass
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
pass
|
||||
#=========================面板通用处理=========================
|
||||
|
||||
# 获取当前选择的道具名称
|
||||
func get_selected_item_name() -> String:
|
||||
return selected_item_name
|
||||
|
||||
# 检查是否有道具被选择
|
||||
func is_item_currently_selected() -> bool:
|
||||
return is_item_selected
|
||||
|
||||
|
||||
#========================筛选功能============================
|
||||
# 当前筛选类型
|
||||
var current_filter_type: String = "全部"
|
||||
|
||||
#显示全部,既全部显示(默认)
|
||||
func _on_all_filter_pressed() -> void:
|
||||
current_filter_type = "全部"
|
||||
update_item_bag_ui()
|
||||
Toast.show("显示全部道具", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
#筛选宠物类型道具
|
||||
func _on_pet_filter_pressed() -> void:
|
||||
current_filter_type = "宠物道具"
|
||||
update_item_bag_ui()
|
||||
Toast.show("筛选宠物道具", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
#筛选作物类型道具
|
||||
func _on_crop_filter_pressed() -> void:
|
||||
current_filter_type = "作物道具"
|
||||
update_item_bag_ui()
|
||||
Toast.show("筛选作物道具", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
#筛选农场类型道具
|
||||
func _on_farm_filter_pressed() -> void:
|
||||
current_filter_type = "农场道具"
|
||||
update_item_bag_ui()
|
||||
Toast.show("筛选农场道具", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
# 检查道具是否符合当前筛选条件
|
||||
func _is_item_match_filter(item_name: String) -> bool:
|
||||
# 如果是显示全部,直接返回true
|
||||
if current_filter_type == "全部":
|
||||
return true
|
||||
|
||||
# 检查道具配置中的类型
|
||||
var item_config = _load_item_config()
|
||||
if item_config and item_config.has(item_name):
|
||||
var item_info = item_config[item_name]
|
||||
var item_type = item_info.get("类型", "")
|
||||
return item_type == current_filter_type
|
||||
|
||||
# 如果没有配置信息,默认不显示
|
||||
return false
|
||||
#========================筛选功能============================
|
||||
1
SproutFarm-Frontend/Script/BigPanel/ItemBagPanel.gd.uid
Normal file
1
SproutFarm-Frontend/Script/BigPanel/ItemBagPanel.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://b701r833vse3u
|
||||
333
SproutFarm-Frontend/Script/BigPanel/ItemStorePanel.gd
Normal file
333
SproutFarm-Frontend/Script/BigPanel/ItemStorePanel.gd
Normal file
@@ -0,0 +1,333 @@
|
||||
extends Panel
|
||||
# 这是道具商店面板,用来展示各种道具
|
||||
|
||||
# 道具商店格子容器
|
||||
@onready var store_grid: GridContainer = $ScrollContainer/Store_Grid
|
||||
@onready var quit_button : Button = $QuitButton
|
||||
@onready var refresh_button : Button = $RefreshButton
|
||||
|
||||
# 预添加常用的面板
|
||||
@onready var main_game = get_node("/root/main")
|
||||
|
||||
@onready var lucky_draw_panel: LuckyDrawPanel = $'../LuckyDrawPanel'
|
||||
@onready var daily_check_in_panel: DailyCheckInPanel = $'../DailyCheckInPanel'
|
||||
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
|
||||
@onready var item_bag_panel: Panel = $'../ItemBagPanel'
|
||||
@onready var player_bag_panel: Panel = $'../PlayerBagPanel'
|
||||
@onready var crop_warehouse_panel: Panel = $'../CropWarehousePanel'
|
||||
@onready var crop_store_panel: Panel = $'../CropStorePanel'
|
||||
@onready var player_ranking_panel: Panel = $'../PlayerRankingPanel'
|
||||
@onready var login_panel: PanelContainer = $'../LoginPanel'
|
||||
@onready var batch_buy_popup: PanelContainer = $'../../DiaLog/BatchBuyPopup'
|
||||
|
||||
|
||||
# 道具配置数据
|
||||
var item_config : Dictionary = {}
|
||||
|
||||
# 准备函数
|
||||
func _ready():
|
||||
# 连接关闭按钮信号
|
||||
quit_button.pressed.connect(self._on_quit_button_pressed)
|
||||
# 连接可见性改变信号
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 隐藏面板(初始默认隐藏)
|
||||
self.hide()
|
||||
|
||||
# 初始化道具商店
|
||||
func init_item_store():
|
||||
# 从主游戏脚本获取道具配置数据
|
||||
_load_item_config_from_main()
|
||||
# 重置筛选状态为显示全部
|
||||
current_filter_type = "全部"
|
||||
update_item_store_ui()
|
||||
|
||||
# 更新道具商店UI
|
||||
func update_item_store_ui():
|
||||
# 清空道具商店格子
|
||||
for child in store_grid.get_children():
|
||||
child.queue_free()
|
||||
|
||||
print("更新道具商店UI,道具种类:", item_config.size(), ",当前筛选:", current_filter_type)
|
||||
|
||||
# 统计符合筛选条件的道具数量
|
||||
var filtered_count = 0
|
||||
|
||||
# 为每个道具配置创建按钮
|
||||
for item_name in item_config.keys():
|
||||
# 检查是否符合筛选条件
|
||||
if not _is_item_match_filter(item_name):
|
||||
continue
|
||||
|
||||
var item_info = item_config[item_name]
|
||||
var item_cost = item_info.get("花费", 0)
|
||||
var item_desc = item_info.get("描述", "暂无描述")
|
||||
|
||||
# 创建道具按钮
|
||||
var button = _create_item_button(item_name, item_cost, item_desc)
|
||||
|
||||
# 更新按钮文本显示价格
|
||||
button.text = str(item_name + "\n价格:" + str(item_cost) + "元")
|
||||
|
||||
# 连接购买点击事件
|
||||
button.pressed.connect(func(): _on_store_item_selected(item_name, item_cost, item_desc))
|
||||
|
||||
store_grid.add_child(button)
|
||||
filtered_count += 1
|
||||
|
||||
print("筛选后显示道具数量:", filtered_count)
|
||||
|
||||
# 创建道具按钮
|
||||
func _create_item_button(item_name: String, item_cost: int, item_desc: String) -> Button:
|
||||
# 使用橙色按钮作为道具商店按钮的样式
|
||||
var button = main_game.item_button.duplicate()
|
||||
|
||||
# 确保按钮可见并可点击
|
||||
button.visible = true
|
||||
button.disabled = false
|
||||
button.focus_mode = Control.FOCUS_ALL
|
||||
|
||||
# 设置按钮文本
|
||||
button.text = item_name
|
||||
|
||||
# 添加工具提示
|
||||
button.tooltip_text = str(
|
||||
"道具: " + item_name + "\n" +
|
||||
"价格: " + str(item_cost) + "元\n" +
|
||||
"描述: " + item_desc + "\n" +
|
||||
"点击购买道具"
|
||||
)
|
||||
|
||||
# 如果按钮有标题标签,设置标题
|
||||
if button.has_node("Title"):
|
||||
button.get_node("Title").text = "商店"
|
||||
button.get_node("Title").modulate = Color.GOLD # 商店标题使用金色
|
||||
|
||||
# 更新按钮的道具图片
|
||||
_update_button_item_image(button, item_name)
|
||||
|
||||
return button
|
||||
|
||||
# 从主游戏脚本获取道具配置数据
|
||||
func _load_item_config_from_main():
|
||||
# 从主游戏脚本的全局变量获取道具配置数据
|
||||
if main_game.item_config_data.size() > 0:
|
||||
item_config = main_game.item_config_data
|
||||
print("道具商店:从主游戏脚本获取道具配置数据,道具种类:", item_config.size())
|
||||
else:
|
||||
print("道具商店:主游戏脚本中没有道具配置数据,使用空配置")
|
||||
item_config = {}
|
||||
|
||||
|
||||
# 商店道具点击处理 - 购买道具
|
||||
func _on_store_item_selected(item_name: String, item_cost: int, item_desc: String):
|
||||
# 检查玩家金钱是否足够(至少能买1个)
|
||||
if main_game.money < item_cost:
|
||||
Toast.show("金钱不足!需要 " + str(item_cost) + " 元,当前只有 " + str(main_game.money) + " 元", Color.RED, 3.0, 1.0)
|
||||
return
|
||||
|
||||
# 显示批量购买弹窗
|
||||
if batch_buy_popup:
|
||||
batch_buy_popup.show_buy_popup(
|
||||
item_name,
|
||||
item_cost,
|
||||
item_desc,
|
||||
"item",
|
||||
_on_confirm_buy_item,
|
||||
_on_cancel_buy_item
|
||||
)
|
||||
else:
|
||||
print("批量购买弹窗未找到")
|
||||
|
||||
# 显示购买确认对话框
|
||||
func _show_buy_confirmation_dialog(item_name: String, item_cost: int, item_desc: String):
|
||||
# 创建确认对话框
|
||||
var confirm_dialog = AcceptDialog.new()
|
||||
confirm_dialog.dialog_text = str(
|
||||
"确认购买道具?\n\n" +
|
||||
"道具名称: " + item_name + "\n" +
|
||||
"购买价格: " + str(item_cost) + " 元\n" +
|
||||
"道具描述: " + item_desc + "\n\n" +
|
||||
"当前金钱: " + str(main_game.money) + " 元\n" +
|
||||
"购买后余额: " + str(main_game.money - item_cost) + " 元"
|
||||
)
|
||||
confirm_dialog.title = "购买道具确认"
|
||||
confirm_dialog.ok_button_text = "确认购买"
|
||||
confirm_dialog.add_cancel_button("取消")
|
||||
|
||||
# 添加到场景
|
||||
add_child(confirm_dialog)
|
||||
|
||||
# 连接信号
|
||||
confirm_dialog.confirmed.connect(_on_confirm_buy_item.bind(item_name, item_cost, confirm_dialog))
|
||||
confirm_dialog.canceled.connect(_on_cancel_buy_item.bind(confirm_dialog))
|
||||
|
||||
# 显示对话框
|
||||
confirm_dialog.popup_centered()
|
||||
|
||||
# 确认购买道具(批量购买版本)
|
||||
func _on_confirm_buy_item(item_name: String, unit_cost: int, quantity: int, buy_type: String):
|
||||
var total_cost = unit_cost * quantity
|
||||
|
||||
# 再次检查金钱是否足够
|
||||
if main_game.money < total_cost:
|
||||
Toast.show("金钱不足!需要 " + str(total_cost) + " 元,当前只有 " + str(main_game.money) + " 元", Color.RED, 3.0, 1.0)
|
||||
return
|
||||
|
||||
# 发送批量购买请求到服务器
|
||||
_send_batch_buy_item_request(item_name, unit_cost, quantity)
|
||||
|
||||
# 取消购买道具(批量购买版本)
|
||||
func _on_cancel_buy_item():
|
||||
print("取消购买道具")
|
||||
|
||||
# 发送批量购买道具请求
|
||||
func _send_batch_buy_item_request(item_name: String, unit_cost: int, quantity: int):
|
||||
# 发送批量购买请求到服务器
|
||||
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("sendBuyItem"):
|
||||
if tcp_network_manager_panel.sendBuyItem(item_name, unit_cost, quantity):
|
||||
# 服务器会处理批量购买逻辑,客户端等待响应
|
||||
print("已发送批量购买道具请求:", item_name, " 数量:", quantity)
|
||||
else:
|
||||
Toast.show("购买请求发送失败", Color.RED, 2.0, 1.0)
|
||||
else:
|
||||
Toast.show("网络管理器不可用", Color.RED, 2.0, 1.0)
|
||||
|
||||
# 将道具添加到道具背包(客户端同步)
|
||||
func _add_item_to_bag(item_name: String):
|
||||
# 确保道具背包存在
|
||||
if "道具背包" not in main_game:
|
||||
main_game["道具背包"] = []
|
||||
|
||||
# 查找是否已存在该道具
|
||||
var found = false
|
||||
for item in main_game["道具背包"]:
|
||||
if item.get("name") == item_name:
|
||||
item["count"] += 1
|
||||
found = true
|
||||
break
|
||||
|
||||
# 如果不存在,添加新道具
|
||||
if not found:
|
||||
main_game["道具背包"].append({
|
||||
"name": item_name,
|
||||
"count": 1
|
||||
})
|
||||
|
||||
# 更新按钮的道具图片
|
||||
func _update_button_item_image(button: Button, item_name: String):
|
||||
# 检查按钮是否有CropImage节点
|
||||
var item_image = button.get_node_or_null("CropImage")
|
||||
if not item_image:
|
||||
print("道具商店按钮没有找到CropImage节点:", button.name)
|
||||
return
|
||||
|
||||
# 从配置文件获取道具图片路径
|
||||
var texture = null
|
||||
|
||||
if item_config.has(item_name):
|
||||
var item_info = item_config[item_name]
|
||||
var image_path = item_info.get("道具图片", "")
|
||||
|
||||
if image_path != "" and ResourceLoader.exists(image_path):
|
||||
# 尝试加载道具图片
|
||||
texture = load(image_path)
|
||||
if texture:
|
||||
pass
|
||||
else:
|
||||
print("加载道具图片失败:", item_name, " -> ", image_path)
|
||||
else:
|
||||
print("道具图片路径无效或不存在:", item_name, " -> ", image_path)
|
||||
|
||||
# 如果没有找到道具图片,尝试使用默认道具图片
|
||||
if not texture:
|
||||
var default_item_path = "res://assets/道具图片/默认道具.webp"
|
||||
if ResourceLoader.exists(default_item_path):
|
||||
texture = load(default_item_path)
|
||||
if texture:
|
||||
print("使用默认道具图片:", item_name)
|
||||
|
||||
# 设置图片
|
||||
if texture:
|
||||
# CropImage是Sprite2D,直接设置texture属性
|
||||
item_image.texture = texture
|
||||
item_image.visible = true
|
||||
print("道具商店更新道具图片:", item_name)
|
||||
else:
|
||||
# 如果没有图片,隐藏图片节点
|
||||
item_image.visible = false
|
||||
print("道具商店无法获取道具图片:", item_name)
|
||||
|
||||
|
||||
#=========================面板通用处理=========================
|
||||
#手动刷新道具商店面板
|
||||
func _on_refresh_button_pressed() -> void:
|
||||
# 重新初始化道具商店
|
||||
init_item_store()
|
||||
Toast.show("道具商店已刷新", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
|
||||
|
||||
# 关闭道具商店面板
|
||||
func _on_quit_button_pressed() -> void:
|
||||
self.hide()
|
||||
pass
|
||||
|
||||
|
||||
#面板显示与隐藏切换处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
# 面板显示时自动刷新数据
|
||||
init_item_store()
|
||||
pass
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
pass
|
||||
#=========================面板通用处理=========================
|
||||
|
||||
|
||||
|
||||
#========================筛选功能============================
|
||||
# 当前筛选类型
|
||||
var current_filter_type: String = "全部"
|
||||
|
||||
#显示全部,既全部显示(默认)
|
||||
func _on_all_filter_pressed() -> void:
|
||||
current_filter_type = "全部"
|
||||
update_item_store_ui()
|
||||
Toast.show("显示全部道具", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
#筛选宠物类型道具
|
||||
func _on_pet_filter_pressed() -> void:
|
||||
current_filter_type = "宠物道具"
|
||||
update_item_store_ui()
|
||||
Toast.show("筛选宠物道具", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
#筛选作物类型道具
|
||||
func _on_crop_filter_pressed() -> void:
|
||||
current_filter_type = "作物道具"
|
||||
update_item_store_ui()
|
||||
Toast.show("筛选作物道具", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
#筛选农场类型道具
|
||||
func _on_farm_filter_pressed() -> void:
|
||||
current_filter_type = "农场道具"
|
||||
update_item_store_ui()
|
||||
Toast.show("筛选农场道具", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
# 检查道具是否符合当前筛选条件
|
||||
func _is_item_match_filter(item_name: String) -> bool:
|
||||
# 如果是显示全部,直接返回true
|
||||
if current_filter_type == "全部":
|
||||
return true
|
||||
|
||||
# 检查道具配置中的类型
|
||||
if item_config.has(item_name):
|
||||
var item_info = item_config[item_name]
|
||||
var item_type = item_info.get("类型", "")
|
||||
return item_type == current_filter_type
|
||||
|
||||
# 如果没有配置信息,默认不显示
|
||||
return false
|
||||
#========================筛选功能============================
|
||||
@@ -0,0 +1 @@
|
||||
uid://bruqwi63myl1m
|
||||
579
SproutFarm-Frontend/Script/BigPanel/LoginPanel.gd
Normal file
579
SproutFarm-Frontend/Script/BigPanel/LoginPanel.gd
Normal file
@@ -0,0 +1,579 @@
|
||||
#玩家登录注册面板
|
||||
extends PanelContainer
|
||||
|
||||
#默认显示登录面板(登录面板可以进入注册面板和忘记密码面板)
|
||||
@onready var login_v_box: VBoxContainer = $LoginVBox #显示或隐藏登录面板
|
||||
@onready var user_name: HBoxContainer = $LoginVBox/UserName #玩家账号
|
||||
@onready var password: HBoxContainer = $LoginVBox/Password #玩家密码
|
||||
@onready var login_button: Button = $LoginVBox/LoginButton #登录按钮
|
||||
@onready var register_button: Button = $LoginVBox/RegisterButton #注册按钮,点击后隐藏登录面板显示注册面板
|
||||
@onready var forget_passwd_button: Button = $LoginVBox/ForgetPasswdButton #忘记密码按钮,点击后隐藏登录面板显示忘记密码面板
|
||||
@onready var status_label: Label = $LoginVBox/status_label #登录状态
|
||||
|
||||
# 登录面板输入框
|
||||
@onready var username_input: LineEdit = $LoginVBox/UserName/username_input
|
||||
@onready var password_input: LineEdit = $LoginVBox/Password/password_input
|
||||
|
||||
#注册面板,注册成功跳转回登录面板
|
||||
@onready var register_vbox: VBoxContainer = $RegisterVbox #显示或隐藏注册面板
|
||||
@onready var register_user_name: HBoxContainer = $RegisterVbox/RegisterUserName #注册玩家账号
|
||||
@onready var password_1: HBoxContainer = $RegisterVbox/Password1 #注册密码
|
||||
@onready var password_2: HBoxContainer = $RegisterVbox/Password2 #二次确认密码
|
||||
@onready var player_name: HBoxContainer = $RegisterVbox/PlayerName #注册玩家昵称
|
||||
@onready var farm_name: HBoxContainer = $RegisterVbox/FarmName #注册玩家农场名称
|
||||
@onready var verification_code: HBoxContainer = $RegisterVbox/VerificationCode #注册所需验证码
|
||||
@onready var register_button_2: Button = $RegisterVbox/RegisterButton2 #注册按钮
|
||||
@onready var status_label_2: Label = $RegisterVbox/status_label2 #注册状态
|
||||
|
||||
# 注册面板输入框
|
||||
@onready var register_username_input: LineEdit = $RegisterVbox/RegisterUserName/username_input
|
||||
@onready var password_input_1: LineEdit = $RegisterVbox/Password1/password_input
|
||||
@onready var password_input_2: LineEdit = $RegisterVbox/Password2/password_input2
|
||||
@onready var playername_input: LineEdit = $RegisterVbox/PlayerName/playername_input
|
||||
@onready var farmname_input: LineEdit = $RegisterVbox/FarmName/farmname_input
|
||||
@onready var verificationcode_input: LineEdit = $RegisterVbox/VerificationCode/verificationcode_input
|
||||
@onready var send_button: Button = $RegisterVbox/VerificationCode/SendButton
|
||||
|
||||
#忘记密码面板,设置新密码成功后同样跳转到登录面板
|
||||
@onready var forget_password_vbox: VBoxContainer = $ForgetPasswordVbox #显示或隐藏忘记密码面板
|
||||
@onready var forget_password_user_name: HBoxContainer = $ForgetPasswordVbox/ForgetPasswordUserName #忘记密码的玩家账号
|
||||
@onready var new_password: HBoxContainer = $ForgetPasswordVbox/NewPassword #设置该账号新的密码
|
||||
@onready var verification_code_2: HBoxContainer = $ForgetPasswordVbox/VerificationCode2 #忘记密码所需验证码
|
||||
@onready var forget_password_button: Button = $ForgetPasswordVbox/ForgetPasswordButton #设置新密码确认按钮
|
||||
@onready var status_label_3: Label = $ForgetPasswordVbox/status_label3 #设置新密码状态
|
||||
|
||||
# 忘记密码面板输入框
|
||||
@onready var forget_username_input: LineEdit = $ForgetPasswordVbox/ForgetPasswordUserName/username_input
|
||||
@onready var new_password_input: LineEdit = $ForgetPasswordVbox/NewPassword/password_input
|
||||
@onready var forget_verificationcode_input: LineEdit = $ForgetPasswordVbox/VerificationCode2/verificationcode_input
|
||||
@onready var forget_send_button: Button = $ForgetPasswordVbox/VerificationCode2/SendButton
|
||||
|
||||
|
||||
# 记住密码选项
|
||||
var remember_password : bool = true # 默认记住密码
|
||||
|
||||
# 引用主场景和全局函数
|
||||
@onready var main_game = get_node("/root/main")
|
||||
|
||||
@onready var lucky_draw_panel: LuckyDrawPanel = $'../LuckyDrawPanel'
|
||||
@onready var daily_check_in_panel: DailyCheckInPanel = $'../DailyCheckInPanel'
|
||||
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
|
||||
@onready var item_store_panel: Panel = $'../ItemStorePanel'
|
||||
@onready var item_bag_panel: Panel = $'../ItemBagPanel'
|
||||
@onready var pet_bag_panel: Panel = $'../PetBagPanel'
|
||||
@onready var player_bag_panel: Panel = $'../PlayerBagPanel'
|
||||
@onready var crop_warehouse_panel: Panel = $'../CropWarehousePanel'
|
||||
@onready var crop_store_panel: Panel = $'../CropStorePanel'
|
||||
@onready var player_ranking_panel: Panel = $'../PlayerRankingPanel'
|
||||
|
||||
|
||||
# 准备函数
|
||||
func _ready():
|
||||
self.show()
|
||||
|
||||
# 初始状态:只显示登录面板,隐藏注册和忘记密码面板
|
||||
login_v_box.show()
|
||||
register_vbox.hide()
|
||||
forget_password_vbox.hide()
|
||||
|
||||
# 连接按钮信号
|
||||
login_button.pressed.connect(self._on_login_button_pressed)
|
||||
register_button.pressed.connect(self._on_show_register_panel)
|
||||
forget_passwd_button.pressed.connect(self._on_forget_password_button_pressed)
|
||||
register_button_2.pressed.connect(self._on_register_button_2_pressed)
|
||||
forget_password_button.pressed.connect(self._on_forget_password_confirm_pressed)
|
||||
send_button.pressed.connect(self._on_send_button_pressed)
|
||||
forget_send_button.pressed.connect(self._on_forget_send_button_pressed)
|
||||
|
||||
# 加载保存的登录信息
|
||||
_load_login_info()
|
||||
|
||||
# 显示客户端版本号
|
||||
_display_version_info()
|
||||
|
||||
# 面板切换函数
|
||||
func _on_show_register_panel():
|
||||
"""切换到注册面板"""
|
||||
login_v_box.hide()
|
||||
register_vbox.show()
|
||||
forget_password_vbox.hide()
|
||||
status_label_2.text = "请填写注册信息"
|
||||
status_label_2.modulate = Color.WHITE
|
||||
|
||||
func _on_forget_password_button_pressed():
|
||||
"""切换到忘记密码面板"""
|
||||
login_v_box.hide()
|
||||
register_vbox.hide()
|
||||
forget_password_vbox.show()
|
||||
status_label_3.text = "请输入账号和新密码"
|
||||
status_label_3.modulate = Color.WHITE
|
||||
|
||||
# 处理登录按钮点击
|
||||
func _on_login_button_pressed():
|
||||
var user_name = username_input.text.strip_edges()
|
||||
var user_password = password_input.text.strip_edges()
|
||||
|
||||
# 验证输入
|
||||
if not _validate_login_input(user_name, user_password, status_label):
|
||||
return
|
||||
|
||||
# 检查网络连接
|
||||
if not await _ensure_network_connection(status_label):
|
||||
return
|
||||
|
||||
|
||||
# 禁用按钮,防止重复点击
|
||||
login_button.disabled = true
|
||||
|
||||
status_label.text = "正在登录,请稍候..."
|
||||
status_label.modulate = Color.YELLOW
|
||||
|
||||
# 如果启用了记住密码,保存登录信息
|
||||
if remember_password:
|
||||
_save_login_info(user_name, user_password)
|
||||
|
||||
tcp_network_manager_panel.sendLoginInfo(user_name, user_password)
|
||||
|
||||
# 更新主游戏数据
|
||||
main_game.user_name = user_name
|
||||
main_game.user_password = user_password
|
||||
|
||||
# 5秒后重新启用按钮(如果没有收到响应)
|
||||
await get_tree().create_timer(5.0).timeout
|
||||
if login_button.disabled:
|
||||
login_button.disabled = false
|
||||
status_label.text = "登录超时,请重试!"
|
||||
status_label.modulate = Color.RED
|
||||
|
||||
# 处理验证码发送按钮点击
|
||||
func _on_send_button_pressed():
|
||||
var user_name = register_username_input.text.strip_edges()
|
||||
|
||||
# 验证输入
|
||||
if not _validate_qq_input(user_name, status_label_2):
|
||||
return
|
||||
|
||||
# 检查网络连接
|
||||
if not await _ensure_network_connection(status_label_2):
|
||||
return
|
||||
|
||||
|
||||
# 禁用按钮,防止重复点击
|
||||
send_button.disabled = true
|
||||
|
||||
status_label_2.text = "正在发送验证码,请稍候..."
|
||||
status_label_2.modulate = Color.YELLOW
|
||||
|
||||
# 发送验证码请求
|
||||
tcp_network_manager_panel.sendVerificationCodeRequest(user_name)
|
||||
|
||||
# 60秒后重新启用按钮(或收到响应后提前启用)
|
||||
var timer = 60
|
||||
while timer > 0 and send_button.disabled:
|
||||
send_button.text = "重新发送(%d)" % timer
|
||||
await get_tree().create_timer(1.0).timeout
|
||||
timer -= 1
|
||||
|
||||
if send_button.disabled:
|
||||
send_button.disabled = false
|
||||
send_button.text = "发送验证码"
|
||||
|
||||
if status_label_2.text == "正在发送验证码,请稍候...":
|
||||
status_label_2.text = "验证码发送超时,请重试!"
|
||||
status_label_2.modulate = Color.RED
|
||||
|
||||
# 处理注册按钮点击
|
||||
func _on_register_button_2_pressed():
|
||||
var user_name = register_username_input.text.strip_edges()
|
||||
var user_password = password_input_1.text.strip_edges()
|
||||
var password_confirm = password_input_2.text.strip_edges()
|
||||
var player_name = playername_input.text.strip_edges()
|
||||
var farm_name = farmname_input.text.strip_edges()
|
||||
var verification_code = verificationcode_input.text.strip_edges()
|
||||
|
||||
# 验证输入
|
||||
if not _validate_register_input(user_name, user_password, password_confirm, player_name, farm_name, verification_code, status_label_2):
|
||||
return
|
||||
|
||||
# 检查网络连接
|
||||
if not await _ensure_network_connection(status_label_2):
|
||||
return
|
||||
|
||||
# 禁用按钮,防止重复点击
|
||||
register_button_2.disabled = true
|
||||
|
||||
status_label_2.text = "正在注册,请稍候..."
|
||||
status_label_2.modulate = Color.YELLOW
|
||||
|
||||
# 发送注册请求
|
||||
tcp_network_manager_panel.sendRegisterInfo(user_name, user_password, player_name, farm_name, verification_code)
|
||||
|
||||
# 5秒后重新启用按钮(如果没有收到响应)
|
||||
await get_tree().create_timer(5.0).timeout
|
||||
if register_button_2.disabled:
|
||||
register_button_2.disabled = false
|
||||
status_label_2.text = "注册超时,请重试!"
|
||||
status_label_2.modulate = Color.RED
|
||||
|
||||
# 忘记密码发送验证码按钮处理
|
||||
func _on_forget_send_button_pressed():
|
||||
var user_name = forget_username_input.text.strip_edges()
|
||||
|
||||
# 验证输入
|
||||
if not _validate_qq_input(user_name, status_label_3):
|
||||
return
|
||||
|
||||
# 检查网络连接
|
||||
if not await _ensure_network_connection(status_label_3):
|
||||
return
|
||||
|
||||
# 禁用按钮,防止重复点击
|
||||
forget_send_button.disabled = true
|
||||
|
||||
status_label_3.text = "正在发送验证码,请稍候..."
|
||||
status_label_3.modulate = Color.YELLOW
|
||||
|
||||
# 发送验证码请求(用于忘记密码)
|
||||
tcp_network_manager_panel.sendForgetPasswordVerificationCode(user_name)
|
||||
|
||||
# 60秒后重新启用按钮
|
||||
var timer = 60
|
||||
while timer > 0 and forget_send_button.disabled:
|
||||
forget_send_button.text = "重新发送(%d)" % timer
|
||||
await get_tree().create_timer(1.0).timeout
|
||||
timer -= 1
|
||||
|
||||
if forget_send_button.disabled:
|
||||
forget_send_button.disabled = false
|
||||
forget_send_button.text = "发送验证码"
|
||||
|
||||
if status_label_3.text == "正在发送验证码,请稍候...":
|
||||
status_label_3.text = "验证码发送超时,请重试!"
|
||||
status_label_3.modulate = Color.RED
|
||||
|
||||
# 忘记密码确认按钮处理
|
||||
func _on_forget_password_confirm_pressed():
|
||||
var user_name = forget_username_input.text.strip_edges()
|
||||
var new_password = new_password_input.text.strip_edges()
|
||||
var verification_code = forget_verificationcode_input.text.strip_edges()
|
||||
|
||||
# 验证输入
|
||||
if not _validate_forget_password_input(user_name, new_password, verification_code, status_label_3):
|
||||
return
|
||||
|
||||
# 检查网络连接
|
||||
if not await _ensure_network_connection(status_label_3):
|
||||
return
|
||||
|
||||
# 禁用按钮,防止重复点击
|
||||
forget_password_button.disabled = true
|
||||
|
||||
status_label_3.text = "正在重置密码,请稍候..."
|
||||
status_label_3.modulate = Color.YELLOW
|
||||
|
||||
# 发送忘记密码请求
|
||||
tcp_network_manager_panel.sendForgetPasswordRequest(user_name, new_password, verification_code)
|
||||
|
||||
# 5秒后重新启用按钮(如果没有收到响应)
|
||||
await get_tree().create_timer(5.0).timeout
|
||||
if forget_password_button.disabled:
|
||||
forget_password_button.disabled = false
|
||||
status_label_3.text = "重置密码超时,请重试!"
|
||||
status_label_3.modulate = Color.RED
|
||||
|
||||
# 处理验证码发送响应
|
||||
func _on_verification_code_response(success: bool, message: String):
|
||||
_set_status(status_label, message, Color.GREEN if success else Color.RED)
|
||||
if not success:
|
||||
send_button.disabled = false
|
||||
send_button.text = "发送验证码"
|
||||
|
||||
# 处理验证码验证响应
|
||||
func _on_verify_code_response(success: bool, message: String):
|
||||
_set_status(status_label, message, Color.GREEN if success else Color.RED)
|
||||
|
||||
# 输入验证函数
|
||||
func is_valid_qq_number(qq_number: String) -> bool:
|
||||
var qq_regex = RegEx.new()
|
||||
if qq_regex.compile(r"^\d{5,12}$") != OK:
|
||||
return false
|
||||
return qq_regex.search(qq_number) != null
|
||||
|
||||
func is_valid_password(password: String) -> bool:
|
||||
return password.match(r"^[a-zA-Z0-9]+$") != null
|
||||
|
||||
# 处理登录响应
|
||||
func _on_login_response_received(success: bool, message: String, user_data: Dictionary):
|
||||
login_button.disabled = false
|
||||
|
||||
if success:
|
||||
_set_status(status_label, "登录成功!正在加载游戏...", Color.GREEN)
|
||||
_handle_login_success(user_data)
|
||||
else:
|
||||
_set_status(status_label, "登录失败:" + message, Color.RED)
|
||||
if "密码" in message or "password" in message.to_lower():
|
||||
print("登录失败,可能是密码错误。如需清除保存的登录信息,请调用_clear_login_info()")
|
||||
|
||||
# 处理注册响应
|
||||
func _on_register_response_received(success: bool, message: String):
|
||||
register_button_2.disabled = false
|
||||
|
||||
if success:
|
||||
_set_status(status_label_2, "注册成功!请登录游戏", Color.GREEN)
|
||||
_handle_register_success()
|
||||
else:
|
||||
_set_status(status_label_2, "注册失败:" + message, Color.RED)
|
||||
|
||||
# 处理忘记密码响应
|
||||
func _on_forget_password_response_received(success: bool, message: String):
|
||||
forget_password_button.disabled = false
|
||||
|
||||
if success:
|
||||
_set_status(status_label_3, "密码重置成功!请使用新密码登录", Color.GREEN)
|
||||
_handle_forget_password_success()
|
||||
else:
|
||||
_set_status(status_label_3, "密码重置失败:" + message, Color.RED)
|
||||
|
||||
# 登录信息文件操作
|
||||
func _save_login_info(user_name: String, password: String):
|
||||
_write_login_file({"玩家账号": user_name, "password": password})
|
||||
print("登录信息已保存" if user_name != "" else "登录信息已清除")
|
||||
|
||||
func _load_login_info():
|
||||
var login_data = _read_login_file()
|
||||
if login_data:
|
||||
var saved_username = login_data.get("玩家账号", "")
|
||||
var saved_password = login_data.get("password", "")
|
||||
|
||||
if saved_username != "" and saved_password != "":
|
||||
username_input.text = saved_username
|
||||
password_input.text = saved_password
|
||||
_set_status(status_label, "已加载保存的登录信息", Color.CYAN)
|
||||
print("登录信息已加载:用户名 =", saved_username)
|
||||
return
|
||||
|
||||
_set_status(status_label, "欢迎使用萌芽农场", Color.WHITE)
|
||||
print("没有有效的保存登录信息")
|
||||
|
||||
func _clear_login_info():
|
||||
_save_login_info("", "")
|
||||
|
||||
func _write_login_file(data: Dictionary):
|
||||
var file = FileAccess.open("user://login.json", FileAccess.WRITE)
|
||||
if file:
|
||||
file.store_string(JSON.stringify(data, "\t"))
|
||||
file.close()
|
||||
|
||||
func _read_login_file() -> Dictionary:
|
||||
var file = FileAccess.open("user://login.json", FileAccess.READ)
|
||||
if not file:
|
||||
_write_login_file({"玩家账号": "", "password": ""})
|
||||
return {}
|
||||
|
||||
var json_text = file.get_as_text()
|
||||
file.close()
|
||||
|
||||
var json = JSON.new()
|
||||
if json.parse(json_text) == OK:
|
||||
return json.get_data()
|
||||
return {}
|
||||
|
||||
# 记住密码和快捷登录功能
|
||||
func toggle_remember_password():
|
||||
remember_password = !remember_password
|
||||
print("记住密码选项:", "开启" if remember_password else "关闭")
|
||||
if not remember_password:
|
||||
_clear_login_info()
|
||||
|
||||
func has_saved_login_info() -> bool:
|
||||
var login_data = _read_login_file()
|
||||
return login_data.get("玩家账号", "") != "" and login_data.get("password", "") != ""
|
||||
|
||||
func quick_login():
|
||||
if has_saved_login_info():
|
||||
var user_name = username_input.text.strip_edges()
|
||||
var user_password = password_input.text.strip_edges()
|
||||
|
||||
if user_name != "" and user_password != "":
|
||||
print("执行快捷登录...")
|
||||
_on_login_button_pressed()
|
||||
else:
|
||||
_set_status(status_label, "保存的登录信息不完整", Color.ORANGE)
|
||||
else:
|
||||
_set_status(status_label, "没有保存的登录信息", Color.ORANGE)
|
||||
|
||||
func get_saved_username() -> String:
|
||||
return _read_login_file().get("玩家账号", "")
|
||||
|
||||
# 显示版本信息
|
||||
func _display_version_info():
|
||||
if status_label.text in ["欢迎使用萌芽农场", "连接状态"]:
|
||||
_set_status(status_label, "萌芽农场 v" + main_game.client_version + " - 欢迎使用", Color.CYAN)
|
||||
|
||||
|
||||
# 登录成功处理
|
||||
func _handle_login_success(user_data: Dictionary):
|
||||
# 保存登录数据到主游戏
|
||||
main_game.login_data = user_data.duplicate()
|
||||
main_game.remaining_likes = user_data.get("点赞系统", {}).get("今日剩余点赞次数", 10)
|
||||
|
||||
# 更新主游戏数据
|
||||
main_game.experience = user_data.get("经验值", 0)
|
||||
main_game.farm_lots = user_data.get("农场土地", [])
|
||||
main_game.level = user_data.get("等级", 1)
|
||||
main_game.money = user_data.get("钱币", 0)
|
||||
main_game.stamina = user_data.get("体力值", 20)
|
||||
main_game.show_farm_name.text = "农场名称:" + user_data.get("农场名称", "")
|
||||
main_game.show_player_name.text = "玩家昵称:" + user_data.get("玩家昵称", "")
|
||||
farmname_input.text = user_data.get("农场名称", "")
|
||||
|
||||
# 加载各种背包数据
|
||||
main_game.player_bag = user_data.get("种子仓库", [])
|
||||
main_game.crop_warehouse = user_data.get("作物仓库", [])
|
||||
main_game.item_bag = user_data.get("道具背包", [])
|
||||
main_game.pet_bag = user_data.get("宠物背包", [])
|
||||
main_game.patrol_pets = user_data.get("巡逻宠物", [])
|
||||
main_game.battle_pets = user_data.get("出战宠物", [])
|
||||
|
||||
# 启动游戏并隐藏登录面板
|
||||
main_game.start_game = true
|
||||
self.hide()
|
||||
|
||||
# 更新UI
|
||||
main_game._update_ui()
|
||||
main_game._refresh_farm_lots()
|
||||
player_bag_panel.update_player_bag_ui()
|
||||
crop_warehouse_panel.update_crop_warehouse_ui()
|
||||
item_bag_panel.update_item_bag_ui()
|
||||
|
||||
if pet_bag_panel and pet_bag_panel.has_method("update_pet_bag_ui"):
|
||||
pet_bag_panel.update_pet_bag_ui()
|
||||
if main_game.has_method("init_patrol_pets"):
|
||||
main_game.init_patrol_pets()
|
||||
|
||||
main_game.handle_login_success(user_data)
|
||||
|
||||
if main_game.game_setting_panel and main_game.game_setting_panel.has_method("refresh_settings"):
|
||||
main_game.game_setting_panel.refresh_settings()
|
||||
|
||||
# 注册成功处理
|
||||
func _handle_register_success():
|
||||
if remember_password:
|
||||
var user_name = register_username_input.text.strip_edges()
|
||||
var user_password = password_input_1.text.strip_edges()
|
||||
_save_login_info(user_name, user_password)
|
||||
|
||||
# 清除注册相关的输入框
|
||||
password_input_2.text = ""
|
||||
verificationcode_input.text = ""
|
||||
|
||||
# 切换回登录面板
|
||||
_switch_to_login_panel()
|
||||
|
||||
# 如果记住密码,自动填充登录信息
|
||||
if remember_password:
|
||||
username_input.text = register_username_input.text
|
||||
password_input.text = password_input_1.text
|
||||
|
||||
# 忘记密码成功处理
|
||||
func _handle_forget_password_success():
|
||||
if remember_password:
|
||||
var user_name = forget_username_input.text.strip_edges()
|
||||
var new_password = new_password_input.text.strip_edges()
|
||||
_save_login_info(user_name, new_password)
|
||||
|
||||
# 清除输入框
|
||||
forget_verificationcode_input.text = ""
|
||||
|
||||
# 切换回登录面板并自动填充账号信息
|
||||
_switch_to_login_panel()
|
||||
username_input.text = forget_username_input.text
|
||||
password_input.text = new_password_input.text
|
||||
_set_status(status_label, "密码已重置,请登录", Color.GREEN)
|
||||
|
||||
# 切换到登录面板
|
||||
func _switch_to_login_panel():
|
||||
register_vbox.hide()
|
||||
forget_password_vbox.hide()
|
||||
login_v_box.show()
|
||||
|
||||
# 公共验证函数
|
||||
func _validate_login_input(user_name: String, password: String, label: Label) -> bool:
|
||||
if user_name.is_empty() or password.is_empty():
|
||||
_set_status(label, "用户名或密码不能为空!", Color.RED)
|
||||
return false
|
||||
return true
|
||||
|
||||
func _validate_register_input(user_name: String, password: String, password_confirm: String, player_name: String, farm_name: String, verification_code: String, label: Label) -> bool:
|
||||
if user_name.is_empty() or password.is_empty() or password_confirm.is_empty() or player_name.is_empty() or farm_name.is_empty():
|
||||
_set_status(label, "所有字段都不能为空!", Color.RED)
|
||||
return false
|
||||
if password != password_confirm:
|
||||
_set_status(label, "两次输入的密码不一致!", Color.RED)
|
||||
return false
|
||||
if not is_valid_qq_number(user_name):
|
||||
_set_status(label, "请输入有效的QQ号(5-12位数字)!", Color.RED)
|
||||
return false
|
||||
if not is_valid_password(password):
|
||||
_set_status(label, "密码只能包含数字和字母!", Color.RED)
|
||||
return false
|
||||
if verification_code.is_empty():
|
||||
_set_status(label, "验证码不能为空!", Color.RED)
|
||||
return false
|
||||
return true
|
||||
|
||||
func _validate_qq_input(user_name: String, label: Label) -> bool:
|
||||
if user_name.is_empty():
|
||||
_set_status(label, "请输入QQ号以接收验证码!", Color.RED)
|
||||
return false
|
||||
if not is_valid_qq_number(user_name):
|
||||
_set_status(label, "请输入正确的QQ号码(5-12位数字)!", Color.RED)
|
||||
return false
|
||||
return true
|
||||
|
||||
func _validate_forget_password_input(user_name: String, new_password: String, verification_code: String, label: Label) -> bool:
|
||||
if user_name.is_empty() or new_password.is_empty():
|
||||
_set_status(label, "用户名或新密码不能为空!", Color.RED)
|
||||
return false
|
||||
if not is_valid_qq_number(user_name):
|
||||
_set_status(label, "请输入正确的QQ号码(5-12位数字)!", Color.RED)
|
||||
return false
|
||||
if not is_valid_password(new_password):
|
||||
_set_status(label, "密码只能包含数字和字母!", Color.RED)
|
||||
return false
|
||||
if verification_code.is_empty():
|
||||
_set_status(label, "请输入验证码!", Color.RED)
|
||||
return false
|
||||
return true
|
||||
|
||||
# 公共网络连接检查函数
|
||||
func _ensure_network_connection(label: Label) -> bool:
|
||||
if not tcp_network_manager_panel.client.is_client_connected():
|
||||
_set_status(label, "未连接到服务器,正在尝试连接...", Color.YELLOW)
|
||||
tcp_network_manager_panel.connect_to_current_server()
|
||||
await get_tree().create_timer(2.0).timeout
|
||||
|
||||
if not tcp_network_manager_panel.client.is_client_connected():
|
||||
_set_status(label, "连接服务器失败,正在尝试其他服务器...", Color.YELLOW)
|
||||
await get_tree().create_timer(3.0).timeout
|
||||
return false
|
||||
return true
|
||||
|
||||
# 公共状态设置函数
|
||||
func _set_status(label: Label, text: String, color: Color):
|
||||
label.text = text
|
||||
label.modulate = color
|
||||
|
||||
#面板显示与隐藏切换处理
|
||||
func _on_visibility_changed():
|
||||
GlobalVariables.isZoomDisabled = visible
|
||||
|
||||
#注册面板返回登录面板
|
||||
func _on_register_2_login_button_pressed() -> void:
|
||||
_switch_to_login_panel()
|
||||
pass
|
||||
|
||||
#找回密码面板返回登录面板
|
||||
func _on_forget_2_login_button_pressed() -> void:
|
||||
_switch_to_login_panel()
|
||||
pass
|
||||
1
SproutFarm-Frontend/Script/BigPanel/LoginPanel.gd.uid
Normal file
1
SproutFarm-Frontend/Script/BigPanel/LoginPanel.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://cka0r4g8tbf0
|
||||
414
SproutFarm-Frontend/Script/BigPanel/LuckyDrawPanel.gd
Normal file
414
SproutFarm-Frontend/Script/BigPanel/LuckyDrawPanel.gd
Normal file
@@ -0,0 +1,414 @@
|
||||
extends Panel
|
||||
class_name LuckyDrawPanel
|
||||
|
||||
signal draw_completed(rewards: Array, draw_type: String)
|
||||
signal draw_failed(error_message: String)
|
||||
|
||||
@onready var lucky_draw_reward: RichTextLabel = $LuckyDrawReward
|
||||
@onready var grid: GridContainer = $Grid
|
||||
@onready var reward_item: RichTextLabel = $Grid/RewardItem
|
||||
@onready var main_game = get_node("/root/main")
|
||||
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
|
||||
|
||||
@onready var confirm_dialog: ConfirmationDialog = $ConfirmDialog #确认弹窗
|
||||
|
||||
|
||||
var reward_templates: Array[RichTextLabel] = []
|
||||
var current_rewards: Array = []
|
||||
var seed_rewards: Dictionary = {}
|
||||
var anticipation_tween: Tween = null
|
||||
|
||||
# 15种模板颜色
|
||||
var template_colors: Array[Color] = [
|
||||
Color(1.0, 0.8, 0.8, 1.0), Color(0.8, 1.0, 0.8, 1.0), Color(0.8, 0.8, 1.0, 1.0),
|
||||
Color(1.0, 1.0, 0.8, 1.0), Color(1.0, 0.8, 1.0, 1.0), Color(0.8, 1.0, 1.0, 1.0),
|
||||
Color(1.0, 0.9, 0.8, 1.0), Color(0.9, 0.8, 1.0, 1.0), Color(0.8, 1.0, 0.9, 1.0),
|
||||
Color(1.0, 0.8, 0.9, 1.0), Color(0.9, 1.0, 0.8, 1.0), Color(0.8, 0.9, 1.0, 1.0),
|
||||
Color(1.0, 0.95, 0.8, 1.0), Color(0.85, 0.8, 1.0, 1.0), Color(0.95, 1.0, 0.85, 1.0)
|
||||
]
|
||||
|
||||
var base_rewards: Dictionary = {
|
||||
"coins": {"name": "金币", "icon": "💰", "color": "#FFD700"},
|
||||
"exp": {"name": "经验", "icon": "⭐", "color": "#00BFFF"},
|
||||
"empty": {"name": "谢谢惠顾", "icon": "😅", "color": "#CCCCCC"}
|
||||
}
|
||||
|
||||
var draw_costs: Dictionary = {
|
||||
"single": 800,
|
||||
"five": 3600,
|
||||
"ten": 6400
|
||||
}
|
||||
|
||||
func _ready() -> void:
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
_initialize_system()
|
||||
|
||||
func _initialize_system() -> void:
|
||||
if main_game:
|
||||
draw_completed.connect(main_game._on_lucky_draw_completed)
|
||||
draw_failed.connect(main_game._on_lucky_draw_failed)
|
||||
|
||||
lucky_draw_reward.hide()
|
||||
_load_crop_data_and_build_rewards()
|
||||
_generate_reward_templates()
|
||||
_update_template_display()
|
||||
|
||||
func _load_crop_data_and_build_rewards() -> void:
|
||||
if main_game and main_game.has_method("get_crop_data"):
|
||||
var crop_data = main_game.get_crop_data()
|
||||
if crop_data:
|
||||
_build_seed_rewards_from_crop_data(crop_data)
|
||||
|
||||
func _build_seed_rewards_from_crop_data(crop_data: Dictionary) -> void:
|
||||
seed_rewards.clear()
|
||||
|
||||
for crop_name in crop_data.keys():
|
||||
var crop_info = crop_data[crop_name]
|
||||
|
||||
if crop_name == "测试作物" or not crop_info.get("能否购买", true):
|
||||
continue
|
||||
|
||||
var quality = crop_info.get("品质", "普通")
|
||||
var rarity_color = _get_rarity_color(quality)
|
||||
|
||||
seed_rewards[crop_name] = {
|
||||
"icon": "🌱",
|
||||
"color": rarity_color,
|
||||
"rarity": quality,
|
||||
"等级": crop_info.get("等级", 1),
|
||||
"cost": crop_info.get("花费", 50)
|
||||
}
|
||||
|
||||
func _get_rarity_color(rarity: String) -> String:
|
||||
match rarity:
|
||||
"普通": return "#90EE90"
|
||||
"优良": return "#87CEEB"
|
||||
"稀有": return "#DDA0DD"
|
||||
"史诗": return "#9932CC"
|
||||
"传奇": return "#FF8C00"
|
||||
_: return "#FFFFFF"
|
||||
|
||||
func _generate_reward_templates() -> void:
|
||||
for child in grid.get_children():
|
||||
if child != reward_item:
|
||||
child.queue_free()
|
||||
|
||||
reward_templates.clear()
|
||||
|
||||
for i in range(15):
|
||||
var template: RichTextLabel
|
||||
|
||||
if i == 0:
|
||||
template = reward_item
|
||||
else:
|
||||
template = reward_item.duplicate()
|
||||
grid.add_child(template)
|
||||
|
||||
template.self_modulate = template_colors[i]
|
||||
template.bbcode_enabled = true
|
||||
template.threaded = true
|
||||
reward_templates.append(template)
|
||||
|
||||
func _update_template_display() -> void:
|
||||
var sample_rewards = _generate_sample_rewards()
|
||||
|
||||
for i in range(reward_templates.size()):
|
||||
var template = reward_templates[i]
|
||||
if i < sample_rewards.size():
|
||||
var reward = sample_rewards[i]
|
||||
template.text = _format_template_text(reward)
|
||||
template.show()
|
||||
else:
|
||||
template.hide()
|
||||
|
||||
func _generate_sample_rewards() -> Array:
|
||||
var sample_rewards = []
|
||||
|
||||
sample_rewards.append({"type": "coins", "amount_range": [100, 300], "rarity": "普通"})
|
||||
sample_rewards.append({"type": "exp", "amount_range": [50, 150], "rarity": "普通"})
|
||||
sample_rewards.append({"type": "empty", "name": "谢谢惠顾", "rarity": "空奖"})
|
||||
|
||||
var quality_examples = ["普通", "优良", "稀有", "史诗", "传奇"]
|
||||
for quality in quality_examples:
|
||||
var example_seeds = []
|
||||
for seed_name in seed_rewards.keys():
|
||||
if seed_rewards[seed_name].rarity == quality:
|
||||
example_seeds.append(seed_name)
|
||||
|
||||
if example_seeds.size() > 0:
|
||||
var seed_name = example_seeds[0]
|
||||
sample_rewards.append({
|
||||
"type": "seed",
|
||||
"name": seed_name,
|
||||
"rarity": quality,
|
||||
"amount_range": [1, 3] if quality != "传奇" else [1, 1]
|
||||
})
|
||||
|
||||
sample_rewards.append({"type": "package", "name": "成长套餐", "rarity": "优良"})
|
||||
sample_rewards.append({"type": "package", "name": "稀有礼包", "rarity": "稀有"})
|
||||
sample_rewards.append({"type": "package", "name": "传奇大礼包", "rarity": "传奇"})
|
||||
sample_rewards.append({"type": "coins", "amount_range": [1000, 2000], "rarity": "史诗"})
|
||||
sample_rewards.append({"type": "exp", "amount_range": [500, 1000], "rarity": "传奇"})
|
||||
|
||||
return sample_rewards.slice(0, 15)
|
||||
|
||||
func _format_template_text(reward: Dictionary) -> String:
|
||||
var text = "[center]"
|
||||
|
||||
match reward.type:
|
||||
"empty":
|
||||
text += "[color=%s]%s[/color]\n" % [base_rewards.empty.color, base_rewards.empty.icon]
|
||||
text += "[color=%s]%s[/color]" % [base_rewards.empty.color, reward.get("name", "谢谢惠顾")]
|
||||
|
||||
"package":
|
||||
var rarity_color = _get_rarity_color(reward.get("rarity", "普通"))
|
||||
text += "[color=%s]🎁[/color]\n" % [rarity_color]
|
||||
text += "[color=%s]%s[/color]\n" % [rarity_color, reward.get("name", "礼包")]
|
||||
text += "[color=#CCCCCC](%s)[/color]" % reward.get("rarity", "普通")
|
||||
|
||||
"coins":
|
||||
var rarity_color = _get_rarity_color(reward.get("rarity", "普通"))
|
||||
text += "[color=%s]%s[/color]\n" % [rarity_color, base_rewards.coins.icon]
|
||||
if reward.has("amount_range"):
|
||||
text += "[color=%s]%d-%d[/color]\n" % [rarity_color, reward.amount_range[0], reward.amount_range[1]]
|
||||
text += "[color=%s]%s[/color]" % [rarity_color, base_rewards.coins.name]
|
||||
|
||||
"exp":
|
||||
var rarity_color = _get_rarity_color(reward.get("rarity", "普通"))
|
||||
text += "[color=%s]%s[/color]\n" % [rarity_color, base_rewards.exp.icon]
|
||||
if reward.has("amount_range"):
|
||||
text += "[color=%s]%d-%d[/color]\n" % [rarity_color, reward.amount_range[0], reward.amount_range[1]]
|
||||
text += "[color=%s]%s[/color]" % [rarity_color, base_rewards.exp.name]
|
||||
|
||||
"seed":
|
||||
if reward.has("name") and reward.name in seed_rewards:
|
||||
var seed_info = seed_rewards[reward.name]
|
||||
text += "[color=%s]%s[/color]\n" % [seed_info.color, seed_info.icon]
|
||||
text += "[color=%s]%s[/color]\n" % [seed_info.color, reward.name]
|
||||
if reward.has("amount_range"):
|
||||
text += "[color=%s]x%d-%d[/color]\n" % [seed_info.color, reward.amount_range[0], reward.amount_range[1]]
|
||||
text += "[color=#CCCCCC](%s)[/color]" % seed_info.rarity
|
||||
else:
|
||||
text += "[color=#90EE90]🌱[/color]\n"
|
||||
text += "[color=#90EE90]种子[/color]"
|
||||
|
||||
text += "[/center]"
|
||||
return text
|
||||
|
||||
func _perform_network_draw(draw_type: String) -> void:
|
||||
if not tcp_network_manager_panel or not tcp_network_manager_panel.is_connected_to_server():
|
||||
_show_error_message("网络未连接,无法进行抽奖")
|
||||
return
|
||||
|
||||
var cost = draw_costs.get(draw_type, 800)
|
||||
if main_game and main_game.money < cost:
|
||||
_show_error_message("金币不足,需要 %d 金币" % cost)
|
||||
return
|
||||
|
||||
var success = tcp_network_manager_panel.sendLuckyDraw(draw_type)
|
||||
if not success:
|
||||
_show_error_message("发送抽奖请求失败")
|
||||
return
|
||||
|
||||
_show_waiting_animation()
|
||||
|
||||
func _show_waiting_animation() -> void:
|
||||
_set_draw_buttons_enabled(false)
|
||||
lucky_draw_reward.hide()
|
||||
|
||||
func handle_lucky_draw_response(response: Dictionary) -> void:
|
||||
_set_draw_buttons_enabled(true)
|
||||
|
||||
if response.get("success", false):
|
||||
var rewards = response.get("rewards", [])
|
||||
var draw_type = response.get("draw_type", "single")
|
||||
var cost = response.get("cost", 0)
|
||||
|
||||
_show_server_draw_results(rewards, draw_type, cost)
|
||||
draw_completed.emit(rewards, draw_type)
|
||||
else:
|
||||
var error_message = response.get("message", "抽奖失败")
|
||||
_show_error_message(error_message)
|
||||
draw_failed.emit(error_message)
|
||||
|
||||
func _show_server_draw_results(rewards: Array, draw_type: String, cost: int) -> void:
|
||||
current_rewards = rewards
|
||||
|
||||
var result_text = _format_server_draw_results(rewards, draw_type, cost)
|
||||
lucky_draw_reward.text = result_text
|
||||
lucky_draw_reward.show()
|
||||
|
||||
|
||||
func _format_server_draw_results(rewards: Array, draw_type: String, cost: int) -> String:
|
||||
var type_names = {"single": "单抽", "five": "五连抽", "ten": "十连抽"}
|
||||
|
||||
var text = "[center][color=#FFD700]🎊 %s结果 🎊[/color][/center]\n" % type_names.get(draw_type, draw_type)
|
||||
text += "[center][color=#87CEEB]消费 %d 金币[/color][/center]\n" % cost
|
||||
|
||||
var stats = _count_server_reward_rarity(rewards)
|
||||
|
||||
var stat_parts = []
|
||||
if stats.legendary > 0:
|
||||
stat_parts.append("[color=#FF8C00]🏆传奇x%d[/color]" % stats.legendary)
|
||||
if stats.epic > 0:
|
||||
stat_parts.append("[color=#9932CC]💎史诗x%d[/color]" % stats.epic)
|
||||
if stats.rare > 0:
|
||||
stat_parts.append("[color=#DDA0DD]⭐稀有x%d[/color]" % stats.rare)
|
||||
if stats.package > 0:
|
||||
stat_parts.append("[color=#FF69B4]🎁礼包x%d[/color]" % stats.package)
|
||||
|
||||
if stat_parts.size() > 0:
|
||||
text += "[center]%s[/center]\n" % " ".join(stat_parts)
|
||||
|
||||
text += "\n"
|
||||
|
||||
for reward in rewards:
|
||||
text += _format_single_server_reward(reward) + "\n"
|
||||
|
||||
if stats.empty_only:
|
||||
text += "[center][color=#87CEEB]💪 别灰心,下次一定能中大奖![/color][/center]"
|
||||
elif stats.legendary > 0:
|
||||
text += "[center][color=#FF8C00]🎉 恭喜获得传奇奖励![/color][/center]"
|
||||
elif stats.epic > 0:
|
||||
text += "[center][color=#9932CC]✨ 史诗奖励,运气不错![/color][/center]"
|
||||
|
||||
return text
|
||||
|
||||
func _count_server_reward_rarity(rewards: Array) -> Dictionary:
|
||||
var stats = {"legendary": 0, "epic": 0, "rare": 0, "package": 0, "empty": 0, "empty_only": false}
|
||||
|
||||
for reward in rewards:
|
||||
var rarity = reward.get("rarity", "普通")
|
||||
match rarity:
|
||||
"传奇": stats.legendary += 1
|
||||
"史诗": stats.epic += 1
|
||||
"稀有": stats.rare += 1
|
||||
"空奖": stats.empty += 1
|
||||
|
||||
if reward.get("type") == "package":
|
||||
stats.package += 1
|
||||
|
||||
stats.empty_only = (stats.empty == rewards.size() and rewards.size() == 1)
|
||||
return stats
|
||||
|
||||
func _format_single_server_reward(reward: Dictionary) -> String:
|
||||
var reward_type = reward.get("type", "")
|
||||
var rarity = reward.get("rarity", "普通")
|
||||
var rarity_color = _get_rarity_color(rarity)
|
||||
|
||||
match reward_type:
|
||||
"empty":
|
||||
return "[color=%s]😅 %s[/color]" % [rarity_color, reward.get("name", "空奖励")]
|
||||
|
||||
"package":
|
||||
var text = "[color=%s]🎁 %s[/color]\n" % [rarity_color, reward.get("name", "礼包")]
|
||||
text += "[color=#DDDDDD]内含:[/color] "
|
||||
|
||||
var content_parts = []
|
||||
if reward.has("contents"):
|
||||
for content in reward.contents:
|
||||
var part = _format_package_content(content)
|
||||
if part != "":
|
||||
content_parts.append(part)
|
||||
|
||||
text += " ".join(content_parts)
|
||||
return text
|
||||
|
||||
"coins":
|
||||
return "[color=%s]💰 金币 +%d[/color]" % [rarity_color, reward.get("amount", 0)]
|
||||
|
||||
"exp":
|
||||
return "[color=%s]⭐ 经验 +%d[/color]" % [rarity_color, reward.get("amount", 0)]
|
||||
|
||||
"seed":
|
||||
return "[color=%s]🌱 %s x%d[/color] [color=#CCCCCC](%s)[/color]" % [
|
||||
rarity_color, reward.get("name", "种子"), reward.get("amount", 0), rarity
|
||||
]
|
||||
|
||||
_:
|
||||
return "[color=#CCCCCC]未知奖励[/color]"
|
||||
|
||||
func _format_package_content(content: Dictionary) -> String:
|
||||
var content_type = content.get("type", "")
|
||||
var amount = content.get("amount", 0)
|
||||
|
||||
match content_type:
|
||||
"coins": return "[color=#FFD700]💰%d[/color]" % amount
|
||||
"exp": return "[color=#00BFFF]⭐%d[/color]" % amount
|
||||
"seed": return "[color=#90EE90]🌱%sx%d[/color]" % [content.get("name", "种子"), amount]
|
||||
_: return ""
|
||||
|
||||
|
||||
func _anticipation_flash(template: RichTextLabel, progress: float) -> void:
|
||||
var flash_intensity = 1.0 + sin(progress * PI * 2) * 0.2
|
||||
template.modulate = Color(flash_intensity, flash_intensity, flash_intensity, 1.0)
|
||||
|
||||
|
||||
func _show_error_message(message: String) -> void:
|
||||
lucky_draw_reward.text = "[center][color=#FF6B6B]❌ %s[/color][/center]" % message
|
||||
lucky_draw_reward.show()
|
||||
|
||||
await get_tree().create_timer(2.0).timeout
|
||||
lucky_draw_reward.hide()
|
||||
|
||||
func _set_draw_buttons_enabled(enabled: bool) -> void:
|
||||
var buttons = [
|
||||
$HBox/LuckyDrawButton,
|
||||
$HBox/FiveLuckyDrawButton,
|
||||
$HBox/TenLuckyDrawButton
|
||||
]
|
||||
|
||||
for button in buttons:
|
||||
if button:
|
||||
button.disabled = not enabled
|
||||
|
||||
# 事件处理
|
||||
func _on_quit_button_pressed() -> void:
|
||||
self.hide()
|
||||
|
||||
func _on_lucky_draw_button_pressed() -> void:
|
||||
_show_draw_confirmation("single")
|
||||
|
||||
func _on_five_lucky_draw_button_pressed() -> void:
|
||||
_show_draw_confirmation("five")
|
||||
|
||||
func _on_ten_lucky_draw_button_pressed() -> void:
|
||||
_show_draw_confirmation("ten")
|
||||
|
||||
func _show_draw_confirmation(draw_type: String) -> void:
|
||||
var cost = draw_costs.get(draw_type, 800)
|
||||
var type_names = {"single": "单抽", "five": "五连抽", "ten": "十连抽"}
|
||||
var type_name = type_names.get(draw_type, draw_type)
|
||||
|
||||
confirm_dialog.title = "幸运抽奖确认"
|
||||
confirm_dialog.dialog_text = "确定要进行%s吗?\n需要花费 %d 金币\n\n可能获得金币、经验、种子等奖励!" % [type_name, cost]
|
||||
confirm_dialog.popup_centered()
|
||||
|
||||
# 保存当前抽奖类型
|
||||
confirm_dialog.set_meta("draw_type", draw_type)
|
||||
|
||||
# 连接确认信号(如果还没连接的话)
|
||||
if not confirm_dialog.confirmed.is_connected(_on_confirm_draw):
|
||||
confirm_dialog.confirmed.connect(_on_confirm_draw)
|
||||
|
||||
func _on_confirm_draw() -> void:
|
||||
var draw_type = confirm_dialog.get_meta("draw_type", "single")
|
||||
_perform_network_draw(draw_type)
|
||||
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
|
||||
# 公共接口
|
||||
func get_current_rewards() -> Array:
|
||||
return current_rewards
|
||||
|
||||
func clear_draw_results() -> void:
|
||||
current_rewards.clear()
|
||||
lucky_draw_reward.hide()
|
||||
|
||||
func refresh_reward_display() -> void:
|
||||
_load_crop_data_and_build_rewards()
|
||||
_update_template_display()
|
||||
@@ -0,0 +1 @@
|
||||
uid://65e0rl31fx0i
|
||||
294
SproutFarm-Frontend/Script/BigPanel/PetBagPanel.gd
Normal file
294
SproutFarm-Frontend/Script/BigPanel/PetBagPanel.gd
Normal file
@@ -0,0 +1,294 @@
|
||||
extends Panel
|
||||
# 这是宠物背包面板,用来显示玩家获得的宠物
|
||||
|
||||
# 宠物背包格子容器
|
||||
@onready var bag_grid: GridContainer = $ScrollContainer/Bag_Grid
|
||||
@onready var quit_button: Button = $QuitButton
|
||||
@onready var refresh_button: Button = $RefreshButton
|
||||
@onready var scroll_container = $ScrollContainer
|
||||
|
||||
# 预添加常用的面板
|
||||
@onready var main_game = get_node("/root/main")
|
||||
|
||||
@onready var lucky_draw_panel: LuckyDrawPanel = $'../LuckyDrawPanel'
|
||||
@onready var daily_check_in_panel: DailyCheckInPanel = $'../DailyCheckInPanel'
|
||||
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
|
||||
@onready var item_store_panel: Panel = $'../ItemStorePanel'
|
||||
@onready var pet_store_panel: Panel = $'../PetStorePanel'
|
||||
@onready var player_bag_panel: Panel = $'../PlayerBagPanel'
|
||||
@onready var crop_warehouse_panel: Panel = $'../CropWarehousePanel'
|
||||
@onready var crop_store_panel: Panel = $'../CropStorePanel'
|
||||
@onready var player_ranking_panel: Panel = $'../PlayerRankingPanel'
|
||||
@onready var login_panel: PanelContainer = $'../LoginPanel'
|
||||
@onready var pet_inform_panel: Panel = $'../../SmallPanel/PetInformPanel'
|
||||
|
||||
# 宠物配置数据
|
||||
var pet_config: Dictionary = {}
|
||||
|
||||
# 准备函数
|
||||
func _ready():
|
||||
# 连接关闭按钮信号
|
||||
quit_button.pressed.connect(self._on_quit_button_pressed)
|
||||
refresh_button.pressed.connect(self._on_refresh_button_pressed)
|
||||
# 连接可见性改变信号
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 隐藏面板(初始默认隐藏)
|
||||
self.hide()
|
||||
|
||||
# 初始化宠物背包
|
||||
func init_pet_bag():
|
||||
|
||||
# 显示背包中的宠物
|
||||
update_pet_bag_ui()
|
||||
|
||||
# 更新宠物背包UI(同步版本,用于刷新按钮)
|
||||
func update_pet_bag_ui():
|
||||
if scroll_container:
|
||||
scroll_container.clip_contents = false
|
||||
|
||||
# 设置GridContainer也不裁剪内容
|
||||
if bag_grid:
|
||||
bag_grid.clip_contents = false
|
||||
|
||||
# 清空宠物背包格子
|
||||
for child in bag_grid.get_children():
|
||||
child.queue_free()
|
||||
|
||||
# 确保宠物背包存在
|
||||
if not "pet_bag" in main_game or main_game.pet_bag == null:
|
||||
main_game.pet_bag = []
|
||||
|
||||
# 为背包中的每个宠物创建按钮
|
||||
for pet_data in main_game.pet_bag:
|
||||
var pet_name = pet_data.get("pet_type", "未知宠物")
|
||||
var pet_level = pet_data.get("pet_level", 1)
|
||||
var pet_owner_name = pet_data.get("pet_name", pet_name)
|
||||
|
||||
# 创建宠物按钮
|
||||
var button = _create_pet_button(pet_name, pet_level, pet_owner_name)
|
||||
|
||||
# 更新按钮文本显示宠物信息
|
||||
button.text = str(pet_owner_name + "\n等级:" + str(pet_level))
|
||||
|
||||
# 根据是否处于访问模式连接不同的事件
|
||||
if main_game.is_visiting_mode:
|
||||
# 访问模式下,点击宠物只显示信息
|
||||
button.pressed.connect(func(): _on_visit_pet_selected(pet_name, pet_data))
|
||||
else:
|
||||
# 正常模式下,连接宠物选择事件
|
||||
button.pressed.connect(func(): _on_pet_selected(pet_name, pet_data, button))
|
||||
|
||||
bag_grid.add_child(button)
|
||||
|
||||
# 创建宠物按钮
|
||||
func _create_pet_button(pet_name: String, pet_level: int, pet_owner_name: String) -> Button:
|
||||
# 使用按钮作为宠物背包按钮的样式
|
||||
var button = main_game.item_button.duplicate()
|
||||
|
||||
# 确保按钮可见并可点击
|
||||
button.visible = true
|
||||
button.disabled = false
|
||||
button.focus_mode = Control.FOCUS_ALL
|
||||
|
||||
# 关闭按钮的内容裁剪,允许图片超出按钮边界
|
||||
button.clip_contents = false
|
||||
|
||||
|
||||
# 添加工具提示
|
||||
button.tooltip_text = str(
|
||||
"宠物: " + pet_name + "\n" +
|
||||
"名称: " + pet_owner_name + "\n" +
|
||||
"等级: " + str(pet_level) + "\n" +
|
||||
"点击查看宠物详情"
|
||||
)
|
||||
|
||||
# 如果按钮有标题标签,设置标题
|
||||
if button.has_node("Title"):
|
||||
button.get_node("Title").text = "宠物"
|
||||
button.get_node("Title").modulate = Color.MAGENTA # 宠物标题使用洋红色
|
||||
|
||||
# 更新按钮的宠物图片
|
||||
_update_button_pet_image(button, pet_name)
|
||||
|
||||
return button
|
||||
|
||||
# 更新按钮的宠物图片
|
||||
func _update_button_pet_image(button: Button, pet_name: String):
|
||||
# 检查按钮是否有CropImage节点
|
||||
var pet_image = button.get_node_or_null("CropImage")
|
||||
if not pet_image:
|
||||
print("宠物背包按钮没有找到CropImage节点:", button.name)
|
||||
return
|
||||
|
||||
# 从服务器的宠物配置获取场景路径
|
||||
var texture = null
|
||||
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)
|
||||
# 加载宠物场景并获取PetImage的纹理
|
||||
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:
|
||||
texture = pet_instance.sprite_frames.get_frame_texture(default_animation, 0)
|
||||
print("宠物背包成功获取宠物纹理:", pet_name)
|
||||
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)
|
||||
|
||||
# 设置图片
|
||||
if texture:
|
||||
pet_image.texture = texture
|
||||
pet_image.visible = true
|
||||
pet_image.scale = Vector2(10, 10)
|
||||
# 确保图片居中显示
|
||||
pet_image.centered = true
|
||||
print("宠物背包成功设置宠物图片:", pet_name)
|
||||
else:
|
||||
pet_image.visible = false
|
||||
print("宠物背包无法获取宠物图片:", pet_name)
|
||||
|
||||
# 加载宠物配置数据
|
||||
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
|
||||
|
||||
# 计算宠物年龄(以天为单位)
|
||||
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_pet_selected(pet_name: String, pet_data: Dictionary, button: Button):
|
||||
# 显示宠物信息面板
|
||||
if pet_inform_panel:
|
||||
pet_inform_panel.show_pet_info(pet_name, pet_data)
|
||||
pet_inform_panel.show()
|
||||
|
||||
|
||||
# 访问模式下的宠物点击处理
|
||||
func _on_visit_pet_selected(pet_name: String, pet_data: Dictionary):
|
||||
# 显示宠物信息面板
|
||||
if pet_inform_panel:
|
||||
pet_inform_panel.show_pet_info(pet_name, pet_data)
|
||||
pet_inform_panel.show()
|
||||
|
||||
#=========================面板通用处理=========================
|
||||
# 关闭宠物背包面板
|
||||
func _on_quit_button_pressed() -> void:
|
||||
self.hide()
|
||||
|
||||
# 手动刷新宠物背包面板
|
||||
func _on_refresh_button_pressed() -> void:
|
||||
# 刷新宠物背包UI
|
||||
update_pet_bag_ui()
|
||||
Toast.show("宠物背包已刷新", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
#面板显示与隐藏切换处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
# 面板显示时请求同步最新的背包数据
|
||||
tcp_network_manager_panel.send_sync_bag_data_request()
|
||||
# 面板显示时自动刷新数据
|
||||
update_pet_bag_ui()
|
||||
pass
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
pass
|
||||
#=========================面板通用处理=========================
|
||||
1
SproutFarm-Frontend/Script/BigPanel/PetBagPanel.gd.uid
Normal file
1
SproutFarm-Frontend/Script/BigPanel/PetBagPanel.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bdhwvqsmakna2
|
||||
343
SproutFarm-Frontend/Script/BigPanel/PetStorePanel.gd
Normal file
343
SproutFarm-Frontend/Script/BigPanel/PetStorePanel.gd
Normal file
@@ -0,0 +1,343 @@
|
||||
extends Panel
|
||||
# 这是宠物商店面板,用来展示各种宠物
|
||||
|
||||
# 宠物商店格子容器
|
||||
@onready var store_grid: GridContainer = $ScrollContainer/Store_Grid
|
||||
@onready var quit_button: Button = $QuitButton
|
||||
@onready var refresh_button: Button = $RefreshButton
|
||||
@onready var scroll_container = $ScrollContainer
|
||||
|
||||
# 预添加常用的面板
|
||||
@onready var main_game = get_node("/root/main")
|
||||
|
||||
@onready var lucky_draw_panel: LuckyDrawPanel = $'../LuckyDrawPanel'
|
||||
@onready var daily_check_in_panel: DailyCheckInPanel = $'../DailyCheckInPanel'
|
||||
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
|
||||
@onready var item_bag_panel: Panel = $'../ItemBagPanel'
|
||||
@onready var pet_bag_panel: Panel = $'../PetBagPanel'
|
||||
@onready var player_bag_panel: Panel = $'../PlayerBagPanel'
|
||||
@onready var crop_warehouse_panel: Panel = $'../CropWarehousePanel'
|
||||
@onready var crop_store_panel: Panel = $'../CropStorePanel'
|
||||
@onready var player_ranking_panel: Panel = $'../PlayerRankingPanel'
|
||||
@onready var login_panel: PanelContainer = $'../LoginPanel'
|
||||
@onready var batch_buy_popup: PanelContainer = $'../../DiaLog/BatchBuyPopup'
|
||||
|
||||
# 宠物配置数据
|
||||
var pet_config: Dictionary = {}
|
||||
# 请求状态标志,防止重复请求
|
||||
var is_requesting_config: bool = false
|
||||
|
||||
# 准备函数
|
||||
func _ready():
|
||||
# 连接关闭按钮信号
|
||||
quit_button.pressed.connect(self._on_quit_button_pressed)
|
||||
refresh_button.pressed.connect(self._on_refresh_button_pressed)
|
||||
# 连接可见性改变信号
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 隐藏面板(初始默认隐藏)
|
||||
self.hide()
|
||||
|
||||
|
||||
# 初始化宠物商店
|
||||
func init_pet_store():
|
||||
# 从主游戏脚本获取宠物配置数据
|
||||
_load_pet_config_from_main()
|
||||
update_pet_store_ui()
|
||||
|
||||
# 更新宠物商店UI
|
||||
func update_pet_store_ui():
|
||||
if scroll_container:
|
||||
scroll_container.clip_contents = false
|
||||
|
||||
# 设置GridContainer也不裁剪内容
|
||||
if store_grid:
|
||||
store_grid.clip_contents = false
|
||||
|
||||
# 清空宠物商店格子
|
||||
for child in store_grid.get_children():
|
||||
child.queue_free()
|
||||
|
||||
print("更新宠物商店UI,宠物种类:", pet_config.size())
|
||||
print("宠物配置数据:", pet_config)
|
||||
|
||||
# 为每个宠物配置创建按钮
|
||||
for pet_name in pet_config.keys():
|
||||
var pet_info = pet_config[pet_name]
|
||||
print("处理宠物:", pet_name, ",数据:", pet_info)
|
||||
|
||||
# 适配扁平化数据格式
|
||||
var can_buy = pet_info.get("can_purchase", false)
|
||||
|
||||
# 只显示可购买的宠物
|
||||
if not can_buy:
|
||||
print("宠物 ", pet_name, " 不可购买,跳过")
|
||||
continue
|
||||
|
||||
var pet_cost = pet_info.get("cost", 0)
|
||||
var pet_desc = pet_info.get("description", "可爱的宠物伙伴")
|
||||
|
||||
# 检查玩家是否已购买该宠物
|
||||
var is_owned = _check_pet_owned(pet_name)
|
||||
|
||||
# 创建宠物按钮
|
||||
var button = _create_pet_button(pet_name, pet_cost, pet_desc, is_owned)
|
||||
|
||||
# 更新按钮文本显示价格和状态
|
||||
if is_owned:
|
||||
button.text = str(pet_name + "\n(已购买)")
|
||||
button.disabled = true
|
||||
else:
|
||||
button.text = str(pet_name + "\n价格:" + str(pet_cost) + "元")
|
||||
# 连接购买点击事件
|
||||
button.pressed.connect(func(): _on_store_pet_selected(pet_name, pet_cost, pet_desc))
|
||||
|
||||
store_grid.add_child(button)
|
||||
print("已添加宠物按钮:", pet_name)
|
||||
|
||||
# 检查玩家是否已拥有某种宠物
|
||||
func _check_pet_owned(pet_name: String) -> bool:
|
||||
if not main_game.pet_bag:
|
||||
return false
|
||||
|
||||
for pet_data in main_game.pet_bag:
|
||||
var pet_type = pet_data.get("pet_type", "")
|
||||
if pet_type == pet_name:
|
||||
return true
|
||||
return false
|
||||
|
||||
# 创建宠物按钮
|
||||
func _create_pet_button(pet_name: String, pet_cost: int, pet_desc: String, is_owned: bool = false) -> Button:
|
||||
# 使用按钮作为宠物商店按钮的样式
|
||||
var button = main_game.item_button.duplicate()
|
||||
|
||||
# 确保按钮可见并可点击
|
||||
button.visible = true
|
||||
button.disabled = false
|
||||
button.focus_mode = Control.FOCUS_ALL
|
||||
|
||||
# 关闭按钮的内容裁剪,允许图片超出按钮边界
|
||||
button.clip_contents = false
|
||||
|
||||
# 设置按钮文本
|
||||
button.text = pet_name
|
||||
|
||||
# 添加工具提示
|
||||
button.tooltip_text = str(
|
||||
"宠物: " + pet_name + "\n" +
|
||||
"价格: " + str(pet_cost) + "元\n" +
|
||||
"描述: " + pet_desc + "\n" +
|
||||
"点击购买宠物"
|
||||
)
|
||||
|
||||
# 如果按钮有标题标签,设置标题
|
||||
if button.has_node("Title"):
|
||||
if is_owned:
|
||||
button.get_node("Title").text = "已购买"
|
||||
button.get_node("Title").modulate = Color.GRAY # 已购买使用灰色
|
||||
else:
|
||||
button.get_node("Title").text = "宠物商店"
|
||||
button.get_node("Title").modulate = Color.PINK # 宠物商店标题使用粉色
|
||||
|
||||
# 更新按钮的宠物图片
|
||||
_update_button_pet_image(button, pet_name)
|
||||
|
||||
return button
|
||||
|
||||
# 更新按钮的宠物图片
|
||||
func _update_button_pet_image(button: Button, pet_name: String):
|
||||
# 检查按钮是否有CropImage节点
|
||||
var pet_image = button.get_node_or_null("CropImage")
|
||||
if not pet_image:
|
||||
print("按钮没有CropImage节点,跳过图片设置")
|
||||
return
|
||||
|
||||
# 从宠物配置获取场景路径
|
||||
var texture = null
|
||||
if pet_config.has(pet_name):
|
||||
var pet_info = pet_config[pet_name]
|
||||
var scene_path = pet_info.get("pet_image", "")
|
||||
print("宠物 ", pet_name, " 的图片路径:", scene_path)
|
||||
|
||||
if scene_path != "" and ResourceLoader.exists(scene_path):
|
||||
print("开始加载宠物场景:", scene_path)
|
||||
# 加载宠物场景并获取PetImage的纹理
|
||||
var pet_scene = load(scene_path)
|
||||
if pet_scene:
|
||||
var pet_instance = pet_scene.instantiate()
|
||||
# 场景的根节点就是PetImage,直接使用
|
||||
var pet_image_node = pet_instance
|
||||
if pet_image_node and pet_image_node.sprite_frames:
|
||||
# 获取默认动画的第一帧
|
||||
var animation_names = pet_image_node.sprite_frames.get_animation_names()
|
||||
if animation_names.size() > 0:
|
||||
var default_animation = animation_names[0]
|
||||
var frame_count = pet_image_node.sprite_frames.get_frame_count(default_animation)
|
||||
if frame_count > 0:
|
||||
texture = pet_image_node.sprite_frames.get_frame_texture(default_animation, 0)
|
||||
print("成功获取宠物纹理:", pet_name)
|
||||
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)
|
||||
|
||||
# 设置图片
|
||||
if texture:
|
||||
pet_image.texture = texture
|
||||
pet_image.visible = true
|
||||
pet_image.scale = Vector2(10, 10)
|
||||
# 确保图片居中显示
|
||||
pet_image.centered = true
|
||||
print("成功设置宠物图片:", pet_name)
|
||||
else:
|
||||
# 如果无法获取图片,隐藏图片节点但保留按钮
|
||||
pet_image.visible = false
|
||||
print("无法获取宠物图片,隐藏图片节点:", pet_name)
|
||||
|
||||
# 从服务器获取MongoDB中的宠物配置数据
|
||||
func _load_pet_config_from_main():
|
||||
# 如果正在请求中,避免重复发送
|
||||
if is_requesting_config:
|
||||
print("宠物商店:正在请求配置数据中,跳过重复请求")
|
||||
return
|
||||
|
||||
# 发送请求到服务器获取宠物配置
|
||||
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("sendGetPetConfig"):
|
||||
is_requesting_config = true
|
||||
if tcp_network_manager_panel.sendGetPetConfig():
|
||||
print("宠物商店:已发送获取宠物配置请求")
|
||||
# 等待服务器响应,配置数据将通过网络回调更新
|
||||
else:
|
||||
print("宠物商店:发送获取宠物配置请求失败")
|
||||
pet_config = {}
|
||||
is_requesting_config = false
|
||||
else:
|
||||
print("宠物商店:网络管理器不可用,无法获取宠物配置")
|
||||
pet_config = {}
|
||||
is_requesting_config = false
|
||||
|
||||
# 处理服务器返回的宠物配置数据
|
||||
func _on_pet_config_received(response_data: Dictionary):
|
||||
"""处理从服务器接收到的宠物配置数据"""
|
||||
# 重置请求状态
|
||||
is_requesting_config = false
|
||||
|
||||
var success = response_data.get("success", false)
|
||||
if success:
|
||||
pet_config = response_data.get("pet_config", {})
|
||||
print("宠物商店:成功接收宠物配置数据,宠物种类:", pet_config.size())
|
||||
# 只更新UI,不重新发送请求
|
||||
update_pet_store_ui()
|
||||
else:
|
||||
var error_message = response_data.get("message", "获取宠物配置失败")
|
||||
print("宠物商店:获取宠物配置失败:", error_message)
|
||||
pet_config = {}
|
||||
# 显示错误提示
|
||||
Toast.show(error_message, Color.RED, 3.0, 1.0)
|
||||
|
||||
# 商店宠物点击处理 - 购买宠物
|
||||
func _on_store_pet_selected(pet_name: String, pet_cost: int, pet_desc: String):
|
||||
# 检查玩家金钱是否足够
|
||||
if main_game.money < pet_cost:
|
||||
Toast.show("金钱不足!需要 " + str(pet_cost) + " 元,当前只有 " + str(main_game.money) + " 元", Color.RED, 3.0, 1.0)
|
||||
return
|
||||
|
||||
# 显示购买确认对话框(宠物只能购买1只,不需要批量购买)
|
||||
_show_buy_confirmation_dialog(pet_name, pet_cost, pet_desc)
|
||||
|
||||
# 显示购买确认对话框
|
||||
func _show_buy_confirmation_dialog(pet_name: String, pet_cost: int, pet_desc: String):
|
||||
# 创建确认对话框
|
||||
var confirm_dialog = AcceptDialog.new()
|
||||
confirm_dialog.dialog_text = str(
|
||||
"确认购买宠物?\n\n" +
|
||||
"宠物名称: " + pet_name + "\n" +
|
||||
"购买价格: " + str(pet_cost) + " 元\n" +
|
||||
"宠物描述: " + pet_desc + "\n\n" +
|
||||
"当前金钱: " + str(main_game.money) + " 元\n" +
|
||||
"购买后余额: " + str(main_game.money - pet_cost) + " 元\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_buy_pet.bind(pet_name, pet_cost, confirm_dialog))
|
||||
confirm_dialog.canceled.connect(_on_cancel_buy_pet.bind(confirm_dialog))
|
||||
|
||||
# 显示对话框
|
||||
confirm_dialog.popup_centered()
|
||||
|
||||
# 确认购买宠物
|
||||
func _on_confirm_buy_pet(pet_name: String, pet_cost: int, dialog: AcceptDialog):
|
||||
# 再次检查金钱是否足够
|
||||
if main_game.money < pet_cost:
|
||||
Toast.show("金钱不足!需要 " + str(pet_cost) + " 元,当前只有 " + str(main_game.money) + " 元", Color.RED, 3.0, 1.0)
|
||||
dialog.queue_free()
|
||||
return
|
||||
|
||||
# 发送购买请求到服务器
|
||||
_send_buy_pet_request(pet_name, pet_cost)
|
||||
init_pet_store()
|
||||
dialog.queue_free()
|
||||
|
||||
# 取消购买宠物
|
||||
func _on_cancel_buy_pet(dialog: AcceptDialog):
|
||||
print("取消购买宠物")
|
||||
dialog.queue_free()
|
||||
|
||||
# 发送购买宠物请求
|
||||
func _send_buy_pet_request(pet_name: String, pet_cost: int):
|
||||
# 发送购买请求到服务器
|
||||
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("sendBuyPet"):
|
||||
if tcp_network_manager_panel.sendBuyPet(pet_name, pet_cost):
|
||||
# 服务器会处理购买逻辑,客户端等待响应
|
||||
print("已发送购买宠物请求:", pet_name)
|
||||
else:
|
||||
Toast.show("购买请求发送失败", Color.RED, 2.0, 1.0)
|
||||
else:
|
||||
Toast.show("网络管理器不可用", Color.RED, 2.0, 1.0)
|
||||
|
||||
#=========================面板通用处理=========================
|
||||
# 手动刷新宠物商店面板
|
||||
#刷新按钮点击
|
||||
func _on_refresh_button_pressed() -> void:
|
||||
# 清空现有配置和请求状态,强制重新获取
|
||||
pet_config = {}
|
||||
is_requesting_config = false
|
||||
# 重新初始化宠物商店
|
||||
init_pet_store()
|
||||
#Toast.show("宠物商店已刷新", Color.GREEN, 2.0, 1.0)
|
||||
|
||||
# 关闭宠物商店面板
|
||||
func _on_quit_button_pressed() -> void:
|
||||
# 打开面板后暂时禁用相机功能
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
self.hide()
|
||||
|
||||
#面板显示与隐藏切换处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
# 面板显示时只在没有配置数据时才请求
|
||||
if pet_config.is_empty():
|
||||
init_pet_store()
|
||||
else:
|
||||
# 如果已有配置数据,直接更新UI
|
||||
update_pet_store_ui()
|
||||
pass
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
pass
|
||||
#=========================面板通用处理=========================
|
||||
1
SproutFarm-Frontend/Script/BigPanel/PetStorePanel.gd.uid
Normal file
1
SproutFarm-Frontend/Script/BigPanel/PetStorePanel.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dc1pmi1ubd2cf
|
||||
27
SproutFarm-Frontend/Script/BigPanel/PlayGamePanel.gd
Normal file
27
SproutFarm-Frontend/Script/BigPanel/PlayGamePanel.gd
Normal file
@@ -0,0 +1,27 @@
|
||||
extends Panel
|
||||
|
||||
|
||||
var _2048_GAME = preload('res://Scene/SmallGame/2048Game.tscn').instantiate()
|
||||
var PUSH_BOX = preload('res://Scene/SmallGame/PushBox.tscn').instantiate()
|
||||
var SNAKE_GAME = preload('res://Scene/SmallGame/SnakeGame.tscn').instantiate()
|
||||
var TETRIS = preload('res://Scene/SmallGame/Tetris.tscn').instantiate()
|
||||
|
||||
|
||||
func _on_game_button_pressed() -> void:
|
||||
self.add_child(_2048_GAME)
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
func _on_push_box_button_pressed() -> void:
|
||||
self.add_child(PUSH_BOX)
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
func _on_snake_game_button_pressed() -> void:
|
||||
self.add_child(SNAKE_GAME)
|
||||
pass # Replace with function body.
|
||||
|
||||
|
||||
func _on_tetris_button_pressed() -> void:
|
||||
self.add_child(TETRIS)
|
||||
pass # Replace with function body.
|
||||
1
SproutFarm-Frontend/Script/BigPanel/PlayGamePanel.gd.uid
Normal file
1
SproutFarm-Frontend/Script/BigPanel/PlayGamePanel.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dvaah0n1ia1a3
|
||||
510
SproutFarm-Frontend/Script/BigPanel/PlayerBagPanel.gd
Normal file
510
SproutFarm-Frontend/Script/BigPanel/PlayerBagPanel.gd
Normal file
@@ -0,0 +1,510 @@
|
||||
extends Panel
|
||||
#种子仓库面板
|
||||
# 背包格子容器
|
||||
@onready var player_bag_grid_container : GridContainer = $ScrollContainer/Bag_Grid
|
||||
@onready var quit_button : Button = $QuitButton
|
||||
@onready var refresh_button : Button = $RefreshButton
|
||||
|
||||
#各种排序过滤按钮
|
||||
@onready var sort_all_button : Button = $SortContainer/Sort_All#全部
|
||||
@onready var sort_common_button : Button = $SortContainer/Sort_Common#普通
|
||||
@onready var sort_superior_button : Button = $SortContainer/Sort_Superior#优良
|
||||
@onready var sort_rare_button : Button = $SortContainer/Sort_Rare#稀有
|
||||
@onready var sort_epic_button : Button = $SortContainer/Sort_Epic#史诗
|
||||
@onready var sort_legendary_button : Button = $SortContainer/Sort_Legendary#传奇
|
||||
@onready var sort_price_button : Button = $SortContainer/Sort_Price#价格
|
||||
@onready var sort_growtime_button : Button = $SortContainer/Sort_GrowTime#生长时间
|
||||
@onready var sort_profit_button : Button = $SortContainer/Sort_Profit#收益
|
||||
@onready var sort_level_button : Button = $SortContainer/Sort_Level#等级
|
||||
|
||||
#预添加常用的面板
|
||||
@onready var main_game = get_node("/root/main")
|
||||
@onready var lucky_draw_panel: LuckyDrawPanel = $'../LuckyDrawPanel'
|
||||
@onready var daily_check_in_panel: DailyCheckInPanel = $'../DailyCheckInPanel'
|
||||
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
|
||||
@onready var item_store_panel: Panel = $'../ItemStorePanel'
|
||||
@onready var item_bag_panel: Panel = $'../ItemBagPanel'
|
||||
@onready var crop_warehouse_panel: Panel = $'../CropWarehousePanel'
|
||||
@onready var crop_store_panel: Panel = $'../CropStorePanel'
|
||||
@onready var player_ranking_panel: Panel = $'../PlayerRankingPanel'
|
||||
@onready var login_panel: PanelContainer = $'../LoginPanel'
|
||||
|
||||
|
||||
# 作物图片缓存(复用主游戏的缓存系统)
|
||||
var crop_textures_cache : Dictionary = {}
|
||||
var crop_frame_counts : Dictionary = {}
|
||||
|
||||
# 当前选择的地块索引,从MainGame获取
|
||||
var selected_lot_index : int = -1
|
||||
|
||||
# 当前过滤和排序设置
|
||||
var current_filter_quality = ""
|
||||
var current_sort_key = ""
|
||||
var current_sort_ascending = true
|
||||
|
||||
# 一键种植模式相关变量
|
||||
var is_planting_mode = false
|
||||
var planting_type = ""
|
||||
var one_click_plant_panel = null
|
||||
|
||||
# 准备函数
|
||||
func _ready():
|
||||
# 连接按钮信号
|
||||
_connect_buttons()
|
||||
# 连接可见性改变信号
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
|
||||
# 隐藏面板(初始默认隐藏)
|
||||
self.hide()
|
||||
|
||||
|
||||
# 连接所有按钮信号
|
||||
func _connect_buttons():
|
||||
# 关闭按钮
|
||||
quit_button.pressed.connect(self._on_quit_button_pressed)
|
||||
|
||||
# 过滤按钮
|
||||
sort_all_button.pressed.connect(func(): _filter_by_quality(""))
|
||||
sort_common_button.pressed.connect(func(): _filter_by_quality("普通"))
|
||||
sort_superior_button.pressed.connect(func(): _filter_by_quality("优良"))
|
||||
sort_rare_button.pressed.connect(func(): _filter_by_quality("稀有"))
|
||||
sort_epic_button.pressed.connect(func(): _filter_by_quality("史诗"))
|
||||
sort_legendary_button.pressed.connect(func(): _filter_by_quality("传奇"))
|
||||
|
||||
# 排序按钮
|
||||
sort_price_button.pressed.connect(func(): _sort_by("花费"))
|
||||
sort_growtime_button.pressed.connect(func(): _sort_by("生长时间"))
|
||||
sort_profit_button.pressed.connect(func(): _sort_by("收益"))
|
||||
sort_level_button.pressed.connect(func(): _sort_by("等级"))
|
||||
|
||||
# 初始化玩家背包
|
||||
func init_player_bag():
|
||||
# 显示背包中的种子
|
||||
update_player_bag_ui()
|
||||
|
||||
# 更新玩家背包UI
|
||||
func update_player_bag_ui():
|
||||
# 清空玩家背包格子
|
||||
for child in player_bag_grid_container.get_children():
|
||||
child.queue_free()
|
||||
|
||||
# 应用过滤和排序
|
||||
var filtered_seeds = _get_filtered_and_sorted_seeds()
|
||||
|
||||
# 为背包中的每个过滤后的种子创建按钮
|
||||
for seed_item in filtered_seeds:
|
||||
var crop_name = seed_item["name"]
|
||||
var crop_quality = seed_item["quality"]
|
||||
var crop_count = seed_item["count"]
|
||||
# 创建种子按钮
|
||||
var button = _create_crop_button(crop_name, crop_quality)
|
||||
# 更新按钮文本显示数量
|
||||
var display_name = crop_name
|
||||
if main_game.can_planted_crop.has(crop_name):
|
||||
display_name = main_game.can_planted_crop[crop_name].get("作物名称", crop_name)
|
||||
button.text = str(crop_quality + "-" + display_name + "\n数量:" + str(crop_count))
|
||||
# 根据是否处于访问模式连接不同的事件
|
||||
if main_game.is_visiting_mode:
|
||||
# 访问模式下,点击种子只显示信息,不能种植
|
||||
button.pressed.connect(func(): _on_visit_seed_selected(crop_name, crop_count))
|
||||
else:
|
||||
# 正常模式下,连接种植事件
|
||||
button.pressed.connect(func(): _on_bag_seed_selected(crop_name))
|
||||
|
||||
player_bag_grid_container.add_child(button)
|
||||
|
||||
# 获取过滤和排序后的种子列表
|
||||
func _get_filtered_and_sorted_seeds():
|
||||
var filtered_seeds = []
|
||||
|
||||
# 收集符合条件的种子
|
||||
for seed_item in main_game.player_bag:
|
||||
# 从crop_data中获取品质信息
|
||||
var item_quality = "普通"
|
||||
if main_game.can_planted_crop.has(seed_item["name"]):
|
||||
item_quality = main_game.can_planted_crop[seed_item["name"]].get("品质", "普通")
|
||||
|
||||
# 品质过滤
|
||||
if current_filter_quality != "" and item_quality != current_filter_quality:
|
||||
continue
|
||||
|
||||
# 获取种子对应的作物数据
|
||||
var crop_data = null
|
||||
if main_game.can_planted_crop.has(seed_item["name"]):
|
||||
crop_data = main_game.can_planted_crop[seed_item["name"]]
|
||||
|
||||
# 添加到过滤后的列表
|
||||
filtered_seeds.append({
|
||||
"name": seed_item["name"],
|
||||
"quality": item_quality,
|
||||
"count": seed_item["count"],
|
||||
"data": crop_data
|
||||
})
|
||||
|
||||
# 如果有排序条件且数据可用,进行排序
|
||||
if current_sort_key != "":
|
||||
filtered_seeds.sort_custom(Callable(self, "_sort_seed_items"))
|
||||
|
||||
return filtered_seeds
|
||||
|
||||
# 自定义排序函数
|
||||
func _sort_seed_items(a, b):
|
||||
# 检查是否有有效数据用于排序
|
||||
if a["data"] == null or b["data"] == null:
|
||||
# 如果某一项没有数据,将其排在后面
|
||||
if a["data"] == null and b["data"] != null:
|
||||
return false
|
||||
if a["data"] != null and b["data"] == null:
|
||||
return true
|
||||
# 如果都没有数据,按名称排序
|
||||
return a["name"] < b["name"]
|
||||
|
||||
# 确保排序键存在于数据中
|
||||
if !a["data"].has(current_sort_key) or !b["data"].has(current_sort_key):
|
||||
print("警告: 排序键 ", current_sort_key, " 在某些种子数据中不存在")
|
||||
return false
|
||||
|
||||
# 安全地获取排序值,并进行类型转换
|
||||
var value_a = a["data"].get(current_sort_key, 0)
|
||||
var value_b = b["data"].get(current_sort_key, 0)
|
||||
|
||||
# 如果是数值类型的字段,确保转换为数值进行比较
|
||||
if current_sort_key in ["花费", "生长时间", "收益", "等级", "经验", "耐候性"]:
|
||||
# 转换为数值,如果转换失败则使用0
|
||||
if typeof(value_a) == TYPE_STRING:
|
||||
value_a = int(value_a) if value_a.is_valid_int() else 0
|
||||
if typeof(value_b) == TYPE_STRING:
|
||||
value_b = int(value_b) if value_b.is_valid_int() else 0
|
||||
|
||||
# 执行排序比较
|
||||
if current_sort_ascending:
|
||||
return value_a < value_b
|
||||
else:
|
||||
return value_a > value_b
|
||||
|
||||
# 按品质过滤种子
|
||||
func _filter_by_quality(quality: String):
|
||||
current_filter_quality = quality
|
||||
update_player_bag_ui()
|
||||
|
||||
# 按指定键排序
|
||||
func _sort_by(sort_key: String):
|
||||
# 切换排序方向或设置新排序键
|
||||
if current_sort_key == sort_key:
|
||||
current_sort_ascending = !current_sort_ascending
|
||||
else:
|
||||
current_sort_key = sort_key
|
||||
current_sort_ascending = true
|
||||
|
||||
update_player_bag_ui()
|
||||
|
||||
# 创建作物按钮
|
||||
func _create_crop_button(crop_name: String, crop_quality: String) -> Button:
|
||||
# 根据品质选择相应的进度条
|
||||
var button = main_game.item_button.duplicate()
|
||||
|
||||
|
||||
# 确保按钮可见并可点击
|
||||
button.visible = true
|
||||
button.disabled = false
|
||||
button.focus_mode = Control.FOCUS_ALL
|
||||
# 设置按钮文本
|
||||
var display_name = crop_name
|
||||
if main_game.can_planted_crop.has(crop_name):
|
||||
display_name = main_game.can_planted_crop[crop_name].get("作物名称", crop_name)
|
||||
button.text = str(crop_quality + "-" + display_name)
|
||||
|
||||
# 添加工具提示 (tooltip)
|
||||
if main_game.can_planted_crop.has(crop_name):
|
||||
var crop = main_game.can_planted_crop[crop_name]
|
||||
|
||||
# 将成熟时间从秒转换为天时分秒格式
|
||||
var total_seconds = int(crop["生长时间"])
|
||||
|
||||
# 定义时间单位换算
|
||||
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
|
||||
|
||||
# 构建时间字符串(只显示有值的单位)
|
||||
var time_str = ""
|
||||
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) + "秒"
|
||||
|
||||
button.tooltip_text = str(
|
||||
"作物: " + display_name + "\n" +
|
||||
"品质: " + crop_quality + "\n" +
|
||||
"价格: " + str(crop["花费"]) + "元\n" +
|
||||
"成熟时间: " + time_str + "\n" +
|
||||
"收获收益: " + str(crop["收益"]) + "元\n" +
|
||||
"需求等级: " + str(crop["等级"]) + "\n" +
|
||||
"耐候性: " + str(crop["耐候性"]) + "\n" +
|
||||
"经验: " + str(crop["经验"]) + "点\n" +
|
||||
"描述: " + str(crop["描述"])
|
||||
)
|
||||
|
||||
# 如果按钮有标题标签,设置标题
|
||||
if button.has_node("Title"):
|
||||
button.get_node("Title").text = crop_quality
|
||||
match crop_quality:
|
||||
"普通":
|
||||
button.get_node("Title").modulate = Color.HONEYDEW#白色
|
||||
"优良":
|
||||
button.get_node("Title").modulate =Color.DODGER_BLUE#深蓝色
|
||||
"稀有":
|
||||
button.get_node("Title").modulate =Color.HOT_PINK#品红色
|
||||
"史诗":
|
||||
button.get_node("Title").modulate =Color.YELLOW#黄色
|
||||
"传奇":
|
||||
button.get_node("Title").modulate =Color.ORANGE_RED#红色
|
||||
|
||||
# 更新按钮的作物图片
|
||||
_update_button_crop_image(button, crop_name)
|
||||
|
||||
return button
|
||||
|
||||
# 从背包中选择种子并种植
|
||||
func _on_bag_seed_selected(crop_name):
|
||||
# 检查是否处于访问模式
|
||||
if main_game.is_visiting_mode:
|
||||
Toast.show("访问模式下无法种植", Color.ORANGE, 2.0, 1.0)
|
||||
return
|
||||
|
||||
# 检查是否是一键种植模式
|
||||
if is_planting_mode:
|
||||
# 一键种植模式下,回调给一键种植面板
|
||||
if one_click_plant_panel and one_click_plant_panel.has_method("on_crop_selected"):
|
||||
one_click_plant_panel.on_crop_selected(crop_name, planting_type)
|
||||
# 退出种植模式
|
||||
_exit_planting_mode()
|
||||
self.hide()
|
||||
return
|
||||
|
||||
# 从主场景获取当前选择的地块索引
|
||||
selected_lot_index = main_game.selected_lot_index
|
||||
|
||||
if selected_lot_index != -1:
|
||||
# 检查背包中是否有这个种子
|
||||
var seed_index = -1
|
||||
for i in range(len(main_game.player_bag)):
|
||||
if main_game.player_bag[i]["name"] == crop_name:
|
||||
seed_index = i
|
||||
break
|
||||
|
||||
if seed_index != -1 and main_game.player_bag[seed_index]["count"] > 0:
|
||||
# 种植种子并从背包中减少数量
|
||||
_plant_crop_from_bag(selected_lot_index, crop_name, seed_index)
|
||||
main_game.selected_lot_index = -1
|
||||
self.hide()
|
||||
|
||||
# 访问模式下的种子点击处理
|
||||
func _on_visit_seed_selected(crop_name, crop_count):
|
||||
pass
|
||||
|
||||
# 从背包种植作物
|
||||
func _plant_crop_from_bag(index, crop_name, seed_index):
|
||||
var crop = main_game.can_planted_crop[crop_name]
|
||||
|
||||
# 检查是否有效的种子索引,防止越界访问
|
||||
if seed_index < 0 or seed_index >= main_game.player_bag.size():
|
||||
#print("错误:无效的种子索引 ", seed_index)
|
||||
return
|
||||
# 发送种植请求到服务器
|
||||
if tcp_network_manager_panel and tcp_network_manager_panel.sendPlantCrop(index, crop_name):
|
||||
# 关闭背包面板
|
||||
hide()
|
||||
|
||||
# 设置种植模式
|
||||
func set_planting_mode(plant_type: String, plant_panel):
|
||||
is_planting_mode = true
|
||||
planting_type = plant_type
|
||||
one_click_plant_panel = plant_panel
|
||||
Toast.show("进入种植模式:"+plant_type,Color.GREEN)
|
||||
|
||||
# 退出种植模式
|
||||
func _exit_planting_mode():
|
||||
is_planting_mode = false
|
||||
planting_type = ""
|
||||
one_click_plant_panel = null
|
||||
Toast.show("退出种植模式",Color.GREEN)
|
||||
|
||||
|
||||
# 获取作物的成熟图片(用于背包显示)
|
||||
func _get_crop_final_texture(crop_name: String) -> Texture2D:
|
||||
# 优先从主游戏的缓存中获取成熟图片
|
||||
if main_game and main_game.crop_mature_textures_cache.has(crop_name):
|
||||
return main_game.crop_mature_textures_cache[crop_name]
|
||||
|
||||
# 如果缓存中没有,再尝试加载"成熟.webp"图片
|
||||
var crop_path = "res://assets/作物/" + crop_name + "/"
|
||||
var mature_texture_path = crop_path + "成熟.webp"
|
||||
|
||||
if ResourceLoader.exists(mature_texture_path):
|
||||
var texture = load(mature_texture_path)
|
||||
if texture:
|
||||
# 如果主游戏存在,也缓存到主游戏中
|
||||
if main_game:
|
||||
main_game.crop_mature_textures_cache[crop_name] = texture
|
||||
return texture
|
||||
|
||||
# 如果没有找到作物的成熟图片,使用默认的成熟图片
|
||||
if main_game and main_game.crop_mature_textures_cache.has("默认"):
|
||||
var default_texture = main_game.crop_mature_textures_cache["默认"]
|
||||
# 缓存给这个作物
|
||||
main_game.crop_mature_textures_cache[crop_name] = default_texture
|
||||
return default_texture
|
||||
|
||||
# 最后尝试直接加载默认成熟图片
|
||||
var default_mature_path = "res://assets/作物/默认/成熟.webp"
|
||||
if ResourceLoader.exists(default_mature_path):
|
||||
var texture = load(default_mature_path)
|
||||
if texture:
|
||||
print("背包使用默认成熟图片:", crop_name)
|
||||
# 缓存到主游戏
|
||||
if main_game:
|
||||
main_game.crop_mature_textures_cache["默认"] = texture
|
||||
main_game.crop_mature_textures_cache[crop_name] = texture
|
||||
return texture
|
||||
|
||||
return null
|
||||
|
||||
# 加载作物图片序列帧(复用主游戏的逻辑)
|
||||
func _load_crop_textures(crop_name: String) -> Array:
|
||||
if crop_textures_cache.has(crop_name):
|
||||
return crop_textures_cache[crop_name]
|
||||
|
||||
var textures = []
|
||||
var crop_path = "res://assets/作物/" + crop_name + "/"
|
||||
var default_path = "res://assets/作物/默认/"
|
||||
|
||||
# 检查作物文件夹是否存在
|
||||
if DirAccess.dir_exists_absolute(crop_path):
|
||||
# 尝试加载作物的序列帧(从0开始)
|
||||
var frame_index = 0
|
||||
while true:
|
||||
var texture_path = crop_path + str(frame_index) + ".webp"
|
||||
if ResourceLoader.exists(texture_path):
|
||||
var texture = load(texture_path)
|
||||
if texture:
|
||||
textures.append(texture)
|
||||
frame_index += 1
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
if textures.size() > 0:
|
||||
pass
|
||||
else:
|
||||
print("背包:作物 ", crop_name, " 文件夹存在但没有找到有效图片,使用默认图片")
|
||||
textures = _load_default_textures()
|
||||
else:
|
||||
print("背包:作物 ", crop_name, " 的文件夹不存在,使用默认图片")
|
||||
textures = _load_default_textures()
|
||||
|
||||
# 缓存结果
|
||||
crop_textures_cache[crop_name] = textures
|
||||
crop_frame_counts[crop_name] = textures.size()
|
||||
|
||||
return textures
|
||||
|
||||
# 加载默认图片
|
||||
func _load_default_textures() -> Array:
|
||||
if crop_textures_cache.has("默认"):
|
||||
return crop_textures_cache["默认"]
|
||||
|
||||
var textures = []
|
||||
var default_path = "res://assets/作物/默认/"
|
||||
|
||||
# 尝试加载默认图片序列帧
|
||||
var frame_index = 0
|
||||
while true:
|
||||
var texture_path = default_path + str(frame_index) + ".webp"
|
||||
if ResourceLoader.exists(texture_path):
|
||||
var texture = load(texture_path)
|
||||
if texture:
|
||||
textures.append(texture)
|
||||
frame_index += 1
|
||||
else:
|
||||
break
|
||||
else:
|
||||
break
|
||||
|
||||
# 如果没有找到序列帧,尝试加载单个默认图片
|
||||
if textures.size() == 0:
|
||||
var single_texture_path = default_path + ".webp"
|
||||
if ResourceLoader.exists(single_texture_path):
|
||||
var texture = load(single_texture_path)
|
||||
if texture:
|
||||
textures.append(texture)
|
||||
|
||||
# 缓存默认图片
|
||||
crop_textures_cache["默认"] = textures
|
||||
crop_frame_counts["默认"] = textures.size()
|
||||
|
||||
print("背包加载了 ", textures.size(), " 个默认作物图片")
|
||||
return textures
|
||||
|
||||
# 更新按钮的作物图片
|
||||
func _update_button_crop_image(button: Button, crop_name: String):
|
||||
# 检查按钮是否有CropImage节点
|
||||
var crop_image = button.get_node_or_null("CropImage")
|
||||
if not crop_image:
|
||||
print("背包按钮没有找到CropImage节点:", button.name)
|
||||
return
|
||||
|
||||
# 获取作物的最后一帧图片
|
||||
var texture = _get_crop_final_texture(crop_name)
|
||||
|
||||
if texture:
|
||||
# CropImage是Sprite2D,直接设置texture属性
|
||||
crop_image.texture = texture
|
||||
crop_image.visible = true
|
||||
else:
|
||||
crop_image.visible = false
|
||||
print("背包无法获取作物图片:", crop_name)
|
||||
|
||||
#=========================面板通用处理=========================
|
||||
#手动刷新种子仓库面板
|
||||
func _on_refresh_button_pressed() -> void:
|
||||
# 刷新种子背包UI
|
||||
update_player_bag_ui()
|
||||
Toast.show("种子仓库已刷新", Color.GREEN)
|
||||
|
||||
# 关闭面板
|
||||
func _on_quit_button_pressed():
|
||||
# 退出种植模式(如果当前在种植模式下)
|
||||
if is_planting_mode:
|
||||
_exit_planting_mode()
|
||||
self.hide()
|
||||
|
||||
#面板显示与隐藏切换处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
# 面板显示时请求同步最新的背包数据
|
||||
tcp_network_manager_panel.send_sync_bag_data_request()
|
||||
# 面板显示时自动刷新数据
|
||||
update_player_bag_ui()
|
||||
pass
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
pass
|
||||
#=========================面板通用处理=========================
|
||||
@@ -0,0 +1 @@
|
||||
uid://cgr332wsx63a8
|
||||
335
SproutFarm-Frontend/Script/BigPanel/PlayerRankingPanel.gd
Normal file
335
SproutFarm-Frontend/Script/BigPanel/PlayerRankingPanel.gd
Normal file
@@ -0,0 +1,335 @@
|
||||
extends Panel
|
||||
|
||||
@onready var player_ranking_list : VBoxContainer = $Scroll/PlayerList
|
||||
@onready var refresh_button : Button = $RefreshButton #刷新玩家排行榜面板按钮
|
||||
@onready var quit_button : Button = $QuitButton #关闭面板按钮
|
||||
@onready var search_button: Button = $SearchButton #搜索玩家按钮
|
||||
@onready var register_player_num: Label = $RegisterPlayerNum #显示注册总人数
|
||||
|
||||
#搜索玩家输入框,通过输入QQ号来查询
|
||||
@onready var search_line_edit: LineEdit = $SearchLineEdit
|
||||
|
||||
#排序筛选玩家面板按钮,默认按从大到小排序
|
||||
#排序元素:种子数,等级,在线时长,最后登录时长,点赞数
|
||||
#筛选元素:是否在线 筛选出在线玩家
|
||||
@onready var seed_sort_btn: Button = $FiterAndSortHBox/SeedSortBtn
|
||||
@onready var level_sort_btn: Button = $FiterAndSortHBox/LevelSortBtn
|
||||
@onready var online_time_sort_btn: Button = $FiterAndSortHBox/OnlineTimeSortBtn
|
||||
@onready var login_time_sort_btn: Button = $FiterAndSortHBox/LoginTimeSortBtn
|
||||
@onready var like_num_sort_btn: Button = $FiterAndSortHBox/LikeNumSortBtn
|
||||
@onready var money_sort_btn: Button = $FiterAndSortHBox/MoneySortBtn
|
||||
@onready var is_online_sort_btn: Button = $FiterAndSortHBox/IsOnlineSortBtn
|
||||
|
||||
|
||||
#预添加常用的面板
|
||||
@onready var main_game = get_node("/root/main")
|
||||
|
||||
|
||||
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
|
||||
@onready var item_store_panel: Panel = $'../ItemStorePanel'
|
||||
@onready var crop_warehouse_panel: Panel = $'../CropWarehousePanel'
|
||||
@onready var login_panel: PanelContainer = $'../LoginPanel'
|
||||
@onready var player_bag_panel: Panel = $'../PlayerBagPanel'
|
||||
@onready var crop_store_panel: Panel = $'../CropStorePanel'
|
||||
@onready var item_bag_panel: Panel = $'../ItemBagPanel'
|
||||
|
||||
|
||||
# 排序状态管理
|
||||
var current_sort_by = "等级" # 当前排序字段
|
||||
var current_sort_order = "desc" # 当前排序顺序
|
||||
var filter_online_only = false # 是否只显示在线玩家
|
||||
var current_search_qq = "" # 当前搜索的QQ号
|
||||
|
||||
#下面这是每个玩家要展示的信息,直接获取服务器玩家数据json文件来实现
|
||||
#模板用于复制创建新的玩家条目
|
||||
@onready var player_info_template : VBoxContainer = $Scroll/PlayerList/PlayerRankingItem
|
||||
@onready var player_entry_scene : PackedScene = preload("res://GUI/PlayerRankingItem.tscn")
|
||||
|
||||
func _ready() -> void:
|
||||
# 隐藏模板
|
||||
player_info_template.visible = false
|
||||
|
||||
# 连接可见性改变信号
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
# 连接按钮信号
|
||||
refresh_button.pressed.connect(_on_refresh_button_pressed)
|
||||
quit_button.pressed.connect(_on_quit_button_pressed)
|
||||
search_button.pressed.connect(_on_search_button_pressed)
|
||||
|
||||
# 连接排序按钮信号
|
||||
seed_sort_btn.pressed.connect(func(): _on_sort_button_pressed("seed_count"))
|
||||
level_sort_btn.pressed.connect(func(): _on_sort_button_pressed("等级"))
|
||||
online_time_sort_btn.pressed.connect(func(): _on_sort_button_pressed("online_time"))
|
||||
login_time_sort_btn.pressed.connect(func(): _on_sort_button_pressed("login_time"))
|
||||
like_num_sort_btn.pressed.connect(func(): _on_sort_button_pressed("like_num"))
|
||||
money_sort_btn.pressed.connect(func(): _on_sort_button_pressed("钱币"))
|
||||
is_online_sort_btn.pressed.connect(_on_online_filter_pressed)
|
||||
|
||||
# 初始化按钮状态
|
||||
_update_button_states()
|
||||
|
||||
# 排序按钮点击处理
|
||||
func _on_sort_button_pressed(sort_field: String):
|
||||
# 如果点击的是当前排序字段,切换排序顺序
|
||||
if current_sort_by == sort_field:
|
||||
current_sort_order = "asc" if current_sort_order == "desc" else "desc"
|
||||
else:
|
||||
# 切换到新的排序字段,默认降序
|
||||
current_sort_by = sort_field
|
||||
current_sort_order = "desc"
|
||||
|
||||
# 更新按钮状态
|
||||
_update_button_states()
|
||||
|
||||
# 重新请求排行榜
|
||||
request_player_rankings()
|
||||
|
||||
# 在线筛选按钮点击处理
|
||||
func _on_online_filter_pressed():
|
||||
filter_online_only = !filter_online_only
|
||||
_update_button_states()
|
||||
request_player_rankings()
|
||||
|
||||
# 更新按钮状态显示
|
||||
func _update_button_states():
|
||||
# 重置所有排序按钮
|
||||
var sort_buttons = [seed_sort_btn, level_sort_btn, online_time_sort_btn, login_time_sort_btn, like_num_sort_btn, money_sort_btn]
|
||||
var sort_fields = ["seed_count", "等级", "online_time", "login_time", "like_num", "钱币"]
|
||||
var sort_names = ["种子数", "等级", "游玩时间", "登录时间", "点赞数", "金币数"]
|
||||
|
||||
for i in range(sort_buttons.size()):
|
||||
var btn = sort_buttons[i]
|
||||
var field = sort_fields[i]
|
||||
var name = sort_names[i]
|
||||
|
||||
if current_sort_by == field:
|
||||
# 当前排序字段,显示排序方向
|
||||
var arrow = "↓" if current_sort_order == "desc" else "↑"
|
||||
btn.text = name + arrow
|
||||
btn.modulate = Color.YELLOW
|
||||
else:
|
||||
# 非当前排序字段
|
||||
btn.text = name
|
||||
btn.modulate = Color.WHITE
|
||||
|
||||
# 更新在线筛选按钮
|
||||
if filter_online_only:
|
||||
is_online_sort_btn.text = "仅在线✓"
|
||||
is_online_sort_btn.modulate = Color.GREEN
|
||||
else:
|
||||
is_online_sort_btn.text = "全部玩家"
|
||||
is_online_sort_btn.modulate = Color.WHITE
|
||||
|
||||
# 请求玩家排行榜数据
|
||||
func request_player_rankings():
|
||||
if not tcp_network_manager_panel:
|
||||
register_player_num.text = "网络管理器不可用"
|
||||
register_player_num.modulate = Color.RED
|
||||
return false
|
||||
|
||||
if not tcp_network_manager_panel.is_connected_to_server():
|
||||
register_player_num.text = "未连接服务器"
|
||||
register_player_num.modulate = Color.RED
|
||||
return false
|
||||
|
||||
var success = tcp_network_manager_panel.sendGetPlayerRankings(current_sort_by, current_sort_order, filter_online_only, current_search_qq)
|
||||
if not success:
|
||||
register_player_num.text = "请求发送失败"
|
||||
register_player_num.modulate = Color.RED
|
||||
return false
|
||||
|
||||
return true
|
||||
|
||||
# 处理玩家排行榜响应
|
||||
func handle_player_rankings_response(data):
|
||||
# 重新启用刷新按钮
|
||||
refresh_button.disabled = false
|
||||
refresh_button.text = "刷新"
|
||||
|
||||
# 检查响应是否成功
|
||||
if not data.get("success", false):
|
||||
register_player_num.text = "获取注册人数失败"
|
||||
register_player_num.modulate = Color.RED
|
||||
Toast.show("获取排行榜失败:" + data.get("message", "未知错误"), Color.RED)
|
||||
return
|
||||
|
||||
# 显示注册总人数和在线人数
|
||||
var total_registered = data.get("total_registered_players", 0)
|
||||
var players_list = data.get("players", [])
|
||||
var online_count = 0
|
||||
for player in players_list:
|
||||
if player.get("is_online", false):
|
||||
online_count += 1
|
||||
|
||||
# 显示搜索和筛选信息
|
||||
var info_text = "总人数:" + str(int(total_registered)) + "| 在线:" + str(online_count)
|
||||
if current_search_qq != "":
|
||||
info_text += "| 搜索:" + current_search_qq
|
||||
if filter_online_only:
|
||||
info_text += "| 仅在线"
|
||||
|
||||
register_player_num.text = info_text
|
||||
register_player_num.modulate = Color.CYAN
|
||||
|
||||
# 清除现有的玩家条目(除了模板)
|
||||
for child in player_ranking_list.get_children():
|
||||
if child != player_info_template:
|
||||
child.queue_free()
|
||||
|
||||
# 添加玩家条目
|
||||
var players = players_list
|
||||
for player_data in players:
|
||||
add_player_entry(player_data)
|
||||
|
||||
print("排行榜数据已更新,显示", players.size(), "个玩家,注册总人数:", total_registered)
|
||||
|
||||
var result_text = "排行榜已刷新!显示 " + str(players.size()) + " 个玩家"
|
||||
if current_search_qq != "":
|
||||
result_text += "(搜索:" + current_search_qq + ")"
|
||||
if filter_online_only:
|
||||
result_text += "(仅在线)"
|
||||
|
||||
Toast.show(result_text, Color.GREEN)
|
||||
|
||||
# 添加单个玩家条目
|
||||
func add_player_entry(player_data):
|
||||
# 实例化新的玩家条目场景,避免 duplicate 引发的复制错误
|
||||
var player_entry = player_entry_scene.instantiate()
|
||||
player_entry.visible = true
|
||||
player_ranking_list.add_child(player_entry)
|
||||
|
||||
# 设置玩家信息
|
||||
|
||||
var player_name = player_entry.get_node("HBox/PlayerName")
|
||||
var player_level = player_entry.get_node("HBox/PlayerLevel")
|
||||
var player_money = player_entry.get_node("HBox/PlayerMoney")
|
||||
var player_seed_num = player_entry.get_node("HBox/SeedNum")
|
||||
var player_online_time = player_entry.get_node("HBox2/OnlineTime")
|
||||
var player_last_login_time = player_entry.get_node("HBox2/LastLoginTime")
|
||||
var player_avatar = player_entry.get_node("HBox/PlayerAvatar")
|
||||
var visit_button = player_entry.get_node("HBox/VisitButton")
|
||||
var player_is_online_time = player_entry.get_node("HBox2/IsOnlineTime")
|
||||
var player_like_num = player_entry.get_node("HBox2/LikeNum")
|
||||
|
||||
# 填充数据
|
||||
var username = player_data.get("玩家账号", "未知")
|
||||
var display_name = player_data.get("玩家昵称", username)
|
||||
player_name.text = display_name
|
||||
#都是整数,不要乱用浮点数
|
||||
player_level.text = "等级: " + str(int(player_data.get("等级", 0)))
|
||||
player_money.text = "金币: " + str(int(player_data.get("钱币", 0)))
|
||||
player_seed_num.text = "种子: " + str(int(player_data.get("seed_count", 0)))
|
||||
player_online_time.text = "游玩时间: " + player_data.get("总游玩时间", "0时0分0秒")
|
||||
player_last_login_time.text = "最后登录: " + player_data.get("最后登录时间", "未知")
|
||||
|
||||
# 设置在线状态显示
|
||||
var is_online = player_data.get("is_online", false)
|
||||
if is_online:
|
||||
player_is_online_time.text = "🟢 在线"
|
||||
player_is_online_time.modulate = Color.GREEN
|
||||
else:
|
||||
player_is_online_time.text = "🔴 离线"
|
||||
player_is_online_time.modulate = Color.GRAY
|
||||
|
||||
# 设置点赞数显示
|
||||
player_like_num.text = "点赞: " + str(int(player_data.get("like_num", 0)))
|
||||
|
||||
# 尝试加载玩家头像(使用用户名/QQ号加载头像,而不是显示名)
|
||||
if username.is_valid_int():
|
||||
player_avatar.load_from_url("http://q1.qlogo.cn/g?b=qq&nk=" + username + "&s=100")
|
||||
|
||||
# 设置访问按钮
|
||||
visit_button.pressed.connect(func(): _on_visit_player_pressed(username))
|
||||
|
||||
# 访问玩家按钮点击
|
||||
func _on_visit_player_pressed(username):
|
||||
#访问玩家后取消禁用相机功能,否则无法恢复
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
|
||||
|
||||
# 检查网络连接
|
||||
if not tcp_network_manager_panel or not tcp_network_manager_panel.is_connected_to_server():
|
||||
Toast.show("未连接服务器,无法访问玩家", Color.RED)
|
||||
return
|
||||
|
||||
# 检查是否尝试访问自己
|
||||
if main_game and main_game.user_name == username:
|
||||
Toast.show("不能访问自己的农场", Color.ORANGE)
|
||||
return
|
||||
|
||||
# 发送访问玩家请求
|
||||
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("sendVisitPlayer"):
|
||||
var success = tcp_network_manager_panel.sendVisitPlayer(username)
|
||||
if success:
|
||||
Toast.show("正在访问 " + username + " 的农场...", Color.YELLOW)
|
||||
else:
|
||||
Toast.show("发送访问请求失败", Color.RED)
|
||||
else:
|
||||
Toast.show("网络管理器不可用", Color.RED)
|
||||
|
||||
|
||||
#搜索按钮点击 - 通过QQ号查询玩家
|
||||
func _on_search_button_pressed():
|
||||
var search_text = search_line_edit.text.strip_edges()
|
||||
|
||||
# 如果搜索框为空,清除搜索条件
|
||||
if search_text == "":
|
||||
current_search_qq = ""
|
||||
Toast.show("已清除搜索条件", Color.YELLOW)
|
||||
else:
|
||||
# 验证输入是否为数字(QQ号)
|
||||
if not search_text.is_valid_int():
|
||||
Toast.show("请输入有效的QQ号(纯数字)", Color.RED)
|
||||
return
|
||||
|
||||
current_search_qq = search_text
|
||||
Toast.show("搜索QQ号:" + search_text, Color.YELLOW)
|
||||
|
||||
# 重新请求排行榜
|
||||
request_player_rankings()
|
||||
|
||||
#===================通用面板处理======================
|
||||
# 面板显示时的处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
pass
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
pass
|
||||
|
||||
# 刷新按钮点击
|
||||
func _on_refresh_button_pressed():
|
||||
# 检查网络连接
|
||||
if not tcp_network_manager_panel or not tcp_network_manager_panel.is_connected_to_server():
|
||||
register_player_num.text = "未连接服务器,无法刷新"
|
||||
register_player_num.modulate = Color.RED
|
||||
Toast.show("未连接服务器,无法刷新排行榜", Color.RED)
|
||||
return
|
||||
|
||||
# 显示加载状态
|
||||
register_player_num.text = "正在刷新排行榜..."
|
||||
register_player_num.modulate = Color.YELLOW
|
||||
refresh_button.disabled = true
|
||||
refresh_button.text = "刷新中..."
|
||||
|
||||
# 请求排行榜数据
|
||||
request_player_rankings()
|
||||
|
||||
# 5秒后重新启用按钮(防止卡住)
|
||||
await get_tree().create_timer(5.0).timeout
|
||||
if refresh_button.disabled:
|
||||
refresh_button.disabled = false
|
||||
refresh_button.text = "刷新"
|
||||
if register_player_num.text == "正在刷新排行榜...":
|
||||
register_player_num.text = "刷新超时,请重试"
|
||||
register_player_num.modulate = Color.RED
|
||||
|
||||
# 退出按钮点击
|
||||
func _on_quit_button_pressed():
|
||||
#打开面板后暂时禁用相机功能
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
|
||||
self.hide()
|
||||
|
||||
#===================通用面板处理======================
|
||||
@@ -0,0 +1 @@
|
||||
uid://fk4q3x6uqydd
|
||||
376
SproutFarm-Frontend/Script/BigPanel/PlayerStorePanel.gd
Normal file
376
SproutFarm-Frontend/Script/BigPanel/PlayerStorePanel.gd
Normal file
@@ -0,0 +1,376 @@
|
||||
extends Panel
|
||||
#玩家小卖部(目前可以卖道具,种子,成熟作物)
|
||||
#初始玩家有10个格子
|
||||
#然后玩家额外购买格子需要1000元,多加一个格子加500元,最多40个格子,格子满了不能再放了
|
||||
#玩家自己点击自己的摊位(商品格子)显示弹窗是否要取消放置商品
|
||||
#别人拜访玩家打开小卖部点击被拜访玩家的摊位显示批量购买弹窗
|
||||
@onready var quit_button: Button = $QuitButton #关闭玩家小卖部面板
|
||||
@onready var refresh_button: Button = $RefreshButton #刷新小卖部按钮
|
||||
@onready var store_grid: GridContainer = $ScrollContainer/Store_Grid #小卖部商品格子
|
||||
@onready var buy_product_booth_button: Button = $BuyProductBoothButton #购买格子按钮
|
||||
|
||||
# 获取主游戏引用
|
||||
@onready var main_game = get_node("/root/main")
|
||||
|
||||
# 当前小卖部数据
|
||||
var player_store_data: Array = []
|
||||
var max_store_slots: int = 10 # 默认10个格子
|
||||
|
||||
func _ready():
|
||||
# 连接按钮信号
|
||||
quit_button.pressed.connect(_on_quit_button_pressed)
|
||||
refresh_button.pressed.connect(_on_refresh_button_pressed)
|
||||
buy_product_booth_button.pressed.connect(_on_buy_product_booth_button_pressed)
|
||||
|
||||
# 连接可见性改变信号
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 默认隐藏面板
|
||||
self.hide()
|
||||
|
||||
#面板显示与隐藏切换处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
# 面板显示时更新小卖部数据
|
||||
update_player_store_ui()
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
|
||||
# 初始化玩家小卖部
|
||||
func init_player_store():
|
||||
update_player_store_ui()
|
||||
|
||||
# 更新小卖部UI
|
||||
func update_player_store_ui():
|
||||
# 清空商品格子
|
||||
for child in store_grid.get_children():
|
||||
child.queue_free()
|
||||
|
||||
# 获取小卖部数据
|
||||
if main_game.is_visiting_mode:
|
||||
# 访问模式:显示被访问玩家的小卖部
|
||||
var store_config = main_game.visited_player_data.get("小卖部配置", {"商品列表": [], "格子数": 10})
|
||||
player_store_data = store_config.get("商品列表", [])
|
||||
max_store_slots = store_config.get("格子数", 10)
|
||||
buy_product_booth_button.hide() # 访问模式下隐藏购买格子按钮
|
||||
else:
|
||||
# 正常模式:显示自己的小卖部
|
||||
var store_config = main_game.login_data.get("小卖部配置", {"商品列表": [], "格子数": 10})
|
||||
player_store_data = store_config.get("商品列表", [])
|
||||
max_store_slots = store_config.get("格子数", 10)
|
||||
buy_product_booth_button.show() # 正常模式下显示购买格子按钮
|
||||
|
||||
# 创建商品按钮
|
||||
_create_store_buttons()
|
||||
|
||||
# 更新购买格子按钮文本
|
||||
_update_buy_booth_button()
|
||||
|
||||
# 创建小卖部商品按钮
|
||||
func _create_store_buttons():
|
||||
# 为每个格子创建按钮
|
||||
for i in range(max_store_slots):
|
||||
var button = _create_store_slot_button(i)
|
||||
store_grid.add_child(button)
|
||||
|
||||
# 创建单个商品格子按钮
|
||||
func _create_store_slot_button(slot_index: int) -> Button:
|
||||
var button = main_game.item_button.duplicate()
|
||||
|
||||
# 确保按钮可见并可点击
|
||||
button.visible = true
|
||||
button.disabled = false
|
||||
button.focus_mode = Control.FOCUS_ALL
|
||||
|
||||
# 检查该格子是否有商品
|
||||
var product_data = null
|
||||
if slot_index < player_store_data.size():
|
||||
product_data = player_store_data[slot_index]
|
||||
|
||||
if product_data:
|
||||
# 有商品的格子
|
||||
var product_name = product_data.get("商品名称", "未知商品")
|
||||
var product_price = product_data.get("商品价格", 0)
|
||||
var product_count = product_data.get("商品数量", 0)
|
||||
var product_type = product_data.get("商品类型", "作物")
|
||||
|
||||
# 设置按钮文本
|
||||
button.text = str(product_name + "\n" + str(product_price) + "元/个\n库存:" + str(product_count))
|
||||
|
||||
# 更新商品图片
|
||||
_update_button_product_image(button, product_name, product_type)
|
||||
|
||||
# 设置工具提示
|
||||
button.tooltip_text = str(
|
||||
"商品: " + product_name + "\n" +
|
||||
"类型: " + product_type + "\n" +
|
||||
"单价: " + str(product_price) + " 元\n" +
|
||||
"库存: " + str(product_count) + " 个"
|
||||
)
|
||||
|
||||
# 连接点击事件
|
||||
if main_game.is_visiting_mode:
|
||||
# 访问模式:显示购买弹窗
|
||||
button.pressed.connect(func(): _on_product_buy_selected(product_data, slot_index))
|
||||
else:
|
||||
# 自己的小卖部:显示移除商品弹窗
|
||||
button.pressed.connect(func(): _on_product_manage_selected(product_data, slot_index))
|
||||
else:
|
||||
# 空格子
|
||||
button.text = "空闲格子\n\n点击添加商品"
|
||||
|
||||
# 设置为灰色样式
|
||||
if button.has_node("Title"):
|
||||
button.get_node("Title").modulate = Color.GRAY
|
||||
|
||||
# 只有在非访问模式下才允许点击空格子
|
||||
if not main_game.is_visiting_mode:
|
||||
button.pressed.connect(func(): _on_empty_slot_selected(slot_index))
|
||||
else:
|
||||
button.disabled = true
|
||||
|
||||
return button
|
||||
|
||||
# 更新商品图片
|
||||
func _update_button_product_image(button: Button, product_name: String, product_type: String):
|
||||
var crop_image = button.get_node_or_null("CropImage")
|
||||
if not crop_image:
|
||||
return
|
||||
|
||||
var texture = null
|
||||
|
||||
if product_type == "作物":
|
||||
# 作物商品:加载收获物图片
|
||||
texture = _get_crop_harvest_texture(product_name)
|
||||
# 未来可以添加其他类型的商品图片加载
|
||||
|
||||
if texture:
|
||||
crop_image.texture = texture
|
||||
crop_image.visible = true
|
||||
else:
|
||||
crop_image.visible = false
|
||||
|
||||
# 获取作物的收获物图片
|
||||
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_product_buy_selected(product_data: Dictionary, slot_index: int):
|
||||
var product_name = product_data.get("商品名称", "未知商品")
|
||||
var product_price = product_data.get("商品价格", 0)
|
||||
var product_count = product_data.get("商品数量", 0)
|
||||
var product_type = product_data.get("商品类型", "作物")
|
||||
|
||||
# 检查商品是否还有库存
|
||||
if product_count <= 0:
|
||||
Toast.show("该商品已售罄", Color.RED, 2.0, 1.0)
|
||||
return
|
||||
|
||||
# 获取批量购买弹窗
|
||||
var batch_buy_popup = get_node_or_null("/root/main/UI/DiaLog/BatchBuyPopup")
|
||||
if batch_buy_popup and batch_buy_popup.has_method("show_buy_popup"):
|
||||
# 显示批量购买弹窗
|
||||
batch_buy_popup.show_buy_popup(
|
||||
product_name,
|
||||
product_price,
|
||||
"小卖部商品",
|
||||
"store_product", # 特殊类型标识
|
||||
_on_confirm_buy_store_product,
|
||||
_on_cancel_buy_store_product
|
||||
)
|
||||
|
||||
# 临时保存购买信息
|
||||
batch_buy_popup.set_meta("store_slot_index", slot_index)
|
||||
batch_buy_popup.set_meta("store_product_data", product_data)
|
||||
else:
|
||||
Toast.show("购买功能暂未实现", Color.RED, 2.0, 1.0)
|
||||
|
||||
# 确认购买小卖部商品
|
||||
func _on_confirm_buy_store_product(product_name: String, unit_price: int, quantity: int, buy_type: String):
|
||||
var slot_index = get_node("/root/main/UI/DiaLog/BatchBuyPopup").get_meta("store_slot_index", -1)
|
||||
var product_data = get_node("/root/main/UI/DiaLog/BatchBuyPopup").get_meta("store_product_data", {})
|
||||
|
||||
if slot_index == -1 or product_data.is_empty():
|
||||
Toast.show("购买信息错误", Color.RED, 2.0, 1.0)
|
||||
return
|
||||
|
||||
# 发送购买请求到服务器
|
||||
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 visited_player_name = main_game.visited_player_data.get("玩家昵称", "")
|
||||
var message = {
|
||||
"type": "buy_store_product",
|
||||
"seller_username": main_game.visited_player_data.get("username", ""),
|
||||
"slot_index": slot_index,
|
||||
"product_name": product_name,
|
||||
"unit_price": unit_price,
|
||||
"quantity": quantity
|
||||
}
|
||||
tcp_network_manager.send_message(message)
|
||||
|
||||
Toast.show("购买请求已发送", Color.YELLOW, 2.0, 1.0)
|
||||
else:
|
||||
Toast.show("网络连接异常,无法购买", Color.RED, 2.0, 1.0)
|
||||
|
||||
# 取消购买小卖部商品
|
||||
func _on_cancel_buy_store_product():
|
||||
# 不需要做任何事情,弹窗会自动关闭
|
||||
pass
|
||||
|
||||
# 自己的小卖部:点击商品管理
|
||||
func _on_product_manage_selected(product_data: Dictionary, slot_index: int):
|
||||
var product_name = product_data.get("商品名称", "未知商品")
|
||||
var product_count = product_data.get("商品数量", 0)
|
||||
|
||||
# 显示管理确认对话框
|
||||
_show_product_manage_dialog(product_name, product_count, slot_index)
|
||||
|
||||
# 显示商品管理对话框
|
||||
func _show_product_manage_dialog(product_name: String, product_count: int, slot_index: int):
|
||||
var confirm_dialog = AcceptDialog.new()
|
||||
confirm_dialog.dialog_text = str(
|
||||
"商品管理\n\n" +
|
||||
"商品:" + product_name + "\n" +
|
||||
"库存:" + str(product_count) + " 个\n\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_remove_product.bind(slot_index, confirm_dialog))
|
||||
confirm_dialog.canceled.connect(_on_cancel_remove_product.bind(confirm_dialog))
|
||||
|
||||
# 显示对话框
|
||||
confirm_dialog.popup_centered()
|
||||
|
||||
# 确认下架商品
|
||||
func _on_confirm_remove_product(slot_index: int, dialog: AcceptDialog):
|
||||
# 发送下架商品请求到服务器
|
||||
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": "remove_store_product",
|
||||
"slot_index": slot_index
|
||||
}
|
||||
tcp_network_manager.send_message(message)
|
||||
|
||||
Toast.show("下架请求已发送", Color.YELLOW, 2.0, 1.0)
|
||||
else:
|
||||
Toast.show("网络连接异常,无法下架", Color.RED, 2.0, 1.0)
|
||||
|
||||
dialog.queue_free()
|
||||
|
||||
# 取消下架商品
|
||||
func _on_cancel_remove_product(dialog: AcceptDialog):
|
||||
dialog.queue_free()
|
||||
|
||||
# 点击空格子
|
||||
func _on_empty_slot_selected(slot_index: int):
|
||||
Toast.show("请从作物仓库选择商品添加到小卖部", Color.CYAN, 3.0, 1.0)
|
||||
|
||||
# 更新购买格子按钮
|
||||
func _update_buy_booth_button():
|
||||
if main_game.is_visiting_mode:
|
||||
return
|
||||
|
||||
var next_slot_cost = 1000 + (max_store_slots - 10) * 500
|
||||
if max_store_slots >= 40:
|
||||
buy_product_booth_button.text = "格子已满(40/40)"
|
||||
buy_product_booth_button.disabled = true
|
||||
else:
|
||||
buy_product_booth_button.text = str("购买格子(+" + str(next_slot_cost) + "元)")
|
||||
buy_product_booth_button.disabled = false
|
||||
|
||||
# 购买格子按钮处理
|
||||
func _on_buy_product_booth_button_pressed():
|
||||
if main_game.is_visiting_mode:
|
||||
return
|
||||
|
||||
if max_store_slots >= 40:
|
||||
Toast.show("格子数量已达上限", Color.RED, 2.0, 1.0)
|
||||
return
|
||||
|
||||
var next_slot_cost = 1000 + (max_store_slots - 10) * 500
|
||||
|
||||
if main_game.money < next_slot_cost:
|
||||
Toast.show("金钱不足,需要 " + str(next_slot_cost) + " 元", Color.RED, 2.0, 1.0)
|
||||
return
|
||||
|
||||
# 显示购买确认对话框
|
||||
_show_buy_booth_dialog(next_slot_cost)
|
||||
|
||||
# 显示购买格子确认对话框
|
||||
func _show_buy_booth_dialog(cost: int):
|
||||
var confirm_dialog = AcceptDialog.new()
|
||||
confirm_dialog.dialog_text = str(
|
||||
"购买小卖部格子\n\n" +
|
||||
"费用:" + str(cost) + " 元\n" +
|
||||
"当前格子数:" + str(max_store_slots) + "\n" +
|
||||
"购买后格子数:" + str(max_store_slots + 1) + "\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_buy_booth.bind(cost, confirm_dialog))
|
||||
confirm_dialog.canceled.connect(_on_cancel_buy_booth.bind(confirm_dialog))
|
||||
|
||||
# 显示对话框
|
||||
confirm_dialog.popup_centered()
|
||||
|
||||
# 确认购买格子
|
||||
func _on_confirm_buy_booth(cost: int, dialog: AcceptDialog):
|
||||
# 发送购买格子请求到服务器
|
||||
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": "buy_store_booth",
|
||||
"cost": cost
|
||||
}
|
||||
tcp_network_manager.send_message(message)
|
||||
|
||||
Toast.show("购买请求已发送", Color.YELLOW, 2.0, 1.0)
|
||||
else:
|
||||
Toast.show("网络连接异常,无法购买", Color.RED, 2.0, 1.0)
|
||||
|
||||
dialog.queue_free()
|
||||
|
||||
# 取消购买格子
|
||||
func _on_cancel_buy_booth(dialog: AcceptDialog):
|
||||
dialog.queue_free()
|
||||
|
||||
# 关闭面板
|
||||
func _on_quit_button_pressed():
|
||||
self.hide()
|
||||
|
||||
# 刷新小卖部
|
||||
func _on_refresh_button_pressed():
|
||||
update_player_store_ui()
|
||||
Toast.show("小卖部已刷新", Color.GREEN, 2.0, 1.0)
|
||||
@@ -0,0 +1 @@
|
||||
uid://bdavskipn547h
|
||||
72
SproutFarm-Frontend/Script/BigPanel/SpecialFarmPanel.gd
Normal file
72
SproutFarm-Frontend/Script/BigPanel/SpecialFarmPanel.gd
Normal file
@@ -0,0 +1,72 @@
|
||||
extends Panel
|
||||
|
||||
# 预添加常用的面板
|
||||
@onready var main_game = get_node("/root/main")
|
||||
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
|
||||
|
||||
func _ready() -> void:
|
||||
self.hide()
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
pass
|
||||
|
||||
func _on_quit_button_pressed() -> void:
|
||||
self.hide()
|
||||
pass
|
||||
|
||||
#访问花卉农场QQ:520
|
||||
func _on_flower_farm_button_pressed() -> void:
|
||||
_visit_special_farm("520", "花卉农场")
|
||||
|
||||
#访问杂交农场QQ:666
|
||||
func _on_hybrid_farm_button_pressed() -> void:
|
||||
_visit_special_farm("666", "杂交农场")
|
||||
|
||||
#访问幸运农场QQ:888
|
||||
func _on_lucky_farm_button_pressed() -> void:
|
||||
_visit_special_farm("888", "幸运农场")
|
||||
|
||||
#访问稻谷农场QQ:111
|
||||
func _on_rice_farm_button_pressed() -> void:
|
||||
_visit_special_farm("111", "稻谷农场")
|
||||
|
||||
#访问小麦农场QQ:222
|
||||
func _on_wheat_farm_button_pressed() -> void:
|
||||
_visit_special_farm("222", "小麦农场")
|
||||
|
||||
#访问水果农场QQ:333
|
||||
func _on_fruit_farm_button_pressed() -> void:
|
||||
_visit_special_farm("333", "水果农场")
|
||||
|
||||
# 访问特殊农场的通用函数
|
||||
func _visit_special_farm(farm_qq: String, farm_name: String) -> void:
|
||||
# 访问农场后取消禁用相机功能,否则无法恢复
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
|
||||
# 检查网络连接
|
||||
if not tcp_network_manager_panel or not tcp_network_manager_panel.is_connected_to_server():
|
||||
Toast.show("未连接服务器,无法访问" + farm_name, Color.RED)
|
||||
return
|
||||
|
||||
# 检查是否尝试访问自己
|
||||
if main_game and main_game.user_name == farm_qq:
|
||||
Toast.show("不能访问自己的农场", Color.ORANGE)
|
||||
return
|
||||
|
||||
# 发送访问特殊农场请求
|
||||
if tcp_network_manager_panel and tcp_network_manager_panel.has_method("sendVisitPlayer"):
|
||||
var success = tcp_network_manager_panel.sendVisitPlayer(farm_qq)
|
||||
if success:
|
||||
Toast.show("正在访问" + farm_name + "...", Color.YELLOW)
|
||||
# 隐藏面板
|
||||
self.hide()
|
||||
else:
|
||||
Toast.show("发送访问请求失败", Color.RED)
|
||||
else:
|
||||
Toast.show("网络管理器不可用", Color.RED)
|
||||
|
||||
# 面板显示与隐藏切换处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
@@ -0,0 +1 @@
|
||||
uid://btm2je8pg7rgk
|
||||
87
SproutFarm-Frontend/Script/Dialog/AcceptDialog.gd
Normal file
87
SproutFarm-Frontend/Script/Dialog/AcceptDialog.gd
Normal file
@@ -0,0 +1,87 @@
|
||||
extends AcceptDialog
|
||||
|
||||
@export var dialog_min_size := Vector2(400, 200)
|
||||
@export var ok_text := "确认"
|
||||
@export var cancel_text := "取消"
|
||||
|
||||
func _ready() -> void:
|
||||
# 设置弹窗最小尺寸
|
||||
self.set("rect_min_size", dialog_min_size)
|
||||
|
||||
# 设置标题和内容(可通过函数修改)
|
||||
set_dialog_title("默认标题")
|
||||
set_dialog_content("默认内容")
|
||||
|
||||
# 添加取消按钮
|
||||
var cancel_btn = self.add_cancel_button(cancel_text)
|
||||
_customize_button(cancel_btn)
|
||||
|
||||
# 获取并设置确认按钮
|
||||
var ok_btn = self.get_ok_button()
|
||||
ok_btn.text = ok_text
|
||||
_customize_button(ok_btn)
|
||||
|
||||
# 设置按钮样式属性
|
||||
self.add_theme_constant_override("buttons_min_height", 40)
|
||||
self.add_theme_constant_override("buttons_min_width", 120)
|
||||
self.add_theme_constant_override("buttons_separation", 16)
|
||||
|
||||
# 添加样式美化
|
||||
_apply_custom_theme()
|
||||
|
||||
func set_dialog_position(new_position :Vector2):
|
||||
self.position = new_position
|
||||
pass
|
||||
|
||||
func set_dialog_title(title: String) -> void:
|
||||
self.title = title
|
||||
|
||||
|
||||
func set_dialog_content(content: String) -> void:
|
||||
self.dialog_text = content
|
||||
|
||||
|
||||
func set_ok_text(text: String) -> void:
|
||||
ok_text = text
|
||||
get_ok_button().text = text
|
||||
|
||||
|
||||
func set_cancel_text(text: String) -> void:
|
||||
cancel_text = text
|
||||
# 注意:add_cancel_button 只能调用一次,想动态更新需要重建按钮
|
||||
|
||||
|
||||
func _customize_button(button: Button) -> void:
|
||||
button.custom_minimum_size = Vector2(120, 40)
|
||||
button.add_theme_color_override("font_color", Color.WHITE)
|
||||
button.add_theme_color_override("font_color_pressed", Color.WHITE)
|
||||
button.add_theme_color_override("font_color_hover", Color.WHITE)
|
||||
button.add_theme_color_override("bg_color", Color("3c82f6")) # 蓝色
|
||||
button.add_theme_color_override("bg_color_hover", Color("2563eb"))
|
||||
button.add_theme_color_override("bg_color_pressed", Color("1e40af"))
|
||||
button.add_theme_color_override("bg_color_disabled", Color("94a3b8"))
|
||||
|
||||
|
||||
func _apply_custom_theme() -> void:
|
||||
# 设置面板背景颜色
|
||||
var panel_style := StyleBoxFlat.new()
|
||||
#panel_style.bg_color = Color.AQUA # very light gray
|
||||
panel_style.set_border_width_all(2)
|
||||
#panel_style.border_color = Color("cbd5e1")
|
||||
|
||||
self.add_theme_stylebox_override("panel", panel_style) # ✅ 修正方法名
|
||||
|
||||
# 设置文字颜色(内容部分)
|
||||
var label = self.get_label()
|
||||
label.add_theme_color_override("font_color", Color("1e293b")) # 深灰蓝
|
||||
|
||||
|
||||
|
||||
# 确认按钮点击
|
||||
func _on_confirmed() -> void:
|
||||
print("确认按钮被点击")
|
||||
|
||||
|
||||
# 取消按钮点击
|
||||
func _on_canceled() -> void:
|
||||
print("取消按钮被点击")
|
||||
1
SproutFarm-Frontend/Script/Dialog/AcceptDialog.gd.uid
Normal file
1
SproutFarm-Frontend/Script/Dialog/AcceptDialog.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://ce8xcp770tolo
|
||||
213
SproutFarm-Frontend/Script/Dialog/AddProduct2StorePopup.gd
Normal file
213
SproutFarm-Frontend/Script/Dialog/AddProduct2StorePopup.gd
Normal file
@@ -0,0 +1,213 @@
|
||||
extends PanelContainer
|
||||
#用于添加商品到玩家小卖部的弹窗
|
||||
@onready var title: Label = $VBox/Title #弹窗标题
|
||||
@onready var contents: Label = $VBox/Contents #这里显示弹窗内容
|
||||
@onready var sell_num_input: LineEdit = $VBox/SellNumInput #这里输入需要放入小卖部的商品数量
|
||||
@onready var sell_price_input: LineEdit = $VBox/SellPriceInput #这里输入每件商品的价格
|
||||
@onready var sure_button: Button = $VBox/HBox/SureButton #确定放入按钮
|
||||
@onready var cancel_button: Button = $VBox/HBox/CancelButton #取消按钮
|
||||
|
||||
# 当前要添加的商品信息
|
||||
var current_product_name: String = ""
|
||||
var current_max_count: int = 0
|
||||
var current_suggested_price: int = 0
|
||||
var current_product_desc: String = ""
|
||||
|
||||
# 回调函数,用于处理确认添加
|
||||
var confirm_callback: Callable
|
||||
var cancel_callback: Callable
|
||||
|
||||
func _ready():
|
||||
# 连接按钮信号
|
||||
sure_button.pressed.connect(_on_sure_button_pressed)
|
||||
cancel_button.pressed.connect(_on_cancel_button_pressed)
|
||||
|
||||
# 设置输入框的默认值和限制
|
||||
sell_num_input.text = "1"
|
||||
sell_num_input.placeholder_text = "请输入数量"
|
||||
sell_price_input.placeholder_text = "请输入单价"
|
||||
|
||||
# 只允许输入数字
|
||||
sell_num_input.text_changed.connect(_on_sell_num_changed)
|
||||
sell_price_input.text_changed.connect(_on_sell_price_changed)
|
||||
|
||||
# 连接可见性改变信号
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 默认隐藏弹窗
|
||||
self.hide()
|
||||
|
||||
#面板显示与隐藏切换处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
pass
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
pass
|
||||
|
||||
# 显示添加商品弹窗
|
||||
func show_add_product_popup(product_name: String, max_count: int, suggested_price: int, product_desc: String, on_confirm: Callable, on_cancel: Callable = Callable()):
|
||||
current_product_name = product_name
|
||||
current_max_count = max_count
|
||||
current_suggested_price = suggested_price
|
||||
current_product_desc = product_desc
|
||||
confirm_callback = on_confirm
|
||||
cancel_callback = on_cancel
|
||||
|
||||
# 设置弹窗内容
|
||||
title.text = "添加商品到小卖部"
|
||||
|
||||
contents.text = str(
|
||||
"商品名称: " + product_name + "\n" +
|
||||
"可用数量: " + str(max_count) + " 个\n" +
|
||||
"建议价格: " + str(suggested_price) + " 元/个\n" +
|
||||
"描述: " + product_desc + "\n\n" +
|
||||
"请设置出售数量和价格:"
|
||||
)
|
||||
|
||||
# 设置默认值
|
||||
sell_num_input.text = "1"
|
||||
sell_price_input.text = str(suggested_price)
|
||||
|
||||
# 显示弹窗并居中
|
||||
self.show()
|
||||
self.move_to_front()
|
||||
|
||||
# 处理数量输入变化
|
||||
func _on_sell_num_changed(new_text: String):
|
||||
# 只允许输入数字
|
||||
var filtered_text = ""
|
||||
for char in new_text:
|
||||
if char.is_valid_int():
|
||||
filtered_text += char
|
||||
|
||||
# 检查是否超过最大值并自动修正
|
||||
if not filtered_text.is_empty():
|
||||
var quantity = filtered_text.to_int()
|
||||
if quantity > current_max_count:
|
||||
filtered_text = str(current_max_count)
|
||||
|
||||
if filtered_text != new_text:
|
||||
sell_num_input.text = filtered_text
|
||||
sell_num_input.caret_column = filtered_text.length()
|
||||
|
||||
# 更新预览信息
|
||||
_update_preview_info()
|
||||
|
||||
# 处理价格输入变化
|
||||
func _on_sell_price_changed(new_text: String):
|
||||
# 只允许输入数字
|
||||
var filtered_text = ""
|
||||
for char in new_text:
|
||||
if char.is_valid_int():
|
||||
filtered_text += char
|
||||
|
||||
# 检查是否超过最大值并自动修正
|
||||
if not filtered_text.is_empty():
|
||||
var price = filtered_text.to_int()
|
||||
if price > 999999999:
|
||||
filtered_text = "999999999"
|
||||
|
||||
if filtered_text != new_text:
|
||||
sell_price_input.text = filtered_text
|
||||
sell_price_input.caret_column = filtered_text.length()
|
||||
|
||||
# 更新预览信息
|
||||
_update_preview_info()
|
||||
|
||||
# 更新预览信息
|
||||
func _update_preview_info():
|
||||
var quantity = get_sell_quantity()
|
||||
var unit_price = get_sell_price()
|
||||
var total_value = quantity * unit_price
|
||||
|
||||
# 检查数量是否超过最大可用数量
|
||||
var quantity_status = ""
|
||||
if quantity > current_max_count:
|
||||
quantity_status = " (超出库存!)"
|
||||
|
||||
# 检查价格是否合理
|
||||
var price_status = ""
|
||||
if unit_price <= 0:
|
||||
price_status = " (价格无效!)"
|
||||
elif unit_price < current_suggested_price * 0.5:
|
||||
price_status = " (价格偏低)"
|
||||
elif unit_price > current_suggested_price * 2:
|
||||
price_status = " (价格偏高)"
|
||||
|
||||
var preview_info = "\n上架数量: " + str(quantity) + " 个" + quantity_status + "\n单价: " + str(unit_price) + " 元/个" + price_status + "\n总价值: " + str(total_value) + " 元"
|
||||
|
||||
# 更新内容显示
|
||||
var base_content = str(
|
||||
"商品名称: " + current_product_name + "\n" +
|
||||
"可用数量: " + str(current_max_count) + " 个\n" +
|
||||
"建议价格: " + str(current_suggested_price) + " 元/个\n" +
|
||||
"描述: " + current_product_desc + "\n\n" +
|
||||
"请设置出售数量和价格:"
|
||||
)
|
||||
|
||||
contents.text = base_content + preview_info
|
||||
|
||||
# 获取出售数量
|
||||
func get_sell_quantity() -> int:
|
||||
var text = sell_num_input.text.strip_edges()
|
||||
if text.is_empty():
|
||||
return 1
|
||||
|
||||
var quantity = text.to_int()
|
||||
quantity = max(1, quantity) # 至少出售1个
|
||||
quantity = min(quantity, current_max_count) # 不超过最大值
|
||||
return quantity
|
||||
|
||||
# 获取出售价格
|
||||
func get_sell_price() -> int:
|
||||
var text = sell_price_input.text.strip_edges()
|
||||
if text.is_empty():
|
||||
return current_suggested_price
|
||||
|
||||
var price = text.to_int()
|
||||
price = max(1, price) # 至少1元
|
||||
price = min(price, 999999999) # 不超过最大值
|
||||
return price
|
||||
|
||||
# 确认添加按钮处理
|
||||
func _on_sure_button_pressed():
|
||||
var quantity = get_sell_quantity()
|
||||
var unit_price = get_sell_price()
|
||||
|
||||
if quantity <= 0:
|
||||
_show_error("数量必须大于0")
|
||||
return
|
||||
|
||||
if quantity > current_max_count:
|
||||
_show_error("数量不能超过库存数量(" + str(current_max_count) + ")")
|
||||
return
|
||||
|
||||
if unit_price <= 0:
|
||||
_show_error("价格必须大于0")
|
||||
return
|
||||
|
||||
# 调用确认回调函数
|
||||
if confirm_callback.is_valid():
|
||||
confirm_callback.call(current_product_name, quantity, unit_price)
|
||||
|
||||
# 隐藏弹窗
|
||||
self.hide()
|
||||
|
||||
# 取消添加按钮处理
|
||||
func _on_cancel_button_pressed():
|
||||
# 调用取消回调函数
|
||||
if cancel_callback.is_valid():
|
||||
cancel_callback.call()
|
||||
|
||||
# 隐藏弹窗
|
||||
self.hide()
|
||||
|
||||
# 显示错误信息
|
||||
func _show_error(message: String):
|
||||
# 显示Toast错误提示
|
||||
if has_node("/root/Toast"):
|
||||
get_node("/root/Toast").show(message, Color.RED, 2.0, 1.0)
|
||||
else:
|
||||
print("添加商品弹窗错误: " + message)
|
||||
@@ -0,0 +1 @@
|
||||
uid://cha0uw4ra1trr
|
||||
163
SproutFarm-Frontend/Script/Dialog/BatchBuyPopup.gd
Normal file
163
SproutFarm-Frontend/Script/Dialog/BatchBuyPopup.gd
Normal file
@@ -0,0 +1,163 @@
|
||||
extends PanelContainer
|
||||
#这是批量购买弹窗
|
||||
@onready var title: Label = $VBox/Title #弹窗标题
|
||||
@onready var contents: Label = $VBox/Contents #弹窗内容
|
||||
@onready var buy_num_edit: LineEdit = $VBox/BuyNumEdit #购买数量
|
||||
@onready var sure_button: Button = $VBox/HBox/SureButton #确认购买
|
||||
@onready var cancel_button: Button = $VBox/HBox/CancelButton #取消购买
|
||||
|
||||
# 当前购买的商品信息
|
||||
var current_item_name: String = ""
|
||||
var current_item_cost: int = 0
|
||||
var current_item_desc: String = ""
|
||||
var current_buy_type: String = "" # "seed" 或 "item"
|
||||
var max_stock: int = 999999999 # 最大库存限制,默认无限制
|
||||
|
||||
# 回调函数,用于处理确认购买
|
||||
var confirm_callback: Callable
|
||||
var cancel_callback: Callable
|
||||
|
||||
func _ready():
|
||||
# 连接按钮信号
|
||||
sure_button.pressed.connect(_on_sure_button_pressed)
|
||||
cancel_button.pressed.connect(_on_cancel_button_pressed)
|
||||
|
||||
# 设置数量输入框的默认值和限制
|
||||
buy_num_edit.text = "1"
|
||||
buy_num_edit.placeholder_text = "请输入购买数量"
|
||||
|
||||
# 只允许输入数字
|
||||
buy_num_edit.text_changed.connect(_on_buy_num_changed)
|
||||
|
||||
# 默认隐藏弹窗
|
||||
self.hide()
|
||||
|
||||
#面板显示与隐藏切换处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
pass
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
pass
|
||||
|
||||
# 显示批量购买弹窗
|
||||
func show_buy_popup(item_name: String, item_cost: int, item_desc: String, buy_type: String, on_confirm: Callable, on_cancel: Callable = Callable(), stock_limit: int = 999999999):
|
||||
current_item_name = item_name
|
||||
current_item_cost = item_cost
|
||||
current_item_desc = item_desc
|
||||
current_buy_type = buy_type
|
||||
confirm_callback = on_confirm
|
||||
cancel_callback = on_cancel
|
||||
max_stock = stock_limit
|
||||
|
||||
# 设置弹窗内容
|
||||
if buy_type == "seed":
|
||||
title.text = "批量购买种子"
|
||||
else:
|
||||
title.text = "批量购买道具"
|
||||
|
||||
# 添加库存信息到内容中
|
||||
var stock_info = ""
|
||||
if stock_limit < 999999999:
|
||||
stock_info = "\n当前库存: " + str(stock_limit) + " 个"
|
||||
|
||||
contents.text = str(
|
||||
"商品名称: " + item_name + "\n" +
|
||||
"单价: " + str(item_cost) + " 元\n" +
|
||||
"描述: " + item_desc + stock_info + "\n\n" +
|
||||
"请输入购买数量:"
|
||||
)
|
||||
|
||||
# 重置购买数量为1
|
||||
buy_num_edit.text = "1"
|
||||
|
||||
# 显示弹窗并居中
|
||||
self.show()
|
||||
|
||||
|
||||
# 处理数量输入变化
|
||||
func _on_buy_num_changed(new_text: String):
|
||||
# 只允许输入数字
|
||||
var filtered_text = ""
|
||||
for char in new_text:
|
||||
if char.is_valid_int():
|
||||
filtered_text += char
|
||||
|
||||
# 检查是否超过库存限制并自动修正
|
||||
if not filtered_text.is_empty():
|
||||
var quantity = filtered_text.to_int()
|
||||
if quantity > max_stock:
|
||||
filtered_text = str(max_stock)
|
||||
elif quantity > 999999999:
|
||||
filtered_text = "999999999"
|
||||
|
||||
if filtered_text != new_text:
|
||||
buy_num_edit.text = filtered_text
|
||||
buy_num_edit.caret_column = filtered_text.length()
|
||||
|
||||
# 更新总价显示
|
||||
_update_total_cost()
|
||||
|
||||
# 更新总价显示
|
||||
func _update_total_cost():
|
||||
var quantity = get_buy_quantity()
|
||||
var total_cost = quantity * current_item_cost
|
||||
|
||||
var cost_info = "\n总价: " + str(total_cost) + " 元"
|
||||
|
||||
# 更新内容显示
|
||||
var base_content = str(
|
||||
"商品名称: " + current_item_name + "\n" +
|
||||
"单价: " + str(current_item_cost) + " 元\n" +
|
||||
"描述: " + current_item_desc + "\n\n" +
|
||||
"请输入购买数量:"
|
||||
)
|
||||
|
||||
contents.text = base_content + cost_info
|
||||
|
||||
# 获取购买数量
|
||||
func get_buy_quantity() -> int:
|
||||
var text = buy_num_edit.text.strip_edges()
|
||||
if text.is_empty():
|
||||
return 1
|
||||
|
||||
var quantity = text.to_int()
|
||||
return max(1, quantity) # 至少购买1个
|
||||
|
||||
# 确认购买按钮处理
|
||||
func _on_sure_button_pressed():
|
||||
var quantity = get_buy_quantity()
|
||||
|
||||
if quantity <= 0:
|
||||
_show_error("购买数量必须大于0")
|
||||
return
|
||||
|
||||
# 检查是否超过库存限制
|
||||
if quantity > max_stock:
|
||||
_show_error("购买数量超过库存限制!最大可购买: " + str(max_stock))
|
||||
return
|
||||
|
||||
# 调用确认回调函数
|
||||
if confirm_callback.is_valid():
|
||||
confirm_callback.call(current_item_name, current_item_cost, quantity, current_buy_type)
|
||||
|
||||
# 隐藏弹窗
|
||||
self.hide()
|
||||
|
||||
# 取消购买按钮处理
|
||||
func _on_cancel_button_pressed():
|
||||
# 调用取消回调函数
|
||||
if cancel_callback.is_valid():
|
||||
cancel_callback.call()
|
||||
|
||||
# 隐藏弹窗
|
||||
self.hide()
|
||||
|
||||
# 显示错误信息
|
||||
func _show_error(message: String):
|
||||
# 这里可以显示Toast或者其他错误提示
|
||||
if has_node("/root/Toast"):
|
||||
get_node("/root/Toast").show(message, Color.RED, 2.0, 1.0)
|
||||
else:
|
||||
print("批量购买弹窗错误: " + message)
|
||||
1
SproutFarm-Frontend/Script/Dialog/BatchBuyPopup.gd.uid
Normal file
1
SproutFarm-Frontend/Script/Dialog/BatchBuyPopup.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://d4fvv2sjngajr
|
||||
163
SproutFarm-Frontend/Script/Dialog/BatchSellPopup.gd
Normal file
163
SproutFarm-Frontend/Script/Dialog/BatchSellPopup.gd
Normal file
@@ -0,0 +1,163 @@
|
||||
extends PanelContainer
|
||||
#用于作物批量出售作物弹窗
|
||||
@onready var title: Label = $VBox/Title #弹窗标题
|
||||
@onready var contents: Label = $VBox/Contents #这里显示弹窗内容
|
||||
@onready var sell_num_edit: LineEdit = $VBox/SellNumEdit #出售作物数量
|
||||
@onready var sure_button: Button = $VBox/HBox/SureButton #确定按钮
|
||||
@onready var cancel_button: Button = $VBox/HBox/CancelButton #取消按钮
|
||||
|
||||
# 当前出售的作物信息
|
||||
var current_crop_name: String = ""
|
||||
var current_max_count: int = 0
|
||||
var current_unit_price: int = 0
|
||||
var current_crop_desc: String = ""
|
||||
|
||||
# 回调函数,用于处理确认出售
|
||||
var confirm_callback: Callable
|
||||
var cancel_callback: Callable
|
||||
|
||||
func _ready():
|
||||
# 连接按钮信号
|
||||
sure_button.pressed.connect(_on_sure_button_pressed)
|
||||
cancel_button.pressed.connect(_on_cancel_button_pressed)
|
||||
|
||||
# 设置数量输入框的默认值和限制
|
||||
sell_num_edit.text = "1"
|
||||
sell_num_edit.placeholder_text = "请输入出售数量"
|
||||
|
||||
# 只允许输入数字
|
||||
sell_num_edit.text_changed.connect(_on_sell_num_changed)
|
||||
|
||||
# 连接可见性改变信号
|
||||
visibility_changed.connect(_on_visibility_changed)
|
||||
|
||||
# 默认隐藏弹窗
|
||||
self.hide()
|
||||
|
||||
#面板显示与隐藏切换处理
|
||||
func _on_visibility_changed():
|
||||
if visible:
|
||||
GlobalVariables.isZoomDisabled = true
|
||||
pass
|
||||
else:
|
||||
GlobalVariables.isZoomDisabled = false
|
||||
pass
|
||||
|
||||
# 显示批量出售弹窗
|
||||
func show_sell_popup(crop_name: String, max_count: int, unit_price: int, crop_desc: String, on_confirm: Callable, on_cancel: Callable = Callable()):
|
||||
current_crop_name = crop_name
|
||||
current_max_count = max_count
|
||||
current_unit_price = unit_price
|
||||
current_crop_desc = crop_desc
|
||||
confirm_callback = on_confirm
|
||||
cancel_callback = on_cancel
|
||||
|
||||
# 设置弹窗内容
|
||||
title.text = "批量出售作物"
|
||||
|
||||
contents.text = str(
|
||||
"作物名称: " + crop_name + "\n" +
|
||||
"单价: " + str(unit_price) + " 元/个\n" +
|
||||
"可出售数量: " + str(max_count) + " 个\n" +
|
||||
"描述: " + crop_desc + "\n\n" +
|
||||
"请输入出售数量:"
|
||||
)
|
||||
|
||||
# 重置出售数量为1
|
||||
sell_num_edit.text = "1"
|
||||
|
||||
# 显示弹窗并居中
|
||||
self.show()
|
||||
self.move_to_front()
|
||||
|
||||
# 处理数量输入变化
|
||||
func _on_sell_num_changed(new_text: String):
|
||||
# 只允许输入数字
|
||||
var filtered_text = ""
|
||||
for char in new_text:
|
||||
if char.is_valid_int():
|
||||
filtered_text += char
|
||||
|
||||
# 检查是否超过最大值并自动修正
|
||||
if not filtered_text.is_empty():
|
||||
var quantity = filtered_text.to_int()
|
||||
if quantity > current_max_count:
|
||||
filtered_text = str(current_max_count)
|
||||
|
||||
if filtered_text != new_text:
|
||||
sell_num_edit.text = filtered_text
|
||||
sell_num_edit.caret_column = filtered_text.length()
|
||||
|
||||
# 更新总价显示
|
||||
_update_total_income()
|
||||
|
||||
# 更新总收入显示
|
||||
func _update_total_income():
|
||||
var quantity = get_sell_quantity()
|
||||
var total_income = quantity * current_unit_price
|
||||
|
||||
# 检查数量是否超过最大可售数量
|
||||
var quantity_status = ""
|
||||
if quantity > current_max_count:
|
||||
quantity_status = " (超出库存!)"
|
||||
#quantity = current_max_count
|
||||
var income_info = "\n出售数量: " + str(quantity) + " 个" + quantity_status + "\n总收入: " + str(total_income) + " 元"
|
||||
|
||||
# 更新内容显示
|
||||
var base_content = str(
|
||||
"作物名称: " + current_crop_name + "\n" +
|
||||
"单价: " + str(current_unit_price) + " 元/个\n" +
|
||||
"可出售数量: " + str(current_max_count) + " 个\n" +
|
||||
"描述: " + current_crop_desc + "\n\n" +
|
||||
"请输入出售数量:"
|
||||
)
|
||||
|
||||
contents.text = base_content + income_info
|
||||
|
||||
# 获取出售数量
|
||||
func get_sell_quantity() -> int:
|
||||
var text = sell_num_edit.text.strip_edges()
|
||||
if text.is_empty():
|
||||
return 1
|
||||
|
||||
var quantity = text.to_int()
|
||||
quantity = max(1, quantity) # 至少出售1个
|
||||
quantity = min(quantity, current_max_count) # 不超过最大值
|
||||
return quantity
|
||||
|
||||
# 确认出售按钮处理
|
||||
func _on_sure_button_pressed():
|
||||
var quantity = get_sell_quantity()
|
||||
|
||||
if quantity <= 0:
|
||||
_show_error("出售数量必须大于0")
|
||||
return
|
||||
|
||||
if quantity > current_max_count:
|
||||
#quantity = current_max_count
|
||||
_show_error("出售数量不能超过库存数量(" + str(current_max_count) + ")")
|
||||
return
|
||||
|
||||
# 调用确认回调函数
|
||||
if confirm_callback.is_valid():
|
||||
confirm_callback.call(current_crop_name, quantity, current_unit_price)
|
||||
|
||||
# 隐藏弹窗
|
||||
self.hide()
|
||||
|
||||
# 取消出售按钮处理
|
||||
func _on_cancel_button_pressed():
|
||||
# 调用取消回调函数
|
||||
if cancel_callback.is_valid():
|
||||
cancel_callback.call()
|
||||
|
||||
# 隐藏弹窗
|
||||
self.hide()
|
||||
|
||||
# 显示错误信息
|
||||
func _show_error(message: String):
|
||||
# 显示Toast错误提示
|
||||
if has_node("/root/Toast"):
|
||||
get_node("/root/Toast").show(message, Color.RED, 2.0, 1.0)
|
||||
else:
|
||||
print("批量出售弹窗错误: " + message)
|
||||
1
SproutFarm-Frontend/Script/Dialog/BatchSellPopup.gd.uid
Normal file
1
SproutFarm-Frontend/Script/Dialog/BatchSellPopup.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://dsmmxivba06ab
|
||||
248
SproutFarm-Frontend/Script/SmallPanel/AccountSettingPanel.gd
Normal file
248
SproutFarm-Frontend/Script/SmallPanel/AccountSettingPanel.gd
Normal 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)
|
||||
@@ -0,0 +1 @@
|
||||
uid://dinrduqwsf5k5
|
||||
215
SproutFarm-Frontend/Script/SmallPanel/CropInformPanel.gd
Normal file
215
SproutFarm-Frontend/Script/SmallPanel/CropInformPanel.gd
Normal 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
|
||||
@@ -0,0 +1 @@
|
||||
uid://b185o1hjnlrv5
|
||||
463
SproutFarm-Frontend/Script/SmallPanel/DebugPanel.gd
Normal file
463
SproutFarm-Frontend/Script/SmallPanel/DebugPanel.gd
Normal 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
|
||||
1
SproutFarm-Frontend/Script/SmallPanel/DebugPanel.gd.uid
Normal file
1
SproutFarm-Frontend/Script/SmallPanel/DebugPanel.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bvhupqlw2h1j8
|
||||
@@ -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 "暂无消息"
|
||||
@@ -0,0 +1 @@
|
||||
uid://bakeq8tm6r4j4
|
||||
637
SproutFarm-Frontend/Script/SmallPanel/LandPanel.gd
Normal file
637
SproutFarm-Frontend/Script/SmallPanel/LandPanel.gd
Normal 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秒"
|
||||
1
SproutFarm-Frontend/Script/SmallPanel/LandPanel.gd.uid
Normal file
1
SproutFarm-Frontend/Script/SmallPanel/LandPanel.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://bljtkxil64h14
|
||||
620
SproutFarm-Frontend/Script/SmallPanel/OneClickPlantPanel.gd
Normal file
620
SproutFarm-Frontend/Script/SmallPanel/OneClickPlantPanel.gd
Normal 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
|
||||
#======================通用面板处理=====================
|
||||
@@ -0,0 +1 @@
|
||||
uid://rlk8e51pibtm
|
||||
207
SproutFarm-Frontend/Script/SmallPanel/OnlineGiftPanel.gd
Normal file
207
SproutFarm-Frontend/Script/SmallPanel/OnlineGiftPanel.gd
Normal 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
|
||||
#================通用面板处理==================
|
||||
@@ -0,0 +1 @@
|
||||
uid://ccaqrb6sdwbux
|
||||
653
SproutFarm-Frontend/Script/SmallPanel/PetInformPanel.gd
Normal file
653
SproutFarm-Frontend/Script/SmallPanel/PetInformPanel.gd
Normal 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
|
||||
@@ -0,0 +1 @@
|
||||
uid://doo34ll0yb078
|
||||
257
SproutFarm-Frontend/Script/SmallPanel/ScareCrowPanel.gd
Normal file
257
SproutFarm-Frontend/Script/SmallPanel/ScareCrowPanel.gd
Normal 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
|
||||
@@ -0,0 +1 @@
|
||||
uid://dobao5y5s2dij
|
||||
123
SproutFarm-Frontend/Script/SmallPanel/TodayDivinationPanel.gd
Normal file
123
SproutFarm-Frontend/Script/SmallPanel/TodayDivinationPanel.gd
Normal 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]"
|
||||
@@ -0,0 +1 @@
|
||||
uid://bkel88rscubov
|
||||
316
SproutFarm-Frontend/Script/SmallPanel/WisdomTreePanel.gd
Normal file
316
SproutFarm-Frontend/Script/SmallPanel/WisdomTreePanel.gd
Normal 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
|
||||
@@ -0,0 +1 @@
|
||||
uid://dwf28j01ckg3y
|
||||
Reference in New Issue
Block a user