mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
gulf & nevada maps integration; updates to commisioning/start generation units logic; mission gen updates; carriers always on map
This commit is contained in:
parent
56c9f97417
commit
92e5514e8d
14
__init__.py
14
__init__.py
@ -1,5 +1,8 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import theater.caucasus
|
import theater.caucasus
|
||||||
|
import theater.persiangulf
|
||||||
|
import theater.nevada
|
||||||
|
|
||||||
import ui.window
|
import ui.window
|
||||||
import ui.mainmenu
|
import ui.mainmenu
|
||||||
import ui.newgamemenu
|
import ui.newgamemenu
|
||||||
@ -19,10 +22,15 @@ game = persistency.restore_game()
|
|||||||
if not game:
|
if not game:
|
||||||
new_game_menu = None # type: NewGameMenu
|
new_game_menu = None # type: NewGameMenu
|
||||||
|
|
||||||
def start_new_game(player_name: str, enemy_name: str):
|
def start_new_game(player_name: str, enemy_name: str, terrain: str):
|
||||||
conflicttheater = theater.caucasus.CaucasusTheater()
|
if terrain == "persiangulf":
|
||||||
start_generator.generate_initial(conflicttheater, enemy_name)
|
conflicttheater = theater.persiangulf.PersianGulfTheater()
|
||||||
|
elif terrain == "nevada":
|
||||||
|
conflicttheater = theater.nevada.NevadaTheater()
|
||||||
|
else:
|
||||||
|
conflicttheater = theater.caucasus.CaucasusTheater()
|
||||||
|
|
||||||
|
start_generator.generate_initial(conflicttheater, enemy_name)
|
||||||
proceed_to_main_menu(Game(player_name=player_name,
|
proceed_to_main_menu(Game(player_name=player_name,
|
||||||
enemy_name=enemy_name,
|
enemy_name=enemy_name,
|
||||||
theater=conflicttheater))
|
theater=conflicttheater))
|
||||||
|
|||||||
207
game/db.py
207
game/db.py
@ -8,33 +8,46 @@ from dcs.task import *
|
|||||||
from dcs.unittype import *
|
from dcs.unittype import *
|
||||||
|
|
||||||
PRICES = {
|
PRICES = {
|
||||||
# planes
|
# fighter
|
||||||
|
C_101CC: 10,
|
||||||
Su_25T: 11,
|
AJS37: 15,
|
||||||
Su_25: 11,
|
F_5E: 12,
|
||||||
A_10A: 18,
|
MiG_23MLD: 15,
|
||||||
A_10C: 20,
|
MiG_25PD: 20,
|
||||||
|
MiG_31: 30,
|
||||||
FA_18C_hornet: 18,
|
|
||||||
AV8BNA: 15,
|
|
||||||
|
|
||||||
Su_27: 30,
|
Su_27: 30,
|
||||||
Su_33: 33,
|
Su_33: 33,
|
||||||
F_15C: 30,
|
|
||||||
M_2000C: 11,
|
|
||||||
|
|
||||||
MiG_15bis: 8,
|
MiG_15bis: 8,
|
||||||
MiG_21Bis: 13,
|
MiG_21Bis: 13,
|
||||||
MiG_29A: 23,
|
MiG_29A: 23,
|
||||||
|
FA_18C_hornet: 18,
|
||||||
|
AV8BNA: 15,
|
||||||
|
F_15C: 30,
|
||||||
|
M_2000C: 15,
|
||||||
|
|
||||||
|
# bomber
|
||||||
|
Su_25T: 15,
|
||||||
|
Su_24M: 18,
|
||||||
|
Su_17M4: 13,
|
||||||
|
L_39ZA: 10,
|
||||||
|
MiG_29G: 18,
|
||||||
|
Su_34: 22,
|
||||||
|
|
||||||
|
A_10A: 18,
|
||||||
|
A_10C: 20,
|
||||||
|
|
||||||
|
# special
|
||||||
IL_76MD: 13,
|
IL_76MD: 13,
|
||||||
|
An_26B: 13,
|
||||||
|
An_30M: 13,
|
||||||
|
Yak_40: 13,
|
||||||
S_3B_Tanker: 13,
|
S_3B_Tanker: 13,
|
||||||
|
|
||||||
A_50: 8,
|
A_50: 8,
|
||||||
E_3A: 8,
|
E_3A: 8,
|
||||||
|
C_130: 8,
|
||||||
|
|
||||||
# armor
|
# armor
|
||||||
|
|
||||||
Armor.MBT_T_55: 4,
|
Armor.MBT_T_55: 4,
|
||||||
Armor.MBT_T_80U: 8,
|
Armor.MBT_T_80U: 8,
|
||||||
Armor.MBT_T_90: 10,
|
Armor.MBT_T_90: 10,
|
||||||
@ -45,49 +58,142 @@ PRICES = {
|
|||||||
Armor.ATGM_M1134_Stryker: 6,
|
Armor.ATGM_M1134_Stryker: 6,
|
||||||
Armor.APC_BTR_80: 6,
|
Armor.APC_BTR_80: 6,
|
||||||
|
|
||||||
AirDefence.AAA_ZU_23_on_Ural_375: 4,
|
AirDefence.AAA_Vulcan_M163: 5,
|
||||||
AirDefence.SAM_Avenger_M1097: 10,
|
AirDefence.SAM_Avenger_M1097: 10,
|
||||||
|
AirDefence.SAM_Patriot_ICC: 15,
|
||||||
|
|
||||||
|
AirDefence.AAA_ZU_23_on_Ural_375: 5,
|
||||||
|
AirDefence.SAM_SA_18_Igla_MANPADS: 8,
|
||||||
|
AirDefence.SAM_SA_19_Tunguska_2S6: 10,
|
||||||
|
AirDefence.SAM_SA_8_Osa_9A33: 15,
|
||||||
|
|
||||||
|
# ship
|
||||||
|
CV_1143_5_Admiral_Kuznetsov: 100,
|
||||||
|
CVN_74_John_C__Stennis: 100,
|
||||||
}
|
}
|
||||||
|
|
||||||
UNIT_BY_TASK = {
|
UNIT_BY_TASK = {
|
||||||
FighterSweep: [Su_27, Su_33, FA_18C_hornet, F_15C, MiG_21Bis, MiG_29A, F_A_18C, AV8BNA, ],
|
FighterSweep: [
|
||||||
CAS: [Su_25T, A_10A, A_10C, ],
|
C_101CC,
|
||||||
Transport: [IL_76MD, S_3B_Tanker, ],
|
AJS37,
|
||||||
|
F_5E,
|
||||||
|
MiG_23MLD,
|
||||||
|
MiG_25PD,
|
||||||
|
MiG_31,
|
||||||
|
Su_27,
|
||||||
|
Su_33,
|
||||||
|
MiG_15bis,
|
||||||
|
MiG_21Bis,
|
||||||
|
MiG_29A,
|
||||||
|
FA_18C_hornet,
|
||||||
|
AV8BNA,
|
||||||
|
F_15C,
|
||||||
|
M_2000C,
|
||||||
|
],
|
||||||
|
CAS: [
|
||||||
|
A_10A,
|
||||||
|
A_10C,
|
||||||
|
Su_25T,
|
||||||
|
Su_24M,
|
||||||
|
Su_17M4,
|
||||||
|
L_39ZA,
|
||||||
|
MiG_29G,
|
||||||
|
Su_34,
|
||||||
|
],
|
||||||
|
|
||||||
|
Transport: [
|
||||||
|
IL_76MD,
|
||||||
|
An_26B,
|
||||||
|
An_30M,
|
||||||
|
Yak_40,
|
||||||
|
|
||||||
|
S_3B_Tanker,
|
||||||
|
C_130,
|
||||||
|
],
|
||||||
AWACS: [E_3A, A_50, ],
|
AWACS: [E_3A, A_50, ],
|
||||||
|
|
||||||
CAP: [Armor.MBT_T_90, Armor.MBT_T_80U, Armor.MBT_T_55, Armor.MBT_M1A2_Abrams, Armor.MBT_M60A3_Patton, Armor.ATGM_M1134_Stryker, Armor.APC_BTR_80, ],
|
CAP: [Armor.MBT_T_90, Armor.MBT_T_80U, Armor.MBT_T_55, Armor.MBT_M1A2_Abrams, Armor.MBT_M60A3_Patton, Armor.ATGM_M1134_Stryker, Armor.APC_BTR_80, ],
|
||||||
AirDefence: [AirDefence.AAA_ZU_23_on_Ural_375, AirDefence.SAM_Avenger_M1097 ],
|
AirDefence: [
|
||||||
|
AirDefence.AAA_Vulcan_M163,
|
||||||
|
AirDefence.SAM_Avenger_M1097,
|
||||||
|
AirDefence.SAM_Patriot_ICC,
|
||||||
|
|
||||||
|
AirDefence.AAA_ZU_23_on_Ural_375,
|
||||||
|
AirDefence.SAM_SA_18_Igla_MANPADS,
|
||||||
|
AirDefence.SAM_SA_19_Tunguska_2S6,
|
||||||
|
AirDefence.SAM_SA_8_Osa_9A33,
|
||||||
|
],
|
||||||
Carriage: [CVN_74_John_C__Stennis, CV_1143_5_Admiral_Kuznetsov, ],
|
Carriage: [CVN_74_John_C__Stennis, CV_1143_5_Admiral_Kuznetsov, ],
|
||||||
}
|
}
|
||||||
|
|
||||||
UNIT_BY_COUNTRY = {
|
UNIT_BY_COUNTRY = {
|
||||||
"Russia": [
|
"Russia": [
|
||||||
Su_25T,
|
C_101CC,
|
||||||
|
AJS37,
|
||||||
|
F_5E,
|
||||||
|
MiG_23MLD,
|
||||||
|
MiG_25PD,
|
||||||
|
MiG_31,
|
||||||
Su_27,
|
Su_27,
|
||||||
Su_33,
|
Su_33,
|
||||||
Su_25,
|
MiG_15bis,
|
||||||
MiG_21Bis,
|
MiG_21Bis,
|
||||||
MiG_29A,
|
MiG_29A,
|
||||||
|
M_2000C,
|
||||||
|
|
||||||
|
A_10A,
|
||||||
|
A_10C,
|
||||||
|
Su_25T,
|
||||||
|
Su_24M,
|
||||||
|
Su_17M4,
|
||||||
|
L_39ZA,
|
||||||
|
MiG_29G,
|
||||||
|
Su_34,
|
||||||
|
|
||||||
|
IL_76MD,
|
||||||
|
An_26B,
|
||||||
|
An_30M,
|
||||||
|
Yak_40,
|
||||||
A_50,
|
A_50,
|
||||||
|
|
||||||
AirDefence.AAA_ZU_23_on_Ural_375,
|
AirDefence.AAA_ZU_23_on_Ural_375,
|
||||||
|
AirDefence.SAM_SA_18_Igla_MANPADS,
|
||||||
|
AirDefence.SAM_SA_19_Tunguska_2S6,
|
||||||
|
AirDefence.SAM_SA_8_Osa_9A33,
|
||||||
|
|
||||||
Armor.APC_BTR_80,
|
Armor.APC_BTR_80,
|
||||||
Armor.MBT_T_90,
|
Armor.MBT_T_90,
|
||||||
Armor.MBT_T_80U,
|
Armor.MBT_T_80U,
|
||||||
Armor.MBT_T_55,
|
Armor.MBT_T_55,
|
||||||
IL_76MD,
|
|
||||||
CV_1143_5_Admiral_Kuznetsov],
|
CV_1143_5_Admiral_Kuznetsov],
|
||||||
|
|
||||||
"USA": [F_15C,
|
"USA": [
|
||||||
A_10C,
|
F_15C,
|
||||||
FA_18C_hornet,
|
FA_18C_hornet,
|
||||||
AV8BNA,
|
AV8BNA,
|
||||||
E_3A,
|
AJS37,
|
||||||
Armor.MBT_M1A2_Abrams,
|
F_5E,
|
||||||
Armor.MBT_M60A3_Patton,
|
M_2000C,
|
||||||
Armor.ATGM_M1134_Stryker,
|
MiG_21Bis,
|
||||||
S_3B_Tanker,
|
MiG_15bis,
|
||||||
AirDefence.SAM_Avenger_M1097,
|
|
||||||
CVN_74_John_C__Stennis],
|
A_10A,
|
||||||
|
A_10C,
|
||||||
|
|
||||||
|
S_3B_Tanker,
|
||||||
|
C_130,
|
||||||
|
E_3A,
|
||||||
|
|
||||||
|
Armor.MBT_M1A2_Abrams,
|
||||||
|
Armor.MBT_M60A3_Patton,
|
||||||
|
Armor.ATGM_M1134_Stryker,
|
||||||
|
|
||||||
|
AirDefence.AAA_Vulcan_M163,
|
||||||
|
AirDefence.SAM_Avenger_M1097,
|
||||||
|
AirDefence.SAM_Patriot_ICC,
|
||||||
|
|
||||||
|
CVN_74_John_C__Stennis,
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
PLANE_PAYLOAD_OVERRIDES = {
|
PLANE_PAYLOAD_OVERRIDES = {
|
||||||
@ -132,3 +238,38 @@ def task_name(task) -> str:
|
|||||||
return "AirDefence"
|
return "AirDefence"
|
||||||
else:
|
else:
|
||||||
return task.name
|
return task.name
|
||||||
|
|
||||||
|
|
||||||
|
def choose_units(for_task: Task, factor: float, count: int, country: str) -> typing.Collection[UnitType]:
|
||||||
|
suitable_unittypes = find_unittype(for_task, country)
|
||||||
|
suitable_unittypes.sort(key=lambda x: PRICES[x])
|
||||||
|
|
||||||
|
idx = int(len(suitable_unittypes) * factor)
|
||||||
|
variety = int(count + count * factor / 2)
|
||||||
|
|
||||||
|
index_start = min(idx, len(suitable_unittypes) - variety)
|
||||||
|
index_end = min(idx + variety, len(suitable_unittypes))
|
||||||
|
return suitable_unittypes[index_start:index_end]
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_db():
|
||||||
|
# check unit by task uniquity
|
||||||
|
total_set = set()
|
||||||
|
for t, unit_collection in UNIT_BY_TASK.items():
|
||||||
|
for unit_type in unit_collection:
|
||||||
|
assert unit_type not in total_set, "{} is duplicate".format(unit_type)
|
||||||
|
total_set.add(unit_type)
|
||||||
|
|
||||||
|
# check country allegiance
|
||||||
|
for unit_type in total_set:
|
||||||
|
did_find = False
|
||||||
|
for country_units_list in UNIT_BY_COUNTRY.values():
|
||||||
|
if unit_type in country_units_list:
|
||||||
|
did_find = True
|
||||||
|
assert did_find, "{} not in country list".format(unit_type)
|
||||||
|
|
||||||
|
# check prices
|
||||||
|
for unit_type in total_set:
|
||||||
|
assert unit_type in PRICES, "{} not in prices".format(unit_type)
|
||||||
|
|
||||||
|
_validate_db()
|
||||||
@ -26,13 +26,13 @@ class Event:
|
|||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
||||||
self.operation.prepare(is_quick=False)
|
self.operation.prepare(self.game.theater.terrain, is_quick=False)
|
||||||
self.operation.generate()
|
self.operation.generate()
|
||||||
self.operation.mission.save("build/nextturn.miz")
|
self.operation.mission.save("build/nextturn.miz")
|
||||||
|
|
||||||
def generate_quick(self):
|
def generate_quick(self):
|
||||||
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
self.operation.is_awacs_enabled = self.is_awacs_enabled
|
||||||
self.operation.prepare(is_quick=True)
|
self.operation.prepare(self.game.theater.terrain, is_quick=True)
|
||||||
self.operation.generate()
|
self.operation.generate()
|
||||||
self.operation.mission.save('build/nextturn_quick.miz')
|
self.operation.mission.save('build/nextturn_quick.miz')
|
||||||
|
|
||||||
@ -88,7 +88,7 @@ class GroundInterceptEvent(Event):
|
|||||||
else:
|
else:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def player_attacking(self, position: Point, strikegroup: db.PlaneDict, clients: db.PlaneDict):
|
def player_attacking(self, strikegroup: db.PlaneDict, clients: db.PlaneDict):
|
||||||
suitable_unittypes = db.find_unittype(CAP, self.defender_name)
|
suitable_unittypes = db.find_unittype(CAP, self.defender_name)
|
||||||
random.shuffle(suitable_unittypes)
|
random.shuffle(suitable_unittypes)
|
||||||
unittypes = suitable_unittypes[:self.TARGET_VARIETY]
|
unittypes = suitable_unittypes[:self.TARGET_VARIETY]
|
||||||
@ -100,9 +100,9 @@ class GroundInterceptEvent(Event):
|
|||||||
defender_name=self.defender_name,
|
defender_name=self.defender_name,
|
||||||
attacker_clients=clients,
|
attacker_clients=clients,
|
||||||
defender_clients={},
|
defender_clients={},
|
||||||
from_cp=self.from_cp)
|
from_cp=self.from_cp,
|
||||||
op.setup(position=position,
|
to_cp=self.to_cp)
|
||||||
target=self.targets,
|
op.setup(target=self.targets,
|
||||||
strikegroup=strikegroup)
|
strikegroup=strikegroup)
|
||||||
|
|
||||||
self.operation = op
|
self.operation = op
|
||||||
|
|||||||
11
game/game.py
11
game/game.py
@ -9,6 +9,7 @@ COMMISION_LIMITS_FACTORS = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
COMMISION_AMOUNTS_SCALE = 2
|
COMMISION_AMOUNTS_SCALE = 2
|
||||||
|
COMMISION_UNIT_VARIETY = 4
|
||||||
COMMISION_AMOUNTS_FACTORS = {
|
COMMISION_AMOUNTS_FACTORS = {
|
||||||
CAP: 0.6,
|
CAP: 0.6,
|
||||||
CAS: 0.3,
|
CAS: 0.3,
|
||||||
@ -85,7 +86,6 @@ class Game:
|
|||||||
enemy_interception = True
|
enemy_interception = True
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|
||||||
if to_cp in self.theater.conflicts(False):
|
if to_cp in self.theater.conflicts(False):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -120,8 +120,10 @@ class Game:
|
|||||||
break
|
break
|
||||||
|
|
||||||
def _generate_globalinterceptions(self):
|
def _generate_globalinterceptions(self):
|
||||||
|
global_count = len([x for x in self.theater.player_points() if x.is_global])
|
||||||
for from_cp in [x for x in self.theater.player_points() if x.is_global]:
|
for from_cp in [x for x in self.theater.player_points() if x.is_global]:
|
||||||
probability = PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE * math.log(len(self.theater.player_points()) + 1, PLAYER_INTERCEPT_GLOBAL_PROBABILITY_LOG)
|
probability_base = max(PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE / global_count, 1)
|
||||||
|
probability = probability_base * math.log(len(self.theater.player_points()) + 1, PLAYER_INTERCEPT_GLOBAL_PROBABILITY_LOG)
|
||||||
if self._roll(probability, from_cp.base.strength):
|
if self._roll(probability, from_cp.base.strength):
|
||||||
to_cp = random.choice([x for x in self.theater.enemy_points() if x not in self.theater.conflicts()])
|
to_cp = random.choice([x for x in self.theater.enemy_points() if x not in self.theater.conflicts()])
|
||||||
self.events.append(InterceptEvent(attacker_name=self.player,
|
self.events.append(InterceptEvent(attacker_name=self.player,
|
||||||
@ -139,8 +141,9 @@ class Game:
|
|||||||
awarded_points = COMMISION_AMOUNTS_FACTORS[for_task] * math.pow(cp.importance, COMMISION_AMOUNTS_SCALE)
|
awarded_points = COMMISION_AMOUNTS_FACTORS[for_task] * math.pow(cp.importance, COMMISION_AMOUNTS_SCALE)
|
||||||
points_to_spend = cp.base.append_commision_points(for_task, awarded_points)
|
points_to_spend = cp.base.append_commision_points(for_task, awarded_points)
|
||||||
if points_to_spend > 0:
|
if points_to_spend > 0:
|
||||||
unit_type = random.choice(db.find_unittype(for_task, self.enemy))
|
importance_factor = (cp.importance - IMPORTANCE_LOW) / (IMPORTANCE_HIGH - IMPORTANCE_LOW)
|
||||||
cp.base.commision_units({unit_type: points_to_spend})
|
unittypes = db.choose_units(for_task, importance_factor, COMMISION_UNIT_VARIETY, self.enemy)
|
||||||
|
cp.base.commision_units({random.choice(unittypes): points_to_spend})
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def budget_reward_amount(self):
|
def budget_reward_amount(self):
|
||||||
|
|||||||
@ -58,7 +58,8 @@ class Operation:
|
|||||||
enemy_name = self.from_cp.captured and self.defender_name or self.attacker_name
|
enemy_name = self.from_cp.captured and self.defender_name or self.attacker_name
|
||||||
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, is_quick: bool):
|
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
|
||||||
|
self.mission = dcs.Mission(terrain)
|
||||||
self.is_quick = is_quick
|
self.is_quick = is_quick
|
||||||
|
|
||||||
if is_quick:
|
if is_quick:
|
||||||
@ -66,14 +67,25 @@ class Operation:
|
|||||||
self.defenders_starting_position = None
|
self.defenders_starting_position = None
|
||||||
else:
|
else:
|
||||||
self.attackers_starting_position = self.from_cp.at
|
self.attackers_starting_position = self.from_cp.at
|
||||||
self.defenders_starting_position = self.to_cp and self.to_cp.at or None
|
self.defenders_starting_position = self.to_cp.at
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
self.extra_aagen.generate()
|
|
||||||
self.envgen.generate(self.is_quick)
|
|
||||||
if self.is_awacs_enabled:
|
if self.is_awacs_enabled:
|
||||||
self.awacsgen.generate()
|
self.awacsgen.generate()
|
||||||
|
|
||||||
|
self.extra_aagen.generate()
|
||||||
|
self.envgen.generate(self.is_quick)
|
||||||
|
|
||||||
|
for global_cp in self.game.theater.controlpoints:
|
||||||
|
if not global_cp.is_global:
|
||||||
|
continue
|
||||||
|
|
||||||
|
ship = self.shipgen.generate(type=db.find_unittype(Carriage, self.attacker_name)[0],
|
||||||
|
at=global_cp.at)
|
||||||
|
|
||||||
|
if global_cp == self.from_cp and not self.is_quick:
|
||||||
|
self.attackers_starting_position = ship
|
||||||
|
|
||||||
def units_of(self, country_name: str) -> typing.Collection[UnitType]:
|
def units_of(self, country_name: str) -> typing.Collection[UnitType]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
@ -103,14 +115,12 @@ class CaptureOperation(Operation):
|
|||||||
self.defense = defense
|
self.defense = defense
|
||||||
self.aa = aa
|
self.aa = aa
|
||||||
|
|
||||||
def prepare(self, is_quick: bool):
|
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
|
||||||
super(CaptureOperation, self).prepare(is_quick)
|
super(CaptureOperation, self).prepare(terrain, is_quick)
|
||||||
mission = dcs.Mission()
|
self.initialize(mission=self.mission,
|
||||||
|
|
||||||
self.initialize(mission=mission,
|
|
||||||
conflict=self.to_cp.conflict_attack(self.from_cp,
|
conflict=self.to_cp.conflict_attack(self.from_cp,
|
||||||
mission.country(self.attacker_name),
|
self.mission.country(self.attacker_name),
|
||||||
mission.country(self.defender_name)))
|
self.mission.country(self.defender_name)))
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
self.armorgen.generate(self.attack, self.defense)
|
self.armorgen.generate(self.attack, self.defense)
|
||||||
@ -140,18 +150,16 @@ class InterceptOperation(Operation):
|
|||||||
self.airdefense = airdefense
|
self.airdefense = airdefense
|
||||||
self.interceptors = interceptors
|
self.interceptors = interceptors
|
||||||
|
|
||||||
def prepare(self, is_quick: bool):
|
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
|
||||||
super(InterceptOperation, self).prepare(is_quick)
|
super(InterceptOperation, self).prepare(terrain, is_quick)
|
||||||
mission = dcs.Mission()
|
|
||||||
|
|
||||||
conflict = Conflict.intercept_conflict(
|
conflict = Conflict.intercept_conflict(
|
||||||
attacker=mission.country(self.attacker_name),
|
attacker=self.mission.country(self.attacker_name),
|
||||||
defender=mission.country(self.defender_name),
|
defender=self.mission.country(self.defender_name),
|
||||||
from_cp=self.from_cp,
|
from_cp=self.from_cp,
|
||||||
to_cp=self.to_cp
|
to_cp=self.to_cp
|
||||||
)
|
)
|
||||||
|
|
||||||
self.initialize(mission=mission,
|
self.initialize(mission=self.mission,
|
||||||
conflict=conflict)
|
conflict=conflict)
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
@ -159,40 +167,30 @@ class InterceptOperation(Operation):
|
|||||||
self.airgen.generate_transport_escort(self.escort, clients=self.defender_clients)
|
self.airgen.generate_transport_escort(self.escort, clients=self.defender_clients)
|
||||||
|
|
||||||
if self.from_cp.is_global:
|
if self.from_cp.is_global:
|
||||||
starting_ship = self.shipgen.generate(type=db.find_unittype(Carriage, self.attacker_name)[0],
|
super(InterceptOperation, self).generate()
|
||||||
at=self.from_cp.at)
|
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.attackers_starting_position)
|
||||||
|
|
||||||
if self.is_quick:
|
|
||||||
starting_ship = None
|
|
||||||
|
|
||||||
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=starting_ship)
|
|
||||||
else:
|
else:
|
||||||
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.attackers_starting_position)
|
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.attackers_starting_position)
|
||||||
|
super(InterceptOperation, self).generate()
|
||||||
super(InterceptOperation, self).generate()
|
|
||||||
|
|
||||||
|
|
||||||
class GroundInterceptOperation(Operation):
|
class GroundInterceptOperation(Operation):
|
||||||
def setup(self,
|
def setup(self,
|
||||||
position: Point,
|
|
||||||
target: db.ArmorDict,
|
target: db.ArmorDict,
|
||||||
strikegroup: db.PlaneDict):
|
strikegroup: db.PlaneDict):
|
||||||
self.position = position
|
|
||||||
self.strikegroup = strikegroup
|
self.strikegroup = strikegroup
|
||||||
self.target = target
|
self.target = target
|
||||||
|
|
||||||
def prepare(self, is_quick: bool):
|
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
|
||||||
super(GroundInterceptOperation, self).prepare(is_quick)
|
super(GroundInterceptOperation, self).prepare(terrain, is_quick)
|
||||||
mission = dcs.Mission()
|
|
||||||
conflict = Conflict.ground_intercept_conflict(
|
conflict = Conflict.ground_intercept_conflict(
|
||||||
attacker=mission.country(self.attacker_name),
|
attacker=self.mission.country(self.attacker_name),
|
||||||
defender=mission.country(self.defender_name),
|
defender=self.mission.country(self.defender_name),
|
||||||
position=self.position,
|
heading=self.to_cp.position.heading_between_point(self.from_cp.position),
|
||||||
heading=randint(0, 360),
|
cp=self.to_cp
|
||||||
radials=ALL_RADIALS
|
|
||||||
)
|
)
|
||||||
|
|
||||||
self.initialize(mission=mission,
|
self.initialize(mission=self.mission,
|
||||||
conflict=conflict)
|
conflict=conflict)
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
|
|||||||
@ -7,8 +7,8 @@ from .naming import *
|
|||||||
from dcs.mission import *
|
from dcs.mission import *
|
||||||
|
|
||||||
DISTANCE_FACTOR = 4, 5
|
DISTANCE_FACTOR = 4, 5
|
||||||
EXTRA_AA_MIN_DISTANCE = 70000
|
EXTRA_AA_MIN_DISTANCE = 35000
|
||||||
EXTRA_AA_POSITION_FROM_CP = 10000
|
EXTRA_AA_POSITION_FROM_CP = 550
|
||||||
|
|
||||||
class AAConflictGenerator:
|
class AAConflictGenerator:
|
||||||
def __init__(self, mission: Mission, conflict: Conflict):
|
def __init__(self, mission: Mission, conflict: Conflict):
|
||||||
|
|||||||
@ -72,6 +72,8 @@ class AircraftConflictGenerator:
|
|||||||
for unit_instance in group.units:
|
for unit_instance in group.units:
|
||||||
unit_instance.livery_id = db.PLANE_LIVERY_OVERRIDES[unit_type]
|
unit_instance.livery_id = db.PLANE_LIVERY_OVERRIDES[unit_type]
|
||||||
|
|
||||||
|
print("AC: {} {}".format(unit_type, len(group.units)))
|
||||||
|
|
||||||
def _generate_at_airport(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, airport: Airport = None) -> FlyingGroup:
|
def _generate_at_airport(self, name: str, side: Country, unit_type: FlyingType, count: int, client_count: int, airport: Airport = None) -> FlyingGroup:
|
||||||
assert count > 0
|
assert count > 0
|
||||||
assert unit is not None
|
assert unit is not None
|
||||||
|
|||||||
@ -8,6 +8,9 @@ from dcs.unittype import *
|
|||||||
from dcs.task import *
|
from dcs.task import *
|
||||||
from dcs.terrain.terrain import NoParkingSlotError
|
from dcs.terrain.terrain import NoParkingSlotError
|
||||||
|
|
||||||
|
AWACS_DISTANCE = 150000
|
||||||
|
AWACS_ALT = 10000
|
||||||
|
|
||||||
|
|
||||||
class AWACSConflictGenerator:
|
class AWACSConflictGenerator:
|
||||||
def __init__(self, mission: Mission, conflict: Conflict, game):
|
def __init__(self, mission: Mission, conflict: Conflict, game):
|
||||||
@ -22,5 +25,6 @@ class AWACSConflictGenerator:
|
|||||||
country=self.conflict.attackers_side,
|
country=self.conflict.attackers_side,
|
||||||
name=namegen.next_awacs_group_name(),
|
name=namegen.next_awacs_group_name(),
|
||||||
plane_type=plane,
|
plane_type=plane,
|
||||||
|
altitude=AWACS_ALT,
|
||||||
airport=None,
|
airport=None,
|
||||||
position=self.conflict.position)
|
position=self.conflict.position.random_point_within(AWACS_DISTANCE, AWACS_DISTANCE))
|
||||||
|
|||||||
@ -14,10 +14,8 @@ from dcs.point import *
|
|||||||
from dcs.task import *
|
from dcs.task import *
|
||||||
from dcs.country import *
|
from dcs.country import *
|
||||||
|
|
||||||
def _opposite_heading(h):
|
|
||||||
return h+180
|
|
||||||
|
|
||||||
GROUND_DISTANCE_FACTOR = 2
|
GROUND_DISTANCE_FACTOR = 2
|
||||||
|
GROUNDINTERCEPT_DISTANCE_FACTOR = 6
|
||||||
AIR_DISTANCE = 32000
|
AIR_DISTANCE = 32000
|
||||||
|
|
||||||
INTERCEPT_ATTACKERS_HEADING = -45, 45
|
INTERCEPT_ATTACKERS_HEADING = -45, 45
|
||||||
@ -28,6 +26,10 @@ INTERCEPT_MAX_DISTANCE = 80000
|
|||||||
INTERCEPT_MIN_DISTANCE = 45000
|
INTERCEPT_MIN_DISTANCE = 45000
|
||||||
|
|
||||||
|
|
||||||
|
def _opposite_heading(h):
|
||||||
|
return h+180
|
||||||
|
|
||||||
|
|
||||||
class Conflict:
|
class Conflict:
|
||||||
attackers_side = None # type: Country
|
attackers_side = None # type: Country
|
||||||
defenders_side = None # type: Country
|
defenders_side = None # type: Country
|
||||||
@ -81,18 +83,18 @@ class Conflict:
|
|||||||
return instance
|
return instance
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def ground_intercept_conflict(self, attacker: Country, defender: Country, position: Point, heading: int, radials: typing.List[int]):
|
def ground_intercept_conflict(self, attacker: Country, defender: Country, heading: int, cp):
|
||||||
from theater.conflicttheater import SIZE_SMALL
|
from theater.conflicttheater import SIZE_SMALL
|
||||||
|
|
||||||
instance = self()
|
instance = self()
|
||||||
instance.attackers_side = attacker
|
instance.attackers_side = attacker
|
||||||
instance.defenders_side = defender
|
instance.defenders_side = defender
|
||||||
|
|
||||||
instance.position = position
|
instance.position = cp.position
|
||||||
instance.size = SIZE_SMALL
|
instance.size = cp.size
|
||||||
instance.radials = radials
|
instance.radials = cp.radials
|
||||||
|
|
||||||
instance.air_attackers_location = instance.position.point_from_heading(random.randint(*INTERCEPT_ATTACKERS_HEADING) + heading, AIR_DISTANCE)
|
instance.air_attackers_location = instance.position.point_from_heading(random.randint(*INTERCEPT_ATTACKERS_HEADING) + heading, AIR_DISTANCE)
|
||||||
instance.ground_defenders_location = instance.position
|
instance.ground_defenders_location = instance.position.point_from_heading(random.choice(cp.radials), instance.size * GROUNDINTERCEPT_DISTANCE_FACTOR)
|
||||||
|
|
||||||
return instance
|
return instance
|
||||||
|
|||||||
@ -6,6 +6,7 @@ from dcs.mission import Mission
|
|||||||
from dcs.triggers import *
|
from dcs.triggers import *
|
||||||
from dcs.condition import *
|
from dcs.condition import *
|
||||||
from dcs.action import *
|
from dcs.action import *
|
||||||
|
from dcs.task import *
|
||||||
|
|
||||||
from theater.weatherforecast import WeatherForecast
|
from theater.weatherforecast import WeatherForecast
|
||||||
from theater.conflicttheater import Conflict
|
from theater.conflicttheater import Conflict
|
||||||
@ -14,18 +15,17 @@ ACTIVATION_TRIGGER_SIZE = 80000
|
|||||||
ACTIVATION_TRIGGER_MIN_DISTANCE = 5000
|
ACTIVATION_TRIGGER_MIN_DISTANCE = 5000
|
||||||
|
|
||||||
RANDOM_TIME = {
|
RANDOM_TIME = {
|
||||||
"night": 0,
|
"night": 5,
|
||||||
"dusk": 5,
|
"dusk": 30,
|
||||||
"dawn": 35,
|
"dawn": 30,
|
||||||
"noon": 75,
|
|
||||||
"day": 100,
|
"day": 100,
|
||||||
}
|
}
|
||||||
|
|
||||||
RANDOM_WEATHER = {
|
RANDOM_WEATHER = {
|
||||||
0: 0, # thunderstorm
|
0: 5, # thunderstorm
|
||||||
1: 5, # heavy rain
|
1: 20, # heavy rain
|
||||||
2: 20, # rain
|
2: 30, # rain
|
||||||
3: 40, # random dynamic
|
3: 100, # random dynamic
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -36,17 +36,7 @@ class EnvironmentSettingsGenerator:
|
|||||||
self.game = game
|
self.game = game
|
||||||
|
|
||||||
def _gen_random_time(self):
|
def _gen_random_time(self):
|
||||||
time_roll = random.randint(0, 100)
|
start_time = datetime.today()
|
||||||
time_period = None
|
|
||||||
for k, v in RANDOM_TIME.items():
|
|
||||||
if v >= time_roll:
|
|
||||||
time_period = k
|
|
||||||
break
|
|
||||||
|
|
||||||
self.mission.random_daytime(time_period)
|
|
||||||
|
|
||||||
def _gen_random_time_2(self):
|
|
||||||
start_time = datetime.now(self.mission.start_time.tzinfo).date()
|
|
||||||
daytime_map = {
|
daytime_map = {
|
||||||
"day": timedelta(hours=random.randrange(9, 18)),
|
"day": timedelta(hours=random.randrange(9, 18)),
|
||||||
"night": timedelta(hours=random.randrange(-3, 6)),
|
"night": timedelta(hours=random.randrange(-3, 6)),
|
||||||
@ -54,24 +44,24 @@ class EnvironmentSettingsGenerator:
|
|||||||
"dawn": timedelta(hours=random.randrange(6, 9)),
|
"dawn": timedelta(hours=random.randrange(6, 9)),
|
||||||
}
|
}
|
||||||
|
|
||||||
time_roll = random.randint(0, 100)
|
|
||||||
time_period = None
|
time_period = None
|
||||||
for k, v in RANDOM_TIME.items():
|
for k, v in RANDOM_TIME.items():
|
||||||
if v >= time_roll:
|
if random.randint(0, 100) <= v:
|
||||||
time_period = k
|
time_period = k
|
||||||
break
|
break
|
||||||
|
|
||||||
|
print("generated {}".format(time_period))
|
||||||
start_time += daytime_map[time_period]
|
start_time += daytime_map[time_period]
|
||||||
self.mission.start_time = start_time
|
self.mission.start_time = start_time
|
||||||
|
|
||||||
def _gen_random_weather(self):
|
def _gen_random_weather(self):
|
||||||
weather_roll = random.randint(0, 100)
|
|
||||||
weather_type = None
|
weather_type = None
|
||||||
for k, v in RANDOM_TIME.items():
|
for k, v in RANDOM_WEATHER.items():
|
||||||
if v >= weather_roll:
|
if random.randint(0, 100) <= v:
|
||||||
weather_type = k
|
weather_type = k
|
||||||
break
|
break
|
||||||
|
|
||||||
|
print("generated weather {}".format(weather_type))
|
||||||
if weather_type == 0:
|
if weather_type == 0:
|
||||||
self.mission.weather.random_thunderstorm()
|
self.mission.weather.random_thunderstorm()
|
||||||
elif weather_type == 1:
|
elif weather_type == 1:
|
||||||
@ -116,9 +106,10 @@ class EnvironmentSettingsGenerator:
|
|||||||
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"
|
||||||
|
|
||||||
self.mission.coalition[player_coalition].bullseye = self.conflict.position
|
self.mission.coalition[player_coalition].bullseye = {"x": self.conflict.position.x,
|
||||||
|
"y": self.conflict.position.y}
|
||||||
|
|
||||||
self._gen_random_time_2()
|
self._gen_random_time()
|
||||||
self._gen_random_weather()
|
self._gen_random_weather()
|
||||||
self._set_allegiances(player_coalition, enemy_coalition)
|
self._set_allegiances(player_coalition, enemy_coalition)
|
||||||
|
|
||||||
|
|||||||
@ -6,6 +6,8 @@ from .base import *
|
|||||||
|
|
||||||
|
|
||||||
class CaucasusTheater(ConflictTheater):
|
class CaucasusTheater(ConflictTheater):
|
||||||
|
terrain = caucasus.Caucasus()
|
||||||
|
overview_image = "caumap.gif"
|
||||||
reference_points = {(-317948.32727306, 635639.37385346): (282.5, 319),
|
reference_points = {(-317948.32727306, 635639.37385346): (282.5, 319),
|
||||||
(-355692.3067714, 617269.96285781): (269, 352), }
|
(-355692.3067714, 617269.96285781): (269, 352), }
|
||||||
|
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import dcs
|
|||||||
|
|
||||||
from .controlpoint import *
|
from .controlpoint import *
|
||||||
|
|
||||||
|
SIZE_TINY = 150
|
||||||
SIZE_SMALL = 600
|
SIZE_SMALL = 600
|
||||||
SIZE_REGULAR = 1000
|
SIZE_REGULAR = 1000
|
||||||
SIZE_BIG = 2000
|
SIZE_BIG = 2000
|
||||||
@ -29,6 +30,7 @@ class ConflictTheater:
|
|||||||
terrain = None # type: dcs.terrain.Terrain
|
terrain = None # type: dcs.terrain.Terrain
|
||||||
controlpoints = None # type: typing.Collection[ControlPoint]
|
controlpoints = None # type: typing.Collection[ControlPoint]
|
||||||
reference_points = None # type: typing.Dict
|
reference_points = None # type: typing.Dict
|
||||||
|
overview_image = None # type: str
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.controlpoints = []
|
self.controlpoints = []
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import typing
|
import typing
|
||||||
|
import re
|
||||||
|
|
||||||
from dcs.mapping import *
|
from dcs.mapping import *
|
||||||
from dcs.country import *
|
from dcs.country import *
|
||||||
@ -17,7 +18,8 @@ class ControlPoint:
|
|||||||
def __init__(self, name: str, position: Point, at, radials: typing.Collection[int], size: int, importance: int):
|
def __init__(self, name: str, position: Point, at, radials: typing.Collection[int], size: int, importance: int):
|
||||||
import theater.base
|
import theater.base
|
||||||
|
|
||||||
self.name = name.split("-")[0]
|
self.name = " ".join(re.split(r" |-", name)[:2])
|
||||||
|
self.full_name = name
|
||||||
self.position = position
|
self.position = position
|
||||||
self.at = at
|
self.at = at
|
||||||
|
|
||||||
@ -30,6 +32,7 @@ class ControlPoint:
|
|||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_airport(cls, airport: Airport, radials: typing.Collection[int], size: int, importance: int):
|
def from_airport(cls, airport: Airport, radials: typing.Collection[int], size: int, importance: int):
|
||||||
|
assert airport
|
||||||
return cls(airport.name, airport.position, airport, radials, size, importance)
|
return cls(airport.name, airport.position, airport, radials, size, importance)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@ -6,6 +6,11 @@ from .base import *
|
|||||||
|
|
||||||
|
|
||||||
class NevadaTheater(ConflictTheater):
|
class NevadaTheater(ConflictTheater):
|
||||||
|
terrain = dcs.terrain.Nevada()
|
||||||
|
overview_image = "nevada.gif"
|
||||||
|
reference_points = {(nevada.Mina_Airport_3Q0.position.x, nevada.Mina_Airport_3Q0.position.y): (45, -360),
|
||||||
|
(nevada.Laughlin_Airport.position.x, nevada.Laughlin_Airport.position.y): (440, 80), }
|
||||||
|
|
||||||
mina = ControlPoint.from_airport(nevada.Mina_Airport_3Q0, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
|
mina = ControlPoint.from_airport(nevada.Mina_Airport_3Q0, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
|
||||||
tonopah = ControlPoint.from_airport(nevada.Tonopah_Airport, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
|
tonopah = ControlPoint.from_airport(nevada.Tonopah_Airport, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
|
||||||
tonopah_test_range = ControlPoint.from_airport(nevada.Tonopah_Test_Range_Airfield, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
|
tonopah_test_range = ControlPoint.from_airport(nevada.Tonopah_Test_Range_Airfield, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
|
||||||
|
|||||||
@ -6,46 +6,65 @@ from .base import *
|
|||||||
|
|
||||||
|
|
||||||
class PersianGulfTheater(ConflictTheater):
|
class PersianGulfTheater(ConflictTheater):
|
||||||
|
terrain = dcs.terrain.PersianGulf()
|
||||||
|
overview_image = "persiangulf.gif"
|
||||||
|
reference_points = {(persiangulf.Sir_Abu_Nuayr.position.x, persiangulf.Sir_Abu_Nuayr.position.y): (351, 115),
|
||||||
|
(persiangulf.Sirri_Island.position.x, persiangulf.Sirri_Island.position.y): (389, 22), }
|
||||||
|
|
||||||
al_dhafra = ControlPoint.from_airport(persiangulf.Al_Dhafra_AB, ALL_RADIALS, SIZE_BIG, IMPORTANCE_LOW)
|
al_dhafra = ControlPoint.from_airport(persiangulf.Al_Dhafra_AB, ALL_RADIALS, SIZE_BIG, IMPORTANCE_LOW)
|
||||||
al_maktoum = ControlPoint.from_airport(persiangulf.Al_Maktoum_Intl, ALL_RADIALS, SIZE_BIG, IMPORTANCE_LOW)
|
al_maktoum = ControlPoint.from_airport(persiangulf.Al_Maktoum_Intl, ALL_RADIALS, SIZE_BIG, IMPORTANCE_LOW)
|
||||||
al_minhad = ControlPoint.from_airport(persiangulf.Al_Minhad_AB, ALL_RADIALS, SIZE_REGULAR, IMPORTANCE_LOW)
|
al_minhad = ControlPoint.from_airport(persiangulf.Al_Minhad_AB, ALL_RADIALS, SIZE_REGULAR, IMPORTANCE_LOW)
|
||||||
sir_abu_nuayr = ControlPoint.from_airport(persiangulf.Sir_Abu_Nuayr, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
|
sir_abu_nuayr = ControlPoint.from_airport(persiangulf.Sir_Abu_Nuayr, [330], SIZE_SMALL, IMPORTANCE_LOW)
|
||||||
|
|
||||||
dubai = ControlPoint.from_airport(persiangulf.Dubai_Intl, COAST_SWNE, SIZE_LARGE, IMPORTANCE_MEDIUM)
|
dubai = ControlPoint.from_airport(persiangulf.Dubai_Intl, COAST_SWNE, SIZE_LARGE, IMPORTANCE_MEDIUM)
|
||||||
sharjah = ControlPoint.from_airport(persiangulf.Sharjah_Intl, ALL_RADIALS, SIZE_BIG, IMPORTANCE_MEDIUM)
|
sharjah = ControlPoint.from_airport(persiangulf.Sharjah_Intl, ALL_RADIALS, SIZE_BIG, IMPORTANCE_MEDIUM)
|
||||||
fujairah = ControlPoint.from_airport(persiangulf.Fujairah_Intl, COAST_NS_E, SIZE_REGULAR, IMPORTANCE_MEDIUM)
|
fujairah = ControlPoint.from_airport(persiangulf.Fujairah_Intl, COAST_NS_W, SIZE_REGULAR, IMPORTANCE_MEDIUM)
|
||||||
khasab = ControlPoint.from_airport(persiangulf.Khasab, COAST_EW_S, SIZE_SMALL, IMPORTANCE_MEDIUM)
|
khasab = ControlPoint.from_airport(persiangulf.Khasab, COAST_EW_S, SIZE_SMALL, IMPORTANCE_MEDIUM)
|
||||||
|
|
||||||
sirri = ControlPoint.from_airport(persiangulf.Sirri_Island, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_MEDIUM)
|
sirri = ControlPoint.from_airport(persiangulf.Sirri_Island, ALL_RADIALS, SIZE_TINY, IMPORTANCE_MEDIUM)
|
||||||
abu_musa = ControlPoint.from_airport(persiangulf.Abu_Musa_Island_Airport, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_MEDIUM)
|
abu_musa = ControlPoint.from_airport(persiangulf.Abu_Musa_Island_Airport, ALL_RADIALS, SIZE_TINY, IMPORTANCE_MEDIUM)
|
||||||
tunb_island = ControlPoint.from_airport(persiangulf.Tunb_Island_AFB, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_HIGH)
|
tunb_island = ControlPoint.from_airport(persiangulf.Tunb_Island_AFB, COAST_EW_N, SIZE_SMALL, IMPORTANCE_HIGH)
|
||||||
|
tunb_kochak = ControlPoint.from_airport(persiangulf.Tunb_Kochak, COAST_EW_S, SIZE_TINY, IMPORTANCE_HIGH)
|
||||||
|
|
||||||
bandar_lengeh = ControlPoint.from_airport(persiangulf.Bandar_Lengeh, COAST_EW_N, SIZE_SMALL, IMPORTANCE_HIGH)
|
bandar_lengeh = ControlPoint.from_airport(persiangulf.Bandar_Lengeh, COAST_EW_N, SIZE_SMALL, IMPORTANCE_HIGH)
|
||||||
qeshm = ControlPoint.from_airport(persiangulf.Qeshm_Island, COAST_EW_N, SIZE_SMALL, IMPORTANCE_HIGH)
|
qeshm = ControlPoint.from_airport(persiangulf.Qeshm_Island, COAST_EW_N, SIZE_SMALL, IMPORTANCE_HIGH)
|
||||||
|
|
||||||
havadarya = ControlPoint.from_airport(persiangulf.Havadarya, COAST_SWNE, SIZE_REGULAR, IMPORTANCE_HIGH)
|
havadarya = ControlPoint.from_airport(persiangulf.Havadarya, COAST_EW_N, SIZE_REGULAR, IMPORTANCE_HIGH)
|
||||||
bandar_abbas = ControlPoint.from_airport(persiangulf.Bandar_Abbas_Intl, COAST_EW_N, SIZE_BIG, IMPORTANCE_HIGH)
|
bandar_abbas = ControlPoint.from_airport(persiangulf.Bandar_Abbas_Intl, COAST_EW_N, SIZE_BIG, IMPORTANCE_HIGH)
|
||||||
lar = ControlPoint.from_airport(persiangulf.Lar_Airbase, ALL_RADIALS, SIZE_REGULAR, IMPORTANCE_HIGH)
|
lar = ControlPoint.from_airport(persiangulf.Lar_Airbase, ALL_RADIALS, SIZE_REGULAR, IMPORTANCE_HIGH)
|
||||||
|
|
||||||
|
east_carrier = ControlPoint.carrier("West carrier", Point(-91023.430176, -159467.078125))
|
||||||
|
west_carrier = ControlPoint.carrier("East carrier", Point(-100531.972946, 60939.275818))
|
||||||
|
north_carrier = ControlPoint.carrier("North carrier", Point(70531.972946, 60939.275818))
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
super(PersianGulfTheater, self).__init__()
|
super(PersianGulfTheater, self).__init__()
|
||||||
|
|
||||||
self.add_controlpoint(self.al_dhafra, connected_to=[self.sir_abu_nuayr, self.al_maktoum])
|
self.add_controlpoint(self.al_dhafra, connected_to=[self.sir_abu_nuayr, self.al_maktoum])
|
||||||
self.add_controlpoint(self.al_maktoum, connected_to=[self.al_dhafra, self.al_minhad, self.sir_abu_nuayr])
|
self.add_controlpoint(self.al_maktoum, connected_to=[self.al_dhafra, self.al_minhad, self.sir_abu_nuayr])
|
||||||
self.add_controlpoint(self.dubai, connected_to=[self.sir_abu_nuayr, self.al_minhad, self.sharjah])
|
self.add_controlpoint(self.al_minhad, connected_to=[self.al_maktoum, self.dubai])
|
||||||
|
self.add_controlpoint(self.dubai, connected_to=[self.al_minhad, self.sharjah])
|
||||||
self.add_controlpoint(self.sharjah, connected_to=[self.dubai, self.khasab])
|
self.add_controlpoint(self.sharjah, connected_to=[self.dubai, self.khasab])
|
||||||
self.add_controlpoint(self.fujairah, connected_to=[self.dubai, self.khasab])
|
self.add_controlpoint(self.fujairah, connected_to=[self.dubai, self.khasab])
|
||||||
self.add_controlpoint(self.khasab, connected_to=[self.sharjah, self.fujairah, self.tunb_island])
|
self.add_controlpoint(self.khasab, connected_to=[self.sharjah, self.fujairah, self.tunb_island])
|
||||||
|
|
||||||
self.add_controlpoint(self.sir_abu_nuayr, connected_to=[self.al_dhafra, self.al_maktoum, self.dubai])
|
self.add_controlpoint(self.sir_abu_nuayr, connected_to=[self.al_dhafra, self.al_maktoum, self.sirri])
|
||||||
self.add_controlpoint(self.sirri, connected_to=[self.sir_abu_nuayr, self.abu_musa, self.tunb_island])
|
self.add_controlpoint(self.sirri, connected_to=[self.sir_abu_nuayr, self.abu_musa])
|
||||||
self.add_controlpoint(self.abu_musa, connected_to=[self.sirri, self.sir_abu_nuayr, self.tunb_island])
|
self.add_controlpoint(self.abu_musa, connected_to=[self.sirri, self.sir_abu_nuayr])
|
||||||
|
self.add_controlpoint(self.tunb_kochak, connected_to=[self.sirri, self.abu_musa, self.tunb_island])
|
||||||
|
|
||||||
self.add_controlpoint(self.tunb_island, connected_to=[self.khasab, self.abu_musa, self.sirri, self.qeshm])
|
self.add_controlpoint(self.tunb_island, connected_to=[self.khasab, self.qeshm, self.tunb_kochak])
|
||||||
self.add_controlpoint(self.bandar_lengeh, connected_to=[self.tunb_island, self.lar, self.qeshm])
|
self.add_controlpoint(self.bandar_lengeh, connected_to=[self.tunb_island, self.lar, self.qeshm])
|
||||||
self.add_controlpoint(self.qeshm, connected_to=[self.bandar_lengeh, self.havadarya, self.tunb_island])
|
self.add_controlpoint(self.qeshm, connected_to=[self.bandar_lengeh, self.havadarya, self.tunb_island])
|
||||||
self.add_controlpoint(self.havadarya, connected_to=[self.lar, self.qeshm, self.bandar_abbas])
|
self.add_controlpoint(self.havadarya, connected_to=[self.lar, self.qeshm, self.bandar_abbas])
|
||||||
self.add_controlpoint(self.bandar_abbas, connected_to=[self.havadarya])
|
self.add_controlpoint(self.bandar_abbas, connected_to=[self.havadarya])
|
||||||
self.add_controlpoint(self.lar, connected_to=[self.bandar_lengeh, self.qeshm, self.havadarya])
|
self.add_controlpoint(self.lar, connected_to=[self.bandar_lengeh, self.qeshm, self.havadarya])
|
||||||
|
|
||||||
|
self.add_controlpoint(self.east_carrier)
|
||||||
|
self.add_controlpoint(self.west_carrier)
|
||||||
|
self.add_controlpoint(self.north_carrier)
|
||||||
|
|
||||||
|
self.east_carrier.captured = True
|
||||||
|
self.west_carrier.captured = True
|
||||||
|
self.north_carrier.captured = True
|
||||||
self.al_dhafra.captured = True
|
self.al_dhafra.captured = True
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
from theater.base import *
|
from theater.base import *
|
||||||
from theater.conflicttheater import *
|
from theater.conflicttheater import *
|
||||||
|
|
||||||
UNIT_VARIETY = 2
|
UNIT_VARIETY = 3
|
||||||
UNIT_AMOUNT_FACTOR = 0.25
|
UNIT_AMOUNT_FACTOR = 16
|
||||||
|
|
||||||
|
|
||||||
def generate_initial(theater: ConflictTheater, enemy: str):
|
def generate_initial(theater: ConflictTheater, enemy: str):
|
||||||
@ -11,19 +11,14 @@ def generate_initial(theater: ConflictTheater, enemy: str):
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
for task in [CAP, FighterSweep, CAS, AirDefence]:
|
for task in [CAP, FighterSweep, CAS, AirDefence]:
|
||||||
suitable_unittypes = db.find_unittype(task, enemy)
|
assert cp.importance <= IMPORTANCE_HIGH, "invalid importance {}".format(cp.importance)
|
||||||
suitable_unittypes.sort(key=lambda x: db.PRICES[x], reverse=True)
|
assert cp.importance >= IMPORTANCE_LOW, "invalid importance {}".format(cp.importance)
|
||||||
|
|
||||||
importance = cp.importance * 10
|
importance_factor = (cp.importance - IMPORTANCE_LOW) / (IMPORTANCE_HIGH - IMPORTANCE_LOW)
|
||||||
reversed_importance = IMPORTANCE_HIGH * 10 - cp.importance * 10
|
variety = int(UNIT_VARIETY + UNIT_VARIETY * importance_factor / 2)
|
||||||
units_idx_start = int(reversed_importance)
|
unittypes = db.choose_units(task, importance_factor, variety, enemy)
|
||||||
units_idx_end = units_idx_start + UNIT_VARIETY
|
|
||||||
|
|
||||||
range_start = min(len(suitable_unittypes)-1, units_idx_start)
|
count = max(int(importance_factor * UNIT_AMOUNT_FACTOR), 1)
|
||||||
range_end = min(len(suitable_unittypes), units_idx_end)
|
count_per_type = max(int(float(count) / len(unittypes)), 1)
|
||||||
unittypes = suitable_unittypes[range_start:range_end]
|
for unit_type in unittypes:
|
||||||
|
cp.base.commision_units({unit_type: count_per_type})
|
||||||
typecount = max(math.floor(importance * UNIT_AMOUNT_FACTOR), 1)
|
|
||||||
#print("{} - {}-{} {}, {}".format(cp.name, units_idx_start, units_idx_end, unittypes, typecount))
|
|
||||||
units = {unittype: typecount for unittype in unittypes}
|
|
||||||
cp.base.commision_units(units)
|
|
||||||
|
|||||||
@ -143,7 +143,7 @@ class EventMenu(Menu):
|
|||||||
clients=scrambled_clients)
|
clients=scrambled_clients)
|
||||||
elif type(self.event) is GroundInterceptEvent:
|
elif type(self.event) is GroundInterceptEvent:
|
||||||
e = self.event # type: GroundInterceptEvent
|
e = self.event # type: GroundInterceptEvent
|
||||||
e.player_attacking(e.to_cp.position.random_point_within(30000), strikegroup=scrambled_aircraft, clients=scrambled_clients)
|
e.player_attacking(strikegroup=scrambled_aircraft, clients=scrambled_clients)
|
||||||
|
|
||||||
self.game.initiate_event(self.event)
|
self.game.initiate_event(self.event)
|
||||||
EventResultsMenu(self.window, self.parent, self.game, self.event).display()
|
EventResultsMenu(self.window, self.parent, self.game, self.event).display()
|
||||||
|
|||||||
@ -21,6 +21,9 @@ class EventResultsMenu(Menu):
|
|||||||
self.window.clear_right_pane()
|
self.window.clear_right_pane()
|
||||||
|
|
||||||
if not self.finished:
|
if not self.finished:
|
||||||
|
"""
|
||||||
|
For debugging purposes
|
||||||
|
|
||||||
Button(self.frame, text="no losses, succ", command=self.simulate_result(0, 1)).grid()
|
Button(self.frame, text="no losses, succ", command=self.simulate_result(0, 1)).grid()
|
||||||
Button(self.frame, text="no losses, fail", command=self.simulate_result(0, 1)).grid(row=1, column=1)
|
Button(self.frame, text="no losses, fail", command=self.simulate_result(0, 1)).grid(row=1, column=1)
|
||||||
|
|
||||||
@ -29,6 +32,7 @@ class EventResultsMenu(Menu):
|
|||||||
|
|
||||||
Button(self.frame, text="full losses, succ", command=self.simulate_result(1, 0)).grid(row=3, )
|
Button(self.frame, text="full losses, succ", command=self.simulate_result(1, 0)).grid(row=3, )
|
||||||
Button(self.frame, text="full losses, fail", command=self.simulate_result(1, 0)).grid(row=3, column=1)
|
Button(self.frame, text="full losses, fail", command=self.simulate_result(1, 0)).grid(row=3, column=1)
|
||||||
|
"""
|
||||||
|
|
||||||
Label(self.frame, text="Play the mission and save debriefing to {}".format(debriefing_directory_location())).grid(row=0, column=0)
|
Label(self.frame, text="Play the mission and save debriefing to {}".format(debriefing_directory_location())).grid(row=0, column=0)
|
||||||
else:
|
else:
|
||||||
|
|||||||
@ -6,6 +6,7 @@ from ui.window import *
|
|||||||
|
|
||||||
class NewGameMenu(Menu):
|
class NewGameMenu(Menu):
|
||||||
selected_country = None # type: IntVar
|
selected_country = None # type: IntVar
|
||||||
|
selected_terrain = None # type: IntVar
|
||||||
|
|
||||||
def __init__(self, window: Window, callback: typing.Callable):
|
def __init__(self, window: Window, callback: typing.Callable):
|
||||||
super(NewGameMenu, self).__init__(window, None, None)
|
super(NewGameMenu, self).__init__(window, None, None)
|
||||||
@ -15,6 +16,9 @@ class NewGameMenu(Menu):
|
|||||||
self.selected_country = IntVar()
|
self.selected_country = IntVar()
|
||||||
self.selected_country.set(0)
|
self.selected_country.set(0)
|
||||||
|
|
||||||
|
self.selected_terrain = IntVar()
|
||||||
|
self.selected_terrain.set(0)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def player_country_name(self):
|
def player_country_name(self):
|
||||||
if self.selected_country.get() == 0:
|
if self.selected_country.get() == 0:
|
||||||
@ -29,13 +33,27 @@ class NewGameMenu(Menu):
|
|||||||
else:
|
else:
|
||||||
return "Russia"
|
return "Russia"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def terrain_name(self) -> str:
|
||||||
|
if self.selected_terrain.get() == 0:
|
||||||
|
return "caucasus"
|
||||||
|
elif self.selected_terrain.get() == 1:
|
||||||
|
return "nevada"
|
||||||
|
else:
|
||||||
|
return "persiangulf"
|
||||||
|
|
||||||
def display(self):
|
def display(self):
|
||||||
self.window.clear_right_pane()
|
self.window.clear_right_pane()
|
||||||
|
|
||||||
Label(self.frame, text="Player country").grid(row=0, column=0)
|
Label(self.frame, text="Player country").grid(row=0, column=0)
|
||||||
Radiobutton(self.frame, text="USA", variable=self.selected_country, value=0).grid(row=1, column=0)
|
Radiobutton(self.frame, text="USA", variable=self.selected_country, value=0).grid(row=1, column=0)
|
||||||
Radiobutton(self.frame, text="Russia", variable=self.selected_country, value=1).grid(row=2, column=0)
|
Radiobutton(self.frame, text="Russia", variable=self.selected_country, value=1).grid(row=2, column=0)
|
||||||
Button(self.frame, text="Proceed", command=self.proceed).grid(row=3, column=0)
|
|
||||||
|
Label(self.frame, text="Terrain").grid(row=0, column=1)
|
||||||
|
Radiobutton(self.frame, text="Caucasus", variable=self.selected_terrain, value=0).grid(row=1, column=1)
|
||||||
|
Radiobutton(self.frame, text="Nevada", variable=self.selected_terrain, value=1).grid(row=2, column=1)
|
||||||
|
Radiobutton(self.frame, text="Persian Gulf", variable=self.selected_terrain, value=2).grid(row=3, column=1)
|
||||||
|
Button(self.frame, text="Proceed", command=self.proceed).grid(row=4, column=0, columnspan=2)
|
||||||
|
|
||||||
def proceed(self):
|
def proceed(self):
|
||||||
self.callback(self.player_country_name, self.enemy_country_name)
|
self.callback(self.player_country_name, self.enemy_country_name, self.terrain_name)
|
||||||
|
|||||||
@ -11,14 +11,14 @@ class OverviewCanvas:
|
|||||||
mainmenu = None # type: ui.mainmenu.MainMenu
|
mainmenu = None # type: ui.mainmenu.MainMenu
|
||||||
|
|
||||||
def __init__(self, frame: Frame, parent, game: Game):
|
def __init__(self, frame: Frame, parent, game: Game):
|
||||||
self.canvas = Canvas(frame, width=616, height=350)
|
|
||||||
self.canvas.grid(column=0, row=0, sticky=NSEW)
|
|
||||||
self.image = PhotoImage(file="resources/caumap.gif")
|
|
||||||
self.parent = parent
|
self.parent = parent
|
||||||
|
|
||||||
self.game = game
|
self.game = game
|
||||||
|
|
||||||
def cp_coordinates(self, cp: ControlPoint) -> (int, int):
|
self.image = PhotoImage(file=os.path.join("resources", game.theater.overview_image))
|
||||||
|
self.canvas = Canvas(frame, width=self.image.width(), height=self.image.height())
|
||||||
|
self.canvas.grid(column=0, row=0, sticky=NSEW)
|
||||||
|
|
||||||
|
def transform_point(self, p: Point) -> (int, int):
|
||||||
point_a = list(self.game.theater.reference_points.keys())[0]
|
point_a = list(self.game.theater.reference_points.keys())[0]
|
||||||
point_a_img = self.game.theater.reference_points[point_a]
|
point_a_img = self.game.theater.reference_points[point_a]
|
||||||
|
|
||||||
@ -35,8 +35,8 @@ class OverviewCanvas:
|
|||||||
y_scale = float(y_dist) / float(lat_dist)
|
y_scale = float(y_dist) / float(lat_dist)
|
||||||
|
|
||||||
# ---
|
# ---
|
||||||
x_offset = cp.position.x - point_a[0]
|
x_offset = p.x - point_a[0]
|
||||||
y_offset = cp.position.y - point_a[1]
|
y_offset = p.y - point_a[1]
|
||||||
|
|
||||||
return point_b_img[1] + y_offset * y_scale, point_a_img[0] - x_offset * x_scale
|
return point_b_img[1] + y_offset * y_scale, point_a_img[0] - x_offset * x_scale
|
||||||
|
|
||||||
@ -54,9 +54,9 @@ class OverviewCanvas:
|
|||||||
self.canvas.create_image((self.image.width()/2, self.image.height()/2), image=self.image)
|
self.canvas.create_image((self.image.width()/2, self.image.height()/2), image=self.image)
|
||||||
|
|
||||||
for cp in self.game.theater.controlpoints:
|
for cp in self.game.theater.controlpoints:
|
||||||
coords = self.cp_coordinates(cp)
|
coords = self.transform_point(cp.position)
|
||||||
for connected_cp in cp.connected_points:
|
for connected_cp in cp.connected_points:
|
||||||
connected_coords = self.cp_coordinates(connected_cp)
|
connected_coords = self.transform_point(connected_cp.position)
|
||||||
if connected_cp.captured != cp.captured:
|
if connected_cp.captured != cp.captured:
|
||||||
color = "red"
|
color = "red"
|
||||||
elif connected_cp.captured and cp.captured:
|
elif connected_cp.captured and cp.captured:
|
||||||
@ -67,7 +67,7 @@ class OverviewCanvas:
|
|||||||
self.canvas.create_line((coords[0], coords[1], connected_coords[0], connected_coords[1]), width=2, fill=color)
|
self.canvas.create_line((coords[0], coords[1], connected_coords[0], connected_coords[1]), width=2, fill=color)
|
||||||
|
|
||||||
for cp in self.game.theater.controlpoints:
|
for cp in self.game.theater.controlpoints:
|
||||||
coords = self.cp_coordinates(cp)
|
coords = self.transform_point(cp.position)
|
||||||
arc_size = 22 * math.pow(cp.importance, 1)
|
arc_size = 22 * math.pow(cp.importance, 1)
|
||||||
extent = max(cp.base.strength * 180, 10)
|
extent = max(cp.base.strength * 180, 10)
|
||||||
start = (180 - extent) / 2
|
start = (180 - extent) / 2
|
||||||
@ -79,6 +79,15 @@ class OverviewCanvas:
|
|||||||
style=PIESLICE,
|
style=PIESLICE,
|
||||||
start=start,
|
start=start,
|
||||||
extent=extent)
|
extent=extent)
|
||||||
|
|
||||||
|
"""
|
||||||
|
For debugging purposes
|
||||||
|
|
||||||
|
for r in cp.radials:
|
||||||
|
p = self.transform_point(cp.position.point_from_heading(r, 20000))
|
||||||
|
self.canvas.create_text(p[0], p[1], text="{}".format(r))
|
||||||
|
"""
|
||||||
|
|
||||||
self.canvas.tag_bind(cp_id, "<Button-1>", self.display(cp))
|
self.canvas.tag_bind(cp_id, "<Button-1>", self.display(cp))
|
||||||
self.create_cp_title((coords[0] + arc_size/4, coords[1] + arc_size/4), cp)
|
self.create_cp_title((coords[0] + arc_size/4, coords[1] + arc_size/4), cp)
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user