From 1258f3e17ce11c67e40a10c6d938491ea483d6fe Mon Sep 17 00:00:00 2001 From: Khopa Date: Thu, 10 Dec 2020 00:13:34 +0100 Subject: [PATCH] Carrier and Tarawa are now fully moveable --- game/theater/conflicttheater.py | 4 ++ game/theater/controlpoint.py | 16 ++++- gen/groundobjectsgen.py | 9 ++- qt_ui/widgets/map/QLiberationMap.py | 94 +++++++++++++++++++++++------ 4 files changed, 102 insertions(+), 21 deletions(-) diff --git a/game/theater/conflicttheater.py b/game/theater/conflicttheater.py index 2f1414f0..6777b2bb 100644 --- a/game/theater/conflicttheater.py +++ b/game/theater/conflicttheater.py @@ -438,6 +438,10 @@ class ConflictTheater: if self.is_on_land(point): return False + for exclusion_zone in self.landmap[1]: + if poly_contains(point.x, point.y, exclusion_zone): + return False + for sea in self.landmap[2]: if poly_contains(point.x, point.y, sea): return True diff --git a/game/theater/controlpoint.py b/game/theater/controlpoint.py index 3885df11..82f1b385 100644 --- a/game/theater/controlpoint.py +++ b/game/theater/controlpoint.py @@ -29,7 +29,7 @@ from .theatergroundobject import ( EwrGroundObject, SamGroundObject, TheaterGroundObject, - VehicleGroupGroundObject, + VehicleGroupGroundObject, GenericCarrierGroundObject, ) from ..weather import Conditions @@ -443,6 +443,20 @@ class ControlPoint(MissionTarget, ABC): if runway_status is not None: runway_status.process_turn() + # Process movements for ships control points group + if self.target_position is not None: + delta = self.target_position - self.position + self.position = self.target_position + self.target_position = None + + # Move the linked unit groups + for ground_object in self.ground_objects: + if isinstance(ground_object, GenericCarrierGroundObject): + for group in ground_object.groups: + for u in group.units: + u.position.x = u.position.x + delta.x + u.position.y = u.position.y + delta.y + class Airfield(ControlPoint): diff --git a/gen/groundobjectsgen.py b/gen/groundobjectsgen.py index 57705d9a..5c3b7aa0 100644 --- a/gen/groundobjectsgen.py +++ b/gen/groundobjectsgen.py @@ -204,7 +204,10 @@ class GenericCarrierGenerator(GenericGroundObjectGenerator): tacan_callsign = self.tacan_callsign() icls = next(self.icls_alloc) - brc = self.steam_into_wind(ship_group) + if self.control_point.target_position is not None: + brc = self.steam_to_target_position(ship_group) + else: + brc = self.steam_into_wind(ship_group) self.activate_beacons(ship_group, tacan, tacan_callsign, icls) self.add_runway_data(brc or 0, atc, tacan, tacan_callsign, icls) self._register_unit_group(group, ship_group) @@ -248,6 +251,10 @@ class GenericCarrierGenerator(GenericGroundObjectGenerator): return brc return None + def steam_to_target_position(self, group: ShipGroup) -> Optional[int]: + group.add_waypoint(self.control_point.target_position) + return group.position.heading_between_point(self.control_point.target_position) + def tacan_callsign(self) -> str: raise NotImplementedError diff --git a/qt_ui/widgets/map/QLiberationMap.py b/qt_ui/widgets/map/QLiberationMap.py index ae10af14..4bf515b5 100644 --- a/qt_ui/widgets/map/QLiberationMap.py +++ b/qt_ui/widgets/map/QLiberationMap.py @@ -32,7 +32,7 @@ from game.theater.conflicttheater import FrontLine from game.theater.theatergroundobject import ( TheaterGroundObject, ) -from game.utils import meter_to_feet +from game.utils import meter_to_feet, nm_to_meter, meter_to_nm from game.weather import TimeOfDay from gen import Conflict from gen.flights.flight import Flight, FlightWaypoint, FlightWaypointType @@ -45,6 +45,7 @@ from qt_ui.widgets.map.QMapControlPoint import QMapControlPoint from qt_ui.widgets.map.QMapGroundObject import QMapGroundObject from qt_ui.windows.GameUpdateSignal import GameUpdateSignal +MAX_SHIP_DISTANCE = 80 def binomial(i: int, n: int) -> float: """Binomial coefficient""" @@ -153,6 +154,9 @@ class QLiberationMap(QGraphicsView): update_flight_selection ) + self.nm_to_pixel_ratio: int = 0 + + def init_scene(self): scene = QLiberationScene(self) self.setScene(scene) @@ -166,6 +170,7 @@ class QLiberationMap(QGraphicsView): self.game = game if self.game is not None: logging.debug("Reloading Map Canvas") + self.nm_to_pixel_ratio = self.km_to_pixel(float(nm_to_meter(1)) / 1000.0) self.reload_scene() """ @@ -239,12 +244,12 @@ class QLiberationMap(QGraphicsView): transformed = self._transform_point(point) diameter = distance_point[0] - transformed[0] scene.addEllipse(transformed[0]-diameter/2, transformed[1]-diameter/2, diameter, diameter, CONST.COLORS["transparent"], CONST.COLORS["light_green_transparent"]) - + @staticmethod def should_display_ground_objects_at(cp: ControlPoint) -> bool: return ((DisplayOptions.sam_ranges and cp.captured) or (DisplayOptions.enemy_sam_ranges and not cp.captured)) - + def draw_threat_range(self, scene: QGraphicsScene, ground_object: TheaterGroundObject, cp: ControlPoint) -> None: go_pos = self._transform_point(ground_object.position) detection_range, threat_range = self.aa_ranges( @@ -277,12 +282,12 @@ class QLiberationMap(QGraphicsView): if not ground_object.airbase_group: buildings = self.game.theater.find_ground_objects_by_obj_name(ground_object.obj_name) scene.addItem(QMapGroundObject(self, go_pos[0], go_pos[1], 14, 12, cp, ground_object, self.game, buildings)) - + should_display = self.should_display_ground_objects_at(cp) if ground_object.might_have_aa and should_display: self.draw_threat_range(scene, ground_object, cp) added_objects.append(ground_object.obj_name) - + def reload_scene(self): scene = self.scene() scene.clear() @@ -302,7 +307,7 @@ class QLiberationMap(QGraphicsView): self.display_culling(scene) for cp in self.game.theater.controlpoints: - + pos = self._transform_point(cp.position) scene.addItem(QMapControlPoint(self, pos[0] - CONST.CP_SIZE / 2, @@ -320,12 +325,10 @@ class QLiberationMap(QGraphicsView): self.draw_ground_objects(scene, cp) if cp.target_position is not None: - tpos = cp.target_position - proj = self._transform_point(Point(tpos[0], tpos[1])) + proj = self._transform_point(cp.target_position) scene.addLine(QLineF(QPointF(pos[0], pos[1]), QPointF(proj[0], proj[1])), QPen(CONST.COLORS["green"], width=10, s=Qt.DashDotLine)) - for cp in self.game.theater.enemy_points(): if DisplayOptions.lines: self.scene_create_lines_for_cp(cp, playerColor, enemyColor) @@ -467,7 +470,7 @@ class QLiberationMap(QGraphicsView): for segment in frontline.segments: bezier_fixed_points.append(self._transform_point(segment.point_a)) bezier_fixed_points.append(self._transform_point(segment.point_b)) - + old_point = bezier_fixed_points[0] for point in bezier_curve_range(int(len(bezier_fixed_points) * 2), bezier_fixed_points): scene.addLine(old_point[0], old_point[1], point[0], point[1], pen=pen) @@ -492,7 +495,7 @@ class QLiberationMap(QGraphicsView): self.draw_frontline_approximation(frontline, scene, pen) else: self.draw_bezier_frontline(scene, pen, frontline) - + def draw_frontline_approximation(self, frontline: FrontLine, scene: QGraphicsScene, pen: QPen) -> None: posx = frontline.position h = frontline.attack_heading @@ -533,6 +536,37 @@ class QLiberationMap(QGraphicsView): ) ) + def draw_scale(self, scale_distance_nm=20, number_of_points=4): + + PADDING = 14 + POS_X = 0 + POS_Y = 10 + BIG_LINE = 5 + SMALL_LINE = 2 + + dist = self.km_to_pixel(nm_to_meter(scale_distance_nm)/1000.0) + self.scene().addRect(POS_X, POS_Y-PADDING, PADDING*2 + dist, BIG_LINE*2+3*PADDING, pen=CONST.COLORS["black"], brush=CONST.COLORS["black"]) + l = self.scene().addLine(POS_X + PADDING, POS_Y + BIG_LINE*2, POS_X + PADDING + dist, POS_Y + BIG_LINE*2) + + text = self.scene().addText("0nm", font=QFont("Trebuchet MS", 6, weight=5, italic=False)) + text.setPos(POS_X, POS_Y + BIG_LINE*2) + text.setDefaultTextColor(Qt.white) + + text2 = self.scene().addText(str(scale_distance_nm) + "nm", font=QFont("Trebuchet MS", 6, weight=5, italic=False)) + text2.setPos(POS_X + dist, POS_Y + BIG_LINE * 2) + text2.setDefaultTextColor(Qt.white) + + l.setPen(CONST.COLORS["white"]) + for i in range(number_of_points+1): + d = float(i)/float(number_of_points) + if i == 0 or i == number_of_points: + h = BIG_LINE + else: + h = SMALL_LINE + + l = self.scene().addLine(POS_X + PADDING + d * dist, POS_Y + BIG_LINE*2, POS_X + PADDING + d * dist, POS_Y + BIG_LINE - h) + l.setPen(CONST.COLORS["white"]) + def wheelEvent(self, event: QWheelEvent): if event.angleDelta().y() > 0: factor = 1.25 @@ -597,6 +631,12 @@ class QLiberationMap(QGraphicsView): return Y, X + def km_to_pixel(self, km): + p1 = Point(0, 0) + p2 = Point(0, 1000*km) + p1a = Point(*self._transform_point(p1)) + p2a = Point(*self._transform_point(p2)) + return p1a.distance_to_point(p2a) def highlight_color(self, transparent: Optional[bool] = False) -> QColor: return QColor(255, 255, 0, 20 if transparent else 255) @@ -644,7 +684,6 @@ class QLiberationMap(QGraphicsView): def addBackground(self): scene = self.scene() - if not DisplayOptions.map_poly: bg = QPixmap("./resources/" + self.game.theater.overview_image) scene.addPixmap(bg) @@ -686,9 +725,7 @@ class QLiberationMap(QGraphicsView): # Uncomment to display plan projection test #self.projection_test(scene) - - zero = self._transform_point(Point(0,0)) - self.scene().addRect(QRectF(zero[0] + 1, zero[1] + 1, 50, 50), CONST.COLORS["red"], QBrush(CONST.COLORS["red"])) + self.draw_scale() def projection_test(self, scene): for i in range(100): @@ -722,8 +759,19 @@ class QLiberationMap(QGraphicsView): def sceneMouseMovedEvent(self, event: QGraphicsSceneMouseEvent): if self.state == QLiberationMapState.MOVING_UNIT: self.setCursor(Qt.PointingHandCursor) + pos = event.scenePos() p1 = self.movement_line.line().p1() - self.movement_line.setLine(QLineF(p1, event.scenePos())) + + distance = Point(p1.x(), p1.y()).distance_to_point(Point(pos.x(), pos.y())) + + self.movement_line.setLine(QLineF(p1, pos)) + + if distance / self.nm_to_pixel_ratio < MAX_SHIP_DISTANCE: + self.movement_line.setPen(CONST.COLORS["green"]) + else: + self.movement_line.setPen(CONST.COLORS["red"]) + + def sceneMousePressEvent(self, event: QGraphicsSceneMouseEvent): if self.state == QLiberationMapState.MOVING_UNIT: @@ -734,9 +782,17 @@ class QLiberationMap(QGraphicsView): # Set movement position for the cp pos = event.scenePos() point = Point(int(pos.x()), int(pos.y())) - proj = self._scene_to_dcs_coords(point) - self.selected_cp.control_point.target_position = proj # TODO : convert to DCS coords ! - print(proj) + proj = Point(*self._scene_to_dcs_coords(point)) + + # Check distance (max = 80 nm) + distance = meter_to_nm(proj.distance_to_point(self.selected_cp.control_point.position)) + + # Check if point is in sea + if self.game.theater.is_in_sea(proj) and distance < MAX_SHIP_DISTANCE: + self.selected_cp.control_point.target_position = proj + else: + self.selected_cp.control_point.target_position = None + GameUpdateSignal.get_instance().updateGame(self.game_model.game) else: return