423 lines
15 KiB
GDScript
423 lines
15 KiB
GDScript
extends Panel
|
||
class_name DailyCheckInPanel
|
||
|
||
## 每日签到系统 - 后端对接版本
|
||
## 功能:与服务器对接的签到系统,支持实时数据同步
|
||
## 奖励平衡性已根据 crop_data.json 调整
|
||
|
||
# =============================================================================
|
||
# 信号定义 - 用于与后端系统通信
|
||
# =============================================================================
|
||
signal check_in_completed(rewards: Dictionary) # 签到完成信号
|
||
signal reward_claimed(reward_type: String, amount: int) # 奖励领取信号
|
||
signal check_in_data_loaded(data: 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
|
||
|
||
# =============================================================================
|
||
# 数据存储
|
||
# =============================================================================
|
||
var check_in_data: Dictionary = {}
|
||
var today_date: String
|
||
var consecutive_days: int = 0
|
||
var has_checked_in_today: bool = false
|
||
|
||
# 网络管理器引用
|
||
var network_manager
|
||
var main_game
|
||
|
||
# =============================================================================
|
||
# 奖励配置系统 - 根据 crop_data.json 平衡调整
|
||
# =============================================================================
|
||
var reward_configs: Dictionary = {
|
||
"coins": {
|
||
"min": 200,
|
||
"max": 500,
|
||
"name": "钱币",
|
||
"color": "#FFD700",
|
||
"icon": "💰"
|
||
},
|
||
"exp": {
|
||
"min": 50,
|
||
"max": 120,
|
||
"name": "经验",
|
||
"color": "#00BFFF",
|
||
"icon": "⭐"
|
||
},
|
||
# 种子配置根据 crop_data.json 的作物等级和价值设定
|
||
"seeds": {
|
||
"普通": [
|
||
{"name": "小麦", "color": "#F4A460", "icon": "🌱", "rarity_color": "#FFFFFF"},
|
||
{"name": "胡萝卜", "color": "#FFA500", "icon": "🌱", "rarity_color": "#FFFFFF"},
|
||
{"name": "土豆", "color": "#D2691E", "icon": "🌱", "rarity_color": "#FFFFFF"},
|
||
{"name": "稻谷", "color": "#DAA520", "icon": "🌱", "rarity_color": "#FFFFFF"}
|
||
],
|
||
"优良": [
|
||
{"name": "玉米", "color": "#FFD700", "icon": "🌱", "rarity_color": "#00FF00"},
|
||
{"name": "番茄", "color": "#FF6347", "icon": "🌱", "rarity_color": "#00FF00"},
|
||
{"name": "洋葱", "color": "#DDA0DD", "icon": "🌱", "rarity_color": "#00FF00"},
|
||
{"name": "大豆", "color": "#8FBC8F", "icon": "🌱", "rarity_color": "#00FF00"},
|
||
{"name": "豌豆", "color": "#90EE90", "icon": "🌱", "rarity_color": "#00FF00"},
|
||
{"name": "黄瓜", "color": "#32CD32", "icon": "🌱", "rarity_color": "#00FF00"},
|
||
{"name": "大白菜", "color": "#F0FFF0", "icon": "🌱", "rarity_color": "#00FF00"}
|
||
],
|
||
"稀有": [
|
||
{"name": "草莓", "color": "#FF69B4", "icon": "🌱", "rarity_color": "#0080FF"},
|
||
{"name": "花椰菜", "color": "#F5F5DC", "icon": "🌱", "rarity_color": "#0080FF"},
|
||
{"name": "柿子", "color": "#FF4500", "icon": "🌱", "rarity_color": "#0080FF"},
|
||
{"name": "蓝莓", "color": "#4169E1", "icon": "🌱", "rarity_color": "#0080FF"},
|
||
{"name": "树莓", "color": "#DC143C", "icon": "🌱", "rarity_color": "#0080FF"}
|
||
],
|
||
"史诗": [
|
||
{"name": "葡萄", "color": "#9370DB", "icon": "🌱", "rarity_color": "#8A2BE2"},
|
||
{"name": "南瓜", "color": "#FF8C00", "icon": "🌱", "rarity_color": "#8A2BE2"},
|
||
{"name": "芦笋", "color": "#9ACD32", "icon": "🌱", "rarity_color": "#8A2BE2"},
|
||
{"name": "茄子", "color": "#9400D3", "icon": "🌱", "rarity_color": "#8A2BE2"},
|
||
{"name": "向日葵", "color": "#FFD700", "icon": "🌱", "rarity_color": "#8A2BE2"},
|
||
{"name": "蕨菜", "color": "#228B22", "icon": "🌱", "rarity_color": "#8A2BE2"}
|
||
],
|
||
"传奇": [
|
||
{"name": "西瓜", "color": "#FF69B4", "icon": "🌱", "rarity_color": "#FF8C00"},
|
||
{"name": "甘蔗", "color": "#DDA0DD", "icon": "🌱", "rarity_color": "#FF8C00"},
|
||
{"name": "香草", "color": "#98FB98", "icon": "🌱", "rarity_color": "#FF8C00"},
|
||
{"name": "甜菜", "color": "#DC143C", "icon": "🌱", "rarity_color": "#FF8C00"},
|
||
{"name": "人参", "color": "#DAA520", "icon": "🌱", "rarity_color": "#FF8C00"},
|
||
{"name": "富贵竹", "color": "#32CD32", "icon": "🌱", "rarity_color": "#FF8C00"},
|
||
{"name": "芦荟", "color": "#9ACD32", "icon": "🌱", "rarity_color": "#FF8C00"},
|
||
{"name": "哈密瓜", "color": "#FFB6C1", "icon": "🌱", "rarity_color": "#FF8C00"}
|
||
]
|
||
}
|
||
}
|
||
|
||
# =============================================================================
|
||
# 系统初始化
|
||
# =============================================================================
|
||
func _ready() -> void:
|
||
_initialize_system()
|
||
|
||
func _initialize_system() -> void:
|
||
"""初始化签到系统"""
|
||
daily_check_in_reward.hide()
|
||
today_date = Time.get_date_string_from_system()
|
||
|
||
# 获取网络管理器和主游戏引用
|
||
network_manager = get_node("/root/main/UI/TCPNetworkManager")
|
||
main_game = get_node("/root/main")
|
||
|
||
_update_display()
|
||
_check_daily_status()
|
||
|
||
# 从服务器加载签到数据
|
||
if network_manager and network_manager.is_connected_to_server():
|
||
network_manager.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_animation(rewards)
|
||
|
||
# 更新按钮状态
|
||
_set_button_state(false, "已签到", Color(0.7, 0.7, 0.7, 1))
|
||
|
||
# 发送完成信号
|
||
check_in_completed.emit(rewards)
|
||
|
||
# 发送奖励信号
|
||
for reward_type in rewards.keys():
|
||
if reward_type == "seeds":
|
||
for seed_reward in rewards.seeds:
|
||
reward_claimed.emit("seed_" + seed_reward.name, seed_reward.quantity)
|
||
elif reward_type in ["coins", "exp", "bonus_coins", "bonus_exp"]:
|
||
reward_claimed.emit(reward_type, rewards[reward_type])
|
||
|
||
Toast.show(message, Color.GREEN)
|
||
print("签到成功: ", message)
|
||
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)
|
||
print("签到失败: ", message)
|
||
|
||
## 处理服务器签到数据响应
|
||
func handle_check_in_data_response(response: Dictionary) -> void:
|
||
var success = response.get("success", false)
|
||
|
||
if success:
|
||
check_in_data = response.get("check_in_data", {})
|
||
consecutive_days = response.get("consecutive_days", 0)
|
||
has_checked_in_today = response.get("has_checked_in_today", false)
|
||
today_date = response.get("current_date", Time.get_date_string_from_system())
|
||
|
||
# 更新显示
|
||
_update_display()
|
||
_check_daily_status()
|
||
|
||
# 发送数据加载完成信号
|
||
check_in_data_loaded.emit(check_in_data)
|
||
|
||
print("签到数据加载成功,连续签到:", consecutive_days, "天")
|
||
else:
|
||
print("加载签到数据失败")
|
||
|
||
# =============================================================================
|
||
# 核心业务逻辑
|
||
# =============================================================================
|
||
|
||
## 检查今日签到状态
|
||
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 network_manager or not network_manager.is_connected_to_server():
|
||
Toast.show("未连接到服务器,无法签到", Color.RED)
|
||
return
|
||
|
||
# 发送签到请求到服务器
|
||
network_manager.sendDailyCheckIn()
|
||
daily_check_in_button.disabled = true
|
||
daily_check_in_button.text = "签到中..."
|
||
|
||
# 3秒后重新启用按钮(防止网络超时)
|
||
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 _show_reward_animation(rewards: Dictionary) -> void:
|
||
daily_check_in_reward.text = _format_reward_text(rewards)
|
||
daily_check_in_reward.show()
|
||
|
||
# 创建动画效果
|
||
var tween = create_tween()
|
||
tween.parallel().tween_method(_animate_reward_display, 0.0, 1.0, 0.5)
|
||
|
||
## 奖励显示动画
|
||
func _animate_reward_display(progress: float) -> void:
|
||
daily_check_in_reward.modulate.a = progress
|
||
var scale = 0.8 + (0.2 * progress)
|
||
daily_check_in_reward.scale = Vector2(scale, scale)
|
||
|
||
# =============================================================================
|
||
# UI显示格式化
|
||
# =============================================================================
|
||
|
||
## 格式化奖励显示文本
|
||
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=%s]%s +%d %s[/color]\n" % [
|
||
reward_configs.coins.color,
|
||
reward_configs.coins.icon,
|
||
rewards.coins,
|
||
reward_configs.coins.name
|
||
]
|
||
|
||
if rewards.has("exp"):
|
||
text += "[color=%s]%s +%d %s[/color]\n" % [
|
||
reward_configs.exp.color,
|
||
reward_configs.exp.icon,
|
||
rewards.exp,
|
||
reward_configs.exp.name
|
||
]
|
||
|
||
# 种子奖励
|
||
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 seed_info = _get_seed_info(seed_name, quality)
|
||
if seed_info:
|
||
text += "[color=%s]%s[/color] [color=%s]%s[/color] x%d [color=%s](%s)[/color]\n" % [
|
||
seed_info.color, seed_info.icon, seed_info.color, seed_name, quantity, seed_info.rarity_color, quality
|
||
]
|
||
|
||
# 连续签到额外奖励
|
||
if rewards.has("bonus_coins"):
|
||
text += "\n[color=#FFD700]🎁 连续签到奖励:[/color]\n"
|
||
text += "[color=%s]%s +%d %s[/color] [color=#FFD700]✨[/color]\n" % [
|
||
reward_configs.coins.color,
|
||
reward_configs.coins.icon,
|
||
rewards.bonus_coins,
|
||
reward_configs.coins.name
|
||
]
|
||
|
||
if rewards.has("bonus_exp"):
|
||
if not rewards.has("bonus_coins"):
|
||
text += "\n[color=#FFD700]🎁 连续签到奖励:[/color]\n"
|
||
text += "[color=%s]%s +%d %s[/color] [color=#FFD700]✨[/color]\n" % [
|
||
reward_configs.exp.color,
|
||
reward_configs.exp.icon,
|
||
rewards.bonus_exp,
|
||
reward_configs.exp.name
|
||
]
|
||
|
||
# 下一个奖励预告
|
||
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
|
||
|
||
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_seed_info(seed_name: String, quality: String) -> Dictionary:
|
||
if quality in reward_configs.seeds:
|
||
for seed in reward_configs.seeds[quality]:
|
||
if seed.name == seed_name:
|
||
return seed
|
||
return {}
|
||
|
||
## 格式化历史记录文本
|
||
func _format_history_text(date: String, rewards: Dictionary) -> String:
|
||
var text = "[color=#87CEEB]📅 %s[/color] " % date
|
||
|
||
var reward_parts = []
|
||
if rewards.has("coins"):
|
||
reward_parts.append("[color=%s]%s %d[/color]" % [
|
||
reward_configs.coins.color,
|
||
reward_configs.coins.name,
|
||
rewards.coins
|
||
])
|
||
|
||
if rewards.has("exp"):
|
||
reward_parts.append("[color=%s]%s %d[/color]" % [
|
||
reward_configs.exp.color,
|
||
reward_configs.exp.name,
|
||
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 seed_info = _get_seed_info(seed_name, quality)
|
||
if seed_info:
|
||
reward_parts.append("[color=%s]%s x%d[/color]" % [
|
||
seed_info.color, seed_name, quantity
|
||
])
|
||
|
||
text += " ".join(reward_parts)
|
||
return text
|
||
|
||
## 更新显示内容
|
||
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_data.size() == 0:
|
||
history_text += "[center][color=#DDDDDD]暂无签到记录[/color][/center]"
|
||
else:
|
||
# 按日期排序显示历史记录
|
||
var sorted_dates = check_in_data.keys()
|
||
sorted_dates.sort()
|
||
sorted_dates.reverse() # 最新的在前
|
||
|
||
for date in sorted_dates:
|
||
var day_data = check_in_data[date]
|
||
var rewards = day_data.get("rewards", {})
|
||
var day_consecutive = day_data.get("consecutive_days", 1)
|
||
|
||
history_text += _format_history_text(date, rewards)
|
||
history_text += " [color=#90EE90](连续%d天)[/color]\n" % day_consecutive
|
||
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:
|
||
execute_check_in()
|
||
|
||
# =============================================================================
|
||
# 公共接口方法 - 供主游戏调用
|
||
# =============================================================================
|
||
|
||
## 刷新签到数据
|
||
func refresh_check_in_data() -> void:
|
||
if network_manager and network_manager.is_connected_to_server():
|
||
network_manager.sendGetCheckInData()
|
||
|
||
## 获取当前签到状态
|
||
func get_check_in_status() -> Dictionary:
|
||
return {
|
||
"has_checked_in_today": has_checked_in_today,
|
||
"consecutive_days": consecutive_days,
|
||
"today_date": today_date
|
||
}
|
||
|
||
|