Compare commits

...

10 Commits
1.0 ... 1.08

Author SHA1 Message Date
Vasyl Horbachenko
26a7609875 fixed crash on mission debriefing 2018-07-04 04:44:58 +03:00
Vasyl Horbachenko
77a07f6628 Merge remote-tracking branch 'origin/master' 2018-07-04 03:07:43 +03:00
Vasyl Horbachenko
42c8b2f989 hotfix for openbeta DCS saves 2018-07-04 03:07:32 +03:00
Vasyl Horbachenko
3861926ff7 Update README.md 2018-07-04 02:31:05 +03:00
Vasyl Horbachenko
3fd3e591e7 fixed SAMless start generation 2018-07-04 01:44:49 +03:00
Vasyl Horbachenko
187ce4a2c5 non-linear importance; balance updates 2018-07-04 01:33:52 +03:00
Vasyl Horbachenko
c6098eb9c2 Update start.bat 2018-07-03 18:16:17 +03:00
Vasyl Horbachenko
e49fd13730 added Su34 2018-07-03 05:18:24 +03:00
Vasyl Horbachenko
a2aff82617 added Mig 29S, lowered importance of 3rd CP in PG 2018-07-03 05:16:57 +03:00
Vasyl Horbachenko
db18c2c7db removed debugging code 2018-07-03 04:56:57 +03:00
11 changed files with 84 additions and 58 deletions

View File

