139 lines
4.6 KiB
GDScript
139 lines
4.6 KiB
GDScript
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)
|