This commit is contained in:
Khopa 2020-08-03 19:43:12 +02:00
parent ccf2cd3425
commit 6f4b7e0f1a
10 changed files with 122 additions and 33 deletions

View File

@ -25,12 +25,13 @@
* **[Mission Generator]** Fixed A-20G spawning with no payload
* **[Mission Generator]** Fixed Su-33 spawning too heavy to take off from carrier
* **[Mission Generator]** Base defense units were not controllable with Combined Arms
* **[Mission Script/Performance]** Mission lua script will not listen to weapons fired event anymore and register every fired weapons. This should improve performance especially in WW2 scenarios or when rocket artillery is firing.
* **[Campaign Generator]** Carrier name will now not appear for faction who do not have carriers
* **[Units/Factions]** Remove JF-17 from USA 2005 faction
* **[Units/Factions]** Removed Oliver Hazard Perry from cold war factions (too powerful sam system)
* **[Bug]** On the persian gulf full map campaign, the two carriers were sharing the same id, this was causing a lot of bugs
* **[Performance]** Tuned the culling setting so that you cannot run into situation where no AI flights are generated
* **[Performance]** Tuned the culling setting so that you cannot run into situation where no friendly or enemy AI flights are generated
* **[Other]** Application doesn't gracefully exit.
* **[Other]** Other minor fixes

View File

@ -0,0 +1,33 @@
from dcs.planes import *
from pydcs_extensions.a4ec.a4ec import A_4E_C
"""
This list contains the aircraft that do not use the guns as the last resort weapons, but as a main weapon
They'll RTB when they don't have gun ammo left
"""
GUNFIGHTERS = [
# Cold War
MiG_15bis,
MiG_19P,
MiG_21Bis,
F_86F_Sabre,
A_4E_C,
F_5E_3,
# Trainers
C_101CC,
L_39ZA,
# WW2
P_51D_30_NA,
P_51D,
P_47D_30,
SpitfireLFMkIXCW,
SpitfireLFMkIX,
Bf_109K_4,
FW_190D9,
FW_190A8,
I_16,
]

View File

@ -76,6 +76,22 @@ class Game:
self.__frontlineData = []
self.__destroyed_units = []
self.sanitize_sides()
def sanitize_sides(self):
"""
Make sure the opposing factions are using different countries
:return:
"""
if self.player_country == self.enemy_country:
if self.player_country == "USA":
self.enemy_country = "USAF Aggressors"
elif self.player_country == "Russia":
self.enemy_country = "USSR"
else:
self.enemy_country = "Russia"
@property
def player_faction(self):
return db.FACTIONS[self.player_name]

View File

@ -91,15 +91,6 @@ class Operation:
p_country = self.game.player_country
e_country = self.game.enemy_country
if self.game.player_country == self.game.enemy_country:
if self.game.player_country != "USAF Aggresors":
e_country = "USAF Aggresors"
else:
if self.game.player_country != "Russia":
e_country = "Russia"
else:
e_country = "USA"
self.current_mission.coalition["blue"].add_country(country_dict[db.country_id_from_name(p_country)]())
self.current_mission.coalition["red"].add_country(country_dict[db.country_id_from_name(e_country)]())

View File

@ -1,5 +1,5 @@
from dcs.action import AITaskPush, AITaskSet
from dcs.condition import TimeAfter, UnitDamaged, Or
from dcs.condition import TimeAfter, UnitDamaged, Or, GroupLifeLess
from dcs.task import *
from dcs.triggers import TriggerOnce, Event
@ -93,13 +93,11 @@ class GroundConflictGenerator:
self.gen_infantry_group_for_group(g, False, self.mission.country(self.game.enemy_country), self.conflict.heading - 90)
# Plan combat actions for groups
self.plan_action_for_groups(self.player_stance, player_groups, enemy_groups, self.conflict.heading + 90, self.conflict.from_cp, self.conflict.to_cp)
self.plan_action_for_groups(self.enemy_stance, enemy_groups, player_groups, self.conflict.heading - 90, self.conflict.to_cp, self.conflict.from_cp)
def gen_infantry_group_for_group(self, group, is_player, side:Country, forward_heading):
# Disable infantry unit gen if disabled
@ -161,8 +159,7 @@ class GroundConflictGenerator:
dcs_group.add_trigger_action(hold_task)
# Artillery strike random start
artillery_trigger = TriggerOnce(Event.NoEvent,
"ArtilleryFireTask #" + str(dcs_group.id))
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)
@ -179,7 +176,7 @@ class GroundConflictGenerator:
# Hold position
dcs_group.points[0].tasks.append(Hold())
retreat = self.find_retreat_point(dcs_group, forward_heading)
retreat = self.find_retreat_point(dcs_group, forward_heading, (int)(RETREAT_DISTANCE/8))
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)
@ -190,12 +187,15 @@ class GroundConflictGenerator:
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 = 3
retreat_task.number = 4
dcs_group.add_trigger_action(retreat_task)
artillery_fallback.add_action(AITaskSet(dcs_group.id, len(dcs_group.tasks)))
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:
@ -232,12 +232,16 @@ class GroundConflictGenerator:
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.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]:
@ -248,6 +252,9 @@ class GroundConflictGenerator:
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
@ -260,14 +267,51 @@ class GroundConflictGenerator:
dcs_group.add_waypoint(reposition_point, PointAction.OffRoad)
def find_retreat_point(self, dcs_group, frontline_heading):
def add_morale_trigger(self, dcs_group, forward_heading):
"""
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
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
fallback = ControlledTask(GoToWaypoint(toIndex=len(dcs_group.points)))
fallback.enabled = False
dcs_group.add_trigger_action(Hold())
dcs_group.add_trigger_action(fallback)
# 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 find_retreat_point(self, dcs_group, frontline_heading, distance=RETREAT_DISTANCE):
"""
Find a point to retreat to
:param dcs_group: DCS mission group we are searching a retreat point for
:param frontline_heading: Heading of the frontline
:return: dcs.mapping.Point object with the desired position
"""
return dcs_group.points[0].position.point_from_heading(frontline_heading-180, RETREAT_DISTANCE)
return dcs_group.points[0].position.point_from_heading(frontline_heading-180, distance)
def find_offensive_point(self, dcs_group, frontline_heading, distance):
"""

