|  |  |  | 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(): | 
					
						
							|  |  |  | 	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 || 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_normal) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	#抖动 | 
					
						
							|  |  |  | 	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) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	#伤害跳字 | 
					
						
							|  |  |  | 	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) |