准备发布正式版

This commit is contained in:
2025-07-31 22:59:40 +08:00
parent 048600e95d
commit ea42a1563d
173 changed files with 3926 additions and 4295 deletions

View File

@@ -54,16 +54,7 @@ func _ready():
# 隐藏面板(初始默认隐藏)
self.hide()
# 面板显示时的处理
func _on_visibility_changed():
if visible:
# 面板显示时自动刷新数据
init_store()
GlobalVariables.isZoomDisabled = true
pass
else:
GlobalVariables.isZoomDisabled = false
pass
# 连接所有按钮信号
func _connect_buttons():
@@ -532,4 +523,15 @@ func _on_refresh_button_pressed() -> void:
#关闭种子商店面板
func _on_quit_button_pressed():
self.hide()
# 面板显示时的处理
func _on_visibility_changed():
if visible:
# 面板显示时自动刷新数据
init_store()
GlobalVariables.isZoomDisabled = true
pass
else:
GlobalVariables.isZoomDisabled = false
pass
#=========================面板通用处理=========================

View File

@@ -32,9 +32,8 @@ extends Panel
@onready var login_panel: PanelContainer = $'../LoginPanel'
# 作物图片缓存(复用主游戏的缓存系统
var crop_textures_cache : Dictionary = {}
var crop_frame_counts : Dictionary = {}
# 注意:作物图片现在使用主游戏的CropTextureManager缓存系统
# 不再需要本地缓存变量
# 当前过滤和排序设置
var current_filter_quality = ""
@@ -84,7 +83,7 @@ func set_pet_feeding_mode(feeding_mode: bool, pet_data: Dictionary = {}):
# 更新UI以反映当前模式
if is_pet_feeding_mode:
# 宠物喂食模式下,只显示有喂养效果的作物
var pet_name = pet_data.get("基本信息", {}).get("宠物名称", "未知宠物")
var pet_name = pet_data.get("pet_name", "未知宠物")
Toast.show("宠物喂食模式:选择要喂给 " + pet_name + " 的作物", Color.CYAN, 3.0, 1.0)
else:
# 普通模式
@@ -423,8 +422,8 @@ func _on_crop_feed_selected(crop_name: String, crop_count: int):
var feed_effects = crop_data.get("喂养效果", {})
# 获取宠物信息
var pet_name = current_pet_data.get("基本信息", {}).get("宠物名称", "未知宠物")
var pet_id = current_pet_data.get("基本信息", {}).get("宠物ID", "")
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)
@@ -511,7 +510,8 @@ func _send_feed_pet_request(crop_name: String, pet_id: String, feed_effects: Dic
# 获取作物的收获物图片(用于仓库显示)
func _get_crop_harvest_texture(crop_name: String) -> Texture2D:
# 尝试加载"收获物.webp"图片
# 使用作物键名(而不是成熟物名称)来构建图片路径
# crop_name 是作物的键名,如"可可豆"、"向日葵"等
var crop_path = "res://assets/作物/" + crop_name + "/"
var harvest_texture_path = crop_path + "收获物.webp"
@@ -521,8 +521,7 @@ func _get_crop_harvest_texture(crop_name: String) -> Texture2D:
print("仓库加载作物收获物图片:", crop_name)
return texture
# 如果都没有找到,使用默认的收获物图片
# 如果没有找到,使用默认的收获物图片
var default_harvest_path = "res://assets/作物/默认/收获物.webp"
if ResourceLoader.exists(default_harvest_path):
var texture = load(default_harvest_path)

View File

@@ -10,6 +10,9 @@ signal check_in_failed(error_message: String)
@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
@@ -35,7 +38,9 @@ func handle_daily_check_in_response(response: Dictionary) -> void:
consecutive_days = response.get("consecutive_days", 0)
has_checked_in_today = true
_show_reward_animation(rewards)
# 显示奖励内容
_show_reward_content(rewards)
_set_button_state(false, "已签到", Color(0.7, 0.7, 0.7, 1))
check_in_completed.emit(rewards)
@@ -86,17 +91,6 @@ func execute_check_in() -> void:
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)
func _format_reward_text(rewards: Dictionary) -> String:
var text = ""
@@ -162,6 +156,11 @@ func _get_rarity_color(rarity: String) -> String:
"传奇": 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"
@@ -194,6 +193,16 @@ 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():

View File

