From d6e4a500649fea3adbaa11f4a3966015dcde7453 Mon Sep 17 00:00:00 2001 From: Khopa Date: Wed, 9 Dec 2020 21:01:32 +0100 Subject: [PATCH 1/4] QOL : On launch, auto load the latest saved game. --- game/persistency.py | 20 +++----------------- qt_ui/liberation_install.py | 25 ++++++++++++++++++++++++- qt_ui/windows/QLiberationWindow.py | 16 +++++++++++++++- 3 files changed, 42 insertions(+), 19 deletions(-) diff --git a/game/persistency.py b/game/persistency.py index 617274ea..38bd5550 100644 --- a/game/persistency.py +++ b/game/persistency.py @@ -7,45 +7,31 @@ from typing import Optional _dcs_saved_game_folder: Optional[str] = None _file_abs_path = None + def setup(user_folder: str): global _dcs_saved_game_folder _dcs_saved_game_folder = user_folder _file_abs_path = os.path.join(base_path(), "default.liberation") + def base_path() -> str: global _dcs_saved_game_folder assert _dcs_saved_game_folder return _dcs_saved_game_folder -def _save_file() -> str: - return os.path.join(base_path(), "default.liberation") def _temporary_save_file() -> str: return os.path.join(base_path(), "tmpsave.liberation") + def _autosave_path() -> str: return os.path.join(base_path(), "autosave.liberation") -def _save_file_exists() -> bool: - return os.path.exists(_save_file()) def mission_path_for(name: str) -> str: return os.path.join(base_path(), "Missions", "{}".format(name)) -def restore_game(): - if not _save_file_exists(): - return None - - with open(_save_file(), "rb") as f: - try: - save = pickle.load(f) - return save - except Exception: - logging.exception("Invalid Save game") - return None - - def load_game(path): with open(path, "rb") as f: try: diff --git a/qt_ui/liberation_install.py b/qt_ui/liberation_install.py index 0440043d..1191f219 100644 --- a/qt_ui/liberation_install.py +++ b/qt_ui/liberation_install.py @@ -8,6 +8,7 @@ from game import persistency global __dcs_saved_game_directory global __dcs_installation_directory +global __last_save_file PREFERENCES_FILE_PATH = "liberation_preferences.json" @@ -15,6 +16,7 @@ PREFERENCES_FILE_PATH = "liberation_preferences.json" def init(): global __dcs_saved_game_directory global __dcs_installation_directory + global __last_save_file if os.path.isfile(PREFERENCES_FILE_PATH): try: @@ -22,10 +24,15 @@ def init(): pref_data = json.loads(prefs.read()) __dcs_saved_game_directory = pref_data["saved_game_dir"] __dcs_installation_directory = pref_data["dcs_install_dir"] + if "last_save_file" in pref_data: + __last_save_file = pref_data["last_save_file"] + else: + __last_save_file = "" is_first_start = False except: __dcs_saved_game_directory = "" __dcs_installation_directory = "" + __last_save_file = "" is_first_start = True else: try: @@ -52,11 +59,18 @@ def setup(saved_game_dir, install_dir): persistency.setup(__dcs_saved_game_directory) +def setup_last_save_file(last_save_file): + global __last_save_file + __last_save_file = last_save_file + + def save_config(): global __dcs_saved_game_directory global __dcs_installation_directory + global __last_save_file pref_data = {"saved_game_dir": __dcs_saved_game_directory, - "dcs_install_dir": __dcs_installation_directory} + "dcs_install_dir": __dcs_installation_directory, + "last_save_file": __last_save_file} with(open(PREFERENCES_FILE_PATH, "w")) as prefs: prefs.write(json.dumps(pref_data)) @@ -71,6 +85,15 @@ def get_saved_game_dir(): return __dcs_saved_game_directory +def get_last_save_file(): + global __last_save_file + print(__last_save_file) + if os.path.exists(__last_save_file): + return __last_save_file + else: + return None + + def replace_mission_scripting_file(): install_dir = get_dcs_install_directory() mission_scripting_path = os.path.join(install_dir, "Scripts", "MissionScripting.lua") diff --git a/qt_ui/windows/QLiberationWindow.py b/qt_ui/windows/QLiberationWindow.py index 99fcf7c2..f3c00875 100644 --- a/qt_ui/windows/QLiberationWindow.py +++ b/qt_ui/windows/QLiberationWindow.py @@ -19,6 +19,7 @@ from PySide2.QtWidgets import ( import qt_ui.uiconstants as CONST from game import Game, VERSION, persistency from game.debriefing import Debriefing +from qt_ui import liberation_install from qt_ui.dialogs import Dialog from qt_ui.displayoptions import DisplayGroup, DisplayOptions, DisplayRule from qt_ui.models import GameModel @@ -62,7 +63,16 @@ class QLiberationWindow(QMainWindow): self.setWindowState(Qt.WindowMaximized) if self.game is None: - self.onGameGenerated(persistency.restore_game()) + last_save_file = liberation_install.get_last_save_file() + if last_save_file: + try: + logging.info("Loading last saved game : {0}".format(str(last_save_file))) + game = persistency.load_game(last_save_file) + self.onGameGenerated(game) + except: + logging.info("Error loading latest save game") + else: + logging.info("No existing save game") else: self.onGameGenerated(self.game) @@ -227,6 +237,8 @@ class QLiberationWindow(QMainWindow): if self.game.savepath: persistency.save_game(self.game) GameUpdateSignal.get_instance().updateGame(self.game) + liberation_install.setup_last_save_file(self.game.savepath) + liberation_install.save_config() else: self.saveGameAs() @@ -235,6 +247,8 @@ class QLiberationWindow(QMainWindow): if file is not None: self.game.savepath = file[0] persistency.save_game(self.game) + liberation_install.setup_last_save_file(self.game.savepath) + liberation_install.save_config() def onGameGenerated(self, game: Game): logging.info("On Game generated") From c74e18e449fc7ead85f8195b77bedf0cd90dda31 Mon Sep 17 00:00:00 2001 From: Khopa Date: Wed, 9 Dec 2020 22:55:11 +0100 Subject: [PATCH 2/4] Target positions for ship movement are now properly projected on DCS game X,Y plane --- qt_ui/widgets/map/QLiberationMap.py | 77 +++++++++++++++++++++++------ qt_ui/windows/QLiberationWindow.py | 2 +- 2 files changed, 62 insertions(+), 17 deletions(-) diff --git a/qt_ui/widgets/map/QLiberationMap.py b/qt_ui/widgets/map/QLiberationMap.py index f4e5cddf..ae10af14 100644 --- a/qt_ui/widgets/map/QLiberationMap.py +++ b/qt_ui/widgets/map/QLiberationMap.py @@ -6,7 +6,7 @@ import math from typing import Iterable, Iterator, List, Optional, Tuple from PySide2 import QtWidgets, QtCore -from PySide2.QtCore import QPointF, Qt, QLineF +from PySide2.QtCore import QPointF, Qt, QLineF, QRectF from PySide2.QtGui import ( QBrush, QColor, @@ -27,11 +27,9 @@ from dcs.mapping import point_from_heading import qt_ui.uiconstants as CONST from game import Game, db -from game.theater import ControlPoint, Enum, NavalControlPoint +from game.theater import ControlPoint, Enum from game.theater.conflicttheater import FrontLine from game.theater.theatergroundobject import ( - EwrGroundObject, - MissileSiteGroundObject, TheaterGroundObject, ) from game.utils import meter_to_feet @@ -323,7 +321,8 @@ class QLiberationMap(QGraphicsView): if cp.target_position is not None: tpos = cp.target_position - scene.addLine(QLineF(QPointF(pos[0], pos[1]), QPointF(tpos[0], tpos[1])), + proj = self._transform_point(Point(tpos[0], tpos[1])) + scene.addLine(QLineF(QPointF(pos[0], pos[1]), QPointF(proj[0], proj[1])), QPen(CONST.COLORS["green"], width=10, s=Qt.DashDotLine)) @@ -535,7 +534,6 @@ class QLiberationMap(QGraphicsView): ) def wheelEvent(self, event: QWheelEvent): - if event.angleDelta().y() > 0: factor = 1.25 self._zoom += 1 @@ -553,9 +551,7 @@ class QLiberationMap(QGraphicsView): else: self._zoom = -4 - #print(self.factorized, factor, self._zoom) - - def _transform_point(self, p: Point, treshold=30) -> Tuple[int, int]: + def _transform_point(self, p: Point) -> Tuple[int, int]: point_a = list(self.game.theater.reference_points.keys())[0] point_a_img = self.game.theater.reference_points[point_a] @@ -578,14 +574,29 @@ class QLiberationMap(QGraphicsView): X = point_b_img[1] + X_offset * X_scale Y = point_a_img[0] - Y_offset * Y_scale - #X += 5 - #Y += 5 + return X, Y - return X > treshold and X or treshold, Y > treshold and Y or treshold + def _scene_to_dcs_coords(self, p: Point): + pa = list(self.game.theater.reference_points.keys())[0] + pa2 = self.game.theater.reference_points[pa] + pb = list(self.game.theater.reference_points.keys())[1] + pb2 = self.game.theater.reference_points[pb] + + dy2 = pa2[0] - pb2[0] + dy = pa[1] - pb[1] + + dx2 = pa2[1] - pb2[1] + dx = pb[0] - pa[0] + + ys = float(dy2) / float(dy) + xs = float(dx2) / float(dx) + + X = ((float(p.x - pb2[1])) / float(xs)) + pa[1] + Y = ((float(pa2[0] - p.y)) / float(ys)) + pa[0] + + return Y, X - def _scene_to_dcs_coords(self, x, y): - pass def highlight_color(self, transparent: Optional[bool] = False) -> QColor: return QColor(255, 255, 0, 20 if transparent else 255) @@ -633,6 +644,7 @@ 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) @@ -672,6 +684,34 @@ class QLiberationMap(QGraphicsView): poly = QPolygonF([QPointF(*self._transform_point(Point(point[0], point[1]))) for point in exclusion_zone]) scene.addPolygon(poly, CONST.COLORS["grey"], CONST.COLORS["dark_dark_grey"]) + # 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"])) + + def projection_test(self, scene): + for i in range(100): + for j in range(100): + x = i * 100 + y = j * 100 + self.scene().addRect(QRectF(x, y, 4, 4), CONST.COLORS["green"]) + proj = self._scene_to_dcs_coords(Point(x, y)) + unproj = self._transform_point(Point(proj[0], proj[1])) + text = scene.addText(str(i) + ", " + str(j) + "\n" + str(unproj[0]) + ", " + str(unproj[1]), + font=QFont("Trebuchet MS", 6, weight=5, italic=False)) + text.setPos(unproj[0] + 2, unproj[1] + 2) + text.setDefaultTextColor(Qt.red) + text2 = scene.addText(str(i) + ", " + str(j) + "\n" + str(x) + ", " + str(y), + font=QFont("Trebuchet MS", 6, weight=5, italic=False)) + text2.setPos(x + 2, y + 10) + text2.setDefaultTextColor(Qt.green) + self.scene().addRect(QRectF(unproj[0] + 1, unproj[1] + 1, 4, 4), CONST.COLORS["red"]) + if i % 2 == 0: + self.scene().addLine(QLineF(x + 1, y + 1, unproj[0], unproj[1]), CONST.COLORS["yellow"]) + else: + self.scene().addLine(QLineF(x + 1, y + 1, unproj[0], unproj[1]), CONST.COLORS["purple"]) + def setSelectedUnit(self, selected_cp: QMapControlPoint): self.state = QLiberationMapState.MOVING_UNIT self.selected_cp = selected_cp @@ -694,10 +734,15 @@ class QLiberationMap(QGraphicsView): # Set movement position for the cp pos = event.scenePos() point = Point(int(pos.x()), int(pos.y())) - self.selected_cp.control_point.target_position = point.x, point.y # TODO : convert to DCS coords ! + proj = self._scene_to_dcs_coords(point) + self.selected_cp.control_point.target_position = proj # TODO : convert to DCS coords ! + print(proj) GameUpdateSignal.get_instance().updateGame(self.game_model.game) else: return self.state = QLiberationMapState.NORMAL - self.scene().removeItem(self.movement_line) + try: + self.scene().removeItem(self.movement_line) + except: + pass self.selected_cp = None \ No newline at end of file diff --git a/qt_ui/windows/QLiberationWindow.py b/qt_ui/windows/QLiberationWindow.py index f3c00875..69101818 100644 --- a/qt_ui/windows/QLiberationWindow.py +++ b/qt_ui/windows/QLiberationWindow.py @@ -66,7 +66,7 @@ class QLiberationWindow(QMainWindow): last_save_file = liberation_install.get_last_save_file() if last_save_file: try: - logging.info("Loading last saved game : {0}".format(str(last_save_file))) + logging.info("Loading last saved game : " + str(last_save_file)) game = persistency.load_game(last_save_file) self.onGameGenerated(game) except: From 1258f3e17ce11c67e40a10c6d938491ea483d6fe Mon Sep 17 00:00:00 2001 From: Khopa Date: Thu, 10 Dec 2020 00:13:34 +0100 Subject: [PATCH 3/4] 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 From 5e2b259af12d54b27b148159d2f699181bc07b0d Mon Sep 17 00:00:00 2001 From: Khopa Date: Thu, 10 Dec 2020 00:20:22 +0100 Subject: [PATCH 4/4] Updated changelog --- changelog.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/changelog.md b/changelog.md index 680bdef0..6ff1821d 100644 --- a/changelog.md +++ b/changelog.md @@ -1,11 +1,17 @@ # 2.3.0 # Features/Improvements +* **[Campaign Map]** Overhauled the campaign model +* **[Campaign Map]** Possible to add FOB as control points +* **[Campaign AI]** Overhauled AI recruiting behaviour +* **[Mission Planner]** Possible to move carrier and tarawa on the campaign map +* **[Mission Generator]** Infantry squads on frontline can have manpads * **[Flight Planner]** Added fighter sweep missions. * **[Flight Planner]** Added BAI missions. * **[Flight Planner]** Added anti-ship missions. * **[Flight Planner]** Differentiated BARCAP and TARCAP. TARCAP is now for hostile areas and will arrive before the package. * **[Culling]** Added possibility to include/exclude carriers from culling zones +* **[QOL]** On liberation startup, your latest save game is loaded automatically ## Fixes : * **[Map]** Missiles sites now have a proper icon and will not re-use the SAM sites icon