new options, landmaps, mission settings generation update & frontlike smokes generation

This commit is contained in:
Vasyl Horbachenko 2018-06-16 21:04:01 +03:00
parent 92e5514e8d
commit e54e548bdd
25 changed files with 344 additions and 41 deletions

View File

@ -1,4 +1,7 @@
#!/usr/bin/env python3
import os
import dcs
import theater.caucasus
import theater.persiangulf
import theater.nevada
@ -11,6 +14,8 @@ from game.game import Game
from theater import start_generator
from userdata import persistency
dcs.planes.FlyingType.payload_dirs.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "resources\\payloads"))
def proceed_to_main_menu(game: Game):
m = ui.mainmenu.MainMenu(w, None, game)
@ -22,7 +27,7 @@ game = persistency.restore_game()
if not game:
new_game_menu = None # type: NewGameMenu
def start_new_game(player_name: str, enemy_name: str, terrain: str):
def start_new_game(player_name: str, enemy_name: str, terrain: str, sams: bool):
if terrain == "persiangulf":
conflicttheater = theater.persiangulf.PersianGulfTheater()
elif terrain == "nevada":
@ -30,7 +35,7 @@ if not game:
else:
conflicttheater = theater.caucasus.CaucasusTheater()
start_generator.generate_initial(conflicttheater, enemy_name)
start_generator.generate_initial(conflicttheater, enemy_name, sams)
proceed_to_main_menu(Game(player_name=player_name,
enemy_name=enemy_name,
theater=conflicttheater))

View File