@@ -371,8 +371,8 @@ func _show_pet_item_confirmation_dialog(item_name: String, item_count: int):
Toast.show("宠物数据丢失,请重新选择宠物", Color.RED, 2.0, 1.0)
return
var pet_name = current_pet_data.get("基本信息", {}).get("宠物名称", "未知宠物")
var pet_id = current_pet_data.get("基本信息", {}).get("宠物ID", "")
var pet_name = current_pet_data.get("pet_name", "未知宠物")
var pet_id = current_pet_data.get("pet_id", "")
# 获取道具信息
var item_config = _load_item_config()
@@ -514,4 +514,4 @@ func get_selected_item_name() -> String:
# 检查是否有道具被选择
func is_item_currently_selected() -> bool:
return is_item_selected
return is_item_selected

View File

@@ -567,3 +567,13 @@ func _set_status(label: Label, text: String, color: 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

View File

@@ -10,6 +10,9 @@ signal draw_failed(error_message: String)
@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 = {}
@@ -212,10 +215,8 @@ func _perform_network_draw(draw_type: String) -> void:
func _show_waiting_animation() -> void:
_set_draw_buttons_enabled(false)
lucky_draw_reward.hide()
_play_anticipation_animation()
func handle_lucky_draw_response(response: Dictionary) -> void:
_stop_anticipation_animation()
_set_draw_buttons_enabled(true)
if response.get("success", false):
@@ -237,8 +238,7 @@ func _show_server_draw_results(rewards: Array, draw_type: String, cost: int) ->
lucky_draw_reward.text = result_text
lucky_draw_reward.show()
_play_result_animation()
func _format_server_draw_results(rewards: Array, draw_type: String, cost: int) -> String:
var type_names = {"single": "单抽", "five": "五连抽", "ten": "十连抽"}
@@ -338,40 +338,11 @@ func _format_package_content(content: Dictionary) -> String:
"seed": return "[color=#90EE90]🌱%sx%d[/color]" % [content.get("name", "种子"), amount]
_: return ""
func _play_anticipation_animation() -> void:
_stop_anticipation_animation()
anticipation_tween = create_tween()
anticipation_tween.set_loops()
for template in reward_templates:
if template.visible:
anticipation_tween.parallel().tween_method(
func(progress: float): _anticipation_flash(template, progress),
0.0, 1.0, 0.8
)
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 _stop_anticipation_animation() -> void:
if anticipation_tween:
anticipation_tween.kill()
anticipation_tween = null
for template in reward_templates:
template.modulate = Color.WHITE
func _play_result_animation() -> void:
var tween = create_tween()
lucky_draw_reward.modulate.a = 0.0
lucky_draw_reward.scale = Vector2(0.8, 0.8)
tween.parallel().tween_property(lucky_draw_reward, "modulate:a", 1.0, 0.5)
tween.parallel().tween_property(lucky_draw_reward, "scale", Vector2(1.0, 1.0), 0.5)
tween.tween_callback(func(): lucky_draw_reward.modulate.a = 1.0)
func _show_error_message(message: String) -> void:
lucky_draw_reward.text = "[center][color=#FF6B6B]❌ %s[/color][/center]" % message
@@ -396,13 +367,33 @@ func _on_quit_button_pressed() -> void:
self.hide()
func _on_lucky_draw_button_pressed() -> void:
_perform_network_draw("single")
_show_draw_confirmation("single")
func _on_five_lucky_draw_button_pressed() -> void:
_perform_network_draw("five")
_show_draw_confirmation("five")
func _on_ten_lucky_draw_button_pressed() -> void:
_perform_network_draw("ten")
_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:

View File

@@ -289,6 +289,7 @@ func _on_confirm_buy_pet(pet_name: String, pet_cost: int, dialog: AcceptDialog):
# 发送购买请求到服务器
_send_buy_pet_request(pet_name, pet_cost)
init_pet_store()
dialog.queue_free()
# 取消购买宠物
@@ -310,6 +311,7 @@ func _send_buy_pet_request(pet_name: String, pet_cost: int):
#=========================面板通用处理=========================
# 手动刷新宠物商店面板
#刷新按钮点击
func _on_refresh_button_pressed() -> void:
# 清空现有配置和请求状态,强制重新获取
pet_config = {}

View File

@@ -49,6 +49,8 @@ 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)
@@ -265,6 +267,37 @@ func _on_visit_player_pressed(username):
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():
# 检查网络连接
@@ -299,22 +332,4 @@ func _on_quit_button_pressed():
self.hide()
#搜索按钮点击 - 通过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()
#===================通用面板处理======================