@@ -1,4 +1,6 @@
WIP [DCS World](https://www.digitalcombatsimulator.com/en/products/world/) single-player liberation dynamic campaign.
[DCS World](https://www.digitalcombatsimulator.com/en/products/world/) single-player liberation dynamic campaign.
[Installation instructions/Manual](https://github.com/shdwp/dcs_liberation/wiki)
Inspired by *ARMA Liberation* mission.

View File

@@ -40,7 +40,8 @@ PRICES = {
MiG_23MLD: 20,
Su_27: 24,
Su_33: 25,
MiG_29A: 26,
MiG_29A: 22,
MiG_29S: 26,
F_5E: 6,
MiG_15bis: 5,
@@ -55,6 +56,7 @@ PRICES = {
# bomber
Su_25T: 13,
L_39ZA: 10,
Su_34: 18,
A_10A: 18,
A_10C: 20,
@@ -99,8 +101,8 @@ PRICES = {
AirDefence.AAA_ZU_23_on_Ural_375: 5,
AirDefence.SAM_SA_18_Igla_S_MANPADS: 8,
AirDefence.SAM_SA_19_Tunguska_2S6: 10,
AirDefence.SAM_SA_8_Osa_9A33: 15,
AirDefence.SAM_SA_19_Tunguska_2S6: 15,
AirDefence.SAM_SA_8_Osa_9A33: 13,
# ship
CV_1143_5_Admiral_Kuznetsov: 100,
@@ -137,6 +139,7 @@ UNIT_BY_TASK = {
Su_33,
MiG_21Bis,
MiG_29A,
MiG_29S,
FA_18C_hornet,
F_15C,
M_2000C,
@@ -148,6 +151,7 @@ UNIT_BY_TASK = {
A_10A,
A_10C,
Su_25T,
Su_34,
Ka_50,
],
@@ -170,13 +174,15 @@ UNIT_BY_TASK = {
AirDefence.AAA_Vulcan_M163,
AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Patriot_ICC,
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.SAM_SA_8_Osa_9A33,
AirDefence.SAM_SA_8_Osa_9A33,
AirDefence.SAM_SA_19_Tunguska_2S6,
],
Reconnaissance: [Unarmed.Transport_M818, Unarmed.Transport_Ural_375, Unarmed.Transport_UAZ_469],
@@ -234,10 +240,11 @@ UNIT_BY_COUNTRY = {
MiG_15bis,
MiG_21Bis,
MiG_29A,
MiG_29S,
M_2000C,
AV8BNA,
Su_25T,
Su_34,
L_39ZA,
IL_76MD,
@@ -252,8 +259,8 @@ UNIT_BY_COUNTRY = {
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.SAM_SA_18_Igla_S_MANPADS,
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_8_Osa_9A33,
AirDefence.SAM_SA_19_Tunguska_2S6,
Armor.APC_BTR_80,
Armor.MBT_T_90,
@@ -409,7 +416,7 @@ def choose_units(for_task: Task, factor: float, count: int, country: str) -> typ
index_start = min(idx, len(suitable_unittypes) - variety)
index_end = min(idx + variety, len(suitable_unittypes))
return suitable_unittypes[index_start:index_end]
return list(set(suitable_unittypes[index_start:index_end]))
def _validate_db():

View File

@@ -13,6 +13,10 @@ class GroundAttackEvent(GroundInterceptEvent):
def __str__(self):
return "Destroy insurgents at {}".format(self.to_cp)
@property
def threat_description(self):
return ""
def player_defending(self, strikegroup: db.PlaneDict, clients: db.PlaneDict):
suitable_unittypes = db.find_unittype(Reconnaissance, self.attacker_name)
random.shuffle(suitable_unittypes)

View File

@@ -18,7 +18,7 @@ COMMISION_LIMITS_FACTORS = {
PinpointStrike: 10,
CAS: 5,
CAP: 8,
AirDefence: 2,
AirDefence: 1,
}
COMMISION_AMOUNTS_SCALE = 1.5
@@ -46,18 +46,21 @@ Events:
* InfantryTransportEvent - helicopter infantry transport
"""
EVENT_PROBABILITIES = {
CaptureEvent: [100, 8],
InterceptEvent: [25, 12],
GroundInterceptEvent: [25, 12],
GroundAttackEvent: [0, 12],
NavalInterceptEvent: [25, 12],
AntiAAStrikeEvent: [25, 12],
CaptureEvent: [100, 10],
InterceptEvent: [25, 10],
GroundInterceptEvent: [25, 10],
GroundAttackEvent: [0, 10],
NavalInterceptEvent: [25, 10],
AntiAAStrikeEvent: [25, 10],
InfantryTransportEvent: [25, 0],
}
# amount of strength captures bases recover for the turn
# amount of strength player bases recover for the turn
PLAYER_BASE_STRENGTH_RECOVERY = 0.2
# amount of strength enemy bases recover for the turn
ENEMY_BASE_STRENGTH_RECOVERY = 0.05
# cost of AWACS for single operation
AWACS_BUDGET_COST = 4
@@ -110,11 +113,10 @@ class Game:
for event_class, (player_probability, enemy_probability) in EVENT_PROBABILITIES.items():
if self._roll(player_probability, player_cp.base.strength):
if event_class == NavalInterceptEvent:
if enemy_cp.radials == LAND:
continue
self.events.append(event_class(self.player, self.enemy, player_cp, enemy_cp, self))
if event_class == NavalInterceptEvent and enemy_cp.radials == LAND:
pass
else:
self.events.append(event_class(self.player, self.enemy, player_cp, enemy_cp, self))
elif self._roll(enemy_probability, enemy_cp.base.strength):
if event_class in enemy_generated_types:
continue
@@ -210,13 +212,14 @@ class Game:
def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint]=None):
for event in self.events:
if isinstance(event, UnitsDeliveryEvent):
event.skip()
event.skip()
if not no_action:
self._budget_player()
for cp in self.theater.enemy_points():
self._commision_units(cp)
for cp in self.theater.player_points():
cp.base.affect_strength(+PLAYER_BASE_STRENGTH_RECOVERY)

View File

@@ -1 +1 @@
.\venv\Scripts\python.exe __init__.py > logs.txt 2>&1
py.exe __init__.py > logs.txt 2>&1

View File

@@ -24,23 +24,23 @@ class CaucasusTheater(ConflictTheater):
soganlug = ControlPoint.from_airport(caucasus.Soganlug, LAND, SIZE_SMALL, IMPORTANCE_LOW)
kutaisi = ControlPoint.from_airport(caucasus.Kutaisi, LAND, SIZE_SMALL, IMPORTANCE_LOW)
senaki = ControlPoint.from_airport(caucasus.Senaki_Kolkhi, LAND, SIZE_REGULAR, IMPORTANCE_LOW)
kobuleti = ControlPoint.from_airport(caucasus.Kobuleti, COAST_A_E, SIZE_SMALL, IMPORTANCE_MEDIUM)
batumi = ControlPoint.from_airport(caucasus.Batumi, COAST_DL_E, SIZE_SMALL, IMPORTANCE_MEDIUM)
sukhumi = ControlPoint.from_airport(caucasus.Sukhumi_Babushara, COAST_DR_E, SIZE_REGULAR, IMPORTANCE_MEDIUM)
gudauta = ControlPoint.from_airport(caucasus.Gudauta, COAST_DR_E, SIZE_REGULAR, IMPORTANCE_MEDIUM)
kobuleti = ControlPoint.from_airport(caucasus.Kobuleti, COAST_A_E, SIZE_SMALL, 1.1)
batumi = ControlPoint.from_airport(caucasus.Batumi, COAST_DL_E, SIZE_SMALL, 1.3)
sukhumi = ControlPoint.from_airport(caucasus.Sukhumi_Babushara, COAST_DR_E, SIZE_REGULAR, 1.2)
gudauta = ControlPoint.from_airport(caucasus.Gudauta, COAST_DR_E, SIZE_REGULAR, 1.2)
sochi = ControlPoint.from_airport(caucasus.Sochi_Adler, COAST_DR_E, SIZE_BIG, IMPORTANCE_HIGH)
gelendzhik = ControlPoint.from_airport(caucasus.Gelendzhik, COAST_DR_E, SIZE_BIG, IMPORTANCE_MEDIUM)
gelendzhik = ControlPoint.from_airport(caucasus.Gelendzhik, COAST_DR_E, SIZE_BIG, 1.1)
maykop = ControlPoint.from_airport(caucasus.Maykop_Khanskaya, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
krasnodar = ControlPoint.from_airport(caucasus.Krasnodar_Center, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
novorossiysk = ControlPoint.from_airport(caucasus.Novorossiysk, COAST_DR_E, SIZE_BIG, IMPORTANCE_MEDIUM)
krymsk = ControlPoint.from_airport(caucasus.Krymsk, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
novorossiysk = ControlPoint.from_airport(caucasus.Novorossiysk, COAST_DR_E, SIZE_BIG, 1.2)
krymsk = ControlPoint.from_airport(caucasus.Krymsk, LAND, SIZE_LARGE, 1.2)
anapa = ControlPoint.from_airport(caucasus.Anapa_Vityazevo, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
beslan = ControlPoint.from_airport(caucasus.Beslan, LAND, SIZE_REGULAR, IMPORTANCE_LOW)
nalchik = ControlPoint.from_airport(caucasus.Nalchik, LAND, SIZE_REGULAR, IMPORTANCE_LOW)
mineralnye = ControlPoint.from_airport(caucasus.Mineralnye_Vody, LAND, SIZE_BIG, IMPORTANCE_MEDIUM)
mozdok = ControlPoint.from_airport(caucasus.Mozdok, LAND, SIZE_BIG, IMPORTANCE_MEDIUM)
nalchik = ControlPoint.from_airport(caucasus.Nalchik, LAND, SIZE_REGULAR, 1.1)
mineralnye = ControlPoint.from_airport(caucasus.Mineralnye_Vody, LAND, SIZE_BIG, 1.3)
mozdok = ControlPoint.from_airport(caucasus.Mozdok, LAND, SIZE_BIG, 1.1)
carrier_1 = ControlPoint.carrier("Carrier", mapping.Point(-305810.6875, 406399.1875))

View File

@@ -20,16 +20,16 @@ class NevadaTheater(ConflictTheater):
mina = ControlPoint.from_airport(nevada.Mina_Airport_3Q0, LAND, SIZE_SMALL, IMPORTANCE_LOW)
tonopah = ControlPoint.from_airport(nevada.Tonopah_Airport, LAND, SIZE_SMALL, IMPORTANCE_LOW)
tonopah_test_range = ControlPoint.from_airport(nevada.Tonopah_Test_Range_Airfield, LAND, SIZE_SMALL, IMPORTANCE_LOW)
lincoln_conty = ControlPoint.from_airport(nevada.Lincoln_County, LAND, SIZE_SMALL, IMPORTANCE_MEDIUM)
lincoln_conty = ControlPoint.from_airport(nevada.Lincoln_County, LAND, SIZE_SMALL, 1.2)
pahute_mesa = ControlPoint.from_airport(nevada.Pahute_Mesa_Airstrip, LAND, SIZE_SMALL, IMPORTANCE_MEDIUM)
groom_lake = ControlPoint.from_airport(nevada.Groom_Lake_AFB, LAND, SIZE_REGULAR, IMPORTANCE_MEDIUM)
mesquite = ControlPoint.from_airport(nevada.Mesquite, LAND, SIZE_REGULAR, IMPORTANCE_MEDIUM)
beatty = ControlPoint.from_airport(nevada.Beatty_Airport, LAND, SIZE_REGULAR, IMPORTANCE_MEDIUM)
pahute_mesa = ControlPoint.from_airport(nevada.Pahute_Mesa_Airstrip, LAND, SIZE_SMALL, 1.1)
groom_lake = ControlPoint.from_airport(nevada.Groom_Lake_AFB, LAND, SIZE_REGULAR, IMPORTANCE_HIGH)
mesquite = ControlPoint.from_airport(nevada.Mesquite, LAND, SIZE_REGULAR, 1.3)
beatty = ControlPoint.from_airport(nevada.Beatty_Airport, LAND, SIZE_REGULAR, 1.1)
creech = ControlPoint.from_airport(nevada.Creech_AFB, LAND, SIZE_BIG, IMPORTANCE_HIGH)
las_vegas = ControlPoint.from_airport(nevada.North_Las_Vegas, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
jean = ControlPoint.from_airport(nevada.Jean_Airport, LAND, SIZE_REGULAR, IMPORTANCE_HIGH)
jean = ControlPoint.from_airport(nevada.Jean_Airport, LAND, SIZE_REGULAR, 1.2)
laughlin = ControlPoint.from_airport(nevada.Laughlin_Airport, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
def __init__(self):

View File

@@ -21,21 +21,21 @@ class PersianGulfTheater(ConflictTheater):
al_dhafra = ControlPoint.from_airport(persiangulf.Al_Dhafra_AB, LAND, SIZE_BIG, IMPORTANCE_LOW)
al_maktoum = ControlPoint.from_airport(persiangulf.Al_Maktoum_Intl, LAND, SIZE_BIG, IMPORTANCE_LOW)
al_minhad = ControlPoint.from_airport(persiangulf.Al_Minhad_AB, LAND, SIZE_REGULAR, IMPORTANCE_MEDIUM)
sir_abu_nuayr = ControlPoint.from_airport(persiangulf.Sir_Abu_Nuayr, [0, 330], SIZE_SMALL, IMPORTANCE_MEDIUM)
al_minhad = ControlPoint.from_airport(persiangulf.Al_Minhad_AB, LAND, SIZE_REGULAR, IMPORTANCE_LOW)
sir_abu_nuayr = ControlPoint.from_airport(persiangulf.Sir_Abu_Nuayr, [0, 330], SIZE_SMALL, 1.1)
dubai = ControlPoint.from_airport(persiangulf.Dubai_Intl, COAST_DL_E, SIZE_LARGE, IMPORTANCE_MEDIUM)
sharjah = ControlPoint.from_airport(persiangulf.Sharjah_Intl, LAND, SIZE_BIG, IMPORTANCE_MEDIUM)
fujairah = ControlPoint.from_airport(persiangulf.Fujairah_Intl, COAST_V_W, SIZE_REGULAR, IMPORTANCE_MEDIUM)
khasab = ControlPoint.from_airport(persiangulf.Khasab, LAND, SIZE_SMALL, IMPORTANCE_MEDIUM)
dubai = ControlPoint.from_airport(persiangulf.Dubai_Intl, COAST_DL_E, SIZE_LARGE, 1.3)
sharjah = ControlPoint.from_airport(persiangulf.Sharjah_Intl, LAND, SIZE_BIG, 1.2)
fujairah = ControlPoint.from_airport(persiangulf.Fujairah_Intl, COAST_V_W, SIZE_REGULAR, 1.3)
khasab = ControlPoint.from_airport(persiangulf.Khasab, LAND, SIZE_SMALL, 1.3)
sirri = ControlPoint.from_airport(persiangulf.Sirri_Island, COAST_DL_W, SIZE_REGULAR, IMPORTANCE_MEDIUM)
abu_musa = ControlPoint.from_airport(persiangulf.Abu_Musa_Island_Airport, LAND, SIZE_SMALL, IMPORTANCE_MEDIUM)
tunb_island = ControlPoint.from_airport(persiangulf.Tunb_Island_AFB, [0, 270, 330], SIZE_REGULAR, IMPORTANCE_HIGH)
sirri = ControlPoint.from_airport(persiangulf.Sirri_Island, COAST_DL_W, SIZE_REGULAR, 1.2)
abu_musa = ControlPoint.from_airport(persiangulf.Abu_Musa_Island_Airport, LAND, SIZE_SMALL, 1.0)
tunb_island = ControlPoint.from_airport(persiangulf.Tunb_Island_AFB, [0, 270, 330], SIZE_REGULAR, 1.1)
tunb_kochak = ControlPoint.from_airport(persiangulf.Tunb_Kochak, [135, 180], SIZE_SMALL, IMPORTANCE_HIGH)
bandar_lengeh = ControlPoint.from_airport(persiangulf.Bandar_Lengeh, [270, 315, 0, 45], SIZE_SMALL, IMPORTANCE_HIGH)
qeshm = ControlPoint.from_airport(persiangulf.Qeshm_Island, [270, 315, 0, 45, 90, 135, 180], SIZE_SMALL, IMPORTANCE_HIGH)
qeshm = ControlPoint.from_airport(persiangulf.Qeshm_Island, [270, 315, 0, 45, 90, 135, 180], SIZE_SMALL, 1.1)
havadarya = ControlPoint.from_airport(persiangulf.Havadarya, COAST_DL_W, SIZE_REGULAR, IMPORTANCE_HIGH)
bandar_abbas = ControlPoint.from_airport(persiangulf.Bandar_Abbas_Intl, LAND, SIZE_BIG, IMPORTANCE_HIGH)

View File

@@ -11,7 +11,7 @@ COUNT_BY_TASK = {
PinpointStrike: 12,
CAP: 8,
CAS: 4,
AirDefence: 2,
AirDefence: 1,
}
@@ -28,8 +28,8 @@ def generate_initial(theater: ConflictTheater, enemy: str, sams: bool, multiplie
variety = int(UNIT_VARIETY)
unittypes = db.choose_units(task, importance_factor, variety, enemy)
if not sams:
unittypes = [x for x in unittypes if x not in db.SAM_BAN]
if not sams and task == AirDefence:
unittypes = [x for x in db.find_unittype(AirDefence, enemy) if x not in db.SAM_BAN]
count_log = math.log(cp.importance + 0.01, UNIT_COUNT_IMPORTANCE_LOG)
count = max(COUNT_BY_TASK[task] * multiplier * (1+count_log), 1)

View File

@@ -14,6 +14,8 @@ from dcs.unit import UnitType
from game import db
from .persistency import _base_path
DEBRIEFING_LOG_EXTENSION = "log"
@@ -92,7 +94,7 @@ class Debriefing:
def debriefing_directory_location() -> str:
return os.path.expanduser("~\Saved Games\DCS\liberation_debriefings")
return os.path.join(_base_path(), "liberation_debriefings")
def _logfiles_snapshot() -> typing.Dict[str, float]:

View File

@@ -4,12 +4,20 @@ import os
import shutil
def _base_path() -> str:
openbeta_path = os.path.expanduser("~\Saved Games\DCS.openbeta")
if os.path.exists(openbeta_path):
return openbeta_path
else:
return os.path.expanduser("~\Saved Games\DCS")
def _save_file() -> str:
return os.path.expanduser("~\Saved Games\DCS\liberation_save")
return os.path.join(_base_path(), "liberation_save")
def _temporary_save_file() -> str:
return os.path.expanduser("~\Saved Games\DCS\liberation_save_tmp")
return os.path.join(_base_path(), "liberation_save_tmp")
def _save_file_exists() -> bool:
@@ -17,7 +25,7 @@ def _save_file_exists() -> bool:
def mission_path_for(name: str) -> str:
return os.path.expanduser("~\Saved Games\DCS\Missions\{}".format(name))
return os.path.join(_base_path(), "Missions\{}".format(name))
def restore_game():