FARP spawn for helis on frontline cas; updated ground object placements

This commit is contained in:
Vasyl Horbachenko 2018-09-11 03:12:33 +03:00
parent ca521e7e51
commit d31876b65e
8 changed files with 97 additions and 54 deletions

View File

@ -358,7 +358,8 @@ PLANE_PAYLOAD_OVERRIDES = {
}, },
Ka_50: { Ka_50: {
"*": "12x9A4172, 40xS-8", CAS: "12x9A4172, 40xS-8",
GroundAttack: "12x9A4172, 40xS-8",
}, },
M_2000C: { M_2000C: {
@ -483,6 +484,27 @@ def assigned_units_from(d: PlaneDict) -> AssignedUnitsDict:
return {k: (v, 0) for k, v in d.items()} return {k: (v, 0) for k, v in d.items()}
def assignedunits_split_to_count(dict: AssignedUnitsDict, count: int):
buffer_dict = {}
for unit_type, (unit_count, client_count) in dict.items():
for _ in range(unit_count):
new_count, new_client_count = buffer_dict.get(unit_type, (0, 0))
new_count += 1
if client_count > 0:
new_client_count += 1
client_count -= 1
buffer_dict[unit_type] = new_count, new_client_count
if new_count >= count:
yield buffer_dict
buffer_dict = {}
if len(buffer_dict):
yield buffer_dict
def unitdict_from(fd: AssignedUnitsDict) -> Dict: def unitdict_from(fd: AssignedUnitsDict) -> Dict:
return {k: v1 for k, (v1, v2) in fd.items()} return {k: v1 for k, (v1, v2) in fd.items()}

View File

@ -2,7 +2,7 @@ import typing
import logging import logging
from dcs.unittype import UnitType from dcs.unittype import UnitType
from dcs.task import Task from dcs.task import *
from dcs.unittype import UnitType from dcs.unittype import UnitType
from game import * from game import *

View File

@ -39,12 +39,15 @@ class FrontlineAttackOperation(Operation):
def generate(self): def generate(self):
self.armorgen.generate_vec(self.attackers, self.target) self.armorgen.generate_vec(self.attackers, self.target)
planes_flights = {k: v for k, v in self.strikegroup.items() if k in plane_map} planes_flights = {k: v for k, v in self.strikegroup.items() if k in plane_map.values()}
self.airgen.generate_cas_strikegroup(*assigned_units_split(planes_flights), at=self.attackers_starting_position) self.airgen.generate_cas_strikegroup(*assigned_units_split(planes_flights), at=self.attackers_starting_position)
heli_flights = {k: v for k, v in self.strikegroup.items() if k in helicopters.helicopter_map} heli_flights = {k: v for k, v in self.strikegroup.items() if k in helicopters.helicopter_map.values()}
if heli_flights: if heli_flights:
self.airgen.generate_cas_strikegroup(*assigned_units_split(heli_flights), at=self.groundobjectgen.generate_farp()) self.briefinggen.append_frequency("FARP", "127.5 MHz AM")
for farp, dict in zip(self.groundobjectgen.generate_farps(sum([x[0] for x in heli_flights.values()])),
db.assignedunits_split_to_count(heli_flights, self.groundobjectgen.FARP_CAPACITY)):
self.airgen.generate_cas_strikegroup(*assigned_units_split(dict), at=farp, escort=False)
self.briefinggen.title = "Frontline CAS" self.briefinggen.title = "Frontline CAS"
self.briefinggen.description = "Provide CAS for the ground forces attacking enemy lines. Operation will be considered successful if total number of enemy units will be lower than your own by a factor of 1.5 (i.e. with 12 units from both sides, enemy forces need to be reduced to at least 8), meaning that you (and, probably, your wingmans) should concentrate on destroying the enemy units. Target base strength will be lowered as a result. Be advised that your flight will not attack anything until you explicitly tell them so by comms menu." self.briefinggen.description = "Provide CAS for the ground forces attacking enemy lines. Operation will be considered successful if total number of enemy units will be lower than your own by a factor of 1.5 (i.e. with 12 units from both sides, enemy forces need to be reduced to at least 8), meaning that you (and, probably, your wingmans) should concentrate on destroying the enemy units. Target base strength will be lowered as a result. Be advised that your flight will not attack anything until you explicitly tell them so by comms menu."

View File

@ -5,6 +5,7 @@ from dcs.mission import *
DISTANCE_FACTOR = 0.5, 1 DISTANCE_FACTOR = 0.5, 1
EXTRA_AA_MIN_DISTANCE = 35000 EXTRA_AA_MIN_DISTANCE = 35000
EXTRA_AA_MAX_DISTANCE = 150000
EXTRA_AA_POSITION_FROM_CP = 550 EXTRA_AA_POSITION_FROM_CP = 550
@ -58,7 +59,9 @@ class ExtraAAConflictGenerator:
if cp.position.distance_to_point(self.conflict.from_cp.position) < EXTRA_AA_MIN_DISTANCE: if cp.position.distance_to_point(self.conflict.from_cp.position) < EXTRA_AA_MIN_DISTANCE:
continue continue
print("generated extra aa for {}".format(cp)) if cp.position.distance_to_point(self.conflict.position) > EXTRA_AA_MAX_DISTANCE:
continue
country_name = cp.captured and self.player_name or self.enemy_name country_name = cp.captured and self.player_name or self.enemy_name
position = cp.position.point_from_heading(0, EXTRA_AA_POSITION_FROM_CP) position = cp.position.point_from_heading(0, EXTRA_AA_POSITION_FROM_CP)

View File

@ -112,6 +112,7 @@ class AircraftConflictGenerator:
group.units[idx].set_client() group.units[idx].set_client()
group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire)) group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire))
group.set_frequency(251.0)
def _generate_at_airport(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, airport: Airport = None) -> FlyingGroup: def _generate_at_airport(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, airport: Airport = None) -> FlyingGroup:
assert count > 0 assert count > 0
@ -155,11 +156,11 @@ class AircraftConflictGenerator:
start_type=self._start_type(), start_type=self._start_type(),
group_size=count) group_size=count)
def _generate_at_carrier(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: ShipGroup) -> FlyingGroup: def _generate_at_group(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: typing.Union[ShipGroup, StaticGroup]) -> FlyingGroup:
assert count > 0 assert count > 0
assert unit is not None assert unit is not None
logging.info("airgen: {} for {} at carrier {}".format(unit_type, side.id, at)) logging.info("airgen: {} for {} at unit {}".format(unit_type, side.id, at))
return self.m.flight_group_from_unit( return self.m.flight_group_from_unit(
country=side, country=side,
name=name, name=name,
@ -172,10 +173,10 @@ class AircraftConflictGenerator:
def _generate_group(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: db.StartingPosition): def _generate_group(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, at: db.StartingPosition):
if isinstance(at, Point): if isinstance(at, Point):
return self._generate_inflight(name, side, unit_type, count, client_count, at) return self._generate_inflight(name, side, unit_type, count, client_count, at)
elif isinstance(at, ShipGroup): elif isinstance(at, Group):
takeoff_ban = unit_type in db.CARRIER_TAKEOFF_BAN takeoff_ban = unit_type in db.CARRIER_TAKEOFF_BAN
if not takeoff_ban: if not takeoff_ban:
return self._generate_at_carrier(name, side, unit_type, count, client_count, at) return self._generate_at_group(name, side, unit_type, count, client_count, at)
else: else:
return self._generate_inflight(name, side, unit_type, count, client_count, at.position) return self._generate_inflight(name, side, unit_type, count, client_count, at.position)
elif issubclass(at, Airport): elif issubclass(at, Airport):
@ -192,14 +193,16 @@ class AircraftConflictGenerator:
assert False assert False
def _rtb_for(self, group: FlyingGroup, cp: ControlPoint, at: db.StartingPosition = None): def _rtb_for(self, group: FlyingGroup, cp: ControlPoint, at: db.StartingPosition = None):
group.add_waypoint(cp.position, RTB_ALTITUDE) if not at:
at = cp.at
if isinstance(cp.at, Point): if isinstance(at, Point):
pass group.add_waypoint(at, RTB_ALTITUDE)
elif isinstance(cp.at, ShipGroup): elif isinstance(at, Group):
pass group.add_waypoint(at.position, RTB_ALTITUDE)
elif issubclass(cp.at, Airport): elif issubclass(at, Airport):
group.land_at(cp.at) group.add_waypoint(at.position, RTB_ALTITUDE)
group.land_at(at)
def _at_position(self, at) -> Point: def _at_position(self, at) -> Point:
if isinstance(at, Point): if isinstance(at, Point):
@ -243,8 +246,8 @@ class AircraftConflictGenerator:
groups.append(group) groups.append(group)
return groups return groups
def generate_cas_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): def generate_cas_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None, escort=True):
assert len(self.escort_targets) == 0 assert not escort or len(self.escort_targets) == 0
for flying_type, count, client_count in self._split_to_groups(attackers, clients): for flying_type, count, client_count in self._split_to_groups(attackers, clients):
group = self._generate_group( group = self._generate_group(
@ -261,11 +264,12 @@ class AircraftConflictGenerator:
group.task = CAS.name group.task = CAS.name
self._setup_group(group, CAS, client_count) self._setup_group(group, CAS, client_count)
if escort:
self.escort_targets.append((group, group.points.index(waypoint))) self.escort_targets.append((group, group.points.index(waypoint)))
self._rtb_for(group, self.conflict.from_cp, at) self._rtb_for(group, self.conflict.from_cp, at)
def generate_ground_attack_strikegroup(self, strikegroup: db.PlaneDict, clients: db.PlaneDict, targets: typing.List[typing.Tuple[str, Point]], at: db.StartingPosition = None): def generate_ground_attack_strikegroup(self, strikegroup: db.PlaneDict, clients: db.PlaneDict, targets: typing.List[typing.Tuple[str, Point]], at: db.StartingPosition = None, escort=True):
assert len(self.escort_targets) == 0 assert not escort or len(self.escort_targets) == 0
for flying_type, count, client_count in self._split_to_groups(strikegroup, clients): for flying_type, count, client_count in self._split_to_groups(strikegroup, clients):
group = self._generate_group( group = self._generate_group(
@ -285,11 +289,12 @@ class AircraftConflictGenerator:
group.task = GroundAttack.name group.task = GroundAttack.name
self._setup_group(group, GroundAttack, client_count) self._setup_group(group, GroundAttack, client_count)
if escort:
self.escort_targets.append((group, group.points.index(escort_until_waypoint))) self.escort_targets.append((group, group.points.index(escort_until_waypoint)))
self._rtb_for(group, self.conflict.from_cp, at) self._rtb_for(group, self.conflict.from_cp, at)
def generate_defenders_cas(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): def generate_defenders_cas(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None, escort=True):
assert len(self.escort_targets) == 0 assert not escort or len(self.escort_targets) == 0
for flying_type, count, client_count in self._split_to_groups(defenders, clients): for flying_type, count, client_count in self._split_to_groups(defenders, clients):
group = self._generate_group( group = self._generate_group(
@ -310,11 +315,12 @@ class AircraftConflictGenerator:
group.task = CAS.name group.task = CAS.name
self._setup_group(group, CAS, client_count) self._setup_group(group, CAS, client_count)
if escort:
self.escort_targets.append((group, group.points.index(waypoint))) self.escort_targets.append((group, group.points.index(waypoint)))
self._rtb_for(group, self.conflict.to_cp, at) self._rtb_for(group, self.conflict.to_cp, at)
def generate_ship_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, target_groups: typing.Collection[ShipGroup], at: db.StartingPosition = None): def generate_ship_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, target_groups: typing.Collection[ShipGroup], at: db.StartingPosition = None, escort=True):
assert len(self.escort_targets) == 0 assert not escort or len(self.escort_targets) == 0
for flying_type, count, client_count in self._split_to_groups(attackers, clients): for flying_type, count, client_count in self._split_to_groups(attackers, clients):
group = self._generate_group( group = self._generate_group(
@ -331,6 +337,7 @@ class AircraftConflictGenerator:
group.task = AntishipStrike.name group.task = AntishipStrike.name
self._setup_group(group, AntishipStrike, client_count) self._setup_group(group, AntishipStrike, client_count)
if escort:
self.escort_targets.append((group, group.points.index(wayp))) self.escort_targets.append((group, group.points.index(wayp)))
self._rtb_for(group, self.conflict.from_cp, at) self._rtb_for(group, self.conflict.from_cp, at)
@ -413,8 +420,8 @@ class AircraftConflictGenerator:
self._setup_group(group, CAP, client_count) self._setup_group(group, CAP, client_count)
self._rtb_for(group, self.conflict.to_cp, at) self._rtb_for(group, self.conflict.to_cp, at)
def generate_transport(self, transport: db.PlaneDict, destination: Airport): def generate_transport(self, transport: db.PlaneDict, destination: Airport, escort=True):
assert len(self.escort_targets) == 0 assert not escort or len(self.escort_targets) == 0
for flying_type, count, client_count in self._split_to_groups(transport): for flying_type, count, client_count in self._split_to_groups(transport):
group = self._generate_group( group = self._generate_group(
@ -426,8 +433,8 @@ class AircraftConflictGenerator:
at=self._group_point(self.conflict.air_defenders_location)) at=self._group_point(self.conflict.air_defenders_location))
waypoint = group.add_waypoint(destination.position.random_point_within(0, 0), TRANSPORT_LANDING_ALT) waypoint = group.add_waypoint(destination.position.random_point_within(0, 0), TRANSPORT_LANDING_ALT)
if escort:
self.escort_targets.append((group, group.points.index(waypoint))) self.escort_targets.append((group, group.points.index(waypoint)))
group.task = Transport.name group.task = Transport.name
group.land_at(destination) group.land_at(destination)

View File

@ -22,20 +22,25 @@ CATEGORY_MAPPING = {
class GroundObjectsGenerator: class GroundObjectsGenerator:
FARP_CAPACITY = 4
def __init__(self, mission: Mission, conflict: Conflict, game): def __init__(self, mission: Mission, conflict: Conflict, game):
self.m = mission self.m = mission
self.conflict = conflict self.conflict = conflict
self.game = game self.game = game
def generate_farp(self) -> StaticGroup: def generate_farps(self, number_of_units=1) -> typing.Collection[StaticGroup]:
assert self.conflict.is_vector, "FARP could be generated only on frontline conflicts!" assert self.conflict.is_vector, "FARP could be generated only on frontline conflicts!"
position = self.conflict.find_ground_position(self.conflict.center.point_from_heading(self.conflict.opposite_heading, FARP_FRONTLINE_DISTANCE)) for i, _ in enumerate(range(0, number_of_units, self.FARP_CAPACITY)):
return self.m.static_group( heading = self.conflict.heading - 90
position = self.conflict.find_ground_position(self.conflict.center.point_from_heading(heading, FARP_FRONTLINE_DISTANCE), heading)
position = position.point_from_heading(0, i * 275)
yield self.m.farp(
country=self.m.country(self.game.player), country=self.m.country(self.game.player),
name="", name="FARP",
_type=Fortification.FARP_Command_Post, position=position,
position=position
) )
def generate(self): def generate(self):

View File

@ -72,32 +72,35 @@ class TriggersGenerator:
for coalition_name, coalition in self.mission.coalition.items(): for coalition_name, coalition in self.mission.coalition.items():
for country in coalition.countries.values(): for country in coalition.countries.values():
if coalition_name == player_coalition: if coalition_name == player_coalition:
for plane_group in country.plane_group + country.helicopter_group: for group in country.plane_group + country.helicopter_group:
if plane_group.task == AWACS.name or plane_group.task == Refueling.name: if group.task == AWACS.name or group.task == Refueling.name:
continue
if player_cp.position.distance_to_point(group.position) > PUSH_TRIGGER_SIZE * 3:
continue continue
regroup_heading = self.conflict.to_cp.position.heading_between_point(player_cp.position) regroup_heading = self.conflict.to_cp.position.heading_between_point(player_cp.position)
pos1 = plane_group.position.point_from_heading(regroup_heading, REGROUP_ZONE_DISTANCE) pos1 = group.position.point_from_heading(regroup_heading, REGROUP_ZONE_DISTANCE)
pos2 = plane_group.position.point_from_heading(regroup_heading, REGROUP_ZONE_DISTANCE+5000) pos2 = group.position.point_from_heading(regroup_heading, REGROUP_ZONE_DISTANCE+5000)
w1 = plane_group.add_waypoint(pos1, REGROUP_ALT) w1 = group.add_waypoint(pos1, REGROUP_ALT)
w2 = plane_group.add_waypoint(pos2, REGROUP_ALT) w2 = group.add_waypoint(pos2, REGROUP_ALT)
plane_group.points.remove(w1) group.points.remove(w1)
plane_group.points.remove(w2) group.points.remove(w2)
plane_group.points.insert(1, w2) group.points.insert(1, w2)
plane_group.points.insert(1, w1) group.points.insert(1, w1)
w1.tasks.append(Silence(True)) w1.tasks.append(Silence(True))
switch_waypoint_task = ControlledTask(SwitchWaypoint(from_waypoint=3, to_waypoint=2)) switch_waypoint_task = ControlledTask(SwitchWaypoint(from_waypoint=3, to_waypoint=2))
switch_waypoint_task.start_if_user_flag(1, False) switch_waypoint_task.start_if_user_flag(1, False)
w2.tasks.append(switch_waypoint_task) w2.tasks.append(switch_waypoint_task)
plane_group.points[3].tasks.append(Silence(False)) group.points[3].tasks.append(Silence(False))
plane_group.add_trigger_action(SwitchWaypoint(to_waypoint=4)) group.add_trigger_action(SwitchWaypoint(to_waypoint=4))
push_by_trigger.append(plane_group) push_by_trigger.append(group)
push_trigger_zone = self.mission.triggers.add_triggerzone(player_cp.position, PUSH_TRIGGER_SIZE, name="Push zone") push_trigger_zone = self.mission.triggers.add_triggerzone(player_cp.position, PUSH_TRIGGER_SIZE, name="Push zone")
push_trigger = TriggerOnce(Event.NoEvent, "Push trigger") push_trigger = TriggerOnce(Event.NoEvent, "Push trigger")