mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Added missions generators in flight planner. + refactoring
This commit is contained in:
parent
397164e667
commit
fde3a988b7
@ -320,7 +320,7 @@ class Event:
|
|||||||
enemy_cp.base.affect_strength(delta)
|
enemy_cp.base.affect_strength(delta)
|
||||||
cp.base.affect_strength(-delta)
|
cp.base.affect_strength(-delta)
|
||||||
info = Information("Frontline Report",
|
info = Information("Frontline Report",
|
||||||
"Our ground forces from " + cp.name + " are losing ground against the enemy forces from" + enemy_cp.name,
|
"Our ground forces from " + cp.name + " are losing ground against the enemy forces from " + enemy_cp.name,
|
||||||
self.game.turn)
|
self.game.turn)
|
||||||
self.game.informations.append(info)
|
self.game.informations.append(info)
|
||||||
|
|
||||||
|
|||||||
@ -258,7 +258,7 @@ class AircraftConflictGenerator:
|
|||||||
def setup_group_activation_trigger(self, flight, group):
|
def setup_group_activation_trigger(self, flight, group):
|
||||||
if flight.scheduled_in > 0 and flight.client_count == 0:
|
if flight.scheduled_in > 0 and flight.client_count == 0:
|
||||||
|
|
||||||
if flight.start_type != "In Flight":
|
if flight.start_type != "In Flight" and flight.from_cp.cptype not in [ControlPointType.AIRCRAFT_CARRIER_GROUP, ControlPointType.LHA_GROUP]:
|
||||||
group.late_activation = False
|
group.late_activation = False
|
||||||
group.uncontrolled = True
|
group.uncontrolled = True
|
||||||
|
|
||||||
@ -402,8 +402,6 @@ class AircraftConflictGenerator:
|
|||||||
elif point.waypoint_type == FlightWaypointType.LANDING_POINT:
|
elif point.waypoint_type == FlightWaypointType.LANDING_POINT:
|
||||||
pt.type = "Land"
|
pt.type = "Land"
|
||||||
elif point.waypoint_type == FlightWaypointType.INGRESS_STRIKE:
|
elif point.waypoint_type == FlightWaypointType.INGRESS_STRIKE:
|
||||||
print("TGTS :")
|
|
||||||
print(point.targets)
|
|
||||||
for j, t in enumerate(point.targets):
|
for j, t in enumerate(point.targets):
|
||||||
print(t.position)
|
print(t.position)
|
||||||
pt.tasks.append(Bombing(t.position))
|
pt.tasks.append(Bombing(t.position))
|
||||||
@ -411,6 +409,12 @@ class AircraftConflictGenerator:
|
|||||||
group.add_nav_target_point(t.position, "PP" + str(j + 1))
|
group.add_nav_target_point(t.position, "PP" + str(j + 1))
|
||||||
if group.units[0].unit_type == F_14B and j == 0:
|
if group.units[0].unit_type == F_14B and j == 0:
|
||||||
group.add_nav_target_point(t.position, "ST")
|
group.add_nav_target_point(t.position, "ST")
|
||||||
|
elif point.waypoint_type == FlightWaypointType.INGRESS_SEAD:
|
||||||
|
for j, t in enumerate(point.targets):
|
||||||
|
if group.units[0].unit_type == JF_17 and j < 4:
|
||||||
|
group.add_nav_target_point(t.position, "PP" + str(j + 1))
|
||||||
|
if group.units[0].unit_type == F_14B and j == 0:
|
||||||
|
group.add_nav_target_point(t.position, "ST")
|
||||||
|
|
||||||
if pt is not None:
|
if pt is not None:
|
||||||
pt.alt_type = point.alt_type
|
pt.alt_type = point.alt_type
|
||||||
|
|||||||
@ -153,67 +153,16 @@ class FlightPlanner:
|
|||||||
break
|
break
|
||||||
|
|
||||||
inventory[unit] = inventory[unit] - 2
|
inventory[unit] = inventory[unit] - 2
|
||||||
ftype = FlightType.BARCAP if self.from_cp.is_carrier else FlightType.CAP
|
flight = Flight(unit, 2, self.from_cp, FlightType.CAP)
|
||||||
flight = Flight(unit, 2, self.from_cp, ftype)
|
|
||||||
|
|
||||||
flight.points = []
|
flight.points = []
|
||||||
flight.scheduled_in = offset + i*random.randint(CAP_EVERY_X_MINUTES-5, CAP_EVERY_X_MINUTES+5)
|
flight.scheduled_in = offset + i*random.randint(CAP_EVERY_X_MINUTES-5, CAP_EVERY_X_MINUTES+5)
|
||||||
|
|
||||||
patrol_alt = random.randint(PATROL_ALT_RANGE[0], PATROL_ALT_RANGE[1])
|
|
||||||
|
|
||||||
# Choose a location for CAP patrols (Either behind frontline if there is one, or to protect ground objects)
|
|
||||||
if len(self._get_cas_locations()) > 0:
|
if len(self._get_cas_locations()) > 0:
|
||||||
loc = random.choice(self._get_cas_locations())
|
enemy_cp = random.choice(self._get_cas_locations())
|
||||||
ingress, heading, distance = Conflict.frontline_vector(self.from_cp, loc, self.game.theater)
|
self.generate_frontline_cap(flight, flight.from_cp, enemy_cp)
|
||||||
center = ingress.point_from_heading(heading, distance / 2)
|
|
||||||
orbit_center = center.point_from_heading(heading - 90, random.randint(nm_to_meter(6), nm_to_meter(15)))
|
|
||||||
radius = distance * 2
|
|
||||||
orbit0p = orbit_center.point_from_heading(heading, radius)
|
|
||||||
orbit1p = orbit_center.point_from_heading(heading + 180, radius)
|
|
||||||
elif len(self.from_cp.ground_objects) > 0:
|
|
||||||
loc = random.choice(self.from_cp.ground_objects)
|
|
||||||
hdg = self.from_cp.position.heading_between_point(loc.position)
|
|
||||||
radius = random.randint(nm_to_meter(5), nm_to_meter(10))
|
|
||||||
orbit0p = loc.position.point_from_heading(hdg - 90, radius)
|
|
||||||
orbit1p = loc.position.point_from_heading(hdg + 90, radius)
|
|
||||||
else:
|
else:
|
||||||
loc = self.from_cp.position.point_from_heading(random.randint(0, 360), random.randint(nm_to_meter(5), nm_to_meter(40)))
|
self.generate_barcap(flight, flight.from_cp)
|
||||||
hdg = self.from_cp.position.heading_between_point(loc.position)
|
|
||||||
radius = random.randint(nm_to_meter(40), nm_to_meter(120))
|
|
||||||
orbit0p = loc.position.point_from_heading(hdg - 90, radius)
|
|
||||||
orbit1p = loc.position.point_from_heading(hdg + 90, radius)
|
|
||||||
|
|
||||||
|
|
||||||
# Create points
|
|
||||||
ascend = self.generate_ascend_point(self.from_cp)
|
|
||||||
flight.points.append(ascend)
|
|
||||||
|
|
||||||
orbit0 = FlightWaypoint(orbit0p.x, orbit0p.y, patrol_alt)
|
|
||||||
orbit0.name = "ORBIT 0"
|
|
||||||
orbit0.description = "Standby between this point and the next one"
|
|
||||||
orbit0.pretty_name = "Orbit race-track start"
|
|
||||||
orbit0.waypoint_type = FlightWaypointType.PATROL_TRACK
|
|
||||||
flight.points.append(orbit0)
|
|
||||||
|
|
||||||
orbit1 = FlightWaypoint(orbit1p.x, orbit1p.y, patrol_alt)
|
|
||||||
orbit1.name = "ORBIT 1"
|
|
||||||
orbit1.description = "Standby between this point and the previous one"
|
|
||||||
orbit1.pretty_name = "Orbit race-track end"
|
|
||||||
orbit1.waypoint_type = FlightWaypointType.PATROL
|
|
||||||
flight.points.append(orbit1)
|
|
||||||
|
|
||||||
orbit0.targets.append(self.from_cp)
|
|
||||||
obj_added = []
|
|
||||||
for ground_object in self.from_cp.ground_objects:
|
|
||||||
if ground_object.obj_name not in obj_added and not ground_object.airbase_group:
|
|
||||||
orbit0.targets.append(ground_object)
|
|
||||||
obj_added.append(ground_object.obj_name)
|
|
||||||
|
|
||||||
descend = self.generate_descend_point(self.from_cp)
|
|
||||||
flight.points.append(descend)
|
|
||||||
|
|
||||||
rtb = self.generate_rtb_waypoint(self.from_cp)
|
|
||||||
flight.points.append(rtb)
|
|
||||||
|
|
||||||
self.cap_flights.append(flight)
|
self.cap_flights.append(flight)
|
||||||
self.flights.append(flight)
|
self.flights.append(flight)
|
||||||
@ -243,47 +192,11 @@ class FlightPlanner:
|
|||||||
|
|
||||||
inventory[unit] = inventory[unit] - 2
|
inventory[unit] = inventory[unit] - 2
|
||||||
flight = Flight(unit, 2, self.from_cp, FlightType.CAS)
|
flight = Flight(unit, 2, self.from_cp, FlightType.CAS)
|
||||||
|
|
||||||
flight.points = []
|
flight.points = []
|
||||||
flight.scheduled_in = offset + i*random.randint(CAS_EVERY_X_MINUTES-5, CAS_EVERY_X_MINUTES+5)
|
flight.scheduled_in = offset + i * random.randint(CAS_EVERY_X_MINUTES - 5, CAS_EVERY_X_MINUTES + 5)
|
||||||
|
|
||||||
location = random.choice(cas_location)
|
location = random.choice(cas_location)
|
||||||
ingress, heading, distance = Conflict.frontline_vector(self.from_cp, location, self.game.theater)
|
|
||||||
center = ingress.point_from_heading(heading, distance/2)
|
|
||||||
egress = ingress.point_from_heading(heading, distance)
|
|
||||||
|
|
||||||
ascend = self.generate_ascend_point(self.from_cp)
|
self.generate_cas(flight, flight.from_cp, location)
|
||||||
flight.points.append(ascend)
|
|
||||||
|
|
||||||
ingress_point = FlightWaypoint(ingress.x, ingress.y, 1000)
|
|
||||||
ingress_point.alt_type = "RADIO"
|
|
||||||
ingress_point.name = "INGRESS"
|
|
||||||
ingress_point.pretty_name = "INGRESS"
|
|
||||||
ingress_point.description = "Ingress into CAS area"
|
|
||||||
ingress_point.waypoint_type = FlightWaypointType.INGRESS_CAS
|
|
||||||
flight.points.append(ingress_point)
|
|
||||||
|
|
||||||
center_point = FlightWaypoint(center.x, center.y, 1000)
|
|
||||||
center_point.alt_type = "RADIO"
|
|
||||||
center_point.description = "Provide CAS"
|
|
||||||
center_point.name = "CAS"
|
|
||||||
center_point.pretty_name = "CAS"
|
|
||||||
center_point.waypoint_type = FlightWaypointType.CAS
|
|
||||||
flight.points.append(center_point)
|
|
||||||
|
|
||||||
egress_point = FlightWaypoint(egress.x, egress.y, 1000)
|
|
||||||
egress_point.alt_type = "RADIO"
|
|
||||||
egress_point.description = "Egress from CAS area"
|
|
||||||
egress_point.name = "EGRESS"
|
|
||||||
egress_point.pretty_name = "EGRESS"
|
|
||||||
egress_point.waypoint_type = FlightWaypointType.EGRESS
|
|
||||||
flight.points.append(egress_point)
|
|
||||||
|
|
||||||
descend = self.generate_descend_point(self.from_cp)
|
|
||||||
flight.points.append(descend)
|
|
||||||
|
|
||||||
rtb = self.generate_rtb_waypoint(self.from_cp)
|
|
||||||
flight.points.append(rtb)
|
|
||||||
|
|
||||||
self.cas_flights.append(flight)
|
self.cas_flights.append(flight)
|
||||||
self.flights.append(flight)
|
self.flights.append(flight)
|
||||||
@ -319,49 +232,10 @@ class FlightPlanner:
|
|||||||
flight.points = []
|
flight.points = []
|
||||||
flight.scheduled_in = offset + i*random.randint(SEAD_EVERY_X_MINUTES-5, SEAD_EVERY_X_MINUTES+5)
|
flight.scheduled_in = offset + i*random.randint(SEAD_EVERY_X_MINUTES-5, SEAD_EVERY_X_MINUTES+5)
|
||||||
|
|
||||||
ascend = self.generate_ascend_point(self.from_cp)
|
|
||||||
flight.points.append(ascend)
|
|
||||||
|
|
||||||
location = self.potential_sead_targets[0][0]
|
location = self.potential_sead_targets[0][0]
|
||||||
self.potential_sead_targets.pop(0)
|
self.potential_sead_targets.pop(0)
|
||||||
|
|
||||||
heading = self.from_cp.position.heading_between_point(location.position)
|
self.generate_sead(flight, location, [])
|
||||||
ingress_heading = heading - 180 + 25
|
|
||||||
egress_heading = heading - 180 - 25
|
|
||||||
|
|
||||||
ingress_pos = location.position.point_from_heading(ingress_heading, INGRESS_EGRESS_DISTANCE)
|
|
||||||
ingress_point = FlightWaypoint(ingress_pos.x, ingress_pos.y, INGRESS_ALT)
|
|
||||||
ingress_point.pretty_name = "INGRESS on " + location.obj_name
|
|
||||||
ingress_point.description = "INGRESS on " + location.obj_name
|
|
||||||
ingress_point.waypoint_type = FlightWaypointType.INGRESS_SEAD
|
|
||||||
flight.points.append(ingress_point)
|
|
||||||
|
|
||||||
point = FlightWaypoint(location.position.x, location.position.y, 0)
|
|
||||||
point.alt_type = "RADIO"
|
|
||||||
if flight.flight_type == FlightType.DEAD:
|
|
||||||
point.description = "SEAD on " + location.obj_name
|
|
||||||
point.pretty_name = "SEAD on " + location.obj_name
|
|
||||||
point.only_for_player = True
|
|
||||||
else:
|
|
||||||
point.description = "DEAD on " + location.obj_name
|
|
||||||
point.pretty_name = "DEAD on " + location.obj_name
|
|
||||||
point.only_for_player = True
|
|
||||||
|
|
||||||
ingress_point.targets.append(location)
|
|
||||||
flight.points.append(point)
|
|
||||||
|
|
||||||
egress_pos = location.position.point_from_heading(egress_heading, INGRESS_EGRESS_DISTANCE)
|
|
||||||
egress_point = FlightWaypoint(egress_pos.x, egress_pos.y, EGRESS_ALT)
|
|
||||||
egress_point.pretty_name = "EGRESS from " + location.obj_name
|
|
||||||
egress_point.description = "EGRESS from " + location.obj_name
|
|
||||||
egress_point.waypoint_type = FlightWaypointType.EGRESS
|
|
||||||
flight.points.append(egress_point)
|
|
||||||
|
|
||||||
descend = self.generate_descend_point(self.from_cp)
|
|
||||||
flight.points.append(descend)
|
|
||||||
|
|
||||||
rtb = self.generate_rtb_waypoint(self.from_cp)
|
|
||||||
flight.points.append(rtb)
|
|
||||||
|
|
||||||
self.sead_flights.append(flight)
|
self.sead_flights.append(flight)
|
||||||
self.flights.append(flight)
|
self.flights.append(flight)
|
||||||
@ -397,75 +271,10 @@ class FlightPlanner:
|
|||||||
flight.points = []
|
flight.points = []
|
||||||
flight.scheduled_in = offset + i*random.randint(SEAD_EVERY_X_MINUTES-5, SEAD_EVERY_X_MINUTES+5)
|
flight.scheduled_in = offset + i*random.randint(SEAD_EVERY_X_MINUTES-5, SEAD_EVERY_X_MINUTES+5)
|
||||||
|
|
||||||
ascend = self.generate_ascend_point(self.from_cp)
|
|
||||||
flight.points.append(ascend)
|
|
||||||
|
|
||||||
location = self.potential_strike_targets[0][0]
|
location = self.potential_strike_targets[0][0]
|
||||||
self.potential_strike_targets.pop(0)
|
self.potential_strike_targets.pop(0)
|
||||||
|
|
||||||
heading = self.from_cp.position.heading_between_point(location.position)
|
self.generate_strike(flight, location)
|
||||||
ingress_heading = heading - 180 + 25
|
|
||||||
egress_heading = heading - 180 - 25
|
|
||||||
|
|
||||||
ingress_pos = location.position.point_from_heading(ingress_heading, INGRESS_EGRESS_DISTANCE)
|
|
||||||
ingress_point = FlightWaypoint(ingress_pos.x, ingress_pos.y, INGRESS_ALT)
|
|
||||||
ingress_point.pretty_name = "INGRESS on " + location.obj_name
|
|
||||||
ingress_point.description = "INGRESS on " + location.obj_name
|
|
||||||
ingress_point.name = "INGRESS"
|
|
||||||
ingress_point.waypoint_type = FlightWaypointType.INGRESS_STRIKE
|
|
||||||
flight.points.append(ingress_point)
|
|
||||||
|
|
||||||
if len(location.groups) > 0 and location.dcs_identifier == "AA":
|
|
||||||
for g in location.groups:
|
|
||||||
for j, u in enumerate(g.units):
|
|
||||||
point = FlightWaypoint(u.position.x, u.position.y, 0)
|
|
||||||
point.description = "STRIKE " + "[" + str(location.obj_name) + "] : " + u.type + " #" + str(j)
|
|
||||||
point.pretty_name = "STRIKE " + "[" + str(location.obj_name) + "] : " + u.type + " #" + str(j)
|
|
||||||
point.name = location.obj_name + "#" + str(j)
|
|
||||||
point.only_for_player = True
|
|
||||||
ingress_point.targets.append(location)
|
|
||||||
flight.points.append(point)
|
|
||||||
else:
|
|
||||||
if hasattr(location, "obj_name"):
|
|
||||||
buildings = self.game.theater.find_ground_objects_by_obj_name(location.obj_name)
|
|
||||||
print(buildings)
|
|
||||||
for building in buildings:
|
|
||||||
print("BUILDING " + str(building.is_dead) + " " + str(building.dcs_identifier))
|
|
||||||
if building.is_dead:
|
|
||||||
continue
|
|
||||||
|
|
||||||
point = FlightWaypoint(building.position.x, building.position.y, 0)
|
|
||||||
point.description = "STRIKE on " + building.obj_name + " " + str(building.category)
|
|
||||||
point.pretty_name = "STRIKE on " + building.obj_name + " " + str(building.category)
|
|
||||||
point.name = building.obj_name
|
|
||||||
point.only_for_player = True
|
|
||||||
ingress_point.targets.append(building)
|
|
||||||
flight.points.append(point)
|
|
||||||
else:
|
|
||||||
point = FlightWaypoint(location.position.x, location.position.y, 0)
|
|
||||||
point.description = "STRIKE on " + location.obj_name + " " + str(location.category)
|
|
||||||
point.pretty_name = "STRIKE on " + location.obj_name + " " + str(location.category)
|
|
||||||
point.name = location.obj_name
|
|
||||||
point.only_for_player = True
|
|
||||||
ingress_point.targets.append(location)
|
|
||||||
flight.points.append(point)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
egress_pos = location.position.point_from_heading(egress_heading, INGRESS_EGRESS_DISTANCE)
|
|
||||||
egress_point = FlightWaypoint(egress_pos.x, egress_pos.y, EGRESS_ALT)
|
|
||||||
egress_point.name = "EGRESS"
|
|
||||||
egress_point.pretty_name = "EGRESS from " + location.obj_name
|
|
||||||
egress_point.description = "EGRESS from " + location.obj_name
|
|
||||||
egress_point.waypoint_type = FlightWaypointType.EGRESS
|
|
||||||
flight.points.append(egress_point)
|
|
||||||
|
|
||||||
descend = self.generate_descend_point(self.from_cp)
|
|
||||||
flight.points.append(descend)
|
|
||||||
|
|
||||||
rtb = self.generate_rtb_waypoint(self.from_cp)
|
|
||||||
flight.points.append(rtb)
|
|
||||||
|
|
||||||
self.strike_flights.append(flight)
|
self.strike_flights.append(flight)
|
||||||
self.flights.append(flight)
|
self.flights.append(flight)
|
||||||
@ -475,9 +284,12 @@ class FlightPlanner:
|
|||||||
self.aircraft_inventory[k] = v
|
self.aircraft_inventory[k] = v
|
||||||
|
|
||||||
def _get_cas_locations(self):
|
def _get_cas_locations(self):
|
||||||
|
return self._get_cas_locations_for_cp(self.from_cp)
|
||||||
|
|
||||||
|
def _get_cas_locations_for_cp(self, for_cp):
|
||||||
cas_locations = []
|
cas_locations = []
|
||||||
for cp in self.from_cp.connected_points:
|
for cp in for_cp.connected_points:
|
||||||
if cp.captured != self.from_cp.captured:
|
if cp.captured != for_cp.captured:
|
||||||
cas_locations.append(cp)
|
cas_locations.append(cp)
|
||||||
return cas_locations
|
return cas_locations
|
||||||
|
|
||||||
@ -563,7 +375,300 @@ class FlightPlanner:
|
|||||||
del base_aircraft_inventory[f.unit_type]
|
del base_aircraft_inventory[f.unit_type]
|
||||||
return base_aircraft_inventory
|
return base_aircraft_inventory
|
||||||
|
|
||||||
|
|
||||||
|
def generate_strike(self, flight, location):
|
||||||
|
|
||||||
|
flight.flight_type = FlightType.STRIKE
|
||||||
|
ascend = self.generate_ascend_point(flight.from_cp)
|
||||||
|
flight.points.append(ascend)
|
||||||
|
|
||||||
|
heading = flight.from_cp.position.heading_between_point(location.position)
|
||||||
|
ingress_heading = heading - 180 + 25
|
||||||
|
egress_heading = heading - 180 - 25
|
||||||
|
|
||||||
|
ingress_pos = location.position.point_from_heading(ingress_heading, INGRESS_EGRESS_DISTANCE)
|
||||||
|
ingress_point = FlightWaypoint(ingress_pos.x, ingress_pos.y, INGRESS_ALT)
|
||||||
|
ingress_point.pretty_name = "INGRESS on " + location.obj_name
|
||||||
|
ingress_point.description = "INGRESS on " + location.obj_name
|
||||||
|
ingress_point.name = "INGRESS"
|
||||||
|
ingress_point.waypoint_type = FlightWaypointType.INGRESS_STRIKE
|
||||||
|
flight.points.append(ingress_point)
|
||||||
|
|
||||||
|
if len(location.groups) > 0 and location.dcs_identifier == "AA":
|
||||||
|
for g in location.groups:
|
||||||
|
for j, u in enumerate(g.units):
|
||||||
|
point = FlightWaypoint(u.position.x, u.position.y, 0)
|
||||||
|
point.description = "STRIKE " + "[" + str(location.obj_name) + "] : " + u.type + " #" + str(j)
|
||||||
|
point.pretty_name = "STRIKE " + "[" + str(location.obj_name) + "] : " + u.type + " #" + str(j)
|
||||||
|
point.name = location.obj_name + "#" + str(j)
|
||||||
|
point.only_for_player = True
|
||||||
|
ingress_point.targets.append(location)
|
||||||
|
flight.points.append(point)
|
||||||
|
else:
|
||||||
|
if hasattr(location, "obj_name"):
|
||||||
|
buildings = self.game.theater.find_ground_objects_by_obj_name(location.obj_name)
|
||||||
|
print(buildings)
|
||||||
|
for building in buildings:
|
||||||
|
print("BUILDING " + str(building.is_dead) + " " + str(building.dcs_identifier))
|
||||||
|
if building.is_dead:
|
||||||
|
continue
|
||||||
|
|
||||||
|
point = FlightWaypoint(building.position.x, building.position.y, 0)
|
||||||
|
point.description = "STRIKE on " + building.obj_name + " " + str(building.category)
|
||||||
|
point.pretty_name = "STRIKE on " + building.obj_name + " " + str(building.category)
|
||||||
|
point.name = building.obj_name
|
||||||
|
point.only_for_player = True
|
||||||
|
ingress_point.targets.append(building)
|
||||||
|
flight.points.append(point)
|
||||||
|
else:
|
||||||
|
point = FlightWaypoint(location.position.x, location.position.y, 0)
|
||||||
|
point.description = "STRIKE on " + location.obj_name
|
||||||
|
point.pretty_name = "STRIKE on " + location.obj_name
|
||||||
|
point.name = location.obj_name
|
||||||
|
point.only_for_player = True
|
||||||
|
ingress_point.targets.append(location)
|
||||||
|
flight.points.append(point)
|
||||||
|
|
||||||
|
egress_pos = location.position.point_from_heading(egress_heading, INGRESS_EGRESS_DISTANCE)
|
||||||
|
egress_point = FlightWaypoint(egress_pos.x, egress_pos.y, EGRESS_ALT)
|
||||||
|
egress_point.name = "EGRESS"
|
||||||
|
egress_point.pretty_name = "EGRESS from " + location.obj_name
|
||||||
|
egress_point.description = "EGRESS from " + location.obj_name
|
||||||
|
egress_point.waypoint_type = FlightWaypointType.EGRESS
|
||||||
|
flight.points.append(egress_point)
|
||||||
|
|
||||||
|
descend = self.generate_descend_point(flight.from_cp)
|
||||||
|
flight.points.append(descend)
|
||||||
|
|
||||||
|
rtb = self.generate_rtb_waypoint(flight.from_cp)
|
||||||
|
flight.points.append(rtb)
|
||||||
|
|
||||||
|
def generate_barcap(self, flight, for_cp):
|
||||||
|
"""
|
||||||
|
Generate a barcap flight at a given location
|
||||||
|
:param flight: Flight to setup
|
||||||
|
:param for_cp: CP to protect
|
||||||
|
:param location: Location to protect in priority
|
||||||
|
:param location: Is the location to protect a frontline
|
||||||
|
"""
|
||||||
|
flight.flight_type = FlightType.BARCAP if for_cp.is_carrier else FlightType.CAP
|
||||||
|
patrol_alt = random.randint(PATROL_ALT_RANGE[0], PATROL_ALT_RANGE[1])
|
||||||
|
|
||||||
|
if len(for_cp.ground_objects) > 0:
|
||||||
|
loc = random.choice(for_cp.ground_objects)
|
||||||
|
hdg = for_cp.position.heading_between_point(loc.position)
|
||||||
|
radius = nm_to_meter(random.randint(15, 40))
|
||||||
|
orbit0p = loc.position.point_from_heading(hdg - 90, radius)
|
||||||
|
orbit1p = loc.position.point_from_heading(hdg + 90, radius)
|
||||||
|
else:
|
||||||
|
loc = for_cp.position.point_from_heading(random.randint(0, 360),random.randint(nm_to_meter(10), nm_to_meter(40)))
|
||||||
|
hdg = for_cp.position.heading_between_point(loc.position)
|
||||||
|
radius = nm_to_meter(random.randint(15, 40))
|
||||||
|
orbit0p = loc.position.point_from_heading(hdg - 90, radius)
|
||||||
|
orbit1p = loc.position.point_from_heading(hdg + 90, radius)
|
||||||
|
|
||||||
|
# Create points
|
||||||
|
ascend = self.generate_ascend_point(flight.from_cp)
|
||||||
|
flight.points.append(ascend)
|
||||||
|
|
||||||
|
orbit0 = FlightWaypoint(orbit0p.x, orbit0p.y, patrol_alt)
|
||||||
|
orbit0.name = "ORBIT 0"
|
||||||
|
orbit0.description = "Standby between this point and the next one"
|
||||||
|
orbit0.pretty_name = "Race-track start"
|
||||||
|
orbit0.waypoint_type = FlightWaypointType.PATROL_TRACK
|
||||||
|
flight.points.append(orbit0)
|
||||||
|
|
||||||
|
orbit1 = FlightWaypoint(orbit1p.x, orbit1p.y, patrol_alt)
|
||||||
|
orbit1.name = "ORBIT 1"
|
||||||
|
orbit1.description = "Standby between this point and the previous one"
|
||||||
|
orbit1.pretty_name = "Race-track end"
|
||||||
|
orbit1.waypoint_type = FlightWaypointType.PATROL
|
||||||
|
flight.points.append(orbit1)
|
||||||
|
|
||||||
|
orbit0.targets.append(for_cp)
|
||||||
|
obj_added = []
|
||||||
|
for ground_object in for_cp.ground_objects:
|
||||||
|
if ground_object.obj_name not in obj_added and not ground_object.airbase_group:
|
||||||
|
orbit0.targets.append(ground_object)
|
||||||
|
obj_added.append(ground_object.obj_name)
|
||||||
|
|
||||||
|
descend = self.generate_descend_point(flight.from_cp)
|
||||||
|
flight.points.append(descend)
|
||||||
|
|
||||||
|
rtb = self.generate_rtb_waypoint(flight.from_cp)
|
||||||
|
flight.points.append(rtb)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_frontline_cap(self, flight, ally_cp, enemy_cp):
|
||||||
|
"""
|
||||||
|
Generate a cap flight for the frontline between ally_cp and enemy cp in order to ensure air superiority and
|
||||||
|
protect friendly CAP airbase
|
||||||
|
:param flight: Flight to setup
|
||||||
|
:param ally_cp: CP to protect
|
||||||
|
:param enemy_cp: Enemy connected cp
|
||||||
|
"""
|
||||||
|
flight.flight_type = FlightType.CAP
|
||||||
|
patrol_alt = random.randint(PATROL_ALT_RANGE[0], PATROL_ALT_RANGE[1])
|
||||||
|
|
||||||
|
# Find targets waypoints
|
||||||
|
ingress, heading, distance = Conflict.frontline_vector(ally_cp, enemy_cp, self.game.theater)
|
||||||
|
center = ingress.point_from_heading(heading, distance / 2)
|
||||||
|
orbit_center = center.point_from_heading(heading - 90, random.randint(nm_to_meter(6), nm_to_meter(15)))
|
||||||
|
radius = distance * 2
|
||||||
|
orbit0p = orbit_center.point_from_heading(heading, radius)
|
||||||
|
orbit1p = orbit_center.point_from_heading(heading + 180, radius)
|
||||||
|
|
||||||
|
# Create points
|
||||||
|
ascend = self.generate_ascend_point(flight.from_cp)
|
||||||
|
flight.points.append(ascend)
|
||||||
|
|
||||||
|
orbit0 = FlightWaypoint(orbit0p.x, orbit0p.y, patrol_alt)
|
||||||
|
orbit0.name = "ORBIT 0"
|
||||||
|
orbit0.description = "Standby between this point and the next one"
|
||||||
|
orbit0.pretty_name = "Race-track start"
|
||||||
|
orbit0.waypoint_type = FlightWaypointType.PATROL_TRACK
|
||||||
|
flight.points.append(orbit0)
|
||||||
|
|
||||||
|
orbit1 = FlightWaypoint(orbit1p.x, orbit1p.y, patrol_alt)
|
||||||
|
orbit1.name = "ORBIT 1"
|
||||||
|
orbit1.description = "Standby between this point and the previous one"
|
||||||
|
orbit1.pretty_name = "Race-track end"
|
||||||
|
orbit1.waypoint_type = FlightWaypointType.PATROL
|
||||||
|
flight.points.append(orbit1)
|
||||||
|
|
||||||
|
# Note : Targets of a PATROL TRACK waypoints are the points to be defended
|
||||||
|
orbit0.targets.append(flight.from_cp)
|
||||||
|
orbit0.targets.append(center)
|
||||||
|
|
||||||
|
descend = self.generate_descend_point(flight.from_cp)
|
||||||
|
flight.points.append(descend)
|
||||||
|
|
||||||
|
rtb = self.generate_rtb_waypoint(flight.from_cp)
|
||||||
|
flight.points.append(rtb)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_sead(self, flight, location, custom_targets = []):
|
||||||
|
"""
|
||||||
|
Generate a sead flight at a given location
|
||||||
|
:param flight: Flight to setup
|
||||||
|
:param location: Location of the SEAD target
|
||||||
|
:param custom_targets: Custom targets if any
|
||||||
|
"""
|
||||||
|
flight.points = []
|
||||||
|
flight.flight_type = random.choice([FlightType.SEAD, FlightType.DEAD])
|
||||||
|
|
||||||
|
ascend = self.generate_ascend_point(flight.from_cp)
|
||||||
|
flight.points.append(ascend)
|
||||||
|
|
||||||
|
heading = flight.from_cp.position.heading_between_point(location.position)
|
||||||
|
ingress_heading = heading - 180 + 25
|
||||||
|
egress_heading = heading - 180 - 25
|
||||||
|
|
||||||
|
ingress_pos = location.position.point_from_heading(ingress_heading, INGRESS_EGRESS_DISTANCE)
|
||||||
|
ingress_point = FlightWaypoint(ingress_pos.x, ingress_pos.y, INGRESS_ALT)
|
||||||
|
ingress_point.name = "INGRESS"
|
||||||
|
ingress_point.pretty_name = "INGRESS on " + location.obj_name
|
||||||
|
ingress_point.description = "INGRESS on " + location.obj_name
|
||||||
|
ingress_point.waypoint_type = FlightWaypointType.INGRESS_SEAD
|
||||||
|
flight.points.append(ingress_point)
|
||||||
|
|
||||||
|
if len(custom_targets) > 0:
|
||||||
|
for target in custom_targets:
|
||||||
|
point = FlightWaypoint(target.position.x, target.position.y, 0)
|
||||||
|
point.alt_type = "RADIO"
|
||||||
|
if flight.flight_type == FlightType.DEAD:
|
||||||
|
point.description = "SEAD on " + target.type
|
||||||
|
point.pretty_name = "SEAD on " + location.obj_name
|
||||||
|
point.only_for_player = True
|
||||||
|
else:
|
||||||
|
point.description = "DEAD on " + location.obj_name
|
||||||
|
point.pretty_name = "DEAD on " + location.obj_name
|
||||||
|
point.only_for_player = True
|
||||||
|
ingress_point.targets.append(location)
|
||||||
|
flight.points.append(point)
|
||||||
|
else:
|
||||||
|
point = FlightWaypoint(location.position.x, location.position.y, 0)
|
||||||
|
point.alt_type = "RADIO"
|
||||||
|
if flight.flight_type == FlightType.DEAD:
|
||||||
|
point.description = "SEAD on " + location.obj_name
|
||||||
|
point.pretty_name = "SEAD on " + location.obj_name
|
||||||
|
point.only_for_player = True
|
||||||
|
else:
|
||||||
|
point.description = "DEAD on " + location.obj_name
|
||||||
|
point.pretty_name = "DEAD on " + location.obj_name
|
||||||
|
point.only_for_player = True
|
||||||
|
ingress_point.targets.append(location)
|
||||||
|
flight.points.append(point)
|
||||||
|
|
||||||
|
egress_pos = location.position.point_from_heading(egress_heading, INGRESS_EGRESS_DISTANCE)
|
||||||
|
egress_point = FlightWaypoint(egress_pos.x, egress_pos.y, EGRESS_ALT)
|
||||||
|
egress_point.name = "INGRESS"
|
||||||
|
egress_point.pretty_name = "EGRESS from " + location.obj_name
|
||||||
|
egress_point.description = "EGRESS from " + location.obj_name
|
||||||
|
egress_point.waypoint_type = FlightWaypointType.EGRESS
|
||||||
|
flight.points.append(egress_point)
|
||||||
|
|
||||||
|
descend = self.generate_descend_point(flight.from_cp)
|
||||||
|
flight.points.append(descend)
|
||||||
|
|
||||||
|
rtb = self.generate_rtb_waypoint(flight.from_cp)
|
||||||
|
flight.points.append(rtb)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_cas(self, flight, from_cp, location):
|
||||||
|
"""
|
||||||
|
Generate a CAS flight at a given location
|
||||||
|
:param flight: Flight to setup
|
||||||
|
:param location: Location of the CAS targets
|
||||||
|
"""
|
||||||
|
|
||||||
|
flight.points = []
|
||||||
|
flight.flight_type = FlightType.CAS
|
||||||
|
|
||||||
|
ingress, heading, distance = Conflict.frontline_vector(from_cp, location, self.game.theater)
|
||||||
|
center = ingress.point_from_heading(heading, distance / 2)
|
||||||
|
egress = ingress.point_from_heading(heading, distance)
|
||||||
|
|
||||||
|
ascend = self.generate_ascend_point(flight.from_cp)
|
||||||
|
flight.points.append(ascend)
|
||||||
|
|
||||||
|
ingress_point = FlightWaypoint(ingress.x, ingress.y, 1000)
|
||||||
|
ingress_point.alt_type = "RADIO"
|
||||||
|
ingress_point.name = "INGRESS"
|
||||||
|
ingress_point.pretty_name = "INGRESS"
|
||||||
|
ingress_point.description = "Ingress into CAS area"
|
||||||
|
ingress_point.waypoint_type = FlightWaypointType.INGRESS_CAS
|
||||||
|
flight.points.append(ingress_point)
|
||||||
|
|
||||||
|
center_point = FlightWaypoint(center.x, center.y, 1000)
|
||||||
|
center_point.alt_type = "RADIO"
|
||||||
|
center_point.description = "Provide CAS"
|
||||||
|
center_point.name = "CAS"
|
||||||
|
center_point.pretty_name = "CAS"
|
||||||
|
center_point.waypoint_type = FlightWaypointType.CAS
|
||||||
|
flight.points.append(center_point)
|
||||||
|
|
||||||
|
egress_point = FlightWaypoint(egress.x, egress.y, 1000)
|
||||||
|
egress_point.alt_type = "RADIO"
|
||||||
|
egress_point.description = "Egress from CAS area"
|
||||||
|
egress_point.name = "EGRESS"
|
||||||
|
egress_point.pretty_name = "EGRESS"
|
||||||
|
egress_point.waypoint_type = FlightWaypointType.EGRESS
|
||||||
|
flight.points.append(egress_point)
|
||||||
|
|
||||||
|
descend = self.generate_descend_point(flight.from_cp)
|
||||||
|
flight.points.append(descend)
|
||||||
|
|
||||||
|
rtb = self.generate_rtb_waypoint(flight.from_cp)
|
||||||
|
flight.points.append(rtb)
|
||||||
|
|
||||||
|
|
||||||
def generate_ascend_point(self, from_cp):
|
def generate_ascend_point(self, from_cp):
|
||||||
|
"""
|
||||||
|
Generate ascend point
|
||||||
|
:param from_cp: Airport you're taking off from
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
ascend_heading = from_cp.heading
|
ascend_heading = from_cp.heading
|
||||||
pos_ascend = from_cp.position.point_from_heading(ascend_heading, 10000)
|
pos_ascend = from_cp.position.point_from_heading(ascend_heading, 10000)
|
||||||
ascend = FlightWaypoint(pos_ascend.x, pos_ascend.y, PATTERN_ALTITUDE)
|
ascend = FlightWaypoint(pos_ascend.x, pos_ascend.y, PATTERN_ALTITUDE)
|
||||||
@ -574,9 +679,15 @@ class FlightPlanner:
|
|||||||
ascend.waypoint_type = FlightWaypointType.ASCEND_POINT
|
ascend.waypoint_type = FlightWaypointType.ASCEND_POINT
|
||||||
return ascend
|
return ascend
|
||||||
|
|
||||||
|
|
||||||
def generate_descend_point(self, from_cp):
|
def generate_descend_point(self, from_cp):
|
||||||
|
"""
|
||||||
|
Generate approach/descend point
|
||||||
|
:param from_cp: Airport you're landing at
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
ascend_heading = from_cp.heading
|
ascend_heading = from_cp.heading
|
||||||
descend = from_cp.position.point_from_heading(ascend_heading - 180, 30000)
|
descend = from_cp.position.point_from_heading(ascend_heading - 180, 10000)
|
||||||
descend = FlightWaypoint(descend.x, descend.y, PATTERN_ALTITUDE)
|
descend = FlightWaypoint(descend.x, descend.y, PATTERN_ALTITUDE)
|
||||||
descend.name = "DESCEND"
|
descend.name = "DESCEND"
|
||||||
descend.alt_type = "RADIO"
|
descend.alt_type = "RADIO"
|
||||||
@ -585,7 +696,13 @@ class FlightPlanner:
|
|||||||
descend.waypoint_type = FlightWaypointType.DESCENT_POINT
|
descend.waypoint_type = FlightWaypointType.DESCENT_POINT
|
||||||
return descend
|
return descend
|
||||||
|
|
||||||
|
|
||||||
def generate_rtb_waypoint(self, from_cp):
|
def generate_rtb_waypoint(self, from_cp):
|
||||||
|
"""
|
||||||
|
Generate RTB landing point
|
||||||
|
:param from_cp: Airport you're landing at
|
||||||
|
:return:
|
||||||
|
"""
|
||||||
rtb = from_cp.position
|
rtb = from_cp.position
|
||||||
rtb = FlightWaypoint(rtb.x, rtb.y, 0)
|
rtb = FlightWaypoint(rtb.x, rtb.y, 0)
|
||||||
rtb.name = "LANDING"
|
rtb.name = "LANDING"
|
||||||
@ -594,4 +711,3 @@ class FlightPlanner:
|
|||||||
rtb.pretty_name = "RTB"
|
rtb.pretty_name = "RTB"
|
||||||
rtb.waypoint_type = FlightWaypointType.LANDING_POINT
|
rtb.waypoint_type = FlightWaypointType.LANDING_POINT
|
||||||
return rtb
|
return rtb
|
||||||
|
|
||||||
|
|||||||
@ -46,6 +46,18 @@ class FlightWaypointType(Enum):
|
|||||||
TARGET_POINT = 12 # A target building or static object, position
|
TARGET_POINT = 12 # A target building or static object, position
|
||||||
TARGET_GROUP_LOC = 13 # A target group approximate location
|
TARGET_GROUP_LOC = 13 # A target group approximate location
|
||||||
TARGET_SHIP = 14 # A target ship known location
|
TARGET_SHIP = 14 # A target ship known location
|
||||||
|
CUSTOM = 15 # User waypoint (no specific behaviour)
|
||||||
|
|
||||||
|
|
||||||
|
class PredefinedWaypointCategory(Enum):
|
||||||
|
NOT_PREDEFINED = 0
|
||||||
|
ALLY_CP = 1
|
||||||
|
ENEMY_CP = 2
|
||||||
|
FRONTLINE = 3
|
||||||
|
ENEMY_BUILDING = 4
|
||||||
|
ENEMY_UNIT = 5
|
||||||
|
ALLY_BUILDING = 6
|
||||||
|
ALLY_UNIT = 7
|
||||||
|
|
||||||
|
|
||||||
class FlightWaypoint:
|
class FlightWaypoint:
|
||||||
@ -61,7 +73,9 @@ class FlightWaypoint:
|
|||||||
self.obj_name = ""
|
self.obj_name = ""
|
||||||
self.pretty_name = ""
|
self.pretty_name = ""
|
||||||
self.waypoint_type = FlightWaypointType.TAKEOFF # type: FlightWaypointType
|
self.waypoint_type = FlightWaypointType.TAKEOFF # type: FlightWaypointType
|
||||||
|
self.category = PredefinedWaypointCategory.NOT_PREDEFINED# type: PredefinedWaypointCategory
|
||||||
self.only_for_player = False
|
self.only_for_player = False
|
||||||
|
self.data = None
|
||||||
|
|
||||||
|
|
||||||
class Flight:
|
class Flight:
|
||||||
|
|||||||
@ -1,153 +0,0 @@
|
|||||||
from PySide2.QtCore import QSortFilterProxyModel, Qt, QModelIndex
|
|
||||||
from PySide2.QtGui import QStandardItem, QStandardItemModel
|
|
||||||
from PySide2.QtWidgets import QComboBox, QCompleter
|
|
||||||
from game import Game
|
|
||||||
from gen import Conflict
|
|
||||||
from gen.flights.flight import FlightWaypoint
|
|
||||||
from theater import ControlPointType
|
|
||||||
|
|
||||||
|
|
||||||
class QPredefinedWaypointSelectionComboBox(QComboBox):
|
|
||||||
|
|
||||||
def __init__(self, game: Game, parent=None):
|
|
||||||
super(QPredefinedWaypointSelectionComboBox, self).__init__(parent)
|
|
||||||
|
|
||||||
self.game = game
|
|
||||||
self.setFocusPolicy(Qt.StrongFocus)
|
|
||||||
self.setEditable(True)
|
|
||||||
self.completer = QCompleter(self)
|
|
||||||
|
|
||||||
# always show all completions
|
|
||||||
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
|
|
||||||
self.pFilterModel = QSortFilterProxyModel(self)
|
|
||||||
self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
|
|
||||||
|
|
||||||
self.completer.setPopup(self.view())
|
|
||||||
|
|
||||||
self.setCompleter(self.completer)
|
|
||||||
|
|
||||||
self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString)
|
|
||||||
self.completer.activated.connect(self.setTextIfCompleterIsClicked)
|
|
||||||
|
|
||||||
self.find_possible_waypoints()
|
|
||||||
|
|
||||||
def setModel(self, model):
|
|
||||||
super(QPredefinedWaypointSelectionComboBox, self).setModel(model)
|
|
||||||
self.pFilterModel.setSourceModel(model)
|
|
||||||
self.completer.setModel(self.pFilterModel)
|
|
||||||
|
|
||||||
def setModelColumn(self, column):
|
|
||||||
self.completer.setCompletionColumn(column)
|
|
||||||
self.pFilterModel.setFilterKeyColumn(column)
|
|
||||||
super(QPredefinedWaypointSelectionComboBox, self).setModelColumn(column)
|
|
||||||
|
|
||||||
def view(self):
|
|
||||||
return self.completer.popup()
|
|
||||||
|
|
||||||
def index(self):
|
|
||||||
return self.currentIndex()
|
|
||||||
|
|
||||||
def setTextIfCompleterIsClicked(self, text):
|
|
||||||
if text:
|
|
||||||
index = self.findText(text)
|
|
||||||
self.setCurrentIndex(index)
|
|
||||||
|
|
||||||
def get_selected_waypoints(self, include_all_from_same_location=False):
|
|
||||||
n = self.currentText()
|
|
||||||
|
|
||||||
first_waypoint = None
|
|
||||||
for w in self.wpts:
|
|
||||||
if w.pretty_name == n:
|
|
||||||
first_waypoint = w
|
|
||||||
break
|
|
||||||
|
|
||||||
if first_waypoint is None:
|
|
||||||
return []
|
|
||||||
|
|
||||||
waypoints = [first_waypoint]
|
|
||||||
if include_all_from_same_location:
|
|
||||||
for w in self.wpts:
|
|
||||||
if w is not first_waypoint and w.obj_name and w.obj_name == first_waypoint.obj_name:
|
|
||||||
waypoints.append(w)
|
|
||||||
|
|
||||||
return waypoints
|
|
||||||
|
|
||||||
def find_possible_waypoints(self):
|
|
||||||
|
|
||||||
self.wpts = []
|
|
||||||
model = QStandardItemModel()
|
|
||||||
i = 0
|
|
||||||
|
|
||||||
def add_model_item(i, model, name, wpt):
|
|
||||||
print(name)
|
|
||||||
item = QStandardItem(name)
|
|
||||||
model.setItem(i, 0, item)
|
|
||||||
self.wpts.append(wpt)
|
|
||||||
return i + 1
|
|
||||||
|
|
||||||
for cp in self.game.theater.controlpoints:
|
|
||||||
print(cp)
|
|
||||||
if cp.captured:
|
|
||||||
enemy_cp = [ecp for ecp in cp.connected_points if ecp.captured != cp.captured]
|
|
||||||
for ecp in enemy_cp:
|
|
||||||
pos = Conflict.frontline_position(self.game.theater, cp, ecp)[0]
|
|
||||||
wpt = FlightWaypoint(pos.x, pos.y, 800)
|
|
||||||
wpt.name = "Frontline " + cp.name + "/" + ecp.name + " [CAS]"
|
|
||||||
wpt.alt_type = "RADIO"
|
|
||||||
wpt.pretty_name = wpt.name
|
|
||||||
wpt.description = "Frontline"
|
|
||||||
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
|
||||||
|
|
||||||
for cp in self.game.theater.controlpoints:
|
|
||||||
for ground_object in cp.ground_objects:
|
|
||||||
if not ground_object.is_dead and not ground_object.dcs_identifier == "AA":
|
|
||||||
wpt = FlightWaypoint(ground_object.position.x,ground_object.position.y, 0)
|
|
||||||
wpt.alt_type = "RADIO"
|
|
||||||
wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + ground_object.category + " #" + str(ground_object.object_id)
|
|
||||||
wpt.pretty_name = wpt.name
|
|
||||||
wpt.obj_name = ground_object.obj_name
|
|
||||||
wpt.targets.append(ground_object)
|
|
||||||
if cp.captured:
|
|
||||||
wpt.description = "Friendly Building"
|
|
||||||
else:
|
|
||||||
wpt.description = "Enemy Building"
|
|
||||||
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
|
||||||
|
|
||||||
for cp in self.game.theater.controlpoints:
|
|
||||||
|
|
||||||
for ground_object in cp.ground_objects:
|
|
||||||
if not ground_object.is_dead and ground_object.dcs_identifier == "AA":
|
|
||||||
for g in ground_object.groups:
|
|
||||||
for j, u in enumerate(g.units):
|
|
||||||
wpt = FlightWaypoint(u.position.x, u.position.y, 0)
|
|
||||||
wpt.alt_type = "RADIO"
|
|
||||||
wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + u.type + " #" + str(j)
|
|
||||||
wpt.pretty_name = wpt.name
|
|
||||||
wpt.targets.append(u)
|
|
||||||
wpt.obj_name = ground_object.obj_name
|
|
||||||
if cp.captured:
|
|
||||||
wpt.description = "Friendly unit : " + u.type
|
|
||||||
else:
|
|
||||||
wpt.description = "Enemy unit : " + u.type
|
|
||||||
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
|
||||||
|
|
||||||
for cp in self.game.theater.controlpoints:
|
|
||||||
|
|
||||||
wpt = FlightWaypoint(cp.position.x, cp.position.y, 0)
|
|
||||||
wpt.alt_type = "RADIO"
|
|
||||||
wpt.name = cp.name
|
|
||||||
if cp.captured:
|
|
||||||
wpt.description = "Position of " + cp.name + " [Friendly Airbase]"
|
|
||||||
else:
|
|
||||||
wpt.description = "Position of " + cp.name + " [Enemy Airbase]"
|
|
||||||
|
|
||||||
if cp.cptype == ControlPointType.AIRCRAFT_CARRIER_GROUP:
|
|
||||||
wpt.pretty_name = cp.name + " (Aircraft Carrier Group)"
|
|
||||||
elif cp.cptype == ControlPointType.LHA_GROUP:
|
|
||||||
wpt.pretty_name = cp.name + " (LHA Group)"
|
|
||||||
else:
|
|
||||||
wpt.pretty_name = cp.name + " (Airbase)"
|
|
||||||
|
|
||||||
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
|
||||||
|
|
||||||
self.setModel(model)
|
|
||||||
53
qt_ui/widgets/combos/QFilteredComboBox.py
Normal file
53
qt_ui/widgets/combos/QFilteredComboBox.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
from PySide2.QtCore import QSortFilterProxyModel, Qt
|
||||||
|
from PySide2.QtWidgets import QComboBox, QCompleter
|
||||||
|
|
||||||
|
|
||||||
|
class QFilteredComboBox(QComboBox):
|
||||||
|
|
||||||
|
def __init__(self, parent=None, include_targets=True, include_airbases=True,
|
||||||
|
include_frontlines=True, include_units=True, include_enemy=True, include_friendly=True):
|
||||||
|
super(QFilteredComboBox, self).__init__(parent)
|
||||||
|
|
||||||
|
self.setFocusPolicy(Qt.StrongFocus)
|
||||||
|
self.setEditable(True)
|
||||||
|
self.completer = QCompleter(self)
|
||||||
|
|
||||||
|
self.include_targets = include_targets
|
||||||
|
self.include_airbases = include_airbases
|
||||||
|
self.include_frontlines = include_frontlines
|
||||||
|
self.include_units = include_units
|
||||||
|
self.include_enemy = include_enemy
|
||||||
|
self.include_friendly = include_friendly
|
||||||
|
|
||||||
|
# always show all completions
|
||||||
|
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
|
||||||
|
self.pFilterModel = QSortFilterProxyModel(self)
|
||||||
|
self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
|
||||||
|
|
||||||
|
self.completer.setPopup(self.view())
|
||||||
|
|
||||||
|
self.setCompleter(self.completer)
|
||||||
|
|
||||||
|
self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString)
|
||||||
|
self.completer.activated.connect(self.setTextIfCompleterIsClicked)
|
||||||
|
|
||||||
|
def setModel(self, model):
|
||||||
|
super(QFilteredComboBox, self).setModel(model)
|
||||||
|
self.pFilterModel.setSourceModel(model)
|
||||||
|
self.completer.setModel(self.pFilterModel)
|
||||||
|
|
||||||
|
def setModelColumn(self, column):
|
||||||
|
self.completer.setCompletionColumn(column)
|
||||||
|
self.pFilterModel.setFilterKeyColumn(column)
|
||||||
|
super(QFilteredComboBox, self).setModelColumn(column)
|
||||||
|
|
||||||
|
def view(self):
|
||||||
|
return self.completer.popup()
|
||||||
|
|
||||||
|
def index(self):
|
||||||
|
return self.currentIndex()
|
||||||
|
|
||||||
|
def setTextIfCompleterIsClicked(self, text):
|
||||||
|
if text:
|
||||||
|
index = self.findText(text)
|
||||||
|
self.setCurrentIndex(index)
|
||||||
139
qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py
Normal file
139
qt_ui/widgets/combos/QPredefinedWaypointSelectionComboBox.py
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
from PySide2.QtCore import QSortFilterProxyModel, Qt, QModelIndex
|
||||||
|
from PySide2.QtGui import QStandardItem, QStandardItemModel
|
||||||
|
from PySide2.QtWidgets import QComboBox, QCompleter
|
||||||
|
from game import Game
|
||||||
|
from gen import Conflict, FlightWaypointType
|
||||||
|
from gen.flights.flight import FlightWaypoint, PredefinedWaypointCategory
|
||||||
|
from qt_ui.widgets.combos.QFilteredComboBox import QFilteredComboBox
|
||||||
|
from theater import ControlPointType
|
||||||
|
|
||||||
|
|
||||||
|
class QPredefinedWaypointSelectionComboBox(QFilteredComboBox):
|
||||||
|
|
||||||
|
def __init__(self, game: Game, parent=None, include_targets=True, include_airbases=True,
|
||||||
|
include_frontlines=True, include_units=True, include_enemy=True, include_friendly=True):
|
||||||
|
super(QPredefinedWaypointSelectionComboBox, self).__init__(parent)
|
||||||
|
self.game = game
|
||||||
|
self.include_targets = include_targets
|
||||||
|
self.include_airbases = include_airbases
|
||||||
|
self.include_frontlines = include_frontlines
|
||||||
|
self.include_units = include_units
|
||||||
|
self.include_enemy = include_enemy
|
||||||
|
self.include_friendly = include_friendly
|
||||||
|
self.find_possible_waypoints()
|
||||||
|
|
||||||
|
def get_selected_waypoints(self, include_all_from_same_location=False):
|
||||||
|
n = self.currentText()
|
||||||
|
first_waypoint = None
|
||||||
|
for w in self.wpts:
|
||||||
|
if w.pretty_name == n:
|
||||||
|
first_waypoint = w
|
||||||
|
break
|
||||||
|
if first_waypoint is None:
|
||||||
|
return []
|
||||||
|
waypoints = [first_waypoint]
|
||||||
|
if include_all_from_same_location:
|
||||||
|
for w in self.wpts:
|
||||||
|
if w is not first_waypoint and w.obj_name and w.obj_name == first_waypoint.obj_name:
|
||||||
|
waypoints.append(w)
|
||||||
|
return waypoints
|
||||||
|
|
||||||
|
def find_possible_waypoints(self):
|
||||||
|
|
||||||
|
self.wpts = []
|
||||||
|
model = QStandardItemModel()
|
||||||
|
i = 0
|
||||||
|
|
||||||
|
def add_model_item(i, model, name, wpt):
|
||||||
|
print(name)
|
||||||
|
item = QStandardItem(name)
|
||||||
|
model.setItem(i, 0, item)
|
||||||
|
self.wpts.append(wpt)
|
||||||
|
return i + 1
|
||||||
|
|
||||||
|
if self.include_frontlines:
|
||||||
|
for cp in self.game.theater.controlpoints:
|
||||||
|
if cp.captured:
|
||||||
|
enemy_cp = [ecp for ecp in cp.connected_points if ecp.captured != cp.captured]
|
||||||
|
for ecp in enemy_cp:
|
||||||
|
pos = Conflict.frontline_position(self.game.theater, cp, ecp)[0]
|
||||||
|
wpt = FlightWaypoint(pos.x, pos.y, 800)
|
||||||
|
wpt.name = "Frontline " + cp.name + "/" + ecp.name + " [CAS]"
|
||||||
|
wpt.alt_type = "RADIO"
|
||||||
|
wpt.pretty_name = wpt.name
|
||||||
|
wpt.description = "Frontline"
|
||||||
|
wpt.data = [cp, ecp]
|
||||||
|
wpt.waypoint_type = FlightWaypointType.CUSTOM
|
||||||
|
wpt.category = PredefinedWaypointCategory.FRONTLINE
|
||||||
|
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
||||||
|
|
||||||
|
if self.include_targets:
|
||||||
|
for cp in self.game.theater.controlpoints:
|
||||||
|
if (self.include_enemy and not cp.captured) or (self.include_friendly and cp.captured):
|
||||||
|
for ground_object in cp.ground_objects:
|
||||||
|
if not ground_object.is_dead and not ground_object.dcs_identifier == "AA":
|
||||||
|
wpt = FlightWaypoint(ground_object.position.x,ground_object.position.y, 0)
|
||||||
|
wpt.alt_type = "RADIO"
|
||||||
|
wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + ground_object.category + " #" + str(ground_object.object_id)
|
||||||
|
wpt.pretty_name = wpt.name
|
||||||
|
wpt.obj_name = ground_object.obj_name
|
||||||
|
wpt.targets.append(ground_object)
|
||||||
|
wpt.data = ground_object
|
||||||
|
wpt.waypoint_type = FlightWaypointType.CUSTOM
|
||||||
|
if cp.captured:
|
||||||
|
wpt.description = "Friendly Building"
|
||||||
|
wpt.category = PredefinedWaypointCategory.ALLY_BUILDING
|
||||||
|
else:
|
||||||
|
wpt.description = "Enemy Building"
|
||||||
|
wpt.category = PredefinedWaypointCategory.ENEMY_BUILDING
|
||||||
|
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
||||||
|
|
||||||
|
if self.include_units:
|
||||||
|
for cp in self.game.theater.controlpoints:
|
||||||
|
if (self.include_enemy and not cp.captured) or (self.include_friendly and cp.captured):
|
||||||
|
for ground_object in cp.ground_objects:
|
||||||
|
if not ground_object.is_dead and ground_object.dcs_identifier == "AA":
|
||||||
|
for g in ground_object.groups:
|
||||||
|
for j, u in enumerate(g.units):
|
||||||
|
wpt = FlightWaypoint(u.position.x, u.position.y, 0)
|
||||||
|
wpt.alt_type = "RADIO"
|
||||||
|
wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + u.type + " #" + str(j)
|
||||||
|
wpt.pretty_name = wpt.name
|
||||||
|
wpt.targets.append(u)
|
||||||
|
wpt.data = u
|
||||||
|
wpt.obj_name = ground_object.obj_name
|
||||||
|
wpt.waypoint_type = FlightWaypointType.CUSTOM
|
||||||
|
if cp.captured:
|
||||||
|
wpt.description = "Friendly unit : " + u.type
|
||||||
|
wpt.category = PredefinedWaypointCategory.ALLY_UNIT
|
||||||
|
else:
|
||||||
|
wpt.description = "Enemy unit : " + u.type
|
||||||
|
wpt.category = PredefinedWaypointCategory.ENEMY_UNIT
|
||||||
|
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
||||||
|
|
||||||
|
if self.include_airbases:
|
||||||
|
for cp in self.game.theater.controlpoints:
|
||||||
|
if (self.include_enemy and not cp.captured) or (self.include_friendly and cp.captured):
|
||||||
|
wpt = FlightWaypoint(cp.position.x, cp.position.y, 0)
|
||||||
|
wpt.alt_type = "RADIO"
|
||||||
|
wpt.name = cp.name
|
||||||
|
wpt.data = cp
|
||||||
|
wpt.waypoint_type = FlightWaypointType.CUSTOM
|
||||||
|
if cp.captured:
|
||||||
|
wpt.description = "Position of " + cp.name + " [Friendly Airbase]"
|
||||||
|
wpt.category = PredefinedWaypointCategory.ALLY_CP
|
||||||
|
else:
|
||||||
|
wpt.description = "Position of " + cp.name + " [Enemy Airbase]"
|
||||||
|
wpt.category = PredefinedWaypointCategory.ENEMY_CP
|
||||||
|
|
||||||
|
if cp.cptype == ControlPointType.AIRCRAFT_CARRIER_GROUP:
|
||||||
|
wpt.pretty_name = cp.name + " (Aircraft Carrier Group)"
|
||||||
|
elif cp.cptype == ControlPointType.LHA_GROUP:
|
||||||
|
wpt.pretty_name = cp.name + " (LHA Group)"
|
||||||
|
else:
|
||||||
|
wpt.pretty_name = cp.name + " (Airbase)"
|
||||||
|
|
||||||
|
|
||||||
|
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
||||||
|
|
||||||
|
self.setModel(model)
|
||||||
76
qt_ui/widgets/combos/QSEADTargetSelectionComboBox.py
Normal file
76
qt_ui/widgets/combos/QSEADTargetSelectionComboBox.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
from PySide2.QtCore import QSortFilterProxyModel, Qt, QModelIndex
|
||||||
|
from PySide2.QtGui import QStandardItem, QStandardItemModel
|
||||||
|
from PySide2.QtWidgets import QComboBox, QCompleter
|
||||||
|
from game import Game
|
||||||
|
from gen import Conflict, FlightWaypointType, db
|
||||||
|
from gen.flights.flight import FlightWaypoint, PredefinedWaypointCategory
|
||||||
|
from qt_ui.widgets.combos.QFilteredComboBox import QFilteredComboBox
|
||||||
|
from theater import ControlPointType
|
||||||
|
|
||||||
|
|
||||||
|
class SEADTargetInfo:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.name = ""
|
||||||
|
self.location = None
|
||||||
|
self.radars = []
|
||||||
|
self.threat_range = 0
|
||||||
|
self.detection_range = 0
|
||||||
|
|
||||||
|
class QSEADTargetSelectionComboBox(QFilteredComboBox):
|
||||||
|
|
||||||
|
def __init__(self, game: Game, parent=None):
|
||||||
|
super(QSEADTargetSelectionComboBox, self).__init__(parent)
|
||||||
|
self.game = game
|
||||||
|
self.find_possible_sead_targets()
|
||||||
|
|
||||||
|
def get_selected_target(self):
|
||||||
|
n = self.currentText()
|
||||||
|
for target in self.targets:
|
||||||
|
if target.name == n:
|
||||||
|
return target
|
||||||
|
|
||||||
|
def find_possible_sead_targets(self):
|
||||||
|
|
||||||
|
self.targets = []
|
||||||
|
i = 0
|
||||||
|
model = QStandardItemModel()
|
||||||
|
|
||||||
|
def add_model_item(i, model, target):
|
||||||
|
item = QStandardItem(target.name)
|
||||||
|
model.setItem(i, 0, item)
|
||||||
|
self.targets.append(target)
|
||||||
|
return i + 1
|
||||||
|
|
||||||
|
for cp in self.game.theater.controlpoints:
|
||||||
|
if cp.captured: continue
|
||||||
|
for g in cp.ground_objects:
|
||||||
|
|
||||||
|
radars = []
|
||||||
|
detection_range = 0
|
||||||
|
threat_range = 0
|
||||||
|
if g.dcs_identifier == "AA":
|
||||||
|
for group in g.groups:
|
||||||
|
for u in group.units:
|
||||||
|
utype = db.unit_type_from_name(u.type)
|
||||||
|
if hasattr(utype, "detection_range") and utype.detection_range > 1000:
|
||||||
|
if utype.detection_range > detection_range:
|
||||||
|
detection_range = utype.detection_range
|
||||||
|
radars.append(u)
|
||||||
|
if hasattr(utype, "threat_range"):
|
||||||
|
if utype.threat_range > threat_range:
|
||||||
|
threat_range = utype.threat_range
|
||||||
|
if len(radars) > 0:
|
||||||
|
tgt_info = SEADTargetInfo()
|
||||||
|
tgt_info.name = g.obj_name + " [" + ",".join([db.unit_type_from_name(u.type).id for u in radars]) + " ]"
|
||||||
|
if len(tgt_info.name) > 25:
|
||||||
|
tgt_info.name = g.obj_name + " [" + str(len(radars)) + " units]"
|
||||||
|
tgt_info.radars = radars
|
||||||
|
tgt_info.location = g
|
||||||
|
tgt_info.threat_range = threat_range
|
||||||
|
tgt_info.detection_range = detection_range
|
||||||
|
i = add_model_item(i, model, tgt_info)
|
||||||
|
|
||||||
|
self.setModel(model)
|
||||||
|
|
||||||
|
|
||||||
69
qt_ui/widgets/combos/QStrikeTargetSelectionComboBox.py
Normal file
69
qt_ui/widgets/combos/QStrikeTargetSelectionComboBox.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
from PySide2.QtGui import QStandardItem, QStandardItemModel
|
||||||
|
|
||||||
|
from game import Game
|
||||||
|
from qt_ui.widgets.combos.QFilteredComboBox import QFilteredComboBox
|
||||||
|
|
||||||
|
|
||||||
|
class StrikeTargetInfo:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.name = ""
|
||||||
|
self.location = None
|
||||||
|
self.units = []
|
||||||
|
self.buildings = []
|
||||||
|
|
||||||
|
|
||||||
|
class QStrikeTargetSelectionComboBox(QFilteredComboBox):
|
||||||
|
|
||||||
|
def __init__(self, game: Game, parent=None):
|
||||||
|
super(QStrikeTargetSelectionComboBox, self).__init__(parent)
|
||||||
|
self.game = game
|
||||||
|
self.find_possible_strike_targets()
|
||||||
|
|
||||||
|
def get_selected_target(self):
|
||||||
|
n = self.currentText()
|
||||||
|
for target in self.targets:
|
||||||
|
if target.name == n:
|
||||||
|
return target
|
||||||
|
|
||||||
|
def find_possible_strike_targets(self):
|
||||||
|
|
||||||
|
self.targets = []
|
||||||
|
i = 0
|
||||||
|
model = QStandardItemModel()
|
||||||
|
|
||||||
|
def add_model_item(i, model, target):
|
||||||
|
item = QStandardItem(target.name)
|
||||||
|
model.setItem(i, 0, item)
|
||||||
|
self.targets.append(target)
|
||||||
|
return i + 1
|
||||||
|
|
||||||
|
for cp in self.game.theater.controlpoints:
|
||||||
|
if cp.captured: continue
|
||||||
|
|
||||||
|
added_obj_names = []
|
||||||
|
|
||||||
|
for g in cp.ground_objects:
|
||||||
|
if g.obj_name in added_obj_names: continue
|
||||||
|
|
||||||
|
target = StrikeTargetInfo()
|
||||||
|
target.location = g
|
||||||
|
target.name = g.obj_name
|
||||||
|
|
||||||
|
if g.dcs_identifier == "AA":
|
||||||
|
target.name = g.obj_name + " [units]"
|
||||||
|
for group in g.groups:
|
||||||
|
for u in group.units:
|
||||||
|
target.units.append(u)
|
||||||
|
else:
|
||||||
|
target.name = g.obj_name + " [" + g.category + "]"
|
||||||
|
for g2 in cp.ground_objects:
|
||||||
|
if g2 is not g and g2.obj_name == g.obj_name:
|
||||||
|
target.buildings.append(g2)
|
||||||
|
|
||||||
|
i = add_model_item(i, model, target)
|
||||||
|
added_obj_names.append(g.obj_name)
|
||||||
|
|
||||||
|
self.setModel(model)
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
from PySide2.QtCore import Qt
|
||||||
|
from PySide2.QtWidgets import QDialog, QPushButton
|
||||||
|
|
||||||
|
from game import Game
|
||||||
|
from gen.flights.flight import Flight
|
||||||
|
from qt_ui.uiconstants import EVENT_ICONS
|
||||||
|
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import QFlightWaypointInfoBox
|
||||||
|
|
||||||
|
|
||||||
|
class QAbstractMissionGenerator(QDialog):
|
||||||
|
|
||||||
|
def __init__(self, game: Game, flight: Flight, flight_waypoint_list, title):
|
||||||
|
super(QAbstractMissionGenerator, self).__init__()
|
||||||
|
self.game = game
|
||||||
|
self.flight = flight
|
||||||
|
self.setWindowFlags(Qt.WindowStaysOnTopHint)
|
||||||
|
self.setMinimumSize(400, 250)
|
||||||
|
self.setModal(True)
|
||||||
|
self.setWindowTitle(title)
|
||||||
|
self.setWindowIcon(EVENT_ICONS["strike"])
|
||||||
|
self.flight_waypoint_list = flight_waypoint_list
|
||||||
|
self.planner = self.game.planners[self.flight.from_cp.id]
|
||||||
|
|
||||||
|
self.selected_waypoints = []
|
||||||
|
self.wpt_info = QFlightWaypointInfoBox()
|
||||||
|
|
||||||
|
self.ok_button = QPushButton("Ok")
|
||||||
|
self.ok_button.clicked.connect(self.apply)
|
||||||
|
|
||||||
|
def on_select_wpt_changed(self):
|
||||||
|
self.selected_waypoints = self.wpt_selection_box.get_selected_waypoints(False)
|
||||||
|
if self.selected_waypoints is None or len(self.selected_waypoints) <= 0:
|
||||||
|
self.ok_button.setDisabled(True)
|
||||||
|
else:
|
||||||
|
self.wpt_info.set_flight_waypoint(self.selected_waypoints[0])
|
||||||
|
self.ok_button.setDisabled(False)
|
||||||
|
|
||||||
|
def apply(self):
|
||||||
|
raise NotImplementedError()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,52 @@
|
|||||||
|
from PySide2.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout
|
||||||
|
|
||||||
|
from game import Game
|
||||||
|
from gen.flights.flight import Flight, PredefinedWaypointCategory
|
||||||
|
from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import QPredefinedWaypointSelectionComboBox
|
||||||
|
from qt_ui.windows.mission.flight.generator.QAbstractMissionGenerator import QAbstractMissionGenerator
|
||||||
|
|
||||||
|
|
||||||
|
class QCAPMissionGenerator(QAbstractMissionGenerator):
|
||||||
|
|
||||||
|
def __init__(self, game: Game, flight: Flight, flight_waypoint_list):
|
||||||
|
super(QCAPMissionGenerator, self).__init__(game, flight, flight_waypoint_list, "CAP Generator")
|
||||||
|
|
||||||
|
self.wpt_selection_box = QPredefinedWaypointSelectionComboBox(self.game, self, False, True, True, False, False, True)
|
||||||
|
self.wpt_selection_box.setMinimumWidth(200)
|
||||||
|
self.wpt_selection_box.currentTextChanged.connect(self.on_select_wpt_changed)
|
||||||
|
|
||||||
|
self.init_ui()
|
||||||
|
self.on_select_wpt_changed()
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
|
wpt_layout = QHBoxLayout()
|
||||||
|
wpt_layout.addWidget(QLabel("CAP mission on : "))
|
||||||
|
wpt_layout.addWidget(self.wpt_selection_box)
|
||||||
|
wpt_layout.addStretch()
|
||||||
|
|
||||||
|
layout.addLayout(wpt_layout)
|
||||||
|
layout.addWidget(self.wpt_info)
|
||||||
|
layout.addStretch()
|
||||||
|
layout.addWidget(self.ok_button)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
def apply(self):
|
||||||
|
self.flight.points = []
|
||||||
|
|
||||||
|
wpt = self.selected_waypoints[0]
|
||||||
|
if wpt.category == PredefinedWaypointCategory.FRONTLINE:
|
||||||
|
self.planner.generate_frontline_cap(self.flight, wpt.data[0], wpt.data[1])
|
||||||
|
elif wpt.category == PredefinedWaypointCategory.ALLY_CP:
|
||||||
|
self.planner.generate_barcap(self.flight, wpt.data)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
self.flight_waypoint_list.update_list()
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
from PySide2.QtGui import Qt
|
||||||
|
from PySide2.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout
|
||||||
|
from dcs import Point
|
||||||
|
|
||||||
|
from game import Game
|
||||||
|
from gen.flights.ai_flight_planner import meter_to_nm
|
||||||
|
from gen.flights.flight import Flight
|
||||||
|
from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import QPredefinedWaypointSelectionComboBox
|
||||||
|
from qt_ui.windows.mission.flight.generator.QAbstractMissionGenerator import QAbstractMissionGenerator
|
||||||
|
|
||||||
|
|
||||||
|
class QCASMissionGenerator(QAbstractMissionGenerator):
|
||||||
|
|
||||||
|
def __init__(self, game: Game, flight: Flight, flight_waypoint_list):
|
||||||
|
super(QCASMissionGenerator, self).__init__(game, flight, flight_waypoint_list, "CAS Generator")
|
||||||
|
|
||||||
|
self.wpt_selection_box = QPredefinedWaypointSelectionComboBox(self.game, self, False, False, True, False, False)
|
||||||
|
self.wpt_selection_box.setMinimumWidth(200)
|
||||||
|
self.wpt_selection_box.currentTextChanged.connect(self.on_select_wpt_changed)
|
||||||
|
|
||||||
|
self.distanceToTargetLabel = QLabel("0 nm")
|
||||||
|
self.init_ui()
|
||||||
|
self.on_select_wpt_changed()
|
||||||
|
|
||||||
|
def on_select_wpt_changed(self):
|
||||||
|
super(QCASMissionGenerator, self).on_select_wpt_changed()
|
||||||
|
wpts = self.wpt_selection_box.get_selected_waypoints()
|
||||||
|
|
||||||
|
if len(wpts) > 0:
|
||||||
|
self.distanceToTargetLabel.setText("~" + str(meter_to_nm(self.flight.from_cp.position.distance_to_point(Point(wpts[0].x, wpts[0].y)))) + " nm")
|
||||||
|
else:
|
||||||
|
self.distanceToTargetLabel.setText("??? nm")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
|
wpt_layout = QHBoxLayout()
|
||||||
|
wpt_layout.addWidget(QLabel("CAS : "))
|
||||||
|
wpt_layout.addWidget(self.wpt_selection_box)
|
||||||
|
wpt_layout.addStretch()
|
||||||
|
|
||||||
|
distToTarget = QHBoxLayout()
|
||||||
|
distToTarget.addWidget(QLabel("Distance to target : "))
|
||||||
|
distToTarget.addStretch()
|
||||||
|
distToTarget.addWidget(self.distanceToTargetLabel, alignment=Qt.AlignRight)
|
||||||
|
|
||||||
|
layout.addLayout(wpt_layout)
|
||||||
|
layout.addWidget(self.wpt_info)
|
||||||
|
layout.addLayout(distToTarget)
|
||||||
|
layout.addStretch()
|
||||||
|
layout.addWidget(self.ok_button)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
def apply(self):
|
||||||
|
self.flight.points = []
|
||||||
|
self.planner.generate_cas(self.flight, self.selected_waypoints[0].data[0], self.selected_waypoints[0].data[1])
|
||||||
|
self.flight_waypoint_list.update_list()
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,73 @@
|
|||||||
|
from PySide2.QtGui import Qt
|
||||||
|
from PySide2.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout
|
||||||
|
|
||||||
|
from game import Game
|
||||||
|
from gen.flights.ai_flight_planner import meter_to_nm
|
||||||
|
from gen.flights.flight import Flight
|
||||||
|
from qt_ui.widgets.combos.QSEADTargetSelectionComboBox import QSEADTargetSelectionComboBox
|
||||||
|
from qt_ui.windows.mission.flight.generator.QAbstractMissionGenerator import QAbstractMissionGenerator
|
||||||
|
|
||||||
|
|
||||||
|
class QSEADMissionGenerator(QAbstractMissionGenerator):
|
||||||
|
|
||||||
|
def __init__(self, game: Game, flight: Flight, flight_waypoint_list):
|
||||||
|
super(QSEADMissionGenerator, self).__init__(game, flight, flight_waypoint_list, "SEAD/DEAD Generator")
|
||||||
|
|
||||||
|
self.tgt_selection_box = QSEADTargetSelectionComboBox(self.game)
|
||||||
|
self.tgt_selection_box.setMinimumWidth(200)
|
||||||
|
self.tgt_selection_box.currentTextChanged.connect(self.on_selected_target_changed)
|
||||||
|
|
||||||
|
self.distanceToTargetLabel = QLabel("0 nm")
|
||||||
|
self.threatRangeLabel = QLabel("0 nm")
|
||||||
|
self.detectionRangeLabel = QLabel("0 nm")
|
||||||
|
self.init_ui()
|
||||||
|
self.on_selected_target_changed()
|
||||||
|
|
||||||
|
def on_selected_target_changed(self):
|
||||||
|
target = self.tgt_selection_box.get_selected_target()
|
||||||
|
self.distanceToTargetLabel.setText("~" + str(meter_to_nm(self.flight.from_cp.position.distance_to_point(target.location.position))) + " nm")
|
||||||
|
self.threatRangeLabel.setText(str(meter_to_nm(target.threat_range)) + " nm")
|
||||||
|
self.detectionRangeLabel.setText(str(meter_to_nm(target.detection_range)) + " nm")
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
|
wpt_layout = QHBoxLayout()
|
||||||
|
wpt_layout.addWidget(QLabel("SEAD/DEAD target : "))
|
||||||
|
wpt_layout.addStretch()
|
||||||
|
wpt_layout.addWidget(self.tgt_selection_box, alignment=Qt.AlignRight)
|
||||||
|
|
||||||
|
distToTarget = QHBoxLayout()
|
||||||
|
distToTarget.addWidget(QLabel("Distance to site : "))
|
||||||
|
distToTarget.addStretch()
|
||||||
|
distToTarget.addWidget(self.distanceToTargetLabel, alignment=Qt.AlignRight)
|
||||||
|
|
||||||
|
threatRangeLayout = QHBoxLayout()
|
||||||
|
threatRangeLayout.addWidget(QLabel("Site threat range : "))
|
||||||
|
threatRangeLayout.addStretch()
|
||||||
|
threatRangeLayout.addWidget(self.threatRangeLabel, alignment=Qt.AlignRight)
|
||||||
|
|
||||||
|
detectionRangeLayout = QHBoxLayout()
|
||||||
|
detectionRangeLayout.addWidget(QLabel("Site radar detection range: "))
|
||||||
|
detectionRangeLayout.addStretch()
|
||||||
|
detectionRangeLayout.addWidget(self.detectionRangeLabel, alignment=Qt.AlignRight)
|
||||||
|
|
||||||
|
layout.addLayout(wpt_layout)
|
||||||
|
layout.addLayout(distToTarget)
|
||||||
|
layout.addLayout(threatRangeLayout)
|
||||||
|
layout.addLayout(detectionRangeLayout)
|
||||||
|
layout.addStretch()
|
||||||
|
layout.addWidget(self.ok_button)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
def apply(self):
|
||||||
|
self.flight.points = []
|
||||||
|
target = self.tgt_selection_box.get_selected_target()
|
||||||
|
self.planner.generate_sead(self.flight, target.location, target.radars)
|
||||||
|
self.flight_waypoint_list.update_list()
|
||||||
|
self.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,57 @@
|
|||||||
|
from PySide2.QtGui import Qt
|
||||||
|
from PySide2.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout
|
||||||
|
|
||||||
|
from game import Game
|
||||||
|
from gen.flights.ai_flight_planner import meter_to_nm
|
||||||
|
from gen.flights.flight import Flight
|
||||||
|
from qt_ui.widgets.combos.QStrikeTargetSelectionComboBox import QStrikeTargetSelectionComboBox
|
||||||
|
from qt_ui.windows.mission.flight.generator.QAbstractMissionGenerator import QAbstractMissionGenerator
|
||||||
|
|
||||||
|
|
||||||
|
class QSTRIKEMissionGenerator(QAbstractMissionGenerator):
|
||||||
|
|
||||||
|
def __init__(self, game: Game, flight: Flight, flight_waypoint_list):
|
||||||
|
super(QSTRIKEMissionGenerator, self).__init__(game, flight, flight_waypoint_list, "SEAD/DEAD Generator")
|
||||||
|
|
||||||
|
self.tgt_selection_box = QStrikeTargetSelectionComboBox(self.game)
|
||||||
|
self.tgt_selection_box.setMinimumWidth(200)
|
||||||
|
self.tgt_selection_box.currentTextChanged.connect(self.on_selected_target_changed)
|
||||||
|
|
||||||
|
self.distanceToTargetLabel = QLabel("0 nm")
|
||||||
|
self.init_ui()
|
||||||
|
self.on_selected_target_changed()
|
||||||
|
|
||||||
|
def on_selected_target_changed(self):
|
||||||
|
target = self.tgt_selection_box.get_selected_target()
|
||||||
|
self.distanceToTargetLabel.setText("~" + str(meter_to_nm(self.flight.from_cp.position.distance_to_point(target.location.position))) + " nm")
|
||||||
|
|
||||||
|
def init_ui(self):
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
|
||||||
|
wpt_layout = QHBoxLayout()
|
||||||
|
wpt_layout.addWidget(QLabel("SEAD/DEAD target : "))
|
||||||
|
wpt_layout.addStretch()
|
||||||
|
wpt_layout.addWidget(self.tgt_selection_box, alignment=Qt.AlignRight)
|
||||||
|
|
||||||
|
distToTarget = QHBoxLayout()
|
||||||
|
distToTarget.addWidget(QLabel("Distance to target : "))
|
||||||
|
distToTarget.addStretch()
|
||||||
|
distToTarget.addWidget(self.distanceToTargetLabel, alignment=Qt.AlignRight)
|
||||||
|
|
||||||
|
layout.addLayout(wpt_layout)
|
||||||
|
layout.addLayout(distToTarget)
|
||||||
|
layout.addStretch()
|
||||||
|
layout.addWidget(self.ok_button)
|
||||||
|
|
||||||
|
self.setLayout(layout)
|
||||||
|
|
||||||
|
def apply(self):
|
||||||
|
self.flight.points = []
|
||||||
|
# target = self.tgt_selection_box.get_selected_target()
|
||||||
|
# self.planner.generate_sead(self.flight, target.location, target.radars)
|
||||||
|
# self.flight_waypoint_list.update_list()
|
||||||
|
# self.close()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -1,6 +1,10 @@
|
|||||||
from PySide2.QtWidgets import QFrame, QGridLayout, QLabel, QPushButton, QVBoxLayout
|
from PySide2.QtWidgets import QFrame, QGridLayout, QLabel, QPushButton, QVBoxLayout
|
||||||
|
|
||||||
from gen.flights.flight import Flight
|
from gen.flights.flight import Flight, FlightWaypoint, FlightWaypointType
|
||||||
|
from qt_ui.windows.mission.flight.generator.QCAPMissionGenerator import QCAPMissionGenerator
|
||||||
|
from qt_ui.windows.mission.flight.generator.QCASMissionGenerator import QCASMissionGenerator
|
||||||
|
from qt_ui.windows.mission.flight.generator.QSEADMissionGenerator import QSEADMissionGenerator
|
||||||
|
from qt_ui.windows.mission.flight.generator.QSTRIKEMissionGenerator import QSTRIKEMissionGenerator
|
||||||
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import QFlightWaypointList
|
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointList import QFlightWaypointList
|
||||||
from qt_ui.windows.mission.flight.waypoints.QPredefinedWaypointSelectionWindow import QPredefinedWaypointSelectionWindow
|
from qt_ui.windows.mission.flight.waypoints.QPredefinedWaypointSelectionWindow import QPredefinedWaypointSelectionWindow
|
||||||
from game import Game
|
from game import Game
|
||||||
@ -11,6 +15,7 @@ class QFlightWaypointTab(QFrame):
|
|||||||
super(QFlightWaypointTab, self).__init__()
|
super(QFlightWaypointTab, self).__init__()
|
||||||
self.flight = flight
|
self.flight = flight
|
||||||
self.game = game
|
self.game = game
|
||||||
|
self.planner = self.game.planners[self.flight.from_cp.id]
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
|
|
||||||
def init_ui(self):
|
def init_ui(self):
|
||||||
@ -19,10 +24,44 @@ class QFlightWaypointTab(QFrame):
|
|||||||
self.flight_waypoint_list = QFlightWaypointList(self.flight)
|
self.flight_waypoint_list = QFlightWaypointList(self.flight)
|
||||||
self.open_fast_waypoint_button = QPushButton("Add Waypoint")
|
self.open_fast_waypoint_button = QPushButton("Add Waypoint")
|
||||||
self.open_fast_waypoint_button.clicked.connect(self.on_fast_waypoint)
|
self.open_fast_waypoint_button.clicked.connect(self.on_fast_waypoint)
|
||||||
|
|
||||||
|
self.cas_generator = QPushButton("Gen. CAS")
|
||||||
|
self.cas_generator.clicked.connect(self.on_cas_generator)
|
||||||
|
|
||||||
|
self.cap_generator = QPushButton("Gen. CAP")
|
||||||
|
self.cap_generator.clicked.connect(self.on_cap_generator)
|
||||||
|
|
||||||
|
self.sead_generator = QPushButton("Gen. SEAD/DEAD")
|
||||||
|
self.sead_generator.clicked.connect(self.on_sead_generator)
|
||||||
|
|
||||||
|
self.strike_generator = QPushButton("Gen. STRIKE")
|
||||||
|
self.strike_generator.clicked.connect(self.on_strike_generator)
|
||||||
|
|
||||||
|
self.rtb_waypoint = QPushButton("Add RTB Waypoint")
|
||||||
|
self.rtb_waypoint.clicked.connect(self.on_rtb_waypoint)
|
||||||
|
|
||||||
|
self.ascend_waypoint = QPushButton("Add Ascend Waypoint")
|
||||||
|
self.ascend_waypoint.clicked.connect(self.on_ascend_waypoint)
|
||||||
|
|
||||||
|
self.descend_waypoint = QPushButton("Add Descend Waypoint")
|
||||||
|
self.descend_waypoint.clicked.connect(self.on_descend_waypoint)
|
||||||
|
|
||||||
self.delete_selected = QPushButton("Delete Selected")
|
self.delete_selected = QPushButton("Delete Selected")
|
||||||
self.delete_selected.clicked.connect(self.on_delete_waypoint)
|
self.delete_selected.clicked.connect(self.on_delete_waypoint)
|
||||||
|
|
||||||
layout.addWidget(self.flight_waypoint_list,0,0)
|
layout.addWidget(self.flight_waypoint_list, 0, 0)
|
||||||
|
|
||||||
|
rlayout.addWidget(QLabel("<strong>Generator :</strong>"))
|
||||||
|
rlayout.addWidget(QLabel("<small>AI compatible</small>"))
|
||||||
|
rlayout.addWidget(self.cas_generator)
|
||||||
|
rlayout.addWidget(self.cap_generator)
|
||||||
|
rlayout.addWidget(self.sead_generator)
|
||||||
|
rlayout.addWidget(self.strike_generator)
|
||||||
|
rlayout.addWidget(QLabel("<strong>Advanced : </strong>"))
|
||||||
|
rlayout.addWidget(QLabel("<small>Do not use for AI flights</small>"))
|
||||||
|
rlayout.addWidget(self.ascend_waypoint)
|
||||||
|
rlayout.addWidget(self.descend_waypoint)
|
||||||
|
rlayout.addWidget(self.rtb_waypoint)
|
||||||
rlayout.addWidget(self.open_fast_waypoint_button)
|
rlayout.addWidget(self.open_fast_waypoint_button)
|
||||||
rlayout.addWidget(self.delete_selected)
|
rlayout.addWidget(self.delete_selected)
|
||||||
rlayout.addStretch()
|
rlayout.addStretch()
|
||||||
@ -38,3 +77,35 @@ class QFlightWaypointTab(QFrame):
|
|||||||
def on_fast_waypoint(self):
|
def on_fast_waypoint(self):
|
||||||
self.subwindow = QPredefinedWaypointSelectionWindow(self.game, self.flight, self.flight_waypoint_list)
|
self.subwindow = QPredefinedWaypointSelectionWindow(self.game, self.flight, self.flight_waypoint_list)
|
||||||
self.subwindow.show()
|
self.subwindow.show()
|
||||||
|
|
||||||
|
def on_ascend_waypoint(self):
|
||||||
|
ascend = self.planner.generate_ascend_point(self.flight.from_cp)
|
||||||
|
self.flight.points.append(ascend)
|
||||||
|
self.flight_waypoint_list.update_list()
|
||||||
|
|
||||||
|
def on_rtb_waypoint(self):
|
||||||
|
rtb = self.planner.generate_rtb_waypoint(self.flight.from_cp)
|
||||||
|
self.flight.points.append(rtb)
|
||||||
|
self.flight_waypoint_list.update_list()
|
||||||
|
|
||||||
|
def on_descend_waypoint(self):
|
||||||
|
descend = self.planner.generate_descend_point(self.flight.from_cp)
|
||||||
|
self.flight.points.append(descend)
|
||||||
|
self.flight_waypoint_list.update_list()
|
||||||
|
|
||||||
|
def on_cas_generator(self):
|
||||||
|
self.subwindow = QCASMissionGenerator(self.game, self.flight, self.flight_waypoint_list)
|
||||||
|
self.subwindow.show()
|
||||||
|
|
||||||
|
def on_cap_generator(self):
|
||||||
|
self.subwindow = QCAPMissionGenerator(self.game, self.flight, self.flight_waypoint_list)
|
||||||
|
self.subwindow.show()
|
||||||
|
|
||||||
|
def on_sead_generator(self):
|
||||||
|
self.subwindow = QSEADMissionGenerator(self.game, self.flight, self.flight_waypoint_list)
|
||||||
|
self.subwindow.show()
|
||||||
|
|
||||||
|
def on_strike_generator(self):
|
||||||
|
self.subwindow = QSTRIKEMissionGenerator(self.game, self.flight, self.flight_waypoint_list)
|
||||||
|
self.subwindow.show()
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,11 @@
|
|||||||
from PySide2.QtCore import Qt
|
from PySide2.QtCore import Qt
|
||||||
from PySide2.QtWidgets import QDialog, QGridLayout, QLabel, QComboBox, QHBoxLayout, QVBoxLayout, QPushButton, QCheckBox
|
from PySide2.QtWidgets import QDialog, QLabel, QHBoxLayout, QVBoxLayout, QPushButton, QCheckBox
|
||||||
from dcs import Point
|
|
||||||
|
|
||||||
from game import Game
|
from game import Game
|
||||||
from gen.flights.flight import Flight, FlightWaypoint
|
from gen.flights.flight import Flight
|
||||||
from qt_ui.uiconstants import EVENT_ICONS
|
from qt_ui.uiconstants import EVENT_ICONS
|
||||||
from qt_ui.widgets.QPredefinedWaypointSelectionComboBox import QPredefinedWaypointSelectionComboBox
|
from qt_ui.widgets.combos.QPredefinedWaypointSelectionComboBox import QPredefinedWaypointSelectionComboBox
|
||||||
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import QFlightWaypointInfoBox
|
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import QFlightWaypointInfoBox
|
||||||
from theater import ControlPointType
|
|
||||||
|
|
||||||
PREDEFINED_WAYPOINT_CATEGORIES = [
|
PREDEFINED_WAYPOINT_CATEGORIES = [
|
||||||
"Frontline (CAS AREA)",
|
"Frontline (CAS AREA)",
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 800 KiB After Width: | Height: | Size: 800 KiB |
Loading…
x
Reference in New Issue
Block a user