Add enemy threat overlay
This commit is contained in:
@@ -1223,6 +1223,28 @@ func get_item_target_cells(unit_id: String, item_id: String) -> Array[Vector2i]:
|
||||
return _item_target_cells_from(unit, item)
|
||||
|
||||
|
||||
func get_threat_cells(source_team := TEAM_ENEMY) -> Array[Vector2i]:
|
||||
var result: Array[Vector2i] = []
|
||||
for unit in get_living_units(source_team):
|
||||
for cell in _unit_threat_cells(unit):
|
||||
if not result.has(cell):
|
||||
result.append(cell)
|
||||
return result
|
||||
|
||||
|
||||
func get_threatening_unit_names(cell: Vector2i, source_team := TEAM_ENEMY) -> Array[String]:
|
||||
var result: Array[String] = []
|
||||
if not is_inside(cell):
|
||||
return result
|
||||
for unit in get_living_units(source_team):
|
||||
if not _unit_threat_cells(unit).has(cell):
|
||||
continue
|
||||
var unit_name := str(unit.get("name", unit.get("id", "Unit")))
|
||||
if not result.has(unit_name):
|
||||
result.append(unit_name)
|
||||
return result
|
||||
|
||||
|
||||
func get_objective_cells() -> Array[Vector2i]:
|
||||
var result: Array[Vector2i] = []
|
||||
_collect_objective_cells(battle_conditions.get("victory", {}), result)
|
||||
@@ -1685,6 +1707,93 @@ func _movement_range_for_unit(unit: Dictionary) -> Array[Vector2i]:
|
||||
return result
|
||||
|
||||
|
||||
func _unit_threat_cells(unit: Dictionary) -> Array[Vector2i]:
|
||||
var result: Array[Vector2i] = []
|
||||
if unit.is_empty() or not unit.get("alive", false) or not unit.get("deployed", true):
|
||||
return result
|
||||
if not bool(unit.get("controllable", true)):
|
||||
return result
|
||||
|
||||
for cell in _unit_physical_threat_cells(unit):
|
||||
if not result.has(cell):
|
||||
result.append(cell)
|
||||
for cell in _unit_skill_threat_cells(unit):
|
||||
if not result.has(cell):
|
||||
result.append(cell)
|
||||
return result
|
||||
|
||||
|
||||
func _unit_threat_origins(unit: Dictionary) -> Array[Vector2i]:
|
||||
var result: Array[Vector2i] = []
|
||||
var origin: Vector2i = unit.get("pos", Vector2i(-1, -1))
|
||||
if not is_inside(origin):
|
||||
return result
|
||||
result.append(origin)
|
||||
for cell in _movement_range_for_unit(unit):
|
||||
if not result.has(cell):
|
||||
result.append(cell)
|
||||
return result
|
||||
|
||||
|
||||
func _unit_physical_threat_cells(unit: Dictionary) -> Array[Vector2i]:
|
||||
var result: Array[Vector2i] = []
|
||||
if _unit_has_action_lock(unit, "attack"):
|
||||
return result
|
||||
for origin in _unit_threat_origins(unit):
|
||||
for cell in _attack_cells_from(unit, origin):
|
||||
if not result.has(cell):
|
||||
result.append(cell)
|
||||
return result
|
||||
|
||||
|
||||
func _unit_skill_threat_cells(unit: Dictionary) -> Array[Vector2i]:
|
||||
var result: Array[Vector2i] = []
|
||||
if _unit_has_action_lock(unit, "skill"):
|
||||
return result
|
||||
if typeof(unit.get("skills", [])) != TYPE_ARRAY:
|
||||
return result
|
||||
for skill_id_value in unit.get("skills", []):
|
||||
var skill_id := str(skill_id_value)
|
||||
var skill := get_skill_def(skill_id)
|
||||
if skill.is_empty():
|
||||
continue
|
||||
if int(unit.get("mp", 0)) < int(skill.get("mp_cost", 0)):
|
||||
continue
|
||||
if not _skill_threatens_opponents(skill):
|
||||
continue
|
||||
for origin in _unit_threat_origins(unit):
|
||||
for cell in _skill_cells_from_origin(unit, skill, origin):
|
||||
if not result.has(cell):
|
||||
result.append(cell)
|
||||
return result
|
||||
|
||||
|
||||
func _skill_threatens_opponents(skill: Dictionary) -> bool:
|
||||
var target_rule := str(skill.get("target", "enemy"))
|
||||
if target_rule != "enemy" and target_rule != "any":
|
||||
return false
|
||||
var skill_kind := str(skill.get("kind", "damage"))
|
||||
if skill_kind == "damage":
|
||||
return true
|
||||
if skill_kind == "support":
|
||||
return _skill_has_harmful_support_effects(skill)
|
||||
return false
|
||||
|
||||
|
||||
func _skill_has_harmful_support_effects(skill: Dictionary) -> bool:
|
||||
for effect in skill.get("effects", []):
|
||||
if typeof(effect) != TYPE_DICTIONARY:
|
||||
continue
|
||||
var effect_type := str(effect.get("type", ""))
|
||||
if effect_type == "damage_over_time" and int(effect.get("amount", 0)) > 0:
|
||||
return true
|
||||
if effect_type == "action_lock" and not str(effect.get("action", "")).strip_edges().is_empty():
|
||||
return true
|
||||
if effect_type == "stat_bonus" and int(effect.get("amount", 0)) < 0:
|
||||
return true
|
||||
return false
|
||||
|
||||
|
||||
func _attack_cells_from(unit: Dictionary, origin: Vector2i) -> Array[Vector2i]:
|
||||
var result: Array[Vector2i] = []
|
||||
var attack_range := int(unit.get("range", 1))
|
||||
@@ -1707,11 +1816,14 @@ func _is_in_attack_range(attacker: Dictionary, target_cell: Vector2i) -> bool:
|
||||
|
||||
|
||||
func _skill_cells_from(unit: Dictionary, skill: Dictionary) -> Array[Vector2i]:
|
||||
return _skill_cells_from_origin(unit, skill, unit["pos"])
|
||||
|
||||
|
||||
func _skill_cells_from_origin(_unit: Dictionary, skill: Dictionary, origin: Vector2i) -> Array[Vector2i]:
|
||||
var result: Array[Vector2i] = []
|
||||
var range_pair := _skill_range_pair(skill)
|
||||
var max_range := int(range_pair["max"])
|
||||
var min_range := int(range_pair["min"])
|
||||
var origin: Vector2i = unit["pos"]
|
||||
for y in range(origin.y - max_range, origin.y + max_range + 1):
|
||||
for x in range(origin.x - max_range, origin.x + max_range + 1):
|
||||
var cell := Vector2i(x, y)
|
||||
|
||||
Reference in New Issue
Block a user