11const DataCacheManager = preload(
"res://scripts/systems/dataCacheManager/data_cache_manager.gd")
14var data_cache_manager = DataCacheManager.new()
18func load_actions(file_path:String) -> void:
19 load_action_data(data_cache_manager.load_json(file_path))
23func load_action_data(data:Dictionary) -> void:
25 for raw_action
in data.get(
"actions", []):
26 if not raw_action
is Dictionary:
28 var action = normalize_action(raw_action)
29 var id = str(action.get(
"id",
""))
35func get_action(action_id:String) -> Dictionary:
36 return actions.get(action_id, {}).duplicate(true)
40func get_actions() -> Array:
42 for id
in actions.keys():
43 result.append(actions[id].duplicate(true))
48func normalize_action(action:Dictionary) -> Dictionary:
49 var normalized = action.duplicate(true)
50 normalized[
"id"] = str(normalized.get(
"id",
""))
51 normalized[
"name"] = str(normalized.get(
"name", normalized.get(
"id",
"Action")))
52 normalized[
"kind"] = str(normalized.get(
"kind",
"action"))
53 normalized[
"costs"] = _normalize_costs(normalized.get(
"costs", normalized.get(
"cost", [])))
54 normalized[
"cooldown"] = max(0.0, float(normalized.get(
"cooldown", 0.0)))
55 normalized[
"targeting"] = normalized.get(
"targeting", {})
if normalized.get(
"targeting", {})
is Dictionary
else {}
56 normalized[
"effects"] = _normalize_effects(normalized.get(
"effects", []))
61func can_pay_costs(action:Dictionary, pools:Dictionary) -> bool:
62 for cost
in _normalize_costs(action.get(
"costs", action.get(
"cost", []))):
63 var pool = str(cost.get(
"pool",
""))
64 var amount = int(cost.get(
"amount", 0))
65 if pool ==
"" or amount <= 0:
67 if int(pools.get(pool, 0)) < amount:
73func apply_costs(action:Dictionary, pools:Dictionary) -> Dictionary:
74 var next = pools.duplicate(true)
75 for cost
in _normalize_costs(action.get(
"costs", action.get(
"cost", []))):
76 var pool = str(cost.get(
"pool",
""))
77 var amount = int(cost.get(
"amount", 0))
78 if pool ==
"" or amount <= 0:
80 next[pool] = int(next.get(pool, 0)) - amount
85func is_on_cooldown(action_id:String, cooldowns:Dictionary) -> bool:
86 return float(cooldowns.get(action_id, 0.0)) > 0.0
90func can_use_action(action:Dictionary, pools:Dictionary = {}, cooldowns:Dictionary = {}) -> Dictionary:
91 var action_id = str(action.get(
"id",
""))
92 if action_id !=
"" and is_on_cooldown(action_id, cooldowns):
93 return {
"ok": false,
"reason":
"cooldown",
"remaining": float(cooldowns.get(action_id, 0.0))}
94 if not can_pay_costs(action, pools):
95 return {
"ok": false,
"reason":
"cost"}
100func begin_cooldown(action:Dictionary, cooldowns:Dictionary = {}) -> Dictionary:
101 var next = cooldowns.duplicate(true)
102 var action_id = str(action.get(
"id",
""))
103 var cooldown = max(0.0, float(action.get(
"cooldown", 0.0)))
104 if action_id !=
"" and cooldown > 0.0:
105 next[action_id] = cooldown
110func tick_cooldowns(cooldowns:Dictionary, delta:float) -> Dictionary:
112 for id
in cooldowns.keys():
113 var remaining = max(0.0, float(cooldowns[id]) - delta)
115 next[str(id)] = remaining
126func resolve_effects(action:Dictionary, context:Dictionary = {}) -> Dictionary:
128 for effect
in _normalize_effects(action.get(
"effects", [])):
129 var type = str(effect.get(
"type",
"custom"))
130 var callback = context.get(type, Callable())
131 if callback
is Callable
and callback.is_valid():
132 var resolved = callback.call(effect)
133 results.append(resolved
if resolved
is Dictionary
else {
"type": type,
"ok": true,
"value": resolved})
135 results.append({
"type": type,
"ok": false,
"reason":
"unhandled",
"effect": effect})
137 "action_id": str(action.get(
"id",
"")),
139 "ok": _results_ok(results)
144func use_action(action:Dictionary, pools:Dictionary = {}, cooldowns:Dictionary = {}, context:Dictionary = {}) -> Dictionary:
145 var availability = can_use_action(action, pools, cooldowns)
146 if not bool(availability.get(
"ok", false)):
149 "reason": str(availability.get(
"reason",
"blocked")),
150 "pools": pools.duplicate(true),
151 "cooldowns": cooldowns.duplicate(true),
154 var next_pools = apply_costs(action, pools)
155 var next_cooldowns = begin_cooldown(action, cooldowns)
156 var resolved = resolve_effects(action, context)
158 "ok": bool(resolved.get(
"ok", true)),
159 "action_id": str(action.get(
"id",
"")),
161 "cooldowns": next_cooldowns,
162 "effects": resolved.get(
"results", [])
166func _normalize_costs(raw_costs) -> Array:
168 var costs = raw_costs
if raw_costs
is Array
else [raw_costs]
169 for raw_cost
in costs:
170 if raw_cost
is Dictionary:
171 var pool = str(raw_cost.get(
"pool", raw_cost.get(
"resource", raw_cost.get(
"id",
""))))
172 var amount = int(raw_cost.get(
"amount", raw_cost.get(
"value", 0)))
173 if pool !=
"" and amount != 0:
174 normalized.append({
"pool": pool,
"amount": amount})
178func _normalize_effects(raw_effects) -> Array:
180 var effects = raw_effects
if raw_effects
is Array
else [raw_effects]
181 for raw_effect
in effects:
182 if not raw_effect
is Dictionary:
184 var effect = raw_effect.duplicate(true)
185 effect[
"type"] = str(effect.get(
"type",
"custom"))
186 normalized.append(effect)
190func _results_ok(results:Array) -> bool:
191 for result
in results:
192 if result
is Dictionary
and not bool(result.get(
"ok", true)):
197func get_cache_stats() -> Dictionary:
198 return data_cache_manager.get_cache_stats()