178 lines
7.5 KiB
GDScript
178 lines
7.5 KiB
GDScript
extends Node
|
|
|
|
func _ready() -> void:
|
|
EventBus.ability_use_requested.connect(_on_ability_use_requested)
|
|
|
|
func _process(_delta: float) -> void:
|
|
var players := get_tree().get_nodes_in_group("player")
|
|
for player in players:
|
|
if not Stats.is_alive(player):
|
|
continue
|
|
_try_auto_attack(player)
|
|
|
|
func _try_auto_attack(player: Node) -> void:
|
|
var targeting: Node = player.get_node_or_null("Targeting")
|
|
if not targeting or not targeting.in_combat or not targeting.current_target:
|
|
return
|
|
if not is_instance_valid(targeting.current_target):
|
|
return
|
|
var cooldown_system: Node = get_node("../CooldownSystem")
|
|
if not cooldown_system.is_aa_ready(player):
|
|
return
|
|
var role: Node = player.get_node("Role")
|
|
var ability_set: AbilitySet = role.get_ability_set()
|
|
if not ability_set:
|
|
return
|
|
var aa_damage: float = ability_set.aa_damage
|
|
var aa_range: float = ability_set.aa_range
|
|
var aa_is_heal: bool = ability_set.aa_is_heal
|
|
var dmg: float = _apply_passive(player, aa_damage, "heal" if aa_is_heal else "damage")
|
|
if aa_is_heal:
|
|
EventBus.heal_requested.emit(player, player, dmg)
|
|
else:
|
|
var dist: float = player.global_position.distance_to(targeting.current_target.global_position)
|
|
if dist > aa_range:
|
|
return
|
|
EventBus.damage_requested.emit(player, targeting.current_target, dmg)
|
|
var player_base: BaseStats = Stats.get_base(player)
|
|
var aa_cd: float = player_base.aa_cooldown if player_base is PlayerStats else 0.5
|
|
cooldown_system.set_aa_cooldown(player, aa_cd)
|
|
|
|
func _on_ability_use_requested(player: Node, ability_index: int) -> void:
|
|
var role: Node = player.get_node_or_null("Role")
|
|
if not role:
|
|
return
|
|
var ability_set: AbilitySet = role.get_ability_set()
|
|
if not ability_set or ability_index >= ability_set.abilities.size():
|
|
return
|
|
var ability: Ability = ability_set.abilities[ability_index]
|
|
if not ability or ability.type == Ability.Type.PASSIVE:
|
|
return
|
|
var cooldown_system: Node = get_node("../CooldownSystem")
|
|
if not cooldown_system.is_ready(player, ability_index):
|
|
return
|
|
if ability.uses_gcd and not cooldown_system.is_gcd_ready(player):
|
|
return
|
|
var success: bool = _execute_ability(player, ability)
|
|
if not success:
|
|
return
|
|
var player_base: BaseStats = Stats.get_base(player)
|
|
var gcd_time: float = player_base.gcd_time if player_base is PlayerStats else 0.5
|
|
var gcd: float = gcd_time if ability.uses_gcd else 0.0
|
|
cooldown_system.set_cooldown(player, ability_index, ability.cooldown, gcd)
|
|
|
|
func _execute_ability(player: Node, ability: Ability) -> bool:
|
|
var targeting: Node = player.get_node("Targeting")
|
|
var stat: String = "heal" if ability.is_heal else "damage"
|
|
var dmg: float = _apply_passive(player, ability.damage, stat)
|
|
match ability.type:
|
|
Ability.Type.SINGLE:
|
|
return _execute_single(player, targeting, ability, dmg)
|
|
Ability.Type.AOE:
|
|
return _execute_aoe(player, ability, dmg)
|
|
Ability.Type.UTILITY:
|
|
return _execute_utility(player, ability)
|
|
Ability.Type.ULT:
|
|
return _execute_ult(player, targeting, ability, dmg)
|
|
return false
|
|
|
|
func _apply_passive(player: Node, base: float, stat: String) -> float:
|
|
var mult: Variant = Stats.get_stat(player, "buff_" + stat)
|
|
if mult != null:
|
|
return base * mult
|
|
return base
|
|
|
|
func _in_range(player: Node, targeting: Node, ability: Ability) -> bool:
|
|
if ability.ability_range <= 0 or ability.is_heal:
|
|
return true
|
|
if not is_instance_valid(targeting.current_target):
|
|
return false
|
|
var dist: float = player.global_position.distance_to(targeting.current_target.global_position)
|
|
return dist <= ability.ability_range
|
|
|
|
func _execute_single(player: Node, targeting: Node, ability: Ability, dmg: float) -> bool:
|
|
if ability.is_heal:
|
|
EventBus.heal_requested.emit(player, player, dmg)
|
|
EventBus.attack_executed.emit(player, player.global_position, -player.global_transform.basis.z, dmg)
|
|
return true
|
|
if not _in_range(player, targeting, ability):
|
|
return false
|
|
if not is_instance_valid(targeting.current_target):
|
|
return false
|
|
EventBus.damage_requested.emit(player, targeting.current_target, dmg)
|
|
if ability.element != 0:
|
|
EventBus.element_damage_dealt.emit(player, targeting.current_target, dmg, ability.element)
|
|
EventBus.attack_executed.emit(player, player.global_position, -player.global_transform.basis.z, dmg)
|
|
return true
|
|
|
|
func _execute_aoe(player: Node, ability: Ability, dmg: float) -> bool:
|
|
if ability.is_heal:
|
|
EventBus.heal_requested.emit(player, player, dmg)
|
|
var players := get_tree().get_nodes_in_group("player")
|
|
for p in players:
|
|
if p != player and is_instance_valid(p):
|
|
var dist: float = player.global_position.distance_to(p.global_position)
|
|
if dist <= ability.ability_range:
|
|
EventBus.heal_requested.emit(player, p, dmg)
|
|
EventBus.attack_executed.emit(player, player.global_position, -player.global_transform.basis.z, dmg)
|
|
return true
|
|
var hit := false
|
|
var enemies := get_tree().get_nodes_in_group("enemies")
|
|
for enemy in enemies:
|
|
var dist: float = player.global_position.distance_to(enemy.global_position)
|
|
if dist <= ability.ability_range:
|
|
EventBus.damage_requested.emit(player, enemy, dmg)
|
|
if ability.element != 0:
|
|
EventBus.element_damage_dealt.emit(player, enemy, dmg, ability.element)
|
|
hit = true
|
|
if hit:
|
|
EventBus.attack_executed.emit(player, player.global_position, -player.global_transform.basis.z, dmg)
|
|
return hit
|
|
|
|
func _execute_utility(player: Node, ability: Ability) -> bool:
|
|
var max_shield: float = Stats.get_stat(player, "max_shield")
|
|
if max_shield <= 0:
|
|
return false
|
|
var shield: float = Stats.get_stat(player, "shield")
|
|
if ability.damage > 0:
|
|
shield = max_shield * (ability.damage / 100.0)
|
|
else:
|
|
if shield >= max_shield:
|
|
return false
|
|
shield = max_shield
|
|
Stats.set_stat(player, "shield", shield)
|
|
EventBus.shield_changed.emit(player, shield, max_shield)
|
|
return true
|
|
|
|
func _execute_ult(player: Node, targeting: Node, ability: Ability, dmg: float) -> bool:
|
|
if ability.is_heal:
|
|
EventBus.heal_requested.emit(player, player, dmg)
|
|
var players := get_tree().get_nodes_in_group("player")
|
|
var aoe_range: float = ability.aoe_radius if ability.aoe_radius > 0 else ability.ability_range
|
|
for p in players:
|
|
if p != player and is_instance_valid(p):
|
|
var dist: float = player.global_position.distance_to(p.global_position)
|
|
if dist <= aoe_range:
|
|
EventBus.heal_requested.emit(player, p, dmg * 0.4)
|
|
EventBus.attack_executed.emit(player, player.global_position, -player.global_transform.basis.z, dmg)
|
|
return true
|
|
if not _in_range(player, targeting, ability):
|
|
return false
|
|
if not is_instance_valid(targeting.current_target):
|
|
return false
|
|
var target: Node3D = targeting.current_target
|
|
EventBus.damage_requested.emit(player, target, dmg * 5.0)
|
|
if ability.element != 0:
|
|
EventBus.element_damage_dealt.emit(player, target, dmg * 5.0, ability.element)
|
|
var splash_range: float = ability.aoe_radius if ability.aoe_radius > 0 else ability.ability_range
|
|
var enemies := get_tree().get_nodes_in_group("enemies")
|
|
for enemy in enemies:
|
|
if enemy != target and is_instance_valid(enemy):
|
|
var enemy_dist: float = target.global_position.distance_to(enemy.global_position)
|
|
if enemy_dist <= splash_range:
|
|
EventBus.damage_requested.emit(player, enemy, dmg * 2.0)
|
|
if ability.element != 0:
|
|
EventBus.element_damage_dealt.emit(player, enemy, dmg * 2.0, ability.element)
|
|
EventBus.attack_executed.emit(player, player.global_position, -player.global_transform.basis.z, dmg * 5.0)
|
|
return true
|