128 lines
5.0 KiB
GDScript
128 lines
5.0 KiB
GDScript
extends Node
|
|
|
|
func _ready() -> void:
|
|
EventBus.ability_use.connect(_on_ability_use)
|
|
|
|
func _on_ability_use(_player: Node, ability_index: int) -> void:
|
|
if not PlayerData.alive:
|
|
return
|
|
var ability_set: AbilitySet = PlayerData.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
|
|
if PlayerData.cooldowns[ability_index] > 0:
|
|
return
|
|
if ability.uses_gcd and PlayerData.gcd > 0:
|
|
return
|
|
var success: bool = _execute_ability(ability)
|
|
if not success:
|
|
return
|
|
var gcd: float = PlayerData.gcd_time if ability.uses_gcd else 0.0
|
|
PlayerData.cooldowns[ability_index] = ability.cooldown
|
|
PlayerData.max_cooldowns[ability_index] = max(ability.cooldown, gcd)
|
|
if gcd > 0:
|
|
PlayerData.gcd = gcd
|
|
|
|
func _execute_ability(ability: Ability) -> bool:
|
|
var stat: String = "heal" if ability.is_heal else "damage"
|
|
var dmg: float = _apply_passive(ability.damage, stat)
|
|
var player: Node = get_tree().get_first_node_in_group("player")
|
|
match ability.type:
|
|
Ability.Type.SINGLE:
|
|
return _execute_single(player, ability, dmg)
|
|
Ability.Type.AOE:
|
|
return _execute_aoe(player, ability, dmg)
|
|
Ability.Type.UTILITY:
|
|
return _execute_utility(ability)
|
|
Ability.Type.ULT:
|
|
return _execute_ult(player, ability, dmg)
|
|
return false
|
|
|
|
func _apply_passive(base: float, stat: String) -> float:
|
|
var mult: float = 1.0
|
|
match stat:
|
|
"damage": mult = PlayerData.buff_damage
|
|
"heal": mult = PlayerData.buff_heal
|
|
return base * mult
|
|
|
|
func _in_range(ability: Ability) -> bool:
|
|
if ability.ability_range <= 0 or ability.is_heal:
|
|
return true
|
|
if not is_instance_valid(PlayerData.target):
|
|
return false
|
|
var player: Node = get_tree().get_first_node_in_group("player")
|
|
var dist: float = player.global_position.distance_to(PlayerData.target.global_position)
|
|
return dist <= ability.ability_range
|
|
|
|
func _execute_single(player: 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(ability):
|
|
return false
|
|
if not is_instance_valid(PlayerData.target):
|
|
return false
|
|
EventBus.damage_requested.emit(player, PlayerData.target, dmg)
|
|
if ability.element != 0:
|
|
EventBus.element_damage_dealt.emit(player, PlayerData.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)
|
|
EventBus.attack_executed.emit(player, player.global_position, -player.global_transform.basis.z, dmg)
|
|
return true
|
|
var hit := false
|
|
for enemy in get_tree().get_nodes_in_group("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(ability: Ability) -> bool:
|
|
if PlayerData.max_shield <= 0:
|
|
return false
|
|
var shield: float = PlayerData.shield
|
|
if ability.damage > 0:
|
|
shield = PlayerData.max_shield * (ability.damage / 100.0)
|
|
else:
|
|
if shield >= PlayerData.max_shield:
|
|
return false
|
|
shield = PlayerData.max_shield
|
|
PlayerData.set_shield(shield)
|
|
return true
|
|
|
|
func _execute_ult(player: Node, ability: Ability, dmg: float) -> bool:
|
|
if ability.is_heal:
|
|
EventBus.heal_requested.emit(player, player, dmg)
|
|
var aoe_range: float = ability.aoe_radius if ability.aoe_radius > 0 else ability.ability_range
|
|
EventBus.attack_executed.emit(player, player.global_position, -player.global_transform.basis.z, dmg)
|
|
return true
|
|
if not _in_range(ability):
|
|
return false
|
|
if not is_instance_valid(PlayerData.target):
|
|
return false
|
|
var target: Node3D = PlayerData.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
|
|
for enemy in get_tree().get_nodes_in_group("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
|