gulf & nevada maps integration; updates to commisioning/start generation units logic; mission gen updates; carriers always on map

This commit is contained in:
Vasyl Horbachenko 2018-06-16 03:30:32 +03:00
parent 56c9f97417
commit 92e5514e8d
20 changed files with 368 additions and 162 deletions

View File

@ -1,5 +1,8 @@
#!/usr/bin/env python3
import theater.caucasus
import theater.persiangulf
import theater.nevada
import ui.window
import ui.mainmenu
import ui.newgamemenu
@ -19,10 +22,15 @@ game = persistency.restore_game()
if not game:
new_game_menu = None # type: NewGameMenu
def start_new_game(player_name: str, enemy_name: str):
conflicttheater = theater.caucasus.CaucasusTheater()
start_generator.generate_initial(conflicttheater, enemy_name)
def start_new_game(player_name: str, enemy_name: str, terrain: str):
if terrain == "persiangulf":
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,
enemy_name=enemy_name,
theater=conflicttheater))

View File

@ -8,33 +8,46 @@ from dcs.task import *
from dcs.unittype import *
PRICES = {
# planes
Su_25T: 11,
Su_25: 11,
A_10A: 18,
A_10C: 20,
FA_18C_hornet: 18,
AV8BNA: 15,
# fighter
C_101CC: 10,
AJS37: 15,
F_5E: 12,
MiG_23MLD: 15,
MiG_25PD: 20,
MiG_31: 30,
Su_27: 30,
Su_33: 33,
F_15C: 30,
M_2000C: 11,
MiG_15bis: 8,
MiG_21Bis: 13,
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,
An_26B: 13,
An_30M: 13,
Yak_40: 13,
S_3B_Tanker: 13,
A_50: 8,
E_3A: 8,
C_130: 8,
# armor
Armor.MBT_T_55: 4,
Armor.MBT_T_80U: 8,
Armor.MBT_T_90: 10,
@ -45,49 +58,142 @@ PRICES = {
Armor.ATGM_M1134_Stryker: 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_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 = {
FighterSweep: [Su_27, Su_33, FA_18C_hornet, F_15C, MiG_21Bis, MiG_29A, F_A_18C, AV8BNA, ],
CAS: [Su_25T, A_10A, A_10C, ],
Transport: [IL_76MD, S_3B_Tanker, ],
FighterSweep: [
C_101CC,
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, ],
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, ],
}
UNIT_BY_COUNTRY = {
"Russia": [
Su_25T,
C_101CC,
AJS37,
F_5E,
MiG_23MLD,
MiG_25PD,
MiG_31,
Su_27,
Su_33,
Su_25,
MiG_15bis,
MiG_21Bis,
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,
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.MBT_T_90,
Armor.MBT_T_80U,
Armor.MBT_T_55,
IL_76MD,
CV_1143_5_Admiral_Kuznetsov],
"USA": [F_15C,
A_10C,
FA_18C_hornet,
AV8BNA,
E_3A,
Armor.MBT_M1A2_Abrams,
Armor.MBT_M60A3_Patton,
Armor.ATGM_M1134_Stryker,
S_3B_Tanker,
AirDefence.SAM_Avenger_M1097,
CVN_74_John_C__Stennis],
"USA": [
F_15C,
FA_18C_hornet,
AV8BNA,
AJS37,
F_5E,
M_2000C,
MiG_21Bis,
MiG_15bis,
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 = {
@ -132,3 +238,38 @@ def task_name(task) -> str:
return "AirDefence"
else:
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()

View File

@ -26,13 +26,13 @@ class Event:
def generate(self):
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.mission.save("build/nextturn.miz")
def generate_quick(self):
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.mission.save('build/nextturn_quick.miz')
@ -88,7 +88,7 @@ class GroundInterceptEvent(Event):
else:
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)
random.shuffle(suitable_unittypes)
unittypes = suitable_unittypes[:self.TARGET_VARIETY]
@ -100,9 +100,9 @@ class GroundInterceptEvent(Event):
defender_name=self.defender_name,
attacker_clients=clients,
defender_clients={},
from_cp=self.from_cp)
op.setup(position=position,
target=self.targets,
from_cp=self.from_cp,
to_cp=self.to_cp)
op.setup(target=self.targets,
strikegroup=strikegroup)
self.operation = op

View File

@ -9,6 +9,7 @@ COMMISION_LIMITS_FACTORS = {
}
COMMISION_AMOUNTS_SCALE = 2
COMMISION_UNIT_VARIETY = 4
COMMISION_AMOUNTS_FACTORS = {
CAP: 0.6,
CAS: 0.3,
@ -85,7 +86,6 @@ class Game:
enemy_interception = True
break
if to_cp in self.theater.conflicts(False):
continue
@ -120,8 +120,10 @@ class Game:
break
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]:
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):
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,
@ -139,8 +141,9 @@ class Game:
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)
if points_to_spend > 0:
unit_type = random.choice(db.find_unittype(for_task, self.enemy))
cp.base.commision_units({unit_type: points_to_spend})
importance_factor = (cp.importance - IMPORTANCE_LOW) / (IMPORTANCE_HIGH - IMPORTANCE_LOW)
unittypes = db.choose_units(for_task, importance_factor, COMMISION_UNIT_VARIETY, self.enemy)
cp.base.commision_units({random.choice(unittypes): points_to_spend})
@property
def budget_reward_amount(self):