File diff suppressed because it is too large Load Diff

View File

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

View File

@@ -1,579 +0,0 @@
extends Panel
# 可用的宠物场景字典(直接使用现有场景文件)
var available_pets: Dictionary = {
"小绿": preload("res://Scene/Pet/SmallGreen.tscn"),
"小蓝": preload("res://Scene/Pet/SmallBlue.tscn"),
"小黄": preload("res://Scene/Pet/SmallYellow.tscn"),
"小橙": preload("res://Scene/Pet/SmallOrange.tscn"),
"小粉": preload("res://Scene/Pet/SmallPink.tscn"),
"红史莱姆": preload("res://Scene/Pet/RedSlime.tscn"),
"绿史莱姆": preload("res://Scene/Pet/GreenSlime.tscn"),
"小骑士": preload("res://Scene/Pet/LittleKnight.tscn"),
"大甲虫": preload("res://Scene/Pet/BigBeetle.tscn"),
"小甲虫": preload("res://Scene/Pet/SmallBeetle.tscn"),
"飞鸟": preload("res://Scene/Pet/FlyingBird.tscn"),
"小钻头": preload("res://Scene/Pet/SmallDrillBit.tscn")
}
# 宠物配置数据
var pet_configs: Dictionary = {}
@onready var battle_end_panel: Panel = $BattleEndPanel #战斗结算面板
@onready var contents: Label = $BattleEndPanel/Contents #结算内容
@onready var return_farm_button: Button = $BattleEndPanel/ReturnFarmButton #返回农场按钮 暂时设定为隐藏战斗面板
@onready var pet_battle_details_panel: Panel = $PetBattleDetailsPanel #宠物对战细节面板
@onready var battle_details: RichTextLabel = $PetBattleDetailsPanel/BattleDetails #宠物对战细节
@onready var tcp_network_manager_panel: Panel = $'../TCPNetworkManagerPanel'
# 对战区域边界
var battle_area_min: Vector2 = Vector2(50, 50)
var battle_area_max: Vector2 = Vector2(1350, 670)
# 队伍宠物列表
var team1_pets: Array[CharacterBody2D] = []
var team2_pets: Array[CharacterBody2D] = []
# 对战状态
var battle_started: bool = false
var battle_ended: bool = false
var winner_team: String = ""
var auto_battle_enabled: bool = true # 是否启用自动对战
var is_steal_battle: bool = false # 是否为偷菜对战
var steal_battle_cost: int = 1300 # 偷菜对战失败的惩罚金币
var battle_start_time: float = 0.0 # 战斗开始时间
# 偷菜对战相关数据
var current_battle_pet_id: String = "" # 当前出战宠物ID
var current_attacker_name: String = "" # 当前进攻者用户名
# 队伍节点引用
@onready var team1_node: Node = $team1
@onready var team2_node: Node = $team2
@onready var neutral_node: Node = $neutral
func _ready():
visibility_changed.connect(_on_visibility_changed)
load_pet_configs()
# 连接返回农场按钮
if return_farm_button:
return_farm_button.pressed.connect(_on_return_farm_pressed)
# 初始隐藏结算面板和细节面板
if battle_end_panel:
battle_end_panel.visible = false
if pet_battle_details_panel:
pet_battle_details_panel.visible = false
# 加载宠物配置
func load_pet_configs():
var file = FileAccess.open("res://Data/pet_data.json", FileAccess.READ)
if file == null:
return
var json_string = file.get_as_text()
file.close()
var json = JSON.new()
var parse_result = json.parse(json_string)
if parse_result != OK:
return
pet_configs = json.data
# 添加对战细节到细节面板
func add_battle_detail(text: String, color: Color = Color.WHITE):
if not battle_details:
return
# 安全获取当前时间
var time_parts = Time.get_datetime_string_from_system().split(" ")
var current_time = ""
if time_parts.size() >= 2:
current_time = time_parts[1] # 获取时间部分
else:
# 如果格式不对,使用简单的时间格式
var time_dict = Time.get_datetime_dict_from_system()
current_time = str(time_dict.hour).pad_zeros(2) + ":" + str(time_dict.minute).pad_zeros(2) + ":" + str(time_dict.second).pad_zeros(2)
var detail_text = "[color=#" + color.to_html() + "]" + current_time + " " + text + "[/color]\n"
battle_details.text += detail_text
# 自动滚动到底部
await get_tree().process_frame
if battle_details.get_v_scroll_bar():
battle_details.get_v_scroll_bar().value = battle_details.get_v_scroll_bar().max_value
# 清空对战细节
func clear_battle_details():
if battle_details:
battle_details.text = ""
# 战斗结束检查计时器
var battle_check_timer: float = 0.0
var battle_check_interval: float = 0.5 # 每0.5秒检查一次,减少性能开销
func _process(delta):
# 只有启用自动对战时才检查战斗结束,并使用计时器减少检查频率
if auto_battle_enabled and battle_started and not battle_ended:
battle_check_timer += delta
if battle_check_timer >= battle_check_interval:
battle_check_timer = 0.0
check_battle_end()
# 获取队伍节点 - 供宠物调用
func get_team_node(team_name: String) -> Node:
match team_name:
"team1":
return team1_node
"team2":
return team2_node
"neutral":
return neutral_node
_:
return null
# 开始战斗
func start_battle():
if battle_started:
return
battle_started = true
battle_ended = false
battle_start_time = Time.get_ticks_msec() / 1000.0 # 记录战斗开始时间
# 显示细节面板并初始化内容
if pet_battle_details_panel:
pet_battle_details_panel.visible = true
add_battle_detail("⚔️ 战斗开始!", Color.YELLOW)
# 显示双方宠物信息
var all_pets = get_tree().get_nodes_in_group("pets")
for pet in all_pets:
if pet.pet_team == "team1":
add_battle_detail("🔵 " + pet.pet_name + " 参战!", Color.CYAN)
elif pet.pet_team == "team2":
add_battle_detail("🟠 " + pet.pet_name + " 参战!", Color.ORANGE)
# 检查战斗是否结束
func check_battle_end():
if battle_ended or not battle_started:
return
# 等待战斗真正开始后再检查(避免立即结束)
if Time.get_ticks_msec() / 1000.0 - battle_start_time < 2.0:
return
var team1_alive = 0
var team2_alive = 0
# 统计存活宠物数量 - 只检查当前对战面板下的宠物
for pet in team1_pets:
if is_instance_valid(pet) and pet.is_alive:
team1_alive += 1
for pet in team2_pets:
if is_instance_valid(pet) and pet.is_alive:
team2_alive += 1
# 判断胜负
if team1_alive == 0 and team2_alive == 0:
end_battle("draw")
elif team1_alive == 0:
end_battle("team2")
elif team2_alive == 0:
end_battle("team1")
# 结束战斗
func end_battle(winner: String):
if battle_ended:
return
battle_ended = true
winner_team = winner
# 添加战斗结束细节
var end_message = ""
var end_color = Color.WHITE
match winner:
"team1":
end_message = "🏆 我方获胜!"
end_color = Color.GREEN
"team2":
end_message = "🏆 敌方获胜!"
end_color = Color.RED
"draw":
end_message = "🤝 平局!双方同归于尽"
end_color = Color.GRAY
add_battle_detail(end_message, end_color)
# 显示战斗结算面板
show_battle_end_panel(winner)
# 处理偷菜对战结果
if is_steal_battle:
await get_tree().create_timer(2.0).timeout
handle_steal_battle_result(winner)
# 显示战斗结算面板
func show_battle_end_panel(winner: String):
var result_text = ""
# 统计存活宠物和详细信息 - 从宠物组中获取
var all_pets = get_tree().get_nodes_in_group("pets")
for pet in all_pets:
if not is_instance_valid(pet):
continue
# 构建结算文本
result_text += "=== 战斗结算 ===\n\n"
match winner:
"team1":
result_text += "🏆 我方获胜!\n\n"
"team2":
result_text += "🏆 敌方获胜!\n\n"
"draw":
result_text += "🤝 平局!双方同归于尽\n\n"
# 给所有参与对战的宠物奖励经验和亲密度
for pet in all_pets:
if is_instance_valid(pet):
# 所有宠物获得参与对战奖励
pet.gain_experience(30.0) # 参与对战随机获得30-100经验
pet.gain_intimacy(15.0) # 参与对战随机获得1-12亲密度
contents.text = result_text
battle_end_panel.visible = true
# 设置偷菜对战
func setup_steal_battle(battle_pet_data: Dictionary, patrol_pet_data: Dictionary, attacker_name: String, defender_name: String):
# 停止当前对战
stop_auto_battle()
# 清理现有宠物
clear_all_pets()
# 设置为偷菜对战模式
is_steal_battle = true
steal_battle_cost = 1300
# 记录对战信息
current_attacker_name = attacker_name
current_battle_pet_id = battle_pet_data.get("基本信息", {}).get("宠物ID", "")
# 根据宠物数据创建对战宠物
var battle_pet = create_pet_from_data(battle_pet_data, team1_node, Vector2(200, 300))
var patrol_pet = create_pet_from_data(patrol_pet_data, team2_node, Vector2(1000, 300))
if battle_pet and patrol_pet:
# 设置宠物名称标识
var battle_original_name = battle_pet_data.get("基本信息", {}).get("宠物名称", "未知宠物")
var patrol_original_name = patrol_pet_data.get("基本信息", {}).get("宠物名称", "未知宠物")
battle_pet.pet_name = "[出战] " + battle_original_name
patrol_pet.pet_name = "[巡逻] " + patrol_original_name
# 确保宠物正确设置类型并加载配置
var battle_pet_type = battle_pet_data.get("基本信息", {}).get("宠物类型", "")
var patrol_pet_type = patrol_pet_data.get("基本信息", {}).get("宠物类型", "")
if battle_pet_type != "":
battle_pet.set_pet_type_and_load_config(battle_pet_type)
if patrol_pet_type != "":
patrol_pet.set_pet_type_and_load_config(patrol_pet_type)
# 重新应用宠物数据覆盖JSON配置
apply_pet_data_to_instance(battle_pet, battle_pet_data)
apply_pet_data_to_instance(patrol_pet, patrol_pet_data)
# 强制设置正确的队伍信息(在数据应用之后)
battle_pet.pet_team = "team1"
patrol_pet.pet_team = "team2"
# 设置碰撞层
battle_pet.setup_collision_layers()
patrol_pet.setup_collision_layers()
# 启用战斗模式
battle_pet.set_combat_enabled(true)
patrol_pet.set_combat_enabled(true)
# 添加到队伍数组
team1_pets.clear()
team2_pets.clear()
team1_pets.append(battle_pet)
team2_pets.append(patrol_pet)
# 添加到宠物组
battle_pet.add_to_group("pets")
battle_pet.add_to_group("team1")
patrol_pet.add_to_group("pets")
patrol_pet.add_to_group("team2")
# 重置对战状态
auto_battle_enabled = true
battle_started = false
battle_ended = false
# 延迟启动战斗
await get_tree().create_timer(1.0).timeout
start_battle()
# 根据宠物数据创建宠物实例
func create_pet_from_data(pet_data: Dictionary, team_node: Node, spawn_pos: Vector2) -> CharacterBody2D:
var pet_type = pet_data.get("基本信息", {}).get("宠物类型", "")
var scene_path = pet_data.get("场景路径", "")
# 优先使用场景路径
var pet_scene = null
if scene_path != "" and ResourceLoader.exists(scene_path):
pet_scene = load(scene_path)
elif available_pets.has(pet_type):
pet_scene = available_pets[pet_type]
else:
return null
var pet_instance = pet_scene.instantiate()
team_node.add_child(pet_instance)
# 应用宠物数据
apply_pet_data_to_instance(pet_instance, pet_data)
# 设置位置
pet_instance.global_position = spawn_pos
return pet_instance
# 应用宠物数据到实例
func apply_pet_data_to_instance(pet_instance: CharacterBody2D, pet_data: Dictionary):
var basic_info = pet_data.get("基本信息", {})
var level_exp = pet_data.get("等级经验", {})
var health_defense = pet_data.get("生命与防御", {})
# 应用基本信息
pet_instance.pet_owner = basic_info.get("宠物主人", "未知主人")
pet_instance.pet_name = basic_info.get("宠物名称", basic_info.get("宠物类型", "未知宠物"))
pet_instance.pet_id = basic_info.get("宠物ID", "")
pet_instance.pet_type = basic_info.get("宠物类型", "")
pet_instance.pet_birthday = basic_info.get("生日", "")
pet_instance.pet_personality = basic_info.get("性格", "活泼")
# 应用等级经验
pet_instance.pet_level = level_exp.get("宠物等级", 1)
pet_instance.pet_experience = level_exp.get("当前经验", 0.0)
pet_instance.max_experience = level_exp.get("最大经验", 100.0)
pet_instance.pet_intimacy = level_exp.get("亲密度", 0.0)
# 应用生命防御属性
pet_instance.max_health = health_defense.get("最大生命值", 100.0)
pet_instance.current_health = health_defense.get("当前生命值", pet_instance.max_health)
pet_instance.max_shield = health_defense.get("最大护盾值", 0.0)
pet_instance.current_shield = health_defense.get("当前护盾值", 0.0)
pet_instance.max_armor = health_defense.get("最大护甲值", 0.0)
pet_instance.current_armor = health_defense.get("当前护甲值", 0.0)
# 启用战斗模式
if pet_instance.has_method("set_combat_enabled"):
pet_instance.set_combat_enabled(true)
# 更新UI显示
if pet_instance.has_method("update_ui"):
pet_instance.update_ui()
# 清理所有宠物
func clear_all_pets():
# 清空对战细节
clear_battle_details()
# 批量处理宠物清理,提高性能
var nodes_to_clear = [team1_node, team2_node, neutral_node]
for node in nodes_to_clear:
if not is_instance_valid(node):
continue
# 先移除组标签,再清理节点
for child in node.get_children():
if is_instance_valid(child):
# 停止宠物的所有行为,防止在清理过程中继续执行逻辑
if child.has_method("set_combat_enabled"):
child.set_combat_enabled(false)
# 移除所有组标签
child.remove_from_group("pets")
child.remove_from_group("team1")
child.remove_from_group("team2")
child.remove_from_group("neutral")
child.remove_from_group("aid_minions")
# 立即销毁,避免延迟
node.remove_child(child)
child.queue_free()
# 清空队伍数组
team1_pets.clear()
team2_pets.clear()
# 清理所有子弹和援助宠物
var groups_to_clear = ["projectiles", "aid_minions"]
for group_name in groups_to_clear:
var group_nodes = get_tree().get_nodes_in_group(group_name)
for node in group_nodes:
if is_instance_valid(node):
node.remove_from_group(group_name)
node.queue_free()
# 等待一帧确保清理完成
await get_tree().process_frame
# 处理偷菜对战结果
func handle_steal_battle_result(winner: String):
var main_game = get_node("/root/main")
if not main_game:
return
# 计算出战宠物获得的经验和亲密度
var exp_gained = 30.0 # 基础参与经验
var intimacy_gained = 15.0 # 基础参与亲密度
# 获取出战宠物的当前状态
var battle_pet = null
for pet in team1_pets:
if is_instance_valid(pet):
battle_pet = pet
break
if not battle_pet:
return
if winner == "team1": # 出战宠物获胜
exp_gained += 50.0 # 胜利额外经验
intimacy_gained += 25.0 # 胜利额外亲密度
Toast.show("对战胜利!可以继续偷菜", Color.GREEN, 3.0)
else: # 巡逻宠物获胜或平局
exp_gained += 10.0 # 失败安慰经验
intimacy_gained += 5.0 # 失败安慰亲密度
# 扣除惩罚金币
if main_game.money >= steal_battle_cost:
main_game.money -= steal_battle_cost
main_game._update_ui()
Toast.show("对战失败!支付了 " + str(steal_battle_cost) + " 金币", Color.RED, 3.0)
else:
Toast.show("对战失败!但金币不足支付惩罚", Color.RED, 3.0)
# 更新宠物数据到服务器
update_battle_pet_data(current_battle_pet_id, current_attacker_name, exp_gained, intimacy_gained, battle_pet)
# 重置偷菜对战状态
is_steal_battle = false
current_battle_pet_id = ""
current_attacker_name = ""
# 返回农场按钮点击事件
func _on_return_farm_pressed():
# 隐藏结算面板和细节面板
if battle_end_panel:
battle_end_panel.visible = false
if pet_battle_details_panel:
pet_battle_details_panel.visible = false
# 完全清理所有宠物和数据
clear_all_pets()
# 等待一帧确保清理完成
await get_tree().process_frame
# 重置对战状态
battle_started = false
battle_ended = false
is_steal_battle = false
auto_battle_enabled = true
winner_team = ""
# 重新启用相机缩放
GlobalVariables.isZoomDisabled = false
# 隐藏面板
self.hide()
# 更新出战宠物数据到服务器
func update_battle_pet_data(pet_id: String, attacker_name: String, exp_gained: float, intimacy_gained: float, battle_pet: CharacterBody2D):
if pet_id == "" or attacker_name == "":
return
# 计算新的经验和亲密度
var current_exp = battle_pet.pet_experience + exp_gained
var current_intimacy = battle_pet.pet_intimacy + intimacy_gained
var current_level = battle_pet.pet_level
var max_exp = battle_pet.max_experience
# 检查升级
var level_ups = 0
while current_exp >= max_exp and current_level < 50:
current_exp -= max_exp
current_level += 1
level_ups += 1
# 重新计算升级经验需求(指数增长)
max_exp = 100.0 * pow(1.2, current_level - 1)
# 计算升级后的属性加成
var level_bonus_multiplier = pow(1.1, level_ups) # 每级10%属性加成
# 准备发送给服务器的数据
var update_data = {
"type": "update_battle_pet_data",
"pet_id": pet_id,
"attacker_name": attacker_name,
"exp_gained": exp_gained,
"intimacy_gained": intimacy_gained,
"new_level": current_level,
"new_experience": current_exp,
"new_max_experience": max_exp,
"new_intimacy": current_intimacy,
"level_ups": level_ups,
"level_bonus_multiplier": level_bonus_multiplier,
"is_steal_battle": is_steal_battle,
"battle_winner": winner_team
}
# 发送数据到服务器
if tcp_network_manager_panel:
tcp_network_manager_panel.client.send_data(update_data)
if level_ups > 0:
add_battle_detail("🎉 " + battle_pet.pet_name + " 升级了 " + str(level_ups) + " 级!当前等级:" + str(current_level), Color.GOLD)
add_battle_detail("📈 " + battle_pet.pet_name + " 获得 " + str(int(exp_gained)) + " 经验," + str(int(intimacy_gained)) + " 亲密度", Color.GREEN)
# 停止自动对战逻辑
func stop_auto_battle():
auto_battle_enabled = false
battle_started = false
battle_ended = false
is_steal_battle = false # 重置偷菜对战状态
battle_start_time = 0.0 # 重置战斗开始时间
winner_team = ""
#面板显示与隐藏切换处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
pass
else:
GlobalVariables.isZoomDisabled = false
pass

