diff --git a/game/operation/operation.py b/game/operation/operation.py index b0851309..a035b808 100644 --- a/game/operation/operation.py +++ b/game/operation/operation.py @@ -82,6 +82,7 @@ class Operation: with open("resources/default_options.lua", "r") as f: options_dict = loads(f.read())["options"] + dcs.Mission.aaa_vehicle_group = aaa.aaa_vehicle_group self.current_mission = dcs.Mission(terrain) if is_quick: self.quick_mission = self.current_mission diff --git a/gen/aaa.py b/gen/aaa.py index 3aaf999a..e2311254 100644 --- a/gen/aaa.py +++ b/gen/aaa.py @@ -1,3 +1,5 @@ +import random +import math from .conflictgen import * from .naming import * @@ -9,6 +11,266 @@ EXTRA_AA_MAX_DISTANCE = 150000 EXTRA_AA_POSITION_FROM_CP = 550 +def determine_positions(position, heading, num_units, launcher_distance, coverage=90): + """ + Given a position on the map, array a group of units in a circle a uniform distance from the unit + :param position: + position of the center unit + :param heading: + the direction the units should be arranged toward if coverage is not 360 + :param num_units: + number of units to play on the circle + :param launcher_distance: + distance the units should be from the center unit + :param coverage: + 0-360 + :return: + list of tuples representing each unit location + [(pos_x, pos_y, heading), ...] + """ + if coverage == 360: + # one of the positions is shared :'( + outer_offset = coverage / num_units + else: + outer_offset = coverage / (num_units - 1) + + positions = [] + + if num_units % 2 == 0: + current_offset = heading - ((coverage / (num_units - 1)) / 2) + else: + current_offset = heading + current_offset -= outer_offset * (math.ceil(num_units / 2) - 1) + for x in range(1, num_units + 1): + positions.append(( + position.x + launcher_distance * math.cos(math.radians(current_offset)), + position.y + launcher_distance * math.sin(math.radians(current_offset)), + current_offset, + )) + current_offset += outer_offset + return positions + + +def aaa_vehicle_group(self, country, name, _type: unittype.VehicleType, position: mapping.Point, + heading=0, group_size=1, + formation=unitgroup.VehicleGroup.Formation.Line, + move_formation: PointAction=PointAction.OffRoad): + """ + Override the default vehicle group so that our group can contain a mix of units (which is required for advanced + SAM sites) + For further docstrings, see the built-in function + """ + vg = unitgroup.VehicleGroup(self.next_group_id(), self.string(name)) + + for i in range(1, group_size + 1): + heading = randint(0, 359) + if _type == AirDefence.SAM_SA_3_S_125_LN_5P73: + # 4 launchers (180 degrees all facing the same direction), 1 SR, 1 TR + num_launchers = 4 + # search radar + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SR_P_19, + ) + v.position.x = position.x + v.position.y = position.y + (i - 1) * 20 + v.heading = heading + vg.add_unit(v) + # track radar + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SA_3_S_125_TR_SNR, + ) + + center_x = position.x + randint(20, 40) + center_y = position.y + (i - 1) * 20 + + v.position.x = center_x + v.position.y = center_y + v.heading = heading + vg.add_unit(v) + plop_positions = determine_positions( + position, + heading, + num_launchers, + launcher_distance=100, + coverage=180, + ) + for x in range(0, num_launchers): + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SA_3_S_125_LN_5P73, + ) + + v.position.x = plop_positions[x][0] + v.position.y = plop_positions[x][1] + v.heading = plop_positions[x][2] + vg.add_unit(v) + + elif _type == AirDefence.SAM_SA_6_Kub_LN_2P25: + # 6 launchers (360 degree coverage) + # 1 S/TR + # search/track radar + num_launchers = 6 + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SA_6_Kub_STR_9S91, + ) + v.position.x = position.x + v.position.y = position.y + (i - 1) * 20 + v.heading = heading + vg.add_unit(v) + + plop_positions = determine_positions( + position, + heading, + num_launchers, + launcher_distance=100, + coverage=360, + ) + for x in range(0, num_launchers): + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SA_6_Kub_LN_2P25, + ) + + v.position.x = plop_positions[x][0] + v.position.y = plop_positions[x][1] + v.heading = plop_positions[x][2] + vg.add_unit(v) + elif _type == AirDefence.SAM_SA_10_S_300PS_LN_5P85C: + # 8 launchers - 4 directions, two in each direction + # 1 SR (offset) + # 1 TR (center) + # search radar + num_launchers = 8 + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SA_10_S_300PS_SR_5N66M, + ) + v.position.x = position.x + v.position.y = position.y + (i - 1) * 20 + v.heading = heading + vg.add_unit(v) + # track radar + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SA_10_S_300PS_TR_30N6, + ) + + center_x = position.x + randint(20, 40) + center_y = position.y + (i - 1) * 20 + + v.position.x = center_x + v.position.y = center_y + v.heading = heading + vg.add_unit(v) + # command center + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SA_10_S_300PS_CP_54K6, + ) + + center_x = position.x + randint(40, 60) + center_y = position.y + (i - 1) * 20 + + v.position.x = center_x + v.position.y = center_y + v.heading = heading + vg.add_unit(v) + + plop_positions = determine_positions( + position, + heading, + num_launchers, + launcher_distance=150, + coverage=360, + ) + for x in range(0, num_launchers): + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SA_10_S_300PS_LN_5P85C, + ) + + v.position.x = plop_positions[x][0] + v.position.y = plop_positions[x][1] + v.heading = plop_positions[x][2] + vg.add_unit(v) + + elif _type == AirDefence.SAM_SA_10_S_300PS_CP_54K6: + # 8 launchers - 4 directions, two in each direction + # 1 SR (offset) + # 1 TR (center) + # search radar + num_launchers = 8 + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SA_10_S_300PS_SR_64H6E, + ) + v.position.x = position.x + v.position.y = position.y + (i - 1) * 20 + v.heading = heading + vg.add_unit(v) + # track radar + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SA_10_S_300PS_TR_30N6, + ) + + center_x = position.x + randint(20, 40) + center_y = position.y + (i - 1) * 20 + + v.position.x = center_x + v.position.y = center_y + v.heading = heading + vg.add_unit(v) + # command center + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SA_10_S_300PS_CP_54K6, + ) + + center_x = position.x + randint(40, 60) + center_y = position.y + (i - 1) * 20 + + v.position.x = center_x + v.position.y = center_y + v.heading = heading + vg.add_unit(v) + + plop_positions = determine_positions( + position, + heading, + num_units=num_launchers, + launcher_distance=150, + coverage=360, + ) + for x in range(0, num_launchers): + v = self.vehicle( + name + " Unit #{nr}".format(nr=i), + AirDefence.SAM_SA_10_S_300PS_LN_5P85D, + ) + + v.position.x = plop_positions[x][0] + v.position.y = plop_positions[x][1] + v.heading = plop_positions[x][2] + vg.add_unit(v) + else: + v = self.vehicle(name + " Unit #{nr}".format(nr=i), _type) + v.position.x = position.x + v.position.y = position.y + (i - 1) * 20 + v.heading = heading + vg.add_unit(v) + + wp = vg.add_waypoint(vg.units[0].position, move_formation, 0) + wp.ETA_locked = True + if _type.eplrs: + wp.tasks.append(task.EPLRS(self.next_eplrs("vehicle"))) + + country.add_vehicle_group(vg) + return vg + + class AAConflictGenerator: def __init__(self, mission: Mission, conflict: Conflict): self.m = mission @@ -30,7 +292,7 @@ class AAConflictGenerator: distance = randint(self.conflict.size * DISTANCE_FACTOR[0], self.conflict.size * DISTANCE_FACTOR[1]) p = self.conflict.position.point_from_heading(radial, distance) - self.m.vehicle_group( + self.m.aaa_vehicle_group( country=self.conflict.defenders_side, name=namegen.next_unit_name(self.conflict.defenders_side, type), _type=type,