View File

@ -58,7 +58,8 @@ class Operation:
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)
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
if is_quick:
@ -66,14 +67,25 @@ class Operation:
self.defenders_starting_position = None
else:
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):
self.extra_aagen.generate()
self.envgen.generate(self.is_quick)
if self.is_awacs_enabled:
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]:
return []
@ -103,14 +115,12 @@ class CaptureOperation(Operation):
self.defense = defense
self.aa = aa
def prepare(self, is_quick: bool):
super(CaptureOperation, self).prepare(is_quick)
mission = dcs.Mission()
self.initialize(mission=mission,
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
super(CaptureOperation, self).prepare(terrain, is_quick)
self.initialize(mission=self.mission,
conflict=self.to_cp.conflict_attack(self.from_cp,
mission.country(self.attacker_name),
mission.country(self.defender_name)))
self.mission.country(self.attacker_name),
self.mission.country(self.defender_name)))
def generate(self):
self.armorgen.generate(self.attack, self.defense)
@ -140,18 +150,16 @@ class InterceptOperation(Operation):
self.airdefense = airdefense
self.interceptors = interceptors
def prepare(self, is_quick: bool):
super(InterceptOperation, self).prepare(is_quick)
mission = dcs.Mission()
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
super(InterceptOperation, self).prepare(terrain, is_quick)
conflict = Conflict.intercept_conflict(
attacker=mission.country(self.attacker_name),
defender=mission.country(self.defender_name),
attacker=self.mission.country(self.attacker_name),
defender=self.mission.country(self.defender_name),
from_cp=self.from_cp,
to_cp=self.to_cp
)
self.initialize(mission=mission,
self.initialize(mission=self.mission,
conflict=conflict)
def generate(self):
@ -159,40 +167,30 @@ class InterceptOperation(Operation):
self.airgen.generate_transport_escort(self.escort, clients=self.defender_clients)
if self.from_cp.is_global:
starting_ship = self.shipgen.generate(type=db.find_unittype(Carriage, self.attacker_name)[0],
at=self.from_cp.at)
if self.is_quick:
starting_ship = None
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=starting_ship)
super(InterceptOperation, self).generate()
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.attackers_starting_position)
else:
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):
def setup(self,
position: Point,
target: db.ArmorDict,
strikegroup: db.PlaneDict):
self.position = position
self.strikegroup = strikegroup
self.target = target
def prepare(self, is_quick: bool):
super(GroundInterceptOperation, self).prepare(is_quick)
mission = dcs.Mission()
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
super(GroundInterceptOperation, self).prepare(terrain, is_quick)
conflict = Conflict.ground_intercept_conflict(
attacker=mission.country(self.attacker_name),
defender=mission.country(self.defender_name),
position=self.position,
heading=randint(0, 360),
radials=ALL_RADIALS
attacker=self.mission.country(self.attacker_name),
defender=self.mission.country(self.defender_name),
heading=self.to_cp.position.heading_between_point(self.from_cp.position),
cp=self.to_cp
)
self.initialize(mission=mission,
self.initialize(mission=self.mission,
conflict=conflict)
def generate(self):

View File

@ -7,8 +7,8 @@ from .naming import *
from dcs.mission import *
DISTANCE_FACTOR = 4, 5
EXTRA_AA_MIN_DISTANCE = 70000
EXTRA_AA_POSITION_FROM_CP = 10000
EXTRA_AA_MIN_DISTANCE = 35000
EXTRA_AA_POSITION_FROM_CP = 550
class AAConflictGenerator:
def __init__(self, mission: Mission, conflict: Conflict):

View File

@ -72,6 +72,8 @@ class AircraftConflictGenerator:
for unit_instance in group.units:
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:
assert count > 0
assert unit is not None

View File

@ -8,6 +8,9 @@ from dcs.unittype import *
from dcs.task import *
from dcs.terrain.terrain import NoParkingSlotError
AWACS_DISTANCE = 150000
AWACS_ALT = 10000
class AWACSConflictGenerator:
def __init__(self, mission: Mission, conflict: Conflict, game):
@ -22,5 +25,6 @@ class AWACSConflictGenerator:
country=self.conflict.attackers_side,
name=namegen.next_awacs_group_name(),
plane_type=plane,
altitude=AWACS_ALT,
airport=None,
position=self.conflict.position)
position=self.conflict.position.random_point_within(AWACS_DISTANCE, AWACS_DISTANCE))

