Initial project sync
This commit is contained in:
@@ -0,0 +1,213 @@
|
||||
class_name EffectContainer
|
||||
extends Node
|
||||
|
||||
signal effect_added(effect_id: StringName)
|
||||
signal effect_removed(effect_id: StringName)
|
||||
|
||||
const EffectInstanceScript := preload("res://resources/effects/effect_instance.gd")
|
||||
|
||||
@export var beats_per_measure := 4
|
||||
@export var initial_effects: Array[Resource] = []
|
||||
|
||||
var effects: Array[RefCounted] = []
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
var bus := _event_bus_or_null()
|
||||
if bus != null and bus.has_signal("beat_ticked") and not bus.is_connected("beat_ticked", _on_beat_ticked):
|
||||
bus.connect("beat_ticked", _on_beat_ticked)
|
||||
for definition: Resource in initial_effects:
|
||||
add_effect(definition, &"loadout")
|
||||
|
||||
|
||||
func _exit_tree() -> void:
|
||||
var bus := _event_bus_or_null()
|
||||
if bus != null and bus.has_signal("beat_ticked") and bus.is_connected("beat_ticked", _on_beat_ticked):
|
||||
bus.disconnect("beat_ticked", _on_beat_ticked)
|
||||
|
||||
|
||||
func _process(delta: float) -> void:
|
||||
tick_time(delta)
|
||||
|
||||
|
||||
func add_effect(definition: Resource, source: Variant = &"-") -> void:
|
||||
if definition == null:
|
||||
return
|
||||
var effect_id := StringName(str(definition.get("id")))
|
||||
var max_stacks := int(definition.get("max_stacks"))
|
||||
for effect: RefCounted in effects:
|
||||
if StringName(str(effect.definition.get("id"))) == effect_id:
|
||||
effect.stacks = mini(effect.stacks + 1, max(1, max_stacks))
|
||||
effect.remaining = float(definition.get("duration"))
|
||||
effect.source = source
|
||||
effect_added.emit(effect_id)
|
||||
return
|
||||
effects.append(EffectInstanceScript.create(definition, source))
|
||||
effect_added.emit(effect_id)
|
||||
|
||||
|
||||
func set_effect_stacks(effect_id: StringName, stacks: int) -> void:
|
||||
if stacks <= 0:
|
||||
remove_effect(effect_id)
|
||||
return
|
||||
for effect: RefCounted in effects:
|
||||
if StringName(str(effect.definition.get("id"))) == effect_id:
|
||||
var max_stacks := maxi(1, int(effect.definition.get("max_stacks")))
|
||||
effect.stacks = mini(stacks, max_stacks)
|
||||
return
|
||||
|
||||
|
||||
func effect_stacks(effect_id: StringName) -> int:
|
||||
for effect: RefCounted in effects:
|
||||
if StringName(str(effect.definition.get("id"))) == effect_id:
|
||||
return int(effect.stacks)
|
||||
return 0
|
||||
|
||||
|
||||
func remove_effect(effect_id: StringName) -> void:
|
||||
for index: int in range(effects.size() - 1, -1, -1):
|
||||
var effect: RefCounted = effects[index]
|
||||
if StringName(str(effect.definition.get("id"))) == effect_id:
|
||||
effects.remove_at(index)
|
||||
effect_removed.emit(effect_id)
|
||||
|
||||
|
||||
func tick_time(delta: float) -> void:
|
||||
for effect: RefCounted in effects:
|
||||
effect.tick_time(delta)
|
||||
_prune_expired()
|
||||
|
||||
|
||||
func tick_beats(beats: float) -> void:
|
||||
for effect: RefCounted in effects:
|
||||
effect.tick_beats(beats)
|
||||
_prune_expired()
|
||||
|
||||
|
||||
func active_count() -> int:
|
||||
return effects.size()
|
||||
|
||||
|
||||
func active_effect_ids() -> Array[StringName]:
|
||||
var ids: Array[StringName] = []
|
||||
for effect: RefCounted in effects:
|
||||
ids.append(StringName(str(effect.definition.get("id"))))
|
||||
return ids
|
||||
|
||||
|
||||
func active_effect_summaries() -> Array[Dictionary]:
|
||||
var summaries: Array[Dictionary] = []
|
||||
for effect: RefCounted in effects:
|
||||
summaries.append({
|
||||
"id": StringName(str(effect.definition.get("id"))),
|
||||
"duration_type": StringName(str(effect.definition.get("duration_type"))),
|
||||
"remaining": float(effect.remaining),
|
||||
"stacks": int(effect.stacks),
|
||||
"source": _source_label(effect.source),
|
||||
})
|
||||
return summaries
|
||||
|
||||
|
||||
func dispatch_event(event_name: StringName, context: Dictionary = {}) -> void:
|
||||
var triggered: Array[Resource] = []
|
||||
for effect: RefCounted in effects:
|
||||
if StringName(str(effect.definition.get("trigger_event"))) != event_name:
|
||||
continue
|
||||
if effect.has_method("matches_event_context") and not bool(effect.call("matches_event_context", context)):
|
||||
continue
|
||||
var next_effects = effect.definition.get("trigger_effects")
|
||||
if not next_effects is Array:
|
||||
continue
|
||||
for definition: Resource in next_effects:
|
||||
if definition != null:
|
||||
triggered.append(definition)
|
||||
for effect: RefCounted in effects:
|
||||
if effect.has_method("tick_event"):
|
||||
effect.call("tick_event", event_name, context)
|
||||
_prune_expired()
|
||||
for definition: Resource in triggered:
|
||||
add_effect(definition)
|
||||
|
||||
|
||||
func damage_mult(action: Resource = null) -> float:
|
||||
return stat_multiplier(&"damage_mult", action)
|
||||
|
||||
|
||||
func cost_mult(action: Resource = null) -> float:
|
||||
return stat_multiplier(&"cost_mult", action)
|
||||
|
||||
|
||||
func move_mult(action: Resource = null) -> float:
|
||||
return stat_multiplier(&"move_mult", action)
|
||||
|
||||
|
||||
func defense_modifiers() -> Array[Resource]:
|
||||
return _active_modifiers("defense_modifiers")
|
||||
|
||||
|
||||
func action_rule_modifiers() -> Array[Resource]:
|
||||
return _active_modifiers("action_rule_modifiers")
|
||||
|
||||
|
||||
func stat_multiplier(stat: StringName, _action: Resource = null) -> float:
|
||||
var multiplier := 1.0
|
||||
for effect: RefCounted in effects:
|
||||
for modifier: Resource in _stat_modifiers(effect):
|
||||
if StringName(str(modifier.get("stat"))) != stat:
|
||||
continue
|
||||
if str(modifier.get("operation")) == "add":
|
||||
multiplier += float(modifier.get("value")) * maxi(1, int(effect.stacks))
|
||||
else:
|
||||
multiplier *= float(modifier.get("value"))
|
||||
return multiplier
|
||||
|
||||
|
||||
func _stat_modifiers(effect: RefCounted) -> Array:
|
||||
var modifiers = effect.definition.get("stat_modifiers")
|
||||
return modifiers if modifiers is Array else []
|
||||
|
||||
|
||||
func _active_modifiers(property_name: String) -> Array[Resource]:
|
||||
var result: Array[Resource] = []
|
||||
for effect: RefCounted in effects:
|
||||
var modifiers = effect.definition.get(property_name)
|
||||
if not modifiers is Array:
|
||||
continue
|
||||
for modifier: Resource in modifiers:
|
||||
if modifier != null:
|
||||
result.append(modifier)
|
||||
return result
|
||||
|
||||
|
||||
func _source_label(source: Variant) -> StringName:
|
||||
if source == null:
|
||||
return &"-"
|
||||
if source is StringName:
|
||||
return source
|
||||
if source is String:
|
||||
return StringName(source)
|
||||
if source is Node:
|
||||
return StringName((source as Node).name)
|
||||
return StringName(str(source))
|
||||
|
||||
|
||||
func _prune_expired() -> void:
|
||||
for index: int in range(effects.size() - 1, -1, -1):
|
||||
var effect: RefCounted = effects[index]
|
||||
if effect.is_expired():
|
||||
var effect_id := StringName(str(effect.definition.get("id")))
|
||||
effects.remove_at(index)
|
||||
effect_removed.emit(effect_id)
|
||||
|
||||
|
||||
func _on_beat_ticked(beat_index: int) -> void:
|
||||
tick_beats(1.0)
|
||||
if beats_per_measure > 0 and beat_index % beats_per_measure == 0:
|
||||
dispatch_event(&"on_measure_start", {"beat_index": beat_index})
|
||||
dispatch_event(&"on_beat", {"beat_index": beat_index})
|
||||
|
||||
|
||||
func _event_bus_or_null() -> Node:
|
||||
if not is_inside_tree():
|
||||
return null
|
||||
return get_tree().root.get_node_or_null("EventBus")
|
||||
Reference in New Issue
Block a user