refactor
This commit is contained in:
166
systems/combat/ability_system.gd
Normal file
166
systems/combat/ability_system.gd
Normal file
@@ -0,0 +1,166 @@
|
||||
extends Node
|
||||
|
||||
@onready var role_system: Node = get_node("../RoleSystem")
|
||||
@onready var cooldown_system: Node = get_node("../CooldownSystem")
|
||||
|
||||
func _ready() -> void:
|
||||
EventBus.ability_use_requested.connect(_on_ability_request)
|
||||
|
||||
func _on_ability_request(player: Node, index: int) -> void:
|
||||
if not is_instance_valid(player) or not Stats.has(player):
|
||||
return
|
||||
var target_str: String = ""
|
||||
var tv: Variant = (player as Node).get("current_target")
|
||||
if tv != null and is_instance_valid(tv) and tv is Node:
|
||||
target_str = String((tv as Node).get_path())
|
||||
if not multiplayer.is_server() and multiplayer.multiplayer_peer != null:
|
||||
_request_use.rpc_id(1, String(player.get_path()), index, target_str)
|
||||
return
|
||||
_execute(player, index, target_str)
|
||||
|
||||
@rpc("any_peer", "reliable")
|
||||
func _request_use(path_str: String, index: int, target_str: String) -> void:
|
||||
var p: Node = get_node_or_null(NodePath(path_str))
|
||||
if p == null:
|
||||
return
|
||||
if target_str != "":
|
||||
var t := get_node_or_null(NodePath(target_str))
|
||||
if t and Stats.has(t):
|
||||
p.set("current_target", t)
|
||||
_execute(p, index, target_str)
|
||||
|
||||
func _execute(player: Node, index: int, _target_str: String = "") -> void:
|
||||
if index < 0 or index > 3:
|
||||
return
|
||||
var role: int = int(Stats.get_stat(player, "role", GameState.ROLE_DAMAGE))
|
||||
var set: AbilitySet = role_system.get_set(role)
|
||||
if set == null or index >= set.abilities.size():
|
||||
return
|
||||
var ability: Ability = set.abilities[index]
|
||||
if ability == null:
|
||||
return
|
||||
if not cooldown_system.is_ready(player, index):
|
||||
return
|
||||
if ability.uses_gcd and not cooldown_system.is_gcd_ready(player):
|
||||
return
|
||||
cooldown_system.set_cooldown(player, index, ability.cooldown, float(Stats.get_stat(player, "gcd_time", 0.5)) if ability.uses_gcd else 0.0)
|
||||
EventBus.ability_used.emit(player, index, ability)
|
||||
_apply_ability(player, ability)
|
||||
|
||||
func _apply_ability(player: Node, ability: Ability) -> void:
|
||||
match ability.type:
|
||||
Ability.Type.SINGLE:
|
||||
_apply_single(player, ability)
|
||||
Ability.Type.AOE:
|
||||
_apply_aoe(player, ability)
|
||||
Ability.Type.UTILITY:
|
||||
_apply_utility(player, ability)
|
||||
Ability.Type.ULT:
|
||||
_apply_ult(player, ability)
|
||||
_:
|
||||
pass
|
||||
|
||||
func _apply_single(player: Node, ability: Ability) -> void:
|
||||
var dmg_mult: float = float(Stats.get_stat(player, "buff_damage", 1.0))
|
||||
var heal_mult: float = float(Stats.get_stat(player, "buff_heal", 1.0))
|
||||
var target: Node = _resolve_target(player, ability)
|
||||
if target == null:
|
||||
return
|
||||
if (player as Node3D).global_position.distance_to((target as Node3D).global_position) > ability.ability_range:
|
||||
return
|
||||
if ability.is_heal:
|
||||
EventBus.heal_requested.emit(player, target, ability.damage * heal_mult)
|
||||
else:
|
||||
EventBus.damage_requested.emit(player, target, ability.damage * dmg_mult, ability.element)
|
||||
if ability.shield_value > 0.0:
|
||||
_apply_shield(player, ability.shield_value)
|
||||
|
||||
func _apply_aoe(player: Node, ability: Ability) -> void:
|
||||
var dmg_mult: float = float(Stats.get_stat(player, "buff_damage", 1.0))
|
||||
var heal_mult: float = float(Stats.get_stat(player, "buff_heal", 1.0))
|
||||
var origin: Vector3 = (player as Node3D).global_position
|
||||
var center: Vector3 = origin
|
||||
var target: Node = _resolve_target(player, ability)
|
||||
if target and (target as Node3D).global_position.distance_to(origin) <= ability.ability_range:
|
||||
center = (target as Node3D).global_position
|
||||
if ability.is_heal:
|
||||
for ally in get_tree().get_nodes_in_group("player"):
|
||||
if (ally as Node3D).global_position.distance_to(center) <= ability.aoe_radius:
|
||||
EventBus.heal_requested.emit(player, ally, ability.damage * heal_mult)
|
||||
else:
|
||||
var hits: int = 0
|
||||
for foe in Stats.entities_in_group(&"enemies"):
|
||||
if (foe as Node3D).global_position.distance_to(center) <= ability.aoe_radius:
|
||||
EventBus.damage_requested.emit(player, foe, ability.damage * dmg_mult, ability.element)
|
||||
hits += 1
|
||||
for foe in Stats.entities_in_group(&"portals"):
|
||||
if (foe as Node3D).global_position.distance_to(center) <= ability.aoe_radius:
|
||||
EventBus.damage_requested.emit(player, foe, ability.damage * dmg_mult, ability.element)
|
||||
hits += 1
|
||||
for foe in Stats.entities_in_group(&"gates"):
|
||||
if (foe as Node3D).global_position.distance_to(center) <= ability.aoe_radius:
|
||||
EventBus.damage_requested.emit(player, foe, ability.damage * dmg_mult, ability.element)
|
||||
hits += 1
|
||||
if ability.shield_value > 0.0:
|
||||
_apply_shield(player, ability.shield_value * hits)
|
||||
|
||||
func _apply_utility(player: Node, ability: Ability) -> void:
|
||||
if ability.shield_multiplier > 0.0:
|
||||
var max_shield: float = float(Stats.get_stat(player, "max_shield", 0.0))
|
||||
var add: float = max_shield * ability.shield_multiplier
|
||||
Stats.set_stat(player, "shield", min(max_shield, float(Stats.get_stat(player, "shield", 0.0)) + add))
|
||||
EventBus.shield_changed.emit(player, Stats.get_stat(player, "shield"), max_shield)
|
||||
|
||||
func _apply_ult(player: Node, ability: Ability) -> void:
|
||||
if ability.is_heal:
|
||||
_apply_aoe(player, ability)
|
||||
elif ability.shield_multiplier > 0.0:
|
||||
var max_shield: float = float(Stats.get_stat(player, "max_shield", 0.0))
|
||||
Stats.set_stat(player, "shield", min(max_shield * (1.0 + ability.shield_multiplier), float(Stats.get_stat(player, "shield", 0.0)) + max_shield * ability.shield_multiplier))
|
||||
EventBus.shield_changed.emit(player, Stats.get_stat(player, "shield"), max_shield)
|
||||
else:
|
||||
var target: Node = _resolve_target(player, ability)
|
||||
if target == null:
|
||||
return
|
||||
var dmg_mult: float = float(Stats.get_stat(player, "buff_damage", 1.0))
|
||||
EventBus.damage_requested.emit(player, target, ability.damage * dmg_mult, ability.element)
|
||||
if ability.aoe_radius > 0.0:
|
||||
var center: Vector3 = (target as Node3D).global_position
|
||||
for foe in Stats.entities_in_group(&"enemies"):
|
||||
if foe == target:
|
||||
continue
|
||||
if (foe as Node3D).global_position.distance_to(center) <= ability.aoe_radius:
|
||||
EventBus.damage_requested.emit(player, foe, ability.damage * 0.5 * dmg_mult, ability.element)
|
||||
|
||||
func _apply_shield(player: Node, amount: float) -> void:
|
||||
var max_shield: float = float(Stats.get_stat(player, "max_shield", 0.0))
|
||||
Stats.set_stat(player, "shield", min(max_shield, float(Stats.get_stat(player, "shield", 0.0)) + amount))
|
||||
EventBus.shield_changed.emit(player, Stats.get_stat(player, "shield"), max_shield)
|
||||
|
||||
func _resolve_target(player: Node, ability: Ability) -> Node:
|
||||
if ability.is_heal:
|
||||
var lowest: Node = null
|
||||
var lowest_pct: float = 2.0
|
||||
for ally in get_tree().get_nodes_in_group("player"):
|
||||
if not Stats.has(ally):
|
||||
continue
|
||||
var hp: float = float(Stats.get_stat(ally, "health", 0.0))
|
||||
var max_hp: float = float(Stats.get_stat(ally, "max_health", 1.0))
|
||||
if max_hp <= 0.0 or hp <= 0.0:
|
||||
continue
|
||||
var pct: float = hp / max_hp
|
||||
if pct < lowest_pct:
|
||||
lowest = ally
|
||||
lowest_pct = pct
|
||||
return lowest
|
||||
var tv: Variant = (player as Node).get("current_target")
|
||||
if tv != null and is_instance_valid(tv) and tv is Node and Stats.has(tv):
|
||||
return tv as Node
|
||||
var nearest: Node = null
|
||||
var nearest_dist: float = INF
|
||||
for foe in Stats.entities_in_group(&"enemies") + Stats.entities_in_group(&"portals") + Stats.entities_in_group(&"gates"):
|
||||
var d: float = (foe as Node3D).global_position.distance_to((player as Node3D).global_position)
|
||||
if d < nearest_dist and d <= ability.ability_range:
|
||||
nearest = foe
|
||||
nearest_dist = d
|
||||
return nearest
|
||||
1
systems/combat/ability_system.gd.uid
Normal file
1
systems/combat/ability_system.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://e47e8o4ofgtg
|
||||
74
systems/combat/auto_attack_system.gd
Normal file
74
systems/combat/auto_attack_system.gd
Normal file
@@ -0,0 +1,74 @@
|
||||
extends Node
|
||||
|
||||
@onready var role_system: Node = get_node("../RoleSystem")
|
||||
@onready var cooldown_system: Node = get_node("../CooldownSystem")
|
||||
|
||||
var _accum: float = 0.0
|
||||
|
||||
func _ready() -> void:
|
||||
if multiplayer.multiplayer_peer != null and not multiplayer.is_server() and not (multiplayer.multiplayer_peer is OfflineMultiplayerPeer):
|
||||
set_physics_process(false)
|
||||
else:
|
||||
set_physics_process(true)
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if not multiplayer.is_server() and multiplayer.multiplayer_peer != null:
|
||||
return
|
||||
_accum += delta
|
||||
if _accum < 0.10:
|
||||
return
|
||||
_accum = 0.0
|
||||
for player in get_tree().get_nodes_in_group("player"):
|
||||
if not Stats.has(player):
|
||||
continue
|
||||
if int(Stats.get_stat(player, "health", 0.0)) <= 0:
|
||||
continue
|
||||
if not cooldown_system.is_aa_ready(player):
|
||||
continue
|
||||
var role: int = int(Stats.get_stat(player, "role", GameState.ROLE_DAMAGE))
|
||||
var set: AbilitySet = role_system.get_set(role)
|
||||
if set == null:
|
||||
continue
|
||||
var target: Node = _pick_target(player, set)
|
||||
if target == null:
|
||||
continue
|
||||
var dist: float = (player as Node3D).global_position.distance_to((target as Node3D).global_position)
|
||||
if dist > set.aa_range:
|
||||
continue
|
||||
var dmg_mult: float = float(Stats.get_stat(player, "buff_damage", 1.0))
|
||||
var heal_mult: float = float(Stats.get_stat(player, "buff_heal", 1.0))
|
||||
if set.aa_is_heal:
|
||||
EventBus.heal_requested.emit(player, target, set.aa_damage * heal_mult)
|
||||
else:
|
||||
EventBus.damage_requested.emit(player, target, set.aa_damage * dmg_mult, Element.NONE)
|
||||
cooldown_system.set_aa(player, float(Stats.get_stat(player, "aa_cooldown", 0.5)))
|
||||
|
||||
func _pick_target(player: Node, set: AbilitySet) -> Node:
|
||||
if set.aa_is_heal:
|
||||
var lowest: Node = null
|
||||
var lowest_pct: float = 2.0
|
||||
for ally in get_tree().get_nodes_in_group("player"):
|
||||
if not Stats.has(ally):
|
||||
continue
|
||||
var hp: float = float(Stats.get_stat(ally, "health", 0.0))
|
||||
var max_hp: float = float(Stats.get_stat(ally, "max_health", 1.0))
|
||||
if hp <= 0.0:
|
||||
continue
|
||||
var pct: float = hp / max_hp
|
||||
if pct < lowest_pct and (player as Node3D).global_position.distance_to((ally as Node3D).global_position) <= set.aa_range:
|
||||
lowest = ally
|
||||
lowest_pct = pct
|
||||
return lowest
|
||||
var current_var: Variant = (player as Node).get("current_target")
|
||||
if current_var != null and is_instance_valid(current_var) and current_var is Node and Stats.has(current_var):
|
||||
return current_var
|
||||
var nearest: Node = null
|
||||
var nearest_dist: float = INF
|
||||
for foe in Stats.entities_in_group(&"enemies"):
|
||||
if not is_instance_valid(foe):
|
||||
continue
|
||||
var d: float = (foe as Node3D).global_position.distance_to((player as Node3D).global_position)
|
||||
if d < nearest_dist and d <= set.aa_range:
|
||||
nearest = foe
|
||||
nearest_dist = d
|
||||
return nearest
|
||||
1
systems/combat/auto_attack_system.gd.uid
Normal file
1
systems/combat/auto_attack_system.gd.uid
Normal file
@@ -0,0 +1 @@
|
||||
uid://comfiqsxl5t1e
|
||||
Reference in New Issue
Block a user