8const DEFAULT_DAMAGE_COLOR :=
"#f05f64"
9const DEFAULT_HEAL_COLOR :=
"#55d17a"
11var feedback_by_side := {}
15 feedback_by_side.clear()
18func record_event(event:Dictionary, now_ms:int, options:Dictionary = {}) -> Dictionary:
19 var event_type = str(event.get(
"type",
"damage"))
20 if event_type ==
"heal":
21 return record_heal(str(event.get(
"target", event.get(
"side",
""))),
int(event.get(
"amount", 0)), now_ms, options)
22 if event_type ==
"damage":
23 return record_damage(str(event.get(
"defender", event.get(
"target", event.get(
"side",
"")))),
int(event.get(
"damage", event.get(
"amount", 0))), now_ms, options)
27func record_damage(side:String, amount:int, now_ms:int, options:Dictionary = {}) -> Dictionary:
28 if side ==
"" or amount <= 0:
30 return _push_feedback(side, {
32 "amount": -abs(amount),
33 "text":
"-%d" % abs(amount),
34 "color": str(options.get(
"damage_color", DEFAULT_DAMAGE_COLOR)),
36 "duration_ms":
int(options.get(
"duration_ms", 900)),
37 "hurt_until_ms": now_ms +
int(options.get(
"hurt_ms", 260))
41func record_heal(side:String, amount:int, now_ms:int, options:Dictionary = {}) -> Dictionary:
42 if side ==
"" or amount <= 0:
44 return _push_feedback(side, {
46 "amount": abs(amount),
47 "text":
"+%d" % abs(amount),
48 "color": str(options.get(
"heal_color", DEFAULT_HEAL_COLOR)),
50 "duration_ms":
int(options.get(
"duration_ms", 900)),
51 "hurt_until_ms": now_ms
55func step(now_ms:int) -> void:
56 for side
in feedback_by_side.keys():
57 var active_entries := []
58 for entry
in feedback_by_side.get(side, []):
59 if now_ms -
int(entry.get(
"created_ms", 0)) <=
int(entry.get(
"duration_ms", 0)):
60 active_entries.append(entry)
61 if active_entries.is_empty():
62 feedback_by_side.erase(side)
64 feedback_by_side[side] = active_entries
67func get_side_feedback(side:String, now_ms:int) -> Dictionary:
69 var entries:Array = feedback_by_side.get(side, [])
70 if entries.is_empty():
72 return _with_timing(entries[entries.size() - 1], now_ms)
75func is_side_hurting(side:String, now_ms:int) -> bool:
77 for entry
in feedback_by_side.get(side, []):
78 if now_ms <=
int(entry.get(
"hurt_until_ms", 0)):
83func has_active_feedback(now_ms:int) -> bool:
85 return not feedback_by_side.is_empty()
88func get_state(now_ms:int = -1) -> Dictionary:
91 return feedback_by_side.duplicate(true)
94func apply_state(state:Dictionary) -> void:
95 feedback_by_side = state.duplicate(true)
98func _push_feedback(side:String, entry:Dictionary) -> Dictionary:
99 var entries:Array = feedback_by_side.get(side, [])
100 entries.append(entry)
101 feedback_by_side[side] = entries
102 return entry.duplicate(true)
105func _with_timing(entry:Dictionary, now_ms:int) -> Dictionary:
106 var next:Dictionary = entry.duplicate(true)
107 var duration_ms:int = max(1,
int(next.get(
"duration_ms", 1)))
108 var age_ms:int = max(0, now_ms -
int(next.get(
"created_ms", now_ms)))
109 var progress:float = clamp(
float(age_ms) /
float(duration_ms), 0.0, 1.0)
110 next[
"age_ms"] = age_ms
111 next[
"progress"] = progress
112 next[
"alpha"] = clamp(1.0 - progress, 0.0, 1.0)
113 next[
"rise"] = -18.0 * progress
114 next[
"scale"] = 1.0 + (0.18 * (1.0 - progress))