|  |  |  | extends Node3D | 
					
						
							|  |  |  | class_name Battle | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @export var hit_back_limit_curve: Curve | 
					
						
							|  |  |  | @export var pause_time_limit_curve: Curve | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | @onready var character: Character = (get_owner() as Character) | 
					
						
							|  |  |  | @onready var status: Status = (%Status as Status) | 
					
						
							|  |  |  | @onready var skill: Skill = (%Skill as Skill) | 
					
						
							|  |  |  | @onready var move: Move = (%Move as Move) | 
					
						
							|  |  |  | @onready var battle_attack_area: BattleAttackArea = (%BattleAttackArea as BattleAttackArea) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func attack1() -> void: | 
					
						
							|  |  |  | 	if not status.skill_cfg: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	var attack_info: Struct.AttackInfo = Struct.AttackInfo.new() | 
					
						
							|  |  |  | 	attack_info.attack = status.skill_cfg.attack1 | 
					
						
							|  |  |  | 	attack_info.attack_box = status.skill_cfg.attack1_box | 
					
						
							|  |  |  | 	attack_info.attack_dir = status.skill_dir | 
					
						
							|  |  |  | 	attack_info.with_stop = status.skill_cfg.attack1_with_stop | 
					
						
							|  |  |  | 	attack_info.ignore_push = status.skill_cfg.ignore_push | 
					
						
							|  |  |  | 	add_attack(attack_info) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func attack2() -> void: | 
					
						
							|  |  |  | 	if not status.skill_cfg: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	var attack_info: Struct.AttackInfo = Struct.AttackInfo.new() | 
					
						
							|  |  |  | 	attack_info.attack = status.skill_cfg.attack2 | 
					
						
							|  |  |  | 	attack_info.attack_box = status.skill_cfg.attack2_box | 
					
						
							|  |  |  | 	attack_info.attack_dir = status.skill_dir | 
					
						
							|  |  |  | 	attack_info.with_stop = status.skill_cfg.attack2_with_stop | 
					
						
							|  |  |  | 	attack_info.ignore_push = status.skill_cfg.ignore_push | 
					
						
							|  |  |  | 	add_attack(attack_info) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func character_attack1() -> void: | 
					
						
							|  |  |  | 	var attack_info: Struct.AttackInfo = Struct.AttackInfo.new() | 
					
						
							|  |  |  | 	attack_info.attack = status.cfg.attack1 | 
					
						
							|  |  |  | 	attack_info.attack_box = status.cfg.attack1_box | 
					
						
							|  |  |  | 	attack_info.attack_dir = status.move_dir | 
					
						
							|  |  |  | 	add_attack(attack_info) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func character_attack2() -> void: | 
					
						
							|  |  |  | 	var attack_info: Struct.AttackInfo = Struct.AttackInfo.new() | 
					
						
							|  |  |  | 	attack_info.attack = status.cfg.attack2 | 
					
						
							|  |  |  | 	attack_info.attack_box = status.cfg.attack2_box | 
					
						
							|  |  |  | 	attack_info.attack_dir = status.move_dir | 
					
						
							|  |  |  | 	add_attack(attack_info) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func add_attack(attack_info: Struct.AttackInfo) -> void: | 
					
						
							|  |  |  | 	if not attack_info.attack or not attack_info.attack_box: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	if character.has_buff("hit_ground_cd") and attack_info.attack == ResourceManager.cfg_attack_rebound: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	var result: Character | 
					
						
							|  |  |  | 	if attack_info.attack_box.is_throw: | 
					
						
							|  |  |  | 		var target: Character = Global.character_mgr.get_character(status.throw_target) | 
					
						
							|  |  |  | 		if target: | 
					
						
							|  |  |  | 			result = target | 
					
						
							|  |  |  | 	elif attack_info.attack_box.is_direct: | 
					
						
							|  |  |  | 		var target: Character = Global.character_mgr.get_character(status.target) | 
					
						
							|  |  |  | 		if target: | 
					
						
							|  |  |  | 			result = target | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 		battle_attack_area.refresh_attack_area(attack_info) | 
					
						
							|  |  |  | 		var offset_xz: Vector2 = attack_info.attack_dir * attack_info.attack_box.offset.x | 
					
						
							|  |  |  | 		var offset_y: float    = attack_info.attack_box.offset.y | 
					
						
							|  |  |  | 		var offset: Vector3    = Vector3(offset_xz.x, offset_y, offset_xz.y) | 
					
						
							|  |  |  | 		var shape: Shape3D     = attack_info.attack_box.shape | 
					
						
							|  |  |  | 		_debug_draw_attack_box(shape, offset) | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	on_attack_character(result, attack_info) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func _debug_draw_attack_box(shape: Shape3D, offset: Vector3) -> void: | 
					
						
							|  |  |  | 	if not get_tree().debug_collisions_hint: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	if shape is BoxShape3D: | 
					
						
							|  |  |  | 		var box_scale: Vector3 = shape.size | 
					
						
							|  |  |  | 		character.cast_particle(ResourceManager.particle_debug_box, false, offset, box_scale) | 
					
						
							|  |  |  | 	elif shape is CylinderShape3D: | 
					
						
							|  |  |  | 		var box_scale: Vector3 = Vector3(shape.radius, shape.height, shape.radius) | 
					
						
							|  |  |  | 		character.cast_particle(ResourceManager.particle_debug_cylinder, false, offset, box_scale) | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func on_attack_character(result: Character, attack_info: Struct.AttackInfo) -> void: | 
					
						
							|  |  |  | 	if not result: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	if attack_info.attack_box.is_hit_self != (result.team() == character.team()): | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	status.is_hit_character = true | 
					
						
							|  |  |  | 	var hit_result: Struct.HitResultInfo = settle(character.id(), result.id(), attack_info) | 
					
						
							|  |  |  | 	on_attack_hit(hit_result) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func settle(from: int, to: int, attack_info: Struct.AttackInfo) -> Struct.HitResultInfo: | 
					
						
							|  |  |  | 	var attack: AttackCfg                = attack_info.attack | 
					
						
							|  |  |  | 	var attack_dir: Vector2              = attack_info.attack_dir | 
					
						
							|  |  |  | 	var with_stop: bool                  = attack_info.with_stop | 
					
						
							|  |  |  | 	var ignore_push: bool                = attack_info.ignore_push | 
					
						
							|  |  |  | 	var hit_result: Struct.HitResultInfo = Struct.HitResultInfo.new() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var character_from: Character = Global.character_mgr.get_character(from) as Character | 
					
						
							|  |  |  | 	var character_to: Character   = Global.character_mgr.get_character(to) as Character | 
					
						
							|  |  |  | 	if !character_from or !character_to: | 
					
						
							|  |  |  | 		return hit_result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var cfg_from: CharacterCfg = character_from.cfg() | 
					
						
							|  |  |  | 	var cfg_to: CharacterCfg   = character_to.cfg() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var is_dead                = character_to.get_status("is_dead") | 
					
						
							|  |  |  | 	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: bool       = shield > 0 | 
					
						
							|  |  |  | 	var is_stagger: bool       = character_to.has_buff("stagger") | 
					
						
							|  |  |  | 	var is_on_floor: bool      = character_to.get_status("is_on_floor") | 
					
						
							|  |  |  | 	var is_self_on_floor: bool = character_from.get_status("is_on_floor") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var is_floating: bool = attack.is_floating or not is_on_floor | 
					
						
							|  |  |  | 	var is_rebound: bool  = attack.is_rebound and (character_from == character_to) | 
					
						
							|  |  |  | 	var is_bullet: bool   = int(character_from.cfg().type) == Enum.ECharacterType.Bullet | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var is_break_shield: bool     = false | 
					
						
							|  |  |  | 	var is_break_stun: bool       = false | 
					
						
							|  |  |  | 	var is_block: bool            = false | 
					
						
							|  |  |  | 	var is_kill: bool             = false | 
					
						
							|  |  |  | 	var is_break_skill: bool      = false | 
					
						
							|  |  |  | 	var is_break_skill_real: bool = false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#基本伤害 | 
					
						
							|  |  |  | 	var damage: float = attack.damage_rate * cfg_from.attack | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#硬直等级 | 
					
						
							|  |  |  | 	var break_level_def: int = character_to.get_break_level_def() | 
					
						
							|  |  |  | 	var break_level_sub: int = clampi(attack.break_level - break_level_def, -1, 4) | 
					
						
							|  |  |  | 	is_break_skill_real = break_level_sub > 0 | 
					
						
							|  |  |  | 	is_break_skill = is_break_skill_real or not is_on_floor | 
					
						
							|  |  |  | 	#硬直等级伤害修正 | 
					
						
							|  |  |  | 	if break_level_sub == -1: | 
					
						
							|  |  |  | 		damage = 0 | 
					
						
							|  |  |  | 	elif break_level_sub == 0: | 
					
						
							|  |  |  | 		damage *= 0.5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	is_floating = is_break_skill and is_floating | 
					
						
							|  |  |  | 	is_block = not is_break_skill | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#造成伤害 | 
					
						
							|  |  |  | 	if has_shield: | 
					
						
							|  |  |  | 		damage = min(shield, damage) | 
					
						
							|  |  |  | 		character_to.set_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>0) and (damage == hp) | 
					
						
							|  |  |  | 		if is_kill: | 
					
						
							|  |  |  | 			character_to.add_buff("die", 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#卡帧时间计算 | 
					
						
							|  |  |  | 	var pause_time: float | 
					
						
							|  |  |  | 	if is_break_skill: | 
					
						
							|  |  |  | 		var break_level_sum_rate: float | 
					
						
							|  |  |  | 		break_level_sum_rate = attack.break_level / 4.0 | 
					
						
							|  |  |  | 		pause_time = pause_time_limit_curve.sample(break_level_sum_rate) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#格挡 带盾破防 破盾以及击杀具有固定值 | 
					
						
							|  |  |  | 	if is_block: | 
					
						
							|  |  |  | 		pause_time = 0.05 | 
					
						
							|  |  |  | 		break_level_sub = 0 | 
					
						
							|  |  |  | 	elif has_shield and is_break_skill and not is_stagger: | 
					
						
							|  |  |  | 		pause_time = 0.1 | 
					
						
							|  |  |  | 		break_level_sub = 2 | 
					
						
							|  |  |  | 	elif is_break_shield: | 
					
						
							|  |  |  | 		pause_time = 0.2 | 
					
						
							|  |  |  | 		break_level_sub = 3 | 
					
						
							|  |  |  | 	elif is_kill: | 
					
						
							|  |  |  | 		pause_time = 0.3 | 
					
						
							|  |  |  | 		break_level_sub = 4 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	if not attack.damage_type == Enum.EDamageType.Blunt: | 
					
						
							|  |  |  | 		pause_time *= 0.6 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#眩晕值累加 | 
					
						
							|  |  |  | 	if not is_stun: | 
					
						
							|  |  |  | 		var stun_damage: float = 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累加 | 
					
						
							|  |  |  | 	if not is_bullet: | 
					
						
							|  |  |  | 		character_from.add_mp_sub(damage * cfg_from.mp.add_rate_attack, true) | 
					
						
							|  |  |  | 	character_to.add_mp_sub(damage * cfg_to.mp.add_rate_hit, true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#被动锁定目标转移 | 
					
						
							|  |  |  | 	if not status.is_lock and not is_dead and not is_bullet: | 
					
						
							|  |  |  | 		character_from.set_status("target", character_to.id()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#受击结束警戒 | 
					
						
							|  |  |  | 	character_to.set_status("ai_is_alert", true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#投技检测 | 
					
						
							|  |  |  | 	if is_break_skill and attack.is_throw_check and not character_to.get_status("is_be_throw") and status.throw_target == 0: | 
					
						
							|  |  |  | 		character_to.set_status("is_be_throw", true) | 
					
						
							|  |  |  | 		status.throw_target = character_to.id() | 
					
						
							|  |  |  | 		is_floating = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#投技结束 | 
					
						
							|  |  |  | 	if attack.is_throw_end: | 
					
						
							|  |  |  | 		character_to.set_status("is_be_throw", false) | 
					
						
							|  |  |  | 		status.throw_target = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#碰撞距离计算 | 
					
						
							|  |  |  | 	var character_dir: Vector2 = character_to.pos2D() - character_from.pos2D() | 
					
						
							|  |  |  | 	var dist: float            = character_dir.length() | 
					
						
							|  |  |  | 	var radius_sum: float      = character_from.radius() + character_to.radius() | 
					
						
							|  |  |  | 	var dist_rate: float       = clamp(dist / radius_sum, 0, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if is_break_skill: | 
					
						
							|  |  |  | 		#取消技能 | 
					
						
							|  |  |  | 		if character_to.get_status("is_skill_running"): | 
					
						
							|  |  |  | 			character_to.cancel_skill() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		#停止移动 | 
					
						
							|  |  |  | 		character_to.move_stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		#受击动画 | 
					
						
							|  |  |  | 		var trigger_hit: String = "" | 
					
						
							|  |  |  | 		if is_rebound: trigger_hit="rebound" | 
					
						
							|  |  |  | 		elif is_floating: trigger_hit = "air_hit_down" if attack.hit_up_speed<0 else "air_hit_up" | 
					
						
							|  |  |  | 		elif is_stun: trigger_hit="stun_hit" | 
					
						
							|  |  |  | 		elif break_level_sub == 4: trigger_hit="lhit" | 
					
						
							|  |  |  | 		elif break_level_sub == 3: trigger_hit="mhit" | 
					
						
							|  |  |  | 		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: float   = attack.hit_up_speed | 
					
						
							|  |  |  | 		var hit_back_speed: float = attack.hit_back_speed | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		#浮空 击落 强制位移 | 
					
						
							|  |  |  | 		if is_floating: | 
					
						
							|  |  |  | 			character_to.add_buff("stagger", -1) | 
					
						
							|  |  |  | 			character_to.add_buff("floating", -1) | 
					
						
							|  |  |  | 			if attack_dir.x!=0: | 
					
						
							|  |  |  | 				character_to.set_status("is_right", attack_dir.x<0) | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			match break_level_sub: | 
					
						
							|  |  |  | 				1: character_to.add_buff("stagger", 0.3) | 
					
						
							|  |  |  | 				2: character_to.add_buff("stagger", 0.6) | 
					
						
							|  |  |  | 				3: character_to.add_buff("stagger", 0.6) | 
					
						
							|  |  |  | 				4: character_to.add_buff("stagger", 0.9) | 
					
						
							|  |  |  | 			hit_up_speed = 0 | 
					
						
							|  |  |  | 			if hit_back_limit_curve: | 
					
						
							|  |  |  | 				hit_back_speed = max(hit_back_limit_curve.sample(dist_rate), hit_back_speed) | 
					
						
							|  |  |  | 		if not is_break_skill_real: | 
					
						
							|  |  |  | 			hit_up_speed *= 0.75 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		character_to.set_hit_move(attack_dir, 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) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#停止自身位移 | 
					
						
							|  |  |  | 	if not is_bullet: | 
					
						
							|  |  |  | 		#character_from.move_tick(pause_time) | 
					
						
							|  |  |  | 		if with_stop: | 
					
						
							|  |  |  | 			character_from.move_stop() | 
					
						
							|  |  |  | 			character_from.set_status("skill_move_stop", true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#攻击到不可移动的物体 造成自身后退 | 
					
						
							|  |  |  | 	var is_against_wall: bool = character_to.move_tick(pause_time) | 
					
						
							|  |  |  | 	if is_self_on_floor and not is_bullet and not ignore_push and (is_against_wall or not is_break_skill): | 
					
						
							|  |  |  | 		var self_hit_back_speed = max(hit_back_limit_curve.sample(dist_rate), 2) | 
					
						
							|  |  |  | 		character_from.move_stop() | 
					
						
							|  |  |  | 		character_from.set_status("skill_move_stop", true) | 
					
						
							|  |  |  | 		character_from.set_hit_move(-attack_dir, self_hit_back_speed, 0) | 
					
						
							|  |  |  | 		character_from.add_buff("hit_back", attack.hit_up_duration) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#受击pt掉落 | 
					
						
							|  |  |  | 	if damage>0: | 
					
						
							|  |  |  | 		if is_kill || is_break_shield: | 
					
						
							|  |  |  | 			Global.item_mgr.create_pt(Enum.EPtType.MP, Setting.pt_mp_break_or_kill, character_to.pos()) | 
					
						
							|  |  |  | 			Global.item_mgr.create_pt(Enum.EPtType.HP, Setting.pt_hp_break_or_kill, character_to.pos()) | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			Global.item_mgr.create_pt(Enum.EPtType.MP, damage * Setting.pt_mp_damage_rate, character_to.pos()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#受击特效 | 
					
						
							|  |  |  | 	if not attack.is_throw_end: | 
					
						
							|  |  |  | 		var particle_hit: PackedScene | 
					
						
							|  |  |  | 		match attack.damage_type: | 
					
						
							|  |  |  | 			Enum.EDamageType.Sharp: | 
					
						
							|  |  |  | 				match break_level_sub: | 
					
						
							|  |  |  | 					-1: particle_hit = ResourceManager.particle_hit_sharp_block | 
					
						
							|  |  |  | 					0: particle_hit = ResourceManager.particle_hit_sharp_block | 
					
						
							|  |  |  | 					1: particle_hit = ResourceManager.particle_hit_sharp_normal | 
					
						
							|  |  |  | 					2: particle_hit = ResourceManager.particle_hit_sharp_mid | 
					
						
							|  |  |  | 					3: particle_hit = ResourceManager.particle_hit_sharp_heavy | 
					
						
							|  |  |  | 					4: particle_hit = ResourceManager.particle_hit_sharp_heavy | 
					
						
							|  |  |  | 			Enum.EDamageType.Blunt: | 
					
						
							|  |  |  | 				match break_level_sub: | 
					
						
							|  |  |  | 					-1: particle_hit = ResourceManager.particle_hit_blunt_block | 
					
						
							|  |  |  | 					0: particle_hit = ResourceManager.particle_hit_blunt_block | 
					
						
							|  |  |  | 					1: particle_hit = ResourceManager.particle_hit_blunt_normal | 
					
						
							|  |  |  | 					2: particle_hit = ResourceManager.particle_hit_blunt_mid | 
					
						
							|  |  |  | 					3: particle_hit = ResourceManager.particle_hit_blunt_heavy | 
					
						
							|  |  |  | 					4: particle_hit = ResourceManager.particle_hit_blunt_heavy | 
					
						
							|  |  |  | 			_: pass | 
					
						
							|  |  |  | 		if particle_hit: | 
					
						
							|  |  |  | 			character_to.cast_particle(particle_hit, false) | 
					
						
							|  |  |  | 	#受击通用特效 | 
					
						
							|  |  |  | 	character_to.cast_particle(ResourceManager.particle_hit_common, false) | 
					
						
							|  |  |  | 	#受击材质特效 | 
					
						
							|  |  |  | 	if damage > 0: | 
					
						
							|  |  |  | 		var material: Enum.EMaterial = cfg_to.material_on if has_shield else cfg_to.material_off | 
					
						
							|  |  |  | 		match material: | 
					
						
							|  |  |  | 			Enum.EMaterial.Cloth: character_to.cast_particle(ResourceManager.particle_material_cloth, false) | 
					
						
							|  |  |  | 			_: pass | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#抖动 | 
					
						
							|  |  |  | 	if is_block: | 
					
						
							|  |  |  | 		character_from.add_buff("shake_x", 0.2, true) | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 		character_to.add_buff("shake_x", 0.2, true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#闪白 | 
					
						
							|  |  |  | 	character_to.add_buff("flash_white", 0.04) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#卡帧 | 
					
						
							|  |  |  | 	if not is_bullet: | 
					
						
							|  |  |  | 		character_from.set_pause_time(pause_time) | 
					
						
							|  |  |  | 		character_to.set_pause_time(pause_time) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	#全局特效 | 
					
						
							|  |  |  | 	var has_global_effect: bool = character_from.is_player() or character_to.is_player() | 
					
						
							|  |  |  | 	if has_global_effect: | 
					
						
							|  |  |  | 		Global.camera_mgr.effect(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") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hit_result.is_break = is_break_skill | 
					
						
							|  |  |  | 	return hit_result | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func add_hp(value: float) -> void: | 
					
						
							|  |  |  | 	if status.is_dead: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	var hp     = character.get_status("hp") | 
					
						
							|  |  |  | 	var hp_max = character.get_status("hp_max") | 
					
						
							|  |  |  | 	character.set_status("hp", min(hp_max, hp+value)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func add_mp_sub(value: float, from_battle: bool): | 
					
						
							|  |  |  | 	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) | 
					
						
							|  |  |  | 	var mp_sub_full = value == mp_sub_max-mp_sub | 
					
						
							|  |  |  | 	var mp_full     = mp == mp_max | 
					
						
							|  |  |  | 	if mp_sub_full: | 
					
						
							|  |  |  | 		#mp_sub已满 | 
					
						
							|  |  |  | 		if mp_full: | 
					
						
							|  |  |  | 			#mp已满 | 
					
						
							|  |  |  | 			character.set_status("mp_sub", mp_sub_max) | 
					
						
							|  |  |  | 			character.remove_buff("mp_recover_cd") | 
					
						
							|  |  |  | 			character.remove_buff("mp_recover") | 
					
						
							|  |  |  | 		else: | 
					
						
							|  |  |  | 			#mp未满 | 
					
						
							|  |  |  | 			character.set_status("mp", mp+1) | 
					
						
							|  |  |  | 			character.set_status("mp_sub", 0) | 
					
						
							|  |  |  | 	else: | 
					
						
							|  |  |  | 		character.set_status("mp_sub", max(mp_sub+value, 0)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if from_battle: | 
					
						
							|  |  |  | 		character.remove_buff("mp_recover") | 
					
						
							|  |  |  | 		character.add_buff("mp_recover_cd", status.cfg.mp.recover_cd) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func cost_mp(value: int): | 
					
						
							|  |  |  | 	var mp     = character.get_status("mp") | 
					
						
							|  |  |  | 	var mp_max = character.get_status("mp_max") | 
					
						
							|  |  |  | 	var mp_new = mp-value | 
					
						
							|  |  |  | 	mp_new = min(mp_new, mp_max) | 
					
						
							|  |  |  | 	mp_new = max(mp_new, 0) | 
					
						
							|  |  |  | 	character.set_status("mp", mp_new) | 
					
						
							|  |  |  | 	character.remove_buff("mp_recover") | 
					
						
							|  |  |  | 	character.add_buff("mp_recover_cd", status.cfg.mp.recover_cd) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func cost_mp_sub(): | 
					
						
							|  |  |  | 	character.set_status("mp_sub", 0) | 
					
						
							|  |  |  | 	character.remove_buff("mp_recover") | 
					
						
							|  |  |  | 	character.add_buff("mp_recover_cd", status.cfg.mp.recover_cd) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func check_ground(): skill.on_check_ground(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func check_ground1(): skill.on_check_ground(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func check_ground2(): skill.on_check_ground(2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func check_charging1(): skill.on_check_charging(1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func check_charging2(): skill.on_check_charging(2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func check_charging3(): skill.on_check_charging(3) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func cast_sub_character(): skill.on_cast_sub_character() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func hold(): skill.on_hold() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func stop(): | 
					
						
							|  |  |  | 	move.stop() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func change_dir() -> void: | 
					
						
							|  |  |  | 	var cast_dir: Vector2 = status.move_dir | 
					
						
							|  |  |  | 	var target: Character = Global.character_mgr.get_character(status.target) | 
					
						
							|  |  |  | 	if target: | 
					
						
							|  |  |  | 		cast_dir = target.pos2D() - character.pos2D() | 
					
						
							|  |  |  | 	status.skill_dir = cast_dir.normalized() | 
					
						
							|  |  |  | 	status.is_right = cast_dir.x > 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func on_attack_hit(hit_result: Struct.HitResultInfo) -> void: | 
					
						
							|  |  |  | 	if not status.skill_cfg: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	var skill_name: String = status.skill_cfg.get_res_name() | 
					
						
							|  |  |  | 	on_skill_trigger(skill_name, "hit") | 
					
						
							|  |  |  | 	if hit_result.is_break: | 
					
						
							|  |  |  | 		on_skill_trigger(skill_name, "hit_break") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func on_skill_release(skill_name: String) -> void: | 
					
						
							|  |  |  | 	on_skill_trigger(skill_name, "release") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func on_skill_cast(skill_name: String) -> void: | 
					
						
							|  |  |  | 	on_skill_trigger(skill_name, "cast") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func on_skill_trigger(skill_name: String, trigger_name: String) -> void: | 
					
						
							|  |  |  | 	var func_name: String = "on_%s_%s" % [skill_name, trigger_name] | 
					
						
							|  |  |  | 	if has_method(func_name): | 
					
						
							|  |  |  | 		call(func_name) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #====skill_trigger==== | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func on_hero01_long_stab01_cast(): | 
					
						
							|  |  |  | 	if status.skill_repeat_count >= 5: | 
					
						
							|  |  |  | 		skill.cast_skill_by_name("hero01_long_stab02", status.move_dir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func on_hero01_fist_skill01_hit_break(): | 
					
						
							|  |  |  | 	var target: int = status.throw_target | 
					
						
							|  |  |  | 	skill.cast_skill_by_name("hero01_fist_skill01_add", status.move_dir) | 
					
						
							|  |  |  | 	status.throw_target = target | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func on_hero01_fist_air_skill_charging_hit(): | 
					
						
							|  |  |  | 	status.stance = Enum.EStance.SpecialFist | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func on_hero01_fist_skill_charging_release(): | 
					
						
							|  |  |  | 	match status.charging_level: | 
					
						
							|  |  |  | 		0: skill.cast_skill_by_name("hero01_fist_skill_charging01", status.move_dir) | 
					
						
							|  |  |  | 		_: skill.cast_skill_by_name("hero01_fist_skill_charging02", status.move_dir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func on_hero01_soul_slash_cast(): | 
					
						
							|  |  |  | 	if not status.sub_character_id: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	var sub_char: Character = Global.character_mgr.get_character(status.sub_character_id) | 
					
						
							|  |  |  | 	if not sub_char: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	sub_char.set_pos(character.pos()) | 
					
						
							|  |  |  | 	var skill_cfg = skill.get_skill_by_name("hero01_long_skill01") | 
					
						
							|  |  |  | 	if not skill_cfg: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	sub_char.cast_skill(skill_cfg, status.skill_move_dir) |