From ab3ea84d70966491995ab1f5265aaab5fac6a4d2 Mon Sep 17 00:00:00 2001 From: Khopa Date: Sat, 30 May 2020 02:32:45 +0200 Subject: [PATCH] AI flight planner now auto generate STRIKE flights. Fix CAS point position in predefined wpt selector. When an airbase is captured, base defenses are re-generated for the new base owner. --- game/event/event.py | 34 ++- game/game.py | 21 +- gen/aircraft.py | 271 +----------------- gen/conflictgen.py | 7 - gen/flights/ai_flight_planner.py | 105 ++++++- gen/flights/ai_flight_planner_db.py | 9 +- .../QPredefinedWaypointSelectionComboBox.py | 4 +- theater/start_generator.py | 32 ++- 8 files changed, 169 insertions(+), 314 deletions(-) diff --git a/game/event/event.py b/game/event/event.py index 25309856..d1f1da34 100644 --- a/game/event/event.py +++ b/game/event/event.py @@ -13,6 +13,7 @@ from theater import * from gen.environmentgen import EnvironmentSettings from gen.conflictgen import Conflict from game.db import assigned_units_from, unitdict_from +from theater.start_generator import generate_airbase_defense_group from userdata.debriefing import Debriefing from userdata import persistency @@ -214,28 +215,35 @@ class Event: for cp in self.game.theater.controlpoints: if cp.id == id: + + pname = "" if cp.captured and new_owner_coalition != coalition: cp.captured = False - cp.base.aircraft = {} - cp.base.armor = {} - cp.base.aa = {} - for g in cp.ground_objects: - g.groups = [] info = Information(cp.name + " lost !", "The ennemy took control of " + cp.name + "\nShame on us !", self.game.turn) self.game.informations.append(info) + pname = self.game.enemy_name elif not(cp.captured) and new_owner_coalition == coalition: cp.captured = True - cp.base.aircraft = {} - cp.base.armor = {} - cp.base.aa = {} - for g in cp.ground_objects: - g.groups = [] - info = Information(cp.name + " captured !", - "The ennemy took control of " + cp.name + "\nShame on us !", - self.game.turn) + info = Information(cp.name + " captured !", "The ennemy took control of " + cp.name + "\nShame on us !", self.game.turn) self.game.informations.append(info) + pname = self.game.player_name + else: + continue + + cp.base.aircraft = {} + cp.base.armor = {} + cp.base.aa = {} + + airbase_def_id = 0 + for g in cp.ground_objects: + g.groups = [] + if g.airbase_group and pname != "": + generate_airbase_defense_group(airbase_def_id, g, pname, self.game, cp) + airbase_def_id = airbase_def_id + 1 + + except Exception as e: print(e) diff --git a/game/game.py b/game/game.py index 330e8d2f..9ca3810d 100644 --- a/game/game.py +++ b/game/game.py @@ -1,24 +1,11 @@ -import logging -import typing -import random -import math - -from dcs.task import * -from dcs.vehicles import * +from datetime import datetime, timedelta from game.db import REWARDS, PLAYER_BUDGET_BASE from game.game_stats import GameStats -from game.infos.information import Information -from gen.conflictgen import Conflict from gen.flights.ai_flight_planner import FlightPlanner from gen.ground_forces.ai_ground_planner import GroundPlanner -from userdata.debriefing import Debriefing -from theater import * - -from . import db -from .settings import Settings from .event import * -from datetime import datetime, timedelta +from .settings import Settings COMMISION_UNIT_VARIETY = 4 COMMISION_LIMITS_SCALE = 1.5 @@ -230,6 +217,10 @@ class Game: self.ground_planners[cp.id] = gplanner def _enemy_reinforcement(self): + """ + Compute and commision reinforcement for enemy bases + """ + MAX_ARMOR = 30 * self.settings.multiplier MAX_AIRCRAFT = 25 * self.settings.multiplier diff --git a/gen/aircraft.py b/gen/aircraft.py index 88925ed9..39f1cd7f 100644 --- a/gen/aircraft.py +++ b/gen/aircraft.py @@ -327,6 +327,11 @@ class AircraftConflictGenerator: self.setup_group_as_sead_flight(group, flight) self._setup_custom_payload(flight, group) + for flight in flight_planner.strike_flights: + group = self.generate_planned_flight(cp, country, flight) + self.setup_group_as_strike_flight(group, flight) + self._setup_custom_payload(flight, group) + for flight in flight_planner.custom_flights: group = self.generate_planned_flight(cp, country, flight) if flight.flight_type == FlightType.INTERCEPTION: @@ -445,11 +450,16 @@ class AircraftConflictGenerator: group.points[0].tasks.clear() group.points[0].tasks.append(CASTaskAction()) group.points[0].tasks.append(OptReactOnThreat(OptReactOnThreat.Values.EvadeFire)) - group.points[0].tasks.append(OptROE(OptROE.Values.OpenFireWeaponFree)) + group.points[0].tasks.append(OptROE(OptROE.Values.OpenFire)) group.points[0].tasks.append(OptRestrictJettison(True)) + i = 1 for point in flight.points: group.add_waypoint(Point(point.x,point.y), point.alt) + for t in point.targets: + group.points[i].tasks.append(Bombing(t.position)) + i = i + 1 + def setup_group_as_antiship_flight(self, group, flight): group.task = AntishipStrike.name @@ -464,263 +474,4 @@ class AircraftConflictGenerator: for point in flight.points: group.add_waypoint(Point(point.x,point.y), point.alt) - def generate_cas_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None, escort=True): - assert not escort or len(self.escort_targets) == 0 - - for flying_type, count, client_count in self._split_to_groups(attackers, clients): - group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), - side=self.conflict.attackers_country, - unit_type=flying_type, - count=count, - client_count=client_count, - at=at and at or self._group_point(self.conflict.air_attackers_location)) - - waypoint = self._add_radio_waypoint(group, self.conflict.position, CAS_ALTITUDE, WARM_START_AIRSPEED) - if self.conflict.is_vector: - self._add_radio_waypoint(group, self.conflict.tail, CAS_ALTITUDE, WARM_START_AIRSPEED) - - group.task = CAS.name - self._setup_group(group, CAS, client_count) - if escort: - self.escort_targets.append((group, group.points.index(waypoint))) - 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, escort=True): - assert not escort or len(self.escort_targets) == 0 - - for flying_type, count, client_count in self._split_to_groups(strikegroup, clients): - group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), - side=self.conflict.attackers_country, - unit_type=flying_type, - count=count, - client_count=client_count, - at=at and at or self._group_point(self.conflict.air_attackers_location)) - - escort_until_waypoint = None - - for name, pos in targets: - waypoint = group.add_waypoint(pos, 0, WARM_START_AIRSPEED, self.m.translation.create_string(name)) - waypoint.tasks.append(Bombing(pos, attack_qty=2)) - if escort_until_waypoint is None: - escort_until_waypoint = waypoint - - group.task = GroundAttack.name - self._setup_group(group, GroundAttack, client_count) - if escort: - self.escort_targets.append((group, group.points.index(escort_until_waypoint))) - self._rtb_for(group, self.conflict.from_cp, at) - - def generate_sead_strikegroup(self, strikegroup: db.PlaneDict, clients: db.PlaneDict, targets: typing.List[typing.Tuple[str, Point]], at: db.StartingPosition, escort=True): - assert not escort or len(self.escort_targets) == 0 - - for flying_type, count, client_count in self._split_to_groups(strikegroup, clients): - group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), - side=self.conflict.attackers_country, - unit_type=flying_type, - count=count, - client_count=client_count, - at=at and at or self._group_point(self.conflict.air_attackers_location)) - - escort_until_waypoint = None - - for name, pos in targets: - waypoint = group.add_waypoint(pos, 0, WARM_START_AIRSPEED, self.m.translation.create_string(name)) - if escort_until_waypoint is None: - escort_until_waypoint = waypoint - - group.task = SEAD.name - self._setup_group(group, SEAD, client_count) - if escort: - self.escort_targets.append((group, group.points.index(escort_until_waypoint))) - - self._rtb_for(group, self.conflict.from_cp, at) - - def generate_defenders_cas(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None, escort=True): - assert not escort or len(self.escort_targets) == 0 - - for flying_type, count, client_count in self._split_to_groups(defenders, clients): - group = self._generate_group( - name=namegen.next_unit_name(self.conflict.defenders_country, self.conflict.to_cp.id, flying_type), - side=self.conflict.defenders_country, - unit_type=flying_type, - count=count, - client_count=client_count, - at=at and at or self._group_point(self.conflict.air_defenders_location)) - - location = self._group_point(self.conflict.air_defenders_location) - insertion_point = self.conflict.find_insertion_point(location) - waypoint = self._add_radio_waypoint(group, insertion_point, CAS_ALTITUDE, WARM_START_AIRSPEED) - - if self.conflict.is_vector: - destination_tail = self.conflict.tail.distance_to_point(insertion_point) > self.conflict.position.distance_to_point(insertion_point) - self._add_radio_waypoint(group, destination_tail and self.conflict.tail or self.conflict.position, CAS_ALTITUDE, WARM_START_AIRSPEED) - - group.task = CAS.name - self._setup_group(group, CAS, client_count) - if escort: - self.escort_targets.append((group, group.points.index(waypoint))) - 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, escort=True): - assert not escort or len(self.escort_targets) == 0 - - for flying_type, count, client_count in self._split_to_groups(attackers, clients): - group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), - side=self.conflict.attackers_country, - unit_type=flying_type, - count=count, - client_count=client_count, - at=at and at or self._group_point(self.conflict.air_attackers_location)) - - wayp = self._add_radio_waypoint(group, self.conflict.position, CAS_ALTITUDE, WARM_START_AIRSPEED) - for target_group in target_groups: - wayp.tasks.append(AttackGroup(target_group.id)) - - group.task = AntishipStrike.name - self._setup_group(group, AntishipStrike, client_count) - if escort: - self.escort_targets.append((group, group.points.index(wayp))) - self._rtb_for(group, self.conflict.from_cp, at) - - def generate_attackers_escort(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): - for g in self._generate_escort( - side=self.conflict.attackers_country, - units=attackers, - clients=clients, - at=at and at or self._group_point(self.conflict.air_attackers_location), - is_quick=at is None, - cp=self.conflict.from_cp, - should_orbit=True): - self._rtb_for(g, self.conflict.from_cp, at) - - def generate_defenders_escort(self, escort: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): - for g in self._generate_escort( - side=self.conflict.defenders_country, - units=escort, - clients=clients, - at=at and at or self._group_point(self.conflict.air_defenders_location), - is_quick=at is None, - cp=self.conflict.to_cp, - should_orbit=False): - self._rtb_for(g, self.conflict.to_cp, at) - - def generate_defense(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): - for flying_type, count, client_count in self._split_to_groups(defenders, clients): - group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.to_cp.id, flying_type), - side=self.conflict.defenders_country, - unit_type=flying_type, - count=count, - client_count=client_count, - at=at and at or self._group_point(self.conflict.air_defenders_location)) - - group.task = CAP.name - wayp = self._add_radio_waypoint(group, self.conflict.position, CAS_ALTITUDE, WARM_START_AIRSPEED) - wayp.tasks.append(dcs.task.EngageTargets(max_distance=DEFENCE_ENGAGEMENT_MAX_DISTANCE)) - wayp.tasks.append(dcs.task.OrbitAction(ATTACK_CIRCLE_ALT, pattern=OrbitAction.OrbitPattern.Circle)) - self._setup_group(group, CAP, client_count) - self._rtb_for(group, self.conflict.to_cp, at) - - def generate_migcap(self, patrol: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): - for flying_type, count, client_count in self._split_to_groups(patrol, clients): - group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), - side=self.conflict.attackers_country, - unit_type=flying_type, - count=count, - client_count=client_count, - at=at and at or self._group_point(self.conflict.air_attackers_location)) - - waypoint = self._add_radio_waypoint(group, self.conflict.position, WARM_START_ALTITUDE, WARM_START_AIRSPEED) - if self.conflict.is_vector: - self._add_radio_waypoint(group, self.conflict.tail, WARM_START_ALTITUDE, WARM_START_AIRSPEED) - - group.task = CAP.name - self._setup_group(group, CAP, client_count) - self._rtb_for(group, self.conflict.from_cp, at) - - def generate_barcap(self, patrol: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): - for flying_type, count, client_count in self._split_to_groups(patrol, clients): - group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), - side=self.conflict.defenders_country, - unit_type=flying_type, - count=count, - client_count=client_count, - at=at and at or self._group_point(self.conflict.air_defenders_location)) - - waypoint = self._add_radio_waypoint(group, self.conflict.position, WARM_START_ALTITUDE, WARM_START_AIRSPEED) - if self.conflict.is_vector: - self._add_radio_waypoint(group, self.conflict.tail, WARM_START_ALTITUDE, WARM_START_AIRSPEED) - else: - heading = group.position.heading_between_point(self.conflict.position) - waypoint = self._add_radio_waypoint(group, self.conflict.position.point_from_heading(heading, BARCAP_RACETRACK_DISTANCE), - WARM_START_ALTITUDE, - WARM_START_AIRSPEED) - waypoint.tasks.append(OrbitAction(WARM_START_ALTITUDE, WARM_START_AIRSPEED)) - - group.task = CAP.name - self._setup_group(group, CAP, client_count) - self._rtb_for(group, self.conflict.to_cp, at) - - def generate_transport(self, transport: db.PlaneDict, destination: Airport, escort=True): - assert not escort or len(self.escort_targets) == 0 - - for flying_type, count, client_count in self._split_to_groups(transport): - group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), - side=self.conflict.defenders_country, - unit_type=flying_type, - count=count, - client_count=client_count, - at=self._group_point(self.conflict.air_defenders_location)) - - waypoint = self._rtb_for(group, self.conflict.to_cp) - if escort: - self.escort_targets.append((group, group.points.index(waypoint))) - - self._add_radio_waypoint(group, destination.position, RTB_ALTITUDE) - group.task = Transport.name - group.land_at(destination) - - def generate_interception(self, interceptors: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): - for flying_type, count, client_count in self._split_to_groups(interceptors, clients): - group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, flying_type), - side=self.conflict.attackers_country, - unit_type=flying_type, - count=count, - client_count=client_count, - at=at and at or self._group_point(self.conflict.air_attackers_location)) - - group.task = CAP.name - group.points[0].tasks.append(EngageTargets(max_distance=INTERCEPT_MAX_DISTANCE)) - - wayp = self._add_radio_waypoint(group, self.conflict.position, WARM_START_ALTITUDE, INTERCEPTION_AIRSPEED) - wayp.tasks.append(EngageTargets(max_distance=INTERCEPT_MAX_DISTANCE)) - - if self.conflict.is_vector: - self._add_radio_waypoint(group, self.conflict.tail, CAS_ALTITUDE, WARM_START_ALTITUDE) - - self._setup_group(group, CAP, client_count) - self._rtb_for(group, self.conflict.from_cp, at) - - def generate_passenger_transport(self, helis: db.HeliDict, clients: db.HeliDict, at: db.StartingPosition): - for heli_type, count, client_count in self._split_to_groups(helis, clients): - group = self._generate_group( - name=namegen.next_unit_name(self.conflict.attackers_country, self.conflict.from_cp.id, heli_type), - side=self.conflict.attackers_country, - unit_type=heli_type, - count=count, - client_count=client_count, - at=at and at or self._group_point(self.conflict.air_attackers_location) - ) - - self._add_radio_waypoint(group, self.conflict.position, HELI_ALT) - self._setup_group(group, Transport, client_count) - diff --git a/gen/conflictgen.py b/gen/conflictgen.py index 5ced0ced..9b83b51e 100644 --- a/gen/conflictgen.py +++ b/gen/conflictgen.py @@ -172,13 +172,6 @@ class Conflict: position = middle_point.point_from_heading(attack_heading, strength_delta * attack_distance / 2 - FRONTLINE_MIN_CP_DISTANCE) return position, _opposite_heading(attack_heading) - ground_position = cls._find_ground_position(position, attack_distance / 2 - FRONTLINE_MIN_CP_DISTANCE, attack_heading, theater) - if ground_position: - return ground_position, _opposite_heading(attack_heading) - else: - logging.warning("Coudn't find frontline position between {} and {}!".format(from_cp, to_cp)) - return position, _opposite_heading(attack_heading) - @classmethod def frontline_vector(cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater) -> typing.Optional[typing.Tuple[Point, int, int]]: diff --git a/gen/flights/ai_flight_planner.py b/gen/flights/ai_flight_planner.py index 0f7f1cc7..72b87469 100644 --- a/gen/flights/ai_flight_planner.py +++ b/gen/flights/ai_flight_planner.py @@ -17,7 +17,13 @@ MISSION_DURATION = 120 # in minutes CAP_EVERY_X_MINUTES = 20 CAS_EVERY_X_MINUTES = 30 SEAD_EVERY_X_MINUTES = 40 +STRIKE_EVERY_X_MINUTES = 40 +INGRESS_EGRESS_DISTANCE = 45000 +INGRESS_ALT = 6096 # 20k feet +EGRESS_ALT = 6096 # 20k feet +PATROL_ALT_RANGE = (3600, 9200) +NAV_ALT = 9144 class FlightPlanner: @@ -61,6 +67,8 @@ class FlightPlanner: # Then prepare some sead flights if required self.commision_sead() + self.commision_strike() + # TODO : commision STRIKE / ANTISHIP def remove_flight(self, index): @@ -130,7 +138,7 @@ class FlightPlanner: flight.points = [] flight.scheduled_in = offset + i*random.randint(CAP_EVERY_X_MINUTES-5, CAP_EVERY_X_MINUTES+5) - patrol_alt = random.randint(3600, 7000) + patrol_alt = random.randint(PATROL_ALT_RANGE[0], PATROL_ALT_RANGE[1]) patrolled = [] for ground_object in self.from_cp.ground_objects: @@ -245,12 +253,33 @@ class FlightPlanner: location = self.potential_sead_targets[0][0] self.potential_sead_targets.pop(0) + heading = self.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 + flight.points.append(ingress_point) + point = FlightWaypoint(location.position.x, location.position.y, 1000) - point.description = "SEAD" - point.pretty_name = "SEAD" + if flight.flight_type == FlightType.DEAD: + point.description = "SEAD on " + location.obj_name + point.pretty_name = "SEAD on " + location.obj_name + else: + point.description = "DEAD on " + location.obj_name + point.pretty_name = "DEAD on " + location.obj_name + 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 on " + location.obj_name + egress_point.description = "EGRESS on " + location.obj_name + flight.points.append(egress_point) + self.sead_flights.append(flight) self.flights.append(flight) @@ -258,6 +287,74 @@ class FlightPlanner: for k, v in inventory.items(): self.aircraft_inventory[k] = v + + def commision_strike(self): + """ + Pick some aircraft to assign them to STRIKE tasks + """ + possible_aircraft = [k for k, v in self.aircraft_inventory.items() if k in CAS_CAPABLE and v >= 2] + inventory = dict({k: v for k, v in self.aircraft_inventory.items() if k in possible_aircraft}) + + if len(self.potential_strike_targets) > 0: + + offset = random.randint(0,5) + for i in range(int(MISSION_DURATION/STRIKE_EVERY_X_MINUTES)): + + if len(self.potential_strike_targets) <= 0: + break + + try: + unit = random.choice([k for k, v in inventory.items() if v >= 2]) + except IndexError: + break + + inventory[unit] = inventory[unit] - 2 + flight = Flight(unit, 2, self.from_cp, FlightType.STRIKE) + + flight.points = [] + flight.scheduled_in = offset + i*random.randint(SEAD_EVERY_X_MINUTES-5, SEAD_EVERY_X_MINUTES+5) + + location = self.potential_strike_targets[0][0] + self.potential_strike_targets.pop(0) + + heading = self.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 + flight.points.append(ingress_point) + + if len(location.groups) > 0: + 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.targets.append(location) + 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.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 on " + location.obj_name + egress_point.description = "EGRESS on " + location.obj_name + flight.points.append(egress_point) + + self.strike_flights.append(flight) + self.flights.append(flight) + + # Update inventory + for k, v in inventory.items(): + self.aircraft_inventory[k] = v + def _get_cas_locations(self): cas_locations = [] for cp in self.from_cp.connected_points: @@ -285,7 +382,7 @@ class FlightPlanner: added_group = [] for g in cp.ground_objects: - if g.group_id in added_group: continue + if g.group_id in added_group or g.is_dead: continue # Compute distance to current cp distance = math.hypot(cp.position.x - self.from_cp.position.x, diff --git a/gen/flights/ai_flight_planner_db.py b/gen/flights/ai_flight_planner_db.py index 1795cd0d..bfe78c67 100644 --- a/gen/flights/ai_flight_planner_db.py +++ b/gen/flights/ai_flight_planner_db.py @@ -119,7 +119,7 @@ CAS_CAPABLE = [ SEAD_CAPABLE = [ F_4E, FA_18C_hornet, - F_16C_50, + # F_16C_50, Not yet AV8BNA, JF_17, @@ -179,7 +179,12 @@ STRIKE_CAPABLE = [ ANTISHIP_CAPABLE = [ Su_24M, + Su_17M4, F_A_18C, AV8BNA, - JF_17 + JF_17, + F_16C_50, + A_10C, + A_10A, + ] \ No newline at end of file diff --git a/qt_ui/widgets/QPredefinedWaypointSelectionComboBox.py b/qt_ui/widgets/QPredefinedWaypointSelectionComboBox.py index ef8cdcaa..e1093e65 100644 --- a/qt_ui/widgets/QPredefinedWaypointSelectionComboBox.py +++ b/qt_ui/widgets/QPredefinedWaypointSelectionComboBox.py @@ -2,6 +2,7 @@ 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 @@ -89,7 +90,8 @@ class QPredefinedWaypointSelectionComboBox(QComboBox): if cp.captured: enemy_cp = [ecp for ecp in cp.connected_points if ecp.captured != cp.captured] for ecp in enemy_cp: - wpt = FlightWaypoint((cp.position.x + ecp.position.x)/2, (cp.position.y + ecp.position.y)/2, 800) + 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.pretty_name = wpt.name wpt.description = "Frontline" diff --git a/theater/start_generator.py b/theater/start_generator.py index 29ad7d11..7ebaf876 100644 --- a/theater/start_generator.py +++ b/theater/start_generator.py @@ -112,6 +112,9 @@ def generate_groundobjects(theater: ConflictTheater, game): if "lhanames" in db.FACTIONS[faction]: cp.name = random.choice(db.FACTIONS[faction]["lhanames"]) else: + + + for i in range(random.randint(2,6)): point = find_location(True, cp.position, theater, 1000, 2800, []) @@ -131,18 +134,7 @@ def generate_groundobjects(theater: ConflictTheater, game): g.heading = 0 g.position = Point(point.x, point.y) - if i == 0: - group = generate_armor_group(faction, game, g) - elif i == 1 and random.randint(0,1) == 0: - group = generate_anti_air_group(game, cp, g, faction) - elif random.randint(0, 2) == 1: - group = generate_shorad_group(game, cp, g, faction) - else: - group = generate_armor_group(faction, game, g) - - g.groups = [] - if group is not None: - g.groups.append(group) + generate_airbase_defense_group(i, g, faction, game, cp) cp.ground_objects.append(g) print("---------------------------") @@ -151,6 +143,22 @@ def generate_groundobjects(theater: ConflictTheater, game): print(ground_object.groups) +def generate_airbase_defense_group(airbase_defense_group_id, ground_obj:TheaterGroundObject, faction, game, cp): + + if airbase_defense_group_id == 0: + group = generate_armor_group(faction, game, ground_obj) + elif airbase_defense_group_id == 1 and random.randint(0, 1) == 0: + group = generate_anti_air_group(game, cp, ground_obj, faction) + elif random.randint(0, 2) == 1: + group = generate_shorad_group(game, cp, ground_obj, faction) + else: + group = generate_armor_group(faction, game, ground_obj) + + ground_obj.groups = [] + if group is not None: + ground_obj.groups.append(group) + + def find_location(on_ground, near, theater, min, max, others) -> typing.Optional[Point]: """ Find a valid ground object location