Merge pull request #884 from Khopa/develop_2_4_x

Release 2.4.2.
This commit is contained in:
Dan Albert 2021-02-12 19:05:44 -08:00 committed by GitHub
commit e40b916b07
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 958 additions and 209 deletions

View File

@ -1,3 +1,15 @@
# 2.4.2
## Features/Improvements
* **[Factions]** Introduction dates and fallback weapons added for US, Russian, UK, and French weapons. Huge thanks to @TheCandianVendingMachine for the massive amount of data entry!
* **[Campaigns]** Added 1995 start dates.
## Fixes
* **[Economy]** Pending ground unit purchases will also be transferred when a connected base is captured.
* **[UI]** Fixed rounding of budget in recruitment menu.
# 2.4.1 # 2.4.1
## Fixes ## Fixes

File diff suppressed because it is too large Load Diff

View File

@ -1300,6 +1300,10 @@ TIME_PERIODS = {
"Gulf War - Winter [1990]": datetime(1990, 1, 1), "Gulf War - Winter [1990]": datetime(1990, 1, 1),
"Gulf War - Spring [1990]": datetime(1990, 4, 1), "Gulf War - Spring [1990]": datetime(1990, 4, 1),
"Gulf War - Summer [1990]": datetime(1990, 6, 1), "Gulf War - Summer [1990]": datetime(1990, 6, 1),
"Mid-90s - Winter [1995]": datetime(1995, 1, 1),
"Mid-90s - Spring [1995]": datetime(1995, 4, 1),
"Mid-90s - Summer [1995]": datetime(1995, 6, 1),
"Mid-90s - Fall [1995]": datetime(1995, 10, 1),
"Gulf War - Fall [1990]": datetime(1990, 10, 1), "Gulf War - Fall [1990]": datetime(1990, 10, 1),
"Modern - Winter [2010]": datetime(2010, 1, 1), "Modern - Winter [2010]": datetime(2010, 1, 1),
"Modern - Spring [2010]": datetime(2010, 4, 1), "Modern - Spring [2010]": datetime(2010, 4, 1),
@ -1309,7 +1313,7 @@ TIME_PERIODS = {
"Syrian War [2011]": datetime(2011, 3, 15), "Syrian War [2011]": datetime(2011, 3, 15),
"6 days war [1967]": datetime(1967, 6, 5), "6 days war [1967]": datetime(1967, 6, 5),
"Yom Kippour War [1973]": datetime(1973, 10, 6), "Yom Kippour War [1973]": datetime(1973, 10, 6),
"Lebanon War [1982]": datetime(1982, 6, 6), "First Lebanon War [1982]": datetime(1982, 6, 6),
"Arab-Israeli War [1948]": datetime(1948, 5, 15), "Arab-Israeli War [1948]": datetime(1948, 5, 15),
} }

View File

