def _gen_markers(self) -> None:
        """
        Generate markers on F10 map for each existing objective
        """
        if self.game.settings.generate_marks:
            mark_trigger = TriggerOnce(Event.NoEvent, "Marks generator")
            mark_trigger.add_condition(TimeAfter(1))
            v = 10
            for cp in self.game.theater.controlpoints:
                seen = set()
                for ground_object in cp.ground_objects:
                    if ground_object.obj_name in seen:
                        continue

                    seen.add(ground_object.obj_name)
                    for location in ground_object.mark_locations:
                        zone = self.mission.triggers.add_triggerzone(
                            location, radius=10, hidden=True, name="MARK")
                        if cp.captured:
                            name = ground_object.obj_name + " [ALLY]"
                        else:
                            name = ground_object.obj_name + " [ENEMY]"
                        mark_trigger.add_action(
                            MarkToAll(v, zone.id, String(name)))
                        v += 1
            self.mission.triggerrules.triggers.append(mark_trigger)
    def set_startup_time(self, delay: timedelta) -> None:
        # Uncontrolled causes the AI unit to spawn, but not begin startup.
        self.group.uncontrolled = True

        activation_trigger = TriggerOnce(Event.NoEvent,
                                         f"FlightStartTrigger{self.group.id}")
        activation_trigger.add_condition(
            TimeAfter(seconds=int(delay.total_seconds())))

        self.prevent_spawn_at_hostile_airbase(activation_trigger)
        self.group.add_trigger_action(StartCommand())
        activation_trigger.add_action(
            AITaskPush(self.group.id, len(self.group.tasks)))
        self.mission.triggerrules.triggers.append(activation_trigger)
    def set_activation_time(self, delay: timedelta) -> None:
        # Note: Late activation causes the waypoint TOTs to look *weird* in the
        # mission editor. Waypoint times will be relative to the group
        # activation time rather than in absolute local time. A flight delayed
        # until 09:10 when the overall mission start time is 09:00, with a join
        # time of 09:30 will show the join time as 00:30, not 09:30.
        self.group.late_activation = True

        activation_trigger = TriggerOnce(
            Event.NoEvent, f"FlightLateActivationTrigger{self.group.id}")
        activation_trigger.add_condition(
            TimeAfter(seconds=int(delay.total_seconds())))

        self.prevent_spawn_at_hostile_airbase(activation_trigger)
        activation_trigger.add_action(ActivateGroup(self.group.id))
        self.mission.triggerrules.triggers.append(activation_trigger)