View File

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

View File

@@ -1,129 +0,0 @@
extends Area2D
# 子弹属性
var damage: float = 20.0
var speed: float = 300.0
var direction: Vector2 = Vector2.ZERO
var attacker_team: String = ""
var attacker_element: int = 0
var armor_penetration: float = 0.0
var attacker_pet: CharacterBody2D = null # 攻击者引用
# 子弹生存时间(防止子弹飞出边界后一直存在)
var lifetime: float = 3.0
var lifetime_timer: float = 0.0 # 生存时间计时器
func _ready():
# 连接碰撞信号
area_entered.connect(_on_area_entered)
body_entered.connect(_on_body_entered)
# 设置子弹的碰撞层 - 子弹需要能检测到所有队伍的宠物
collision_layer = 0 # 子弹本身不需要被检测
collision_mask = 3 # 检测team1和team2的宠物 (1+2)
# 创建简单的圆形纹理
create_circle_texture()
# 添加到子弹组
add_to_group("projectiles")
func _physics_process(delta):
# 子弹移动
global_position += direction * speed * delta
# 更新生存时间
lifetime_timer += delta
if lifetime_timer >= lifetime:
destroy_projectile()
# 销毁子弹(直接销毁)
func destroy_projectile():
# 延迟销毁,避免在物理回调中移除节点
call_deferred("queue_free")
# 穿透属性
var pierce_remaining: int = 1 # 剩余穿透次数
var hit_enemies: Array[CharacterBody2D] = [] # 已击中的敌人列表(防止重复击中)
func set_projectile_data(dmg: float, spd: float, dir: Vector2, team: String, element: int, armor_pen: float = 0.0, pierce: int = 1, attacker: CharacterBody2D = null):
damage = dmg
speed = spd
direction = dir.normalized()
attacker_team = team
attacker_element = element
armor_penetration = armor_pen
pierce_remaining = pierce
attacker_pet = attacker
func _on_area_entered(area):
# 这里可以处理与其他Area2D的碰撞如果需要
pass
func _on_body_entered(body):
# 检查是否击中敌方宠物
if body is CharacterBody2D and body.has_method("get_team"):
var target_team = body.get_team()
# 不能击中同队伍的宠物
if target_team == attacker_team:
print("子弹跳过同队伍宠物: " + body.pet_name + " (队伍: " + target_team + ")")
return
# 不能击中死亡的宠物
if not body.is_alive:
print("子弹跳过死亡宠物: " + body.pet_name)
return
# 不能重复击中同一个敌人
if body in hit_enemies:
print("子弹跳过已击中的宠物: " + body.pet_name)
return
# 记录击中的敌人
hit_enemies.append(body)
# 对目标造成伤害(检查攻击者是否还有效)
var valid_attacker = null
if attacker_pet and is_instance_valid(attacker_pet):
valid_attacker = attacker_pet
body.take_damage(damage, armor_penetration, attacker_element, valid_attacker)
print("子弹击中敌方宠物: " + body.pet_name + " (攻击方: " + attacker_team + " 目标: " + target_team + ") 造成伤害: " + str(damage))
# 减少穿透次数
pierce_remaining -= 1
# 如果穿透次数用完,销毁子弹
if pierce_remaining <= 0:
print("子弹穿透次数用完,销毁")
destroy_projectile()
else:
print("子弹穿透,剩余穿透次数: " + str(pierce_remaining))
else:
print("子弹击中非宠物对象: " + str(body))
# 创建简单的圆形纹理
func create_circle_texture():
var sprite = get_node_or_null("ProjectileSprite")
if sprite:
# 创建一个简单的圆形图像纹理
var image = Image.create(20, 20, false, Image.FORMAT_RGBA8)
var center = Vector2(10, 10)
var radius = 8
# 绘制圆形
for x in range(20):
for y in range(20):
var distance = Vector2(x, y).distance_to(center)
if distance <= radius:
# 设置黄色像素
image.set_pixel(x, y, Color.YELLOW)
else:
# 设置透明像素
image.set_pixel(x, y, Color.TRANSPARENT)
# 创建纹理并应用
var texture = ImageTexture.new()
texture.set_image(image)
sprite.texture = texture

