完善宠物系统

This commit is contained in:
2025-07-26 22:41:15 +08:00
parent 02a7e29e52
commit 048600e95d
135 changed files with 10204 additions and 5859 deletions

View File

@@ -293,7 +293,7 @@ func _show_item_info(item_name: String, item_count: int):
info_text += "描述: " + description
if not _is_item_usable(item_name):
info_text += "\n注意: 此道具功能暂未实现"
pass
else:
info_text = item_name + " (数量: " + str(item_count) + ")\n描述: 暂无信息"
@@ -363,7 +363,7 @@ func _send_farm_item_use_request(item_name: String):
# 发送请求
tcp_network_manager_panel.send_message(message)
Toast.show("正在使用道具...", Color.BLUE, 2.0, 1.0)
#Toast.show("正在使用道具...", Color.BLUE, 2.0, 1.0)
# 显示宠物使用道具确认对话框
func _show_pet_item_confirmation_dialog(item_name: String, item_count: int):
@@ -431,13 +431,12 @@ func _send_pet_item_use_request(item_name: String, pet_id: String):
# 退出宠物使用道具模式
_exit_pet_item_mode()
Toast.show("正在使用道具...", Color.BLUE, 2.0, 1.0)
#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()
@@ -496,13 +495,12 @@ func _on_quit_button_pressed() -> void:
func _on_refresh_button_pressed() -> void:
# 刷新道具背包UI
update_item_bag_ui()
Toast.show("道具背包已刷新", Color.GREEN, 2.0, 1.0)
#Toast.show("道具背包已刷新", Color.GREEN, 2.0, 1.0)
#面板显示与隐藏切换处理
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
# 面板显示时自动刷新数据
update_item_bag_ui()
pass
else:

View File

@@ -433,6 +433,7 @@ func _handle_login_success(user_data: Dictionary):
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

View File

@@ -61,9 +61,9 @@ func update_pet_bag_ui():
# 为背包中的每个宠物创建按钮
for pet_data in main_game.pet_bag:
var pet_name = pet_data.get("基本信息", {}).get("宠物类型", "未知宠物")
var pet_level = pet_data.get("等级经验", {}).get("宠物等级", 1)
var pet_owner_name = pet_data.get("基本信息", {}).get("宠物名称", pet_name)
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)
@@ -118,31 +118,45 @@ 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 = _load_pet_config()
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("场景路径", "")
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()
var pet_image_node = pet_instance.get_node_or_null("PetImage")
if pet_image_node and pet_image_node.sprite_frames:
# 直接使用实例化的场景根节点,因为根节点就是PetImage
if pet_instance and pet_instance.sprite_frames:
# 获取默认动画的第一帧
var animation_names = pet_image_node.sprite_frames.get_animation_names()
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_image_node.sprite_frames.get_frame_count(default_animation)
var frame_count = pet_instance.sprite_frames.get_frame_count(default_animation)
if frame_count > 0:
texture = pet_image_node.sprite_frames.get_frame_texture(default_animation, 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:
@@ -151,8 +165,10 @@ func _update_button_pet_image(button: Button, pet_name: String):
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:

View File

@@ -24,6 +24,8 @@ extends Panel
# 宠物配置数据
var pet_config: Dictionary = {}
# 请求状态标志,防止重复请求
var is_requesting_config: bool = false
# 准备函数
func _ready():
@@ -57,20 +59,23 @@ func update_pet_store_ui():
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]
var purchase_info = pet_info.get("购买信息", {})
var can_buy = purchase_info.get("能否购买", false)
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 = purchase_info.get("购买价格", 0)
var basic_info = pet_info.get("基本信息", {})
var pet_desc = basic_info.get("简介", "可爱的宠物伙伴")
var pet_cost = pet_info.get("cost", 0)
var pet_desc = pet_info.get("description", "可爱的宠物伙伴")
# 检查玩家是否已购买该宠物
var is_owned = _check_pet_owned(pet_name)
@@ -88,6 +93,7 @@ func update_pet_store_ui():
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:
@@ -95,8 +101,7 @@ func _check_pet_owned(pet_name: String) -> bool:
return false
for pet_data in main_game.pet_bag:
var basic_info = pet_data.get("基本信息", {})
var pet_type = basic_info.get("宠物类型", "")
var pet_type = pet_data.get("pet_type", "")
if pet_type == pet_name:
return true
return false
@@ -144,28 +149,44 @@ 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("场景路径", "")
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()
var pet_image_node = pet_instance.get_node_or_null("PetImage")
# 场景的根节点就是PetImage,直接使用
var pet_image_node = pet_instance
if pet_image_node and pet_image_node.sprite_frames:
# 获取默认动画的第一帧
var default_animation = pet_image_node.sprite_frames.get_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)
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:
@@ -174,31 +195,52 @@ func _update_button_pet_image(button: Button, pet_name: String):
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():
# 从宠物数据文件加载配置
var file = FileAccess.open("res://Data/pet_data.json", FileAccess.READ)
if file == null:
print("宠物商店:无法打开宠物配置文件")
pet_config = {}
# 如果正在请求中,避免重复发送
if is_requesting_config:
print("宠物商店:正在请求配置数据中,跳过重复请求")
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:
print("宠物商店:解析宠物配置文件失败")
# 发送请求到服务器获取宠物配置
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 = {}
return
is_requesting_config = false
# 处理服务器返回的宠物配置数据
func _on_pet_config_received(response_data: Dictionary):
"""处理从服务器接收到的宠物配置数据"""
# 重置请求状态
is_requesting_config = false
pet_config = json.data
print("宠物商店:成功加载宠物配置数据,宠物种类:", pet_config.size())
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):
@@ -269,9 +311,12 @@ func _send_buy_pet_request(pet_name: String, pet_cost: int):
#=========================面板通用处理=========================
# 手动刷新宠物商店面板
func _on_refresh_button_pressed() -> void:
# 清空现有配置和请求状态,强制重新获取
pet_config = {}
is_requesting_config = false
# 重新初始化宠物商店
init_pet_store()
Toast.show("宠物商店已刷新", Color.GREEN, 2.0, 1.0)
#Toast.show("宠物商店已刷新", Color.GREEN, 2.0, 1.0)
# 关闭宠物商店面板
func _on_quit_button_pressed() -> void:
@@ -283,8 +328,12 @@ func _on_quit_button_pressed() -> void:
func _on_visibility_changed():
if visible:
GlobalVariables.isZoomDisabled = true
# 面板显示时自动刷新数据
update_pet_store_ui()
# 面板显示时只在没有配置数据时才请求
if pet_config.is_empty():
init_pet_store()
else:
# 如果已有配置数据直接更新UI
update_pet_store_ui()
pass
else:
GlobalVariables.isZoomDisabled = false