View File

@ -14,10 +14,8 @@ from dcs.point import *
from dcs.task import *
from dcs.country import *
def _opposite_heading(h):
return h+180
GROUND_DISTANCE_FACTOR = 2
GROUNDINTERCEPT_DISTANCE_FACTOR = 6
AIR_DISTANCE = 32000
INTERCEPT_ATTACKERS_HEADING = -45, 45
@ -28,6 +26,10 @@ INTERCEPT_MAX_DISTANCE = 80000
INTERCEPT_MIN_DISTANCE = 45000
def _opposite_heading(h):
return h+180
class Conflict:
attackers_side = None # type: Country
defenders_side = None # type: Country
@ -81,18 +83,18 @@ class Conflict:
return instance
@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
instance = self()
instance.attackers_side = attacker
instance.defenders_side = defender
instance.position = position
instance.size = SIZE_SMALL
instance.radials = radials
instance.position = cp.position
instance.size = cp.size
instance.radials = cp.radials
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

View File

@ -6,6 +6,7 @@ from dcs.mission import Mission
from dcs.triggers import *
from dcs.condition import *
from dcs.action import *
from dcs.task import *
from theater.weatherforecast import WeatherForecast
from theater.conflicttheater import Conflict
@ -14,18 +15,17 @@ ACTIVATION_TRIGGER_SIZE = 80000
ACTIVATION_TRIGGER_MIN_DISTANCE = 5000
RANDOM_TIME = {
"night": 0,
"dusk": 5,
"dawn": 35,
"noon": 75,
"night": 5,
"dusk": 30,
"dawn": 30,
"day": 100,
}
RANDOM_WEATHER = {
0: 0, # thunderstorm
1: 5, # heavy rain
2: 20, # rain
3: 40, # random dynamic
0: 5, # thunderstorm
1: 20, # heavy rain
2: 30, # rain
3: 100, # random dynamic
}
@ -36,17 +36,7 @@ class EnvironmentSettingsGenerator:
self.game = game
def _gen_random_time(self):
time_roll = random.randint(0, 100)
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()
start_time = datetime.today()
daytime_map = {
"day": timedelta(hours=random.randrange(9, 18)),
"night": timedelta(hours=random.randrange(-3, 6)),
@ -54,24 +44,24 @@ class EnvironmentSettingsGenerator:
"dawn": timedelta(hours=random.randrange(6, 9)),
}
time_roll = random.randint(0, 100)
time_period = None
for k, v in RANDOM_TIME.items():
if v >= time_roll:
if random.randint(0, 100) <= v:
time_period = k
break
print("generated {}".format(time_period))
start_time += daytime_map[time_period]
self.mission.start_time = start_time
def _gen_random_weather(self):
weather_roll = random.randint(0, 100)
weather_type = None
for k, v in RANDOM_TIME.items():
if v >= weather_roll:
for k, v in RANDOM_WEATHER.items():
if random.randint(0, 100) <= v:
weather_type = k
break
print("generated weather {}".format(weather_type))
if weather_type == 0:
self.mission.weather.random_thunderstorm()
elif weather_type == 1:
@ -116,9 +106,10 @@ class EnvironmentSettingsGenerator:
player_coalition = self.game.player == "USA" and "blue" or "red"
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._set_allegiances(player_coalition, enemy_coalition)