View File

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

View File

@@ -186,7 +186,6 @@ func _on_add_to_store_pressed():
_on_cancel_add_to_store
)
else:
Toast.show("添加商品功能暂未实现", Color.RED, 2.0, 1.0)
print("错误找不到AddProduct2StorePopup或相关方法")
# 确认添加到小卖部回调

View File

@@ -62,9 +62,12 @@ 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)
@@ -82,6 +85,7 @@ func _process(delta):
if plant_timer >= PLANT_INTERVAL:
plant_timer = 0.0
_process_plant_queue()
#==================基础函数=====================
#=================================一键种植模式=========================================
@@ -293,8 +297,6 @@ func _prepare_random_plant():
#=================================一键种植模式=========================================
# 开始地块选择模式
func _start_lot_selection_mode(plant_type: String):
is_waiting_for_lot_selection = true
@@ -593,6 +595,8 @@ func stop_planting():
Toast.show("一键种植已停止", Color.YELLOW)
_finish_planting()
#======================通用面板处理=====================
#关闭一键种植面板
func _on_quit_button_pressed() -> void:
# 如果正在种植,先停止种植
@@ -604,3 +608,13 @@ func _on_quit_button_pressed() -> void:
return
self.hide()
pass
#面板显示切换处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
pass
else:
GlobalVariables.isZoomDisabled = false
pass
#======================通用面板处理=====================

View File

@@ -57,6 +57,10 @@ func _ready():
"5小时": five_hours
}
# 连接可见性改变信号
visibility_changed.connect(_on_visibility_changed)
# 连接按钮信号
for gift_name in button_mapping.keys():
var button = button_mapping[gift_name]
@@ -186,6 +190,18 @@ func handle_claim_online_gift_response(data: Dictionary):
else:
Toast.show(message, Color.RED)
#================通用面板处理==================
#关闭在线礼包面板
func _on_quit_button_pressed() -> void:
self.hide()
# 面板显示时的处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
pass
else:
GlobalVariables.isZoomDisabled = false
pass
#================通用面板处理==================

View File

@@ -32,7 +32,6 @@ var current_pet_name: String = ""
@onready var item_bag_panel: Panel = $'../../BigPanel/ItemBagPanel'
@onready var pet_store_panel: Panel = $'../../BigPanel/PetStorePanel'
@onready var pet_bag_panel: Panel = $'../../BigPanel/PetBagPanel'
@onready var pet_fight_panel: Panel = $'../../BigPanel/PetFightPanel'
@@ -202,6 +201,8 @@ func _set_pet_detailed_info(pet_name: String, pet_data: Dictionary):
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"
# 设置文本

View File

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

View File

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