Generate CAP on whole map, for 2 hours. Added China.

This commit is contained in:
Khopa 2019-10-07 01:57:36 +02:00
parent 2167953b87
commit 7a14376765
17 changed files with 132 additions and 1802 deletions

View File

@ -45,7 +45,10 @@ PRICES = {
Su_33: 22, Su_33: 22,
MiG_29A: 18, MiG_29A: 18,
MiG_29S: 20, MiG_29S: 20,
MiG_29G: 18,
MiG_31: 30, MiG_31: 30,
J_11A: 26,
Su_30: 24,
F_5E_3: 8, F_5E_3: 8,
MiG_15bis: 4, MiG_15bis: 4,
@ -62,6 +65,8 @@ PRICES = {
F_15C: 26, F_15C: 26,
F_16C_bl_52d: 20, F_16C_bl_52d: 20,
F_14B: 22, F_14B: 22,
Tornado_IDS: 24,
# Tornado_GR4: 24,
# bomber # bomber
Su_17M4: 10, Su_17M4: 10,
@ -200,7 +205,10 @@ UNIT_BY_TASK = {
M_2000C, M_2000C,
Mirage_2000_5, Mirage_2000_5,
P_51D_30_NA, P_51D_30_NA,
P_51D P_51D,
MiG_29G,
Su_30,
J_11A
], ],
CAS: [ CAS: [
F_86F_Sabre, F_86F_Sabre,
@ -224,6 +232,8 @@ UNIT_BY_TASK = {
OH_58D, OH_58D,
B_52H, B_52H,
B_1B, B_1B,
Tornado_IDS,
# Tornado_GR4,
], ],
Transport: [ Transport: [
IL_76MD, IL_76MD,
@ -379,8 +389,12 @@ CARRIER_TAKEOFF_BAN = [
AirDefense units that will be spawned at control points not related to the current operation AirDefense units that will be spawned at control points not related to the current operation
""" """
EXTRA_AA = { EXTRA_AA = {
"Russia": AirDefence.SAM_SA_8_Osa_9A33, "Russia": AirDefence.SAM_SA_9_Strela_1_9P31,
"USA": AirDefence.SAM_Linebacker_M6, "USA": AirDefence.SAM_Linebacker_M6,
"France": AirDefence.SPAAA_Gepard,
"Germany": AirDefence.SPAAA_Gepard,
"China": AirDefence.SPAAA_ZSU_23_4_Shilka,
"UK": AirDefence.AAA_Vulcan_M163,
"Russia 1955": AirDefence.AAA_ZU_23_Closed, "Russia 1955": AirDefence.AAA_ZU_23_Closed,
"USA 1955": AirDefence.AAA_Vulcan_M163, "USA 1955": AirDefence.AAA_Vulcan_M163,
"Russia 1965": AirDefence.AAA_ZU_23_Closed, "Russia 1965": AirDefence.AAA_ZU_23_Closed,
@ -389,7 +403,9 @@ EXTRA_AA = {
"Russia 1988": AirDefence.AAA_ZU_23_Closed, "Russia 1988": AirDefence.AAA_ZU_23_Closed,
"USA 1990": AirDefence.AAA_Vulcan_M163, "USA 1990": AirDefence.AAA_Vulcan_M163,
"France 1990": AirDefence.AAA_Vulcan_M163, "France 1990": AirDefence.AAA_Vulcan_M163,
"Germany 1990": AirDefence.AAA_Vulcan_M163 "Germany 1990": AirDefence.AAA_Vulcan_M163,
"Iran 2015": AirDefence.SPAAA_ZSU_23_4_Shilka,
"China 2015": AirDefence.SPAAA_ZSU_23_4_Shilka
} }
""" """
@ -596,13 +612,9 @@ FACTIONS = {
Mi_8MT, Mi_8MT,
AirDefence.SPAAA_ZSU_23_4_Shilka, AirDefence.SPAAA_ZSU_23_4_Shilka,
AirDefence.SAM_SA_9_Strela_1_9P31,
AirDefence.SAM_SA_8_Osa_9A33,
AirDefence.AAA_ZU_23_Closed,
AirDefence.SAM_SA_19_Tunguska_2S6, AirDefence.SAM_SA_19_Tunguska_2S6,
AirDefence.SAM_SA_6_Kub_LN_2P25,
AirDefence.SAM_SA_3_S_125_LN_5P73,
AirDefence.SAM_SA_11_Buk_LN_9A310M1, AirDefence.SAM_SA_11_Buk_LN_9A310M1,
AirDefence.SAM_SA_10_S_300PS_LN_5P85C,
Armor.APC_BTR_80, Armor.APC_BTR_80,
Armor.MBT_T_90, Armor.MBT_T_90,
@ -620,7 +632,7 @@ FACTIONS = {
}, },
"Iran 2015": { "Iran 2015": {
"country": "Russia", "country": "Iran",
"side": "red", "side": "red",
"units": [ "units": [
@ -667,6 +679,46 @@ FACTIONS = {
] ]
}, },
"China 2000": {
"country": "China",
"side": "red",
"units": [
MiG_21Bis, # Standing as J-7
Su_30,
J_11A,
IL_76MD,
IL_78M,
An_26B,
An_30M,
Yak_40,
A_50,
Mi_8MT,
AirDefence.AAA_ZU_23_Closed,
AirDefence.Rapier_FSA_Launcher, # Standing as PL-9C Shorad
AirDefence.SAM_SA_10_S_300PS_LN_5P85C, # Standing as HQ-9+
AirDefence.SAM_SA_6_Kub_LN_2P25,
# TODO : ADD HQ-7 (need pydcs support)
Armor.MBT_T_55,
Armor.ZBD_04A,
Armor.IFV_BMP_1,
Unarmed.Transport_Ural_375,
Unarmed.Transport_UAZ_469,
Infantry.Soldier_AK,
CV_1143_5_Admiral_Kuznetsov,
Bulk_cargo_ship_Yakushev,
Dry_cargo_ship_Ivanov,
Tanker_Elnya_160
]
},
"USA 1955": { "USA 1955": {
"country": "USA", "country": "USA",
"side": "blue", "side": "blue",
@ -803,7 +855,7 @@ FACTIONS = {
}, },
"France 1990": { "France 1990": {
"country": "USA", "country": "France",
"side": "blue", "side": "blue",
"units":[ "units":[
M_2000C, M_2000C,
@ -820,8 +872,7 @@ FACTIONS = {
Unarmed.Transport_M818, Unarmed.Transport_M818,
Infantry.Infantry_M4, Infantry.Infantry_M4,
AirDefence.AAA_Vulcan_M163, AirDefence.SAM_Roland_ADS,
AirDefence.SAM_Linebacker_M6,
CVN_74_John_C__Stennis, CVN_74_John_C__Stennis,
LHA_1_Tarawa, LHA_1_Tarawa,
@ -830,10 +881,12 @@ FACTIONS = {
}, },
"Germany 1990": { "Germany 1990": {
"country": "USA", "country": "Germany",
"side": "blue", "side": "blue",
"units":[ "units":[
MiG_29G, MiG_29G,
Tornado_IDS,
F_4E,
KC_135, KC_135,
S_3B_Tanker, S_3B_Tanker,
@ -850,7 +903,7 @@ FACTIONS = {
Infantry.Infantry_M4, Infantry.Infantry_M4,
AirDefence.SPAAA_Gepard, AirDefence.SPAAA_Gepard,
AirDefence.SAM_Linebacker_M6, AirDefence.SAM_Roland_ADS,
CVN_74_John_C__Stennis, CVN_74_John_C__Stennis,
LHA_1_Tarawa, LHA_1_Tarawa,
@ -1153,7 +1206,7 @@ def _validate_db():
for country_units_list in FACTIONS.values(): for country_units_list in FACTIONS.values():
if unit_type in country_units_list["units"]: if unit_type in country_units_list["units"]:
did_find = True did_find = True
assert did_find, "{} not in country list".format(unit_type) print("WARN : {} not in country list".format(unit_type))
# check prices # check prices
for unit_type in total_set: for unit_type in total_set:

View File

@ -125,6 +125,13 @@ class Operation:
# air support # air support
self.airsupportgen.generate(self.is_awacs_enabled) self.airsupportgen.generate(self.is_awacs_enabled)
for cp in self.game.theater.controlpoints:
if not cp.captured:
self.airgen.generate_patrol_group(cp, self.current_mission.country(self.game.enemy_country))
else:
self.airgen.generate_patrol_group(cp, self.current_mission.country(self.game.player_country))
for i, tanker_type in enumerate(self.airsupportgen.generated_tankers): for i, tanker_type in enumerate(self.airsupportgen.generated_tankers):
self.briefinggen.append_frequency("Tanker {} ({})".format(TANKER_CALLSIGNS[i], tanker_type), "{}X/{} MHz AM".format(97+i, 130+i)) self.briefinggen.append_frequency("Tanker {} ({})".format(TANKER_CALLSIGNS[i], tanker_type), "{}X/{} MHz AM".format(97+i, 130+i))

View File

@ -10,7 +10,7 @@ from dcs.mission import *
from dcs.unitgroup import * from dcs.unitgroup import *
from dcs.unittype import * from dcs.unittype import *
from dcs.task import * from dcs.task import *
from dcs.terrain.terrain import NoParkingSlotError from dcs.terrain.terrain import NoParkingSlotError, RunwayOccupiedError
SPREAD_DISTANCE_FACTOR = 1, 2 SPREAD_DISTANCE_FACTOR = 1, 2
ESCORT_ENGAGEMENT_MAX_DIST = 100000 ESCORT_ENGAGEMENT_MAX_DIST = 100000
@ -125,10 +125,13 @@ class AircraftConflictGenerator:
else: else:
group.set_frequency(251.0) group.set_frequency(251.0)
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, start_type = None) -> FlyingGroup:
assert count > 0 assert count > 0
assert unit is not None assert unit is not None
if start_type is None:
start_type = self._start_type()
logging.info("airgen: {} for {} at {}".format(unit_type, side.id, airport)) logging.info("airgen: {} for {} at {}".format(unit_type, side.id, airport))
return self.m.flight_group_from_airport( return self.m.flight_group_from_airport(
country=side, country=side,
@ -136,7 +139,7 @@ class AircraftConflictGenerator:
aircraft_type=unit_type, aircraft_type=unit_type,
airport=self.m.terrain.airport_by_id(airport.id), airport=self.m.terrain.airport_by_id(airport.id),
maintask=None, maintask=None,
start_type=self._start_type(), start_type=start_type,
group_size=count, group_size=count,
parking_slots=None) parking_slots=None)
@ -293,6 +296,51 @@ class AircraftConflictGenerator:
self.escort_targets.append((group, group.points.index(waypoint))) self.escort_targets.append((group, group.points.index(waypoint)))
self._rtb_for(group, self.conflict.from_cp, at) self._rtb_for(group, self.conflict.from_cp, at)
def generate_patrol_group(self, cp: ControlPoint, country):
aircraft = dict({k:v for k,v in cp.base.aircraft.items() if k in [u for u in db.UNIT_BY_TASK[CAP]]})
delta = random.randint(10, 20)
for i in range(12):
if(len(aircraft.keys())) > 0:
print(aircraft.keys())
type = random.choice(list(aircraft.keys()))
number = random.choice([2, 4])
if(number > aircraft[type]):
del aircraft[type]
else:
aircraft[type] = aircraft[type] - number
try:
group = self._generate_at_airport(
name=namegen.next_unit_name(country, type),
side=country,
unit_type=type,
count=number,
client_count=0,
airport=self.m.terrain.airport_by_id(cp.at.id),
start_type=StartType.Runway)
except RunwayOccupiedError:
group = self._generate_group(
name=namegen.next_unit_name(country, type),
side=country,
unit_type=type,
count=number,
client_count=0,
at=cp.position)
patrol_alt = random.randint(3600, 7000)
group.points[0].alt = patrol_alt
group.points[0].ETA = delta*60 + i*10*60
patrolled = []
for ground_object in cp.ground_objects:
if not ground_object.group_id in patrolled:
group.add_waypoint(ground_object.position, patrol_alt)
patrolled.append(ground_object.group_id)
def generate_ground_attack_strikegroup(self, strikegroup: db.PlaneDict, clients: db.PlaneDict, targets: typing.List[typing.Tuple[str, Point]], at: db.StartingPosition = None, escort=True): def generate_ground_attack_strikegroup(self, strikegroup: db.PlaneDict, clients: db.PlaneDict, targets: typing.List[typing.Tuple[str, Point]], at: db.StartingPosition = None, escort=True):
assert not escort or len(self.escort_targets) == 0 assert not escort or len(self.escort_targets) == 0

View File

@ -91,7 +91,7 @@ class TriggersGenerator:
push_by_trigger.append(group) push_by_trigger.append(group)
if not group.units[0].is_human(): """if not group.units[0].is_human():
regroup_heading = self.conflict.to_cp.position.heading_between_point(player_cp.position) regroup_heading = self.conflict.to_cp.position.heading_between_point(player_cp.position)
pos1 = group.position.point_from_heading(regroup_heading, REGROUP_ZONE_DISTANCE) pos1 = group.position.point_from_heading(regroup_heading, REGROUP_ZONE_DISTANCE)
@ -112,7 +112,7 @@ class TriggersGenerator:
w2.tasks.append(switch_waypoint_task) w2.tasks.append(switch_waypoint_task)
group.points[3].tasks.append(Silence(False)) group.points[3].tasks.append(Silence(False))
group.add_trigger_action(SwitchWaypoint(to_waypoint=4)) group.add_trigger_action(SwitchWaypoint(to_waypoint=4))"""
push_trigger = TriggerOnce(Event.NoEvent, "Push trigger") push_trigger = TriggerOnce(Event.NoEvent, "Push trigger")
@ -187,7 +187,7 @@ class TriggersGenerator:
self.mission.triggerrules.triggers.append(trigger_two) self.mission.triggerrules.triggers.append(trigger_two)
def generate(self, player_cp: ControlPoint, is_quick: bool, activation_trigger_radius: int, awacs_enabled: bool): def generate(self, player_cp: ControlPoint, is_quick: bool, activation_trigger_radius: int, awacs_enabled: bool):
player_coalition = self.game.player_country == "USA" and "blue" or "red" player_coalition = self.game.player_country in ["USA", "France", "Germany", "Uk"] 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 = {"x": self.conflict.position.x, self.mission.coalition[player_coalition].bullseye = {"x": self.conflict.position.x,

View File

@ -81,14 +81,14 @@ class QMapControlPoint(QGraphicsRectItem):
@property @property
def brush_color(self)->QColor: def brush_color(self)->QColor:
if self.parent.game.player_country == "USA": if self.parent.game.player_country in ["USA", "France", "Germany", "UK"]:
return self.model.captured and CONST.COLORS["blue"] or CONST.COLORS["red"] return self.model.captured and CONST.COLORS["blue"] or CONST.COLORS["red"]
else: else:
return self.model.captured and CONST.COLORS["red"] or CONST.COLORS["blue"] return self.model.captured and CONST.COLORS["red"] or CONST.COLORS["blue"]
@property @property
def pen_color(self) -> QColor: def pen_color(self) -> QColor:
if self.parent.game.player_country == "USA": if self.parent.game.player_country in ["USA", "France", "Germany", "UK"]:
return self.model.captured and CONST.COLORS["dark_blue"] or CONST.COLORS["bright_red"] return self.model.captured and CONST.COLORS["dark_blue"] or CONST.COLORS["bright_red"]
else: else:
return self.model.captured and CONST.COLORS["bright_red"] or CONST.COLORS["dark_blue"] return self.model.captured and CONST.COLORS["bright_red"] or CONST.COLORS["dark_blue"]

View File

@ -25,7 +25,7 @@ class QMapGroundObject(QGraphicsRectItem):
tooltip = "" tooltip = ""
for unit in units.keys(): for unit in units.keys():
tooltip = tooltip + str(unit) + "x" + str(units[unit]) + "\n" tooltip = tooltip + str(unit) + "x" + str(units[unit]) + "\n"
self.setToolTip(tooltip + str(model.groups[0].id) + str(model.groups[0].name)) self.setToolTip(tooltip[:-1])
else: else:
self.setToolTip(cp.name + "'s " + self.model.category) self.setToolTip(cp.name + "'s " + self.model.category)

View File

View File

@ -1,116 +0,0 @@
from ui.eventmenu import *
from game.game import *
from .styles import STYLES
class BaseMenu(Menu):
bought_amount_labels = None # type: typing.Collection[Label]
budget_label = None # type: Label
def __init__(self, window: Window, parent, game: Game, cp: ControlPoint):
super(BaseMenu, self).__init__(window, parent, game)
self.cp = cp
self.base = cp.base
self.frame = window.right_pane
self.event = self.game.units_delivery_event(cp)
self.bought_amount_labels = {}
def display(self):
self.window.clear_right_pane()
units = {
CAP: db.find_unittype(CAP, self.game.player_name),
Embarking: db.find_unittype(Embarking, self.game.player_name),
AirDefence: db.find_unittype(AirDefence, self.game.player_name),
CAS: db.find_unittype(CAS, self.game.player_name),
PinpointStrike: db.find_unittype(PinpointStrike, self.game.player_name),
}
# Header
head = Frame(self.frame, **STYLES["header"])
head.grid(row=0, column=0, columnspan=99, sticky=NSEW, pady=5)
Label(head, text=self.cp.name, **STYLES["title"]).grid(row=0, column=0, sticky=NW+S)
units_title = "{}/{}/{}".format(self.cp.base.total_planes, self.cp.base.total_armor, self.cp.base.total_aa)
Label(head, text=units_title, **STYLES["strong-grey"]).grid(row=0, column=1, sticky=NE+S)
self.budget_label = Label(self.frame, text="Budget: {}m".format(self.game.budget), **STYLES["widget"])
self.budget_label.grid(row=1, sticky=W)
Button(self.frame, text="Back", command=self.dismiss, **STYLES["btn-primary"]).grid(column=9, row=1, padx=(0,15), pady=(0,5))
tasks = list(units.keys())
tasks_per_column = 3
column = 0
for i, tasks_column in [(i, tasks[idx:idx+tasks_per_column]) for i, idx in enumerate(range(0, len(tasks), tasks_per_column))]:
row = 2
def purchase_row(unit_type, unit_price):
nonlocal row
nonlocal column
existing_units = self.base.total_units_of_type(unit_type)
scheduled_units = self.event.units.get(unit_type, 0)
Label(self.frame, text="{}".format(db.unit_type_name(unit_type)), **STYLES["widget"]).grid(row=row, column=column, sticky=W)
label = Label(self.frame, text="({}) ".format(existing_units), **STYLES["widget"])
label.grid(column=column + 1, row=row)
self.bought_amount_labels[unit_type] = label
Label(self.frame, text="{}m".format(unit_price), **STYLES["widget"]).grid(column=column + 2, row=row, sticky=E)
Button(self.frame, text="+", command=self.buy(unit_type), **STYLES["btn-primary"]).grid(column=column + 3, row=row, padx=(10,0))
Button(self.frame, text="-", command=self.sell(unit_type), **STYLES["btn-warning"]).grid(column=column + 4, row=row, padx=(10,5))
row += 1
for task_type in tasks_column:
Label(self.frame, text="{}".format(db.task_name(task_type)), **STYLES["strong"]).grid(row=row, column=column, columnspan=5, sticky=NSEW)
row += 1
units_column = list(set(units[task_type]))
units_column.sort(key=lambda x: db.PRICES[x])
for unit_type in units_column:
purchase_row(unit_type, db.PRICES[unit_type])
column += 5
def dismiss(self):
if sum([x for x in self.event.units.values()]) == 0:
self.game.units_delivery_remove(self.event)
super(BaseMenu, self).dismiss()
def _update_count_label(self, unit_type: UnitType):
self.bought_amount_labels[unit_type]["text"] = "({}{})".format(
self.cp.base.total_units_of_type(unit_type),
unit_type in self.event.units and ", bought {}".format(self.event.units[unit_type]) or ""
)
self.budget_label["text"] = "Budget: {}m".format(self.game.budget)
def buy(self, unit_type):
def action():
price = db.PRICES[unit_type]
if self.game.budget >= price:
self.event.deliver({unit_type: 1})
self.game.budget -= price
self._update_count_label(unit_type)
return action
def sell(self, unit_type):
def action():
if self.event.units.get(unit_type, 0) > 0:
price = db.PRICES[unit_type]
self.game.budget += price
self.event.units[unit_type] = self.event.units[unit_type] - 1
if self.event.units[unit_type] == 0:
del self.event.units[unit_type]
elif self.base.total_units_of_type(unit_type) > 0:
price = db.PRICES[unit_type]
self.game.budget += price
self.base.commit_losses({unit_type: 1})
self._update_count_label(unit_type)
return action

View File

@ -1,125 +0,0 @@
import webbrowser
from tkinter import *
from tkinter.ttk import *
from .styles import STYLES
from userdata.logging import ShowLogsException
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.settings.player_skill)
self.enemy_skill_var = StringVar()
self.enemy_skill_var.set(self.game.settings.enemy_skill)
self.enemy_vehicle_var = StringVar()
self.enemy_vehicle_var.set(self.game.settings.enemy_vehicle_skill)
self.map_coalition_visibility_var = StringVar()
self.map_coalition_visibility_var.set(self.game.settings.map_coalition_visibility)
self.labels_var = StringVar()
self.labels_var.set(self.game.settings.labels)
self.takeoff_var = BooleanVar()
self.takeoff_var.set(self.game.settings.only_player_takeoff)
self.night_var = BooleanVar()
self.night_var.set(self.game.settings.night_disabled)
self.cold_start_var = BooleanVar()
self.cold_start_var.set(self.game.settings.cold_start)
def dismiss(self):
self.game.settings.player_skill = self.player_skill_var.get()
self.game.settings.enemy_skill = self.enemy_skill_var.get()
self.game.settings.enemy_vehicle_skill = self.enemy_vehicle_var.get()
self.game.settings.map_coalition_visibility = self.map_coalition_visibility_var.get()
self.game.settings.labels = self.labels_var.get()
self.game.settings.only_player_takeoff = self.takeoff_var.get()
self.game.settings.night_disabled = self.night_var.get()
self.game.settings.cold_start = self.cold_start_var.get()
super(ConfigurationMenu, self).dismiss()
def display(self):
self.window.clear_right_pane()
# Header
head = Frame(self.frame, **STYLES["header"])
head.grid(row=0, column=0, sticky=NSEW)
head.grid_columnconfigure(0, weight=100)
Label(head, text="Configuration", **STYLES["title"]).grid(row=0, sticky=W)
Button(head, text="Back", command=self.dismiss, **STYLES["btn-primary"]).grid(row=0, column=1, sticky=E)
# Body
body = Frame(self.frame, **STYLES["body"])
body.grid(row=1, column=0, sticky=NSEW)
row = 0
Label(body, text="Player coalition skill", **STYLES["widget"]).grid(row=row, column=0, sticky=W)
p_skill = OptionMenu(body, self.player_skill_var, "Average", "Good", "High", "Excellent")
p_skill.grid(row=row, column=1, sticky=E, pady=5)
p_skill.configure(**STYLES["btn-primary"])
row += 1
Label(body, text="Enemy coalition skill", **STYLES["widget"]).grid(row=row, column=0, sticky=W)
e_skill = OptionMenu(body, self.enemy_skill_var, "Average", "Good", "High", "Excellent")
e_skill.grid(row=row, column=1, sticky=E)
e_skill.configure(**STYLES["btn-primary"])
row += 1
Label(body, text="Enemy AA and vehicle skill", **STYLES["widget"]).grid(row=row, column=0, sticky=W)
e_skill = OptionMenu(body, self.enemy_vehicle_var, "Average", "Good", "High", "Excellent")
e_skill.grid(row=row, column=1, sticky=E)
e_skill.configure(**STYLES["btn-primary"])
row += 1
Label(body, text="F10 Map Coalition Visibility", **STYLES["widget"]).grid(row=row, column=0, sticky=W)
map_vis = OptionMenu(body, self.map_coalition_visibility_var, "All Units", "Allied Units", "Own Aircraft", "None")
map_vis.grid(row=row, column=1, sticky=E)
map_vis.configure(**STYLES["btn-primary"])
row += 1
Label(body, text="In Game Labels", **STYLES["widget"]).grid(row=row, column=0, sticky=W)
g_labels = OptionMenu(body, self.labels_var, "Full", "Abbreviated", "Dot Only", "Off")
g_labels.grid(row=row, column=1, sticky=E)
g_labels.configure(**STYLES["btn-primary"])
row += 1
Label(body, text="Aircraft cold start", **STYLES["widget"]).grid(row=row, column=0, sticky=W)
Checkbutton(body, variable=self.cold_start_var, **STYLES["radiobutton"]).grid(row=row, column=1, sticky=E)
row += 1
Label(body, text="Takeoff only for player group", **STYLES["widget"]).grid(row=row, column=0, sticky=W)
Checkbutton(body, variable=self.takeoff_var, **STYLES["radiobutton"]).grid(row=row, column=1, sticky=E)
row += 1
Label(body, text="Disable night missions", **STYLES["widget"]).grid(row=row, column=0, sticky=W)
Checkbutton(body, variable=self.night_var, **STYLES["radiobutton"]).grid(row=row, column=1, sticky=E)
row += 1
Label(body, text="Contributors: ", **STYLES["strong"]).grid(row=row, column=0, columnspan=2, sticky=EW)
row += 1
Label(body, text="shdwp - author, maintainer", **STYLES["widget"]).grid(row=row, column=0, sticky=W)
Button(body, text="[github]", command=lambda: webbrowser.open_new_tab("http://github.com/shdwp"), **STYLES["widget"]).grid(row=row, column=1, sticky=E)
row += 1
Label(body, text="Khopa - contributions", **STYLES["widget"]).grid(row=row, column=0, sticky=W)
Button(body, text="[github]", command=lambda: webbrowser.open_new_tab("http://github.com/Khopa"), **STYLES["widget"]).grid(row=row, column=1, sticky=E)
row += 1
Button(body, text="Display logs", command=self.display_logs, **STYLES["btn-primary"]).grid(row=row, column=0, pady=5)
Button(body, text="Cheat +200m", command=self.cheat_money, **STYLES["btn-danger"]).grid(row=row, column=1)
def display_logs(self):
raise ShowLogsException()
def cheat_money(self):
self.game.budget += 200

View File

@ -1,18 +0,0 @@
from tkinter import *
from tkinter.ttk import *
from .styles import STYLES
from ui.window import *
class CorruptedSaveMenu(Menu):
def __init__(self, window: Window):
super(CorruptedSaveMenu, self).__init__(window, None, None)
self.frame = window.right_pane
def display(self):
self.window.clear_right_pane()
Label(text="Your save game is either incompatible or was corrupted!", **STYLES["widget"]).grid(row=0, column=0)
Label(text="Please restore it by replacing \"liberation_save\" file with \"liberation_save_tmp\" to restore last saved copy.", **STYLES["widget"]).grid(row=1, column=0)
Label(text="You can find those files under user Saved Games\\DCS directory.", **STYLES["widget"]).grid(row=2, column=0)

View File

@ -1,219 +0,0 @@
from dcs.helicopters import helicopter_map
from ui.eventresultsmenu import *
from game import *
from game.event import *
from .styles import STYLES, RED
class EventMenu(Menu):
scramble_entries = None # type: typing.Dict[typing.Type[Task], typing.Dict[typing.Type[UnitType], typing.Tuple[Entry, Entry]]]
ca_slot_entry = None # type: Entry
error_label = None # type: Label
awacs = None # type: IntVar
def __init__(self, window: Window, parent, game: Game, event: event.Event):
super(EventMenu, self).__init__(window, parent, game)
self.event = event
self.scramble_entries = {k: {} for k in self.event.tasks}
if self.event.attacker_name == self.game.player_name:
self.base = self.event.departure_cp.base
else:
self.base = self.event.to_cp.base
self.frame = self.window.right_pane
self.awacs = IntVar()
def display(self):
self.window.clear_right_pane()
row = 0
def header(text, style="strong"):
nonlocal row
head = Frame(self.frame, **STYLES["header"])
head.grid(row=row, column=0, sticky=N+EW, columnspan=5)
Label(head, text=text, **STYLES[style]).grid()
row += 1
def label(text, _row=None, _column=None, columnspan=None, sticky=None):
nonlocal row
new_label = Label(self.frame, text=text, **STYLES["widget"])
new_label.grid(row=_row and _row or row, column=_column and _column or 0, columnspan=columnspan, sticky=sticky)
if _row is None:
row += 1
return new_label
def scrable_row(task_type, unit_type, unit_count, client_slots: bool):
nonlocal row
Label(self.frame, text="{} ({})".format(db.unit_type_name(unit_type), unit_count), **STYLES["widget"]).grid(row=row, sticky=W)
scramble_entry = Entry(self.frame, width=2)
scramble_entry.grid(column=1, row=row, sticky=E, padx=5)
scramble_entry.insert(0, "0")
Button(self.frame, text="+", command=self.scramble_half(task_type, unit_type), **STYLES["btn-primary"]).grid(column=2, row=row)
if client_slots:
client_entry = Entry(self.frame, width=2)
client_entry.grid(column=3, row=row, sticky=E, padx=5)
client_entry.insert(0, "0")
Button(self.frame, text="+", command=self.client_one(task_type, unit_type), **STYLES["btn-primary"]).grid(column=4, row=row)
else:
client_entry = None
self.scramble_entries[task_type][unit_type] = scramble_entry, client_entry
row += 1
# Header
header("Mission Menu", "title")
# Mission Description
Label(self.frame, text="{}".format(self.event), **STYLES["mission-preview"]).grid(row=row, column=0, columnspan=5, sticky=S+EW, padx=5, pady=5)
row += 1
Label(self.frame, text="Amount", **STYLES["widget"]).grid(row=row, column=1, columnspan=2)
Label(self.frame, text="Client slots", **STYLES["widget"]).grid(row=row, column=3, columnspan=2)
row += 1
for flight_task in self.event.tasks:
header("{}:".format(self.event.flight_name(flight_task)))
if flight_task == PinpointStrike:
if not self.base.armor:
label("No units")
for t, c in self.base.armor.items():
scrable_row(flight_task, t, c, client_slots=False)
else:
if not self.base.aircraft:
label("No units")
for t, c in self.base.aircraft.items():
scrable_row(flight_task, t, c, client_slots=True)
header("Support:")
# Options
awacs_enabled = self.game.budget >= AWACS_BUDGET_COST and NORMAL or DISABLED
Label(self.frame, text="AWACS ({}m)".format(AWACS_BUDGET_COST), **STYLES["widget"]).grid(row=row, column=0, sticky=W, pady=5)
Checkbutton(self.frame, var=self.awacs, state=awacs_enabled, **STYLES["radiobutton"]).grid(row=row, column=4, sticky=E)
row += 1
Label(self.frame, text="Combined Arms Slots", **STYLES["widget"]).grid(row=row, sticky=W)
self.ca_slot_entry = Entry(self.frame, width=2)
self.ca_slot_entry.insert(0, "0")
self.ca_slot_entry.grid(column=3, row=row, sticky=E, padx=5)
Button(self.frame, text="+", command=self.add_ca_slot, **STYLES["btn-primary"]).grid(column=4, row=row, padx=5, sticky=W)
row += 1
header("Ready?")
self.error_label = label("", columnspan=4)
self.error_label["fg"] = RED
Button(self.frame, text="Commit", command=self.start, **STYLES["btn-primary"]).grid(column=0, row=row, sticky=E, padx=5, pady=(10,10))
Button(self.frame, text="Back", command=self.dismiss, **STYLES["btn-warning"]).grid(column=3, row=row, sticky=E, padx=5, pady=(10,10))
row += 1
def scramble_half(self, task: typing.Type[UnitType], unit_type: UnitType) -> typing.Callable:
def action():
entry = self.scramble_entries[task][unit_type][0] # type: Entry
value = entry.get()
total_units = self.base.total_units_of_type(unit_type)
amount = int(value and value or "0")
entry.delete(0, END)
entry.insert(0, str(amount + int(math.ceil(total_units/2))))
return action
def add_ca_slot(self):
value = self.ca_slot_entry.get()
amount = int(value and value or "0")
self.ca_slot_entry.delete(0, END)
self.ca_slot_entry.insert(0, str(amount+1))
def client_one(self, task: typing.Type[Task], unit_type: UnitType) -> typing.Callable:
def action():
entry = self.scramble_entries[task][unit_type][1] # type: Entry
value = entry.get()
amount = int(value and value or "0")
entry.delete(0, END)
entry.insert(0, str(amount+1))
return action
def start(self):
if self.awacs.get() == 1:
self.event.is_awacs_enabled = True
self.game.awacs_expense_commit()
else:
self.event.is_awacs_enabled = False
ca_slot_entry_value = self.ca_slot_entry.get()
try:
ca_slots = int(ca_slot_entry_value and ca_slot_entry_value or "0")
except:
ca_slots = 0
self.event.ca_slots = ca_slots
flights = {k: {} for k in self.event.tasks} # type: db.TaskForceDict
units_scramble_counts = {} # type: typing.Dict[typing.Type[UnitType], int]
tasks_scramble_counts = {} # type: typing.Dict[typing.Type[Task], int]
tasks_clients_counts = {} # type: typing.Dict[typing.Type[Task], int]
def dampen_count(for_task: typing.Type[Task], unit_type: typing.Type[UnitType], count: int) -> int:
nonlocal units_scramble_counts
total_count = self.base.total_units_of_type(unit_type)
total_scrambled = units_scramble_counts.get(unit_type, 0)
dampened_value = count if count + total_scrambled < total_count else total_count - total_scrambled
units_scramble_counts[unit_type] = units_scramble_counts.get(unit_type, 0) + dampened_value
return dampened_value
for task_type, dict in self.scramble_entries.items():
for unit_type, (count_entry, clients_entry) in dict.items():
try:
count = int(count_entry.get())
except:
count = 0
try:
clients_count = int(clients_entry and clients_entry.get() or 0)
except:
clients_count = 0
dampened_count = dampen_count(task_type, unit_type, count)
tasks_clients_counts[task_type] = tasks_clients_counts.get(task_type, 0) + clients_count
tasks_scramble_counts[task_type] = tasks_scramble_counts.get(task_type, 0) + dampened_count
flights[task_type][unit_type] = dampened_count, clients_count
for task in self.event.ai_banned_tasks:
if tasks_clients_counts.get(task, 0) == 0 and tasks_scramble_counts.get(task, 0) > 0:
self.error_label["text"] = "Need at least one player in flight {}".format(self.event.flight_name(task))
return
for task in self.event.player_banned_tasks:
if tasks_clients_counts.get(task, 0) != 0:
self.error_label["text"] = "Players are not allowed on flight {}".format(self.event.flight_name(task))
return
if self.game.is_player_attack(self.event):
if isinstance(self.event, FrontlineAttackEvent) or isinstance(self.event, FrontlinePatrolEvent):
if self.event.from_cp.base.total_armor == 0:
self.error_label["text"] = "No ground vehicles available to attack!"
return
self.event.player_attacking(flights)
else:
if isinstance(self.event, FrontlineAttackEvent) or isinstance(self.event, FrontlinePatrolEvent):
if self.event.to_cp.base.total_armor == 0:
self.error_label["text"] = "No ground vehicles available to defend!"
return
self.event.player_defending(flights)
self.game.initiate_event(self.event)
EventResultsMenu(self.window, self.parent, self.game, self.event).display()

View File

@ -1,180 +0,0 @@
from tkinter.ttk import *
from ui.window import *
from game.game import *
from userdata.debriefing import *
from .styles import STYLES
class EventResultsMenu(Menu):
debriefing = None # type: Debriefing
player_losses = {} # type: typing.Dict[UnitType, int]
enemy_losses = {} # type: typing.Dict[UnitType, int]
def __init__(self, window: Window, parent, game: Game, event: Event):
super(EventResultsMenu, self).__init__(window, parent, game)
self.frame = window.right_pane
self.frame.grid_rowconfigure(0, weight=0)
self.event = event
self.finished = False
wait_for_debriefing(callback=self.process_debriefing)
def display(self):
self.window.clear_right_pane()
row = 0
def header(text, style="strong"):
nonlocal row
head = Frame(self.frame, **STYLES["header"])
head.grid(row=row, column=0, sticky=N + EW, columnspan=2, pady=(0, 10))
Label(head, text=text, **STYLES[style]).grid()
row += 1
def label(text, style="widget"):
nonlocal row
Label(self.frame, text=text, **STYLES[style]).grid(row=row, column=0, sticky=NW, columnspan=2)
row += 1
if not self.finished:
header("You are clear for takeoff!")
label("In DCS, open and play the mission:")
label("liberation_nextturn", "italic")
label("or")
label("liberation_nextturn_quick", "italic")
header("Then save the debriefing to the folder:")
label(debriefing_directory_location(), "italic")
header("Waiting for results...")
pg = Progressbar(self.frame, orient="horizontal", length=200, mode="determinate")
pg.grid(row=row, column=0, columnspan=2, sticky=EW, pady=5, padx=5)
pg.start(10)
row += 1
"""
Label(self.frame, text="Cheat operation results: ", **STYLES["strong"]).grid(column=0, row=row,
columnspan=2, sticky=NSEW,
pady=5)
row += 1
Button(self.frame, text="full enemy losses", command=self.simulate_result(0, 1),
**STYLES["btn-warning"]).grid(column=0, row=row, padx=5, pady=5)
Button(self.frame, text="full player losses", command=self.simulate_result(1, 0),
**STYLES["btn-warning"]).grid(column=1, row=row, padx=5, pady=5)
row += 1
Button(self.frame, text="some enemy losses", command=self.simulate_result(0, 0.8),
**STYLES["btn-warning"]).grid(column=0, row=row, padx=5, pady=5)
Button(self.frame, text="some player losses", command=self.simulate_result(0.8, 0),
**STYLES["btn-warning"]).grid(column=1, row=row, padx=5, pady=5)
row += 1
"""
else:
row = 0
if self.event.is_successfull(self.debriefing):
header("Operation success", "title-green")
else:
header("Operation failed", "title-red")
header("Player losses")
for unit_type, count in self.player_losses.items():
Label(self.frame, text=db.unit_type_name(unit_type), **STYLES["widget"]).grid(row=row)
Label(self.frame, text="{}".format(count), **STYLES["widget"]).grid(column=1, row=row)
row += 1
header("Enemy losses")
if self.debriefing.destroyed_objects:
Label(self.frame, text="Ground assets", **STYLES["widget"]).grid(row=row)
Label(self.frame, text="{}".format(len(self.debriefing.destroyed_objects)), **STYLES["widget"]).grid(column=1, row=row)
row += 1
for unit_type, count in self.enemy_losses.items():
if count == 0:
continue
Label(self.frame, text=db.unit_type_name(unit_type), **STYLES["widget"]).grid(row=row)
Label(self.frame, text="{}".format(count), **STYLES["widget"]).grid(column=1, row=row)
row += 1
Button(self.frame, text="Okay", command=self.dismiss, **STYLES["btn-primary"]).grid(columnspan=1, row=row)
row += 1
def process_debriefing(self, debriefing: Debriefing):
self.debriefing = debriefing
debriefing.calculate_units(regular_mission=self.event.operation.regular_mission,
quick_mission=self.event.operation.quick_mission,
player_country=self.game.player_country,
enemy_country=self.game.enemy_country)
self.game.finish_event(event=self.event, debriefing=debriefing)
self.game.pass_turn(ignored_cps=[self.event.to_cp, ])
self.finished = True
self.player_losses = debriefing.destroyed_units.get(self.game.player_country, {})
self.enemy_losses = debriefing.destroyed_units.get(self.game.enemy_country, {})
self.display()
def simulate_result(self, player_factor: float, enemy_factor: float):
def action():
debriefing = Debriefing({}, [])
def count(country: Country) -> typing.Dict[UnitType, int]:
result = {}
for g in country.plane_group + country.vehicle_group + country.helicopter_group + country.ship_group:
group = g # type: Group
for unit in group.units:
unit_type = None
if isinstance(unit, Vehicle):
unit_type = vehicle_map[unit.type]
elif isinstance(unit, Ship):
unit_type = ship_map[unit.type]
else:
unit_type = unit.unit_type
if unit_type in db.EXTRA_AA.values():
continue
result[unit_type] = result.get(unit_type, 0) + 1
return result
player = self.event.operation.mission.country(self.game.player_country)
enemy = self.event.operation.mission.country(self.game.enemy_country)
alive_player_units = count(player)
alive_enemy_units = count(enemy)
destroyed_player_units = db.unitdict_restrict_count(alive_player_units, math.ceil(
sum(alive_player_units.values()) * player_factor))
destroyed_enemy_units = db.unitdict_restrict_count(alive_enemy_units, math.ceil(
sum(alive_enemy_units.values()) * enemy_factor))
alive_player_units = {k: v - destroyed_player_units.get(k, 0) for k, v in alive_player_units.items()}
alive_enemy_units = {k: v - destroyed_enemy_units.get(k, 0) for k, v in alive_enemy_units.items()}
debriefing.alive_units = {
enemy.name: alive_enemy_units,
player.name: alive_player_units,
}
debriefing.destroyed_units = {
player.name: destroyed_player_units,
enemy.name: destroyed_enemy_units,
}
self.finished = True
self.debriefing = debriefing
self.player_losses = debriefing.destroyed_units.get(self.game.player_country, {})
self.enemy_losses = debriefing.destroyed_units.get(self.game.enemy_country, {})
self.game.finish_event(self.event, debriefing)
self.display()
self.game.pass_turn()
return action

View File

@ -1,58 +0,0 @@
from game.game import *
from ui.basemenu import *
from ui.configurationmenu import *
from ui.overviewcanvas import *
from userdata import persistency
from .styles import STYLES
import tkinter as tk
from tkinter import ttk
class MainMenu(Menu):
basemenu = None # type: BaseMenu
def __init__(self, window: Window, parent, game: Game):
super(MainMenu, self).__init__(window, parent, game)
self.upd = OverviewCanvas(self.window.left_pane, self, game)
self.upd.update()
self.frame = self.window.right_pane
self.frame.rowconfigure(0, weight=0)
self.frame.rowconfigure(1, weight=1)
def display(self):
persistency.save_game(self.game)
self.window.clear_right_pane()
self.upd.update()
header = Frame(self.frame, **STYLES["header"])
header.grid(column=0, row=0, sticky=NSEW)
def pass_turn(self):
self.game.pass_turn(no_action=True)
self.upd.update()
self.display()
def configuration_menu(self):
ConfigurationMenu(self.window, self, self.game).display()
def start_event(self, event) -> typing.Callable:
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
self.basemenu = BaseMenu(self.window, self, self.game, cp)
self.basemenu.display()

View File

@ -1,171 +0,0 @@
import os
from tkinter import *
from tkinter.ttk import *
from ui.window import *
from .styles import STYLES
from game import db
class NewGameMenu(Menu):
selected_country = None # type: IntVar
selected_terrain = None # type: IntVar
sams = None
midgame = None
multiplier = None
def __init__(self, window: Window, callback: typing.Callable):
super(NewGameMenu, self).__init__(window, None, None)
self.frame = window.right_pane
window.left_pane.configure(background="black")
self.callback = callback
self.selected_country = IntVar()
self.selected_country.set(0)
self.selected_terrain = IntVar()
self.selected_terrain.set(0)
self.selected_time_period = StringVar()
self.selected_blue_faction = StringVar()
self.selected_red_faction = StringVar()
self.sams = BooleanVar()
self.sams.set(1)
self.multiplier = StringVar()
self.multiplier.set("1")
self.midgame = BooleanVar()
self.midgame.set(0)
@property
def player_country_name(self):
if self.selected_country.get() == 0:
return self.selected_blue_faction.get()
else:
return self.selected_red_faction.get()
@property
def enemy_country_name(self):
if self.selected_country.get() == 1:
return self.selected_blue_faction.get()
else:
return self.selected_red_faction.get()
@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()
# Header
head = Frame(self.frame, **STYLES["header"])
head.grid(row=0, column=0, sticky=NSEW)
Label(head, text="Start a new game", **STYLES["title"]).grid()
# Body
body = Frame(self.frame, **STYLES["body"])
body.grid(row=1, column=0, sticky=NSEW)
# Side Selection
side = LabelFrame(body, text="Player Side", **STYLES["label-frame"])
side.grid(row=2, column=0, sticky=NW, padx=5)
Radiobutton(side, variable=self.selected_country, value=0, **STYLES["radiobutton"]).grid(row=0, column=0,
sticky=W)
Label(side, text="BLUEFOR", **STYLES["widget"]).grid(row=0, column=1, sticky=W)
Radiobutton(side, variable=self.selected_country, value=1, **STYLES["radiobutton"]).grid(row=1, column=0,
sticky=W)
Label(side, text="REDFOR", **STYLES["widget"]).grid(row=1, column=1, sticky=W)
# Country Selection
blues = [c for c in db.FACTIONS if db.FACTIONS[c]["side"] == "blue"]
reds = [c for c in db.FACTIONS if db.FACTIONS[c]["side"] == "red"]
factions = LabelFrame(body, text="Factions", **STYLES["label-frame"])
factions.grid(row=0, column=0, sticky=NW, padx=5)
Label(factions, text="Blue Faction", **STYLES["widget"]).grid(row=1, column=0, sticky=SE)
self.selected_blue_faction.set(blues[0])
blue_select = OptionMenu(factions, self.selected_blue_faction, *blues)
blue_select.configure(**STYLES["btn-primary"])
blue_select.grid(row=1, column=1, sticky=W)
self.selected_red_faction.set(reds[1])
Label(factions, text="Red Faction", **STYLES["widget"]).grid(row=2, column=0, sticky=W)
red_select = OptionMenu(factions, self.selected_red_faction, *reds)
red_select.configure(**STYLES["btn-primary"])
red_select.grid(row=2, column=1, sticky=W)
# Terrain Selection
terrain = LabelFrame(body, text="Terrain", **STYLES["label-frame"])
terrain.grid(row=0, column=1, sticky=N, padx=5)
Radiobutton(terrain, variable=self.selected_terrain, value=0, **STYLES["radiobutton"]) \
.grid(row=0, column=0, sticky=W)
Label(terrain, text="Caucasus", **STYLES["widget"]).grid(row=0, column=1, sticky=W)
self.create_label_image(terrain, "terrain_caucasus.gif").grid(row=0, column=2, padx=5)
Radiobutton(terrain, variable=self.selected_terrain, value=1, **STYLES["radiobutton"]) \
.grid(row=1, column=0, sticky=W)
Label(terrain, text="Nevada", **STYLES["widget"]).grid(row=1, column=1, sticky=W)
self.create_label_image(terrain, "terrain_nevada.gif").grid(row=1, column=2, padx=5)
Radiobutton(terrain, variable=self.selected_terrain, value=2, **STYLES["radiobutton"]) \
.grid(row=2, column=0, sticky=W)
Label(terrain, text="Persian Gulf", **STYLES["widget"]).grid(row=2, column=1, sticky=W)
self.create_label_image(terrain, "terrain_pg.gif").grid(row=2, column=2, padx=5)
# Period selection
period = LabelFrame(body, text="Time Period", **STYLES["label-frame"])
period.grid(row=0, column=2, sticky=N, padx=5)
vals = list(db.TIME_PERIODS)
self.selected_time_period.set(vals[21])
period_select = OptionMenu(period, self.selected_time_period, *vals)
period_select.configure(**STYLES["btn-primary"])
period_select.grid(row=0, column=0, sticky=W)
#Label(terrain, text="Caucasus", **STYLES["widget"]).grid(row=0, column=1, sticky=W)
# Misc Options
options = LabelFrame(body, text="Misc Options", **STYLES["label-frame"])
options.grid(row=0, column=3, sticky=NE, padx=5)
Checkbutton(options, variable=self.sams, **STYLES["radiobutton"]).grid(row=0, column=0, sticky=W)
Label(options, text="SAMs", **STYLES["widget"]).grid(row=0, column=1, sticky=W)
Checkbutton(options, variable=self.midgame, **STYLES["radiobutton"]).grid(row=1, column=0, sticky=W)
Label(options, text="Mid Game", **STYLES["widget"]).grid(row=1, column=1, sticky=W)
Label(options, text="Multiplier", **STYLES["widget"]).grid(row=2, column=0, sticky=W)
Entry(options, textvariable=self.multiplier).grid(row=2, column=1, sticky=W)
# Footer with Proceed Button
footer = Frame(self.frame, **STYLES["header"])
footer.grid(row=2, sticky=N + E + W)
Button(footer, text="Proceed", command=self.proceed, **STYLES["btn-primary"]).grid(row=0, column=0, sticky=SE,
padx=5, pady=5)
@staticmethod
def create_label_image(parent, image):
im = PhotoImage(file=os.path.join("resources", "ui", image))
label = Label(parent, image=im)
label.image = im
return label
def proceed(self):
self.callback(self.player_country_name,
self.enemy_country_name,
self.terrain_name,
bool(self.sams.get()),
bool(self.midgame.get()),
float(self.multiplier.get()),
db.TIME_PERIODS[self.selected_time_period.get()])

View File

@ -1,675 +0,0 @@
import os
import platform
from threading import Thread
from tkinter.ttk import *
import pygame
from theater.theatergroundobject import CATEGORY_MAP
from ui.styles import STYLES
from ui.window import *
EVENT_COLOR_ATTACK = (100, 100, 255)
EVENT_COLOR_DEFENSE = (255, 100, 100)
RED = (255, 125, 125)
BRIGHT_RED = (200, 64, 64)
BLUE = (164, 164, 255)
DARK_BLUE = (45, 62, 80)
WHITE = (255, 255, 255)
GREEN = (128, 186, 128)
BRIGHT_GREEN = (64, 200, 64)
BLACK = (0, 0, 0)
BACKGROUND = pygame.Color(0, 64, 64)
ANTIALIASING = True
WIDTH = 1000
HEIGHT = 700
MAP_PADDING = 100
class OverviewCanvas:
mainmenu = None # type: ui.mainmenu.MainMenu
budget_label = None # type: Label
started = None
ground_assets_icons = None # type: typing.Dict[str, pygame.Surface]
event_icons = None # type: typing.Dict[typing.Type, pygame.Surface]
selected_event_info = None # type: typing.Tuple[Event, typing.Tuple[int, int]]
frontline_vector_cache = None # type: typing.Dict[str, typing.Tuple[Point, int, int]]
DAWN_ICON = None
DAY_ICON = None
DUSK_ICON = None
NIGHT_ICON = None
def __init__(self, frame: Frame, parent, game: Game):
self.parent = parent
self.game = game
self.load_icons()
# Remove any previously existing pygame instance
pygame.quit()
# Pygame objects
self.map = None
self.map_dusk_dawn = None
self.map_night = None
self.screen = None
self.surface: pygame.Surface = None
self.thread: Thread = None
self.clock = pygame.time.Clock()
self.expanded = True
pygame.font.init()
self.font: pygame.font.SysFont = pygame.font.SysFont("arial", 15)
self.fontsmall: pygame.font.SysFont = pygame.font.SysFont("arial", 10)
self.ground_assets_icons = {}
# Frontline are too heavy on performance to compute in realtime, so keep them in a cache
self.frontline_vector_cache = {}
# Map state
self.redraw_required = True
self.zoom = 1
self.scroll = [0, 0]
self.exited = False
# Display options
self.display_ground_targets = BooleanVar(value=True)
self.display_forces = BooleanVar(value=True)
self.display_bases = BooleanVar(value=True)
self.display_road = BooleanVar(value=True)
self.display_rules = self.compute_display_rules()
parent.window.tk.protocol("<WM_DELETE_WINDOW>", self.on_close)
self.wrapper = Frame(frame, **STYLES["frame-wrapper"])
self.wrapper.grid(column=0, row=0, sticky=NSEW) # Adds grid
self.wrapper.pack(side=LEFT) # packs window to the left
self.embed = Frame(self.wrapper, width=WIDTH, height=HEIGHT, borderwidth=2, **STYLES["frame-wrapper"])
self.embed.grid(column=0, row=1, sticky=NSEW) # Adds grid
self.options = Frame(self.wrapper, borderwidth=2, **STYLES["frame-wrapper"])
self.options.grid(column=0, row=0, sticky=NSEW)
self.options.grid_columnconfigure(1, weight=1)
self.build_map_options_panel()
self.init_sdl_layer()
self.init_sdl_thread()
def build_map_options_panel(self):
col = 0
Button(self.options, text="Configuration", command=self.parent.configuration_menu,
**{**STYLES["btn-primary"],**{ "pady": 4}}).grid(column=col, row=0, sticky=NW)
col += 1
money_icon = Label(self.options, image=self.MONEY_ICON, **STYLES["widget-big"])
money_icon.grid(column=col, row=0, sticky=NE)
col += 1
self.current_budget = StringVar()
self.budget_label = Label(self.options, textvariable=self.current_budget, **STYLES["widget-big"])
self.budget_label.grid(column=col, row=0, sticky=NW)
col += 1
self.daytime_icon = Label(self.options, image=self.DAWN_ICON, **STYLES["widget-big"])
self.daytime_icon.grid(column=col, row=0, sticky=NE)
col += 1
self.current_turn = StringVar()
self.turn_label = Label(self.options, textvariable=self.current_turn, **STYLES["widget-big"])
self.turn_label.grid(column=col, row=0, sticky=NE)
col += 1
Button(self.options, text="Pass turn", command=self.parent.pass_turn,
**{**STYLES["btn-primary"],**{ "pady": 4}}).grid(column=col, row=0, sticky=NE)
col += 1
def map_size_toggle(self):
if self.expanded:
self.embed.configure(width=0)
self.options.configure(width=0)
self.expanded = False
else:
self.embed.configure(width=WIDTH)
self.options.configure(width=WIDTH)
self.expanded = True
def on_close(self):
self.exited = True
if self.thread is not None:
self.thread.join()
def load_icons(self):
if self.DAWN_ICON is None :
self.DAWN_ICON = PhotoImage(file="./resources/ui/daytime/dawn.png")
self.DAY_ICON = PhotoImage(file="./resources/ui/daytime/day.png")
self.DUSK_ICON = PhotoImage(file="./resources/ui/daytime/dusk.png")
self.NIGHT_ICON = PhotoImage(file="./resources/ui/daytime/night.png")
self.MONEY_ICON = PhotoImage(file="./resources/ui/misc/money_icon.png")
self.ORDNANCE_ICON = PhotoImage(file="./resources/ui/misc/ordnance_icon.png")
def init_sdl_layer(self):
# Setup pygame to run in tk frame
os.environ['SDL_WINDOWID'] = str(self.embed.winfo_id())
if platform.system == "Windows":
os.environ['SDL_VIDEODRIVER'] = 'windib'
# Create pygame 'screen'
self.screen = pygame.display.set_mode((WIDTH, HEIGHT), pygame.DOUBLEBUF | pygame.HWSURFACE)
self.screen.fill(pygame.Color(*BLACK))
# Load icons resources
self.ground_assets_icons = {}
self.ground_assets_icons["target"] = pygame.image.load(os.path.join("resources", "ui", "ground_assets", "target.png"))
self.ground_assets_icons["cleared"] = pygame.image.load(os.path.join("resources", "ui", "ground_assets", "cleared.png"))
for category in CATEGORY_MAP.keys():
self.ground_assets_icons[category] = pygame.image.load(os.path.join("resources", "ui", "ground_assets", category + ".png"))
self.event_icons = {}
for category, image in {BaseAttackEvent: "capture",
FrontlinePatrolEvent: "attack",
FrontlineAttackEvent: "attack",
InfantryTransportEvent: "infantry",
InsurgentAttackEvent: "insurgent_attack",
ConvoyStrikeEvent: "convoy",
InterceptEvent: "air_intercept",
NavalInterceptEvent: "naval_intercept",
StrikeEvent: "strike",
UnitsDeliveryEvent: "delivery"}.items():
self.event_icons[category] = pygame.image.load(os.path.join("resources", "ui", "events", image + ".png"))
# Load the map image
self.map = pygame.image.load(os.path.join("resources", self.game.theater.overview_image)).convert()
pygame.draw.rect(self.map, BLACK, (0, 0, self.map.get_width(), self.map.get_height()), 10)
pygame.draw.rect(self.map, WHITE, (0, 0, self.map.get_width(), self.map.get_height()), 5)
# Generate map for night and dusk/dawn
self.map_night = self.map.copy()
self.map_night.fill((100, 100, 110, 128), special_flags=pygame.BLEND_MULT)
self.map_dusk_dawn = self.map.copy()
self.map_dusk_dawn.fill((220, 150, 125, 128), special_flags=pygame.BLEND_MULT)
# Create surfaces for drawing
self.surface = pygame.Surface((self.map.get_width() + MAP_PADDING * 2,
self.map.get_height() + MAP_PADDING * 2))
self.surface.set_alpha(None)
self.overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
# Init pygame display
pygame.display.init()
pygame.display.update()
def init_sdl_thread(self):
if OverviewCanvas.started is not None:
OverviewCanvas.started.exited = True
self.thread = Thread(target=self.sdl_thread)
self.thread.start()
OverviewCanvas.started = self
print("Started SDL app")
def sdl_thread(self):
self.redraw_required = True
i = 0
while not self.exited:
self.clock.tick(30)
self.updateOptions()
self.draw()
i += 1
if i == 600:
self.frontline_vector_cache = {}
i = 0
print("Stopped SDL app")
def draw(self):
try:
self.embed.winfo_ismapped()
self.embed.winfo_manager()
except:
self.exited = True
right_down = False
left_down = False
# Detect changes on display rules
r = self.compute_display_rules()
if r != self.display_rules:
self.display_rules = r
self.redraw_required = True
for event in pygame.event.get():
if event.type == pygame.MOUSEMOTION:
self.redraw_required = True
elif event.type == pygame.MOUSEBUTTONDOWN:
"""
Due to rendering not really supporting the zoom this is currently disabled.
@TODO: improve rendering so zoom would actually make sense
# Scroll wheel"""
if event.button == 4:
self.zoom += 0.25
self.redraw_required = True
elif event.button == 5:
self.zoom -= 0.25
self.redraw_required = True
""""""
if event.button == 3:
right_down = True
pygame.mouse.get_rel()
if event.button == 1:
left_down = True
self.redraw_required = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_F2:
self.display_bases.set(not self.display_bases.get())
elif event.key == pygame.K_F3:
self.display_forces.set(not self.display_forces.get())
elif event.key == pygame.K_F4:
self.display_ground_targets.set(not self.display_ground_targets.get())
elif event.key == pygame.K_F5:
self.display_road.set(not self.display_road.get())
# If Right click pressed
if pygame.mouse.get_pressed()[2] == 1 and not right_down:
scr = pygame.mouse.get_rel()
self.scroll[0] += scr[0]
self.scroll[1] += scr[1]
self.redraw_required = True
if self.zoom <= 0.5:
self.zoom = 0.5
elif self.zoom > 3:
self.zoom = 3
if self.redraw_required:
# Fill
self.screen.fill(BACKGROUND)
self.surface.fill(BACKGROUND)
self.overlay.fill(pygame.Color(0, 0, 0, 0))
# Surface
cursor_pos = pygame.mouse.get_pos()
cursor_pos = (
cursor_pos[0] / self.zoom - self.scroll[0], cursor_pos[1] / self.zoom - self.scroll[1])
self.draw_map(self.surface, self.overlay, cursor_pos, [left_down, right_down])
# Scaling
scaled = pygame.transform.scale(self.surface, (
int(self.surface.get_width() * self.zoom), int(self.surface.get_height() * self.zoom)))
self.screen.blit(scaled, (self.scroll[0]*self.zoom, self.scroll[1]*self.zoom))
self.screen.blit(self.overlay, (0, 0))
pygame.display.flip()
self.redraw_required = False
def draw_map(self, surface: pygame.Surface, overlay: pygame.Surface, mouse_pos: (int, int), mouse_down: [bool, bool]):
daytime = self.game.current_turn_daytime
if daytime == "day":
self.surface.blit(self.map, (MAP_PADDING, MAP_PADDING))
elif daytime == "night":
self.surface.blit(self.map_night, (MAP_PADDING, MAP_PADDING))
else:
self.surface.blit(self.map_dusk_dawn, (MAP_PADDING, MAP_PADDING))
# Display zoom level on overlay
zoom_lvl = self.font.render(" x " + str(self.zoom) + " ", ANTIALIASING, WHITE, DARK_BLUE)
self.overlay.blit(zoom_lvl, (self.overlay.get_width()-zoom_lvl.get_width()-5,
self.overlay.get_height()-zoom_lvl.get_height()-5))
# Debug
# pygame.draw.rect(surface, (255, 0, 255), (mouse_pos[0], mouse_pos[1], 5, 5), 2)
for cp in self.game.theater.controlpoints:
coords = self._transform_point(cp.position)
if self.display_road.get():
for connected_cp in cp.connected_points:
connected_coords = self._transform_point(connected_cp.position)
if connected_cp.captured != cp.captured:
color = self._enemy_color()
elif connected_cp.captured and cp.captured:
color = self._player_color()
else:
color = BLACK
pygame.draw.line(surface, color, coords, connected_coords, 2)
if cp.captured and not connected_cp.captured and Conflict.has_frontline_between(cp, connected_cp):
frontline = self._frontline_vector(cp, connected_cp)
if not frontline:
continue
frontline_pos, heading, distance = frontline
if distance < 10000:
frontline_pos = frontline_pos.point_from_heading(heading + 180, 5000)
distance = 10000
start_coords = self._transform_point(frontline_pos, treshold=10)
end_coords = self._transform_point(frontline_pos.point_from_heading(heading, distance),
treshold=60)
pygame.draw.line(surface, color, start_coords, end_coords, 4)
if self.display_ground_targets.get():
for ground_object in cp.ground_objects:
pygame.draw.line(surface, RED, self._transform_point(cp.position), self._transform_point(ground_object.position), 1)
self.draw_ground_object(ground_object, surface, cp.captured, mouse_pos)
if self.display_bases.get():
mouse_down = self.draw_bases(mouse_pos, mouse_down)
mouse_down = self.draw_events(self.surface, mouse_pos, mouse_down)
if mouse_down[0]:
self.selected_event_info = None
def draw_bases(self, mouse_pos, mouse_down):
for cp in self.game.theater.controlpoints:
coords = self._transform_point(cp.position)
radius = 12 * math.pow(cp.importance, 1)
radius_m = max(radius * cp.base.strength - 2, 0)
if cp.captured:
color = self._player_color()
else:
color = self._enemy_color()
pygame.draw.circle(self.surface, BLACK, (int(coords[0]), int(coords[1])), int(radius))
pygame.draw.circle(self.surface, color, (int(coords[0]), int(coords[1])), int(radius_m))
label = self.font.render(cp.name, ANTIALIASING, (225, 225, 225), BLACK)
labelHover = self.font.render(cp.name, ANTIALIASING, (255, 255, 255), (128, 186, 128))
labelClick = self.font.render(cp.name, ANTIALIASING, (255, 255, 255), (122, 122, 255))
point = coords[0] - label.get_width() / 2 + 1, coords[1] + 1
rect = pygame.Rect(*point, label.get_width(), label.get_height())
if rect.collidepoint(*mouse_pos):
if mouse_down[0]:
self.surface.blit(labelClick, (coords[0] - label.get_width() / 2 + 1, coords[1] + 1))
self._selected_cp(cp)
mouse_down[0] = False
else:
self.surface.blit(labelHover, (coords[0] - label.get_width() / 2 + 1, coords[1] + 1))
self.draw_base_info(self.overlay, cp, (0, 0))
if self.selected_event_info:
if self._cp_available_for_selected_event(cp):
pygame.draw.line(self.surface, WHITE, rect.center, self.selected_event_info[1])
else:
self.surface.blit(label, (coords[0] - label.get_width() / 2 + 1, coords[1] + 1))
if self.display_forces.get():
units_title = " {} / {} / {} ".format(cp.base.total_planes, cp.base.total_armor, cp.base.total_aa)
label2 = self.fontsmall.render(units_title, ANTIALIASING, color, (30, 30, 30))
self.surface.blit(label2, (coords[0] - label2.get_width() / 2, coords[1] + label.get_height() + 1))
return mouse_down
def draw_base_info(self, surface: pygame.Surface, control_point: ControlPoint, pos):
title = self.font.render(control_point.name, ANTIALIASING, BLACK, GREEN)
hp = self.font.render("Strength : ", ANTIALIASING, (225, 225, 225), BLACK)
armor_txt = "ARMOR > "
for key, value in control_point.base.armor.items():
armor_txt += key.id + " x " + str(value) + " | "
armor = self.font.render(armor_txt, ANTIALIASING, (225, 225, 225), BLACK)
aircraft_txt = "AIRCRAFT > "
for key, value in control_point.base.aircraft.items():
aircraft_txt += key.id + " x " + str(value) + " | "
aircraft = self.font.render(aircraft_txt, ANTIALIASING, (225, 225, 225), BLACK)
aa_txt = "AA/SAM > "
for key, value in control_point.base.aa.items():
aa_txt += key.id + " x " + str(value) + " | "
aa = self.font.render(aa_txt, ANTIALIASING, (225, 225, 225), BLACK)
lineheight = title.get_height()
w = max([max([a.get_width() for a in [title, armor, aircraft, aa]]), 150])
h = 5 * lineheight + 4 * 5
# Draw frame
pygame.draw.rect(surface, GREEN, (pos[0], pos[1], w + 8, h + 8))
pygame.draw.rect(surface, BLACK, (pos[0] + 2, pos[1] + 2, w + 4, h + 4))
pygame.draw.rect(surface, GREEN, (pos[0] + 2, pos[1], w + 4, lineheight + 4))
# Title
surface.blit(title, (pos[0] + 4, 4 + pos[1]))
surface.blit(hp, (pos[0] + 4, 4 + pos[1] + lineheight + 5))
# Draw gauge
pygame.draw.rect(surface, WHITE,
(pos[0] + hp.get_width() + 3, 4 + pos[1] + lineheight + 5, 54, lineheight))
pygame.draw.rect(surface, BRIGHT_RED,
(pos[0] + hp.get_width() + 5, 4 + pos[1] + lineheight + 5 + 2, 50, lineheight - 4))
pygame.draw.rect(surface, BRIGHT_GREEN, (
pos[0] + hp.get_width() + 5, 4 + pos[1] + lineheight + 5 + 2, 50 * control_point.base.strength, lineheight - 4))
# Text
surface.blit(armor, (pos[0] + 4, 4 + pos[1] + lineheight * 2 + 10))
surface.blit(aircraft, (pos[0] + 4, 4 + pos[1] + lineheight * 3 + 15))
surface.blit(aa, (pos[0] + 4, 4 + pos[1] + lineheight * 4 + 20))
def draw_selected_event_info(self):
event = self.selected_event_info[0]
title = self.font.render(str(event), ANTIALIASING, BLACK, GREEN)
hint = self.font.render("Select CP to depart from.", ANTIALIASING, (225, 225, 225), BLACK)
w = hint.get_width()
h = title.get_height() + hint.get_height() + 20
pos = self.overlay.get_width() / 2 - w / 2, self.overlay.get_height() - h
# Draw frame
pygame.draw.rect(self.overlay, GREEN, (pos[0], pos[1], w + 8, h + 8))
pygame.draw.rect(self.overlay, BLACK, (pos[0] + 2, pos[1] + 2, w + 4, h + 4))
pygame.draw.rect(self.overlay, GREEN, (pos[0] + 2, pos[1], w + 4, title.get_height() + 4))
# Title
self.overlay.blit(title, (pos[0] + 4, 4 + pos[1]))
self.overlay.blit(hint, (pos[0] + 4, 4 + pos[1] + title.get_height() + 5))
def draw_ground_object(self, ground_object: TheaterGroundObject, surface: pygame.Surface, captured: bool, mouse_pos):
if captured:
color = self._player_color()
else:
color = self._enemy_color()
x, y = self._transform_point(ground_object.position)
rect = pygame.Rect(x, y, 16, 16)
if ground_object.is_dead or captured:
surface.blit(self.ground_assets_icons["cleared"], (x, y))
else:
if ground_object.category in self.ground_assets_icons.keys():
icon = self.ground_assets_icons[ground_object.category]
else:
icon = self.ground_assets_icons["target"]
surface.blit(icon, (x, y))
if rect.collidepoint(*mouse_pos):
self.draw_ground_object_info(ground_object, (x, y), color, surface)
def draw_ground_object_info(self, ground_object: TheaterGroundObject, pos, color, surface: pygame.Surface):
lb = self.font.render(str(ground_object), ANTIALIASING, color, BLACK)
surface.blit(lb, (pos[0] + 18, pos[1]))
def draw_events(self, surface: pygame.Surface, mouse_pos, mouse_down):
occupied_rects = []
for cp in self.game.theater.controlpoints:
point = self._transform_point(cp.position)
occupied_rects.append(pygame.Rect(point[0] - 16, point[1] - 16, 32, 48))
def _location_to_rect(location: Point) -> pygame.Rect:
nonlocal occupied_rects
point = self._transform_point(location)
rect = pygame.Rect(point[0] - 16, point[1] - 16, 32, 32)
i = 0
while True:
result = True
for occupied_rect in occupied_rects:
if rect.colliderect(occupied_rect):
i += 1
if i % 2:
rect.y += occupied_rect.height
else:
rect.x += occupied_rect.width
result = False
break
if result:
break
occupied_rects.append(rect)
return rect
def _events_priority_key(event: Event) -> int:
priority_list = [InfantryTransportEvent, StrikeEvent, BaseAttackEvent, UnitsDeliveryEvent]
if type(event) not in priority_list:
return 0
else:
return priority_list.index(type(event)) + 1
events = self.game.events
events.sort(key=_events_priority_key, reverse=True)
label_to_draw = None
for event in self.game.events:
location = event.location
if type(event) in [FrontlineAttackEvent, FrontlinePatrolEvent, ConvoyStrikeEvent]:
location = self._frontline_center(event.from_cp, event.to_cp)
rect = _location_to_rect(location)
pygame.draw.rect(surface, EVENT_COLOR_ATTACK if event.is_player_attacking else EVENT_COLOR_DEFENSE, rect)
self.surface.blit(self.event_icons[event.__class__], rect.topleft)
if rect.collidepoint(*mouse_pos) or self.selected_event_info == (event, rect.center):
if not label_to_draw:
label_to_draw = self.font.render(str(event), ANTIALIASING, WHITE, BLACK), rect.center
if rect.collidepoint(*mouse_pos):
if mouse_down[0]:
self.selected_event_info = event, rect.center
mouse_down[0] = False
if label_to_draw:
surface.blit(*label_to_draw)
if self.selected_event_info:
self.draw_selected_event_info()
return mouse_down
def _selected_cp(self, cp):
if self.selected_event_info:
if self. _cp_available_for_selected_event(cp):
event = self.selected_event_info[0]
event.departure_cp = cp
self.selected_event_info = None
self.parent.start_event(event)
else:
return
else:
self.parent.go_cp(cp)
def _transform_point(self, p: Point, treshold=30) -> (int, int):
point_a = list(self.game.theater.reference_points.keys())[0]
point_a_img = self.game.theater.reference_points[point_a]
point_b = list(self.game.theater.reference_points.keys())[1]
point_b_img = self.game.theater.reference_points[point_b]
Y_dist = point_a_img[0] - point_b_img[0]
lon_dist = point_a[1] - point_b[1]
X_dist = point_a_img[1] - point_b_img[1]
lat_dist = point_b[0] - point_a[0]
Y_scale = float(Y_dist) / float(lon_dist)
X_scale = float(X_dist) / float(lat_dist)
# ---
Y_offset = p.x - point_a[0]
X_offset = p.y - point_a[1]
X = point_b_img[1] + X_offset * X_scale
Y = point_a_img[0] - Y_offset * Y_scale
X += MAP_PADDING
Y += MAP_PADDING
return X > treshold and X or treshold, Y > treshold and Y or treshold
def _frontline_vector(self, from_cp: ControlPoint, to_cp: ControlPoint):
# Cache mechanism to avoid performing frontline vector computation on every frame
key = str(from_cp.id) + "_" + str(to_cp.id)
if key in self.frontline_vector_cache:
return self.frontline_vector_cache[key]
else:
frontline = Conflict.frontline_vector(from_cp, to_cp, self.game.theater)
self.frontline_vector_cache[key] = frontline
return frontline
def _frontline_center(self, from_cp: ControlPoint, to_cp: ControlPoint) -> typing.Optional[Point]:
frontline_vector = self._frontline_vector(from_cp, to_cp)
if frontline_vector:
return frontline_vector[0].point_from_heading(frontline_vector[1], frontline_vector[2]/2)
else:
return None
def _cp_available_for_selected_event(self, cp: ControlPoint) -> bool:
event = self.selected_event_info[0]
return event.is_departure_available_from(cp)
def _player_color(self):
return self.game.player_country == "USA" and BLUE or RED
def _enemy_color(self):
return self.game.player_country == "USA" and RED or BLUE
def update(self):
self.redraw_required = True
self.draw()
def compute_display_rules(self):
return sum([1 if a.get() else 0 for a in [self.display_forces, self.display_road, self.display_bases, self.display_ground_targets]])
def display(self, cp: ControlPoint):
def action(_):
return self.parent.go_cp(cp)
return action
def updateOptions(self):
self.current_turn.set("Turn : {} - {}".format(self.game.turn, self.game.current_day.strftime("%d %b %Y")))
self.current_budget.set("{}M $ (+{}M $)".format(self.game.budget, self.game.budget_reward_amount))
daytime = self.game.current_turn_daytime
if daytime == "dawn":
self.daytime_icon.configure(image=self.DAWN_ICON)
elif daytime == "day":
self.daytime_icon.configure(image=self.DAY_ICON)
elif daytime == "dusk":
self.daytime_icon.configure(image=self.DUSK_ICON)
elif daytime == "night":
self.daytime_icon.configure(image=self.NIGHT_ICON)

View File

@ -1,52 +0,0 @@
# Style for UI
# Padding
PADDING_X = 5
PADDING_Y = 5
# Colors
FG_COLOR = "white"
FG_COLOR_LIGHT = "#dddddd"
BG_COLOR = "#4E5760"
GREEN = "#699245"
YELLOW = "#BF9A46"
RED = "#D0232E"
BG_TITLE_COLOR = "#2D3E50"
BG_SUBTITLE_COLOR = "#3E4F61"
# Fonts
FONT_FAMILY = "Trebuchet MS"
DEFAULT_FONT = (FONT_FAMILY, 8)
FONT_BIG = (FONT_FAMILY, 12)
ITALIC = (FONT_FAMILY, 8, "italic")
BOLD_FONT = (FONT_FAMILY, 10, "bold italic")
TITLE_FONT = (FONT_FAMILY, 16, "bold italic")
# List of styles
STYLES = {}
STYLES["label-frame"] = {"font": BOLD_FONT, "bg": BG_COLOR, "fg": FG_COLOR}
STYLES["frame-wrapper"] = {"bg": BG_COLOR, "relief":"sunken"}
STYLES["body"] = {"bg": BG_COLOR, "padx": 10, "pady": 10}
STYLES["strong"] = {"font": BOLD_FONT, "bg": BG_TITLE_COLOR, "fg": FG_COLOR}
STYLES["substrong"] = {"font": BOLD_FONT, "bg": BG_SUBTITLE_COLOR, "fg": FG_COLOR}
STYLES["supstrong"] = {"font": BOLD_FONT, "bg": RED, "fg": FG_COLOR}
STYLES["strong-grey"] = {"font": BOLD_FONT, "bg": BG_TITLE_COLOR, "fg": FG_COLOR_LIGHT}
STYLES["mission-preview"] = {"font": BOLD_FONT, "bg": YELLOW, "fg": FG_COLOR}
STYLES["widget"] = {"bg": BG_COLOR, "fg": FG_COLOR, "padx": PADDING_X, "pady": PADDING_Y, "font": DEFAULT_FONT}
STYLES["widget-big"] = {"bg": BG_COLOR, "fg": FG_COLOR, "padx": PADDING_X, "pady": PADDING_Y, "font": FONT_BIG, "relief": "ridge", "borderwidth": 1, "highlightcolor": "white"}
STYLES["italic"] = {"bg": BG_COLOR, "fg": FG_COLOR, "padx": PADDING_X, "pady": PADDING_Y, "font": ITALIC}
STYLES["radiobutton"] = {"bg": BG_COLOR, "fg": "black", "padx": PADDING_X, "pady": PADDING_Y, "font": DEFAULT_FONT,
"activebackground": BG_COLOR, "highlightbackground": BG_COLOR, "selectcolor": "white"}
STYLES["title"] = {"bg": BG_TITLE_COLOR, "fg": FG_COLOR, "padx": PADDING_X, "pady": PADDING_Y, "font": TITLE_FONT}
STYLES["title-green"] = {"bg": GREEN, "fg": FG_COLOR, "padx": PADDING_X, "pady": PADDING_Y, "font": TITLE_FONT}
STYLES["title-red"] = {"bg": RED, "fg": FG_COLOR, "padx": PADDING_X, "pady": PADDING_Y, "font": TITLE_FONT}
STYLES["header"] = {"bg": BG_TITLE_COLOR}
STYLES["subheader"] = {"bg": BG_SUBTITLE_COLOR}
STYLES["btn-primary"] = {"bg": GREEN, "fg": FG_COLOR, "padx": PADDING_X, "pady": 2, "font": DEFAULT_FONT}
STYLES["btn-primary-big"] = {"bg": GREEN, "fg": FG_COLOR, "padx": PADDING_X, "pady": 2, "font": FONT_BIG}
STYLES["btn-danger"] = {"bg": RED, "fg": FG_COLOR, "padx": PADDING_X, "pady": 2, "font": DEFAULT_FONT}
STYLES["btn-warning"] = {"bg": YELLOW, "fg": FG_COLOR, "padx": PADDING_X, "pady": 2, "font": DEFAULT_FONT}

View File

@ -1,164 +0,0 @@
from tkinter import *
from tkinter import Menu as TkMenu
from tkinter import messagebox
from .styles import BG_COLOR,BG_TITLE_COLOR
from game.game import *
from theater import persiangulf, nevada, caucasus, start_generator
from userdata import logging as logging_module
import sys
import webbrowser
class Window:
image = None
left_pane = None # type: Frame
right_pane = None # type: Frame
def __init__(self):
self.tk = Tk()
self.tk.title("DCS Liberation")
self.tk.iconbitmap("resources/icon.ico")
self.tk.resizable(False, False)
self.tk.grid_columnconfigure(0, weight=1)
self.tk.grid_rowconfigure(0, weight=1)
self.frame = None
self.right_pane = None
self.left_pane = None
self.build()
menubar = TkMenu(self.tk)
filemenu = TkMenu(menubar, tearoff=0)
filemenu.add_command(label="New Game", command=lambda: self.new_game_confirm())
filemenu.add_separator()
filemenu.add_command(label="Exit", command=lambda: self.exit())
menubar.add_cascade(label="File", menu=filemenu)
helpmenu = TkMenu(menubar, tearoff=0)
helpmenu.add_command(label="Online Manual", command=lambda: webbrowser.open_new_tab("https://github.com/shdwp/dcs_liberation/wiki/Manual"))
helpmenu.add_command(label="Troubleshooting Guide", command=lambda: webbrowser.open_new_tab("https://github.com/shdwp/dcs_liberation/wiki/Troubleshooting"))
helpmenu.add_command(label="Modding Guide", command=lambda: webbrowser.open_new_tab("https://github.com/shdwp/dcs_liberation/wiki/Modding-tutorial"))
helpmenu.add_separator()
helpmenu.add_command(label="Contribute", command=lambda: webbrowser.open_new_tab("https://github.com/shdwp/dcs_liberation"))
helpmenu.add_command(label="Forum Thread", command=lambda: webbrowser.open_new_tab("https://forums.eagle.ru/showthread.php?t=214834"))
helpmenu.add_command(label="Report an issue", command=self.report_issue)
menubar.add_cascade(label="Help", menu=helpmenu)
self.tk.config(menu=menubar)
self.tk.focus()
def build(self):
self.frame = Frame(self.tk, bg=BG_COLOR)
self.frame.grid(column=0, row=0, sticky=NSEW)
self.frame.grid_columnconfigure(0)
self.frame.grid_columnconfigure(1)
self.frame.grid_columnconfigure(0, weight=0)
self.frame.grid_columnconfigure(1, weight=1)
self.frame.grid_rowconfigure(0, weight=1)
self.left_pane = Frame(self.frame, bg=BG_TITLE_COLOR)
self.left_pane.grid(row=0, column=0, sticky=NSEW)
self.right_pane = Frame(self.frame, bg=BG_COLOR)
self.right_pane.grid(row=0, column=1, sticky=NSEW)
def clear_right_pane(self):
for i in range(100):
self.right_pane.grid_columnconfigure(1, weight=0)
self.right_pane.grid_rowconfigure(1, weight=0)
for x in self.right_pane.winfo_children():
x.grid_remove()
def clear(self):
def clear_recursive(x, n=50):
if n < 0:
return
for y in x.winfo_children():
clear_recursive(y, n-1)
x.grid_forget()
clear_recursive(self.frame, 50)
self.left_pane.grid_remove()
self.right_pane.grid_remove()
self.build()
def start_new_game(self, player_name: str, enemy_name: str, terrain: str, sams: bool, midgame: bool, multiplier: float, period:datetime):
player_country = db.FACTIONS[player_name]["country"]
enemy_country = db.FACTIONS[enemy_name]["country"]
if terrain == "persiangulf":
conflicttheater = persiangulf.PersianGulfTheater()
elif terrain == "nevada":
conflicttheater = nevada.NevadaTheater()
else:
conflicttheater = caucasus.CaucasusTheater()
if midgame:
for i in range(0, int(len(conflicttheater.controlpoints) / 2)):
conflicttheater.controlpoints[i].captured = True
start_generator.generate_inital_units(conflicttheater, enemy_name, sams, multiplier)
game = Game(player_name=player_name,
enemy_name=enemy_name,
theater=conflicttheater,
start_date=period)
start_generator.generate_groundobjects(conflicttheater, game)
game.budget = int(game.budget * multiplier)
game.settings.multiplier = multiplier
game.settings.sams = sams
game.settings.version = logging_module.version_string()
if midgame:
game.budget = game.budget * 4 * len(list(conflicttheater.conflicts()))
self.proceed_to_main_menu(game)
def proceed_to_main_menu(self, game: Game):
from ui.mainmenu import MainMenu
self.clear()
m = MainMenu(self, None, game)
m.display()
def proceed_to_new_game_menu(self):
from ui.newgamemenu import NewGameMenu
self.clear()
new_game_menu = NewGameMenu(self, self.start_new_game)
new_game_menu.display()
def new_game_confirm(self):
result = messagebox.askquestion("Start a new game", "Are you sure you want to start a new game ? Your current campaign will be overriden and there is no going back !", icon='warning')
if result == 'yes':
self.proceed_to_new_game_menu()
else:
pass
def report_issue(self):
raise logging_module.ShowLogsException()
def exit(self):
self.tk.destroy()
sys.exit(0)
def run(self):
self.tk.mainloop()
class Menu:
parent = None # type: Menu
def __init__(self, window: Window, parent, game: Game):
self.window = window
self.parent = parent
self.game = game
def dismiss(self):
self.parent.display()
def display(self):
pass