View File

@ -6,6 +6,8 @@ from .base import *
class CaucasusTheater(ConflictTheater):
terrain = caucasus.Caucasus()
overview_image = "caumap.gif"
reference_points = {(-317948.32727306, 635639.37385346): (282.5, 319),
(-355692.3067714, 617269.96285781): (269, 352), }

View File

@ -5,6 +5,7 @@ import dcs
from .controlpoint import *
SIZE_TINY = 150
SIZE_SMALL = 600
SIZE_REGULAR = 1000
SIZE_BIG = 2000
@ -29,6 +30,7 @@ class ConflictTheater:
terrain = None # type: dcs.terrain.Terrain
controlpoints = None # type: typing.Collection[ControlPoint]
reference_points = None # type: typing.Dict
overview_image = None # type: str
def __init__(self):
self.controlpoints = []

View File

@ -1,4 +1,5 @@
import typing
import re
from dcs.mapping 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):
import theater.base
self.name = name.split("-")[0]
self.name = " ".join(re.split(r" |-", name)[:2])
self.full_name = name
self.position = position
self.at = at
@ -30,6 +32,7 @@ class ControlPoint:
@classmethod
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)
@classmethod

View File

@ -6,6 +6,11 @@ from .base import *
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)
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)

View File

@ -6,46 +6,65 @@ from .base import *
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_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)
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)
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)
sirri = ControlPoint.from_airport(persiangulf.Sirri_Island, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_MEDIUM)
abu_musa = ControlPoint.from_airport(persiangulf.Abu_Musa_Island_Airport, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_MEDIUM)
tunb_island = ControlPoint.from_airport(persiangulf.Tunb_Island_AFB, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_HIGH)
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_TINY, IMPORTANCE_MEDIUM)
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)
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)
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):
super(PersianGulfTheater, self).__init__()
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.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.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.sir_abu_nuayr, connected_to=[self.al_dhafra, self.al_maktoum, self.dubai])
self.add_controlpoint(self.sirri, connected_to=[self.sir_abu_nuayr, self.abu_musa, self.tunb_island])
self.add_controlpoint(self.abu_musa, connected_to=[self.sirri, self.sir_abu_nuayr, self.tunb_island])
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.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.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.bandar_abbas, connected_to=[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

View File

@ -1,8 +1,8 @@
from theater.base import *
from theater.conflicttheater import *
UNIT_VARIETY = 2
UNIT_AMOUNT_FACTOR = 0.25
UNIT_VARIETY = 3
UNIT_AMOUNT_FACTOR = 16
def generate_initial(theater: ConflictTheater, enemy: str):
@ -11,19 +11,14 @@ def generate_initial(theater: ConflictTheater, enemy: str):
continue
for task in [CAP, FighterSweep, CAS, AirDefence]:
suitable_unittypes = db.find_unittype(task, enemy)
suitable_unittypes.sort(key=lambda x: db.PRICES[x], reverse=True)
assert cp.importance <= IMPORTANCE_HIGH, "invalid importance {}".format(cp.importance)
assert cp.importance >= IMPORTANCE_LOW, "invalid importance {}".format(cp.importance)
importance = cp.importance * 10
reversed_importance = IMPORTANCE_HIGH * 10 - cp.importance * 10
units_idx_start = int(reversed_importance)
units_idx_end = units_idx_start + UNIT_VARIETY
importance_factor = (cp.importance - IMPORTANCE_LOW) / (IMPORTANCE_HIGH - IMPORTANCE_LOW)
variety = int(UNIT_VARIETY + UNIT_VARIETY * importance_factor / 2)
unittypes = db.choose_units(task, importance_factor, variety, enemy)
range_start = min(len(suitable_unittypes)-1, units_idx_start)
range_end = min(len(suitable_unittypes), units_idx_end)
unittypes = suitable_unittypes[range_start:range_end]
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)
count = max(int(importance_factor * UNIT_AMOUNT_FACTOR), 1)
count_per_type = max(int(float(count) / len(unittypes)), 1)
for unit_type in unittypes:
cp.base.commision_units({unit_type: count_per_type})