Exemple #4
0
    def add_morale_trigger(self, dcs_group: VehicleGroup,
                           forward_heading: Heading) -> None:
        """
        This add a trigger to manage units fleeing whenever their group is hit hard, or being engaged by CAS
        """

        if len(dcs_group.units) == 1:
            return

        # Units should hold position on last waypoint
        dcs_group.points[len(dcs_group.points) - 1].tasks.append(Hold())

        # Force unit heading
        for unit in dcs_group.units:
            unit.heading = forward_heading.degrees
        dcs_group.manualHeading = True

        # We add a new retreat waypoint
        dcs_group.add_waypoint(
            self.find_retreat_point(dcs_group, forward_heading,
                                    (int)(RETREAT_DISTANCE / 8)),
            PointAction.OffRoad,
        )

        # Fallback task
        task = ControlledTask(GoToWaypoint(to_index=len(dcs_group.points)))
        task.enabled = False
        dcs_group.add_trigger_action(Hold())
        dcs_group.add_trigger_action(task)

        # Create trigger
        fallback = TriggerOnce(Event.NoEvent,
                               "Morale manager #" + str(dcs_group.id))

        # Usually more than 50% casualties = RETREAT
        fallback.add_condition(
            GroupLifeLess(dcs_group.id, random.randint(51, 76)))

        # Do retreat to the configured retreat waypoint
        fallback.add_action(AITaskPush(dcs_group.id, len(dcs_group.tasks)))

        self.mission.triggerrules.triggers.append(fallback)
    def setup_group_activation_trigger(self, flight, group):
        if flight.scheduled_in > 0 and flight.client_count == 0:

            if flight.start_type != "In Flight" and flight.from_cp.cptype not in [
                    ControlPointType.AIRCRAFT_CARRIER_GROUP,
                    ControlPointType.LHA_GROUP
            ]:
                group.late_activation = False
                group.uncontrolled = True

                activation_trigger = TriggerOnce(
                    Event.NoEvent, "FlightStartTrigger" + str(group.id))
                activation_trigger.add_condition(
                    TimeAfter(seconds=flight.scheduled_in * 60))
                if (flight.from_cp.cptype == ControlPointType.AIRBASE):
                    if flight.from_cp.captured:
                        activation_trigger.add_condition(
                            CoalitionHasAirdrome(
                                self.game.get_player_coalition_id(),
                                flight.from_cp.id))
                    else:
                        activation_trigger.add_condition(
                            CoalitionHasAirdrome(
                                self.game.get_enemy_coalition_id(),
                                flight.from_cp.id))

                if flight.flight_type == FlightType.INTERCEPTION:
                    self.setup_interceptor_triggers(group, flight,
                                                    activation_trigger)

                group.add_trigger_action(StartCommand())
                activation_trigger.add_action(
                    AITaskPush(group.id, len(group.tasks)))

                self.m.triggerrules.triggers.append(activation_trigger)
            else:
                group.late_activation = True
                activation_trigger = TriggerOnce(
                    Event.NoEvent,
                    "FlightLateActivationTrigger" + str(group.id))
                activation_trigger.add_condition(
                    TimeAfter(seconds=flight.scheduled_in * 60))

                if (flight.from_cp.cptype == ControlPointType.AIRBASE):
                    if flight.from_cp.captured:
                        activation_trigger.add_condition(
                            CoalitionHasAirdrome(
                                self.game.get_player_coalition_id(),
                                flight.from_cp.id))
                    else:
                        activation_trigger.add_condition(
                            CoalitionHasAirdrome(
                                self.game.get_enemy_coalition_id(),
                                flight.from_cp.id))

                if flight.flight_type == FlightType.INTERCEPTION:
                    self.setup_interceptor_triggers(group, flight,
                                                    activation_trigger)

                activation_trigger.add_action(ActivateGroup(group.id))
                self.m.triggerrules.triggers.append(activation_trigger)
