mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Improve Ground Unit Behavior
* Prevent spinning units * Prevent units spawning in exclusion zone * Prevent units from moving into exclusion zone
This commit is contained in:
parent
817d6a0e15
commit
c8e71d269b
@ -9,6 +9,9 @@ from itertools import tee
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Dict, Iterator, List, Optional, Set, Tuple, Union, cast
|
from typing import Any, Dict, Iterator, List, Optional, Set, Tuple, Union, cast
|
||||||
|
|
||||||
|
from shapely import geometry
|
||||||
|
from shapely import ops
|
||||||
|
|
||||||
from dcs import Mission
|
from dcs import Mission
|
||||||
from dcs.countries import (
|
from dcs.countries import (
|
||||||
CombinedJointTaskForcesBlue,
|
CombinedJointTaskForcesBlue,
|
||||||
@ -472,6 +475,32 @@ class ConflictTheater:
|
|||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def nearest_land_pos(self, point: Point, extend_dist: int = 50) -> Point:
|
||||||
|
"""Returns the nearest point inside a land exclusion zone from point
|
||||||
|
`extend_dist` determines how far inside the zone the point should be placed"""
|
||||||
|
if self.is_on_land(point):
|
||||||
|
return point
|
||||||
|
point = geometry.Point(point.x, point.y)
|
||||||
|
nearest_points = []
|
||||||
|
for inclusion_zone in self.landmap[0]:
|
||||||
|
nearest_pair = ops.nearest_points(point, inclusion_zone)
|
||||||
|
nearest_points.append(nearest_pair[1])
|
||||||
|
min_distance = None # type: Optional[geometry.Point]
|
||||||
|
nearest_point = None # type: Optional[geometry.Point]
|
||||||
|
for pt in nearest_points:
|
||||||
|
distance = point.distance(pt)
|
||||||
|
if not min_distance or distance < min_distance:
|
||||||
|
min_distance = distance
|
||||||
|
nearest_point = pt
|
||||||
|
assert isinstance(nearest_point, geometry.Point)
|
||||||
|
point = Point(point.x, point.y)
|
||||||
|
nearest_point = Point(nearest_point.x, nearest_point.y)
|
||||||
|
new_point = point.point_from_heading(
|
||||||
|
point.heading_between_point(nearest_point),
|
||||||
|
point.distance_to_point(nearest_point) + extend_dist
|
||||||
|
)
|
||||||
|
return new_point
|
||||||
|
|
||||||
def player_points(self) -> List[ControlPoint]:
|
def player_points(self) -> List[ControlPoint]:
|
||||||
return [point for point in self.controlpoints if point.captured]
|
return [point for point in self.controlpoints if point.captured]
|
||||||
|
|
||||||
|
|||||||
53
gen/armor.py
53
gen/armor.py
@ -177,7 +177,12 @@ class GroundConflictGenerator:
|
|||||||
forward_heading: int
|
forward_heading: int
|
||||||
) -> None:
|
) -> None:
|
||||||
|
|
||||||
infantry_position = group.points[0].position.random_point_within(250, 50)
|
infantry_position = self.conflict.find_ground_position(
|
||||||
|
group.points[0].position.random_point_within(250, 50),
|
||||||
|
500,
|
||||||
|
forward_heading,
|
||||||
|
self.conflict.theater
|
||||||
|
)
|
||||||
|
|
||||||
if side == self.conflict.attackers_country:
|
if side == self.conflict.attackers_country:
|
||||||
cp = self.conflict.from_cp
|
cp = self.conflict.from_cp
|
||||||
@ -236,7 +241,7 @@ class GroundConflictGenerator:
|
|||||||
"""Setting a waypoint close to the spawn position allows the group to reform gracefully
|
"""Setting a waypoint close to the spawn position allows the group to reform gracefully
|
||||||
rather than spin
|
rather than spin
|
||||||
"""
|
"""
|
||||||
reform_point = dcs_group.position.point_from_heading(forward_heading, 30)
|
reform_point = dcs_group.position.point_from_heading(forward_heading, 50)
|
||||||
dcs_group.add_waypoint(reform_point)
|
dcs_group.add_waypoint(reform_point)
|
||||||
|
|
||||||
def _plan_artillery_action(
|
def _plan_artillery_action(
|
||||||
@ -326,7 +331,10 @@ class GroundConflictGenerator:
|
|||||||
-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK
|
-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
dcs_group.add_waypoint(target.points[0].position + rand_offset, PointAction.OffRoad)
|
target_point = self.conflict.theater.nearest_land_pos(
|
||||||
|
target.points[0].position + rand_offset
|
||||||
|
)
|
||||||
|
dcs_group.add_waypoint(target_point)
|
||||||
dcs_group.points[2].tasks.append(AttackGroup(target.id))
|
dcs_group.points[2].tasks.append(AttackGroup(target.id))
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -334,7 +342,9 @@ class GroundConflictGenerator:
|
|||||||
<=
|
<=
|
||||||
AGGRESIVE_MOVE_DISTANCE
|
AGGRESIVE_MOVE_DISTANCE
|
||||||
):
|
):
|
||||||
attack_point = to_cp.position.random_point_within(500, 0)
|
attack_point = self.conflict.theater.nearest_land_pos(
|
||||||
|
to_cp.position.random_point_within(500, 0)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
attack_point = self.find_offensive_point(
|
attack_point = self.find_offensive_point(
|
||||||
dcs_group,
|
dcs_group,
|
||||||
@ -347,7 +357,9 @@ class GroundConflictGenerator:
|
|||||||
# If the enemy base is close enough, the units will attack the base
|
# If the enemy base is close enough, the units will attack the base
|
||||||
if to_cp.position.distance_to_point(
|
if to_cp.position.distance_to_point(
|
||||||
dcs_group.points[0].position) <= BREAKTHROUGH_OFFENSIVE_DISTANCE:
|
dcs_group.points[0].position) <= BREAKTHROUGH_OFFENSIVE_DISTANCE:
|
||||||
attack_point = to_cp.position.random_point_within(500, 0)
|
attack_point = self.conflict.theater.nearest_land_pos(
|
||||||
|
to_cp.position.random_point_within(500, 0)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
attack_point = self.find_offensive_point(dcs_group, forward_heading, BREAKTHROUGH_OFFENSIVE_DISTANCE)
|
attack_point = self.find_offensive_point(dcs_group, forward_heading, BREAKTHROUGH_OFFENSIVE_DISTANCE)
|
||||||
dcs_group.add_waypoint(attack_point, PointAction.OffRoad)
|
dcs_group.add_waypoint(attack_point, PointAction.OffRoad)
|
||||||
@ -364,10 +376,15 @@ class GroundConflictGenerator:
|
|||||||
RANDOM_OFFSET_ATTACK
|
RANDOM_OFFSET_ATTACK
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
dcs_group.add_waypoint(target.points[0].position+rand_offset, PointAction.OffRoad)
|
target_point = self.conflict.theater.nearest_land_pos(
|
||||||
|
target.points[0].position+rand_offset
|
||||||
|
)
|
||||||
|
dcs_group.add_waypoint(target_point, PointAction.OffRoad)
|
||||||
dcs_group.points[i + 1].tasks.append(AttackGroup(target.id))
|
dcs_group.points[i + 1].tasks.append(AttackGroup(target.id))
|
||||||
if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
|
if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
|
||||||
attack_point = to_cp.position.random_point_within(500, 0)
|
attack_point = self.conflict.theater.nearest_land_pos(
|
||||||
|
to_cp.position.random_point_within(500, 0)
|
||||||
|
)
|
||||||
dcs_group.add_waypoint(attack_point)
|
dcs_group.add_waypoint(attack_point)
|
||||||
|
|
||||||
if stance != CombatStance.RETREAT:
|
if stance != CombatStance.RETREAT:
|
||||||
@ -390,7 +407,7 @@ class GroundConflictGenerator:
|
|||||||
if stance in [CombatStance.AGGRESSIVE, CombatStance.BREAKTHROUGH, CombatStance.ELIMINATION]:
|
if stance in [CombatStance.AGGRESSIVE, CombatStance.BREAKTHROUGH, CombatStance.ELIMINATION]:
|
||||||
# APC & ATGM will never move too much forward, but will follow along any offensive
|
# APC & ATGM will never move too much forward, but will follow along any offensive
|
||||||
if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
|
if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
|
||||||
attack_point = to_cp.position.random_point_within(500, 0)
|
attack_point = self.conflict.theater.nearest_land_pos(to_cp.position.random_point_within(500, 0))
|
||||||
else:
|
else:
|
||||||
attack_point = self.find_offensive_point(dcs_group, forward_heading, AGGRESIVE_MOVE_DISTANCE)
|
attack_point = self.find_offensive_point(dcs_group, forward_heading, AGGRESIVE_MOVE_DISTANCE)
|
||||||
dcs_group.add_waypoint(attack_point, PointAction.OffRoad)
|
dcs_group.add_waypoint(attack_point, PointAction.OffRoad)
|
||||||
@ -491,12 +508,9 @@ class GroundConflictGenerator:
|
|||||||
:return: dcs.mapping.Point object with the desired position
|
:return: dcs.mapping.Point object with the desired position
|
||||||
"""
|
"""
|
||||||
desired_point = dcs_group.points[0].position.point_from_heading(heading_sum(frontline_heading, +180), distance)
|
desired_point = dcs_group.points[0].position.point_from_heading(heading_sum(frontline_heading, +180), distance)
|
||||||
return Conflict.find_ground_position(
|
if self.conflict.theater.is_on_land(desired_point):
|
||||||
desired_point,
|
return desired_point
|
||||||
1000000,
|
return self.conflict.theater.nearest_land_pos(desired_point)
|
||||||
heading_sum(frontline_heading, 90),
|
|
||||||
self.conflict.theater,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def find_offensive_point(
|
def find_offensive_point(
|
||||||
@ -513,12 +527,9 @@ class GroundConflictGenerator:
|
|||||||
:return: dcs.mapping.Point object with the desired position
|
:return: dcs.mapping.Point object with the desired position
|
||||||
"""
|
"""
|
||||||
desired_point = dcs_group.points[0].position.point_from_heading(frontline_heading, distance)
|
desired_point = dcs_group.points[0].position.point_from_heading(frontline_heading, distance)
|
||||||
return Conflict.find_ground_position(
|
if self.conflict.theater.is_on_land(desired_point):
|
||||||
desired_point,
|
return desired_point
|
||||||
1000000,
|
return self.conflict.theater.nearest_land_pos(desired_point)
|
||||||
heading_sum(frontline_heading, 90),
|
|
||||||
self.conflict.theater,
|
|
||||||
)
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def find_n_nearest_enemy_groups(
|
def find_n_nearest_enemy_groups(
|
||||||
@ -681,7 +692,7 @@ class GroundConflictGenerator:
|
|||||||
group = self.mission.vehicle_group(
|
group = self.mission.vehicle_group(
|
||||||
side,
|
side,
|
||||||
namegen.next_unit_name(side, cp.id, unit), unit,
|
namegen.next_unit_name(side, cp.id, unit), unit,
|
||||||
position=self._group_point(at, distance_from_frontline),
|
position=at,
|
||||||
group_size=count,
|
group_size=count,
|
||||||
heading=heading,
|
heading=heading,
|
||||||
move_formation=move_formation)
|
move_formation=move_formation)
|
||||||
|
|||||||
@ -91,8 +91,12 @@ class Conflict:
|
|||||||
return pos
|
return pos
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def find_ground_position(cls, initial: Point, max_distance: int, heading: int, theater: ConflictTheater) -> Point:
|
def find_ground_position(cls, initial: Point, max_distance: int, heading: int, theater: ConflictTheater, coerce=True) -> Optional[Point]:
|
||||||
"""Finds the nearest valid ground position along a provided heading and it's inverse"""
|
"""
|
||||||
|
Finds the nearest valid ground position along a provided heading and it's inverse up to max_distance.
|
||||||
|
`coerce=True` will return the closest land position to `initial` regardless of heading or distance
|
||||||
|
`coerce=False` will return None if a point isn't found
|
||||||
|
"""
|
||||||
pos = initial
|
pos = initial
|
||||||
if theater.is_on_land(pos):
|
if theater.is_on_land(pos):
|
||||||
return pos
|
return pos
|
||||||
@ -101,5 +105,9 @@ class Conflict:
|
|||||||
if theater.is_on_land(pos):
|
if theater.is_on_land(pos):
|
||||||
return pos
|
return pos
|
||||||
pos = initial.point_from_heading(opposite_heading(heading), distance)
|
pos = initial.point_from_heading(opposite_heading(heading), distance)
|
||||||
|
if coerce:
|
||||||
|
pos = theater.nearest_land_pos(initial)
|
||||||
|
return pos
|
||||||
logging.error("Didn't find ground position ({})!".format(initial))
|
logging.error("Didn't find ground position ({})!".format(initial))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user