View File

@ -143,7 +143,7 @@ class EventMenu(Menu):
clients=scrambled_clients)
elif type(self.event) is 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)
EventResultsMenu(self.window, self.parent, self.game, self.event).display()

View File

@ -21,6 +21,9 @@ class EventResultsMenu(Menu):
self.window.clear_right_pane()
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, 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, 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)
else:

View File

@ -6,6 +6,7 @@ from ui.window import *
class NewGameMenu(Menu):
selected_country = None # type: IntVar
selected_terrain = None # type: IntVar
def __init__(self, window: Window, callback: typing.Callable):
super(NewGameMenu, self).__init__(window, None, None)
@ -15,6 +16,9 @@ class NewGameMenu(Menu):
self.selected_country = IntVar()
self.selected_country.set(0)
self.selected_terrain = IntVar()
self.selected_terrain.set(0)
@property
def player_country_name(self):
if self.selected_country.get() == 0:
@ -29,13 +33,27 @@ class NewGameMenu(Menu):
else:
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):
self.window.clear_right_pane()
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="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):
self.callback(self.player_country_name, self.enemy_country_name)
self.callback(self.player_country_name, self.enemy_country_name, self.terrain_name)

View File

@ -11,14 +11,14 @@ class OverviewCanvas:
mainmenu = None # type: ui.mainmenu.MainMenu
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.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_img = self.game.theater.reference_points[point_a]
@ -35,8 +35,8 @@ class OverviewCanvas:
y_scale = float(y_dist) / float(lat_dist)
# ---
x_offset = cp.position.x - point_a[0]
y_offset = cp.position.y - point_a[1]
x_offset = p.x - point_a[0]
y_offset = p.y - point_a[1]
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)
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:
connected_coords = self.cp_coordinates(connected_cp)
connected_coords = self.transform_point(connected_cp.position)
if connected_cp.captured != cp.captured:
color = "red"
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)
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)
extent = max(cp.base.strength * 180, 10)
start = (180 - extent) / 2
@ -79,6 +79,15 @@ class OverviewCanvas:
style=PIESLICE,
start=start,
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.create_cp_title((coords[0] + arc_size/4, coords[1] + arc_size/4), cp)