Show enemy AI reaction zones
This commit is contained in:
@@ -6428,6 +6428,8 @@ func _draw_overlays() -> void:
|
||||
_draw_objective_seal_marker(objective_rect)
|
||||
_draw_tactical_tile_overlay("objective", objective_rect, OBJECTIVE_OVERLAY_COLOR, UI_SEAL_RED, 0.56, 0.30, 6.0)
|
||||
|
||||
_draw_hovered_ai_zone_overlay()
|
||||
|
||||
for cell in threat_cells:
|
||||
var threat_rect := _rect_for_cell(cell)
|
||||
_draw_tactical_tile_overlay("attack", threat_rect, THREAT_OVERLAY_COLOR, THREAT_BORDER_COLOR, 0.30, 0.42, 6.0)
|
||||
@@ -6484,6 +6486,117 @@ func _draw_overlays() -> void:
|
||||
_draw_tactical_tile_overlay(hover_marker, hover_rect, hover_color, hover_color, 0.44, 0.22, 4.0)
|
||||
|
||||
|
||||
func _draw_hovered_ai_zone_overlay() -> void:
|
||||
var unit := _hovered_ai_zone_unit()
|
||||
if unit.is_empty():
|
||||
return
|
||||
var cells := _ai_zone_cells_for_unit(unit)
|
||||
if cells.is_empty():
|
||||
return
|
||||
var anchor := _ai_zone_anchor_for_unit(unit)
|
||||
var radius := _ai_zone_radius_for_unit(unit)
|
||||
var marker_key := _ai_zone_overlay_marker_key(unit)
|
||||
var fill := _ai_zone_overlay_fill_color(unit)
|
||||
var border := _ai_zone_overlay_border_color(unit)
|
||||
var fade_base := float(maxi(1, radius))
|
||||
for cell in cells:
|
||||
if not _cell_is_in_visible_bounds(cell):
|
||||
continue
|
||||
var distance := absi(cell.x - anchor.x) + absi(cell.y - anchor.y)
|
||||
var fade := 1.0 - clampf(float(distance) / fade_base, 0.0, 1.0) * 0.24
|
||||
var cell_fill := fill
|
||||
cell_fill.a *= fade
|
||||
var cell_border := border
|
||||
cell_border.a *= fade
|
||||
_draw_tactical_tile_overlay(marker_key, _rect_for_cell(cell), cell_fill, cell_border, 0.13 * fade, 0.36, 8.0)
|
||||
if state.is_inside(anchor) and _cell_is_in_visible_bounds(anchor):
|
||||
_draw_tactical_tile_overlay("target", _rect_for_cell(anchor), _ai_zone_anchor_fill_color(unit), _ai_zone_overlay_border_color(unit), 0.25, 0.40, 6.0)
|
||||
|
||||
|
||||
func _hovered_ai_zone_unit() -> Dictionary:
|
||||
if _is_input_locked() or not battle_started or not state.is_inside(hover_cell):
|
||||
return {}
|
||||
var unit := state.get_unit_at(hover_cell)
|
||||
if unit.is_empty() or str(unit.get("team", "")) != BattleState.TEAM_ENEMY:
|
||||
return {}
|
||||
if _ai_zone_radius_for_unit(unit) < 0:
|
||||
return {}
|
||||
if not state.is_inside(_ai_zone_anchor_for_unit(unit)):
|
||||
return {}
|
||||
return unit
|
||||
|
||||
|
||||
func _ai_zone_cells_for_unit(unit: Dictionary) -> Array[Vector2i]:
|
||||
var cells: Array[Vector2i] = []
|
||||
var radius := _ai_zone_radius_for_unit(unit)
|
||||
var anchor := _ai_zone_anchor_for_unit(unit)
|
||||
if radius < 0 or not state.is_inside(anchor):
|
||||
return cells
|
||||
for y in range(anchor.y - radius, anchor.y + radius + 1):
|
||||
for x in range(anchor.x - radius, anchor.x + radius + 1):
|
||||
var cell := Vector2i(x, y)
|
||||
if not state.is_inside(cell):
|
||||
continue
|
||||
if absi(cell.x - anchor.x) + absi(cell.y - anchor.y) <= radius:
|
||||
cells.append(cell)
|
||||
return cells
|
||||
|
||||
|
||||
func _ai_zone_anchor_for_unit(unit: Dictionary) -> Vector2i:
|
||||
var behavior := str(unit.get("ai_behavior", "")).strip_edges().to_lower()
|
||||
var fallback: Vector2i = unit.get("pos", Vector2i(-1, -1))
|
||||
var anchor: Vector2i = fallback
|
||||
if behavior == "guard":
|
||||
anchor = unit.get("ai_guard_anchor", fallback)
|
||||
elif behavior == "sentry":
|
||||
anchor = unit.get("ai_sentry_anchor", fallback)
|
||||
if not state.is_inside(anchor):
|
||||
return fallback
|
||||
return anchor
|
||||
|
||||
|
||||
func _ai_zone_radius_for_unit(unit: Dictionary) -> int:
|
||||
var behavior := str(unit.get("ai_behavior", "")).strip_edges().to_lower()
|
||||
if behavior == "guard":
|
||||
return max(0, int(unit.get("ai_guard_radius", 0)))
|
||||
if behavior == "sentry":
|
||||
return max(0, int(unit.get("ai_sentry_radius", 0)))
|
||||
return -1
|
||||
|
||||
|
||||
func _ai_zone_overlay_marker_key(unit: Dictionary) -> String:
|
||||
var behavior := str(unit.get("ai_behavior", "")).strip_edges().to_lower()
|
||||
if behavior == "guard":
|
||||
return "select"
|
||||
if behavior == "sentry" and bool(unit.get("ai_awake", false)):
|
||||
return "attack"
|
||||
return "move"
|
||||
|
||||
|
||||
func _ai_zone_overlay_fill_color(unit: Dictionary) -> Color:
|
||||
var behavior := str(unit.get("ai_behavior", "")).strip_edges().to_lower()
|
||||
if behavior == "guard":
|
||||
return Color(UI_OLD_BRONZE.r, UI_OLD_BRONZE.g, UI_OLD_BRONZE.b, 0.20)
|
||||
if behavior == "sentry" and bool(unit.get("ai_awake", false)):
|
||||
return Color(UI_SEAL_RED.r, UI_SEAL_RED.g, UI_SEAL_RED.b, 0.19)
|
||||
return Color(UI_MUTED_JADE.r, UI_MUTED_JADE.g, UI_MUTED_JADE.b, 0.20)
|
||||
|
||||
|
||||
func _ai_zone_anchor_fill_color(unit: Dictionary) -> Color:
|
||||
var color := _ai_zone_overlay_fill_color(unit)
|
||||
color.a = minf(color.a + 0.10, 0.34)
|
||||
return color
|
||||
|
||||
|
||||
func _ai_zone_overlay_border_color(unit: Dictionary) -> Color:
|
||||
var behavior := str(unit.get("ai_behavior", "")).strip_edges().to_lower()
|
||||
if behavior == "guard":
|
||||
return Color(UI_OLD_BRONZE.r, UI_OLD_BRONZE.g, UI_OLD_BRONZE.b, 0.42)
|
||||
if behavior == "sentry" and bool(unit.get("ai_awake", false)):
|
||||
return Color(UI_SEAL_RED.r, UI_SEAL_RED.g, UI_SEAL_RED.b, 0.38)
|
||||
return Color(UI_MUTED_JADE.r, UI_MUTED_JADE.g, UI_MUTED_JADE.b, 0.40)
|
||||
|
||||
|
||||
func _draw_units() -> void:
|
||||
for unit in state.units:
|
||||
if not unit.get("alive", false) or not unit.get("deployed", true):
|
||||
|
||||
Reference in New Issue
Block a user