View File

@@ -53,15 +53,10 @@ extends CharacterBody2D
#- 亲密度(额外加属性)
#- 品质(白/绿/蓝/橙/红/紫)
#基本攻击方式:
#近战
#近战攻击伤害
#近战攻击速度
#远程
#远程攻击伤害
#远程攻击速度
#附录
#- 护甲公式示例:实际伤害 = 基础伤害 × (1 - 护甲值/(护甲值 + 100)),搭配"护甲穿透"可直接减少目标护甲值
#- 元素克制火属性攻击对冰属性敌人造成150%伤害同时被水属性克制仅造成80%伤害)
@@ -111,7 +106,7 @@ var current_armor: float = 100.0 # 当前护甲值
# 攻击属性
var attack_type: AttackType = AttackType.RANGED # 攻击类型
var attack_damage: float = 20.0 # 基础攻击伤害
var attack_range: float = 300.0 # 攻击距离
var attack_range: float = 400.0 # 攻击距离
var crit_rate: float = 0.1 # 暴击率0.0-1.0
var crit_damage: float = 1.5 # 暴击伤害倍数
var life_steal: float = 0.1 # 生命汲取0.0-1.0
@@ -152,7 +147,7 @@ enum RangedAttackMode {
PIERCING # 穿透攻击
}
# 内部状态变量(不需要导出)
var attack_speed: float = 1.0 # 当前攻击速度(根据攻击类型动态设置)
var gatling_firing: bool = false # 是否正在加特林射击
var gatling_current_bullet: int = 0 # 当前加特林子弹计数
@@ -219,13 +214,57 @@ var is_attacking: bool = false # 是否正在攻击
var is_berserker: bool = false # 是否处于狂暴状态
var is_stunned: bool = false # 是否被眩晕
var is_invulnerable: bool = false # 是否无敌
var is_being_knocked_back: bool = false # 是否正在被击退
var current_target: CharacterBody2D = null # 当前目标
var last_attacker: CharacterBody2D = null # 最后攻击者(用于击杀奖励)
var last_attack_time: float = 0.0 # 上次攻击时间
var last_regen_time: float = 0.0 # 上次恢复时间
var last_target_check_time: float = 0.0 # 上次目标检查时间
var knockback_velocity: Vector2 = Vector2.ZERO # 击退速度
# 受伤动画相关
var hurt_tween: Tween = null # 受伤动画缓动
var original_modulate: Color = Color.WHITE # 原始颜色
var last_hurt_time: float = 0.0 # 上次受伤时间(防止受伤动画过于频繁)
var hurt_animation_cooldown: float = 0.3 # 受伤动画冷却时间
# 攻击频率控制
var min_attack_interval: float = 0.5 # 最小攻击间隔(防止攻击过于频繁)
# 伤害反弹保护
var damage_reflect_depth: int = 0 # 伤害反弹递归深度
var max_reflect_depth: int = 3 # 最大反弹深度(防止无限递归)
# 性能保护
var performance_mode: bool = false # 性能模式(减少特效和计算)
var frame_skip_counter: int = 0 # 帧跳跃计数器
# 升级系统 - 基础属性列表(每次升级随机选择加点)
var base_upgrade_attributes: Array[String] = [
"max_health", # 最大生命值
"attack_damage", # 攻击伤害
"move_speed", # 移动速度
"max_shield", # 最大护盾值
"max_armor", # 最大护甲值
"crit_rate", # 暴击率
"health_regen", # 生命恢复
"attack_range" # 攻击距离
]
# 每次升级随机选择的属性数量
var attributes_per_level: int = 3
# 每5级额外属性奖励表
var level_milestone_bonuses: Dictionary = {
5: {"max_health": 20, "attack_damage": 5, "crit_rate": 0.02},
10: {"max_shield": 30, "armor_penetration": 5, "life_steal": 0.05},
15: {"max_armor": 25, "knockback_resist": 0.1, "dodge_rate": 0.03},
20: {"health_regen": 2, "move_speed": 15, "attack_range": 30},
25: {"max_health": 40, "attack_damage": 10, "enable_berserker_mode": true},
30: {"max_shield": 50, "shield_regen": 1, "enable_damage_reflect": true},
35: {"crit_damage": 0.3, "berserker_bonus": 0.2, "damage_reflect": 0.05},
40: {"max_armor": 40, "control_resist": 0.15, "enable_aid_system": true},
45: {"projectile_speed": 50, "pierce_count": 1, "enable_death_immunity": true},
50: {"max_health": 100, "attack_damage": 25, "enable_resurrection": true}
}
# 巡逻状态
var is_patrolling: bool = false # 是否正在巡逻
@@ -642,6 +681,10 @@ func _ready():
# 初始化生日
initialize_birthday()
# 保存原始颜色
if pet_image:
original_modulate = pet_image.modulate
# 延迟初始化UI显示确保所有节点都已准备好
call_deferred("update_ui")
@@ -702,35 +745,50 @@ func clamp_to_battle_area():
global_position.x = clamp(global_position.x, battle_area_min.x, battle_area_max.x)
global_position.y = clamp(global_position.y, battle_area_min.y, battle_area_max.y)
#宠物物理更新
#宠物物理更新(带性能保护)
func _physics_process(delta):
if not is_alive or is_dying:
return
# 性能保护每3帧执行一次非关键逻辑
frame_skip_counter += 1
var should_skip_frame = performance_mode and (frame_skip_counter % 3 != 0)
# 检测性能问题(如果帧时间过长,自动启用性能模式)
if delta > 0.025: # 帧时间超过25ms低于40FPS
if not performance_mode:
performance_mode = true
print("" + pet_name + " 启用性能模式(帧时间: " + str("%.3f" % delta) + "s")
# 巡逻宠物特殊处理
if is_patrolling:
handle_patrol(delta)
return
# 处理生命和护盾恢复
handle_regeneration(delta)
if not should_skip_frame:
handle_regeneration(delta)
# 更新年龄和亲密度
update_age_and_intimacy(delta)
# 更新年龄和亲密度(低优先级,可跳帧)
if not should_skip_frame:
update_age_and_intimacy(delta)
# 检查狂暴状态
check_berserker_mode()
if not should_skip_frame:
check_berserker_mode()
# 检查援助系统
check_aid_system()
# 检查援助系统(低优先级,可跳帧)
if not should_skip_frame:
check_aid_system()
# 如果被眩晕则不能行动
if is_stunned:
return
# 定期检查目标状态(每0.5秒检查一次
# 定期检查目标状态(性能模式下降低检查频率
var current_time = Time.get_ticks_msec() / 1000.0
if current_time - last_target_check_time >= 0.5:
var check_interval = 0.5 if not performance_mode else 1.0
if current_time - last_target_check_time >= check_interval:
check_target_validity()
last_target_check_time = current_time
@@ -791,15 +849,7 @@ func update_ai_state(delta):
#宠物移动
func handle_movement(delta):
# 处理击退效果
if is_being_knocked_back:
velocity = knockback_velocity
# 击退衰减
knockback_velocity = knockback_velocity.lerp(Vector2.ZERO, 5.0 * delta)
if knockback_velocity.length() < 10.0:
is_being_knocked_back = false
knockback_velocity = Vector2.ZERO
elif current_state == PetState.MOVING_TO_TARGET and current_target:
if current_state == PetState.MOVING_TO_TARGET and current_target:
var distance_to_target = global_position.distance_to(current_target.global_position)
var direction = (current_target.global_position - global_position).normalized()
@@ -832,7 +882,7 @@ func handle_movement(delta):
else:
velocity = Vector2.ZERO
#宠物攻击
#宠物攻击(带频率保护)
func handle_attack(delta):
if current_state == PetState.ATTACKING and current_target:
var current_time = Time.get_ticks_msec() / 1000.0 # 转换为秒
@@ -841,8 +891,9 @@ func handle_attack(delta):
if ranged_mode == RangedAttackMode.GATLING:
handle_gatling_attack(current_time, delta)
else:
# 普通攻击频率控制
if current_time - last_attack_time >= 1.0 / attack_speed:
# 普通攻击频率控制(确保最小攻击间隔)
var attack_interval = max(1.0 / attack_speed, min_attack_interval)
if current_time - last_attack_time >= attack_interval:
perform_attack(current_target)
last_attack_time = current_time
@@ -959,9 +1010,9 @@ func perform_melee_attack(target: CharacterBody2D):
var heal_amount = damage * life_steal
heal(heal_amount)
# 击退效果
if knockback_force > 0:
apply_knockback_to_target(target)
# 击退效果已禁用
# if knockback_force > 0:
# apply_knockback_to_target(target)
# 根据攻击模式发射子弹
func fire_projectile_by_mode(target: CharacterBody2D):
@@ -1090,15 +1141,29 @@ func create_and_fire_projectile(start_pos: Vector2, target_pos: Vector2, damage:
RangedAttackMode.PIERCING:
projectile.get_node("ProjectileSprite").modulate = Color.PURPLE
#宠物受到伤害
#宠物受到伤害(带死循环保护)
func take_damage(damage: float, armor_pen: float = 0.0, attacker_element: ElementType = ElementType.NONE, attacker: CharacterBody2D = null):
if not is_alive or is_invulnerable:
return
# 防止过于频繁的伤害处理(性能保护)
var current_time = Time.get_ticks_msec() / 1000.0
if current_time - last_attack_time < 0.05: # 50ms最小伤害间隔
return
# 增加伤害反弹递归深度
damage_reflect_depth += 1
# 递归深度保护(防止无限反弹)
if damage_reflect_depth > max_reflect_depth:
damage_reflect_depth = max(0, damage_reflect_depth - 1)
return
# 闪避检测
if randf() < dodge_rate:
if attacker and is_instance_valid(attacker):
add_battle_detail_to_panel("" + pet_name + " 闪避了 " + attacker.pet_name + " 的攻击!", Color.CYAN)
damage_reflect_depth = max(0, damage_reflect_depth - 1)
return
var actual_damage = damage
@@ -1123,8 +1188,11 @@ func take_damage(damage: float, armor_pen: float = 0.0, attacker_element: Elemen
if actual_damage > 0:
current_health -= actual_damage
# 添加受伤细节
if attacker and is_instance_valid(attacker):
# 播放受伤动画(带冷却保护)
play_hurt_animation()
# 添加受伤细节(性能模式下减少文本输出)
if not performance_mode and attacker and is_instance_valid(attacker):
var damage_text = "💔 " + pet_name + " 受到 " + str(int(actual_damage)) + " 点伤害"
if element_extra_damage > 0:
damage_text += " (元素克制 +" + str(int(element_extra_damage)) + ""
@@ -1135,15 +1203,19 @@ func take_damage(damage: float, armor_pen: float = 0.0, attacker_element: Elemen
last_attacker = attacker
# 反击机制:立即将攻击者设为目标(只有启用战斗时才反击)
# 添加反击冷却,防止过于频繁的目标切换
if combat_enabled and attacker and is_instance_valid(attacker) and attacker.is_alive:
if attacker.get_team() != pet_team: # 确保不攻击队友
current_target = attacker
current_state = PetState.MOVING_TO_TARGET
# 只有当前没有目标或当前目标已死亡时才切换目标
if not current_target or not is_instance_valid(current_target) or not current_target.is_alive:
current_target = attacker
current_state = PetState.MOVING_TO_TARGET
# 伤害反弹
if enable_damage_reflect and damage_reflect > 0.0 and attacker and is_instance_valid(attacker):
var reflect_damage = damage * damage_reflect
attacker.take_damage(reflect_damage, 0.0, element_type, self) # 反弹伤害也会触发反击
# 伤害反弹(带递归深度保护)
if enable_damage_reflect and damage_reflect > 0.0 and attacker and is_instance_valid(attacker) and damage_reflect_depth <= max_reflect_depth:
var reflect_damage = damage * damage_reflect * 0.5 # 反弹伤害减半,防止无限递归
# 延迟反弹,避免同帧内的递归调用
call_deferred("apply_reflect_damage", attacker, reflect_damage)
# 检查死亡
if current_health <= 0:
@@ -1159,9 +1231,17 @@ func take_damage(damage: float, armor_pen: float = 0.0, attacker_element: Elemen
if not is_dying: # 防止重复调用die()
call_deferred("die")
# 减少伤害反弹递归深度
damage_reflect_depth = max(0, damage_reflect_depth - 1)
# 更新UI
call_deferred("update_ui")
# 延迟应用反弹伤害(防止递归调用)
func apply_reflect_damage(target: CharacterBody2D, reflect_damage: float):
if target and is_instance_valid(target) and target.is_alive:
target.take_damage(reflect_damage, 0.0, element_type, self)
#宠物死亡
func die():
if is_dying: # 如果已经在死亡过程中,直接返回
@@ -1416,6 +1496,10 @@ func apply_quality_bonuses():
func get_team() -> String:
return pet_team
# 获取攻击类型(调试用)
func get_attack_type() -> AttackType:
return attack_type
# 处理生命和护盾恢复
func handle_regeneration(delta: float):
var current_time = Time.get_ticks_msec() / 1000.0
@@ -1516,7 +1600,7 @@ func gain_experience(amount: float):
while pet_experience >= max_experience and pet_level < 50:
level_up()
# 升级
# 升级(新的随机属性系统)
func level_up():
pet_experience -= max_experience
pet_level += 1
@@ -1524,25 +1608,197 @@ func level_up():
# 计算新的升级经验需求(指数增长)
max_experience = 100.0 * pow(1.2, pet_level - 1)
# 升级属性加成
var level_bonus = 1.1 # 每级10%属性加成
# 随机选择属性进行升级
var upgraded_attributes = apply_random_attribute_upgrade()
max_health *= level_bonus
current_health = max_health # 升级回满血
attack_damage *= level_bonus
max_shield *= level_bonus
current_shield = max_shield # 升级回满护盾
max_armor *= level_bonus
current_armor = max_armor # 升级回满护甲
# 检查是否有里程碑奖励每5级
var milestone_rewards = apply_milestone_bonus()
# 升级回血和护盾护甲
current_health = max_health
current_shield = max_shield
current_armor = max_armor
# 升级特效
show_level_up_effect()
# 添加升级细节
add_battle_detail_to_panel("🎉 " + pet_name + " 升级到 " + str(pet_level) + " 级!", Color.GOLD)
var upgrade_text = "🎉 " + pet_name + " 升级到 " + str(pet_level) + " 级!"
upgrade_text += "\n📈 随机提升:" + ", ".join(upgraded_attributes)
if milestone_rewards.size() > 0:
upgrade_text += "\n🏆 里程碑奖励:" + ", ".join(milestone_rewards)
add_battle_detail_to_panel(upgrade_text, Color.GOLD)
call_deferred("update_ui")
# 应用随机属性升级
func apply_random_attribute_upgrade() -> Array[String]:
var upgraded_attributes: Array[String] = []
var available_attributes = base_upgrade_attributes.duplicate()
# 随机选择几个属性进行升级
for i in range(min(attributes_per_level, available_attributes.size())):
var random_index = randi() % available_attributes.size()
var selected_attribute = available_attributes[random_index]
available_attributes.remove_at(random_index)
# 应用属性升级
var upgrade_applied = apply_single_attribute_upgrade(selected_attribute)
if upgrade_applied:
upgraded_attributes.append(upgrade_applied)
return upgraded_attributes
# 应用单个属性升级
func apply_single_attribute_upgrade(attribute_name: String) -> String:
match attribute_name:
"max_health":
var bonus = randf_range(8.0, 15.0) # 随机8-15点生命值
max_health += bonus
return "生命值 +" + str(int(bonus))
"attack_damage":
var bonus = randf_range(2.0, 5.0) # 随机2-5点攻击力
attack_damage += bonus
return "攻击力 +" + str(int(bonus))
"move_speed":
var bonus = randf_range(3.0, 8.0) # 随机3-8点移动速度
move_speed += bonus
return "移动速度 +" + str(int(bonus))
"max_shield":
var bonus = randf_range(5.0, 12.0) # 随机5-12点护盾值
max_shield += bonus
return "护盾值 +" + str(int(bonus))
"max_armor":
var bonus = randf_range(4.0, 10.0) # 随机4-10点护甲值
max_armor += bonus
return "护甲值 +" + str(int(bonus))
"crit_rate":
var bonus = randf_range(0.01, 0.03) # 随机1-3%暴击率
crit_rate = min(1.0, crit_rate + bonus) # 暴击率上限100%
return "暴击率 +" + str(int(bonus * 100)) + "%"
"health_regen":
var bonus = randf_range(0.3, 0.8) # 随机0.3-0.8点生命恢复
health_regen += bonus
return "生命恢复 +" + str("%.1f" % bonus)
"attack_range":
var bonus = randf_range(8.0, 20.0) # 随机8-20点攻击距离
attack_range += bonus
return "攻击距离 +" + str(int(bonus))
_:
return ""
# 应用里程碑奖励
func apply_milestone_bonus() -> Array[String]:
var milestone_rewards: Array[String] = []
if not level_milestone_bonuses.has(pet_level):
return milestone_rewards
var bonuses = level_milestone_bonuses[pet_level]
for bonus_key in bonuses.keys():
var bonus_value = bonuses[bonus_key]
var reward_text = apply_milestone_bonus_single(bonus_key, bonus_value)
if reward_text != "":
milestone_rewards.append(reward_text)
return milestone_rewards
# 应用单个里程碑奖励
func apply_milestone_bonus_single(bonus_key: String, bonus_value) -> String:
match bonus_key:
"max_health":
max_health += bonus_value
return "生命值 +" + str(bonus_value)
"attack_damage":
attack_damage += bonus_value
return "攻击力 +" + str(bonus_value)
"max_shield":
max_shield += bonus_value
return "护盾值 +" + str(bonus_value)
"max_armor":
max_armor += bonus_value
return "护甲值 +" + str(bonus_value)
"crit_rate":
crit_rate = min(1.0, crit_rate + bonus_value)
return "暴击率 +" + str(int(bonus_value * 100)) + "%"
"armor_penetration":
armor_penetration += bonus_value
return "护甲穿透 +" + str(bonus_value)
"life_steal":
life_steal = min(1.0, life_steal + bonus_value)
return "生命汲取 +" + str(int(bonus_value * 100)) + "%"
"knockback_resist":
knockback_resist = min(1.0, knockback_resist + bonus_value)
return "击退抗性 +" + str(int(bonus_value * 100)) + "%"
"dodge_rate":
dodge_rate = min(1.0, dodge_rate + bonus_value)
return "闪避率 +" + str(int(bonus_value * 100)) + "%"
"health_regen":
health_regen += bonus_value
return "生命恢复 +" + str(bonus_value)
"move_speed":
move_speed += bonus_value
return "移动速度 +" + str(bonus_value)
"attack_range":
attack_range += bonus_value
return "攻击距离 +" + str(bonus_value)
"shield_regen":
shield_regen += bonus_value
return "护盾恢复 +" + str(bonus_value)
"crit_damage":
crit_damage += bonus_value
return "暴击伤害 +" + str(int(bonus_value * 100)) + "%"
"berserker_bonus":
berserker_bonus += bonus_value
return "狂暴加成 +" + str(int(bonus_value * 100)) + "%"
"damage_reflect":
damage_reflect = min(1.0, damage_reflect + bonus_value)
return "伤害反弹 +" + str(int(bonus_value * 100)) + "%"
"control_resist":
control_resist = min(1.0, control_resist + bonus_value)
return "控制抗性 +" + str(int(bonus_value * 100)) + "%"
"projectile_speed":
projectile_speed += bonus_value
return "子弹速度 +" + str(bonus_value)
"pierce_count":
pierce_count += bonus_value
return "穿透数量 +" + str(bonus_value)
"enable_berserker_mode":
if bonus_value:
enable_berserker_mode = true
return "解锁狂暴模式"
else:
return ""
"enable_damage_reflect":
if bonus_value:
enable_damage_reflect = true
return "解锁伤害反弹"
else:
return ""
"enable_aid_system":
if bonus_value:
enable_aid_system = true
return "解锁援助召唤"
else:
return ""
"enable_death_immunity":
if bonus_value:
enable_death_immunity = true
death_immunity = true
return "解锁死亡免疫"
else:
return ""
"enable_resurrection":
if bonus_value:
enable_resurrection = true
return "解锁死亡重生"
else:
return ""
_:
return ""
# 显示升级特效
func show_level_up_effect():
if not pet_image:
@@ -1677,34 +1933,24 @@ func heal(amount: float):
current_health = min(max_health, current_health + amount)
call_deferred("update_ui")
# 对目标应用击退效果
# 击退效果已禁用
func apply_knockback_to_target(target: CharacterBody2D):
if not target or not is_instance_valid(target):
return
# 计算击退方向
var direction = (target.global_position - global_position).normalized()
# 计算击退力度(考虑目标的击退抗性)
var effective_knockback = knockback_force * (1.0 - target.knockback_resist)
if effective_knockback > 0:
target.apply_knockback(direction, effective_knockback)
add_battle_detail_to_panel(pet_name + " 击退了 " + target.pet_name)
# 击退功能暂时禁用
pass
# 击退时调
# 击退效果已禁
func apply_knockback(direction: Vector2, force: float):
if not is_alive:
return
# 击退功能暂时禁用
pass
# 将位置限制在战斗区域内
func clamp_position_to_battle_area(pos: Vector2) -> Vector2:
var battle_area_min = Vector2(50, 50)
var battle_area_max = Vector2(1350, 670)
# 设置击退状态
is_being_knocked_back = true
knockback_velocity = direction * force
# 击退时短暂失去目标(可选)
if current_target and randf() < 0.3: # 30%概率失去目标
current_target = null
current_state = PetState.IDLE
pos.x = clamp(pos.x, battle_area_min.x, battle_area_max.x)
pos.y = clamp(pos.y, battle_area_min.y, battle_area_max.y)
return pos
# 元素克制计算
func get_element_multiplier(attacker_element: ElementType, defender_element: ElementType) -> float:
@@ -1827,3 +2073,82 @@ func clamp_to_patrol_area():
# 限制位置
position.x = clamp(position.x, min_x, max_x)
position.y = clamp(position.y, min_y, max_y)
# 播放受伤动画(带冷却保护)
func play_hurt_animation():
if not pet_image:
return
# 检查受伤动画冷却时间
var current_time = Time.get_ticks_msec() / 1000.0
if current_time - last_hurt_time < hurt_animation_cooldown:
return # 冷却中,不播放动画
last_hurt_time = current_time
# 如果已经有受伤动画在播放,停止之前的
if hurt_tween:
hurt_tween.kill()
hurt_tween = null
# 性能模式下简化动画
if performance_mode:
# 简单的颜色变化无需Tween
pet_image.modulate = Color.RED
# 使用计时器恢复颜色(更轻量)
await get_tree().create_timer(0.1).timeout
if pet_image: # 确保宠物还存在
pet_image.modulate = original_modulate
return
# 创建受伤动画(闪红效果)
hurt_tween = create_tween()
# 立即变红
pet_image.modulate = Color.RED
# 0.2秒后恢复原色
hurt_tween.tween_property(pet_image, "modulate", original_modulate, 0.2)
# 动画结束后清理
hurt_tween.tween_callback(func():
hurt_tween = null
)
# 切换性能模式
func toggle_performance_mode():
performance_mode = !performance_mode
var mode_text = "性能模式" if performance_mode else "正常模式"
add_battle_detail_to_panel("" + pet_name + " 切换到 " + mode_text, Color.YELLOW)
print("" + pet_name + " 切换到 " + mode_text)
# 输出宠物性能状态
func debug_performance_status():
print("=== " + pet_name + " 性能状态调试 ===")
print("性能模式: " + str(performance_mode))
print("伤害反弹深度: " + str(damage_reflect_depth))
print("帧跳跃计数: " + str(frame_skip_counter))
print("上次受伤时间: " + str(last_hurt_time))
print("上次攻击时间: " + str(last_attack_time))
print("当前状态: " + str(current_state))
print("是否存活: " + str(is_alive))
print("是否正在死亡: " + str(is_dying))
print("============================")
# 重置性能状态(紧急恢复)
func reset_performance_state():
performance_mode = false
damage_reflect_depth = 0
frame_skip_counter = 0
# 清理可能卡住的动画
if hurt_tween:
hurt_tween.kill()
hurt_tween = null
# 恢复正常颜色
if pet_image:
pet_image.modulate = original_modulate
print("🔄 " + pet_name + " 性能状态已重置")
add_battle_detail_to_panel("🔄 " + pet_name + " 性能状态已重置", Color.GREEN)

View File

@@ -57,7 +57,7 @@ var current_attacker_name: String = "" # 当前进攻者用户名
func _ready():
# 加载宠物配置
visibility_changed.connect(_on_visibility_changed)
load_pet_configs()
# 连接返回农场按钮
@@ -69,7 +69,6 @@ func _ready():
battle_end_panel.visible = false
if pet_battle_details_panel:
pet_battle_details_panel.visible = false
# 加载宠物配置
func load_pet_configs():
@@ -115,10 +114,17 @@ 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:
check_battle_end()
battle_check_timer += delta
if battle_check_timer >= battle_check_interval:
battle_check_timer = 0.0
check_battle_end()
# 获取队伍节点 - 供宠物调用
@@ -224,12 +230,6 @@ func end_battle(winner: String):
# 显示战斗结算面板
func show_battle_end_panel(winner: String):
var result_text = ""
var team1_survivors = 0
var team2_survivors = 0
var team1_total_damage = 0.0
var team2_total_damage = 0.0
var team1_pets_info: Array[String] = []
var team2_pets_info: Array[String] = []
# 统计存活宠物和详细信息 - 从宠物组中获取
var all_pets = get_tree().get_nodes_in_group("pets")
@@ -237,22 +237,6 @@ func show_battle_end_panel(winner: String):
if not is_instance_valid(pet):
continue
var status = "💀死亡"
if pet.is_alive:
status = "❤️存活(" + str(int(pet.current_health)) + ")"
if pet.pet_team == "team1":
team1_survivors += 1
elif pet.pet_team == "team2":
team2_survivors += 1
# 统计战力
if pet.pet_team == "team1":
team1_total_damage += pet.attack_damage
team1_pets_info.append(pet.pet_name + " " + status)
elif pet.pet_team == "team2":
team2_total_damage += pet.attack_damage
team2_pets_info.append(pet.pet_name + " " + status)
# 构建结算文本
result_text += "=== 战斗结算 ===\n\n"
@@ -416,39 +400,46 @@ func clear_all_pets():
# 清空对战细节
clear_battle_details()
# 先移除宠物组标签
var all_pets = get_tree().get_nodes_in_group("pets")
for pet in all_pets:
if is_instance_valid(pet):
# 检查是否是当前面板下的宠物
if pet.get_parent() == team1_node or pet.get_parent() == team2_node or pet.get_parent() == neutral_node:
pet.remove_from_group("pets")
pet.remove_from_group("team1")
pet.remove_from_group("team2")
pet.remove_from_group("neutral")
# 批量处理宠物清理,提高性能
var nodes_to_clear = [team1_node, team2_node, neutral_node]
# 清理现有宠物
for child in team1_node.get_children():
if is_instance_valid(child):
child.queue_free()
for child in team2_node.get_children():
if is_instance_valid(child):
child.queue_free()
for child in neutral_node.get_children():
if is_instance_valid(child):
child.queue_free()
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 all_projectiles = get_tree().get_nodes_in_group("projectiles")
for projectile in all_projectiles:
if is_instance_valid(projectile):
projectile.queue_free()
# 清理所有子弹和援助宠物
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):
@@ -556,7 +547,9 @@ func update_battle_pet_data(pet_id: String, attacker_name: String, exp_gained: f
"new_max_experience": max_exp,
"new_intimacy": current_intimacy,
"level_ups": level_ups,
"level_bonus_multiplier": level_bonus_multiplier
"level_bonus_multiplier": level_bonus_multiplier,
"is_steal_battle": is_steal_battle,
"battle_winner": winner_team
}
# 发送数据到服务器

View File

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

View File

@@ -95,8 +95,9 @@ func _add_message_to_history(data: Dictionary):
# 如果有玩家昵称,优先显示昵称
var display_name = player_name if player_name != "" else username
# 格式化时间
var datetime = Time.get_datetime_dict_from_unix_time(timestamp)
# 格式化时间 - 确保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]
# 创建消息记录

View File

@@ -427,7 +427,7 @@ func _on_harvest_button_pressed():
#=================面板通用函数==========================
#===================面板通用函数==========================
#退出
func _on_quit_button_pressed():
self.hide()
@@ -447,7 +447,7 @@ func _on_visibility_changed():
GlobalVariables.isZoomDisabled = false
pass
#=================面板通用函数==========================
#===================面板通用函数==========================
# 更新面板信息显示
func _update_panel_information():

View File

@@ -60,9 +60,8 @@ func show_pet_info(pet_name: String, pet_data: Dictionary):
# 设置宠物图片
_set_pet_image(pet_name)
# 设置宠物名称
var basic_info = pet_data.get("基本信息", {})
var pet_owner_name = basic_info.get("宠物名称", pet_name)
# 设置宠物名称新格式直接从pet_name字段获取
var pet_owner_name = pet_data.get("pet_name", pet_name)
pet_name_edit.text = pet_owner_name
# 设置宠物详细信息
@@ -85,26 +84,40 @@ func _set_pet_image(pet_name: String):
# 获取宠物纹理
func _get_pet_texture(pet_name: String) -> Texture2D:
var pet_config = _load_pet_config()
# 从服务器的宠物配置获取场景路径
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("场景路径", "")
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()
var pet_image_node = pet_instance.get_node_or_null("PetImage")
if pet_image_node and pet_image_node.sprite_frames:
var animation_names = pet_image_node.sprite_frames.get_animation_names()
# 直接使用实例化的场景根节点,因为根节点就是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_image_node.sprite_frames.get_frame_count(default_animation)
var frame_count = pet_instance.sprite_frames.get_frame_count(default_animation)
if frame_count > 0:
var texture = pet_image_node.sprite_frames.get_frame_texture(default_animation, 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
# 加载宠物配置数据
@@ -123,19 +136,10 @@ func _load_pet_config() -> Dictionary:
return json.data
# 设置宠物详细信息使用bbcode美化
# 设置宠物详细信息使用bbcode美化- 新格式
func _set_pet_detailed_info(pet_name: String, pet_data: Dictionary):
var basic_info = pet_data.get("基本信息", {})
var level_exp = pet_data.get("等级经验", {})
var purchase_info = pet_data.get("购买信息", {})
var health_defense = pet_data.get("生命与防御", {})
var attack_info = pet_data.get("基础攻击属性", {})
var movement = pet_data.get("移动与闪避", {})
var element = pet_data.get("元素属性", {})
var quality = pet_data.get("品质系统", {})
# 计算宠物年龄
var pet_birthday = basic_info.get("生日", "")
var pet_birthday = pet_data.get("pet_birthday", "")
var pet_age = 0
if pet_birthday != "":
pet_age = _calculate_pet_age(pet_birthday)
@@ -145,76 +149,64 @@ func _set_pet_detailed_info(pet_name: String, pet_data: Dictionary):
# 基本信息
info_text += "[color=pink][b]🐾 基本信息[/b][/color]\n"
info_text += "宠物类型:[color=yellow]" + str(basic_info.get("宠物类型", "未知")) + "[/color]\n"
info_text += "宠物编号:[color=gray]" + str(basic_info.get("宠物ID", "")) + "[/color]\n"
info_text += "性格特点:[color=cyan]" + str(basic_info.get("性格", "活泼")) + "[/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(level_exp.get("宠物等级", 1)) + " 级[/color]\n"
info_text += "经验值:[color=cyan]" + str(level_exp.get("当前经验", 0)) + "/" + str(level_exp.get("最大经验", 100)) + "[/color]\n"
info_text += "亲密度:[color=pink]" + str(level_exp.get("亲密度", 0)) + "/" + str(level_exp.get("最大亲密度", 1000)) + "[/color]\n\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(health_defense.get("当前生命值", 0)) + "/" + str(health_defense.get("最大生命值", 0)) + "[/color]\n"
info_text += "护甲值:[color=blue]" + str(health_defense.get("当前护甲值", 0)) + "/" + str(health_defense.get("最大护甲值", 0)) + "[/color]\n"
info_text += "护盾值:[color=cyan]" + str(health_defense.get("当前护盾值", 0)) + "/" + str(health_defense.get("最大护盾值", 0)) + "[/color]\n"
info_text += "生命恢复:[color=lime]" + str(health_defense.get("生命恢复速度", 0)) + "/秒[/color]\n\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=yellow]" + _get_attack_type_name(str(attack_info.get("攻击类型", "MELEE"))) + "[/color]\n"
info_text += "攻击伤害[color=red]" + str(attack_info.get("基础攻击伤害", 0)) + "[/color]\n"
info_text += "攻击距离[color=green]" + str(attack_info.get("攻击距离", 0)) + " 像素[/color]\n"
info_text += "暴击几率[color=purple]" + str(attack_info.get("暴击率", 0) * 100) + "%[/color]\n"
info_text += "暴击倍数[color=purple]" + str(attack_info.get("暴击伤害倍数", 1.0)) + "[/color]\n"
info_text += "生命汲取[color=magenta]" + str(attack_info.get("生命汲取", 0) * 100) + "%[/color]\n\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(movement.get("移动速度", 0)) + " 像素/秒[/color]\n"
info_text += "闪避几率:[color=yellow]" + str(movement.get("闪避率", 0) * 100) + "%[/color]\n"
info_text += "击退力度:[color=red]" + str(movement.get("击退力度", 0)) + " 点[/color]\n"
info_text += "击退抗性:[color=blue]" + str(movement.get("击退抗性", 0) * 100) + "%[/color]\n\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(element.get("元素类型", "NONE"))) + "[/color]\n"
info_text += "元素伤害:[color=orange]" + str(element.get("元素克制额外伤害", 0)) + " 点[/color]\n\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"
# 品质系统
var quality_text = str(quality.get("宠物品质", "COMMON"))
var quality_color = "white"
var quality_name = ""
if quality_text == "COMMON":
quality_color = "gray"
quality_name = "普通"
elif quality_text == "RARE":
quality_color = "blue"
quality_name = "稀有"
elif quality_text == "EPIC":
quality_color = "purple"
quality_name = "史诗"
elif quality_text == "LEGENDARY":
quality_color = "orange"
quality_name = "传说"
else:
quality_name = quality_text
info_text += "[color=gold][b]✨ 品质系统[/b][/color]\n"
info_text += "宠物品质:[color=" + quality_color + "]" + quality_name + "[/color]\n\n"
# 购买信息
info_text += "[color=gold][b]💰 购买信息[/b][/color]\n"
info_text += "购买价格:[color=yellow]" + str(purchase_info.get("购买价格", 0)) + " 金币[/color]\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"
info_text += "\n"
# 设置文本
pet_inform.text = info_text
# 获取攻击类型名称
func _get_attack_type_name(attack_type: String) -> String:
match attack_type:
@@ -340,9 +332,8 @@ func on_edit_inform_button_pressed():
Toast.show("宠物名字太长最多20个字符", Color.RED, 2.0, 1.0)
return
# 获取当前宠物名字
var basic_info = current_pet_data.get("基本信息", {})
var current_name = basic_info.get("宠物名称", "")
# 获取当前宠物名字(新格式)
var current_name = current_pet_data.get("pet_name", "")
# 检查名字是否有变化
if new_pet_name == current_name:
@@ -383,9 +374,8 @@ func _on_confirm_rename_pet(new_name: String, dialog: AcceptDialog):
# 取消重命名宠物
func _on_cancel_rename_pet(dialog: AcceptDialog):
# 恢复原名字
var basic_info = current_pet_data.get("基本信息", {})
var original_name = basic_info.get("宠物名称", "")
# 恢复原名字(新格式)
var original_name = current_pet_data.get("pet_name", "")
pet_name_edit.text = original_name
dialog.queue_free()
@@ -395,9 +385,8 @@ func _send_rename_pet_request(new_name: String):
Toast.show("网络功能不可用", Color.RED, 2.0, 1.0)
return
# 获取宠物ID
var basic_info = current_pet_data.get("基本信息", {})
var pet_id = basic_info.get("宠物ID", "")
# 获取宠物ID(新格式)
var pet_id = current_pet_data.get("pet_id", "")
if pet_id == "":
Toast.show("宠物ID无效", Color.RED, 2.0, 1.0)
@@ -411,9 +400,9 @@ func _send_rename_pet_request(new_name: String):
# 处理重命名成功的响应(从宠物背包或其他地方调用)
func on_rename_pet_success(pet_id: String, new_name: String):
# 更新当前宠物数据
if current_pet_data.get("基本信息", {}).get("宠物ID", "") == pet_id:
current_pet_data["基本信息"]["宠物名称"] = new_name
# 更新当前宠物数据(新格式)
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)
@@ -469,11 +458,6 @@ func on_use_item_button_pressed():
# 巡逻按钮点击事件
func _on_patrol_button_pressed():
#直接在客户端
patro_button.text = "取消巡逻"
patro_button.modulate = Color.ORANGE
if current_pet_data.is_empty():
Toast.show("没有选择宠物", Color.RED, 2.0, 1.0)
return
@@ -484,65 +468,61 @@ func _on_patrol_button_pressed():
return
# 获取宠物ID
var basic_info = current_pet_data.get("基本信息", {})
var pet_id = basic_info.get("宠物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_patrolling = _is_pet_patrolling(pet_id)
# 检查是否已在巡逻
var is_patrolling = _is_pet_patrolling(pet_id)
if is_currently_patrolling:
# 取消巡逻
_remove_from_patrol(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:
# 添加到巡逻
_add_to_patrol(pet_id)
# 检查巡逻宠物数量限制
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:
# 检查服务器的巡逻宠物数据
if main_game.patrol_pets == null or main_game.patrol_pets.size() == 0:
return false
# 遍历巡逻宠物列表查找匹配的ID
for patrol_pet in main_game.patrol_pets:
var patrol_pet_id = patrol_pet.get("基本信息", {}).get("宠物ID", "")
if patrol_pet_id == pet_id:
return true
# 检查本地 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
# 添加到巡逻新的基于ID的逻辑
func _add_to_patrol(pet_id: String):
# 检查巡逻宠物数量限制目前服务器设置最多3个
if main_game.patrol_pets != null and main_game.patrol_pets.size() >= 3:
Toast.show("最多只能设置3个巡逻宠物", Color.ORANGE, 3.0, 1.0)
return
# 移除巡逻宠物
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
# 目前简化为只允许一个巡逻宠物
if main_game.patrol_pets != null and main_game.patrol_pets.size() >= 1:
Toast.show("已有宠物在巡逻,请先取消当前巡逻", Color.ORANGE, 3.0, 1.0)
return
# 如果不是访问模式,则发送到服务器保存
if not main_game.is_visiting_mode:
# 发送到服务器保存
tcp_network_manager_panel.sendSetPatrolPet(pet_id, true)
var pet_name = current_pet_data.get("基本信息", {}).get("宠物名称", "未知")
else:
Toast.show("访问模式下无法设置巡逻宠物", Color.ORANGE, 2.0, 1.0)
# 从巡逻中移除新的基于ID的逻辑
func _remove_from_patrol(pet_id: String):
# 如果不是访问模式,则发送到服务器保存
if not main_game.is_visiting_mode:
# 发送到服务器移除
tcp_network_manager_panel.sendSetPatrolPet(pet_id, false)
else:
Toast.show("访问模式下无法取消巡逻宠物", Color.ORANGE, 2.0, 1.0)
print("未找到对应的巡逻宠物实例: " + pet_id)
# 更新巡逻按钮文本
func _update_patrol_button_text(is_patrolling: bool):
@@ -558,8 +538,7 @@ func _refresh_patrol_button():
if current_pet_data.is_empty():
return
var basic_info = current_pet_data.get("基本信息", {})
var pet_id = basic_info.get("宠物ID", "")
var pet_id = current_pet_data.get("pet_id", "")
if pet_id == "":
return
@@ -578,9 +557,8 @@ func _on_battle_button_pressed():
Toast.show("访问模式下无法设置出战宠物", Color.ORANGE, 2.0, 1.0)
return
# 获取宠物ID
var basic_info = current_pet_data.get("基本信息", {})
var pet_id = basic_info.get("宠物ID", "")
# 获取宠物ID(新格式)
var pet_id = current_pet_data.get("pet_id", "")
if pet_id == "":
Toast.show("宠物ID无效", Color.RED, 2.0, 1.0)
@@ -602,9 +580,9 @@ func _is_pet_battling(pet_id: String) -> bool:
if main_game.battle_pets == null or main_game.battle_pets.size() == 0:
return false
# 遍历出战宠物列表查找匹配的ID
# 遍历出战宠物列表查找匹配的ID(新格式)
for battle_pet in main_game.battle_pets:
var battle_pet_id = battle_pet.get("基本信息", {}).get("宠物ID", "")
var battle_pet_id = battle_pet.get("pet_id", "")
if battle_pet_id == pet_id:
return true
@@ -612,9 +590,9 @@ func _is_pet_battling(pet_id: String) -> bool:
# 添加到出战新的基于ID的逻辑
func _add_to_battle(pet_id: String):
# 检查出战宠物数量限制(目前服务器设置最多1个)
if main_game.battle_pets != null and main_game.battle_pets.size() >= 1:
Toast.show("最多只能设置1个出战宠物", Color.ORANGE, 3.0, 1.0)
# 检查出战宠物数量限制(目前服务器设置最多4个)
if main_game.battle_pets != null and main_game.battle_pets.size() >= 4:
Toast.show("最多只能设置4个出战宠物", Color.ORANGE, 3.0, 1.0)
return
# 检查是否在巡逻中(出战宠物不能是巡逻宠物)
@@ -626,7 +604,7 @@ func _add_to_battle(pet_id: String):
if not main_game.is_visiting_mode:
# 发送到服务器保存
tcp_network_manager_panel.sendSetBattlePet(pet_id, true)
var pet_name = current_pet_data.get("基本信息", {}).get("宠物名称", "未知")
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)
@@ -655,8 +633,7 @@ func _refresh_battle_button():
if current_pet_data.is_empty():
return
var basic_info = current_pet_data.get("基本信息", {})
var pet_id = basic_info.get("宠物ID", "")
var pet_id = current_pet_data.get("pet_id", "")
if pet_id == "":
return

View File

@@ -247,15 +247,20 @@ func handle_wisdom_tree_operation_response(success: bool, message: String, opera
# 根据操作类型显示不同的提示
match operation_type:
"water":
Toast.show("浇水成功!" + message, Color.CYAN)
#Toast.show("浇水成功!" + message, Color.CYAN)
pass
"fertilize":
Toast.show("施肥成功!" + message, Color.PURPLE)
#Toast.show("施肥成功!" + message, Color.PURPLE)
pass
"kill_grass":
Toast.show("除草成功!" + message, Color.GREEN)
#Toast.show("除草成功!" + message, Color.GREEN)
pass
"kill_bug":
Toast.show("杀虫成功!" + message, Color.GREEN)
#Toast.show("杀虫成功!" + message, Color.GREEN)
pass
"play_music":
Toast.show("放音乐成功!" + message, Color.MAGENTA)
#Toast.show("放音乐成功!" + message, Color.MAGENTA)
pass
# 放音乐时可能获得随机消息,需要特殊处理
if updated_data.has("random_message"):
var random_message = updated_data["random_message"]
@@ -293,7 +298,7 @@ func handle_wisdom_tree_message_response(success: bool, message: String, updated
main_game.money = updated_data["钱币"]
main_game._update_ui()
Toast.show("消息发送成功!", Color.GREEN)
#Toast.show("消息发送成功!", Color.GREEN)
else:
Toast.show(message, Color.RED)