diff --git a/game/operation/strike.py b/game/operation/strike.py index d937e89d..586bae14 100644 --- a/game/operation/strike.py +++ b/game/operation/strike.py @@ -35,6 +35,17 @@ class StrikeOperation(Operation): conflict=conflict) def generate(self): + for global_cp in self.game.theater.controlpoints: + if not global_cp.is_global: + continue + + ship = self.shipgen.generate_carrier(type=db.find_unittype(Carriage, self.game.player)[0], + country=self.game.player, + at=global_cp.at) + + if global_cp == self.from_cp and not self.is_quick: + self.attackers_starting_position = ship + targets = [] # type: typing.List[typing.Tuple[str, Point]] category_counters = {} # type: typing.Dict[str, int] processed_groups = [] diff --git a/gen/conflictgen.py b/gen/conflictgen.py index 0718ca9d..f28f70f3 100644 --- a/gen/conflictgen.py +++ b/gen/conflictgen.py @@ -155,7 +155,7 @@ class Conflict: return from_cp.has_frontline and to_cp.has_frontline @classmethod - def frontline_position(cls, from_cp: ControlPoint, to_cp: ControlPoint) -> typing.Tuple[Point, int]: + def frontline_position0(cls, from_cp: ControlPoint, to_cp: ControlPoint) -> typing.Tuple[Point, int]: cp_distance = from_cp.position.distance_to_point(to_cp.position) cp_distance -= cp_distance * to_cp.frontline_offset + cp_distance * from_cp.frontline_offset @@ -164,8 +164,45 @@ class Conflict: return to_cp.position.point_from_heading(heading, distance), heading @classmethod - def frontline_vector(cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater) -> typing.Tuple[Point, int, int]: - center_position, heading = cls.frontline_position(from_cp, to_cp) + def frontline_position2(cls, theater: ConflictTheater, from_cp: ControlPoint, to_cp: ControlPoint) -> typing.Optional[typing.Tuple[Point, int]]: + attack_heading = from_cp.position.heading_between_point(to_cp.position) + attack_starting_position = cls._find_ground_position(from_cp.position, 200000, attack_heading, theater) + if not attack_starting_position: + return None + + attack_ending_position = cls._find_ground_position(to_cp.position, 200000, _opposite_heading(attack_heading), theater) + if not attack_ending_position: + return None + + attack_distance = attack_ending_position.distance_to_point(attack_starting_position) + strength_delta = (from_cp.base.strength - to_cp.base.strength) / 1.0 + middle_position = attack_starting_position.point_from_heading(attack_heading, attack_distance / 2) + + return middle_position.point_from_heading(attack_heading, strength_delta * attack_distance), _opposite_heading(attack_heading) + + @classmethod + def frontline_position(cls, theater: ConflictTheater, from_cp: ControlPoint, to_cp: ControlPoint) -> typing.Optional[typing.Tuple[Point, int]]: + attack_heading = from_cp.position.heading_between_point(to_cp.position) + attack_distance = from_cp.position.distance_to_point(to_cp.position) + middle_point = from_cp.position.point_from_heading(attack_heading, attack_distance / 2) + + strength_delta = (from_cp.base.strength - to_cp.base.strength) / 1.0 + position = middle_point.point_from_heading(attack_heading, strength_delta * attack_distance / 2 - FRONTLINE_MIN_CP_DISTANCE) + ground_position = cls._find_ground_position(position, attack_distance / 2 - FRONTLINE_MIN_CP_DISTANCE, attack_heading, theater) + if ground_position: + return ground_position, attack_heading + else: + print(from_cp, to_cp) + return None + + + @classmethod + def frontline_vector(cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater) -> typing.Optional[typing.Tuple[Point, int, int]]: + frontline = cls.frontline_position(theater, from_cp, to_cp) + if not frontline: + return None + + center_position, heading = frontline left_position, right_position = None, None if not theater.is_on_land(center_position): @@ -401,7 +438,7 @@ class Conflict: @classmethod def transport_conflict(cls, attacker: Country, defender: Country, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater): - frontline_position, heading = cls.frontline_position(from_cp, to_cp) + frontline_position, heading = cls.frontline_position(theater, from_cp, to_cp) initial_dest = frontline_position.point_from_heading(heading, TRANSPORT_FRONTLINE_DIST) dest = cls._find_ground_position(initial_dest, from_cp.position.distance_to_point(to_cp.position) / 3, heading, theater) if not dest: diff --git a/gen/visualgen.py b/gen/visualgen.py index 175924e6..011765cf 100644 --- a/gen/visualgen.py +++ b/gen/visualgen.py @@ -98,7 +98,11 @@ class VisualGenerator: def _generate_frontline_smokes(self): for from_cp, to_cp in self.game.theater.conflicts(): - point, heading = Conflict.frontline_position(from_cp, to_cp) + frontline = Conflict.frontline_position(self.game.theater, from_cp, to_cp) + if not frontline: + continue + + point, heading = frontline plane_start = point.point_from_heading(turn_heading(heading, 90), FRONTLINE_LENGTH / 2) for offset in range(0, FRONTLINE_LENGTH, FRONT_SMOKE_SPACING): diff --git a/resources/caulandmap.p b/resources/caulandmap.p index f6e34d8e..88ba4d3c 100644 Binary files a/resources/caulandmap.p and b/resources/caulandmap.p differ diff --git a/resources/groundobject_templates.p b/resources/groundobject_templates.p index df95b3a1..779eaef9 100644 Binary files a/resources/groundobject_templates.p and b/resources/groundobject_templates.p differ diff --git a/resources/tools/cau_terrain.miz b/resources/tools/cau_terrain.miz index 65610873..e2373b5e 100644 Binary files a/resources/tools/cau_terrain.miz and b/resources/tools/cau_terrain.miz differ diff --git a/resources/tools/generate_groundobject_templates.py b/resources/tools/generate_groundobject_templates.py index 2995a9c4..78f2cd3b 100644 --- a/resources/tools/generate_groundobject_templates.py +++ b/resources/tools/generate_groundobject_templates.py @@ -11,7 +11,7 @@ def load_templates(): temp_mis = Mission() temp_mis.load_file("resources/tools/groundobject_templates.miz") - groups = {} # type: typing.Dict[str, typing.Dict[int, typing.Collection[Static]]] + groups = {} # type: typing.Dict[str, typing.Dict[int, typing.List[Static]]] for static_group in temp_mis.country("USA").static_group: for static in static_group.units: @@ -42,6 +42,7 @@ def load_templates(): "heading": static.heading, }) + tpls["aa"] = {0: [{"type": "AA", "offset": Point(0, 0), "heading": 0}]} return tpls diff --git a/theater/base.py b/theater/base.py index 46850300..d88f3995 100644 --- a/theater/base.py +++ b/theater/base.py @@ -3,18 +3,20 @@ import typing import math import itertools -from game import db -from theater.controlpoint import ControlPoint - from dcs.planes import * from dcs.vehicles import * from dcs.task import * +from game import db + STRENGTH_AA_ASSEMBLE_MIN = 0.2 PLANES_SCRAMBLE_MIN_BASE = 4 PLANES_SCRAMBLE_MAX_BASE = 8 PLANES_SCRAMBLE_FACTOR = 0.6 +BASE_MAX_STRENGTH = 1 +BASE_MIN_STRENGTH = 0 + class Base: aircraft = {} # type: typing.Dict[PlaneType, int] @@ -136,10 +138,10 @@ class Base: def affect_strength(self, amount): self.strength += amount - if self.strength > 1: - self.strength = 1 - elif self.strength < 0: - self.strength = 0.001 + if self.strength > BASE_MAX_STRENGTH: + self.strength = BASE_MAX_STRENGTH + elif self.strength <= 0: + self.strength = BASE_MIN_STRENGTH def scramble_count(self, multiplier: float, task: Task = None) -> int: if task: diff --git a/theater/caucasus.py b/theater/caucasus.py index ca5bb3f6..0db76aec 100644 --- a/theater/caucasus.py +++ b/theater/caucasus.py @@ -25,12 +25,12 @@ class CaucasusTheater(ConflictTheater): kutaisi = ControlPoint.from_airport(caucasus.Kutaisi, LAND, SIZE_SMALL, IMPORTANCE_LOW) senaki = ControlPoint.from_airport(caucasus.Senaki_Kolkhi, LAND, SIZE_REGULAR, IMPORTANCE_LOW) kobuleti = ControlPoint.from_airport(caucasus.Kobuleti, COAST_A_E, SIZE_SMALL, 1.1) - batumi = ControlPoint.from_airport(caucasus.Batumi, COAST_DL_E, SIZE_SMALL, 1.3) + batumi = ControlPoint.from_airport(caucasus.Batumi, COAST_DL_E, SIZE_SMALL, 1.3, has_frontline=False) sukhumi = ControlPoint.from_airport(caucasus.Sukhumi_Babushara, COAST_DR_E, SIZE_REGULAR, 1.2) - gudauta = ControlPoint.from_airport(caucasus.Gudauta, COAST_DR_E, SIZE_REGULAR, 1.2) - sochi = ControlPoint.from_airport(caucasus.Sochi_Adler, COAST_DR_E, SIZE_BIG, IMPORTANCE_HIGH) + gudauta = ControlPoint.from_airport(caucasus.Gudauta, COAST_DR_E, SIZE_REGULAR, 1.2, has_frontline=False) + sochi = ControlPoint.from_airport(caucasus.Sochi_Adler, COAST_DR_E, SIZE_BIG, IMPORTANCE_HIGH, has_frontline=False) - gelendzhik = ControlPoint.from_airport(caucasus.Gelendzhik, COAST_DR_E, SIZE_BIG, 1.1) + gelendzhik = ControlPoint.from_airport(caucasus.Gelendzhik, COAST_DR_E, SIZE_BIG, 1.1, has_frontline=False) maykop = ControlPoint.from_airport(caucasus.Maykop_Khanskaya, LAND, SIZE_LARGE, IMPORTANCE_HIGH) krasnodar = ControlPoint.from_airport(caucasus.Krasnodar_Center, LAND, SIZE_LARGE, IMPORTANCE_HIGH) novorossiysk = ControlPoint.from_airport(caucasus.Novorossiysk, COAST_DR_E, SIZE_BIG, 1.2) @@ -75,6 +75,7 @@ class CaucasusTheater(ConflictTheater): self.carrier_1.captured = True self.soganlug.captured = True + self.gudauta.captured = True def add_controlpoint(self, point: ControlPoint, connected_to: typing.Collection[ControlPoint] = []): point.name = " ".join(re.split(r"[ -]", point.name)[:1]) diff --git a/theater/controlpoint.py b/theater/controlpoint.py index b418285a..25865e42 100644 --- a/theater/controlpoint.py +++ b/theater/controlpoint.py @@ -49,7 +49,7 @@ class ControlPoint: @classmethod def carrier(cls, name: str, at: Point): import theater.conflicttheater - return cls(0, name, at, at, theater.conflicttheater.LAND, theater.conflicttheater.SIZE_SMALL, 1) + return cls(0, name, at, at, theater.conflicttheater.LAND, theater.conflicttheater.SIZE_SMALL, 1, has_frontline=False) def __str__(self): return self.name diff --git a/theater/nevada.py b/theater/nevada.py index da04e2de..566ca762 100644 --- a/theater/nevada.py +++ b/theater/nevada.py @@ -13,7 +13,7 @@ class NevadaTheater(ConflictTheater): daytime_map = { "dawn": (4, 6), "day": (6, 17), - "dusk": (17, 19), + "dusk": (17, 18), "night": (0, 5), } diff --git a/theater/start_generator.py b/theater/start_generator.py index e3e70b2f..bf5d8a75 100644 --- a/theater/start_generator.py +++ b/theater/start_generator.py @@ -59,7 +59,7 @@ def generate_groundobjects(theater: ConflictTheater): group_id = 0 for cp in theater.enemy_points(): for _ in range(0, random.randrange(3, 6)): - available_categories = list(tpls) + available_categories = list(tpls) + ["aa", "aa", "aa"] tpl_category = random.choice(available_categories) tpl = random.choice(list(tpls[tpl_category].values())) @@ -87,7 +87,7 @@ def generate_groundobjects(theater: ConflictTheater): g.cp_id = cp.id g.dcs_identifier = object["type"] - g.heading = object["heading"], + g.heading = object["heading"] g.position = Point(point.x + object["offset"].x, point.y + object["offset"].y) cp.ground_objects.append(g) diff --git a/ui/overviewcanvas.py b/ui/overviewcanvas.py index d1323b06..ff88a217 100644 --- a/ui/overviewcanvas.py +++ b/ui/overviewcanvas.py @@ -80,8 +80,16 @@ class OverviewCanvas: self.canvas.create_line((coords[0], coords[1], connected_coords[0], connected_coords[1]), width=2, fill=color) if cp.captured and not connected_cp.captured and Conflict.has_frontline_between(cp, connected_cp): - frontline_pos, heading, distance = Conflict.frontline_vector(cp, connected_cp, self.game.theater) - distance = max(distance, 1000) + frontline = Conflict.frontline_vector(cp, connected_cp, self.game.theater) + if not frontline: + print(cp, connected_cp) + continue + + frontline_pos, heading, distance = frontline + if distance < 10000: + frontline_pos = frontline_pos.point_from_heading(heading + 180, 5000) + distance = 10000 + start_coords = self.transform_point(frontline_pos, treshold=10) end_coords = self.transform_point(frontline_pos.point_from_heading(heading, distance), treshold=60)