View File

@ -45,12 +45,6 @@ class GroundObjectsGenerator:
def generate(self):
cp = None # type: ControlPoint
if self.conflict.attackers_country.name == self.game.player_country:
cp = self.conflict.to_cp
else:
cp = self.conflict.from_cp
for cp in self.game.theater.controlpoints:
if cp.captured:

View File

@ -21,10 +21,11 @@ from userdata import liberation_install, persistency, liberation_theme
if __name__ == "__main__":
os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1" # Potential fix for 4K screens
app = QApplication(sys.argv)
# init the theme and load the stylesheet based on the theme index
liberation_theme.init();
liberation_theme.init()
css = ""
with open("./resources/stylesheets/"+liberation_theme.get_theme_css_file()) as stylesheet:
app.setStyleSheet(stylesheet.read())

View File

@ -35,8 +35,8 @@ class QBaseMenu2(QDialog):
self.setWindowFlags(Qt.WindowStaysOnTopHint)
self.setMinimumSize(300, 200)
self.setMinimumWidth(680)
self.setMaximumWidth(680)
self.setMinimumWidth(800)
self.setMaximumWidth(800)
self.setModal(True)
self.initUi()
@ -50,7 +50,7 @@ class QBaseMenu2(QDialog):
header = QLabel(self)
header.setGeometry(0, 0, 655, 106)
pixmap = QPixmap("./resources/ui/airbase.png")
pixmap = QPixmap(self.get_base_image())
header.setPixmap(pixmap)
title = QLabel("<b>" + self.cp.name + "</b>")
@ -75,7 +75,6 @@ class QBaseMenu2(QDialog):
def closeEvent(self, closeEvent:QCloseEvent):
GameUpdateSignal.get_instance().updateGame(self.game)
def get_base_image(self):
if self.cp.cptype == ControlPointType.AIRCRAFT_CARRIER_GROUP:
return "./resources/ui/carrier.png"

View File

@ -33,10 +33,12 @@ class QMissionPlanning(QDialog):
self.select_airbase = QChooseAirbase(self.game)
self.select_airbase.selected_airbase_changed.connect(self.on_departure_cp_changed)
self.planned_flight_view = QPlannedFlightsView(None)
self.available_aircraft_at_selected_location = {}
if self.captured_cp[0].id in self.game.planners.keys():
self.planner = self.game.planners[self.captured_cp[0].id]
self.planned_flight_view.set_flight_planner(self.planner)
self.selected_cp = self.captured_cp[0]
self.available_aircraft_at_selected_location = self.planner.get_available_aircraft()
self.planned_flight_view.selectionModel().setCurrentIndex(self.planned_flight_view.indexAt(QPoint(1, 1)), QItemSelectionModel.Rows)
self.planned_flight_view.selectionModel().selectionChanged.connect(self.on_flight_selection_change)
@ -82,8 +84,10 @@ class QMissionPlanning(QDialog):
if len(cps) == 1:
self.selected_cp = cps[0]
self.planner = self.game.planners[cps[0].id]
self.available_aircraft_at_selected_location = self.planner.get_available_aircraft()
self.planned_flight_view.set_flight_planner(self.planner)
else:
self.available_aircraft_at_selected_location = {}
self.planned_flight_view.set_flight_planner(None)
def on_flight_selection_change(self):

View File

@ -40,7 +40,8 @@ class QFlightCreator(QDialog):
for aircraft_type in self.planner.get_available_aircraft().keys():
print(aircraft_type)
print(aircraft_type.name)
self.select_type_aircraft.addItem(aircraft_type.id, userData=aircraft_type)
if self.available[aircraft_type] > 0:
self.select_type_aircraft.addItem(aircraft_type.id, userData=aircraft_type)
self.select_type_aircraft.setCurrentIndex(0)
self.select_flight_type = QComboBox()
@ -61,6 +62,11 @@ class QFlightCreator(QDialog):
self.select_count_of_aircraft.setMaximum(4)
self.select_count_of_aircraft.setValue(2)
aircraft_type = self.select_type_aircraft.currentData()
if aircraft_type is not None:
self.select_count_of_aircraft.setValue(min(self.available[aircraft_type], 2))
self.select_count_of_aircraft.setMaximum(min(self.available[aircraft_type], 4))
self.add_button = QPushButton("Add")
self.add_button.clicked.connect(self.create_flight)