refactor
This commit is contained in:
138
systems/effect_system.gd
Normal file
138
systems/effect_system.gd
Normal file
@@ -0,0 +1,138 @@
|
||||
extends Node
|
||||
|
||||
var _active: Dictionary = {}
|
||||
var _passive_auras: Dictionary = {}
|
||||
|
||||
func _ready() -> void:
|
||||
EventBus.entity_died.connect(_on_died)
|
||||
EventBus.entity_deregistered.connect(_on_dereg)
|
||||
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)
|
||||
|
||||
var _heavy_accum: float = 0.0
|
||||
|
||||
func _physics_process(delta: float) -> void:
|
||||
if not multiplayer.is_server() and multiplayer.multiplayer_peer != null:
|
||||
return
|
||||
_tick_durations(delta)
|
||||
_heavy_accum += delta
|
||||
if _heavy_accum < 0.20:
|
||||
return
|
||||
_heavy_accum = 0.0
|
||||
_propagate_auras()
|
||||
_recompute_buffs()
|
||||
|
||||
func apply(target: Node, effect: Effect, source: Node = null) -> void:
|
||||
if not is_instance_valid(target):
|
||||
return
|
||||
if not target in _active:
|
||||
_active[target] = []
|
||||
for entry in _active[target]:
|
||||
if entry.effect.effect_name == effect.effect_name and entry.source == source:
|
||||
entry.remaining = effect.duration
|
||||
entry.tick_timer = effect.tick_interval
|
||||
EventBus.effect_applied.emit(target, effect, source)
|
||||
return
|
||||
_active[target].append({
|
||||
"effect": effect,
|
||||
"source": source,
|
||||
"remaining": effect.duration,
|
||||
"tick_timer": effect.tick_interval
|
||||
})
|
||||
EventBus.effect_applied.emit(target, effect, source)
|
||||
|
||||
func remove_by_source(target: Node, source: Node) -> void:
|
||||
if not target in _active:
|
||||
return
|
||||
var keep: Array = []
|
||||
for entry in _active[target]:
|
||||
if entry.source == source:
|
||||
EventBus.effect_expired.emit(target, entry.effect)
|
||||
else:
|
||||
keep.append(entry)
|
||||
_active[target] = keep
|
||||
|
||||
func apply_passive_aura(player: Node, ability: Ability) -> void:
|
||||
if ability == null or ability.passive_stat == &"":
|
||||
return
|
||||
_passive_auras[player] = ability
|
||||
for target in get_tree().get_nodes_in_group("player"):
|
||||
remove_by_source(target, player)
|
||||
|
||||
func _propagate_auras() -> void:
|
||||
for source in _passive_auras.keys():
|
||||
if not is_instance_valid(source):
|
||||
_passive_auras.erase(source)
|
||||
continue
|
||||
var ability: Ability = _passive_auras[source]
|
||||
var effect := Effect.new()
|
||||
effect.effect_name = StringName("aura_%s_%s" % [ability.passive_stat, source.name])
|
||||
effect.type = Effect.Type.AURA
|
||||
effect.stat = ability.passive_stat
|
||||
effect.value = ability.passive_value
|
||||
effect.is_multiplier = true
|
||||
effect.duration = 0.5
|
||||
effect.aura_radius = ability.passive_radius
|
||||
var src_pos: Vector3 = (source as Node3D).global_position
|
||||
for target in get_tree().get_nodes_in_group("player"):
|
||||
if not Stats.has(target):
|
||||
continue
|
||||
var d: float = (target as Node3D).global_position.distance_to(src_pos)
|
||||
if d <= ability.passive_radius:
|
||||
apply(target, effect, source)
|
||||
|
||||
func _tick_durations(delta: float) -> void:
|
||||
for target in _active.keys():
|
||||
if not is_instance_valid(target):
|
||||
_active.erase(target)
|
||||
continue
|
||||
var keep: Array = []
|
||||
for entry in _active[target]:
|
||||
if entry.effect.duration > 0.0:
|
||||
entry.remaining -= delta
|
||||
if entry.remaining <= 0.0:
|
||||
EventBus.effect_expired.emit(target, entry.effect)
|
||||
continue
|
||||
if entry.effect.tick_interval > 0.0:
|
||||
entry.tick_timer -= delta
|
||||
if entry.tick_timer <= 0.0:
|
||||
entry.tick_timer = entry.effect.tick_interval
|
||||
if entry.effect.type == Effect.Type.DOT:
|
||||
EventBus.damage_requested.emit(entry.source, target, entry.effect.value, entry.effect.element)
|
||||
elif entry.effect.type == Effect.Type.HOT:
|
||||
EventBus.heal_requested.emit(entry.source, target, entry.effect.value)
|
||||
keep.append(entry)
|
||||
_active[target] = keep
|
||||
|
||||
func _recompute_buffs() -> void:
|
||||
for target in _active.keys():
|
||||
if not is_instance_valid(target) or not Stats.has(target):
|
||||
continue
|
||||
var bonus: Dictionary = {}
|
||||
var mult: Dictionary = {}
|
||||
for entry in _active[target]:
|
||||
var e: Effect = entry.effect
|
||||
if e.stat == &"":
|
||||
continue
|
||||
if e.is_multiplier:
|
||||
mult[e.stat] = mult.get(e.stat, 0.0) + e.value
|
||||
else:
|
||||
bonus[e.stat] = bonus.get(e.stat, 0.0) + e.value
|
||||
for stat in [&"buff_damage", &"buff_heal", &"buff_shield"]:
|
||||
var base: float = 1.0
|
||||
var v: float = base + mult.get(stat, 0.0) + bonus.get(stat, 0.0)
|
||||
Stats.set_stat(target, stat, v)
|
||||
EventBus.buff_changed.emit(target, stat, v)
|
||||
|
||||
func _on_died(entity: Node) -> void:
|
||||
if entity in _active:
|
||||
for entry in _active[entity]:
|
||||
EventBus.effect_expired.emit(entity, entry.effect)
|
||||
_active.erase(entity)
|
||||
_passive_auras.erase(entity)
|
||||
|
||||
func _on_dereg(entity: Node) -> void:
|
||||
_active.erase(entity)
|
||||
_passive_auras.erase(entity)
|
||||
Reference in New Issue
Block a user