148 lines
5.2 KiB
GDScript
148 lines
5.2 KiB
GDScript
extends RefCounted
|
|
|
|
## NEO-97: shared combat-active gate + NPC/telegraph HUD copy for [code]main.gd[/code] and tests.
|
|
|
|
const PrototypeTargetConstants := preload("res://scripts/prototype_target_constants.gd")
|
|
const NpcRuntimeClient := preload("res://scripts/npc_runtime_client.gd")
|
|
|
|
|
|
static func locked_target_id_from_state(state: Dictionary) -> String:
|
|
var locked_variant: Variant = state.get("lockedTargetId", null)
|
|
if locked_variant is String:
|
|
return (locked_variant as String).strip_edges()
|
|
return ""
|
|
|
|
|
|
static func is_known_npc_id(target_id: String) -> bool:
|
|
return PrototypeTargetConstants.ANCHORS.has(target_id.strip_edges())
|
|
|
|
|
|
static func incoming_aggro_row(
|
|
dev_player_id: String, npc_runtime_snapshot: Dictionary
|
|
) -> Dictionary:
|
|
if npc_runtime_snapshot.is_empty():
|
|
return {}
|
|
return NpcRuntimeClient.row_for_aggro_holder(dev_player_id, npc_runtime_snapshot)
|
|
|
|
|
|
static func is_combat_active(
|
|
last_target_state: Dictionary, npc_runtime_snapshot: Dictionary, dev_player_id: String
|
|
) -> bool:
|
|
var lock_id := locked_target_id_from_state(last_target_state)
|
|
if is_known_npc_id(lock_id):
|
|
return true
|
|
return not incoming_aggro_row(dev_player_id, npc_runtime_snapshot).is_empty()
|
|
|
|
|
|
static func resolve_hud_npc_rows(
|
|
last_target_state: Dictionary,
|
|
npc_runtime_snapshot: Dictionary,
|
|
dev_player_id: String,
|
|
runtime_client: Node = null
|
|
) -> Dictionary:
|
|
var lock_id := locked_target_id_from_state(last_target_state)
|
|
var locked_row: Dictionary = {}
|
|
if is_known_npc_id(lock_id):
|
|
if is_instance_valid(runtime_client) and runtime_client.has_method("npc_row"):
|
|
locked_row = runtime_client.call("npc_row", lock_id, npc_runtime_snapshot) as Dictionary
|
|
else:
|
|
locked_row = NpcRuntimeClient.npc_row_in_snapshot(lock_id, npc_runtime_snapshot)
|
|
var incoming_row: Dictionary = {}
|
|
var aggro_row: Dictionary = incoming_aggro_row(dev_player_id, npc_runtime_snapshot)
|
|
if not aggro_row.is_empty():
|
|
var aggro_id: String = str(aggro_row.get("npcInstanceId", "")).strip_edges()
|
|
if aggro_id != lock_id:
|
|
incoming_row = aggro_row
|
|
return {"locked": locked_row, "incoming": incoming_row}
|
|
|
|
|
|
static func build_npc_state_label(rows: Dictionary, runtime_sync_error: String = "") -> String:
|
|
var lines: PackedStringArray = PackedStringArray()
|
|
var locked_row: Dictionary = rows.get("locked", {}) as Dictionary
|
|
if not locked_row.is_empty():
|
|
var locked_id: String = str(locked_row.get("npcInstanceId", ""))
|
|
(
|
|
lines
|
|
. append(
|
|
(
|
|
"NPC state: %s → %s"
|
|
% [
|
|
PrototypeTargetConstants.display_short_name(locked_id),
|
|
str(locked_row.get("state", "unknown")),
|
|
]
|
|
)
|
|
)
|
|
)
|
|
var incoming_row: Dictionary = rows.get("incoming", {}) as Dictionary
|
|
if not incoming_row.is_empty():
|
|
var incoming_id: String = str(incoming_row.get("npcInstanceId", ""))
|
|
(
|
|
lines
|
|
. append(
|
|
(
|
|
"Incoming: %s → %s"
|
|
% [
|
|
PrototypeTargetConstants.display_short_name(incoming_id),
|
|
str(incoming_row.get("state", "unknown")),
|
|
]
|
|
)
|
|
)
|
|
)
|
|
if lines.is_empty():
|
|
if not runtime_sync_error.is_empty():
|
|
return "NPC state: — (%s)" % runtime_sync_error
|
|
return "NPC state: —"
|
|
if not runtime_sync_error.is_empty():
|
|
lines.append("(runtime sync: %s)" % runtime_sync_error)
|
|
return "\n".join(lines)
|
|
|
|
|
|
static func format_telegraph_line(row: Dictionary, hud_state: RefCounted = null) -> String:
|
|
var instance_id: String = str(row.get("npcInstanceId", "")).strip_edges()
|
|
var telegraph: Variant = row.get("activeTelegraph", null)
|
|
if telegraph == null or not telegraph is Dictionary:
|
|
return ""
|
|
var telegraph_dict: Dictionary = telegraph as Dictionary
|
|
var remaining: float = float(telegraph_dict.get("windupRemainingSeconds", 0.0))
|
|
if hud_state != null and hud_state.has_method("display_windup_remaining"):
|
|
remaining = float(hud_state.call("display_windup_remaining", instance_id))
|
|
if remaining <= 0.0:
|
|
return ""
|
|
var short_name: String = PrototypeTargetConstants.display_short_name(instance_id)
|
|
var telegraph_id: String = str(telegraph_dict.get("telegraphId", ""))
|
|
var archetype: String = str(telegraph_dict.get("archetypeKind", ""))
|
|
return "Telegraph: %s %s · %.1fs (%s)" % [short_name, telegraph_id, remaining, archetype]
|
|
|
|
|
|
static func build_telegraph_label(
|
|
rows: Dictionary, hud_state: RefCounted = null, runtime_sync_error: String = ""
|
|
) -> String:
|
|
var locked_row: Dictionary = rows.get("locked", {}) as Dictionary
|
|
var line: String = format_telegraph_line(locked_row, hud_state)
|
|
if line.is_empty():
|
|
line = format_telegraph_line(rows.get("incoming", {}) as Dictionary, hud_state)
|
|
if line.is_empty():
|
|
if not runtime_sync_error.is_empty():
|
|
return "Telegraph: — (%s)" % runtime_sync_error
|
|
return "Telegraph: —"
|
|
return line
|
|
|
|
|
|
static func has_interpolated_telegraph_display(rows: Dictionary, hud_state: RefCounted) -> bool:
|
|
if hud_state == null:
|
|
return false
|
|
for key: String in ["locked", "incoming"]:
|
|
var row: Dictionary = rows.get(key, {}) as Dictionary
|
|
if row.is_empty():
|
|
continue
|
|
var instance_id: String = str(row.get("npcInstanceId", "")).strip_edges()
|
|
if instance_id.is_empty():
|
|
continue
|
|
var telegraph: Variant = row.get("activeTelegraph", null)
|
|
if telegraph == null or not telegraph is Dictionary:
|
|
continue
|
|
if hud_state.has_method("has_active_windup"):
|
|
if bool(hud_state.call("has_active_windup", instance_id)):
|
|
return true
|
|
return false
|