Compare commits

...

13 Commits
1.0 ... 1.12

Author SHA1 Message Date
Vasyl Horbachenko
32fb5ad0e2 fixed a number of issues: user directory on different drive, carrier ops, multiplayer debriefing parser, multiplayer mission generation; added su25 2018-07-05 02:42:46 +03:00
Vasyl Horbachenko
fa55ae1fcc fixed multiplayer mission start 2018-07-04 05:20:35 +03:00
Vasyl Horbachenko
90fbe77682 fixed unplayable F-5 2018-07-04 04:51:31 +03:00
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
16 changed files with 213 additions and 81 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. Inspired by *ARMA Liberation* mission.

View File

@@ -1,5 +1,6 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import os import os
import sys
import dcs import dcs
import theater.caucasus import theater.caucasus
@@ -15,6 +16,47 @@ from game.game import Game
from theater import start_generator from theater import start_generator
from userdata import persistency from userdata import persistency
"""
from dcs.lua.parse import *
a = loads(open("build/mission", "r").read())
b = loads(open("build/mission_workin.lua", "r").read())
def get(a, k):
b = a
for x in k.strip().split(" "):
if isinstance(a, dict):
y = a
a = a.get(x, None)
if a is None:
try:
a = y.get(int(x), None)
except:
pass
else:
break
if a is None:
pass
return a
def cycle(kk, ref, v):
if isinstance(v, dict):
for k, v in v.items():
cycle(kk + " " + str(k), ref, v)
elif isinstance(v, list):
for i, v in enumerate(v):
cycle(kk + " " + str(i), ref, v)
else:
if get(ref, kk) != v:
print(kk, v)
print(get(ref, kk))
cycle("", a, b)
sys.exit(0)
"""
persistency.setup(sys.argv[1])
dcs.planes.FlyingType.payload_dirs.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "resources\\payloads")) dcs.planes.FlyingType.payload_dirs.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "resources\\payloads"))

View File