@ -115,10 +115,17 @@ UNIT_BY_TASK = {
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_Vulcan_M163,
AirDefence.AAA_Vulcan_M163,
AirDefence.AAA_Vulcan_M163,
AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Patriot_ICC,
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.AAA_ZU_23_on_Ural_375,
AirDefence.SAM_SA_18_Igla_MANPADS,
AirDefence.SAM_SA_18_Igla_MANPADS,
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_8_Osa_9A33,
@ -126,6 +133,14 @@ UNIT_BY_TASK = {
Carriage: [CVN_74_John_C__Stennis, CV_1143_5_Admiral_Kuznetsov, ],
}
SAM_BAN = [
AirDefence.SAM_Avenger_M1097,
AirDefence.SAM_Patriot_ICC,
AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_8_Osa_9A33,
]
UNIT_BY_COUNTRY = {
"Russia": [
C_101CC,
@ -256,7 +271,7 @@ 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:
for unit_type in set(unit_collection):
assert unit_type not in total_set, "{} is duplicate".format(unit_type)
total_set.add(unit_type)
@ -272,4 +287,5 @@ def _validate_db():
for unit_type in total_set:
assert unit_type in PRICES, "{} not in prices".format(unit_type)
_validate_db()

View File

@ -258,7 +258,7 @@ class CaptureEvent(Event):
attack=armor,
intercept=interceptors,
defense=self.to_cp.base.armor,
aa=self.to_cp.base.aa)
aa=self.to_cp.base.assemble_aa())
self.operation = op

View File

@ -5,7 +5,7 @@ COMMISION_LIMITS_FACTORS = {
CAP: 2,
CAS: 1,
FighterSweep: 3,
AirDefence: 2,
AirDefence: 1,
}
COMMISION_AMOUNTS_SCALE = 2
@ -39,6 +39,8 @@ class Game:
budget = PLAYER_BUDGET_INITIAL
events = None # type: typing.List[Event]
pending_transfers = None # type: typing.Dict[]
player_skill = "Good"
enemy_skill = "Average"
def __init__(self, player_name: str, enemy_name: str, theater: ConflictTheater):
self.events = []

View File

@ -7,8 +7,9 @@ from gen.aircraft import *
from gen.aaa import *
from gen.shipgen import *
from gen.conflictgen import *
from gen.envsettingsgen import *
from gen.settingsgen import *
from gen.awacsgen import *
from gen.visualgen import *
class Operation:
@ -21,8 +22,9 @@ class Operation:
aagen = None # type: AAConflictGenerator
extra_aagen = None # type: ExtraAAConflictGenerator
shipgen = None # type: ShipGenerator
envgen = None # type: EnvironmentSettingsGenerator
envgen = None # type: SettingsGenerator
awacsgen = None # type: AWACSConflictGenerator
visualgen = None # type: VisualGenerator
is_awacs_enabled = False
@ -52,7 +54,8 @@ class Operation:
self.aagen = AAConflictGenerator(mission, conflict)
self.shipgen = ShipGenerator(mission, conflict)
self.awacsgen = AWACSConflictGenerator(mission, conflict, self.game)
self.envgen = EnvironmentSettingsGenerator(mission, conflict, self.game)
self.envgen = SettingsGenerator(mission, conflict, self.game)
self.visualgen = VisualGenerator(mission, conflict, self.game)
player_name = self.from_cp.captured and self.attacker_name or self.defender_name
enemy_name = self.from_cp.captured and self.defender_name or self.attacker_name
@ -70,6 +73,8 @@ class Operation:
self.defenders_starting_position = self.to_cp.at
def generate(self):
self.visualgen.generate()
if self.is_awacs_enabled:
self.awacsgen.generate()
@ -117,6 +122,11 @@ class CaptureOperation(Operation):
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
super(CaptureOperation, self).prepare(terrain, is_quick)
self.defenders_starting_position = None
if self.game.player == self.defender_name:
self.attackers_starting_position = None
self.initialize(mission=self.mission,
conflict=self.to_cp.conflict_attack(self.from_cp,
self.mission.country(self.attacker_name),
@ -131,6 +141,7 @@ class CaptureOperation(Operation):
self.airgen.generate_cas(self.cas, clients=self.attacker_clients, at=self.attackers_starting_position)
self.airgen.generate_cas_escort(self.escort, clients=self.attacker_clients, at=self.attackers_starting_position)
self.visualgen.generate_target_smokes(self.to_cp)
super(CaptureOperation, self).generate()
@ -152,6 +163,8 @@ class InterceptOperation(Operation):
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
super(InterceptOperation, self).prepare(terrain, is_quick)
self.defenders_starting_position = None
conflict = Conflict.intercept_conflict(
attacker=self.mission.country(self.attacker_name),
defender=self.mission.country(self.defender_name),

View File

@ -1,13 +1,14 @@
import typing
import random
from datetime import datetime, timedelta
from datetime import datetime, timedelta, time
from dcs.mission import Mission
from dcs.triggers import *
from dcs.condition import *
from dcs.action import *
from dcs.task import *
from dcs.unit import Skill
from game import db
from theater.weatherforecast import WeatherForecast
from theater.conflicttheater import Conflict
@ -23,35 +24,27 @@ RANDOM_TIME = {
RANDOM_WEATHER = {
0: 5, # thunderstorm
1: 20, # heavy rain
2: 30, # rain
1: 10, # heavy rain
2: 20, # rain
3: 100, # random dynamic
}
class EnvironmentSettingsGenerator:
class SettingsGenerator:
def __init__(self, mission: Mission, conflict: Conflict, game):
self.mission = mission
self.conflict = conflict
self.game = game
def _gen_random_time(self):
start_time = datetime.today()
daytime_map = {
"day": timedelta(hours=random.randrange(9, 18)),
"night": timedelta(hours=random.randrange(-3, 6)),
"dusk": timedelta(hours=random.randrange(18, 21)),
"dawn": timedelta(hours=random.randrange(6, 9)),
}
time_period = None
start_time = datetime.combine(datetime.today(), time())
time_range = None
for k, v in RANDOM_TIME.items():
if random.randint(0, 100) <= v:
time_period = k
time_range = self.game.theater.daytime_map[k]
break
print("generated {}".format(time_period))
start_time += daytime_map[time_period]
start_time += timedelta(hours=random.randint(*time_range))
self.mission.start_time = start_time
def _gen_random_weather(self):
@ -102,6 +95,16 @@ class EnvironmentSettingsGenerator:
continue
self.mission.terrain.airport_by_id(cp.at.id).set_coalition(cp.captured and player_coalition or enemy_coalition)
def _set_skill(self, player_coalition: str, enemy_coalition: str):
for coalition_name, coalition in self.mission.coalition.items():
skill_level = player_coalition == coalition_name and self.game.player_skill or self.game.enemy_skill
for country in coalition.countries.values():
for plane_group in country.plane_group:
plane_group.set_skill(Skill(skill_level))
for vehicle_group in country.vehicle_group:
vehicle_group.set_skill(Skill(skill_level))
def generate(self, is_quick: bool):
player_coalition = self.game.player == "USA" and "blue" or "red"
enemy_coalition = player_coalition == "blue" and "red" or "blue"
@ -111,6 +114,7 @@ class EnvironmentSettingsGenerator:
self._gen_random_time()
self._gen_random_weather()
self._set_skill(player_coalition, enemy_coalition)
self._set_allegiances(player_coalition, enemy_coalition)
if not is_quick:

126
gen/visualgen.py Normal file
View File

@ -0,0 +1,126 @@
import typing
import random
from datetime import datetime, timedelta
from dcs.mission import Mission
from dcs.statics import *
from dcs.unit import Static
from theater.conflicttheater import Conflict
#from game.game import Game
class Smoke(unittype.StaticType):
id = "big_smoke"
category = "Effects"
name = "big_smoke"
shape_name = 2
rate = 100
class BigSmoke(unittype.StaticType):
id = "big_smoke"
category = "Effects"
name = "big_smoke"
shape_name = 3
rate = 100
class MassiveSmoke(unittype.StaticType):
id = "big_smoke"
category = "Effects"
name = "big_smoke"
shape_name = 4
rate = 100
def __monkey_static_dict(self: Static):
global __original_static_dict
d = __original_static_dict(self)
if self.type == "big_smoke":
d["effectPreset"] = self.shape_name
return d
__original_static_dict = Static.dict
Static.dict = __monkey_static_dict
FRONT_SMOKE_MIN_DISTANCE = 10000
FRONT_SMOKE_DISTANCE_FACTOR = 0.75
FRONT_SMOKE_LENGTH = 80000
FRONT_SMOKE_SPACING = 600
FRONT_SMOKE_RANDOM_SPREAD = 1200
FRONT_SMOKE_TYPE_CHANCES = {
5: MassiveSmoke,
40: BigSmoke,
100: Smoke,
}
DESTINATION_SMOKE_AMOUNT_FACTOR = 0.03
DESTINATION_SMOKE_DISTANCE_FACTOR = 1
DESTINATION_SMOKE_TYPE_CHANCES = {
5: BigSmoke,
100: Smoke,
}
def turn_heading(heading, fac):
heading += fac
if heading > 359:
heading = heading - 359
if heading < 0:
heading = 359 + heading
return heading
class VisualGenerator:
game = None # type: Game
def __init__(self, mission: Mission, conflict: Conflict, game):
self.mission = mission
self.conflict = conflict
self.game = game
def _generate_frontline_smokes(self):
for from_cp, to_cp in self.game.theater.conflicts():
distance = max(from_cp.position.distance_to_point(to_cp.position) * FRONT_SMOKE_DISTANCE_FACTOR * to_cp.base.strength, FRONT_SMOKE_MIN_DISTANCE)
heading = to_cp.position.heading_between_point(from_cp.position)
point = to_cp.position.point_from_heading(heading, distance)
plane_start = point.point_from_heading(turn_heading(heading, 90), FRONT_SMOKE_LENGTH / 2)
for offset in range(0, FRONT_SMOKE_LENGTH, FRONT_SMOKE_SPACING):
position = plane_start.point_from_heading(turn_heading(heading, - 90), offset)
for k, v in FRONT_SMOKE_TYPE_CHANCES.items():
if random.randint(0, 100) <= k:
pos = position.random_point_within(FRONT_SMOKE_RANDOM_SPREAD, FRONT_SMOKE_RANDOM_SPREAD)
if not self.game.theater.is_on_land(pos):
break
self.mission.static_group(
self.mission.country(self.game.enemy),
"",
_type=v,
position=pos)
break
def generate_target_smokes(self, target):
spread = target.size * DESTINATION_SMOKE_DISTANCE_FACTOR
for _ in range(0, int(target.size * DESTINATION_SMOKE_AMOUNT_FACTOR * (1.1 - target.base.strength))):
for k, v in DESTINATION_SMOKE_TYPE_CHANCES.items():
if random.randint(0, 100) <= k:
position = target.position.random_point_within(0, spread)
if not self.game.theater.is_on_land(position):
break
self.mission.static_group(
self.mission.country(self.game.enemy),
"",
_type=v,
position=position)
break
def generate(self):
self._generate_frontline_smokes()

BIN
resources/cau_terrain.miz Normal file

Binary file not shown.

BIN
resources/caulandmap.p Normal file

Binary file not shown.

View File

@ -0,0 +1,14 @@
import pickle
from dcs.mission import Mission
from dcs.terrain import PersianGulf
m = Mission()
m.load_file("./gulf_terrain.miz")
landmap = []
for plane_group in m.country("USA").plane_group:
landmap.append([(x.position.x, x.position.y) for x in plane_group.points])
with open("gulflandmap.p", "wb") as f:
pickle.dump(landmap, f)

BIN
resources/gulf_terrain.miz Normal file

Binary file not shown.

BIN
resources/gulflandmap.p Normal file

Binary file not shown.

BIN
resources/nevada.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
resources/persiangulf.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

View File

@ -127,7 +127,6 @@ class Base:
def commit_losses(self, units_lost: typing.Dict[typing.Any, int]):
for unit_type, count in units_lost.items():
target_array = None
if unit_type in self.aircraft:
target_array = self.aircraft
elif unit_type in self.armor:
@ -164,3 +163,7 @@ class Base:
def assemble_defense(self, factor: float) -> typing.Dict[Armor, int]:
return self._find_best_armor(CAP, math.ceil(self.total_armor * factor * self.strength))
def assemble_aa(self) -> typing.Dict[AirDefence, int]:
count = int(self.total_aa * (self.strength > 0.2 and self.strength or 0))
return self._find_best_unit(self.aa, AirDefence, count)

View File

@ -1,6 +1,7 @@
from dcs.terrain import caucasus
from dcs import mapping
from .landmap import *
from .conflicttheater import *
from .base import *
@ -10,6 +11,13 @@ class CaucasusTheater(ConflictTheater):
overview_image = "caumap.gif"
reference_points = {(-317948.32727306, 635639.37385346): (282.5, 319),
(-355692.3067714, 617269.96285781): (269, 352), }
landmap_poly = load_poly("resources\\caulandmap.p")
daytime_map = {
"dawn": (6, 9),
"day": (9, 18),
"dusk": (18, 21),
"night": (0, 5),
}
soganlug = ControlPoint.from_airport(caucasus.Soganlug, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
kutaisi = ControlPoint.from_airport(caucasus.Kutaisi, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
@ -32,7 +40,7 @@ class CaucasusTheater(ConflictTheater):
mineralnye = ControlPoint.from_airport(caucasus.Mineralnye_Vody, ALL_RADIALS, SIZE_BIG, IMPORTANCE_MEDIUM)
mozdok = ControlPoint.from_airport(caucasus.Mozdok, ALL_RADIALS, SIZE_BIG, IMPORTANCE_MEDIUM)
carrier_1 = ControlPoint.carrier("Carrier", mapping.Point(-355810.6875, 516399.1875))
carrier_1 = ControlPoint.carrier("Carrier", mapping.Point(-305810.6875, 406399.1875))
def __init__(self):
super(CaucasusTheater, self).__init__()
@ -63,3 +71,9 @@ class CaucasusTheater(ConflictTheater):
self.carrier_1.captured = True
self.soganlug.captured = True
self.sukhumi.captured = True
self.gudauta.base.strength = 0.5
self.kobuleti.captured = True
self.batumi.base.strength = 0.15

View File

@ -3,6 +3,7 @@ import itertools
import dcs
from .landmap import ray_tracing
from .controlpoint import *
SIZE_TINY = 150
@ -31,6 +32,8 @@ class ConflictTheater:
controlpoints = None # type: typing.Collection[ControlPoint]
reference_points = None # type: typing.Dict
overview_image = None # type: str
landmap_poly = None
daytime_map = None # type: typing.Dict[str, typing.Tuple[int, int]]
def __init__(self):
self.controlpoints = []
@ -41,6 +44,15 @@ class ConflictTheater:
self.controlpoints.append(point)
def is_on_land(self, point: Point) -> bool:
if not self.landmap_poly:
return True
for poly in self.landmap_poly:
return ray_tracing(point.x, point.y, poly)
return False
def player_points(self) -> typing.Collection[ControlPoint]:
return [point for point in self.controlpoints if point.captured]

24
theater/landmap.py Normal file
View File

@ -0,0 +1,24 @@
import pickle
def load_poly(filename: str):
with open(filename, "rb") as f:
return pickle.load(f)
def ray_tracing(x, y, poly):
n = len(poly)
inside = False
xints = 0.0
p1x, p1y = poly[0]
for i in range(n+1):
p2x, p2y = poly[i % n]
if y > min(p1y, p2y):
if y <= max(p1y, p2y):
if x <= max(p1x, p2x):
if p1y != p2y:
xints = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x
if p1x == p2x or x <= xints:
inside = not inside
p1x, p1y = p2x, p2y
return inside

View File

@ -10,6 +10,12 @@ class NevadaTheater(ConflictTheater):
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), }
daytime_map = {
"dawn": (4, 6),
"day": (6, 17),
"dusk": (17, 19),
"night": (0, 5),
}
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)
@ -45,3 +51,5 @@ class NevadaTheater(ConflictTheater):
self.add_controlpoint(self.laughlin, connected_to=[self.jean, self.las_vegas])
self.mina.captured = True
self.pahute_mesa.captured = True
self.groom_lake.captured = True

View File

@ -3,6 +3,7 @@ from dcs import mapping
from .conflicttheater import *
from .base import *
from .landmap import load_poly
class PersianGulfTheater(ConflictTheater):
@ -10,6 +11,13 @@ class PersianGulfTheater(ConflictTheater):
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), }
landmap_poly = load_poly("resources\\gulflandmap.p")
daytime_map = {
"dawn": (5, 7),
"day": (7, 17),
"dusk": (17, 19),
"night": (0, 5),
}
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)

View File

@ -1,11 +1,20 @@
import math
from theater.base import *
from theater.conflicttheater import *
UNIT_VARIETY = 3
UNIT_AMOUNT_FACTOR = 16
COUNT_BY_TASK = {
CAP: 12,
FighterSweep: 16,
CAS: 8,
AirDefence: 0.5,
}
def generate_initial(theater: ConflictTheater, enemy: str):
def generate_initial(theater: ConflictTheater, enemy: str, sams: bool):
for cp in theater.enemy_points():
if cp.captured:
continue
@ -15,10 +24,14 @@ def generate_initial(theater: ConflictTheater, enemy: str):
assert cp.importance >= IMPORTANCE_LOW, "invalid importance {}".format(cp.importance)
importance_factor = (cp.importance - IMPORTANCE_LOW) / (IMPORTANCE_HIGH - IMPORTANCE_LOW)
variety = int(UNIT_VARIETY + UNIT_VARIETY * importance_factor / 2)
variety = int(UNIT_VARIETY)
unittypes = db.choose_units(task, importance_factor, variety, enemy)
count = max(int(importance_factor * UNIT_AMOUNT_FACTOR), 1)
if not sams:
unittypes = [x for x in unittypes if x not in db.SAM_BAN]
count = max(COUNT_BY_TASK[task] * importance_factor, 1)
count_per_type = max(int(float(count) / len(unittypes)), 1)
for unit_type in unittypes:
print("{} - {} {}".format(cp.name, db.unit_type_name(unit_type), count_per_type))
cp.base.commision_units({unit_type: count_per_type})

View File

@ -7,3 +7,26 @@ from ui.window import *
class ConfigurationMenu(Menu):
def __init__(self, window: Window, parent, game: Game):
super(ConfigurationMenu, self).__init__(window, parent, game)
self.frame = window.right_pane
self.player_skill_var = StringVar()
self.player_skill_var.set(self.game.player_skill)
self.enemy_skill_var = StringVar()
self.enemy_skill_var.set(self.game.enemy_skill)
def dismiss(self):
self.game.player_skill = self.player_skill_var.get()
self.game.enemy_skill = self.enemy_skill_var.get()
super(ConfigurationMenu, self).dismiss()
def display(self):
self.window.clear_right_pane()
Label(self.frame, text="Player coalition skill").grid(row=0, column=0)
Label(self.frame, text="Enemy coalition skill").grid(row=1, column=0)
OptionMenu(self.frame, self.player_skill_var, "Average", "Good", "High", "Excellent").grid(row=0, column=1)
OptionMenu(self.frame, self.enemy_skill_var, "Average", "Good", "High", "Excellent").grid(row=1, column=1)
Button(self.frame, text="Back", command=self.dismiss).grid(row=2, column=0, columnspan=1)

View File

@ -30,9 +30,9 @@ class EventMenu(Menu):
self.window.clear_right_pane()
row = 0
def label(text, _row=None, _column=None):
def label(text, _row=None, _column=None, sticky=None):
nonlocal row
Label(self.frame, text=text).grid(row=_row and _row or row, column=_column and _column or 0)
Label(self.frame, text=text).grid(row=_row and _row or row, column=_column and _column or 0, sticky=sticky)
if _row is None:
row += 1
@ -62,7 +62,12 @@ class EventMenu(Menu):
row += 1
Checkbutton(self.frame, text="AWACS", var=self.awacs).grid(row=row, column=2)
Button(self.frame, text="Commit", command=self.start).grid(column=1, row=row, sticky=E)
Button(self.frame, text="Back", command=self.dismiss).grid(column=2, row=row, sticky=E)
awacs_enabled = self.game.budget >= AWACS_BUDGET_COST and NORMAL or DISABLED
Checkbutton(self.frame, text="AWACS ({}m)".format(AWACS_BUDGET_COST), var=self.awacs, state=awacs_enabled).grid(row=row, column=0, sticky=W)
row += 1
label("Aircraft")
@ -76,17 +81,14 @@ class EventMenu(Menu):
scrable_row(unit_type, count)
if not self.base.total_planes:
label("None")
label("None", sticky=W)
label("Armor")
for unit_type, count in self.base.armor.items():
scramble_armor_row(unit_type, count)
if not self.base.total_armor:
label("None")
Button(self.frame, text="Commit", command=self.start).grid(column=0, row=row)
Button(self.frame, text="Back", command=self.dismiss).grid(column=2, row=row)
label("None", sticky=W)
def start(self):
if self.awacs.get() == 1:

View File

@ -2,6 +2,7 @@ import pickle
from ui.basemenu import *
from ui.overviewcanvas import *
from ui.configurationmenu import *
from game.game import *
from userdata import persistency
@ -41,7 +42,8 @@ class MainMenu(Menu):
row += 1
Separator(self.frame, orient='horizontal').grid(row=row, sticky=EW); row += 1
Button(self.frame, text="Pass turn", command=self.pass_turn).grid(column=0, row=0, sticky=NE)
Button(self.frame, text="Configuration", command=self.configuration_menu).grid(column=0, row=0, sticky=NE)
Button(self.frame, text="Pass turn", command=self.pass_turn).grid(column=0, row=0, sticky=N)
Label(self.frame, text="Budget: {}m (+{}m)".format(self.game.budget, self.game.budget_reward_amount)).grid(column=0, row=0, sticky=NW)
Separator(self.frame, orient='horizontal').grid(row=row, sticky=EW); row += 1
@ -58,10 +60,16 @@ class MainMenu(Menu):
self.game.pass_turn(no_action=True)
self.display()
def configuration_menu(self):
ConfigurationMenu(self.window, self, self.game).display()
def start_event(self, event) -> typing.Callable:
return lambda: EventMenu(self.window, self, self.game, event).display()
def go_cp(self, cp: ControlPoint):
if not cp.captured:
return
if self.basemenu:
self.basemenu.dismiss()
self.basemenu = None

View File

@ -7,6 +7,7 @@ from ui.window import *
class NewGameMenu(Menu):
selected_country = None # type: IntVar
selected_terrain = None # type: IntVar
sams = True
def __init__(self, window: Window, callback: typing.Callable):
super(NewGameMenu, self).__init__(window, None, None)
@ -19,6 +20,9 @@ class NewGameMenu(Menu):
self.selected_terrain = IntVar()
self.selected_terrain.set(0)
self.sams = BooleanVar()
self.sams.set(1)
@property
def player_country_name(self):
if self.selected_country.get() == 0:
@ -53,7 +57,11 @@ class NewGameMenu(Menu):
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)
Label(self.frame, text="Options").grid(row=1, column=2)
Checkbutton(self.frame, text="SAMs", variable=self.sams).grid(row=1, column=2)
Button(self.frame, text="Proceed", command=self.proceed).grid(row=4, column=0, columnspan=3)
def proceed(self):
self.callback(self.player_country_name, self.enemy_country_name, self.terrain_name)
self.callback(self.player_country_name, self.enemy_country_name, self.terrain_name, bool(self.sams.get()))