extends Node3D class_name Battle @onready var character = (get_owner() as Character) @onready var status = (%Status as Status) @onready var skill = (%Skill as Skill) class HitInfo: var from : int var to : int var dir : Vector2 var attack : AttackCfg func attack(): call_deferred("_attack") func _attack(): if !status.skill_cfg: return var attack = status.skill_cfg.get_attack(status.skill_attack_index) as AttackCfg status.skill_attack_index += 1 var enemy_list = Global.character_mgr.get_enemy_list(character.id()) var pos = character.pos() var attack_dir = status.skill_dir.normalized() var attack_height = attack.height var attack_size = Util.grid_vector2(attack.size) var attack_radius = attack.radius var offset_xz = attack_dir * Util.grid_float(attack.offset.x) pos += Vector3(offset_xz.x,Util.grid_float(attack.offset.y),offset_xz.y) var is_stuck = false for enemy in enemy_list: var target_pos = enemy.pos() var target_radius = enemy.radius() var target_height = enemy.height() if Util.attack_detection(pos,target_pos,target_radius,target_height,attack_dir,attack_height,attack_size,attack_radius): var hit_info = HitInfo.new() hit_info.from = character.id() hit_info.to = enemy.id() hit_info.dir = attack_dir hit_info.attack = attack is_stuck = is_stuck or settle(hit_info) if !is_stuck and !attack.is_force_pause: skill.on_attack_miss() func add_attack(from:int,dir:Vector2,attack:AttackCfg): var hit_info = HitInfo.new() hit_info.from = from hit_info.to = character.id() hit_info.dir = dir hit_info.attack = attack settle(hit_info) func settle(hit_info:HitInfo) -> bool: var character_from = Global.character_mgr.get_character(hit_info.from) as Character var character_to = Global.character_mgr.get_character(hit_info.to) as Character if !character_from or !character_to: return false var cfg_from = character_from.cfg() var cfg_to = character_to.cfg() var is_stun = character_to.get_status("is_stun") var hp = character_to.get_status("hp") var shield = character_to.get_status("shield") var has_shield = shield > 0 var attack = hit_info.attack var is_floating = attack.is_floating or not character_to.get_status("is_on_floor") var is_hit_down = attack.is_hit_down var is_rebound = attack.is_rebound var is_break_shield = false var is_break_stun = false var is_block = false var is_kill = false var is_break_skill = false #造成伤害 var damage = attack.damage_rate * cfg_from.attack if has_shield: damage = min(shield,damage) character_to.set_status("shield",shield-damage) is_break_shield = damage == shield if is_break_shield: character_to.remove_buff("shield_recover_cd") character_to.remove_buff("shield_recover") has_shield = false else: character_to.remove_buff("shield_recover") character_to.add_buff("shield_recover_cd",cfg_to.shield.recover_cd) else: damage = min(hp,damage) character_to.set_status("hp",hp-damage) is_kill = damage == hp if is_kill: character_to.add_buff("die",1) #眩晕值累加 if not is_stun: var stun_damage = attack.stun_attack var stun = character_to.get_status("stun") var stun_max = character_to.get_status("stun_max") stun_damage = min(stun_max-stun,stun_damage) character_to.set_status("stun",stun+stun_damage) is_break_stun = stun_damage == stun_max-stun if is_break_stun: is_stun = true character_to.set_status("is_stun",true) character_to.remove_buff("stun_recover_cd") character_to.remove_buff("stun_recover") character_to.add_buff("stun_recover_break_cd",cfg_to.stun.recover_break_cd) else: character_to.remove_buff("stun_recover") character_to.add_buff("stun_recover_cd",cfg_to.stun.recover_cd) #mp累加 character_from.add_mp(damage * cfg_from.mp.add_rate_attack) character_from.remove_buff("mp_recover") character_from.add_buff("mp_recover_cd",status.cfg.mp.recover_cd) character_to.add_mp(damage * cfg_to.mp.add_rate_hit) character_to.remove_buff("mp_recover") character_to.add_buff("mp_recover_cd",status.cfg.mp.recover_cd) #硬直等级 var break_level_def = cfg_to.shield.break_level_on if has_shield else cfg_to.shield.break_level_off var break_level_sub = clampi(attack.break_level - break_level_def,0,3) is_break_skill = break_level_sub > 0 if is_break_skill: #取消技能 if character_to.get_status("is_skill_running"): character_to.cancel_skill() #停止移动 character_to.move_stop() #受击动画 var trigger_hit = "" if is_rebound: trigger_hit="rebound" elif is_floating: trigger_hit = "air_hit_down" if is_hit_down else "air_hit_up" elif is_stun: trigger_hit="stun_hit" elif break_level_sub == 3: trigger_hit="lhit" elif break_level_sub == 2: trigger_hit="mhit" elif break_level_sub == 1: trigger_hit="hit" character_to.set_view_trigger(trigger_hit) #浮空 击落 强制位移 var hit_up_speed = attack.hit_up_speed if is_floating: character_to.add_buff("stagger",-1) character_to.add_buff("floating",-1) if hit_info.dir.x!=0: character_to.set_status("is_right",hit_info.dir.x<0) else: character_to.add_buff("stagger",1) hit_up_speed = 0 if is_hit_down: character_to.add_buff("hit_down",-1) character_to.set_hit_move(hit_info.dir,attack.hit_back_speed,hit_up_speed) character_to.add_buff("hit_back",attack.hit_back_duration) character_to.add_buff("hit_up",attack.hit_up_duration) #受击特效 character_to.cast_particle(ResourceManager.particle_hit) #抖动 character_to.add_buff("shake_x",0.2,true) #闪白 character_to.add_buff("flash_white",0.1) #卡帧 character_from.add_buff("pause",attack.pause_time) character_to.add_buff("pause",attack.pause_time) #全局特效 Global.camera_mgr.effect(attack.pause_time) #伤害跳字 character_to.show_hit_damage(damage) #状态跳字 if is_break_shield:character_to.show_hit_text("Break") elif is_break_stun:character_to.show_hit_text("Stun") elif not is_break_skill:character_to.show_hit_text("Block") return !is_break_skill func add_mp(value:float): var mp = character.get_status("mp") var mp_max = character.get_status("mp_max") var mp_sub = character.get_status("mp_sub") var mp_sub_max = character.get_status("mp_sub_max") value = min(mp_sub_max-mp_sub,value) if value == mp_sub_max-mp_sub: var mp_add = min(mp_max-mp,1) if mp_add > 0: character.set_status("mp",mp+mp_add) character.set_status("mp_sub",0) else: character.set_status("mp_sub",mp_sub_max) character.remove_buff("mp_recover_cd") character.remove_buff("mp_recover") else: character.set_status("mp_sub",mp_sub+value) func check_ground(): skill.on_check_ground()