RapidGameFramework
Reusable Godot managers for data-driven small games
Loading...
Searching...
No Matches
projectile_lifecycle_manager.gd
Go to the documentation of this file.
1extends RefCounted
2
3
13
14
15func should_queue(card:Dictionary, direction:Vector2i, affected_cells:Array) -> bool:
16 if direction == Vector2i.ZERO or affected_cells.is_empty():
17 return false
18 var targeting = _targeting(card)
19 var type = str(targeting.get("type", "projectile"))
20 if card.has("compound") and str(card.get("manifestation", "")) == "":
21 return false
22 return type in ["projectile", "lob"]
23
24
25func create_effect(card:Dictionary, origin_cell:Vector2i, affected_cells:Array, used_slot:int, direction:Vector2i, options:Dictionary = {}) -> Dictionary:
26 var targeting = _targeting(card)
27 var type = str(targeting.get("type", "projectile"))
28 var travel_seconds = max(0.08, float(options.get("travel_ms", 520)) / 1000.0)
29 var end_cell = _impact_cell(card, origin_cell, affected_cells, direction)
30 return {
31 "card": card.duplicate(true),
32 "used_slot": used_slot,
33 "card_id": str(card.get("id", "")),
34 "type": type,
35 "shape": str(card.get("visual", {}).get("shape", type)),
36 "origin_cell": origin_cell,
37 "end_cell": end_cell,
38 "direction": direction,
39 "affected_cells": affected_cells.duplicate(true),
40 "age": 0.0,
41 "duration": travel_seconds,
42 "color": str(card.get("visual", {}).get("color", options.get("color", "#ffffff")))
43 }
44
45
46func step_effects(active_effects:Array, delta:float) -> Dictionary:
47 var active := []
48 var ready := []
49 for raw_effect in active_effects:
50 if not raw_effect is Dictionary:
51 continue
52 var effect = raw_effect.duplicate(true)
53 effect["age"] = float(effect.get("age", 0.0)) + delta
54 if float(effect.get("age", 0.0)) >= float(effect.get("duration", 0.1)):
55 ready.append(effect)
56 else:
57 active.append(effect)
58 return {
59 "active": active,
60 "ready": ready
61 }
62
63
64func resolve_cells(effect:Dictionary, resolver:Callable = Callable()) -> Array:
65 if resolver.is_valid():
66 var resolved = resolver.call(
67 effect.get("card", {}),
68 _cell_from_any(effect.get("origin_cell", Vector2i.ZERO)),
69 _cell_from_any(effect.get("direction", Vector2i.ZERO))
70 )
71 if resolved is Array:
72 return resolved.duplicate(true)
73 var cells = effect.get("affected_cells", [])
74 return cells.duplicate(true) if cells is Array else []
75
76
77func _impact_cell(card:Dictionary, origin_cell:Vector2i, affected_cells:Array, direction:Vector2i) -> Vector2i:
78 var targeting = _targeting(card)
79 var type = str(targeting.get("type", "projectile"))
80 if type == "lob" and direction != Vector2i.ZERO:
81 return origin_cell + direction * int(targeting.get("range", 1))
82 if affected_cells.is_empty():
83 return origin_cell
84 return _cell_from_any(affected_cells[affected_cells.size() - 1])
85
86
87func _targeting(card:Dictionary) -> Dictionary:
88 var targeting = card.get("targeting", {})
89 return targeting if targeting is Dictionary else {}
90
91
92func _cell_from_any(value) -> Vector2i:
93 if value is Vector2i:
94 return value
95 if value is Vector2:
96 return Vector2i(int(value.x), int(value.y))
97 if value is Array and value.size() >= 2:
98 return Vector2i(int(value[0]), int(value[1]))
99 if value is Dictionary and value.has("cell"):
100 return _cell_from_any(value.get("cell"))
101 return Vector2i.ZERO