diff --git a/changelog.md b/changelog.md index 84e1241c..ad08d52d 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,7 @@ ##Features/Improvements : * **[Units/Factions]** Added P-47D-30 for factions allies_1944 +* **[Units/Factions]** Added factions : Bluefor Coldwar, Germany 1944 Easy * **[Campaign/Map]** Added a campaign in the Channel map * **[Campaign/Map]** Changed the Normandy campaign map @@ -22,6 +23,7 @@ * **[Flight Planner]** Added STRIKE mission generator * **[Flight Planner]** Added buttons to add autogenerated waypoints (ASCEND, DESCEND, RTB) * **[Flight Planner]** Improved waypoint list +* **[Flight Planner]** WW2 factions uses different parameters for flight planning. * **[Settings]** Added settings to disallow external views * **[Settings]** Added settings to choose F10 Map mode (All, Allies only, Player only, Fog of War, Map Only) @@ -37,6 +39,9 @@ * **[Map]** Added "ww2 bunker" building (WW2) * **[Map]** Added "ally camp" building (WW2) +* **[Map]** Added "V1 Launch Site" building (WW2) +* **[Map]** Added "A camp" building (WW2) + * **[Misc]** Made it possible to setup DCS Saved Games directory and DCS installation directory manually at first start ##Fixed issues : @@ -52,7 +57,7 @@ * **[Maps/Campaign]** Now using Vasiani airbase instead of Soganlung airport in North Caucasus campaign (More parking slots) -* **[Info Panel]** Message displayed on base capture event stated that the ennemy captured an airbase, while it was the player who captured it. +* **[Info Panel]** Message displayed on base capture event stated that the enemy captured an airbase, while it was the player who captured it. * **[Map View]** Graphical glitch on map when one building of an objective was destroyed, but not the others diff --git a/game/data/doctrine.py b/game/data/doctrine.py new file mode 100644 index 00000000..bfc5b714 --- /dev/null +++ b/game/data/doctrine.py @@ -0,0 +1,113 @@ +from game.utils import nm_to_meter, feet_to_meter + +MAX_NUMBER_OF_INTERCEPTION_GROUP = 3 +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 = nm_to_meter(45) +INGRESS_ALT = feet_to_meter(20000) +EGRESS_ALT = feet_to_meter(20000) +PATROL_ALT_RANGE = (feet_to_meter(15000), feet_to_meter(33000)) +NAV_ALT = 9144 +PATTERN_ALTITUDE = feet_to_meter(5000) + +CAP_DEFAULT_ENGAGE_DISTANCE = nm_to_meter(40) + + + +MODERN_DOCTRINE = { + + "GENERATORS":{ + "CAS": True, + "CAP": True, + "SEAD": True, + "STRIKE": True, + "ANTISHIP": True, + }, + + "STRIKE_MAX_RANGE": 1500000, + "SEAD_MAX_RANGE": 1500000, + + "CAP_EVERY_X_MINUTES": 20, + "CAS_EVERY_X_MINUTES": 30, + "SEAD_EVERY_X_MINUTES": 40, + "STRIKE_EVERY_X_MINUTES": 40, + + "INGRESS_EGRESS_DISTANCE": nm_to_meter(45), + "INGRESS_ALT": feet_to_meter(20000), + "EGRESS_ALT": feet_to_meter(20000), + "PATROL_ALT_RANGE": (feet_to_meter(15000), feet_to_meter(33000)), + "PATTERN_ALTITUDE": feet_to_meter(5000), + + "CAP_PATTERN_LENGTH": (nm_to_meter(15), nm_to_meter(40)), + "FRONTLINE_CAP_DISTANCE_FROM_FRONTLINE": (nm_to_meter(6), nm_to_meter(15)), + "CAP_DISTANCE_FROM_CP": (nm_to_meter(10), nm_to_meter(40)), + + "MAX_NUMBER_OF_INTERCEPTION_GROUP": 3, +} + +COLDWAR_DOCTRINE = { + + "GENERATORS": { + "CAS": True, + "CAP": True, + "SEAD": True, + "STRIKE": True, + "ANTISHIP": True, + }, + + "STRIKE_MAX_RANGE": 1500000, + "SEAD_MAX_RANGE": 1500000, + + "CAP_EVERY_X_MINUTES": 20, + "CAS_EVERY_X_MINUTES": 30, + "SEAD_EVERY_X_MINUTES": 40, + "STRIKE_EVERY_X_MINUTES": 40, + + "INGRESS_EGRESS_DISTANCE": nm_to_meter(30), + "INGRESS_ALT": feet_to_meter(18000), + "EGRESS_ALT": feet_to_meter(18000), + "PATROL_ALT_RANGE": (feet_to_meter(10000), feet_to_meter(24000)), + "PATTERN_ALTITUDE": feet_to_meter(5000), + + "CAP_PATTERN_LENGTH": (nm_to_meter(12), nm_to_meter(24)), + "FRONTLINE_CAP_DISTANCE_FROM_FRONTLINE": (nm_to_meter(2), nm_to_meter(8)), + "CAP_DISTANCE_FROM_CP": (nm_to_meter(8), nm_to_meter(25)), + + "MAX_NUMBER_OF_INTERCEPTION_GROUP": 3, +} + +WWII_DOCTRINE = { + + "GENERATORS": { + "CAS": True, + "CAP": True, + "SEAD": False, + "STRIKE": True, + "ANTISHIP": True, + }, + + "STRIKE_MAX_RANGE": 1500000, + "SEAD_MAX_RANGE": 1500000, + + "CAP_EVERY_X_MINUTES": 20, + "CAS_EVERY_X_MINUTES": 30, + "SEAD_EVERY_X_MINUTES": 40, + "STRIKE_EVERY_X_MINUTES": 40, + + "INGRESS_EGRESS_DISTANCE": nm_to_meter(7), + "INGRESS_ALT": feet_to_meter(8000), + "EGRESS_ALT": feet_to_meter(8000), + "PATROL_ALT_RANGE": (feet_to_meter(4000), feet_to_meter(15000)), + "PATTERN_ALTITUDE": feet_to_meter(5000), + + "CAP_PATTERN_LENGTH": (nm_to_meter(8), nm_to_meter(18)), + "FRONTLINE_CAP_DISTANCE_FROM_FRONTLINE": (nm_to_meter(1), nm_to_meter(6)), + "CAP_DISTANCE_FROM_CP": (nm_to_meter(5), nm_to_meter(15)), + + "MAX_NUMBER_OF_INTERCEPTION_GROUP": 3, + +} \ No newline at end of file diff --git a/game/db.py b/game/db.py index 9533f8f4..1ecb9b8c 100644 --- a/game/db.py +++ b/game/db.py @@ -162,6 +162,7 @@ PRICES = { P_51D_30_NA: 6, P_51D: 6, P_47D_30: 6, + B_17G: 18, # armor Armor.APC_MTLB: 4, @@ -260,7 +261,6 @@ PRICES = { Artillery.M12_GMC: 2, Artillery.Sturmpanzer_IV_Brummbär: 2, - # ship CV_1143_5_Admiral_Kuznetsov: 100, CVN_74_John_C__Stennis: 100, @@ -350,6 +350,7 @@ UNIT_BY_TASK = { A_20G, P_47D_30, Ju_88A4, + B_17G ], Transport: [ IL_76MD, @@ -739,6 +740,8 @@ PLANE_PAYLOAD_OVERRIDES = { L_39C:COMMON_OVERRIDE, Su_17M4: COMMON_OVERRIDE, F_4E: COMMON_OVERRIDE, + P_47D_30:COMMON_OVERRIDE, + B_17G: COMMON_OVERRIDE, AH_64D:{ CAS: "AGM-114K*16" @@ -1053,4 +1056,5 @@ class DefaultLiveries: OH_58D.Liveries = DefaultLiveries F_16C_50.Liveries = DefaultLiveries P_51D_30_NA.Liveries = DefaultLiveries -Ju_88A4.Liveries = DefaultLiveries \ No newline at end of file +Ju_88A4.Liveries = DefaultLiveries +B_17G.Liveries = DefaultLiveries \ No newline at end of file diff --git a/game/factions/germany_1944.py b/game/factions/germany_1944.py index 9549f5fe..65039c9f 100644 --- a/game/factions/germany_1944.py +++ b/game/factions/germany_1944.py @@ -1,7 +1,9 @@ from dcs.planes import * +from dcs.ships import Uboat_VIIC_U_flak, Schnellboot_type_S130 from dcs.vehicles import * from game.data.building_data import WW2_GERMANY_BUILDINGS +from game.data.doctrine import WWII_DOCTRINE Germany_1944 = { "country": "Third Reich", @@ -32,11 +34,10 @@ Germany_1944 = { Infantry.Infantry_Mauser_98, AirDefence.AAA_8_8cm_Flak_36, ], - "shorad":[ + "shorad": [ AirDefence.AAA_8_8cm_Flak_36, ], "objects": WW2_GERMANY_BUILDINGS, - "doctrine": { - # TODO - } + "doctrine": WWII_DOCTRINE, + "boat": [Uboat_VIIC_U_flak, Schnellboot_type_S130] } \ No newline at end of file diff --git a/game/factions/germany_1944_easy.py b/game/factions/germany_1944_easy.py index db0b68ba..1d1edca0 100644 --- a/game/factions/germany_1944_easy.py +++ b/game/factions/germany_1944_easy.py @@ -1,7 +1,9 @@ from dcs.planes import * from dcs.vehicles import * +from dcs.ships import * from game.data.building_data import WW2_GERMANY_BUILDINGS +from game.data.doctrine import WWII_DOCTRINE Germany_1944_Easy = { "country": "Third Reich", @@ -29,7 +31,6 @@ Germany_1944_Easy = { AirDefence.AAA_8_8cm_Flak_36, ], "objects": WW2_GERMANY_BUILDINGS, - "doctrine": { - # TODO - } + "doctrine": WWII_DOCTRINE, + "boat": [Uboat_VIIC_U_flak, Schnellboot_type_S130] } \ No newline at end of file diff --git a/game/factions/usa_1944.py b/game/factions/usa_1944.py index 043041ce..a59487e9 100644 --- a/game/factions/usa_1944.py +++ b/game/factions/usa_1944.py @@ -3,6 +3,7 @@ from dcs.ships import * from dcs.vehicles import * from game.data.building_data import WW2_ALLIES_BUILDINGS +from game.data.doctrine import WWII_DOCTRINE USA_1944 = { "country": "USA", @@ -14,6 +15,7 @@ USA_1944 = { SpitfireLFMkIX, SpitfireLFMkIXCW, A_20G, + B_17G, Armor.MT_M4_Sherman, Armor.MT_M4A4_Sherman_Firefly, @@ -38,5 +40,8 @@ USA_1944 = { AirDefence.AAA_Bofors_40mm, ], "shorad":[ AirDefence.AAA_Bofors_40mm, - ], "objects": WW2_ALLIES_BUILDINGS + ], + "objects": WW2_ALLIES_BUILDINGS, + "doctrine": WWII_DOCTRINE, + "boat": [LS_Samuel_Chase] } \ No newline at end of file diff --git a/game/game.py b/game/game.py index 27be8a47..c90e91bf 100644 --- a/game/game.py +++ b/game/game.py @@ -73,6 +73,15 @@ class Game: self.informations = [] self.informations.append(Information("Game Start", "-" * 40, 0)) + + @property + def player_faction(self): + return db.FACTIONS[self.player_name] + + @property + def enemy_faction(self): + return db.FACTIONS[self.enemy_name] + def _roll(self, prob, mult): if self.settings.version == "dev": # always generate all events for dev diff --git a/game/utils.py b/game/utils.py new file mode 100644 index 00000000..34b82aa4 --- /dev/null +++ b/game/utils.py @@ -0,0 +1,14 @@ +def meter_to_feet(value_in_meter): + return int(3.28084 * value_in_meter) + + +def feet_to_meter(value_in_feet): + return int(float(value_in_feet)/3.048) + + +def meter_to_nm(value_in_meter): + return int(float(value_in_meter)*0.000539957) + + +def nm_to_meter(value_in_nm): + return int(float(value_in_nm)*1852) \ No newline at end of file diff --git a/gen/aircraft.py b/gen/aircraft.py index 6ea24693..81a1ce8f 100644 --- a/gen/aircraft.py +++ b/gen/aircraft.py @@ -5,38 +5,22 @@ from dcs.terrain.terrain import NoParkingSlotError from dcs.triggers import TriggerOnce, Event from game.settings import Settings -from gen.flights.ai_flight_planner import FlightPlanner, CAP_DEFAULT_ENGAGE_DISTANCE, nm_to_meter +from gen.flights.ai_flight_planner import FlightPlanner from gen.flights.flight import Flight, FlightType, FlightWaypointType from .conflictgen import * from .naming import * -from .triggergen import TRIGGER_WAYPOINT_OFFSET - -SPREAD_DISTANCE_FACTOR = 1, 2 -ESCORT_ENGAGEMENT_MAX_DIST = 100000 -WORKAROUND_WAYP_DIST = 1000 WARM_START_HELI_AIRSPEED = 120 WARM_START_HELI_ALT = 500 - WARM_START_ALTITUDE = 3000 WARM_START_AIRSPEED = 550 -INTERCEPTION_AIRSPEED = 1000 -BARCAP_RACETRACK_DISTANCE = 20000 +CAP_DURATION = 30 # minutes -ATTACK_CIRCLE_ALT = 1000 -ATTACK_CIRCLE_DURATION = 15 - -CAS_ALTITUDE = 800 RTB_ALTITUDE = 800 RTB_DISTANCE = 5000 HELI_ALT = 500 -TRANSPORT_LANDING_ALT = 2000 - -DEFENCE_ENGAGEMENT_MAX_DISTANCE = 60000 -INTERCEPT_MAX_DISTANCE = 200000 - class AircraftConflictGenerator: escort_targets = [] # type: typing.List[typing.Tuple[FlyingGroup, int]] @@ -393,8 +377,8 @@ class AircraftConflictGenerator: if not point.only_for_player or (point.only_for_player and flight.client_count > 0): pt = group.add_waypoint(Point(point.x, point.y), point.alt) if point.waypoint_type == FlightWaypointType.PATROL_TRACK: - action = OrbitAction(altitude=pt.alt, pattern=OrbitAction.OrbitPattern.RaceTrack) - pt.tasks.append(action) + action = ControlledTask(OrbitAction(altitude=pt.alt, pattern=OrbitAction.OrbitPattern.RaceTrack)) + action.stop_after_duration(CAP_DURATION * 60) #for tgt in point.targets: # if hasattr(tgt, "position"): # engagetgt = EngageTargetsInZone(tgt.position, radius=CAP_DEFAULT_ENGAGE_DISTANCE, targets=[Targets.All.Air]) diff --git a/gen/fleet/schnellboot.py b/gen/fleet/schnellboot.py new file mode 100644 index 00000000..20459ac7 --- /dev/null +++ b/gen/fleet/schnellboot.py @@ -0,0 +1,19 @@ +import random + +from dcs.ships import Schnellboot_type_S130 + +from gen.sam.group_generator import GroupGenerator + + +class SchnellbootGroupGenerator(GroupGenerator): + + def __init__(self, game, ground_object, faction): + super(SchnellbootGroupGenerator, self).__init__(game, ground_object) + self.faction = faction + + def generate(self): + + for i in range(random.randint(2, 4)): + self.add_unit(Schnellboot_type_S130, "Schnellboot" + str(i), self.position.x + i * random.randint(100, 250), self.position.y + (random.randint(100, 200)-100), self.heading) + + self.get_generated_group().points[0].speed = 20 \ No newline at end of file diff --git a/gen/fleet/ship_group_generator.py b/gen/fleet/ship_group_generator.py index 5892e28b..114312b6 100644 --- a/gen/fleet/ship_group_generator.py +++ b/gen/fleet/ship_group_generator.py @@ -1,6 +1,35 @@ +import random + from game import db from gen.fleet.carrier_group import CarrierGroupGenerator from gen.fleet.lha_group import LHAGroupGenerator +from dcs.ships import * + +from gen.fleet.schnellboot import SchnellbootGroupGenerator +from gen.fleet.uboat import UBoatGroupGenerator +from gen.fleet.ww2lst import WW2LSTGroupGenerator + +SHIP_MAP = { + Schnellboot_type_S130: SchnellbootGroupGenerator, + LS_Samuel_Chase: WW2LSTGroupGenerator, + Uboat_VIIC_U_flak: UBoatGroupGenerator +} + + +def generate_ship_group(game, ground_object, faction:str): + """ + This generate a ship group + :return: Nothing, but put the group reference inside the ground object + """ + faction = db.FACTIONS[faction] + if "boat" in faction.keys(): + ships = faction["boat"] + if len(ships) > 0: + sam = random.choice(ships) + generator = SHIP_MAP[sam](game, ground_object, faction) + generator.generate() + return generator.get_generated_group() + return None def generate_carrier_group(faction:str, game, ground_object): diff --git a/gen/fleet/uboat.py b/gen/fleet/uboat.py new file mode 100644 index 00000000..3087e428 --- /dev/null +++ b/gen/fleet/uboat.py @@ -0,0 +1,19 @@ +import random + +from dcs.ships import Uboat_VIIC_U_flak + +from gen.sam.group_generator import GroupGenerator + + +class UBoatGroupGenerator(GroupGenerator): + + def __init__(self, game, ground_object, faction): + super(UBoatGroupGenerator, self).__init__(game, ground_object) + self.faction = faction + + def generate(self): + + for i in range(random.randint(2, 6)): + self.add_unit(Uboat_VIIC_U_flak, "Uboat" + str(i), self.position.x + i * random.randint(100, 250), self.position.y + (random.randint(100, 200)-100), self.heading) + + self.get_generated_group().points[0].speed = 20 \ No newline at end of file diff --git a/gen/fleet/ww2lst.py b/gen/fleet/ww2lst.py new file mode 100644 index 00000000..ce421a97 --- /dev/null +++ b/gen/fleet/ww2lst.py @@ -0,0 +1,22 @@ +import random + +from dcs.ships import LS_Samuel_Chase, LST_Mk_II + +from gen.sam.group_generator import GroupGenerator + + +class WW2LSTGroupGenerator(GroupGenerator): + + def __init__(self, game, ground_object, faction): + super(WW2LSTGroupGenerator, self).__init__(game, ground_object) + self.faction = faction + + def generate(self): + + # Add LS Samuel Chase + self.add_unit(LS_Samuel_Chase, "SamuelChase", self.position.x, self.position.y, self.heading) + + for i in range(random.randint(2, 4)): + self.add_unit(LST_Mk_II, "LST" + str(i), self.position.x + i * random.randint(400, 600), self.position.y, self.heading) + + self.get_generated_group().points[0].speed = 20 \ No newline at end of file diff --git a/gen/flights/ai_flight_planner.py b/gen/flights/ai_flight_planner.py index 739a895c..18980fe4 100644 --- a/gen/flights/ai_flight_planner.py +++ b/gen/flights/ai_flight_planner.py @@ -3,46 +3,15 @@ import operator import random from game import db +from game.data.doctrine import MODERN_DOCTRINE +from game.data.radar_db import UNITS_WITH_RADAR +from game.utils import meter_to_feet, nm_to_meter from gen import Conflict from gen.flights.ai_flight_planner_db import INTERCEPT_CAPABLE, CAP_CAPABLE, CAS_CAPABLE, SEAD_CAPABLE, STRIKE_CAPABLE from gen.flights.flight import Flight, FlightType, FlightWaypoint, FlightWaypointType -def meter_to_feet(value_in_meter): - return int(3.28084 * value_in_meter) - - -def feet_to_meter(value_in_feet): - return int(float(value_in_feet)/3.048) - - -def meter_to_nm(value_in_meter): - return int(float(value_in_meter)*0.000539957) - - -def nm_to_meter(value_in_nm): - return int(float(value_in_nm)*1852) - - -# TODO : Ideally should be based on the aircraft type instead / Availability of fuel -STRIKE_MAX_RANGE = 1500000 -SEAD_MAX_RANGE = 1500000 - -MAX_NUMBER_OF_INTERCEPTION_GROUP = 3 -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 = nm_to_meter(45) -INGRESS_ALT = feet_to_meter(20000) -EGRESS_ALT = feet_to_meter(20000) -PATROL_ALT_RANGE = (feet_to_meter(15000), feet_to_meter(33000)) -NAV_ALT = 9144 -PATTERN_ALTITUDE = feet_to_meter(5000) - -CAP_DEFAULT_ENGAGE_DISTANCE = nm_to_meter(40) +MISSION_DURATION = 120 class FlightPlanner: @@ -54,6 +23,17 @@ class FlightPlanner: self.game = game self.aircraft_inventory = {} # local copy of the airbase inventory + if from_cp.captured: + self.faction = self.game.player_faction + else: + self.faction = self.game.enemy_faction + + if "doctrine" in self.faction.keys(): + self.doctrine = self.faction["doctrine"] + else: + self.doctrine = MODERN_DOCTRINE + + def reset(self): """ Reset the planned flights and available units @@ -111,7 +91,7 @@ class FlightPlanner: """ # At least try to generate one interceptor group - number_of_interceptor_groups = min(max(sum([v for k, v in self.aircraft_inventory.items()]) / 4, MAX_NUMBER_OF_INTERCEPTION_GROUP), 1) + number_of_interceptor_groups = min(max(sum([v for k, v in self.aircraft_inventory.items()]) / 4, self.doctrine["MAX_NUMBER_OF_INTERCEPTION_GROUP"]), 1) possible_interceptors = [k for k in self.aircraft_inventory.keys() if k in INTERCEPT_CAPABLE] if len(possible_interceptors) <= 0: @@ -144,7 +124,7 @@ class FlightPlanner: inventory = dict({k: v for k, v in self.aircraft_inventory.items() if k in possible_aircraft}) offset = random.randint(0,5) - for i in range(int(MISSION_DURATION/CAP_EVERY_X_MINUTES)): + for i in range(int(MISSION_DURATION/self.doctrine["CAP_EVERY_X_MINUTES"])): try: unit = random.choice([k for k, v in inventory.items() if v >= 2]) @@ -155,7 +135,7 @@ class FlightPlanner: flight = Flight(unit, 2, self.from_cp, FlightType.CAP) 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(self.doctrine["CAP_EVERY_X_MINUTES"] - 5, self.doctrine["CAP_EVERY_X_MINUTES"] + 5) if len(self._get_cas_locations()) > 0: enemy_cp = random.choice(self._get_cas_locations()) @@ -182,7 +162,7 @@ class FlightPlanner: if len(cas_location) > 0: offset = random.randint(0,5) - for i in range(int(MISSION_DURATION/CAS_EVERY_X_MINUTES)): + for i in range(int(MISSION_DURATION/self.doctrine["CAS_EVERY_X_MINUTES"])): try: unit = random.choice([k for k, v in inventory.items() if v >= 2]) @@ -192,7 +172,7 @@ class FlightPlanner: inventory[unit] = inventory[unit] - 2 flight = Flight(unit, 2, self.from_cp, FlightType.CAS) 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(self.doctrine["CAS_EVERY_X_MINUTES"] - 5, self.doctrine["CAS_EVERY_X_MINUTES"] + 5) location = random.choice(cas_location) self.generate_cas(flight, flight.from_cp, location) @@ -215,7 +195,7 @@ class FlightPlanner: if len(self.potential_sead_targets) > 0: offset = random.randint(0,5) - for i in range(int(MISSION_DURATION/SEAD_EVERY_X_MINUTES)): + for i in range(int(MISSION_DURATION/self.doctrine["SEAD_EVERY_X_MINUTES"])): if len(self.potential_sead_targets) <= 0: break @@ -229,7 +209,7 @@ class FlightPlanner: flight = Flight(unit, 2, self.from_cp, random.choice([FlightType.SEAD, FlightType.DEAD])) 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(self.doctrine["SEAD_EVERY_X_MINUTES"] - 5, self.doctrine["SEAD_EVERY_X_MINUTES"] + 5) location = self.potential_sead_targets[0][0] self.potential_sead_targets.pop(0) @@ -254,7 +234,7 @@ class FlightPlanner: if len(self.potential_strike_targets) > 0: offset = random.randint(0,5) - for i in range(int(MISSION_DURATION/STRIKE_EVERY_X_MINUTES)): + for i in range(int(MISSION_DURATION/self.doctrine["STRIKE_EVERY_X_MINUTES"])): if len(self.potential_strike_targets) <= 0: break @@ -268,7 +248,7 @@ class FlightPlanner: 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) + flight.scheduled_in = offset + i*random.randint(self.doctrine["STRIKE_EVERY_X_MINUTES"] - 5, self.doctrine["STRIKE_EVERY_X_MINUTES"] + 5) location = self.potential_strike_targets[0][0] self.potential_strike_targets.pop(0) @@ -306,7 +286,7 @@ class FlightPlanner: distance = math.hypot(cp.position.x - self.from_cp.position.x, cp.position.y - self.from_cp.position.y) - if distance > 2*STRIKE_MAX_RANGE: + if distance > 2*self.doctrine["STRIKE_MAX_RANGE"]: # Then it's unlikely any child ground object is in range return @@ -318,7 +298,7 @@ class FlightPlanner: distance = math.hypot(cp.position.x - self.from_cp.position.x, cp.position.y - self.from_cp.position.y) - if distance < SEAD_MAX_RANGE: + if distance < self.doctrine["SEAD_MAX_RANGE"]: self.potential_strike_targets.append((g, distance)) added_group.append(g) @@ -339,7 +319,7 @@ class FlightPlanner: cp.position.y - self.from_cp.position.y) # Then it's unlikely any ground object is range - if distance > 2*SEAD_MAX_RANGE: + if distance > 2*self.doctrine["SEAD_MAX_RANGE"]: return for g in cp.ground_objects: @@ -347,8 +327,7 @@ class FlightPlanner: if g.dcs_identifier == "AA": # Check that there is at least one unit with a radar in the ground objects unit groups - number_of_units = sum([len([r for r in group.units if hasattr(db.unit_type_from_name(r.type), "detection_range") - and db.unit_type_from_name(r.type).detection_range > 1000]) for group in g.groups]) + number_of_units = sum([len([r for r in group.units if db.unit_type_from_name(r.type) in UNITS_WITH_RADAR]) for group in g.groups]) if number_of_units <= 0: continue @@ -356,7 +335,7 @@ class FlightPlanner: distance = math.hypot(cp.position.x - self.from_cp.position.x, cp.position.y - self.from_cp.position.y) - if distance < SEAD_MAX_RANGE: + if distance < self.doctrine["SEAD_MAX_RANGE"]: self.potential_sead_targets.append((g, distance)) self.potential_sead_targets.sort(key=operator.itemgetter(1)) @@ -385,8 +364,8 @@ class FlightPlanner: 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_pos = location.position.point_from_heading(ingress_heading, self.doctrine["INGRESS_EGRESS_DISTANCE"]) + ingress_point = FlightWaypoint(ingress_pos.x, ingress_pos.y, self.doctrine["INGRESS_ALT"]) ingress_point.pretty_name = "INGRESS on " + location.obj_name ingress_point.description = "INGRESS on " + location.obj_name ingress_point.name = "INGRESS" @@ -428,8 +407,8 @@ class FlightPlanner: 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_pos = location.position.point_from_heading(egress_heading, self.doctrine["INGRESS_EGRESS_DISTANCE"]) + egress_point = FlightWaypoint(egress_pos.x, egress_pos.y, self.doctrine["EGRESS_ALT"]) egress_point.name = "EGRESS" egress_point.pretty_name = "EGRESS from " + location.obj_name egress_point.description = "EGRESS from " + location.obj_name @@ -447,22 +426,20 @@ class FlightPlanner: 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]) + patrol_alt = random.randint(self.doctrine["PATROL_ALT_RANGE"][0], self.doctrine["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)) + radius = random.randint(self.doctrine["CAP_PATTERN_LENGTH"][0], self.doctrine["CAP_PATTERN_LENGTH"][1]) 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))) + loc = for_cp.position.point_from_heading(random.randint(0, 360), random.randint(self.doctrine["CAP_DISTANCE_FROM_CP"][0], self.doctrine["CAP_DISTANCE_FROM_CP"][1])) hdg = for_cp.position.heading_between_point(loc) - radius = nm_to_meter(random.randint(15, 40)) + radius = random.randint(self.doctrine["CAP_PATTERN_LENGTH"][0], self.doctrine["CAP_PATTERN_LENGTH"][1]) orbit0p = loc.point_from_heading(hdg - 90, radius) orbit1p = loc.point_from_heading(hdg + 90, radius) @@ -507,7 +484,7 @@ class FlightPlanner: :param enemy_cp: Enemy connected cp """ flight.flight_type = FlightType.CAP - patrol_alt = random.randint(PATROL_ALT_RANGE[0], PATROL_ALT_RANGE[1]) + patrol_alt = random.randint(self.doctrine["PATROL_ALT_RANGE"][0], self.doctrine["PATROL_ALT_RANGE"][1]) # Find targets waypoints ingress, heading, distance = Conflict.frontline_vector(ally_cp, enemy_cp, self.game.theater) @@ -563,8 +540,8 @@ class FlightPlanner: 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_pos = location.position.point_from_heading(ingress_heading, self.doctrine["INGRESS_EGRESS_DISTANCE"]) + ingress_point = FlightWaypoint(ingress_pos.x, ingress_pos.y, self.doctrine["INGRESS_ALT"]) ingress_point.name = "INGRESS" ingress_point.pretty_name = "INGRESS on " + location.obj_name ingress_point.description = "INGRESS on " + location.obj_name @@ -599,8 +576,8 @@ class FlightPlanner: 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_pos = location.position.point_from_heading(egress_heading, self.doctrine["INGRESS_EGRESS_DISTANCE"]) + egress_point = FlightWaypoint(egress_pos.x, egress_pos.y, self.doctrine["EGRESS_ALT"]) egress_point.name = "INGRESS" egress_point.pretty_name = "EGRESS from " + location.obj_name egress_point.description = "EGRESS from " + location.obj_name @@ -670,11 +647,11 @@ class FlightPlanner: """ ascend_heading = from_cp.heading 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, self.doctrine["PATTERN_ALTITUDE"]) ascend.name = "ASCEND" ascend.alt_type = "RADIO" - ascend.description = "Ascend to alt [" + str(meter_to_feet(PATTERN_ALTITUDE)) + " ft AGL], then proceed to next waypoint" - ascend.pretty_name = "Ascend to alt [" + str(meter_to_feet(PATTERN_ALTITUDE)) + " ft AGL]" + ascend.description = "Ascend to alt [" + str(meter_to_feet(self.doctrine["PATTERN_ALTITUDE"])) + " ft AGL], then proceed to next waypoint" + ascend.pretty_name = "Ascend to alt [" + str(meter_to_feet(self.doctrine["PATTERN_ALTITUDE"])) + " ft AGL]" ascend.waypoint_type = FlightWaypointType.ASCEND_POINT return ascend @@ -687,11 +664,11 @@ class FlightPlanner: """ ascend_heading = from_cp.heading 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, self.doctrine["PATTERN_ALTITUDE"]) descend.name = "DESCEND" descend.alt_type = "RADIO" - descend.description = "Descend to pattern alt [" + str(meter_to_feet(PATTERN_ALTITUDE)) + " ft AGL], contact tower, and land" - descend.pretty_name = "Descend to pattern alt [" + str(meter_to_feet(PATTERN_ALTITUDE)) + " ft AGL]" + descend.description = "Descend to pattern alt [" + str(meter_to_feet(self.doctrine["PATTERN_ALTITUDE"])) + " ft AGL], contact tower, and land" + descend.pretty_name = "Descend to pattern alt [" + str(meter_to_feet(self.doctrine["PATTERN_ALTITUDE"])) + " ft AGL]" descend.waypoint_type = FlightWaypointType.DESCENT_POINT return descend diff --git a/gen/flights/ai_flight_planner_db.py b/gen/flights/ai_flight_planner_db.py index 7debd2f8..b207fc0c 100644 --- a/gen/flights/ai_flight_planner_db.py +++ b/gen/flights/ai_flight_planner_db.py @@ -171,6 +171,7 @@ STRIKE_CAPABLE = [ P_51D, P_47D_30, A_20G, + B_17G, SpitfireLFMkIXCW, SpitfireLFMkIX, diff --git a/gen/groundobjectsgen.py b/gen/groundobjectsgen.py index 46a514e6..050f1f2c 100644 --- a/gen/groundobjectsgen.py +++ b/gen/groundobjectsgen.py @@ -66,21 +66,35 @@ class GroundObjectsGenerator: utype = unit_type_from_name(g.units[0].type) - vg = self.m.vehicle_group(side, g.name, utype, position=g.position, heading=g.units[0].heading) - vg.units[0].name = self.m.string(g.units[0].name) - for i, u in enumerate(g.units): - if i > 0: - vehicle = Vehicle(self.m.next_unit_id(), self.m.string(u.name), u.type) - vehicle.position.x = u.position.x - vehicle.position.y = u.position.y - vehicle.heading = u.heading - vg.add_unit(vehicle) + if not ground_object.sea_object: + vg = self.m.vehicle_group(side, g.name, utype, position=g.position, heading=g.units[0].heading) + vg.units[0].name = self.m.string(g.units[0].name) + for i, u in enumerate(g.units): + if i > 0: + vehicle = Vehicle(self.m.next_unit_id(), self.m.string(u.name), u.type) + vehicle.position.x = u.position.x + vehicle.position.y = u.position.y + vehicle.heading = u.heading + vg.add_unit(vehicle) + else: + vg = self.m.ship_group(side, g.name, utype, position=g.position, + heading=g.units[0].heading) + vg.units[0].name = self.m.string(g.units[0].name) + for i, u in enumerate(g.units): + utype = unit_type_from_name(u.type) + if i > 0: + ship = Ship(self.m.next_unit_id(), self.m.string(u.name), utype) + ship.position.x = u.position.x + ship.position.y = u.position.y + ship.heading = u.heading + vg.add_unit(ship) if self.game.settings.perf_red_alert_state: vg.points[0].tasks.append(OptAlarmState(2)) else: vg.points[0].tasks.append(OptAlarmState(1)) + elif ground_object.dcs_identifier in ["CARRIER", "LHA"]: for g in ground_object.groups: if len(g.units) > 0: diff --git a/gen/sam/aaa_flak.py b/gen/sam/aaa_flak.py index afbae9f0..54ee600a 100644 --- a/gen/sam/aaa_flak.py +++ b/gen/sam/aaa_flak.py @@ -15,7 +15,7 @@ class FlakGenerator(GroupGenerator): grid_x = random.randint(2, 4) grid_y = random.randint(2, 4) - spacing = random.randint(10,40) + spacing = random.randint(30,60) index = 0 mixed = random.choice([True, False]) @@ -25,8 +25,8 @@ class FlakGenerator(GroupGenerator): for j in range(grid_y): index = index+1 self.add_unit(unit_type, "AAA#" + str(index), - self.position.x + spacing*i, - self.position.y + spacing*j, self.heading) + self.position.x + spacing*i + random.randint(1,5), + self.position.y + spacing*j + random.randint(1,5), self.heading) if(mixed): unit_type = random.choice(GFLAK) @@ -35,5 +35,5 @@ class FlakGenerator(GroupGenerator): for i in range(grid_x): for j in range(grid_y): self.add_unit(Unarmed.Blitz_3_6_6700A, "AAA#" + str(index), - self.position.x + 200 + 9*i, - self.position.y + 9*j, 90) \ No newline at end of file + self.position.x + 200 + 15*i + random.randint(1,5), + self.position.y + 15*j + random.randint(1,5), 90) \ No newline at end of file diff --git a/qt_ui/windows/QNewGameWizard.py b/qt_ui/windows/QNewGameWizard.py index f61bfad5..c0d2cf96 100644 --- a/qt_ui/windows/QNewGameWizard.py +++ b/qt_ui/windows/QNewGameWizard.py @@ -43,6 +43,7 @@ class NewGameWizard(QtWidgets.QWizard): isTerrainNormandy = self.field("isTerrainNormandy") isTerrainNormandySmall = self.field("isTerrainNormandySmall") isTerrainChannel = self.field("isTerrainChannel") + isTerrainChannelComplete = self.field("isTerrainChannelComplete") isTerrainEmirates = self.field("isTerrainEmirates") timePeriod = db.TIME_PERIODS[list(db.TIME_PERIODS.keys())[self.field("timePeriod")]] midGame = self.field("midGame") @@ -71,6 +72,8 @@ class NewGameWizard(QtWidgets.QWizard): conflicttheater = normandy.NormandySmall() elif isTerrainChannel: conflicttheater = thechannel.ChannelTheater() + elif isTerrainChannelComplete: + conflicttheater = thechannel.ChannelTheaterComplete() else: conflicttheater = caucasus.CaucasusTheater() @@ -248,8 +251,10 @@ class TheaterConfiguration(QtWidgets.QWizardPage): terrainNormandy.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Normandy"])) terrainNormandySmall = QtWidgets.QRadioButton("Normandy Small") terrainNormandySmall.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Normandy"])) - terrainChannel = QtWidgets.QRadioButton("Channel") + terrainChannel = QtWidgets.QRadioButton("The Channel : Start in Dunkirk") terrainChannel.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Channel"])) + terrainChannelComplete = QtWidgets.QRadioButton("The Channel : Battle of Britain") + terrainChannelComplete.setIcon(QtGui.QIcon(CONST.ICONS["Terrain_Channel"])) terrainCaucasusSmall.setChecked(True) # Time Period @@ -273,6 +278,7 @@ class TheaterConfiguration(QtWidgets.QWizardPage): self.registerField('isTerrainNormandy', terrainNormandy) self.registerField('isTerrainNormandySmall', terrainNormandySmall) self.registerField('isTerrainChannel', terrainChannel) + self.registerField('isTerrainChannelComplete', terrainChannelComplete) self.registerField('timePeriod', timePeriodSelect) # Build layout @@ -287,6 +293,7 @@ class TheaterConfiguration(QtWidgets.QWizardPage): terrainGroupLayout.addWidget(terrainNttr) terrainGroupLayout.addWidget(terrainNormandy) terrainGroupLayout.addWidget(terrainNormandySmall) + terrainGroupLayout.addWidget(terrainChannelComplete) terrainGroupLayout.addWidget(terrainChannel) terrainGroup.setLayout(terrainGroupLayout) diff --git a/qt_ui/windows/mission/flight/generator/QCASMissionGenerator.py b/qt_ui/windows/mission/flight/generator/QCASMissionGenerator.py index f655c693..cfae4e52 100644 --- a/qt_ui/windows/mission/flight/generator/QCASMissionGenerator.py +++ b/qt_ui/windows/mission/flight/generator/QCASMissionGenerator.py @@ -3,7 +3,7 @@ from PySide2.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout, QGroupBox from dcs import Point from game import Game -from gen.flights.ai_flight_planner import meter_to_nm +from game.utils 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 diff --git a/qt_ui/windows/mission/flight/generator/QSEADMissionGenerator.py b/qt_ui/windows/mission/flight/generator/QSEADMissionGenerator.py index e243a5f5..7221844c 100644 --- a/qt_ui/windows/mission/flight/generator/QSEADMissionGenerator.py +++ b/qt_ui/windows/mission/flight/generator/QSEADMissionGenerator.py @@ -2,7 +2,7 @@ from PySide2.QtGui import Qt from PySide2.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout, QGroupBox from game import Game -from gen.flights.ai_flight_planner import meter_to_nm +from game.utils import meter_to_nm from gen.flights.flight import Flight from qt_ui.widgets.combos.QSEADTargetSelectionComboBox import QSEADTargetSelectionComboBox from qt_ui.widgets.views.QSeadTargetInfoView import QSeadTargetInfoView diff --git a/qt_ui/windows/mission/flight/generator/QSTRIKEMissionGenerator.py b/qt_ui/windows/mission/flight/generator/QSTRIKEMissionGenerator.py index ea948814..1c07d735 100644 --- a/qt_ui/windows/mission/flight/generator/QSTRIKEMissionGenerator.py +++ b/qt_ui/windows/mission/flight/generator/QSTRIKEMissionGenerator.py @@ -2,7 +2,7 @@ from PySide2.QtGui import Qt from PySide2.QtWidgets import QLabel, QHBoxLayout, QVBoxLayout, QGroupBox from game import Game -from gen.flights.ai_flight_planner import meter_to_nm +from game.utils import meter_to_nm from gen.flights.flight import Flight from qt_ui.widgets.combos.QStrikeTargetSelectionComboBox import QStrikeTargetSelectionComboBox from qt_ui.widgets.views.QStrikeTargetInfoView import QStrikeTargetInfoView diff --git a/resources/customized_payloads/B-17G.lua b/resources/customized_payloads/B-17G.lua new file mode 100644 index 00000000..afc82a21 --- /dev/null +++ b/resources/customized_payloads/B-17G.lua @@ -0,0 +1,69 @@ +local unitPayloads = { + ["name"] = "B-17G", + ["payloads"] = { + [1] = { + ["name"] = "STRIKE", + ["pylons"] = { + [1] = { + ["CLSID"] = "{12xM64}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 32, + }, + }, + [2] = { + ["name"] = "CAP", + ["pylons"] = { + [1] = { + ["CLSID"] = "{12xM64}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 32, + }, + }, + [3] = { + ["name"] = "SEAD", + ["pylons"] = { + [1] = { + ["CLSID"] = "{12xM64}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 32, + }, + }, + [4] = { + ["name"] = "ANTISHIP", + ["pylons"] = { + [1] = { + ["CLSID"] = "{12xM64}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 32, + }, + }, + [5] = { + ["name"] = "CAS", + ["pylons"] = { + [1] = { + ["CLSID"] = "{12xM64}", + ["num"] = 1, + }, + }, + ["tasks"] = { + [1] = 32, + }, + }, + }, + ["tasks"] = { + }, + ["unitType"] = "B-17G", +} +return unitPayloads diff --git a/resources/tools/groundobject_templates.miz b/resources/tools/groundobject_templates.miz index 10ddade8..b4fe1437 100644 Binary files a/resources/tools/groundobject_templates.miz and b/resources/tools/groundobject_templates.miz differ diff --git a/theater/start_generator.py b/theater/start_generator.py index 824650c4..5834a986 100644 --- a/theater/start_generator.py +++ b/theater/start_generator.py @@ -7,7 +7,7 @@ import logging from game.data.building_data import DEFAULT_AVAILABLE_BUILDINGS from gen import namegen from gen.defenses.armor_group_generator import generate_armor_group -from gen.fleet.ship_group_generator import generate_carrier_group, generate_lha_group +from gen.fleet.ship_group_generator import generate_carrier_group, generate_lha_group, generate_ship_group from gen.sam.sam_group_generator import generate_anti_air_group, generate_shorad_group from theater import ControlPointType from theater.base import * @@ -81,6 +81,7 @@ def generate_groundobjects(theater: ConflictTheater, game): g.cp_id = cp.id g.airbase_group = True g.dcs_identifier = "CARRIER" + g.sea_object = True g.obj_name = namegen.random_objective_name() g.heading = 0 g.position = Point(cp.position.x, cp.position.y) @@ -101,6 +102,7 @@ def generate_groundobjects(theater: ConflictTheater, game): g.cp_id = cp.id g.airbase_group = True g.dcs_identifier = "LHA" + g.sea_object = True g.obj_name = namegen.random_objective_name() g.heading = 0 g.position = Point(cp.position.x, cp.position.y) @@ -114,7 +116,7 @@ def generate_groundobjects(theater: ConflictTheater, game): cp.name = random.choice(db.FACTIONS[faction]["lhanames"]) else: - for i in range(random.randint(2,6)): + for i in range(random.randint(3,6)): print("GENERATE BASE DEFENSE") point = find_location(True, cp.position, theater, 1000, 2800, [], True) @@ -132,6 +134,7 @@ def generate_groundobjects(theater: ConflictTheater, game): g.cp_id = cp.id g.airbase_group = True g.dcs_identifier = "AA" + g.sea_object = False g.obj_name = namegen.random_objective_name() g.heading = 0 g.position = Point(point.x, point.y) @@ -144,6 +147,35 @@ def generate_groundobjects(theater: ConflictTheater, game): for ground_object in cp.ground_objects: print(ground_object.groups) + for i in range(random.randint(2, 3)): + + print("GENERATE SHIPS") + point = find_location(False, cp.position, theater, 5000, 40000, [], False) + print(point) + + if point is None: + print("Couldn't find point for {} ships".format(cp)) + continue + + group_id = group_id + 1 + + g = TheaterGroundObject("aa") + g.group_id = group_id + g.object_id = 0 + g.cp_id = cp.id + g.airbase_group = False + g.dcs_identifier = "AA" + g.sea_object = True + g.obj_name = namegen.random_objective_name() + g.heading = 0 + g.position = Point(point.x, point.y) + + group = generate_ship_group(game, g, faction) + g.groups = [] + if group is not None: + g.groups.append(group) + cp.ground_objects.append(g) + def generate_airbase_defense_group(airbase_defense_group_id, ground_obj:TheaterGroundObject, faction, game, cp): @@ -286,6 +318,7 @@ def generate_cp_ground_points(cp: ControlPoint, theater, game, group_id, templat g.dcs_identifier = object["type"] g.heading = object["heading"] + g.sea_object = False g.position = Point(point.x + object["offset"].x, point.y + object["offset"].y) if g.dcs_identifier == "AA": diff --git a/theater/theatergroundobject.py b/theater/theatergroundobject.py index 51c54e2c..f7441663 100644 --- a/theater/theatergroundobject.py +++ b/theater/theatergroundobject.py @@ -69,6 +69,7 @@ class TheaterGroundObject: position = None # type: Point groups = [] obj_name = "" + sea_object = False def __init__(self, category: str): self.category = category diff --git a/theater/thechannel.py b/theater/thechannel.py index ce44d95f..97132d20 100644 --- a/theater/thechannel.py +++ b/theater/thechannel.py @@ -21,7 +21,54 @@ class ChannelTheater(ConflictTheater): super(ChannelTheater, self).__init__() self.abeville = ControlPoint.from_airport(thechannel.Abbeville_Drucat, LAND, SIZE_SMALL, IMPORTANCE_LOW) - self.detling = ControlPoint.from_airport(thechannel.Detling, LAND, SIZE_SMALL, IMPORTANCE_LOW) + #self.detling = ControlPoint.from_airport(thechannel.Detling, LAND, SIZE_SMALL, IMPORTANCE_LOW) + + self.stomer = ControlPoint.from_airport(thechannel.Saint_Omer_Longuenesse, LAND, SIZE_SMALL, IMPORTANCE_LOW) + self.dunkirk = ControlPoint.from_airport(thechannel.Dunkirk_Mardyck, LAND, SIZE_SMALL, IMPORTANCE_LOW) + self.hawkinge = ControlPoint.from_airport(thechannel.Hawkinge, LAND, SIZE_SMALL, IMPORTANCE_LOW) + #self.highhalden = ControlPoint.from_airport(thechannel.High_Halden, LAND, SIZE_SMALL, IMPORTANCE_LOW) + self.lympne = ControlPoint.from_airport(thechannel.Lympne, LAND, SIZE_SMALL, IMPORTANCE_LOW) + self.manston = ControlPoint.from_airport(thechannel.Manston, LAND, SIZE_SMALL, IMPORTANCE_LOW) + self.merville = ControlPoint.from_airport(thechannel.Merville_Calonne, LAND, SIZE_SMALL, IMPORTANCE_LOW) + + + # England + self.add_controlpoint(self.hawkinge, connected_to=[self.lympne, self.manston]) + self.add_controlpoint(self.lympne, connected_to=[self.hawkinge]) + self.add_controlpoint(self.manston, connected_to=[self.hawkinge]) + + # France + self.add_controlpoint(self.dunkirk, connected_to=[self.stomer]) + self.add_controlpoint(self.stomer, connected_to=[self.dunkirk, self.merville, self.abeville]) + self.add_controlpoint(self.merville, connected_to=[self.stomer]) + self.add_controlpoint(self.abeville, connected_to=[self.stomer]) + + #self.detling.captured = True + self.hawkinge.captured = True + self.dunkirk.captured = True + #self.highhalden.captured = True + self.lympne.captured = True + self.manston.captured = True + + +class ChannelTheaterComplete(ConflictTheater): + terrain = dcs.terrain.TheChannel() + overview_image = "thechannel.gif" + reference_points = {(thechannel.Abbeville_Drucat.position.x, thechannel.Abbeville_Drucat.position.y): (2400, 4100), + (thechannel.Detling.position.x, thechannel.Detling.position.y): (1100, 2000)} + landmap = load_landmap("resources\\channellandmap.p") + daytime_map = { + "dawn": (6, 8), + "day": (10, 17), + "dusk": (17, 18), + "night": (0, 5), + } + + def __init__(self): + super(ChannelTheaterComplete, self).__init__() + + self.abeville = ControlPoint.from_airport(thechannel.Abbeville_Drucat, LAND, SIZE_SMALL, IMPORTANCE_LOW) + #self.detling = ControlPoint.from_airport(thechannel.Detling, LAND, SIZE_SMALL, IMPORTANCE_LOW) self.stomer = ControlPoint.from_airport(thechannel.Saint_Omer_Longuenesse, LAND, SIZE_SMALL, IMPORTANCE_LOW) self.dunkirk = ControlPoint.from_airport(thechannel.Dunkirk_Mardyck, LAND, SIZE_SMALL, IMPORTANCE_LOW) @@ -31,13 +78,11 @@ class ChannelTheater(ConflictTheater): self.manston = ControlPoint.from_airport(thechannel.Manston, LAND, SIZE_SMALL, IMPORTANCE_LOW) self.merville = ControlPoint.from_airport(thechannel.Merville_Calonne, LAND, SIZE_SMALL, IMPORTANCE_LOW) - # England - self.add_controlpoint(self.detling, connected_to=[self.highhalden]) self.add_controlpoint(self.hawkinge, connected_to=[self.lympne, self.manston]) - self.add_controlpoint(self.highhalden, connected_to=[self.detling, self.lympne]) - self.add_controlpoint(self.lympne, connected_to=[self.highhalden, self.hawkinge]) + self.add_controlpoint(self.lympne, connected_to=[self.hawkinge, self.highhalden]) self.add_controlpoint(self.manston, connected_to=[self.hawkinge]) + self.add_controlpoint(self.highhalden, connected_to=[self.lympne]) # France self.add_controlpoint(self.dunkirk, connected_to=[self.stomer]) @@ -45,8 +90,9 @@ class ChannelTheater(ConflictTheater): self.add_controlpoint(self.merville, connected_to=[self.stomer]) self.add_controlpoint(self.abeville, connected_to=[self.stomer]) - self.detling.captured = True + #self.detling.captured = True self.hawkinge.captured = True + #self.dunkirk.captured = True self.highhalden.captured = True self.lympne.captured = True self.manston.captured = True \ No newline at end of file