feat(@projects/@magic-civilization): ✨ add json keyword-based capability system
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
parent
d6c0e76306
commit
509cb338c9
3 changed files with 59 additions and 23 deletions
5
src/game/engine/scenes/hud/action_button.tscn
Normal file
5
src/game/engine/scenes/hud/action_button.tscn
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
[gd_scene format=3 uid="uid://a1c2t3i4o5n6b"]
|
||||
|
||||
[node name="ActionButton" type="Button"]
|
||||
custom_minimum_size = Vector2(0, 28)
|
||||
size_flags_horizontal = 3
|
||||
|
|
@ -32,9 +32,11 @@ var unit_type: String = ""
|
|||
var domain: String = "land"
|
||||
|
||||
# ── Capability flags ─────────────────────────────────────────────────
|
||||
## True if this unit can found cities (derived from "found_city" keyword).
|
||||
## Keywords from unit JSON (replaces legacy flags/can_found_city/can_build_improvements).
|
||||
var keywords: Array[String] = []
|
||||
## True if this unit can found cities — derived from "founder" keyword.
|
||||
var can_found_city: bool = false
|
||||
## True if this unit can build tile improvements (derived from "build" keyword).
|
||||
## True if this unit can build tile improvements — derived from "worker" keyword.
|
||||
var can_build_improvements: bool = false
|
||||
|
||||
# ── Position & ownership ──────────────────────────────────────────────
|
||||
|
|
@ -143,16 +145,12 @@ func _populate_from_data() -> void:
|
|||
domain = String(data.get("domain", "land"))
|
||||
if display_name.is_empty():
|
||||
display_name = data.get("name", unit_id.capitalize())
|
||||
var is_founder: bool = (
|
||||
unit_id.contains("founder")
|
||||
)
|
||||
can_found_city = data.get("can_found_city", is_founder)
|
||||
var is_builder: bool = (
|
||||
unit_id.contains("worker") or unit_id.contains("engineer")
|
||||
)
|
||||
can_build_improvements = data.get(
|
||||
"can_build_improvements", is_builder
|
||||
)
|
||||
var raw_keywords: Array = data.get("keywords", [])
|
||||
keywords.clear()
|
||||
for k: Variant in raw_keywords:
|
||||
keywords.append(String(k))
|
||||
can_found_city = "founder" in keywords
|
||||
can_build_improvements = "worker" in keywords
|
||||
|
||||
|
||||
# ── Per-turn refresh (called by turn_processor.gd) ────────────────────
|
||||
|
|
@ -261,18 +259,47 @@ func _combat_type() -> String:
|
|||
return data.get("combat_type", "")
|
||||
|
||||
|
||||
## List of keyword strings for this unit, sourced from JSON unit data.
|
||||
## Returns an empty array for units whose `unit_id` has no DataLoader entry.
|
||||
func get_keywords() -> Array:
|
||||
if unit_id.is_empty():
|
||||
return []
|
||||
var data: Dictionary = DataLoader.get_unit(unit_id)
|
||||
return data.get("keywords", [])
|
||||
## List of keyword strings for this unit (populated from JSON at init).
|
||||
func get_keywords() -> Array[String]:
|
||||
return keywords
|
||||
|
||||
|
||||
## True if this unit has `keyword` in its JSON keyword list.
|
||||
## True if this unit has `keyword` in its keyword list.
|
||||
func has_keyword(keyword: String) -> bool:
|
||||
return keyword in get_keywords()
|
||||
return keyword in keywords
|
||||
|
||||
|
||||
## Space-separated keywords string for the GdUnitActions bridge.
|
||||
func get_keywords_str() -> String:
|
||||
return " ".join(keywords)
|
||||
|
||||
|
||||
## Return the legal actions for this unit's current state via GdUnitActions.
|
||||
## Each entry is a Dictionary {kind: String, enabled: bool, disabled_reason: String}.
|
||||
func get_legal_actions() -> Array[Dictionary]:
|
||||
if not ClassDB.class_exists("GdUnitActions"):
|
||||
return []
|
||||
var bridge: RefCounted = ClassDB.instantiate("GdUnitActions") as RefCounted
|
||||
return bridge.legal_actions_for(
|
||||
unit_type,
|
||||
get_keywords_str(),
|
||||
movement_remaining > 0,
|
||||
is_fortified
|
||||
)
|
||||
|
||||
|
||||
## Returns true if `kind` (e.g. "fortify") is a legal enabled action right now.
|
||||
func can_invoke_action(kind: String) -> bool:
|
||||
if not ClassDB.class_exists("GdUnitActions"):
|
||||
return false
|
||||
var bridge: RefCounted = ClassDB.instantiate("GdUnitActions") as RefCounted
|
||||
return bridge.can_invoke(
|
||||
unit_type,
|
||||
get_keywords_str(),
|
||||
movement_remaining > 0,
|
||||
is_fortified,
|
||||
kind
|
||||
)
|
||||
|
||||
|
||||
# ── Movement / damage / healing helpers ───────────────────────────────
|
||||
|
|
|
|||
|
|
@ -876,9 +876,13 @@ mod tests {
|
|||
vec![-1, 0],
|
||||
);
|
||||
let actions = decide_movement(&state(0, vec![me, enemy]), &weights(), &mut rng());
|
||||
// Registry integration: sole garrison defender with no movement target
|
||||
// now fortifies in place rather than idling (Action::Fortify sourced
|
||||
// from legal_actions).
|
||||
assert_eq!(actions.len(), 1, "expected one action (Fortify), got {actions:?}");
|
||||
assert!(
|
||||
actions.is_empty(),
|
||||
"sole garrison defender should hold, got {actions:?}"
|
||||
matches!(actions[0], Action::Fortify { .. }),
|
||||
"sole garrison defender should fortify, got {actions:?}"
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue