diff --git a/game/event/event.py b/game/event/event.py index 21130a9f..8a01c736 100644 --- a/game/event/event.py +++ b/game/event/event.py @@ -9,6 +9,7 @@ from dcs.unittype import UnitType from game import * from theater import * from gen.environmentgen import EnvironmentSettings +from gen.conflictgen import Conflict from game.db import assigned_units_from, unitdict_from from userdata.debriefing import Debriefing diff --git a/game/event/intercept.py b/game/event/intercept.py index c9a62ae3..1a99303a 100644 --- a/game/event/intercept.py +++ b/game/event/intercept.py @@ -10,6 +10,11 @@ class InterceptEvent(Event): transport_unit = None # type: FlyingType + def __init__(self, game, from_cp: ControlPoint, target_cp: ControlPoint, location: Point, attacker_name: str, + defender_name: str): + super().__init__(game, from_cp, target_cp, location, attacker_name, defender_name) + self.location = Conflict.intercept_position(self.from_cp, self.to_cp) + def __str__(self): return "Air Intercept" @@ -74,7 +79,8 @@ class InterceptEvent(Event): from_cp=self.departure_cp, to_cp=self.to_cp) - op.setup(escort=assigned_units_from(escort), + op.setup(location=self.location, + escort=assigned_units_from(escort), transport={self.transport_unit: 1}, airdefense={airdefense_unit: self.AIRDEFENSE_COUNT}, interceptors=flights[CAP]) diff --git a/game/event/navalintercept.py b/game/event/navalintercept.py index c9d5ff7e..269c22f5 100644 --- a/game/event/navalintercept.py +++ b/game/event/navalintercept.py @@ -9,6 +9,11 @@ class NavalInterceptEvent(Event): targets = None # type: db.ShipDict + def __init__(self, game, from_cp: ControlPoint, target_cp: ControlPoint, location: Point, attacker_name: str, + defender_name: str): + super().__init__(game, from_cp, target_cp, location, attacker_name, defender_name) + self.location = Conflict.naval_intercept_position(from_cp, target_cp, game.theater) + def _targets_count(self) -> int: from gen.conflictgen import IMPORTANCE_LOW factor = (self.to_cp.importance - IMPORTANCE_LOW + 0.1) * 20 @@ -83,7 +88,8 @@ class NavalInterceptEvent(Event): to_cp=self.to_cp ) - op.setup(strikegroup=flights[CAS], + op.setup(location=self.location, + strikegroup=flights[CAS], interceptors={}, targets=self.targets) diff --git a/game/game.py b/game/game.py index b99116be..d177271b 100644 --- a/game/game.py +++ b/game/game.py @@ -51,7 +51,7 @@ Events: EVENT_PROBABILITIES = { # events always present; only for the player FrontlineAttackEvent: [100, 0], - FrontlinePatrolEvent: [100, 0], + #FrontlinePatrolEvent: [100, 0], StrikeEvent: [100, 0], # events randomly present; only for the player @@ -169,10 +169,10 @@ class Game: if not Conflict.has_frontline_between(player_cp, enemy_cp): continue - if player_probability == 100 or self._roll(player_probability, player_cp.base.strength): + if player_probability == 100 or player_probability > 0 and self._roll(player_probability, player_cp.base.strength): self._generate_player_event(event_class, player_cp, enemy_cp) - if enemy_probability == 100 or self._roll(enemy_probability, enemy_cp.base.strength): + if enemy_probability == 100 or enemy_probability > 0 and self._roll(enemy_probability, enemy_cp.base.strength): self._generate_enemy_event(event_class, player_cp, enemy_cp) def commision_unit_types(self, cp: ControlPoint, for_task: Task) -> typing.Collection[UnitType]: diff --git a/game/operation/intercept.py b/game/operation/intercept.py index 14d4e344..9414b0a2 100644 --- a/game/operation/intercept.py +++ b/game/operation/intercept.py @@ -4,6 +4,7 @@ from .operation import * class InterceptOperation(Operation): + location = None # type: Point escort = None # type: db.AssignedUnitsDict transport = None # type: db.PlaneDict interceptors = None # type: db.AssignedUnitsDict @@ -12,10 +13,12 @@ class InterceptOperation(Operation): trigger_radius = TRIGGER_RADIUS_LARGE def setup(self, + location: Point, escort: db.AssignedUnitsDict, transport: db.PlaneDict, airdefense: db.AirDefenseDict, interceptors: db.AssignedUnitsDict): + self.location = location self.escort = escort self.transport = transport self.airdefense = airdefense @@ -30,6 +33,7 @@ class InterceptOperation(Operation): conflict = Conflict.intercept_conflict( attacker=self.current_mission.country(self.attacker_name), defender=self.current_mission.country(self.defender_name), + position=self.location, from_cp=self.from_cp, to_cp=self.to_cp, theater=self.game.theater diff --git a/game/operation/navalintercept.py b/game/operation/navalintercept.py index b4ab9157..5f7d5ce5 100644 --- a/game/operation/navalintercept.py +++ b/game/operation/navalintercept.py @@ -4,15 +4,18 @@ from .operation import * class NavalInterceptionOperation(Operation): + location = None # type: Point strikegroup = None # type: db.AssignedUnitsDict interceptors = None # type: db.AssignedUnitsDict targets = None # type: db.ShipDict trigger_radius = TRIGGER_RADIUS_LARGE def setup(self, + location: Point, strikegroup: db.AssignedUnitsDict, interceptors: db.AssignedUnitsDict, targets: db.ShipDict): + self.location = location self.strikegroup = strikegroup self.interceptors = interceptors self.targets = targets @@ -25,6 +28,7 @@ class NavalInterceptionOperation(Operation): conflict = Conflict.naval_intercept_conflict( attacker=self.current_mission.country(self.attacker_name), defender=self.current_mission.country(self.defender_name), + position=self.location, from_cp=self.from_cp, to_cp=self.to_cp, theater=self.game.theater diff --git a/gen/conflictgen.py b/gen/conflictgen.py index f1f4f70e..f4b03bf8 100644 --- a/gen/conflictgen.py +++ b/gen/conflictgen.py @@ -277,13 +277,14 @@ class Conflict: ) @classmethod - def intercept_conflict(cls, attacker: Country, defender: Country, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater): + def intercept_position(cls, from_cp: ControlPoint, to_cp:ControlPoint) -> Point: raw_distance = from_cp.position.distance_to_point(to_cp.position) * 1.5 distance = max(min(raw_distance, INTERCEPT_MAX_DISTANCE), INTERCEPT_MIN_DISTANCE) - heading = _heading_sum(from_cp.position.heading_between_point(to_cp.position), random.choice([-1, 1]) * random.randint(60, 100)) - position = from_cp.position.point_from_heading(heading, distance) + return from_cp.position.point_from_heading(heading, distance) + @classmethod + def intercept_conflict(cls, attacker: Country, defender: Country, position: Point, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater): return cls( position=position.point_from_heading(position.heading_between_point(to_cp.position), INTERCEPT_CONFLICT_DISTANCE), theater=theater, @@ -385,7 +386,7 @@ class Conflict: ) @classmethod - def naval_intercept_conflict(cls, attacker: Country, defender: Country, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater): + def naval_intercept_position(cls, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater): radial = random.choice(to_cp.sea_radials) initial_distance = min(int(from_cp.position.distance_to_point(to_cp.position) * NAVAL_INTERCEPT_DISTANCE_FACTOR), NAVAL_INTERCEPT_DISTANCE_MAX) @@ -395,7 +396,10 @@ class Conflict: if not theater.is_on_land(position): break + return position + @classmethod + def naval_intercept_conflict(cls, attacker: Country, defender: Country, position: Point, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater): attacker_heading = from_cp.position.heading_between_point(to_cp.position) return cls( position=position, diff --git a/theater/conflicttheater.py b/theater/conflicttheater.py index d44caf4e..82e82794 100644 --- a/theater/conflicttheater.py +++ b/theater/conflicttheater.py @@ -18,8 +18,6 @@ IMPORTANCE_LOW = 1 IMPORTANCE_MEDIUM = 1.2 IMPORTANCE_HIGH = 1.4 -GLOBAL_CP_CONFLICT_DISTANCE_MIN = 340000 - """ ALL_RADIALS = [0, 45, 90, 135, 180, 225, 270, 315, ] COAST_NS_E = [45, 90, 135, ] diff --git a/ui/overviewcanvas.py b/ui/overviewcanvas.py index 66248f3b..acf98b1b 100644 --- a/ui/overviewcanvas.py +++ b/ui/overviewcanvas.py @@ -10,7 +10,10 @@ from ui.styles import STYLES from ui.window import * -EVENT_DEPARTURE_MAX_DISTANCE = 250000 +EVENT_DEPARTURE_MAX_DISTANCE = 340000 + +EVENT_COLOR_ATTACK = (100, 100, 255) +EVENT_COLOR_DEFENSE = (255, 100, 100) class OverviewCanvas: @@ -30,6 +33,7 @@ class OverviewCanvas: WIDTH = 1066 HEIGHT = 600 + MAP_PADDING = 0 started = None ground_assets_icons = None # type: typing.Dict[str, pygame.Surface] @@ -170,7 +174,8 @@ class OverviewCanvas: pygame.draw.rect(self.map, self.WHITE, (0, 0, self.map.get_width(), self.map.get_height()), 5) # Create surfaces for drawing - self.surface = pygame.Surface((self.map.get_width(), self.map.get_height())) + self.surface = pygame.Surface((self.map.get_width() + self.MAP_PADDING * 2, + self.map.get_height() + self.MAP_PADDING * 2)) self.surface.set_alpha(None) self.overlay = pygame.Surface((self.WIDTH, self.HEIGHT), pygame.SRCALPHA) @@ -190,10 +195,10 @@ class OverviewCanvas: self.redraw_required = True i = 0 while not self.exited: - self.clock.tick(60) + self.clock.tick(30) self.draw() i += 1 - if i == 300: + if i == 600: self.frontline_vector_cache = {} i = 0 print("Stopped SDL app") @@ -248,6 +253,7 @@ class OverviewCanvas: if self.redraw_required: # Fill self.screen.fill(self.BACKGROUND) + self.surface.fill(self.BACKGROUND) self.overlay.fill(pygame.Color(0, 0, 0, 0)) # Surface @@ -267,7 +273,7 @@ class OverviewCanvas: self.redraw_required = False def draw_map(self, surface: pygame.Surface, overlay: pygame.Surface, mouse_pos: (int, int), mouse_down: [bool, bool]): - self.surface.blit(self.map, (0, 0)) + self.surface.blit(self.map, (self.MAP_PADDING, self.MAP_PADDING)) # Display zoom level on overlay zoom_lvl = self.font.render(" x " + str(self.zoom) + " ", self.ANTIALIASING, self.WHITE, self.DARK_BLUE) @@ -436,24 +442,47 @@ class OverviewCanvas: surface.blit(lb, (pos[0] + 18, pos[1])) def draw_events(self, surface: pygame.Surface, mouse_pos, mouse_down): - occupied_rects = [pygame.Rect(*self._transform_point(x.position), 32, 32) for x in self.game.theater.controlpoints] + occupied_rects = [] + for cp in self.game.theater.controlpoints: + point = self._transform_point(cp.position) + occupied_rects.append(pygame.Rect(point[0] - 16, point[1] - 16, 32, 48)) def _location_to_rect(location: Point) -> pygame.Rect: nonlocal occupied_rects point = self._transform_point(location) - rect = pygame.Rect(*point, 32, 32) + rect = pygame.Rect(point[0] - 16, point[1] - 16, 32, 32) + i = 0 - for occupied_rect in occupied_rects: - if rect.colliderect(occupied_rect): - i += 1 - if i % 2: - rect.y = occupied_rect.y + occupied_rect.height + 3 - else: - rect.x = occupied_rect.x + occupied_rect.width + 3 + while True: + result = True + for occupied_rect in occupied_rects: + if rect.colliderect(occupied_rect): + i += 1 + + if i % 2: + rect.y += occupied_rect.height + else: + rect.x += occupied_rect.width + + result = False + break + if result: + break occupied_rects.append(rect) return rect + def _events_priority_key(event: Event) -> int: + priority_list = [InfantryTransportEvent, StrikeEvent, BaseAttackEvent] + if type(event) not in priority_list: + return 0 + else: + return priority_list.index(type(event)) + 1 + + events = self.game.events + events.sort(key=_events_priority_key, reverse=True) + print(events) + label_to_draw = None for event in self.game.events: location = event.location @@ -461,7 +490,7 @@ class OverviewCanvas: location = self._frontline_center(event.from_cp, event.to_cp) rect = _location_to_rect(location) - pygame.draw.rect(surface, self.RED, rect) + pygame.draw.rect(surface, EVENT_COLOR_ATTACK if event.is_player_attacking else EVENT_COLOR_DEFENSE, rect) self.surface.blit(self.event_icons[event.__class__], rect.topleft) if rect.collidepoint(*mouse_pos) or self.selected_event_info == (event, rect.center): @@ -511,6 +540,9 @@ class OverviewCanvas: X = point_b_img[1] + X_offset * X_scale Y = point_a_img[0] - Y_offset * Y_scale + X += self.MAP_PADDING + Y += self.MAP_PADDING + return X > treshold and X or treshold, Y > treshold and Y or treshold def _frontline_vector(self, from_cp: ControlPoint, to_cp: ControlPoint):