2155 lines
70 KiB
GDScript
2155 lines
70 KiB
GDScript
extends CharacterBody2D
|
||
|
||
@onready var pet_image: AnimatedSprite2D = $PetImage #这里展示宠物动画
|
||
@onready var pet_tool_image: Sprite2D = $PetImage/PetToolImage #这里展示宠物武器工具
|
||
@onready var pet_name_rich_text: RichTextLabel = $PetInformVBox/PetNameRichText #这里展示主人给宠物命名的名字
|
||
@onready var armor_bar: ProgressBar = $PetInformVBox/ArmorBar #宠物盔甲值进度条
|
||
@onready var armor_label: Label = $PetInformVBox/ArmorBar/ArmorLabel #宠物盔甲值
|
||
@onready var shield_bar: ProgressBar = $PetInformVBox/ShieldBar #宠物护盾值进度条
|
||
@onready var shield_label: Label = $PetInformVBox/ShieldBar/ShieldLabel #宠物护盾值
|
||
@onready var health_bar: ProgressBar = $PetInformVBox/HealthBar #宠物生命值进度条
|
||
@onready var health_label: Label = $PetInformVBox/HealthBar/HealthLabel #宠物生命值
|
||
@onready var volume_collision: CollisionShape2D = $VolumeCollision #宠物碰撞体积
|
||
|
||
|
||
#=====================宠物基本属性=====================
|
||
### 一、基础信息
|
||
#- 主人(主人名字)
|
||
#- 生日(年月日时分秒)
|
||
#- 年龄(从生日开始算
|
||
#- 性格(开朗,内向,活泼,安静,暴躁,温和,调皮,懒惰
|
||
#- 简介
|
||
#- 爱好
|
||
#- 宠物ID(唯一标识,从0000开始)
|
||
#- 宠物类型(宠物原本的名字,比如绿史莱姆,红史莱姆,迷你护卫,小绿人)
|
||
#- 宠物名称 (主人给宠物命名的名字)
|
||
#- 能否购买(true/false)
|
||
#- 购买价格(如果可以购买)
|
||
#- 出售价格(如果可以出售)
|
||
|
||
### 二、生存与防御
|
||
#- 生命值(可恢复,小于等于0则死亡)
|
||
#- 护盾值(不可恢复的生命值)
|
||
#- 护甲值(折扣伤害)
|
||
#- 生命恢复(恢复生命值,多少秒恢复多少生命值,如0.5秒恢复10点生命值)
|
||
#- 闪避率(免疫伤害概率)
|
||
#- 控制抗性(减免被控时长和概率)
|
||
#- 击退抗性(抵消击退力度)
|
||
#- 移动速度
|
||
|
||
### 三、攻击与效果
|
||
#- 普通攻击伤害
|
||
#- 普通攻击速度
|
||
#- 暴击率(暴击概率)
|
||
#- 暴击伤害
|
||
#- 护甲穿透(忽视敌人护甲)
|
||
#- 生命汲取(普攻回血%)
|
||
#- 击退(攻击使敌人后退)
|
||
|
||
### 四、其他属性
|
||
#- 元素属性(金木水火土,雷)
|
||
#- 等级(等级高属性强)
|
||
#- 经验值(满额升级)
|
||
#- 亲密度(额外加属性)
|
||
#- 品质(白/绿/蓝/橙/红/紫)
|
||
|
||
#近战
|
||
#近战攻击伤害
|
||
#近战攻击速度
|
||
|
||
#附录
|
||
#- 护甲公式示例:实际伤害 = 基础伤害 × (1 - 护甲值/(护甲值 + 100)),搭配"护甲穿透"可直接减少目标护甲值
|
||
#- 元素克制:火属性攻击对冰属性敌人造成150%伤害,同时被水属性克制(仅造成80%伤害)
|
||
#- 成长曲线:低级宠物升级快,高级宠物经验需求指数增长,避免养成周期过短
|
||
|
||
#特殊机制
|
||
#1.伤害反弹,无视防具穿透伤害,
|
||
#2.血量低于某个值进入狂暴模式,
|
||
#3.死亡后重生一次,
|
||
#4.毅力不倒、不死图腾(受到致命伤害抵挡并维持一滴血)
|
||
#5.援助 宠物血量低于某个值时,会自动召唤宠物仆从,宠物仆从会自动攻击敌人,唤数量(一次召唤多少个宠物仆从),唤间隔(多少秒召唤一次)
|
||
#=====================宠物基本属性=====================
|
||
|
||
|
||
# 宠物基本属性(从JSON配置文件加载)
|
||
var pet_owner: String = "树萌芽" # 宠物主人
|
||
var pet_name: String = "宠物名称" # 宠物名称
|
||
var pet_team: String = "team1" # 队伍标识:team1, team2, neutral
|
||
var pet_id: String = "0001" # 宠物唯一ID
|
||
var pet_type: String = "小绿人" # 宠物类型(原本名字)
|
||
var pet_birthday: String = "" # 生日(年月日时分秒)
|
||
var pet_age: int = 0 # 年龄(天数)
|
||
var pet_personality: String = "活泼" # 性格
|
||
var pet_introduction: String = "" # 简介
|
||
var pet_hobby: String = "" # 爱好
|
||
|
||
var pet_level: int = 1 # 宠物等级
|
||
var pet_experience: float = 0.0 # 当前经验值
|
||
var max_experience: float = 100.0 # 升级所需经验值
|
||
var pet_intimacy: float = 0.0 # 亲密度
|
||
var max_intimacy: float = 1000.0 # 最大亲密度
|
||
|
||
var can_buy: bool = true # 能否购买
|
||
var buy_price: int = 100 # 购买价格
|
||
var sell_price: int = 50 # 出售价格
|
||
|
||
# 生命与防御属性
|
||
var max_health: float = 100.0 # 最大生命值
|
||
var current_health: float = 100.0 # 当前生命值
|
||
var health_regen: float = 1.0 # 生命恢复速度(每秒)
|
||
var max_shield: float = 0.0 # 最大护盾值
|
||
var current_shield: float = 0.0 # 当前护盾值
|
||
var shield_regen: float = 0.0 # 护盾恢复速度(每秒)- 默认不恢复
|
||
var max_armor: float = 100.0 # 最大护甲值
|
||
var current_armor: float = 100.0 # 当前护甲值
|
||
|
||
# 攻击属性
|
||
var attack_type: AttackType = AttackType.RANGED # 攻击类型
|
||
var attack_damage: float = 20.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)
|
||
var armor_penetration: float = 0.0 # 护甲穿透
|
||
|
||
var melee_damage_bonus: float = 0.0 # 近战额外伤害(在基础伤害上加成)
|
||
var melee_attack_speed: float = 1.0 # 近战攻击速度
|
||
|
||
var ranged_damage_bonus: float = 0.0 # 远程额外伤害(在基础伤害上加成)
|
||
var ranged_attack_speed: float = 1.0 # 远程攻击速度
|
||
var ranged_mode: RangedAttackMode = RangedAttackMode.SINGLE # 远程攻击模式
|
||
var projectile_speed: float = 300.0 # 子弹速度
|
||
|
||
var shotgun_bullets: int = 5 # 散弹数量
|
||
var shotgun_spread_angle: float = 45.0 # 散弹扩散角度(度)
|
||
|
||
var burst_rows: int = 2 # 多发射击行数
|
||
var burst_cols: int = 3 # 多发射击列数
|
||
var burst_spacing: float = 30.0 # 多发射击间距
|
||
|
||
var gatling_bullets: int = 8 # 加特林子弹数量
|
||
var gatling_interval: float = 0.1 # 加特林射击间隔
|
||
var gatling_cooldown: float = 2.0 # 加特林冷却时间
|
||
|
||
var pierce_count: int = 3 # 穿透数量
|
||
|
||
# 远程攻击类型枚举
|
||
enum AttackType {
|
||
MELEE, # 近战攻击
|
||
RANGED # 远程攻击
|
||
}
|
||
|
||
enum RangedAttackMode {
|
||
SINGLE, # 普通单发
|
||
SHOTGUN, # 散弹攻击
|
||
BURST, # 多发射击(平行)
|
||
GATLING, # 加特林式连射
|
||
PIERCING # 穿透攻击
|
||
}
|
||
|
||
|
||
var attack_speed: float = 1.0 # 当前攻击速度(根据攻击类型动态设置)
|
||
var gatling_firing: bool = false # 是否正在加特林射击
|
||
var gatling_current_bullet: int = 0 # 当前加特林子弹计数
|
||
var gatling_last_shot: float = 0.0 # 上次加特林射击时间
|
||
|
||
@export var projectile_scene: PackedScene = preload("res://Scene/Pet/Projectile.tscn") # 子弹场景
|
||
|
||
# 移动与闪避属性
|
||
var move_speed: float = 100.0 # 移动速度
|
||
var dodge_rate: float = 0.05 # 闪避率(0.0-1.0)
|
||
var knockback_force: float = 300.0 # 击退力度
|
||
var knockback_resist: float = 0.0 # 击退抗性(0.0-1.0)
|
||
|
||
# 元素属性
|
||
enum ElementType {
|
||
NONE, # 无属性
|
||
METAL, # 金
|
||
WOOD, # 木
|
||
WATER, # 水
|
||
FIRE, # 火
|
||
EARTH, # 土
|
||
THUNDER # 雷
|
||
}
|
||
var element_type: ElementType = ElementType.NONE# 宠物元素属性
|
||
var element_damage_bonus: float = 50.0 # 元素克制额外伤害
|
||
|
||
var control_resist: float = 0.0 # 控制抗性(减少眩晕等控制时间)
|
||
var damage_reflect: float = 0.0 # 伤害反弹(0.0-1.0)
|
||
var death_immunity: bool = false # 死亡免疫(一次性)
|
||
var berserker_threshold: float = 0.3 # 狂暴阈值(血量低于此值时触发狂暴)
|
||
var berserker_bonus: float = 1.5 # 狂暴状态伤害倍数
|
||
|
||
# 特殊机制开关(布尔值控制是否启用各种特殊机制)
|
||
var enable_damage_reflect: bool = false # 启用伤害反弹机制
|
||
var enable_berserker_mode: bool = false # 启用狂暴模式机制
|
||
var enable_death_immunity: bool = false # 启用死亡免疫机制
|
||
var enable_aid_system: bool = false # 启用援助召唤机制
|
||
var enable_resurrection: bool = false # 启用死亡重生机制
|
||
var resurrection_used: bool = false # 重生是否已使用
|
||
|
||
# 援助系统属性
|
||
var aid_threshold: float = 0.2 # 援助触发阈值(血量低于此值时召唤援助)
|
||
var aid_summon_count: int = 2 # 一次召唤的援助数量
|
||
var aid_summon_interval: float = 5.0 # 援助召唤间隔(秒)
|
||
var aid_last_summon_time: float = 0.0 # 上次召唤援助的时间
|
||
var aid_summoned: bool = false # 是否已经召唤过援助(防止重复召唤)
|
||
var aid_minions: Array[CharacterBody2D] = [] # 召唤的援助宠物列表
|
||
|
||
# 品质系统
|
||
enum PetQuality {
|
||
COMMON, # 普通(白)
|
||
UNCOMMON, # 不凡(绿)
|
||
RARE, # 稀有(蓝)
|
||
EPIC, # 史诗(紫)
|
||
LEGENDARY, # 传说(橙)
|
||
MYTHIC # 神话(红)
|
||
}
|
||
var pet_quality: PetQuality = PetQuality.COMMON # 宠物品质
|
||
|
||
# 战斗状态
|
||
var is_alive: bool = true # 是否存活
|
||
var is_dying: bool = false # 是否正在死亡过程中(防止重复调用die())
|
||
var is_attacking: bool = false # 是否正在攻击
|
||
var is_berserker: bool = false # 是否处于狂暴状态
|
||
var is_stunned: bool = false # 是否被眩晕
|
||
var is_invulnerable: 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 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 # 是否正在巡逻
|
||
var patrol_path: PackedVector2Array = [] # 巡逻路径点
|
||
var patrol_speed: float = 80.0 # 巡逻移动速度
|
||
var current_patrol_index: int = 0 # 当前巡逻目标点索引
|
||
var patrol_wait_time: float = 0.0 # 在巡逻点等待的时间
|
||
var patrol_max_wait_time: float = 1.0 # 在巡逻点的最大等待时间
|
||
|
||
# 战斗控制
|
||
var combat_enabled: bool = true # 是否启用战斗行为
|
||
|
||
# AI状态
|
||
enum PetState {
|
||
IDLE, #站立空闲
|
||
MOVING_TO_TARGET, #移动到目标
|
||
ATTACKING, #攻击
|
||
PATROLLING, #巡逻
|
||
DEAD #死亡
|
||
}
|
||
var current_state: PetState = PetState.IDLE # 当前状态
|
||
|
||
# 队伍节点引用
|
||
var team_nodes: Dictionary = {}
|
||
|
||
# 从JSON配置文件加载宠物配置(强制要求)
|
||
func load_pet_config_from_json():
|
||
var file = FileAccess.open("res://Data/pet_data.json", FileAccess.READ)
|
||
if not file:
|
||
set_basic_default_values()
|
||
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:
|
||
set_basic_default_values()
|
||
return
|
||
|
||
var pet_configs = json.data
|
||
var pet_name_key = get_pet_name_key()
|
||
|
||
if not pet_configs.has(pet_name_key):
|
||
set_basic_default_values()
|
||
return
|
||
|
||
var config = pet_configs[pet_name_key]
|
||
apply_json_config(config)
|
||
|
||
# 设置基本默认值(当JSON加载失败时使用)
|
||
func set_basic_default_values():
|
||
# 基本信息
|
||
pet_owner = "未知主人"
|
||
pet_name = "未配置宠物"
|
||
pet_team = "team1"
|
||
pet_id = "0000"
|
||
pet_type = "未知类型"
|
||
pet_birthday = ""
|
||
pet_age = 0
|
||
pet_personality = "活泼"
|
||
pet_introduction = ""
|
||
pet_hobby = ""
|
||
|
||
# 等级经验
|
||
pet_level = 1
|
||
pet_experience = 0.0
|
||
max_experience = 100.0
|
||
pet_intimacy = 0.0
|
||
max_intimacy = 1000.0
|
||
|
||
# 购买信息
|
||
can_buy = true
|
||
buy_price = 100
|
||
sell_price = 50
|
||
|
||
# 生命与防御
|
||
max_health = 100.0
|
||
current_health = 100.0
|
||
health_regen = 1.0
|
||
max_shield = 0.0
|
||
current_shield = 0.0
|
||
shield_regen = 0.0
|
||
max_armor = 100.0
|
||
current_armor = 100.0
|
||
|
||
# 基础攻击属性
|
||
attack_type = AttackType.RANGED
|
||
attack_damage = 20.0
|
||
attack_range = 300.0
|
||
crit_rate = 0.1
|
||
crit_damage = 1.5
|
||
life_steal = 0.1
|
||
armor_penetration = 0.0
|
||
|
||
# 近战攻击
|
||
melee_damage_bonus = 0.0
|
||
melee_attack_speed = 1.0
|
||
|
||
# 远程攻击
|
||
ranged_damage_bonus = 0.0
|
||
ranged_attack_speed = 1.0
|
||
ranged_mode = RangedAttackMode.SINGLE
|
||
projectile_speed = 300.0
|
||
|
||
# 散弹攻击
|
||
shotgun_bullets = 5
|
||
shotgun_spread_angle = 45.0
|
||
|
||
# 多发射击
|
||
burst_rows = 2
|
||
burst_cols = 3
|
||
burst_spacing = 30.0
|
||
|
||
# 加特林属性
|
||
gatling_bullets = 8
|
||
gatling_interval = 0.1
|
||
gatling_cooldown = 2.0
|
||
|
||
# 穿透属性
|
||
pierce_count = 3
|
||
|
||
# 移动与闪避
|
||
move_speed = 100.0
|
||
dodge_rate = 0.05
|
||
knockback_force = 300.0
|
||
knockback_resist = 0.0
|
||
|
||
# 元素属性
|
||
element_type = ElementType.NONE
|
||
element_damage_bonus = 50.0
|
||
|
||
# 特殊属性
|
||
control_resist = 0.0
|
||
damage_reflect = 0.0
|
||
death_immunity = false
|
||
berserker_threshold = 0.3
|
||
berserker_bonus = 1.5
|
||
|
||
# 特殊机制开关
|
||
enable_damage_reflect = false
|
||
enable_berserker_mode = false
|
||
enable_death_immunity = false
|
||
enable_aid_system = false
|
||
enable_resurrection = false
|
||
|
||
# 援助系统
|
||
aid_threshold = 0.2
|
||
aid_summon_count = 2
|
||
aid_summon_interval = 5.0
|
||
|
||
# 品质系统
|
||
pet_quality = PetQuality.COMMON
|
||
|
||
# 获取宠物名称键(用于JSON配置查找)
|
||
func get_pet_name_key() -> String:
|
||
# 直接返回宠物类型作为JSON键
|
||
# 现在pet_type已经是正确的JSON键名了
|
||
return pet_type
|
||
|
||
# 应用JSON配置到宠物属性
|
||
func apply_json_config(config: Dictionary):
|
||
# 基本信息
|
||
if config.has("基本信息"):
|
||
var basic_info = config["基本信息"]
|
||
if basic_info.has("宠物主人"):
|
||
pet_owner = basic_info["宠物主人"]
|
||
if basic_info.has("宠物名称"):
|
||
pet_name = basic_info["宠物名称"]
|
||
if basic_info.has("队伍标识"):
|
||
pet_team = basic_info["队伍标识"]
|
||
if basic_info.has("宠物ID"):
|
||
pet_id = basic_info["宠物ID"]
|
||
if basic_info.has("宠物类型"):
|
||
pet_type = basic_info["宠物类型"]
|
||
if basic_info.has("生日"):
|
||
pet_birthday = basic_info["生日"]
|
||
if basic_info.has("年龄"):
|
||
pet_age = basic_info["年龄"]
|
||
if basic_info.has("性格"):
|
||
pet_personality = basic_info["性格"]
|
||
if basic_info.has("简介"):
|
||
pet_introduction = basic_info["简介"]
|
||
if basic_info.has("爱好"):
|
||
pet_hobby = basic_info["爱好"]
|
||
|
||
# 等级经验
|
||
if config.has("等级经验"):
|
||
var level_exp = config["等级经验"]
|
||
if level_exp.has("宠物等级"):
|
||
pet_level = level_exp["宠物等级"]
|
||
if level_exp.has("当前经验"):
|
||
pet_experience = level_exp["当前经验"]
|
||
if level_exp.has("最大经验"):
|
||
max_experience = level_exp["最大经验"]
|
||
if level_exp.has("亲密度"):
|
||
pet_intimacy = level_exp["亲密度"]
|
||
if level_exp.has("最大亲密度"):
|
||
max_intimacy = level_exp["最大亲密度"]
|
||
|
||
# 购买信息
|
||
if config.has("购买信息"):
|
||
var buy_info = config["购买信息"]
|
||
if buy_info.has("能否购买"):
|
||
can_buy = buy_info["能否购买"]
|
||
if buy_info.has("购买价格"):
|
||
buy_price = buy_info["购买价格"]
|
||
if buy_info.has("出售价格"):
|
||
sell_price = buy_info["出售价格"]
|
||
|
||
# 生命与防御
|
||
if config.has("生命与防御"):
|
||
var health_defense = config["生命与防御"]
|
||
if health_defense.has("最大生命值"):
|
||
max_health = health_defense["最大生命值"]
|
||
if health_defense.has("当前生命值"):
|
||
current_health = health_defense["当前生命值"]
|
||
if health_defense.has("生命恢复速度"):
|
||
health_regen = health_defense["生命恢复速度"]
|
||
if health_defense.has("最大护盾值"):
|
||
max_shield = health_defense["最大护盾值"]
|
||
if health_defense.has("当前护盾值"):
|
||
current_shield = health_defense["当前护盾值"]
|
||
if health_defense.has("护盾恢复速度"):
|
||
shield_regen = health_defense["护盾恢复速度"]
|
||
if health_defense.has("最大护甲值"):
|
||
max_armor = health_defense["最大护甲值"]
|
||
if health_defense.has("当前护甲值"):
|
||
current_armor = health_defense["当前护甲值"]
|
||
|
||
# 基础攻击属性
|
||
if config.has("基础攻击属性"):
|
||
var attack_attr = config["基础攻击属性"]
|
||
if attack_attr.has("攻击类型"):
|
||
var attack_type_str = attack_attr["攻击类型"]
|
||
if attack_type_str == "MELEE":
|
||
attack_type = AttackType.MELEE
|
||
elif attack_type_str == "RANGED":
|
||
attack_type = AttackType.RANGED
|
||
if attack_attr.has("基础攻击伤害"):
|
||
attack_damage = attack_attr["基础攻击伤害"]
|
||
if attack_attr.has("攻击距离"):
|
||
attack_range = attack_attr["攻击距离"]
|
||
if attack_attr.has("暴击率"):
|
||
crit_rate = attack_attr["暴击率"]
|
||
if attack_attr.has("暴击伤害倍数"):
|
||
crit_damage = attack_attr["暴击伤害倍数"]
|
||
if attack_attr.has("生命汲取"):
|
||
life_steal = attack_attr["生命汲取"]
|
||
if attack_attr.has("护甲穿透"):
|
||
armor_penetration = attack_attr["护甲穿透"]
|
||
|
||
# 近战攻击
|
||
if config.has("近战攻击"):
|
||
var melee_attack = config["近战攻击"]
|
||
if melee_attack.has("近战额外伤害"):
|
||
melee_damage_bonus = melee_attack["近战额外伤害"]
|
||
if melee_attack.has("近战攻击速度"):
|
||
melee_attack_speed = melee_attack["近战攻击速度"]
|
||
|
||
# 远程攻击
|
||
if config.has("远程攻击"):
|
||
var ranged_attack = config["远程攻击"]
|
||
if ranged_attack.has("远程额外伤害"):
|
||
ranged_damage_bonus = ranged_attack["远程额外伤害"]
|
||
if ranged_attack.has("远程攻击速度"):
|
||
ranged_attack_speed = ranged_attack["远程攻击速度"]
|
||
if ranged_attack.has("远程攻击模式"):
|
||
var ranged_mode_str = ranged_attack["远程攻击模式"]
|
||
match ranged_mode_str:
|
||
"SINGLE":
|
||
ranged_mode = RangedAttackMode.SINGLE
|
||
"SHOTGUN":
|
||
ranged_mode = RangedAttackMode.SHOTGUN
|
||
"BURST":
|
||
ranged_mode = RangedAttackMode.BURST
|
||
"GATLING":
|
||
ranged_mode = RangedAttackMode.GATLING
|
||
"PIERCING":
|
||
ranged_mode = RangedAttackMode.PIERCING
|
||
if ranged_attack.has("子弹速度"):
|
||
projectile_speed = ranged_attack["子弹速度"]
|
||
|
||
# 散弹攻击
|
||
if config.has("散弹攻击"):
|
||
var shotgun_attack = config["散弹攻击"]
|
||
if shotgun_attack.has("散弹数量"):
|
||
shotgun_bullets = shotgun_attack["散弹数量"]
|
||
if shotgun_attack.has("散弹扩散角度"):
|
||
shotgun_spread_angle = shotgun_attack["散弹扩散角度"]
|
||
|
||
# 多发射击
|
||
if config.has("多发射击"):
|
||
var burst_attack = config["多发射击"]
|
||
if burst_attack.has("多发射击行数"):
|
||
burst_rows = burst_attack["多发射击行数"]
|
||
if burst_attack.has("多发射击列数"):
|
||
burst_cols = burst_attack["多发射击列数"]
|
||
if burst_attack.has("多发射击间距"):
|
||
burst_spacing = burst_attack["多发射击间距"]
|
||
|
||
# 加特林属性
|
||
if config.has("加特林属性"):
|
||
var gatling_attr = config["加特林属性"]
|
||
if gatling_attr.has("加特林子弹数量"):
|
||
gatling_bullets = gatling_attr["加特林子弹数量"]
|
||
if gatling_attr.has("加特林射击间隔"):
|
||
gatling_interval = gatling_attr["加特林射击间隔"]
|
||
if gatling_attr.has("加特林冷却时间"):
|
||
gatling_cooldown = gatling_attr["加特林冷却时间"]
|
||
|
||
# 穿透属性
|
||
if config.has("穿透属性"):
|
||
var pierce_attr = config["穿透属性"]
|
||
if pierce_attr.has("穿透数量"):
|
||
pierce_count = pierce_attr["穿透数量"]
|
||
|
||
# 移动与闪避
|
||
if config.has("移动与闪避"):
|
||
var move_dodge = config["移动与闪避"]
|
||
if move_dodge.has("移动速度"):
|
||
move_speed = move_dodge["移动速度"]
|
||
if move_dodge.has("闪避率"):
|
||
dodge_rate = move_dodge["闪避率"]
|
||
if move_dodge.has("击退力度"):
|
||
knockback_force = move_dodge["击退力度"]
|
||
if move_dodge.has("击退抗性"):
|
||
knockback_resist = move_dodge["击退抗性"]
|
||
|
||
# 元素属性
|
||
if config.has("元素属性"):
|
||
var element_attr = config["元素属性"]
|
||
if element_attr.has("元素类型"):
|
||
var element_type_str = element_attr["元素类型"]
|
||
match element_type_str:
|
||
"NONE":
|
||
element_type = ElementType.NONE
|
||
"METAL":
|
||
element_type = ElementType.METAL
|
||
"WOOD":
|
||
element_type = ElementType.WOOD
|
||
"WATER":
|
||
element_type = ElementType.WATER
|
||
"FIRE":
|
||
element_type = ElementType.FIRE
|
||
"EARTH":
|
||
element_type = ElementType.EARTH
|
||
"THUNDER":
|
||
element_type = ElementType.THUNDER
|
||
if element_attr.has("元素克制额外伤害"):
|
||
element_damage_bonus = element_attr["元素克制额外伤害"]
|
||
|
||
# 特殊属性
|
||
if config.has("特殊属性"):
|
||
var special_attr = config["特殊属性"]
|
||
if special_attr.has("控制抗性"):
|
||
control_resist = special_attr["控制抗性"]
|
||
if special_attr.has("伤害反弹"):
|
||
damage_reflect = special_attr["伤害反弹"]
|
||
if special_attr.has("死亡免疫"):
|
||
death_immunity = special_attr["死亡免疫"]
|
||
if special_attr.has("狂暴阈值"):
|
||
berserker_threshold = special_attr["狂暴阈值"]
|
||
if special_attr.has("狂暴状态伤害倍数"):
|
||
berserker_bonus = special_attr["狂暴状态伤害倍数"]
|
||
|
||
# 特殊机制开关
|
||
if config.has("特殊机制开关"):
|
||
var special_toggle = config["特殊机制开关"]
|
||
if special_toggle.has("启用伤害反弹机制"):
|
||
enable_damage_reflect = special_toggle["启用伤害反弹机制"]
|
||
if special_toggle.has("启用狂暴模式机制"):
|
||
enable_berserker_mode = special_toggle["启用狂暴模式机制"]
|
||
if special_toggle.has("启用死亡免疫机制"):
|
||
enable_death_immunity = special_toggle["启用死亡免疫机制"]
|
||
if special_toggle.has("启用援助召唤机制"):
|
||
enable_aid_system = special_toggle["启用援助召唤机制"]
|
||
if special_toggle.has("启用死亡重生机制"):
|
||
enable_resurrection = special_toggle["启用死亡重生机制"]
|
||
|
||
# 援助系统
|
||
if config.has("援助系统"):
|
||
var aid_system = config["援助系统"]
|
||
if aid_system.has("援助触发阈值"):
|
||
aid_threshold = aid_system["援助触发阈值"]
|
||
if aid_system.has("援助召唤数量"):
|
||
aid_summon_count = aid_system["援助召唤数量"]
|
||
if aid_system.has("援助召唤间隔"):
|
||
aid_summon_interval = aid_system["援助召唤间隔"]
|
||
|
||
# 品质系统
|
||
if config.has("品质系统"):
|
||
var quality_system = config["品质系统"]
|
||
if quality_system.has("宠物品质"):
|
||
var quality_str = quality_system["宠物品质"]
|
||
match quality_str:
|
||
"COMMON":
|
||
pet_quality = PetQuality.COMMON
|
||
"UNCOMMON":
|
||
pet_quality = PetQuality.UNCOMMON
|
||
"RARE":
|
||
pet_quality = PetQuality.RARE
|
||
"EPIC":
|
||
pet_quality = PetQuality.EPIC
|
||
"LEGENDARY":
|
||
pet_quality = PetQuality.LEGENDARY
|
||
"MYTHIC":
|
||
pet_quality = PetQuality.MYTHIC
|
||
|
||
|
||
|
||
func _ready():
|
||
# 初始化生日
|
||
initialize_birthday()
|
||
|
||
# 保存原始颜色
|
||
if pet_image:
|
||
original_modulate = pet_image.modulate
|
||
|
||
# 延迟初始化UI显示,确保所有节点都已准备好
|
||
call_deferred("update_ui")
|
||
|
||
# 设置初始动画为空闲状态
|
||
if pet_image:
|
||
pet_image.animation = "idle"
|
||
|
||
# 获取队伍节点引用
|
||
call_deferred("setup_team_references")
|
||
|
||
# 延迟设置碰撞层,确保队伍信息已设置
|
||
call_deferred("setup_collision_layers")
|
||
|
||
# 设置宠物类型并加载对应配置
|
||
func set_pet_type_and_load_config(pet_type_name: String):
|
||
pet_type = pet_type_name
|
||
load_pet_config_from_json()
|
||
|
||
# 设置队伍节点引用
|
||
func setup_team_references():
|
||
var battle_panel = get_parent()
|
||
while battle_panel and not battle_panel.has_method("get_team_node"):
|
||
battle_panel = battle_panel.get_parent()
|
||
|
||
if battle_panel:
|
||
team_nodes["team1"] = battle_panel.get_node_or_null("team1")
|
||
team_nodes["team2"] = battle_panel.get_node_or_null("team2")
|
||
team_nodes["neutral"] = battle_panel.get_node_or_null("neutral")
|
||
|
||
# 设置碰撞层,让队友之间不碰撞
|
||
func setup_collision_layers():
|
||
# 简化的碰撞层设计:
|
||
# 第1位(值1):team1宠物
|
||
# 第2位(值2):team2宠物
|
||
# 第3位(值4):中立宠物
|
||
|
||
match pet_team:
|
||
"team1":
|
||
collision_layer = 1 # 第1位
|
||
collision_mask = 2 # 只检测team2
|
||
"team2":
|
||
collision_layer = 2 # 第2位
|
||
collision_mask = 1 # 只检测team1
|
||
"neutral":
|
||
collision_layer = 4 # 第3位
|
||
collision_mask = 3 # 检测team1和team2
|
||
_:
|
||
# 默认设置为team1
|
||
collision_layer = 1
|
||
collision_mask = 2
|
||
|
||
#限制宠物在战斗区域内
|
||
func clamp_to_battle_area():
|
||
var battle_area_min = Vector2(0,0)
|
||
var battle_area_max = Vector2(1400, 720)
|
||
|
||
# 限制位置
|
||
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
|
||
|
||
# 处理生命和护盾恢复
|
||
if not should_skip_frame:
|
||
handle_regeneration(delta)
|
||
|
||
# 更新年龄和亲密度(低优先级,可跳帧)
|
||
if not should_skip_frame:
|
||
update_age_and_intimacy(delta)
|
||
|
||
# 检查狂暴状态
|
||
if not should_skip_frame:
|
||
check_berserker_mode()
|
||
|
||
# 检查援助系统(低优先级,可跳帧)
|
||
if not should_skip_frame:
|
||
check_aid_system()
|
||
|
||
# 如果被眩晕则不能行动
|
||
if is_stunned:
|
||
return
|
||
|
||
# 定期检查目标状态(性能模式下降低检查频率)
|
||
var current_time = Time.get_ticks_msec() / 1000.0
|
||
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
|
||
|
||
# 更新AI状态机
|
||
update_ai_state(delta)
|
||
|
||
# 处理移动
|
||
handle_movement(delta)
|
||
|
||
# 处理攻击
|
||
handle_attack(delta)
|
||
|
||
# 应用移动
|
||
move_and_slide()
|
||
|
||
# 限制在战斗区域内
|
||
clamp_to_battle_area()
|
||
|
||
#宠物AI状态机
|
||
func update_ai_state(delta):
|
||
match current_state:
|
||
PetState.IDLE:
|
||
# 播放空闲动画
|
||
if pet_image.animation != "idle":
|
||
pet_image.animation = "idle"
|
||
|
||
# 只有启用战斗时才寻找敌人
|
||
if combat_enabled:
|
||
find_nearest_enemy()
|
||
if current_target and is_instance_valid(current_target):
|
||
current_state = PetState.MOVING_TO_TARGET
|
||
|
||
PetState.MOVING_TO_TARGET:
|
||
# 播放行走动画
|
||
if pet_image.animation != "walk":
|
||
pet_image.animation = "walk"
|
||
|
||
if not current_target or not is_instance_valid(current_target):
|
||
current_state = PetState.IDLE
|
||
else:
|
||
var distance_to_target = global_position.distance_to(current_target.global_position)
|
||
if distance_to_target <= attack_range:
|
||
# 进入攻击范围开始攻击
|
||
current_state = PetState.ATTACKING
|
||
|
||
PetState.ATTACKING:
|
||
# 攻击时播放空闲动画(或者你可以添加攻击动画)
|
||
if pet_image.animation != "idle":
|
||
pet_image.animation = "idle"
|
||
|
||
if not current_target or not is_instance_valid(current_target):
|
||
current_state = PetState.IDLE
|
||
else:
|
||
var distance_to_target = global_position.distance_to(current_target.global_position)
|
||
if distance_to_target > attack_range * 1.2:
|
||
# 目标超出射程,继续追击
|
||
current_state = PetState.MOVING_TO_TARGET
|
||
|
||
#宠物移动
|
||
func handle_movement(delta):
|
||
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()
|
||
|
||
# 根据攻击类型调整移动策略
|
||
if attack_type == AttackType.MELEE:
|
||
# 近战:直接冲向目标
|
||
velocity = direction * move_speed
|
||
else:
|
||
# 远程:保持适当距离
|
||
var optimal_distance = attack_range * 0.8 # 保持在80%射程距离
|
||
if distance_to_target > optimal_distance:
|
||
# 太远了,靠近一点
|
||
velocity = direction * move_speed
|
||
elif distance_to_target < optimal_distance * 0.6:
|
||
# 太近了,后退一点
|
||
velocity = -direction * move_speed * 0.5
|
||
else:
|
||
# 距离合适,停止移动
|
||
velocity = Vector2.ZERO
|
||
|
||
# 翻转精灵朝向
|
||
if direction.x < 0:
|
||
pet_image.flip_h = false
|
||
pet_tool_image.flip_h = true
|
||
pet_tool_image.position.x = -10
|
||
elif direction.x > 0:
|
||
pet_image.flip_h = true
|
||
pet_tool_image.flip_h = false
|
||
pet_tool_image.position.x = 10
|
||
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 # 转换为秒
|
||
|
||
# 处理加特林连射
|
||
if ranged_mode == RangedAttackMode.GATLING:
|
||
handle_gatling_attack(current_time, delta)
|
||
else:
|
||
# 普通攻击频率控制(确保最小攻击间隔)
|
||
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
|
||
|
||
# 处理加特林攻击
|
||
func handle_gatling_attack(current_time: float, delta: float):
|
||
if gatling_firing:
|
||
# 正在连射
|
||
if current_time - gatling_last_shot >= gatling_interval:
|
||
fire_projectile_by_mode(current_target)
|
||
gatling_current_bullet += 1
|
||
gatling_last_shot = current_time
|
||
|
||
if gatling_current_bullet >= gatling_bullets:
|
||
# 连射完毕,进入冷却
|
||
gatling_firing = false
|
||
gatling_current_bullet = 0
|
||
last_attack_time = current_time + gatling_cooldown
|
||
print(pet_name + " 加特林连射完毕,进入冷却")
|
||
else:
|
||
# 检查是否可以开始新的连射
|
||
if current_time - last_attack_time >= 1.0 / attack_speed:
|
||
gatling_firing = true
|
||
gatling_current_bullet = 0
|
||
gatling_last_shot = current_time - gatling_interval # 立即开始第一发
|
||
print(pet_name + " 开始加特林连射!")
|
||
|
||
#寻找最近的敌人
|
||
func find_nearest_enemy():
|
||
var nearest_enemy: CharacterBody2D = null
|
||
var nearest_distance: float = INF
|
||
|
||
# 获取所有存活的敌方宠物
|
||
var all_enemies: Array[CharacterBody2D] = []
|
||
|
||
# 直接从pets组中查找敌人(更可靠的方法)
|
||
var all_pets = get_tree().get_nodes_in_group("pets")
|
||
for pet in all_pets:
|
||
if not is_instance_valid(pet) or pet == self or not pet.is_alive:
|
||
continue
|
||
|
||
# 检查是否为敌人
|
||
if pet.has_method("get_team") and pet.get_team() != pet_team:
|
||
all_enemies.append(pet)
|
||
|
||
# 如果没有敌人,清除目标
|
||
if all_enemies.is_empty():
|
||
if current_target:
|
||
current_target = null
|
||
return
|
||
|
||
# 寻找最近的敌人
|
||
for enemy in all_enemies:
|
||
var distance = global_position.distance_to(enemy.global_position)
|
||
if distance < nearest_distance:
|
||
nearest_distance = distance
|
||
nearest_enemy = enemy
|
||
|
||
# 更新目标(只有在没有目标或目标已死亡时才更换)
|
||
if not current_target or not is_instance_valid(current_target) or not current_target.is_alive:
|
||
if nearest_enemy != current_target:
|
||
current_target = nearest_enemy
|
||
|
||
# 检查目标有效性
|
||
func check_target_validity():
|
||
if current_target:
|
||
# 检查目标是否还存活且有效
|
||
if not is_instance_valid(current_target) or not current_target.is_alive:
|
||
current_target = null
|
||
current_state = PetState.IDLE
|
||
# 检查目标是否还是敌人(防止队伍变更等情况)
|
||
elif current_target.get_team() == pet_team:
|
||
current_target = null
|
||
current_state = PetState.IDLE
|
||
|
||
#宠物攻击
|
||
func perform_attack(target: CharacterBody2D):
|
||
if not target or not is_instance_valid(target) or not target.is_alive:
|
||
# 目标无效或已死亡,重新寻找目标
|
||
current_target = null
|
||
current_state = PetState.IDLE
|
||
return
|
||
|
||
# 根据攻击类型执行不同的攻击方式
|
||
if attack_type == AttackType.MELEE:
|
||
perform_melee_attack(target)
|
||
else:
|
||
fire_projectile_by_mode(target)
|
||
|
||
# 执行近战攻击
|
||
func perform_melee_attack(target: CharacterBody2D):
|
||
# 计算基础伤害 + 近战额外伤害
|
||
var damage = attack_damage + melee_damage_bonus
|
||
|
||
# 狂暴状态加成
|
||
if is_berserker:
|
||
damage *= berserker_bonus
|
||
|
||
# 护甲穿透计算
|
||
var final_armor_penetration = armor_penetration
|
||
|
||
# 暴击计算
|
||
var is_critical = randf() < crit_rate
|
||
if is_critical:
|
||
damage *= crit_damage
|
||
|
||
# 添加战斗细节
|
||
add_battle_detail_to_panel("⚔️ " + pet_name + " 对 " + target.pet_name + " 造成近战攻击 " + str(int(damage)) + " 点伤害" + ("(暴击)" if is_critical else ""))
|
||
|
||
# 对目标造成伤害
|
||
target.take_damage(damage, final_armor_penetration, element_type, self)
|
||
|
||
# 生命汲取
|
||
if life_steal > 0:
|
||
var heal_amount = damage * life_steal
|
||
heal(heal_amount)
|
||
|
||
# 击退效果已禁用
|
||
# if knockback_force > 0:
|
||
# apply_knockback_to_target(target)
|
||
|
||
# 根据攻击模式发射子弹
|
||
func fire_projectile_by_mode(target: CharacterBody2D):
|
||
# 计算基础伤害 + 远程额外伤害
|
||
var damage = attack_damage + ranged_damage_bonus
|
||
|
||
# 狂暴状态加成
|
||
if is_berserker:
|
||
damage *= berserker_bonus
|
||
|
||
# 护甲穿透计算
|
||
var final_armor_penetration = armor_penetration
|
||
|
||
# 暴击计算
|
||
var is_critical = randf() < crit_rate
|
||
if is_critical:
|
||
damage *= crit_damage
|
||
|
||
# 根据远程攻击模式执行不同的射击方式
|
||
match ranged_mode:
|
||
RangedAttackMode.SINGLE:
|
||
fire_single_projectile(target, damage, final_armor_penetration, is_critical)
|
||
RangedAttackMode.SHOTGUN:
|
||
fire_shotgun_projectiles(target, damage, final_armor_penetration, is_critical)
|
||
RangedAttackMode.BURST:
|
||
fire_burst_projectiles(target, damage, final_armor_penetration, is_critical)
|
||
RangedAttackMode.GATLING:
|
||
fire_single_projectile(target, damage, final_armor_penetration, is_critical) # 加特林也是单发,但频率高
|
||
RangedAttackMode.PIERCING:
|
||
fire_piercing_projectile(target, damage, final_armor_penetration, is_critical)
|
||
|
||
# 发射单发子弹
|
||
func fire_single_projectile(target: CharacterBody2D, damage: float, armor_pen: float, is_critical: bool):
|
||
add_battle_detail_to_panel("🏹 " + pet_name + " 向 " + target.pet_name + " 发射单发子弹 " + str(int(damage)) + " 点伤害" + ("(暴击)" if is_critical else ""))
|
||
create_and_fire_projectile(global_position, target.global_position, damage, armor_pen, is_critical, 1)
|
||
|
||
# 发射散弹
|
||
func fire_shotgun_projectiles(target: CharacterBody2D, damage: float, armor_pen: float, is_critical: bool):
|
||
var base_direction = (target.global_position - global_position).normalized()
|
||
var base_angle = atan2(base_direction.y, base_direction.x)
|
||
|
||
# 计算每发子弹的角度偏移
|
||
var angle_step = deg_to_rad(shotgun_spread_angle) / (shotgun_bullets - 1)
|
||
var start_angle = base_angle - deg_to_rad(shotgun_spread_angle) / 2
|
||
|
||
for i in range(shotgun_bullets):
|
||
var bullet_angle = start_angle + i * angle_step
|
||
var bullet_direction = Vector2(cos(bullet_angle), sin(bullet_angle))
|
||
var target_pos = global_position + bullet_direction * attack_range
|
||
|
||
create_and_fire_projectile(global_position, target_pos, damage * 0.7, armor_pen, is_critical, 1) # 散弹伤害降低
|
||
|
||
# 发射多发射击(平行)
|
||
func fire_burst_projectiles(target: CharacterBody2D, damage: float, armor_pen: float, is_critical: bool):
|
||
var base_direction = (target.global_position - global_position).normalized()
|
||
var perpendicular = Vector2(-base_direction.y, base_direction.x) # 垂直方向
|
||
|
||
# 计算起始位置偏移
|
||
var total_width = (burst_cols - 1) * burst_spacing
|
||
var total_height = (burst_rows - 1) * burst_spacing
|
||
|
||
for row in range(burst_rows):
|
||
for col in range(burst_cols):
|
||
var offset_x = (col - (burst_cols - 1) * 0.5) * burst_spacing
|
||
var offset_y = (row - (burst_rows - 1) * 0.5) * burst_spacing
|
||
|
||
var start_pos = global_position + perpendicular * offset_x + base_direction.rotated(PI/2) * offset_y
|
||
var target_pos = target.global_position + perpendicular * offset_x + base_direction.rotated(PI/2) * offset_y
|
||
|
||
create_and_fire_projectile(start_pos, target_pos, damage * 0.8, armor_pen, is_critical, 1) # 多发伤害稍微降低
|
||
|
||
# 发射穿透子弹
|
||
func fire_piercing_projectile(target: CharacterBody2D, damage: float, armor_pen: float, is_critical: bool):
|
||
create_and_fire_projectile(global_position, target.global_position, damage * 1.2, armor_pen, is_critical, pierce_count) # 穿透子弹伤害更高
|
||
|
||
# 创建并发射子弹的通用函数
|
||
func create_and_fire_projectile(start_pos: Vector2, target_pos: Vector2, damage: float, armor_pen: float, is_critical: bool, pierce: int = 1):
|
||
# 直接创建新子弹
|
||
if not projectile_scene:
|
||
print("错误:没有设置子弹场景!")
|
||
return
|
||
|
||
var projectile: Area2D = projectile_scene.instantiate()
|
||
if not projectile:
|
||
print("错误:无法创建子弹实例")
|
||
return
|
||
|
||
# 将子弹添加到战斗场景中
|
||
if get_tree():
|
||
var battle_scene = get_tree().current_scene
|
||
if battle_scene.has_node("PetFightPanel"):
|
||
battle_scene.get_node("PetFightPanel").add_child(projectile)
|
||
else:
|
||
get_tree().current_scene.add_child(projectile)
|
||
else:
|
||
# 如果场景树不存在,直接销毁子弹
|
||
projectile.queue_free()
|
||
return
|
||
|
||
# 设置子弹位置
|
||
projectile.global_position = start_pos
|
||
|
||
# 计算射击方向
|
||
var direction = (target_pos - start_pos).normalized()
|
||
|
||
# 设置子弹数据
|
||
projectile.set_projectile_data(damage, projectile_speed, direction, pet_team, element_type, armor_pen, pierce, self)
|
||
|
||
# 设置子弹颜色
|
||
if projectile.has_node("ProjectileSprite"):
|
||
if is_critical:
|
||
projectile.get_node("ProjectileSprite").modulate = Color.RED # 暴击红色
|
||
elif pierce > 1:
|
||
projectile.get_node("ProjectileSprite").modulate = Color.PURPLE # 穿透紫色
|
||
else:
|
||
# 根据攻击模式设置不同颜色
|
||
match ranged_mode:
|
||
RangedAttackMode.SINGLE:
|
||
projectile.get_node("ProjectileSprite").modulate = Color.YELLOW
|
||
RangedAttackMode.SHOTGUN:
|
||
projectile.get_node("ProjectileSprite").modulate = Color.ORANGE
|
||
RangedAttackMode.BURST:
|
||
projectile.get_node("ProjectileSprite").modulate = Color.CYAN
|
||
RangedAttackMode.GATLING:
|
||
projectile.get_node("ProjectileSprite").modulate = Color.GREEN
|
||
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
|
||
|
||
# 元素克制计算 - 额外伤害
|
||
var element_extra_damage = get_element_multiplier(attacker_element, element_type)
|
||
actual_damage += element_extra_damage
|
||
|
||
# 护甲减伤计算(考虑护甲穿透)
|
||
var effective_armor = max(0, current_armor - armor_pen)
|
||
if effective_armor > 0:
|
||
var armor_reduction = effective_armor / (effective_armor + 100.0)
|
||
actual_damage = actual_damage * (1.0 - armor_reduction)
|
||
|
||
# 先扣护盾
|
||
if current_shield > 0:
|
||
var shield_damage = min(actual_damage, current_shield)
|
||
current_shield -= shield_damage
|
||
actual_damage -= shield_damage
|
||
|
||
# 再扣血量
|
||
if actual_damage > 0:
|
||
current_health -= actual_damage
|
||
|
||
# 播放受伤动画(带冷却保护)
|
||
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)) + ")"
|
||
add_battle_detail_to_panel(damage_text, Color.ORANGE)
|
||
|
||
# 记录最后攻击者
|
||
if attacker and is_instance_valid(attacker):
|
||
last_attacker = attacker
|
||
|
||
# 反击机制:立即将攻击者设为目标(只有启用战斗时才反击)
|
||
# 添加反击冷却,防止过于频繁的目标切换
|
||
if combat_enabled and attacker and is_instance_valid(attacker) and attacker.is_alive:
|
||
if attacker.get_team() != pet_team: # 确保不攻击队友
|
||
# 只有当前没有目标或当前目标已死亡时才切换目标
|
||
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) 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:
|
||
if enable_death_immunity and death_immunity:
|
||
current_health = 1.0
|
||
death_immunity = false
|
||
is_invulnerable = true
|
||
# 设置短暂无敌时间
|
||
if get_tree():
|
||
var timer = get_tree().create_timer(2.0)
|
||
timer.timeout.connect(func(): is_invulnerable = false)
|
||
else:
|
||
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: # 如果已经在死亡过程中,直接返回
|
||
return
|
||
|
||
# 检查重生机制
|
||
if enable_resurrection and not resurrection_used:
|
||
resurrection_used = true
|
||
add_battle_detail_to_panel("💀 " + pet_name + " 死亡,但触发重生机制!", Color.GOLD)
|
||
resurrect()
|
||
return
|
||
|
||
is_dying = true # 设置死亡标志
|
||
is_alive = false
|
||
current_state = PetState.DEAD
|
||
|
||
# 添加死亡细节
|
||
var death_message = "💀 " + pet_name + " 死亡了!"
|
||
if last_attacker and is_instance_valid(last_attacker):
|
||
death_message += " (被 " + last_attacker.pet_name + " 击杀)"
|
||
add_battle_detail_to_panel(death_message, Color.RED)
|
||
|
||
# 给击杀者奖励
|
||
if last_attacker and is_instance_valid(last_attacker) and last_attacker.has_method("on_kill_enemy"):
|
||
last_attacker.on_kill_enemy(self)
|
||
|
||
# 通知其他宠物这个目标已死亡,让它们重新寻找目标
|
||
if get_tree(): # 确保场景树存在
|
||
var all_pets = get_tree().get_nodes_in_group("pets")
|
||
for pet in all_pets:
|
||
if pet != self and is_instance_valid(pet) and pet.has_method("on_enemy_died"):
|
||
pet.on_enemy_died(self)
|
||
|
||
# 立即通知战斗面板检查战斗结束
|
||
var battle_panel = get_parent()
|
||
while battle_panel and not battle_panel.has_method("check_battle_end"):
|
||
battle_panel = battle_panel.get_parent()
|
||
|
||
if battle_panel:
|
||
battle_panel.call_deferred("check_battle_end")
|
||
|
||
# 延迟0.5秒后移除自己,避免在物理回调中操作
|
||
if get_tree():
|
||
await get_tree().create_timer(0.5).timeout
|
||
if get_parent():
|
||
get_parent().remove_child(self)
|
||
queue_free()
|
||
else:
|
||
# 如果场景树不存在,直接销毁
|
||
queue_free()
|
||
|
||
# 重生机制
|
||
func resurrect():
|
||
# 恢复生命值到50%
|
||
current_health = max_health * 0.5
|
||
current_shield = max_shield * 0.5
|
||
current_armor = max_armor * 0.5
|
||
|
||
# 设置短暂无敌状态
|
||
is_invulnerable = true
|
||
is_dying = false
|
||
is_alive = true
|
||
current_state = PetState.IDLE
|
||
|
||
# 清除目标,重新开始
|
||
current_target = null
|
||
|
||
# 重生特效(变为金色闪烁)
|
||
var original_modulate = pet_image.modulate
|
||
pet_image.modulate = Color.GOLD
|
||
|
||
# 3秒后恢复正常状态
|
||
if get_tree():
|
||
var timer = get_tree().create_timer(3.0)
|
||
timer.timeout.connect(func():
|
||
is_invulnerable = false
|
||
pet_image.modulate = original_modulate
|
||
)
|
||
|
||
call_deferred("update_ui")
|
||
|
||
# 显示启用的特殊机制
|
||
func show_enabled_special_abilities():
|
||
var abilities: Array[String] = []
|
||
|
||
if enable_damage_reflect:
|
||
abilities.append("伤害反弹(" + str(int(damage_reflect * 100)) + "%)")
|
||
if enable_berserker_mode:
|
||
abilities.append("狂暴模式(" + str(int(berserker_threshold * 100)) + "%血量触发)")
|
||
if enable_death_immunity:
|
||
abilities.append("死亡免疫")
|
||
if enable_aid_system:
|
||
abilities.append("援助召唤(x" + str(aid_summon_count) + ")")
|
||
if enable_resurrection:
|
||
abilities.append("死亡重生")
|
||
|
||
# 可以在这里添加UI显示特殊能力的逻辑,暂时注释掉print
|
||
# if abilities.size() > 0:
|
||
# print(pet_name + " 启用特殊机制: " + ", ".join(abilities))
|
||
# else:
|
||
# print(pet_name + " 无特殊机制")
|
||
|
||
#更新宠物状态UI
|
||
func update_ui():
|
||
# 检查UI节点是否存在,防止援助宠物或未完全初始化的宠物出错
|
||
if not health_bar or not shield_bar or not armor_bar or not health_label or not shield_label or not armor_label or not pet_name_rich_text:
|
||
return
|
||
|
||
# 更新血量条
|
||
health_bar.max_value = max_health
|
||
health_bar.value = current_health
|
||
health_label.text = "生命值:" + str(int(current_health)) + "/" + str(int(max_health))
|
||
|
||
# 更新护盾条
|
||
shield_bar.max_value = max_shield
|
||
shield_bar.value = current_shield
|
||
shield_label.text = "护盾值:" + str(int(current_shield)) + "/" + str(int(max_shield))
|
||
|
||
# 更新护甲条
|
||
armor_bar.max_value = max_armor
|
||
armor_bar.value = current_armor
|
||
armor_label.text = "护甲值:" + str(int(current_armor)) + "/" + str(int(max_armor))
|
||
|
||
# 更新名称(包含等级、经验、亲密度信息)
|
||
var display_name = pet_name + " [Lv." + str(pet_level) + "]"
|
||
display_name += "\n经验:" + str(int(pet_experience)) + "/" + str(int(max_experience))
|
||
display_name += "\n亲密度:" + str(int(pet_intimacy)) + "/" + str(int(max_intimacy))
|
||
if pet_age > 0:
|
||
display_name += "\n年龄:" + get_age_display()
|
||
pet_name_rich_text.text = display_name
|
||
|
||
# 获取友好的年龄显示
|
||
func get_age_display() -> String:
|
||
if pet_age == 0:
|
||
return "新生"
|
||
elif pet_age < 7:
|
||
return str(pet_age) + "天"
|
||
elif pet_age < 30:
|
||
var weeks = pet_age / 7
|
||
return str(weeks) + "周"
|
||
elif pet_age < 365:
|
||
var months = pet_age / 30
|
||
return str(months) + "个月"
|
||
else:
|
||
var years = pet_age / 365
|
||
var remaining_days = pet_age % 365
|
||
if remaining_days > 0:
|
||
return str(years) + "年" + str(remaining_days) + "天"
|
||
else:
|
||
return str(years) + "年"
|
||
|
||
# 添加战斗细节到对战面板
|
||
func add_battle_detail_to_panel(text: String, color: Color = Color.WHITE):
|
||
# 查找战斗面板
|
||
var battle_panel = find_battle_panel()
|
||
if battle_panel and battle_panel.has_method("add_battle_detail"):
|
||
battle_panel.add_battle_detail(text, color)
|
||
|
||
# 查找战斗面板
|
||
func find_battle_panel():
|
||
var current_scene = get_tree().current_scene
|
||
if current_scene.has_node("PetFightPanel"):
|
||
return current_scene.get_node("PetFightPanel")
|
||
else:
|
||
# 遍历所有子节点查找
|
||
var queue = [current_scene]
|
||
while queue.size() > 0:
|
||
var node = queue.pop_front()
|
||
if node.name == "PetFightPanel":
|
||
return node
|
||
for child in node.get_children():
|
||
queue.append(child)
|
||
return null
|
||
|
||
#设置宠物数据
|
||
func set_pet_data(name: String, team: String, health: float = 100.0, attack: float = 20.0, speed: float = 100.0, quality: PetQuality = PetQuality.COMMON, element: ElementType = ElementType.NONE):
|
||
pet_name = name
|
||
pet_team = team
|
||
max_health = health
|
||
current_health = health
|
||
attack_damage = attack
|
||
move_speed = speed
|
||
pet_quality = quality
|
||
element_type = element
|
||
|
||
# 根据品质调整属性
|
||
apply_quality_bonuses()
|
||
|
||
# 更新攻击速度
|
||
update_attack_speed()
|
||
|
||
# 设置碰撞层(现在team信息已确定)
|
||
setup_collision_layers()
|
||
|
||
# 显示启用的特殊机制
|
||
call_deferred("show_enabled_special_abilities")
|
||
|
||
call_deferred("update_ui")
|
||
|
||
# 更新攻击速度(根据当前攻击类型)
|
||
func update_attack_speed():
|
||
if attack_type == AttackType.MELEE:
|
||
attack_speed = melee_attack_speed
|
||
else:
|
||
attack_speed = ranged_attack_speed
|
||
|
||
# 根据品质应用属性加成
|
||
func apply_quality_bonuses():
|
||
var quality_multiplier = 1.0
|
||
match pet_quality:
|
||
PetQuality.COMMON:
|
||
quality_multiplier = 1.0
|
||
PetQuality.UNCOMMON:
|
||
quality_multiplier = 1.1
|
||
PetQuality.RARE:
|
||
quality_multiplier = 1.25
|
||
PetQuality.EPIC:
|
||
quality_multiplier = 1.5
|
||
PetQuality.LEGENDARY:
|
||
quality_multiplier = 1.75
|
||
PetQuality.MYTHIC:
|
||
quality_multiplier = 2.0
|
||
|
||
# 应用品质加成到基础属性
|
||
max_health *= quality_multiplier
|
||
current_health = max_health
|
||
max_shield *= quality_multiplier
|
||
current_shield = max_shield
|
||
max_armor *= quality_multiplier
|
||
current_armor = max_armor
|
||
attack_damage *= quality_multiplier
|
||
|
||
# 高品质宠物获得额外属性
|
||
if pet_quality >= PetQuality.RARE:
|
||
crit_rate += 0.05
|
||
life_steal += 0.05
|
||
enable_berserker_mode = true # 稀有品质启用狂暴模式
|
||
if pet_quality >= PetQuality.EPIC:
|
||
armor_penetration += 10.0
|
||
health_regen += 1.0
|
||
enable_damage_reflect = true # 史诗品质启用伤害反弹
|
||
damage_reflect += 0.1
|
||
if pet_quality >= PetQuality.LEGENDARY:
|
||
knockback_resist += 0.2
|
||
enable_aid_system = true # 传说品质启用援助系统
|
||
enable_death_immunity = true # 传说品质启用死亡免疫
|
||
death_immunity = true
|
||
if pet_quality >= PetQuality.MYTHIC:
|
||
berserker_bonus += 0.5
|
||
enable_resurrection = true # 神话品质启用重生机制
|
||
|
||
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
|
||
if current_time - last_regen_time >= 1.0: # 每秒恢复一次
|
||
# 生命恢复
|
||
if current_health < max_health and health_regen > 0:
|
||
current_health = min(max_health, current_health + health_regen)
|
||
|
||
# 护盾恢复
|
||
if current_shield < max_shield and shield_regen > 0:
|
||
current_shield = min(max_shield, current_shield + shield_regen)
|
||
|
||
last_regen_time = current_time
|
||
call_deferred("update_ui")
|
||
|
||
# 更新亲密度
|
||
var intimacy_timer: float = 0.0
|
||
|
||
func update_age_and_intimacy(delta: float):
|
||
# 更新年龄(基于出生日期和现实时间)
|
||
update_pet_age()
|
||
|
||
# 每10秒增加1点亲密度(战斗中会增加更多)
|
||
intimacy_timer += delta
|
||
if intimacy_timer >= 10.0:
|
||
gain_intimacy(1.0)
|
||
intimacy_timer = 0.0
|
||
|
||
# 根据出生日期计算宠物年龄
|
||
func update_pet_age():
|
||
if pet_birthday == "":
|
||
return
|
||
|
||
# 解析出生日期
|
||
var birth_parts = pet_birthday.split(" ")
|
||
if birth_parts.size() != 2:
|
||
return
|
||
|
||
var date_parts = birth_parts[0].split("-")
|
||
var time_parts = birth_parts[1].split(":")
|
||
|
||
if date_parts.size() != 3 or time_parts.size() != 3:
|
||
return
|
||
|
||
# 获取当前时间
|
||
var current_time = Time.get_datetime_dict_from_system()
|
||
|
||
# 计算出生时间
|
||
var birth_year = int(date_parts[0])
|
||
var birth_month = int(date_parts[1])
|
||
var birth_day = int(date_parts[2])
|
||
var birth_hour = int(time_parts[0])
|
||
var birth_minute = int(time_parts[1])
|
||
var birth_second = int(time_parts[2])
|
||
|
||
# 创建出生时间的Unix时间戳
|
||
var birth_dict = {
|
||
"year": birth_year,
|
||
"month": birth_month,
|
||
"day": birth_day,
|
||
"hour": birth_hour,
|
||
"minute": birth_minute,
|
||
"second": birth_second
|
||
}
|
||
|
||
var birth_unix = Time.get_unix_time_from_datetime_dict(birth_dict)
|
||
var current_unix = Time.get_unix_time_from_system()
|
||
|
||
# 计算年龄(秒差转换为天数)
|
||
var age_seconds = current_unix - birth_unix
|
||
pet_age = int(age_seconds / 86400) # 86400秒 = 1天
|
||
|
||
if pet_age < 0:
|
||
pet_age = 0 # 防止负数年龄
|
||
|
||
# 增加亲密度
|
||
func gain_intimacy(amount: float):
|
||
if pet_intimacy < max_intimacy:
|
||
pet_intimacy = min(max_intimacy, pet_intimacy + amount)
|
||
|
||
# 每100点亲密度提供属性加成
|
||
var intimacy_level = int(pet_intimacy / 100.0)
|
||
if intimacy_level > 0:
|
||
# 亲密度加成:每100点提供5%属性加成
|
||
var intimacy_bonus = 1.0 + (intimacy_level * 0.05)
|
||
# 这里可以应用到各种属性上,暂时先输出提示
|
||
if int(pet_intimacy) % 100 == 0:
|
||
pass
|
||
|
||
# 增加经验值
|
||
func gain_experience(amount: float):
|
||
if pet_level >= 50: # 等级上限
|
||
return
|
||
|
||
pet_experience += amount
|
||
|
||
# 检查是否升级
|
||
while pet_experience >= max_experience and pet_level < 50:
|
||
level_up()
|
||
|
||
# 升级(新的随机属性系统)
|
||
func level_up():
|
||
pet_experience -= max_experience
|
||
pet_level += 1
|
||
|
||
# 计算新的升级经验需求(指数增长)
|
||
max_experience = 100.0 * pow(1.2, pet_level - 1)
|
||
|
||
# 随机选择属性进行升级
|
||
var upgraded_attributes = apply_random_attribute_upgrade()
|
||
|
||
# 检查是否有里程碑奖励(每5级)
|
||
var milestone_rewards = apply_milestone_bonus()
|
||
|
||
# 升级回血和护盾护甲
|
||
current_health = max_health
|
||
current_shield = max_shield
|
||
current_armor = max_armor
|
||
|
||
# 升级特效
|
||
show_level_up_effect()
|
||
|
||
# 添加升级细节
|
||
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:
|
||
return
|
||
|
||
# 保存原始颜色
|
||
var original_color = pet_image.modulate
|
||
|
||
# 创建升级特效(金色闪烁)
|
||
var tween = create_tween()
|
||
tween.set_loops(3) # 闪烁3次
|
||
|
||
# 闪烁效果
|
||
tween.tween_method(func(color): pet_image.modulate = color, original_color, Color.GOLD, 0.2)
|
||
tween.tween_method(func(color): pet_image.modulate = color, Color.GOLD, original_color, 0.2)
|
||
|
||
# 恢复原始颜色
|
||
tween.tween_callback(func(): pet_image.modulate = original_color)
|
||
|
||
# 击杀敌人时获得额外经验
|
||
func on_kill_enemy(enemy: CharacterBody2D):
|
||
var kill_exp = enemy.pet_level * 20.0 # 根据敌人等级获得经验
|
||
gain_experience(kill_exp)
|
||
gain_intimacy(10.0) # 击杀获得更多亲密度
|
||
|
||
# 初始化生日
|
||
func initialize_birthday():
|
||
if pet_birthday == "":
|
||
var time_dict = Time.get_datetime_dict_from_system()
|
||
pet_birthday = str(time_dict.year) + "-" + str(time_dict.month).pad_zeros(2) + "-" + str(time_dict.day).pad_zeros(2) + " " + str(time_dict.hour).pad_zeros(2) + ":" + str(time_dict.minute).pad_zeros(2) + ":" + str(time_dict.second).pad_zeros(2)
|
||
|
||
# 检查狂暴模式
|
||
func check_berserker_mode():
|
||
if not enable_berserker_mode:
|
||
return
|
||
|
||
var health_ratio = current_health / max_health
|
||
if health_ratio <= berserker_threshold and not is_berserker:
|
||
is_berserker = true
|
||
pet_image.modulate = Color.RED # 狂暴状态变红色
|
||
add_battle_detail_to_panel("🔥 " + pet_name + " 血量过低,进入狂暴模式!", Color.RED)
|
||
elif health_ratio > berserker_threshold and is_berserker:
|
||
is_berserker = false
|
||
add_battle_detail_to_panel("😌 " + pet_name + " 脱离狂暴模式", Color.GREEN)
|
||
# 恢复原来的队伍颜色
|
||
if pet_team == "team1":
|
||
pet_image.modulate = Color.CYAN
|
||
else:
|
||
pet_image.modulate = Color.ORANGE
|
||
|
||
# 检查援助系统
|
||
func check_aid_system():
|
||
if not enable_aid_system:
|
||
return
|
||
|
||
var health_ratio = current_health / max_health
|
||
var current_time = Time.get_ticks_msec() / 1000.0
|
||
|
||
# 如果血量低于阈值且还没召唤过援助,或者距离上次召唤已经超过间隔时间
|
||
if health_ratio <= aid_threshold:
|
||
if not aid_summoned or (current_time - aid_last_summon_time >= aid_summon_interval):
|
||
summon_aid()
|
||
aid_last_summon_time = current_time
|
||
aid_summoned = true
|
||
|
||
# 召唤援助
|
||
func summon_aid():
|
||
# 获取战斗面板引用
|
||
var battle_panel = get_parent()
|
||
while battle_panel and not battle_panel.has_method("get_team_node"):
|
||
battle_panel = battle_panel.get_parent()
|
||
|
||
if not battle_panel:
|
||
return
|
||
|
||
var team_node = battle_panel.get_team_node(pet_team)
|
||
if not team_node:
|
||
return
|
||
|
||
# 召唤多个援助宠物
|
||
for i in range(aid_summon_count):
|
||
var aid_pet = create_aid_minion()
|
||
if aid_pet:
|
||
team_node.add_child(aid_pet)
|
||
aid_minions.append(aid_pet)
|
||
|
||
# 设置援助宠物位置(在主宠物周围)
|
||
var offset_angle = (PI * 2 / aid_summon_count) * i
|
||
var offset_distance = 80.0
|
||
var offset = Vector2(cos(offset_angle), sin(offset_angle)) * offset_distance
|
||
aid_pet.global_position = global_position + offset
|
||
|
||
# 添加到宠物组
|
||
aid_pet.add_to_group("pets")
|
||
aid_pet.add_to_group(pet_team)
|
||
aid_pet.add_to_group("aid_minions")
|
||
|
||
# 创建援助宠物
|
||
func create_aid_minion() -> CharacterBody2D:
|
||
# 使用相同的宠物场景
|
||
var pet_scene = preload("res://Scene/Pet/PetBase.tscn")
|
||
var aid_pet = pet_scene.instantiate()
|
||
|
||
# 设置援助宠物属性(比主宠物弱一些)
|
||
var aid_name = pet_name + "的援助"
|
||
var aid_health = max_health * 0.3 # 30%血量
|
||
var aid_attack = attack_damage * 0.5 # 50%攻击力
|
||
var aid_speed = move_speed * 1.2 # 120%移动速度
|
||
|
||
aid_pet.set_pet_data(aid_name, pet_team, aid_health, aid_attack, aid_speed, PetQuality.COMMON, element_type)
|
||
|
||
# 援助宠物使用简单的远程攻击
|
||
aid_pet.attack_type = AttackType.RANGED
|
||
aid_pet.ranged_mode = RangedAttackMode.SINGLE
|
||
aid_pet.attack_range = 250.0
|
||
|
||
# 设置援助宠物的特殊标识(小一点,颜色稍微不同)
|
||
aid_pet.scale = Vector2(0.7, 0.7) # 缩小到70%
|
||
if aid_pet.pet_image:
|
||
aid_pet.pet_image.modulate = aid_pet.pet_image.modulate * Color(1.0, 1.0, 1.0, 0.8) # 半透明
|
||
|
||
# 隐藏援助宠物的UI面板,减少性能开销
|
||
if aid_pet.has_node("PetInformVBox"):
|
||
aid_pet.get_node("PetInformVBox").visible = false
|
||
|
||
return aid_pet
|
||
|
||
# 治疗函数
|
||
func heal(amount: float):
|
||
if not is_alive:
|
||
return
|
||
current_health = min(max_health, current_health + amount)
|
||
call_deferred("update_ui")
|
||
|
||
# 击退效果已禁用
|
||
func apply_knockback_to_target(target: CharacterBody2D):
|
||
# 击退功能暂时禁用
|
||
pass
|
||
|
||
# 击退效果已禁用
|
||
func apply_knockback(direction: Vector2, force: float):
|
||
# 击退功能暂时禁用
|
||
pass
|
||
|
||
# 将位置限制在战斗区域内
|
||
func clamp_position_to_battle_area(pos: Vector2) -> Vector2:
|
||
var battle_area_min = Vector2(50, 50)
|
||
var battle_area_max = Vector2(1350, 670)
|
||
|
||
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:
|
||
# 如果攻击者无属性,返回正常伤害
|
||
if attacker_element == ElementType.NONE:
|
||
return 0.0 # 无额外伤害
|
||
|
||
# 雷属性克制所有其他属性
|
||
if attacker_element == ElementType.THUNDER and defender_element != ElementType.NONE:
|
||
return element_damage_bonus # 雷克制所有
|
||
|
||
# 如果防御者无属性,无克制关系
|
||
if defender_element == ElementType.NONE:
|
||
return 0.0
|
||
|
||
# 五行克制:金克木,木克水,水克火,火克土,土克金
|
||
match attacker_element:
|
||
ElementType.METAL:
|
||
if defender_element == ElementType.WOOD:
|
||
return element_damage_bonus # 金克木
|
||
ElementType.WOOD:
|
||
if defender_element == ElementType.WATER:
|
||
return element_damage_bonus # 木克水
|
||
ElementType.WATER:
|
||
if defender_element == ElementType.FIRE:
|
||
return element_damage_bonus # 水克火
|
||
ElementType.FIRE:
|
||
if defender_element == ElementType.EARTH:
|
||
return element_damage_bonus # 火克土
|
||
ElementType.EARTH:
|
||
if defender_element == ElementType.METAL:
|
||
return element_damage_bonus # 土克金
|
||
|
||
return 0.0 # 无克制关系,无额外伤害
|
||
|
||
# 当敌人死亡时被调用
|
||
func on_enemy_died(dead_enemy: CharacterBody2D):
|
||
if current_target == dead_enemy:
|
||
current_target = null
|
||
current_state = PetState.IDLE
|
||
|
||
# 处理巡逻逻辑
|
||
func handle_patrol(delta: float):
|
||
if patrol_path.size() == 0:
|
||
return
|
||
|
||
# 确保当前巡逻索引有效
|
||
if current_patrol_index >= patrol_path.size():
|
||
current_patrol_index = 0
|
||
|
||
var target_point = patrol_path[current_patrol_index]
|
||
# 使用本地坐标进行计算(因为宠物现在在巡逻线节点下)
|
||
var distance_to_target = position.distance_to(target_point)
|
||
|
||
# 如果距离目标点很近,移动到下一个点
|
||
if distance_to_target < 30.0: # 增加检测距离,避免抖动
|
||
patrol_wait_time += delta
|
||
if patrol_wait_time >= patrol_max_wait_time:
|
||
current_patrol_index = (current_patrol_index + 1) % patrol_path.size()
|
||
patrol_wait_time = 0.0
|
||
|
||
# 在等待期间播放空闲动画
|
||
if pet_image and pet_image.animation != "idle":
|
||
pet_image.animation = "idle"
|
||
velocity = Vector2.ZERO
|
||
else:
|
||
# 移动到目标点
|
||
var direction = (target_point - position).normalized()
|
||
velocity = direction * patrol_speed
|
||
|
||
# 播放移动动画
|
||
if pet_image and pet_image.animation != "walk":
|
||
pet_image.animation = "walk"
|
||
|
||
# 根据移动方向翻转精灵
|
||
if direction.x < 0:
|
||
pet_image.flip_h = false
|
||
elif direction.x > 0:
|
||
pet_image.flip_h = true
|
||
|
||
patrol_wait_time = 0.0
|
||
|
||
# 应用移动
|
||
move_and_slide()
|
||
|
||
# 限制在巡逻区域内(使用本地坐标)
|
||
clamp_to_patrol_area()
|
||
|
||
# 设置战斗启用状态
|
||
func set_combat_enabled(enabled: bool):
|
||
combat_enabled = enabled
|
||
if not enabled:
|
||
# 禁用战斗时,清除当前目标
|
||
current_target = null
|
||
current_state = PetState.IDLE
|
||
|
||
# 限制巡逻宠物在合理的坐标范围内
|
||
func clamp_to_patrol_area():
|
||
# 基于巡逻路径计算合理的边界
|
||
if patrol_path.size() > 0:
|
||
var min_x = patrol_path[0].x
|
||
var max_x = patrol_path[0].x
|
||
var min_y = patrol_path[0].y
|
||
var max_y = patrol_path[0].y
|
||
|
||
# 找到路径的边界
|
||
for point in patrol_path:
|
||
min_x = min(min_x, point.x)
|
||
max_x = max(max_x, point.x)
|
||
min_y = min(min_y, point.y)
|
||
max_y = max(max_y, point.y)
|
||
|
||
# 添加一些缓冲区域
|
||
var buffer = 100.0
|
||
min_x -= buffer
|
||
max_x += buffer
|
||
min_y -= buffer
|
||
max_y += buffer
|
||
|
||
# 限制位置
|
||
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)
|