Exemple #6
0
    def plan_action_for_groups(self, stance, ally_groups, enemy_groups, forward_heading, from_cp, to_cp):

        if not self.game.settings.perf_moving_units:
            return

        for dcs_group, group in ally_groups:
            if group.role == CombatGroupRole.ARTILLERY:
                # Fire on any ennemy in range
                if self.game.settings.perf_artillery:
                    target = self.get_artillery_target_in_range(dcs_group, group, enemy_groups)
                    if target is not None:

                        if stance != CombatStance.RETREAT:
                            hold_task = Hold()
                            hold_task.number = 1
                            dcs_group.add_trigger_action(hold_task)

                        # Artillery strike random start
                        artillery_trigger = TriggerOnce(Event.NoEvent, "ArtilleryFireTask #" + str(dcs_group.id))
                        artillery_trigger.add_condition(TimeAfter(seconds=random.randint(1, 45)* 60))

                        fire_task = FireAtPoint(target, len(group.units) * 10, 100)
                        if stance != CombatStance.RETREAT:
                            fire_task.number = 2
                        else:
                            fire_task.number = 1
                        dcs_group.add_trigger_action(fire_task)
                        artillery_trigger.add_action(AITaskPush(dcs_group.id, len(dcs_group.tasks)))
                        self.mission.triggerrules.triggers.append(artillery_trigger)

                        # Artillery will fall back when under attack
                        if stance != CombatStance.RETREAT:

                            # Hold position
                            dcs_group.points[0].tasks.append(Hold())
                            retreat = self.find_retreat_point(dcs_group, forward_heading, (int)(RETREAT_DISTANCE/3))
                            dcs_group.add_waypoint(dcs_group.position.point_from_heading(forward_heading, 1), PointAction.OffRoad)
                            dcs_group.points[1].tasks.append(Hold())
                            dcs_group.add_waypoint(retreat, PointAction.OffRoad)

                            artillery_fallback = TriggerOnce(Event.NoEvent, "ArtilleryRetreat #" + str(dcs_group.id))
                            for i, u in enumerate(dcs_group.units):
                                artillery_fallback.add_condition(UnitDamaged(u.id))
                                if i < len(dcs_group.units) - 1:
                                    artillery_fallback.add_condition(Or())

                            hold_2 = Hold()
                            hold_2.number = 3
                            dcs_group.add_trigger_action(hold_2)

                            retreat_task = GoToWaypoint(toIndex=3)
                            retreat_task.number = 4
                            dcs_group.add_trigger_action(retreat_task)

                            artillery_fallback.add_action(AITaskPush(dcs_group.id, len(dcs_group.tasks)))
                            self.mission.triggerrules.triggers.append(artillery_fallback)

                            for u in dcs_group.units:
                                u.initial = True
                                u.heading = forward_heading + random.randint(-5,5)

            elif group.role in [CombatGroupRole.TANK, CombatGroupRole.IFV]:
                if stance == CombatStance.AGGRESIVE:
                    # Attack nearest enemy if any
                    # Then move forward OR Attack enemy base if it is not too far away
                    target = self.find_nearest_enemy_group(dcs_group, enemy_groups)
                    if target is not None:
                        rand_offset = Point(random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK), random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK))
                        dcs_group.add_waypoint(target.points[0].position + rand_offset, PointAction.OffRoad)
                        dcs_group.points[1].tasks.append(AttackGroup(target.id))

                    if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
                        attack_point = to_cp.position.random_point_within(500, 0)
                    else:
                        attack_point = self.find_offensive_point(dcs_group, forward_heading, AGGRESIVE_MOVE_DISTANCE)
                    dcs_group.add_waypoint(attack_point, PointAction.OnRoad)
                elif stance == CombatStance.BREAKTHROUGH:
                    # In breakthrough mode, the units will move forward
                    # If the enemy base is close enough, the units will attack the base
                    if to_cp.position.distance_to_point(
                            dcs_group.points[0].position) <= BREAKTHROUGH_OFFENSIVE_DISTANCE:
                        attack_point = to_cp.position.random_point_within(500, 0)
                    else:
                        attack_point = self.find_offensive_point(dcs_group, forward_heading, BREAKTHROUGH_OFFENSIVE_DISTANCE)
                    dcs_group.add_waypoint(attack_point, PointAction.OnRoad)
                elif stance == CombatStance.ELIMINATION:
                    # In elimination mode, the units focus on destroying as much enemy groups as possible
                    targets = self.find_n_nearest_enemy_groups(dcs_group, enemy_groups, 3)
                    i = 1
                    for target in targets:
                        rand_offset = Point(random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK), random.randint(-RANDOM_OFFSET_ATTACK, RANDOM_OFFSET_ATTACK))
                        dcs_group.add_waypoint(target.points[0].position+rand_offset, PointAction.OffRoad)
                        dcs_group.points[i].tasks.append(AttackGroup(target.id))
                        i = i + 1
                    if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
                        attack_point = to_cp.position.random_point_within(500, 0)
                        dcs_group.add_waypoint(attack_point)

                if stance != CombatStance.RETREAT:
                    self.add_morale_trigger(dcs_group, forward_heading)

            elif group.role in [CombatGroupRole.APC, CombatGroupRole.ATGM]:

                if stance in [CombatStance.AGGRESIVE, CombatStance.BREAKTHROUGH, CombatStance.ELIMINATION]:
                    # APC & ATGM will never move too much forward, but will follow along any offensive
                    if to_cp.position.distance_to_point(dcs_group.points[0].position) <= AGGRESIVE_MOVE_DISTANCE:
                        attack_point = to_cp.position.random_point_within(500, 0)
                    else:
                        attack_point = self.find_offensive_point(dcs_group, forward_heading, AGGRESIVE_MOVE_DISTANCE)
                    dcs_group.add_waypoint(attack_point, PointAction.OnRoad)

                if stance != CombatStance.RETREAT:
                    self.add_morale_trigger(dcs_group, forward_heading)

            if stance == CombatStance.RETREAT:
                # In retreat mode, the units will fall back
                # If the ally base is close enough, the units will even regroup there
                if from_cp.position.distance_to_point(dcs_group.points[0].position) <= RETREAT_DISTANCE:
                    retreat_point = from_cp.position.random_point_within(500, 250)
                else:
                    retreat_point = self.find_retreat_point(dcs_group, forward_heading)
                reposition_point = retreat_point.point_from_heading(forward_heading, 10)  # Another point to make the unit face the enemy
                dcs_group.add_waypoint(retreat_point, PointAction.OnRoad)
                dcs_group.add_waypoint(reposition_point, PointAction.OffRoad)