@@ -40,9 +40,10 @@ PRICES = {
MiG_23MLD: 20, MiG_23MLD: 20,
Su_27: 24, Su_27: 24,
Su_33: 25, Su_33: 25,
MiG_29A: 26, MiG_29A: 22,
MiG_29S: 26,
F_5E: 6, F_5E_3: 6,
MiG_15bis: 5, MiG_15bis: 5,
MiG_21Bis: 6, MiG_21Bis: 6,
AJS37: 8, AJS37: 8,
@@ -53,8 +54,10 @@ PRICES = {
F_15C: 24, F_15C: 24,
# bomber # bomber
Su_25: 15,
Su_25T: 13, Su_25T: 13,
L_39ZA: 10, L_39ZA: 10,
Su_34: 18,
A_10A: 18, A_10A: 18,
A_10C: 20, A_10C: 20,
@@ -99,8 +102,8 @@ PRICES = {
AirDefence.AAA_ZU_23_on_Ural_375: 5, AirDefence.AAA_ZU_23_on_Ural_375: 5,
AirDefence.SAM_SA_18_Igla_S_MANPADS: 8, AirDefence.SAM_SA_18_Igla_S_MANPADS: 8,
AirDefence.SAM_SA_19_Tunguska_2S6: 10, AirDefence.SAM_SA_19_Tunguska_2S6: 15,
AirDefence.SAM_SA_8_Osa_9A33: 15, AirDefence.SAM_SA_8_Osa_9A33: 13,
# ship # ship
CV_1143_5_Admiral_Kuznetsov: 100, CV_1143_5_Admiral_Kuznetsov: 100,
@@ -132,11 +135,12 @@ UNIT_BY_TASK = {
CAP: [ CAP: [
C_101CC, C_101CC,
AJS37, AJS37,
F_5E, F_5E_3,
Su_27, Su_27,
Su_33, Su_33,
MiG_21Bis, MiG_21Bis,
MiG_29A, MiG_29A,
MiG_29S,
FA_18C_hornet, FA_18C_hornet,
F_15C, F_15C,
M_2000C, M_2000C,
@@ -147,7 +151,9 @@ UNIT_BY_TASK = {
AV8BNA, AV8BNA,
A_10A, A_10A,
A_10C, A_10C,
Su_25,
Su_25T, Su_25T,
Su_34,
Ka_50, Ka_50,
], ],
@@ -170,13 +176,15 @@ UNIT_BY_TASK = {
AirDefence.AAA_Vulcan_M163, AirDefence.AAA_Vulcan_M163,
AirDefence.SAM_Avenger_M1097, AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Avenger_M1097, AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Patriot_ICC, AirDefence.SAM_Patriot_ICC,
AirDefence.AAA_ZU_23_on_Ural_375, AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.AAA_ZU_23_on_Ural_375, AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.SAM_SA_19_Tunguska_2S6, AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_8_Osa_9A33, 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], Reconnaissance: [Unarmed.Transport_M818, Unarmed.Transport_Ural_375, Unarmed.Transport_UAZ_469],
@@ -228,16 +236,18 @@ UNIT_BY_COUNTRY = {
"Russia": [ "Russia": [
C_101CC, C_101CC,
AJS37, AJS37,
F_5E, F_5E_3,
Su_25,
Su_27, Su_27,
Su_33, Su_33,
MiG_15bis, MiG_15bis,
MiG_21Bis, MiG_21Bis,
MiG_29A, MiG_29A,
MiG_29S,
M_2000C, M_2000C,
AV8BNA,
Su_25T, Su_25T,
Su_34,
L_39ZA, L_39ZA,
IL_76MD, IL_76MD,
@@ -252,8 +262,8 @@ UNIT_BY_COUNTRY = {
AirDefence.AAA_ZU_23_on_Ural_375, AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.SAM_SA_18_Igla_S_MANPADS, AirDefence.SAM_SA_18_Igla_S_MANPADS,
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_8_Osa_9A33, AirDefence.SAM_SA_8_Osa_9A33,
AirDefence.SAM_SA_19_Tunguska_2S6,
Armor.APC_BTR_80, Armor.APC_BTR_80,
Armor.MBT_T_90, Armor.MBT_T_90,
@@ -272,7 +282,6 @@ UNIT_BY_COUNTRY = {
F_15C, F_15C,
FA_18C_hornet, FA_18C_hornet,
AJS37, AJS37,
F_5E,
M_2000C, M_2000C,
MiG_21Bis, MiG_21Bis,
MiG_15bis, MiG_15bis,
@@ -409,7 +418,7 @@ def choose_units(for_task: Task, factor: float, count: int, country: str) -> typ
index_start = min(idx, len(suitable_unittypes) - variety) index_start = min(idx, len(suitable_unittypes) - variety)
index_end = min(idx + variety, len(suitable_unittypes)) 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(): def _validate_db():

View File

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

View File

@@ -26,7 +26,7 @@ class GroundInterceptEvent(Event):
return super(GroundInterceptEvent, self).threat_description return super(GroundInterceptEvent, self).threat_description
def __str__(self): def __str__(self):
return "Fontline CAS from {} at {}".format(self.from_cp, self.to_cp) return "Frontline CAS from {} at {}".format(self.from_cp, self.to_cp)
def is_successfull(self, debriefing: Debriefing): def is_successfull(self, debriefing: Debriefing):
total_targets = sum(self.targets.values()) total_targets = sum(self.targets.values())

View File

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

View File

@@ -1,4 +1,5 @@
from dcs.terrain import Terrain from dcs.terrain import Terrain
from dcs.lua.parse import loads
from userdata.debriefing import * from userdata.debriefing import *
@@ -61,7 +62,11 @@ class Operation:
self.extra_aagen = ExtraAAConflictGenerator(mission, conflict, self.game, player_name, enemy_name) self.extra_aagen = ExtraAAConflictGenerator(mission, conflict, self.game, player_name, enemy_name)
def prepare(self, terrain: Terrain, is_quick: bool): def prepare(self, terrain: Terrain, is_quick: bool):
with open("resources/default_options.lua", "r") as f:
options_dict = loads(f.read())["options"]
self.mission = dcs.Mission(terrain) self.mission = dcs.Mission(terrain)
self.mission.options.load_from_dict(options_dict)
self.is_quick = is_quick self.is_quick = is_quick
if is_quick: if is_quick:

View File

@@ -164,6 +164,16 @@ class AircraftConflictGenerator:
else: else:
assert False assert False
def _rtb_for(self, group: FlyingGroup, cp: ControlPoint, at: db.StartingPosition = None):
group.add_waypoint(cp.position, RTB_ALTITUDE)
if isinstance(cp.at, Point):
pass
elif isinstance(cp.at, ShipGroup):
pass
elif issubclass(cp.at, Airport):
group.land_at(cp.at)
def _at_position(self, at) -> Point: def _at_position(self, at) -> Point:
if isinstance(at, Point): if isinstance(at, Point):
return at return at
@@ -226,9 +236,7 @@ class AircraftConflictGenerator:
group.task = CAS.name group.task = CAS.name
self._setup_group(group, CAS, client_count) self._setup_group(group, CAS, client_count)
self.escort_targets.append((group, group.points.index(waypoint))) self.escort_targets.append((group, group.points.index(waypoint)))
self._rtb_for(group, self.conflict.from_cp, at)
group.add_waypoint(self.conflict.from_cp.position, RTB_ALTITUDE)
group.land_at(self.conflict.from_cp.at)
def generate_ship_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, target_groups: typing.Collection[ShipGroup], at: db.StartingPosition = None): def generate_ship_strikegroup(self, attackers: db.PlaneDict, clients: db.PlaneDict, target_groups: typing.Collection[ShipGroup], at: db.StartingPosition = None):
assert len(self.escort_targets) == 0 assert len(self.escort_targets) == 0
@@ -249,9 +257,7 @@ class AircraftConflictGenerator:
group.task = AntishipStrike.name group.task = AntishipStrike.name
self._setup_group(group, AntishipStrike, client_count) self._setup_group(group, AntishipStrike, client_count)
self.escort_targets.append((group, group.points.index(wayp))) self.escort_targets.append((group, group.points.index(wayp)))
self._rtb_for(group, self.conflict.from_cp, at)
group.add_waypoint(self.conflict.from_cp.position, RTB_ALTITUDE)
group.land_at(self.conflict.from_cp.at)
def generate_strikegroup_escort(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): def generate_strikegroup_escort(self, attackers: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
for g in self._generate_escort( for g in self._generate_escort(
@@ -261,8 +267,7 @@ class AircraftConflictGenerator:
at=at and at or self._group_point(self.conflict.air_attackers_location), at=at and at or self._group_point(self.conflict.air_attackers_location),
is_quick=at is None, is_quick=at is None,
should_orbit=True): should_orbit=True):
g.add_waypoint(self.conflict.position, WARM_START_ALTITUDE) self._rtb_for(g, self.conflict.from_cp, at)
g.land_at(self.conflict.from_cp.at)
def generate_transport_escort(self, escort: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): def generate_transport_escort(self, escort: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
for g in self._generate_escort( for g in self._generate_escort(
@@ -272,8 +277,7 @@ class AircraftConflictGenerator:
at=at and at or self._group_point(self.conflict.air_defenders_location), at=at and at or self._group_point(self.conflict.air_defenders_location),
is_quick=at is None, is_quick=at is None,
should_orbit=False): should_orbit=False):
g.add_waypoint(self.conflict.to_cp.position, RTB_ALTITUDE) self._rtb_for(g, self.conflict.to_cp, at)
g.land_at(self.conflict.to_cp.at)
def generate_defense(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None): def generate_defense(self, defenders: db.PlaneDict, clients: db.PlaneDict, at: db.StartingPosition = None):
for flying_type, count, client_count in self._split_to_groups(defenders, clients): for flying_type, count, client_count in self._split_to_groups(defenders, clients):
@@ -290,9 +294,7 @@ class AircraftConflictGenerator:
wayp.tasks.append(dcs.task.EngageTargets(max_distance=DEFENCE_ENGAGEMENT_MAX_DISTANCE)) wayp.tasks.append(dcs.task.EngageTargets(max_distance=DEFENCE_ENGAGEMENT_MAX_DISTANCE))
wayp.tasks.append(dcs.task.OrbitAction(ATTACK_CIRCLE_ALT, pattern=OrbitAction.OrbitPattern.Circle)) wayp.tasks.append(dcs.task.OrbitAction(ATTACK_CIRCLE_ALT, pattern=OrbitAction.OrbitPattern.Circle))
self._setup_group(group, CAP, client_count) self._setup_group(group, CAP, client_count)
self._rtb_for(group, self.conflict.to_cp, at)
group.add_waypoint(self.conflict.to_cp.position, RTB_ALTITUDE)
group.land_at(self.conflict.to_cp.at)
def generate_transport(self, transport: db.PlaneDict, destination: Airport): def generate_transport(self, transport: db.PlaneDict, destination: Airport):
assert len(self.escort_targets) == 0 assert len(self.escort_targets) == 0
@@ -331,9 +333,7 @@ class AircraftConflictGenerator:
wayp = group.add_waypoint(self.conflict.position, WARM_START_ALTITUDE, INTERCEPTION_AIRSPEED) wayp = group.add_waypoint(self.conflict.position, WARM_START_ALTITUDE, INTERCEPTION_AIRSPEED)
wayp.tasks.append(EngageTargets(max_distance=INTERCEPT_MAX_DISTANCE)) wayp.tasks.append(EngageTargets(max_distance=INTERCEPT_MAX_DISTANCE))
self._setup_group(group, CAP, client_count) self._setup_group(group, CAP, client_count)
self._rtb_for(group, self.conflict.from_cp, at)
group.add_waypoint(self.conflict.from_cp.position, RTB_ALTITUDE)
group.land_at(self.conflict.from_cp.at)
def generate_passenger_transport(self, helis: db.HeliDict, clients: db.HeliDict, at: db.StartingPosition): def generate_passenger_transport(self, helis: db.HeliDict, clients: db.HeliDict, at: db.StartingPosition):
for heli_type, count, client_count in self._split_to_groups(helis, clients): for heli_type, count, client_count in self._split_to_groups(helis, clients):

View File

@@ -138,6 +138,10 @@ class TriggersGenerator:
player_coalition = self.game.player == "USA" and "blue" or "red" player_coalition = self.game.player == "USA" and "blue" or "red"
enemy_coalition = player_coalition == "blue" and "red" or "blue" enemy_coalition = player_coalition == "blue" and "red" or "blue"
# dcs require at least some slots on both sides for the mission to start
self.mission.groundControl.red_observer = 1
self.mission.groundControl.blue_observer = 1
self.mission.coalition[player_coalition].bullseye = {"x": self.conflict.position.x, self.mission.coalition[player_coalition].bullseye = {"x": self.conflict.position.x,
"y": self.conflict.position.y} "y": self.conflict.position.y}

View File

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

View File

@@ -24,23 +24,23 @@ class CaucasusTheater(ConflictTheater):
soganlug = ControlPoint.from_airport(caucasus.Soganlug, LAND, SIZE_SMALL, IMPORTANCE_LOW) soganlug = ControlPoint.from_airport(caucasus.Soganlug, LAND, SIZE_SMALL, IMPORTANCE_LOW)
kutaisi = ControlPoint.from_airport(caucasus.Kutaisi, 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) 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) kobuleti = ControlPoint.from_airport(caucasus.Kobuleti, COAST_A_E, SIZE_SMALL, 1.1)
batumi = ControlPoint.from_airport(caucasus.Batumi, COAST_DL_E, SIZE_SMALL, IMPORTANCE_MEDIUM) 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, IMPORTANCE_MEDIUM) 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, IMPORTANCE_MEDIUM) 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) 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) maykop = ControlPoint.from_airport(caucasus.Maykop_Khanskaya, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
krasnodar = ControlPoint.from_airport(caucasus.Krasnodar_Center, 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) novorossiysk = ControlPoint.from_airport(caucasus.Novorossiysk, COAST_DR_E, SIZE_BIG, 1.2)
krymsk = ControlPoint.from_airport(caucasus.Krymsk, LAND, SIZE_LARGE, IMPORTANCE_HIGH) krymsk = ControlPoint.from_airport(caucasus.Krymsk, LAND, SIZE_LARGE, 1.2)
anapa = ControlPoint.from_airport(caucasus.Anapa_Vityazevo, LAND, SIZE_LARGE, IMPORTANCE_HIGH) anapa = ControlPoint.from_airport(caucasus.Anapa_Vityazevo, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
beslan = ControlPoint.from_airport(caucasus.Beslan, LAND, SIZE_REGULAR, IMPORTANCE_LOW) beslan = ControlPoint.from_airport(caucasus.Beslan, LAND, SIZE_REGULAR, IMPORTANCE_LOW)
nalchik = ControlPoint.from_airport(caucasus.Nalchik, LAND, SIZE_REGULAR, IMPORTANCE_LOW) nalchik = ControlPoint.from_airport(caucasus.Nalchik, LAND, SIZE_REGULAR, 1.1)
mineralnye = ControlPoint.from_airport(caucasus.Mineralnye_Vody, LAND, SIZE_BIG, IMPORTANCE_MEDIUM) mineralnye = ControlPoint.from_airport(caucasus.Mineralnye_Vody, LAND, SIZE_BIG, 1.3)
mozdok = ControlPoint.from_airport(caucasus.Mozdok, LAND, SIZE_BIG, IMPORTANCE_MEDIUM) mozdok = ControlPoint.from_airport(caucasus.Mozdok, LAND, SIZE_BIG, 1.1)
carrier_1 = ControlPoint.carrier("Carrier", mapping.Point(-305810.6875, 406399.1875)) 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) 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 = 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) 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) 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_MEDIUM) groom_lake = ControlPoint.from_airport(nevada.Groom_Lake_AFB, LAND, SIZE_REGULAR, IMPORTANCE_HIGH)
mesquite = ControlPoint.from_airport(nevada.Mesquite, LAND, SIZE_REGULAR, IMPORTANCE_MEDIUM) mesquite = ControlPoint.from_airport(nevada.Mesquite, LAND, SIZE_REGULAR, 1.3)
beatty = ControlPoint.from_airport(nevada.Beatty_Airport, LAND, SIZE_REGULAR, IMPORTANCE_MEDIUM) beatty = ControlPoint.from_airport(nevada.Beatty_Airport, LAND, SIZE_REGULAR, 1.1)
creech = ControlPoint.from_airport(nevada.Creech_AFB, LAND, SIZE_BIG, IMPORTANCE_HIGH) 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) 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) laughlin = ControlPoint.from_airport(nevada.Laughlin_Airport, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
def __init__(self): 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_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_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) 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, IMPORTANCE_MEDIUM) 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) dubai = ControlPoint.from_airport(persiangulf.Dubai_Intl, COAST_DL_E, SIZE_LARGE, 1.3)
sharjah = ControlPoint.from_airport(persiangulf.Sharjah_Intl, LAND, SIZE_BIG, IMPORTANCE_MEDIUM) sharjah = ControlPoint.from_airport(persiangulf.Sharjah_Intl, LAND, SIZE_BIG, 1.2)
fujairah = ControlPoint.from_airport(persiangulf.Fujairah_Intl, COAST_V_W, SIZE_REGULAR, IMPORTANCE_MEDIUM) fujairah = ControlPoint.from_airport(persiangulf.Fujairah_Intl, COAST_V_W, SIZE_REGULAR, 1.3)
khasab = ControlPoint.from_airport(persiangulf.Khasab, LAND, SIZE_SMALL, IMPORTANCE_MEDIUM) 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) 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, IMPORTANCE_MEDIUM) 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, IMPORTANCE_HIGH) 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) 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) 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) 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) 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, PinpointStrike: 12,
CAP: 8, CAP: 8,
CAS: 4, CAS: 4,
AirDefence: 2, AirDefence: 1,
} }
@@ -28,8 +28,8 @@ def generate_initial(theater: ConflictTheater, enemy: str, sams: bool, multiplie
variety = int(UNIT_VARIETY) variety = int(UNIT_VARIETY)
unittypes = db.choose_units(task, importance_factor, variety, enemy) unittypes = db.choose_units(task, importance_factor, variety, enemy)
if not sams: if not sams and task == AirDefence:
unittypes = [x for x in unittypes if x not in db.SAM_BAN] 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_log = math.log(cp.importance + 0.01, UNIT_COUNT_IMPORTANCE_LOG)
count = max(COUNT_BY_TASK[task] * multiplier * (1+count_log), 1) count = max(COUNT_BY_TASK[task] * multiplier * (1+count_log), 1)

View File

@@ -1,4 +1,5 @@
import typing import typing
import re
import threading import threading
import time import time
import os import os
@@ -14,6 +15,8 @@ from dcs.unit import UnitType
from game import db from game import db
from .persistency import base_path
DEBRIEFING_LOG_EXTENSION = "log" DEBRIEFING_LOG_EXTENSION = "log"
@@ -22,11 +25,53 @@ class Debriefing:
self.destroyed_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]] self.destroyed_units = {} # type: typing.Dict[str, typing.Dict[UnitType, int]]
self.alive_units = alive_units # type: typing.Dict[str, typing.Dict[UnitType, int]] self.alive_units = alive_units # type: typing.Dict[str, typing.Dict[UnitType, int]]
@classmethod
def parse_mp_debrief(cls, string: str):
# TODO: actually write a parser
result = {}
append = False
country = None
unit_type = None
for line in string.split("\n"):
line = line.strip()
if not append:
if line == "world_state =":
append = True
continue
if append:
if line.startswith("country"):
country = re.findall(r"country\s*=\s*(\d+),", line)[0]
if line.startswith("type"):
unit_type = re.findall(r"type\s*=\s*\"(.*?)\",", line)[0]
if country and unit_type:
result[len(result)+1] = {
"country": int(country),
"type": unit_type,
}
country = unit_type = None
if line.strip() == "} -- end of world_state":
break
return {
"debriefing": {
"world_state": result,
},
}
@classmethod @classmethod
def parse(cls, path: str): def parse(cls, path: str):
with open(path, "r") as f: with open(path, "r") as f:
table_string = f.read() table_string = f.read()
table = parse.loads(table_string) try:
table = parse.loads(table_string)
except:
table = cls.parse_mp_debrief(table_string)
units = table.get("debriefing", {}).get("world_state", {}) units = table.get("debriefing", {}).get("world_state", {})
alive_units = {} alive_units = {}
@@ -92,7 +137,7 @@ class Debriefing:
def debriefing_directory_location() -> str: 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]: def _logfiles_snapshot() -> typing.Dict[str, float]:

View File

@@ -3,13 +3,31 @@ import pickle
import os import os
import shutil import shutil
_user_folder = None # type: str
def setup(user_folder: str):
global _user_folder
_user_folder = user_folder
def base_path() -> str:
global _user_folder
assert _user_folder
openbeta_path = os.path.join(_user_folder, "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: 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: 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: def _save_file_exists() -> bool:
@@ -17,7 +35,7 @@ def _save_file_exists() -> bool:
def mission_path_for(name: str) -> str: 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(): def restore_game():