@ -6,7 +6,7 @@ from typing import Dict, Iterator, List, TYPE_CHECKING, Tuple, Type
from dcs.mapping import Point from dcs.mapping import Point
from dcs.task import Task from dcs.task import Task
from dcs.unittype import UnitType from dcs.unittype import UnitType, VehicleType
from game import persistency from game import persistency
from game.debriefing import AirLosses, Debriefing from game.debriefing import AirLosses, Debriefing
@ -296,45 +296,69 @@ class Event:
self.game.turn) self.game.turn)
self.game.informations.append(info) self.game.informations.append(info)
def redeploy_units(self, cp): def redeploy_units(self, cp: ControlPoint) -> None:
"""" """"
Auto redeploy units to newly captured base Auto redeploy units to newly captured base
""" """
ally_connected_cps = [ocp for ocp in cp.connected_points if cp.captured == ocp.captured] ally_connected_cps = [ocp for ocp in cp.connected_points if
enemy_connected_cps = [ocp for ocp in cp.connected_points if cp.captured != ocp.captured] cp.captured == ocp.captured]
enemy_connected_cps = [ocp for ocp in cp.connected_points if
cp.captured != ocp.captured]
# If the newly captured cp does not have enemy connected cp, # If the newly captured cp does not have enemy connected cp,
# then it is not necessary to redeploy frontline units there. # then it is not necessary to redeploy frontline units there.
if len(enemy_connected_cps) == 0: if len(enemy_connected_cps) == 0:
return return
# From each ally cp, send reinforcements
for ally_cp in ally_connected_cps:
self.redeploy_between(cp, ally_cp)
def redeploy_between(self, destination: ControlPoint,
source: ControlPoint) -> None:
total_units_redeployed = 0
moved_units = {}
if source.has_active_frontline or not destination.captured:
# If there are still active front lines to defend at the
# transferring CP we should not transfer all units.
#
# Opfor also does not transfer all of their units.
# TODO: Balance the CPs rather than moving half from everywhere.
move_factor = 0.5
else: else:
# From each ally cp, send reinforcements # Otherwise we can move everything.
for ally_cp in ally_connected_cps: move_factor = 1
total_units_redeployed = 0
own_enemy_cp = [ocp for ocp in ally_cp.connected_points if ally_cp.captured != ocp.captured]
moved_units = {} for frontline_unit, count in source.base.armor.items():
moved_units[frontline_unit] = int(count * move_factor)
total_units_redeployed = total_units_redeployed + int(
count * move_factor)
# If the connected base, does not have any more enemy cp connected. destination.base.commision_units(moved_units)
# Or if it is not the opponent redeploying forces there (enemy AI will never redeploy all their forces at once) source.base.commit_losses(moved_units)
if len(own_enemy_cp) > 0 or not cp.captured:
for frontline_unit, count in ally_cp.base.armor.items():
moved_units[frontline_unit] = int(count/2)
total_units_redeployed = total_units_redeployed + int(count/2)
else: # So if the old base, does not have any more enemy cp connected, or if it is an enemy base
for frontline_unit, count in ally_cp.base.armor.items():
moved_units[frontline_unit] = count
total_units_redeployed = total_units_redeployed + count
cp.base.commision_units(moved_units) # Also transfer pending deliveries.
ally_cp.base.commit_losses(moved_units) for unit_type, count in source.pending_unit_deliveries.units.items():
if not issubclass(unit_type, VehicleType):
continue
if count <= 0:
# Don't transfer *sales*...
continue
move_count = int(count * move_factor)
source.pending_unit_deliveries.sell({unit_type: move_count})
destination.pending_unit_deliveries.order({unit_type: move_count})
total_units_redeployed += move_count
if total_units_redeployed > 0: if total_units_redeployed > 0:
info = Information("Units redeployed", "", self.game.turn) text = (
info.text = str(total_units_redeployed) + " units have been redeployed from " + ally_cp.name + " to " + cp.name f"{total_units_redeployed} units have been redeployed from "
self.game.informations.append(info) f"{source.name} to {destination.name}"
logging.info(info.text) )
info = Information("Units redeployed", text, self.game.turn)
self.game.informations.append(info)
logging.info(text)
class UnitsDeliveryEvent: class UnitsDeliveryEvent:

View File

@ -606,6 +606,10 @@ class ControlPoint(MissionTarget, ABC):
def income_per_turn(self) -> int: def income_per_turn(self) -> int:
return 0 return 0
@property
def has_active_frontline(self) -> bool:
return any(
not c.is_friendly(self.captured) for c in self.connected_points)
class Airfield(ControlPoint): class Airfield(ControlPoint):

View File

@ -2,7 +2,7 @@ from pathlib import Path
def _build_version_string() -> str: def _build_version_string() -> str:
components = ["2.4"] components = ["2.4.2"]
build_number_path = Path("resources/buildnumber") build_number_path = Path("resources/buildnumber")
if build_number_path.exists(): if build_number_path.exists():
with build_number_path.open("r") as build_number_file: with build_number_path.open("r") as build_number_file:

View File

@ -28,7 +28,7 @@ class QRecruitBehaviour:
bought_amount_labels = None bought_amount_labels = None
maximum_units = -1 maximum_units = -1
recruitable_types = [] recruitable_types = []
BUDGET_FORMAT = "Available Budget: <b>${}M</b>" BUDGET_FORMAT = "Available Budget: <b>${:.2f}M</b>"
def __init__(self) -> None: def __init__(self) -> None:
self.bought_amount_labels = {} self.bought_amount_labels = {}

View File

@ -3,7 +3,7 @@
dofile('Scripts/ScriptingSystem.lua') dofile('Scripts/ScriptingSystem.lua')
--Sanitize Mission Scripting environment --Sanitize Mission Scripting environment
--This makes unavailable some unsecure functions. --This makes unavailable some unsecure functions.
--Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions. --Mission downloaded from server to client may contain potentialy harmful lua code that may use these functions.
--You can remove the code below and make availble these functions at your own risk. --You can remove the code below and make availble these functions at your own risk.