Exemple #7
0
    def _plan_artillery_action(
        self,
        stance: CombatStance,
        gen_group: CombatGroup,
        dcs_group: VehicleGroup,
        forward_heading: int,
        target: Point,
    ) -> bool:
        """
        Handles adding the DCS tasks for artillery groups for all combat stances.
        Returns True if tasking was added, returns False if the stance was not a combat stance.
        """
        self._set_reform_waypoint(dcs_group, forward_heading)
        if stance != CombatStance.RETREAT:
            hold_task = Hold()
            hold_task.number = 1
            dcs_group.add_trigger_action(hold_task)

        # Artillery strike random start
        artillery_trigger = TriggerOnce(
            Event.NoEvent, "ArtilleryFireTask #" + str(dcs_group.id)
        )
        artillery_trigger.add_condition(TimeAfter(seconds=random.randint(1, 45) * 60))
        # TODO: Update to fire at group instead of point
        fire_task = FireAtPoint(target, gen_group.size * 10, 100)
        fire_task.number = 2 if stance != CombatStance.RETREAT else 1
        dcs_group.add_trigger_action(fire_task)
        artillery_trigger.add_action(AITaskPush(dcs_group.id, len(dcs_group.tasks)))
        self.mission.triggerrules.triggers.append(artillery_trigger)

        # Artillery will fall back when under attack
        if stance != CombatStance.RETREAT:

            # Hold position
            dcs_group.points[1].tasks.append(Hold())
            retreat = self.find_retreat_point(
                dcs_group, forward_heading, (int)(RETREAT_DISTANCE / 3)
            )
            dcs_group.add_waypoint(
                dcs_group.position.point_from_heading(forward_heading, 1),
                PointAction.OffRoad,
            )
            dcs_group.points[2].tasks.append(Hold())
            dcs_group.add_waypoint(retreat, PointAction.OffRoad)

            artillery_fallback = TriggerOnce(
                Event.NoEvent, "ArtilleryRetreat #" + str(dcs_group.id)
            )
            for i, u in enumerate(dcs_group.units):
                artillery_fallback.add_condition(UnitDamaged(u.id))
                if i < len(dcs_group.units) - 1:
                    artillery_fallback.add_condition(Or())

            hold_2 = Hold()
            hold_2.number = 3
            dcs_group.add_trigger_action(hold_2)

            retreat_task = GoToWaypoint(to_index=3)
            retreat_task.number = 4
            dcs_group.add_trigger_action(retreat_task)

            artillery_fallback.add_action(
                AITaskPush(dcs_group.id, len(dcs_group.tasks))
            )
            self.mission.triggerrules.triggers.append(artillery_fallback)

            for u in dcs_group.units:
                u.heading = forward_heading + random.randint(-5, 5)
            return True
        return False