mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
UI update; enemy vehicle difficulty settings; minor adjustments
This commit is contained in:
parent
0015667829
commit
520a0f91fd
@ -76,6 +76,7 @@ PRICES = {
|
|||||||
S_3B_Tanker: 13,
|
S_3B_Tanker: 13,
|
||||||
IL_78M: 13,
|
IL_78M: 13,
|
||||||
KC_135: 13,
|
KC_135: 13,
|
||||||
|
KC130: 13,
|
||||||
|
|
||||||
A_50: 8,
|
A_50: 8,
|
||||||
E_3A: 8,
|
E_3A: 8,
|
||||||
@ -172,6 +173,7 @@ UNIT_BY_TASK = {
|
|||||||
Refueling: [
|
Refueling: [
|
||||||
IL_78M,
|
IL_78M,
|
||||||
KC_135,
|
KC_135,
|
||||||
|
KC130,
|
||||||
],
|
],
|
||||||
|
|
||||||
AWACS: [E_3A, A_50, ],
|
AWACS: [E_3A, A_50, ],
|
||||||
@ -297,6 +299,7 @@ UNIT_BY_COUNTRY = {
|
|||||||
AV8BNA,
|
AV8BNA,
|
||||||
|
|
||||||
KC_135,
|
KC_135,
|
||||||
|
KC130,
|
||||||
S_3B_Tanker,
|
S_3B_Tanker,
|
||||||
C_130,
|
C_130,
|
||||||
E_3A,
|
E_3A,
|
||||||
|
|||||||
@ -86,7 +86,9 @@ class Operation:
|
|||||||
|
|
||||||
# air support
|
# air support
|
||||||
self.airsupportgen.generate(self.is_awacs_enabled)
|
self.airsupportgen.generate(self.is_awacs_enabled)
|
||||||
self.briefinggen.append_frequency("Tanker", "10X/131 MHz AM")
|
for i, tanker_type in enumerate(self.airsupportgen.generated_tankers):
|
||||||
|
self.briefinggen.append_frequency("{} Tanker".format(tanker_type), "{}X/{} MHz AM".format(97+i, 130+i))
|
||||||
|
|
||||||
if self.is_awacs_enabled:
|
if self.is_awacs_enabled:
|
||||||
self.briefinggen.append_frequency("AWACS", "133 MHz AM")
|
self.briefinggen.append_frequency("AWACS", "133 MHz AM")
|
||||||
|
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
class Settings:
|
class Settings:
|
||||||
player_skill = "Good"
|
player_skill = "Good"
|
||||||
enemy_skill = "Average"
|
enemy_skill = "Average"
|
||||||
|
enemy_vehicle_skill = "Average"
|
||||||
only_player_takeoff = True
|
only_player_takeoff = True
|
||||||
night_disabled = False
|
night_disabled = False
|
||||||
multiplier = 1
|
multiplier = 1
|
||||||
|
|||||||
@ -4,7 +4,7 @@ from .naming import *
|
|||||||
from dcs.mission import *
|
from dcs.mission import *
|
||||||
|
|
||||||
DISTANCE_FACTOR = 0.5, 1
|
DISTANCE_FACTOR = 0.5, 1
|
||||||
EXTRA_AA_MIN_DISTANCE = 35000
|
EXTRA_AA_MIN_DISTANCE = 50000
|
||||||
EXTRA_AA_MAX_DISTANCE = 150000
|
EXTRA_AA_MAX_DISTANCE = 150000
|
||||||
EXTRA_AA_POSITION_FROM_CP = 550
|
EXTRA_AA_POSITION_FROM_CP = 550
|
||||||
|
|
||||||
@ -59,6 +59,9 @@ class ExtraAAConflictGenerator:
|
|||||||
if cp.position.distance_to_point(self.conflict.from_cp.position) < EXTRA_AA_MIN_DISTANCE:
|
if cp.position.distance_to_point(self.conflict.from_cp.position) < EXTRA_AA_MIN_DISTANCE:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
if cp.position.distance_to_point(self.conflict.to_cp.position) < EXTRA_AA_MIN_DISTANCE:
|
||||||
|
continue
|
||||||
|
|
||||||
if cp.position.distance_to_point(self.conflict.position) > EXTRA_AA_MAX_DISTANCE:
|
if cp.position.distance_to_point(self.conflict.position) > EXTRA_AA_MAX_DISTANCE:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
@ -10,16 +10,20 @@ from dcs.terrain.terrain import NoParkingSlotError
|
|||||||
|
|
||||||
TANKER_DISTANCE = 15000
|
TANKER_DISTANCE = 15000
|
||||||
TANKER_ALT = 10000
|
TANKER_ALT = 10000
|
||||||
|
TANKER_HEADING_OFFSET = 45
|
||||||
|
|
||||||
AWACS_DISTANCE = 150000
|
AWACS_DISTANCE = 150000
|
||||||
AWACS_ALT = 10000
|
AWACS_ALT = 10000
|
||||||
|
|
||||||
|
|
||||||
class AirSupportConflictGenerator:
|
class AirSupportConflictGenerator:
|
||||||
|
generated_tankers = None # type: typing.List[str]
|
||||||
|
|
||||||
def __init__(self, mission: Mission, conflict: Conflict, game):
|
def __init__(self, mission: Mission, conflict: Conflict, game):
|
||||||
self.mission = mission
|
self.mission = mission
|
||||||
self.conflict = conflict
|
self.conflict = conflict
|
||||||
self.game = game
|
self.game = game
|
||||||
|
self.generated_tankers = []
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def support_tasks(cls) -> typing.Collection[typing.Type[MainTask]]:
|
def support_tasks(cls) -> typing.Collection[typing.Type[MainTask]]:
|
||||||
@ -27,22 +31,24 @@ class AirSupportConflictGenerator:
|
|||||||
|
|
||||||
def generate(self, is_awacs_enabled):
|
def generate(self, is_awacs_enabled):
|
||||||
player_cp = self.conflict.from_cp if self.conflict.from_cp.captured else self.conflict.to_cp
|
player_cp = self.conflict.from_cp if self.conflict.from_cp.captured else self.conflict.to_cp
|
||||||
tanker_unit = db.find_unittype(Refueling, self.conflict.attackers_side.name)[0]
|
|
||||||
tanker_heading = self.conflict.to_cp.position.heading_between_point(self.conflict.from_cp.position)
|
for i, tanker_unit_type in enumerate(db.find_unittype(Refueling, self.conflict.attackers_side.name)):
|
||||||
|
self.generated_tankers.append(db.unit_type_name(tanker_unit_type))
|
||||||
|
tanker_heading = self.conflict.to_cp.position.heading_between_point(self.conflict.from_cp.position) + TANKER_HEADING_OFFSET * i
|
||||||
tanker_position = player_cp.position.point_from_heading(tanker_heading, TANKER_DISTANCE)
|
tanker_position = player_cp.position.point_from_heading(tanker_heading, TANKER_DISTANCE)
|
||||||
tanker_group = self.mission.refuel_flight(
|
tanker_group = self.mission.refuel_flight(
|
||||||
country=self.mission.country(self.game.player),
|
country=self.mission.country(self.game.player),
|
||||||
name=namegen.next_tanker_name(self.mission.country(self.game.player)),
|
name=namegen.next_tanker_name(self.mission.country(self.game.player)),
|
||||||
airport=None,
|
airport=None,
|
||||||
plane_type=tanker_unit,
|
plane_type=tanker_unit_type,
|
||||||
position=tanker_position,
|
position=tanker_position,
|
||||||
altitude=TANKER_ALT,
|
altitude=TANKER_ALT,
|
||||||
frequency=131,
|
frequency=130 + i,
|
||||||
start_type=StartType.Warm,
|
start_type=StartType.Warm,
|
||||||
tacanchannel="99X",
|
tacanchannel="{}X".format(97 + i),
|
||||||
)
|
)
|
||||||
|
|
||||||
tanker_group.points[0].tasks.append(ActivateBeaconCommand(channel=10, unit_id=tanker_group.id, aa=False))
|
tanker_group.points[0].tasks.append(ActivateBeaconCommand(channel=97 + i, unit_id=tanker_group.id, aa=False))
|
||||||
|
|
||||||
if is_awacs_enabled:
|
if is_awacs_enabled:
|
||||||
awacs_unit = db.find_unittype(AWACS, self.conflict.attackers_side.name)[0]
|
awacs_unit = db.find_unittype(AWACS, self.conflict.attackers_side.name)[0]
|
||||||
|
|||||||
@ -154,32 +154,6 @@ class Conflict:
|
|||||||
def has_frontline_between(cls, from_cp: ControlPoint, to_cp: ControlPoint) -> bool:
|
def has_frontline_between(cls, from_cp: ControlPoint, to_cp: ControlPoint) -> bool:
|
||||||
return from_cp.has_frontline and to_cp.has_frontline
|
return from_cp.has_frontline and to_cp.has_frontline
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def frontline_position0(cls, from_cp: ControlPoint, to_cp: ControlPoint) -> typing.Tuple[Point, int]:
|
|
||||||
cp_distance = from_cp.position.distance_to_point(to_cp.position)
|
|
||||||
cp_distance -= cp_distance * to_cp.frontline_offset + cp_distance * from_cp.frontline_offset
|
|
||||||
|
|
||||||
distance = max(cp_distance * FRONTLINE_DISTANCE_STRENGTH_FACTOR * to_cp.base.strength, FRONTLINE_MIN_CP_DISTANCE)
|
|
||||||
heading = to_cp.position.heading_between_point(from_cp.position)
|
|
||||||
return to_cp.position.point_from_heading(heading, distance), heading
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def frontline_position2(cls, theater: ConflictTheater, from_cp: ControlPoint, to_cp: ControlPoint) -> typing.Optional[typing.Tuple[Point, int]]:
|
|
||||||
attack_heading = from_cp.position.heading_between_point(to_cp.position)
|
|
||||||
attack_starting_position = cls._find_ground_position(from_cp.position, 200000, attack_heading, theater)
|
|
||||||
if not attack_starting_position:
|
|
||||||
return None
|
|
||||||
|
|
||||||
attack_ending_position = cls._find_ground_position(to_cp.position, 200000, _opposite_heading(attack_heading), theater)
|
|
||||||
if not attack_ending_position:
|
|
||||||
return None
|
|
||||||
|
|
||||||
attack_distance = attack_ending_position.distance_to_point(attack_starting_position)
|
|
||||||
strength_delta = (from_cp.base.strength - to_cp.base.strength) / 1.0
|
|
||||||
middle_position = attack_starting_position.point_from_heading(attack_heading, attack_distance / 2)
|
|
||||||
|
|
||||||
return middle_position.point_from_heading(attack_heading, strength_delta * attack_distance), _opposite_heading(attack_heading)
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def frontline_position(cls, theater: ConflictTheater, from_cp: ControlPoint, to_cp: ControlPoint) -> typing.Optional[typing.Tuple[Point, int]]:
|
def frontline_position(cls, theater: ConflictTheater, from_cp: ControlPoint, to_cp: ControlPoint) -> typing.Optional[typing.Tuple[Point, int]]:
|
||||||
attack_heading = from_cp.position.heading_between_point(to_cp.position)
|
attack_heading = from_cp.position.heading_between_point(to_cp.position)
|
||||||
@ -190,10 +164,10 @@ class Conflict:
|
|||||||
position = middle_point.point_from_heading(attack_heading, strength_delta * attack_distance / 2 - FRONTLINE_MIN_CP_DISTANCE)
|
position = middle_point.point_from_heading(attack_heading, strength_delta * attack_distance / 2 - FRONTLINE_MIN_CP_DISTANCE)
|
||||||
ground_position = cls._find_ground_position(position, attack_distance / 2 - FRONTLINE_MIN_CP_DISTANCE, attack_heading, theater)
|
ground_position = cls._find_ground_position(position, attack_distance / 2 - FRONTLINE_MIN_CP_DISTANCE, attack_heading, theater)
|
||||||
if ground_position:
|
if ground_position:
|
||||||
return ground_position, attack_heading
|
return ground_position, _opposite_heading(attack_heading)
|
||||||
else:
|
else:
|
||||||
print(from_cp, to_cp)
|
print("Coudn't find frontline position between {} and {}!".format(from_cp, to_cp))
|
||||||
return None
|
return position, _opposite_heading(attack_heading)
|
||||||
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|||||||
@ -8,6 +8,7 @@ from dcs.mission import *
|
|||||||
from dcs.statics import *
|
from dcs.statics import *
|
||||||
|
|
||||||
FARP_FRONTLINE_DISTANCE = 10000
|
FARP_FRONTLINE_DISTANCE = 10000
|
||||||
|
AA_CP_MIN_DISTANCE = 40000
|
||||||
|
|
||||||
|
|
||||||
class GroundObjectsGenerator:
|
class GroundObjectsGenerator:
|
||||||
@ -47,6 +48,9 @@ class GroundObjectsGenerator:
|
|||||||
|
|
||||||
for ground_object in cp.ground_objects:
|
for ground_object in cp.ground_objects:
|
||||||
if ground_object.dcs_identifier == "AA":
|
if ground_object.dcs_identifier == "AA":
|
||||||
|
if ground_object.position.distance_to_point(self.conflict.from_cp.position) < AA_CP_MIN_DISTANCE:
|
||||||
|
continue
|
||||||
|
|
||||||
if ground_object.is_dead:
|
if ground_object.is_dead:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
@ -130,9 +130,9 @@ class TriggersGenerator:
|
|||||||
def _set_skill(self, player_coalition: str, enemy_coalition: str):
|
def _set_skill(self, player_coalition: str, enemy_coalition: str):
|
||||||
for coalition_name, coalition in self.mission.coalition.items():
|
for coalition_name, coalition in self.mission.coalition.items():
|
||||||
if coalition_name == player_coalition:
|
if coalition_name == player_coalition:
|
||||||
skill_level = self.game.settings.player_skill
|
skill_level = self.game.settings.player_skill, self.game.settings.player_skill
|
||||||
elif coalition_name == enemy_coalition:
|
elif coalition_name == enemy_coalition:
|
||||||
skill_level = self.game.settings.enemy_skill
|
skill_level = self.game.settings.enemy_skill, self.game.settings.enemy_vehicle_skill
|
||||||
else:
|
else:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@ -140,10 +140,10 @@ class TriggersGenerator:
|
|||||||
for plane_group in country.plane_group:
|
for plane_group in country.plane_group:
|
||||||
for plane_unit in plane_group.units:
|
for plane_unit in plane_group.units:
|
||||||
if plane_unit.skill != Skill.Client and plane_unit.skill != Skill.Player:
|
if plane_unit.skill != Skill.Client and plane_unit.skill != Skill.Player:
|
||||||
plane_unit.skill = Skill(skill_level)
|
plane_unit.skill = Skill(skill_level[0])
|
||||||
|
|
||||||
for vehicle_group in country.vehicle_group:
|
for vehicle_group in country.vehicle_group:
|
||||||
vehicle_group.set_skill(Skill(skill_level))
|
vehicle_group.set_skill(Skill(skill_level[1]))
|
||||||
|
|
||||||
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 == "USA" and "blue" or "red"
|
player_coalition = self.game.player == "USA" and "blue" or "red"
|
||||||
|
|||||||
@ -98,6 +98,9 @@ class VisualGenerator:
|
|||||||
|
|
||||||
def _generate_frontline_smokes(self):
|
def _generate_frontline_smokes(self):
|
||||||
for from_cp, to_cp in self.game.theater.conflicts():
|
for from_cp, to_cp in self.game.theater.conflicts():
|
||||||
|
if from_cp.is_global or to_cp.is_global:
|
||||||
|
continue
|
||||||
|
|
||||||
frontline = Conflict.frontline_position(self.game.theater, from_cp, to_cp)
|
frontline = Conflict.frontline_position(self.game.theater, from_cp, to_cp)
|
||||||
if not frontline:
|
if not frontline:
|
||||||
continue
|
continue
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
BIN
resources/nevlandmap.p
Normal file
BIN
resources/nevlandmap.p
Normal file
Binary file not shown.
Binary file not shown.
@ -3,7 +3,7 @@ import pickle
|
|||||||
from dcs.mission import Mission
|
from dcs.mission import Mission
|
||||||
from dcs.planes import A_10C
|
from dcs.planes import A_10C
|
||||||
|
|
||||||
for terrain in ["cau", "gulf"]:
|
for terrain in ["cau", "gulf", "nev"]:
|
||||||
m = Mission()
|
m = Mission()
|
||||||
m.load_file("./{}_terrain.miz".format(terrain))
|
m.load_file("./{}_terrain.miz".format(terrain))
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@ -25,12 +25,12 @@ class CaucasusTheater(ConflictTheater):
|
|||||||
kutaisi = ControlPoint.from_airport(caucasus.Kutaisi, LAND, SIZE_SMALL, IMPORTANCE_LOW)
|
kutaisi = ControlPoint.from_airport(caucasus.Kutaisi, LAND, SIZE_SMALL, IMPORTANCE_LOW)
|
||||||
senaki = ControlPoint.from_airport(caucasus.Senaki_Kolkhi, LAND, SIZE_REGULAR, IMPORTANCE_LOW)
|
senaki = ControlPoint.from_airport(caucasus.Senaki_Kolkhi, LAND, SIZE_REGULAR, IMPORTANCE_LOW)
|
||||||
kobuleti = ControlPoint.from_airport(caucasus.Kobuleti, COAST_A_E, SIZE_SMALL, 1.1)
|
kobuleti = ControlPoint.from_airport(caucasus.Kobuleti, COAST_A_E, SIZE_SMALL, 1.1)
|
||||||
batumi = ControlPoint.from_airport(caucasus.Batumi, COAST_DL_E, SIZE_SMALL, 1.3, has_frontline=False)
|
batumi = ControlPoint.from_airport(caucasus.Batumi, COAST_DL_E, SIZE_SMALL, 1.3)
|
||||||
sukhumi = ControlPoint.from_airport(caucasus.Sukhumi_Babushara, COAST_DR_E, SIZE_REGULAR, 1.2)
|
sukhumi = ControlPoint.from_airport(caucasus.Sukhumi_Babushara, COAST_DR_E, SIZE_REGULAR, 1.2)
|
||||||
gudauta = ControlPoint.from_airport(caucasus.Gudauta, COAST_DR_E, SIZE_REGULAR, 1.2, has_frontline=False)
|
gudauta = ControlPoint.from_airport(caucasus.Gudauta, COAST_DR_E, SIZE_REGULAR, 1.2)
|
||||||
sochi = ControlPoint.from_airport(caucasus.Sochi_Adler, COAST_DR_E, SIZE_BIG, IMPORTANCE_HIGH, has_frontline=False)
|
sochi = ControlPoint.from_airport(caucasus.Sochi_Adler, COAST_DR_E, SIZE_BIG, IMPORTANCE_HIGH)
|
||||||
|
|
||||||
gelendzhik = ControlPoint.from_airport(caucasus.Gelendzhik, COAST_DR_E, SIZE_BIG, 1.1, has_frontline=False)
|
gelendzhik = ControlPoint.from_airport(caucasus.Gelendzhik, COAST_DR_E, SIZE_BIG, 1.1)
|
||||||
maykop = ControlPoint.from_airport(caucasus.Maykop_Khanskaya, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
|
maykop = ControlPoint.from_airport(caucasus.Maykop_Khanskaya, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
|
||||||
krasnodar = ControlPoint.from_airport(caucasus.Krasnodar_Center, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
|
krasnodar = ControlPoint.from_airport(caucasus.Krasnodar_Center, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
|
||||||
novorossiysk = ControlPoint.from_airport(caucasus.Novorossiysk, COAST_DR_E, SIZE_BIG, 1.2)
|
novorossiysk = ControlPoint.from_airport(caucasus.Novorossiysk, COAST_DR_E, SIZE_BIG, 1.2)
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
from dcs.terrain import nevada
|
from dcs.terrain import nevada
|
||||||
from dcs import mapping
|
from dcs import mapping
|
||||||
|
|
||||||
|
from .landmap import *
|
||||||
from .conflicttheater import *
|
from .conflicttheater import *
|
||||||
from .base import *
|
from .base import *
|
||||||
|
|
||||||
@ -10,6 +11,7 @@ class NevadaTheater(ConflictTheater):
|
|||||||
overview_image = "nevada.gif"
|
overview_image = "nevada.gif"
|
||||||
reference_points = {(nevada.Mina_Airport_3Q0.position.x, nevada.Mina_Airport_3Q0.position.y): (45, -360),
|
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), }
|
(nevada.Laughlin_Airport.position.x, nevada.Laughlin_Airport.position.y): (440, 80), }
|
||||||
|
landmap = load_landmap("resources\\nev_landmap.p")
|
||||||
daytime_map = {
|
daytime_map = {
|
||||||
"dawn": (4, 6),
|
"dawn": (4, 6),
|
||||||
"day": (6, 17),
|
"day": (6, 17),
|
||||||
@ -32,7 +34,7 @@ class NevadaTheater(ConflictTheater):
|
|||||||
jean = ControlPoint.from_airport(nevada.Jean_Airport, LAND, SIZE_REGULAR, 1.2)
|
jean = ControlPoint.from_airport(nevada.Jean_Airport, LAND, SIZE_REGULAR, 1.2)
|
||||||
laughlin = ControlPoint.from_airport(nevada.Laughlin_Airport, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
|
laughlin = ControlPoint.from_airport(nevada.Laughlin_Airport, LAND, SIZE_LARGE, IMPORTANCE_HIGH)
|
||||||
|
|
||||||
def __init__(self, load_ground_objects=True):
|
def __init__(self):
|
||||||
super(NevadaTheater, self).__init__()
|
super(NevadaTheater, self).__init__()
|
||||||
|
|
||||||
self.add_controlpoint(self.mina, connected_to=[self.tonopah])
|
self.add_controlpoint(self.mina, connected_to=[self.tonopah])
|
||||||
|
|||||||
@ -47,12 +47,26 @@ def generate_groundobjects(theater: ConflictTheater):
|
|||||||
tpls = pickle.load(f)
|
tpls = pickle.load(f)
|
||||||
|
|
||||||
def find_location(on_ground, near, theater, min, max) -> typing.Optional[Point]:
|
def find_location(on_ground, near, theater, min, max) -> typing.Optional[Point]:
|
||||||
for _ in range(500):
|
point = None
|
||||||
|
for _ in range(1000):
|
||||||
p = near.random_point_within(max, min)
|
p = near.random_point_within(max, min)
|
||||||
if on_ground and theater.is_on_land(p):
|
if on_ground and theater.is_on_land(p):
|
||||||
return p
|
point = p
|
||||||
elif not on_ground and theater.is_in_sea(p):
|
elif not on_ground and theater.is_in_sea(p):
|
||||||
return p
|
point = p
|
||||||
|
|
||||||
|
if point:
|
||||||
|
for angle in range(0, 360, 45):
|
||||||
|
p = point.point_from_heading(angle, 1000)
|
||||||
|
if on_ground and not theater.is_on_land(p):
|
||||||
|
point = None
|
||||||
|
break
|
||||||
|
elif not on_ground and not theater.is_in_sea(p):
|
||||||
|
point = None
|
||||||
|
break
|
||||||
|
|
||||||
|
if point:
|
||||||
|
return point
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|||||||
@ -18,54 +18,62 @@ class BaseMenu(Menu):
|
|||||||
|
|
||||||
def display(self):
|
def display(self):
|
||||||
self.window.clear_right_pane()
|
self.window.clear_right_pane()
|
||||||
row = 0
|
|
||||||
|
|
||||||
def purchase_row(unit_type, unit_price):
|
|
||||||
nonlocal row
|
|
||||||
|
|
||||||
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, sticky=W)
|
|
||||||
|
|
||||||
label = Label(self.frame, text="({})".format(existing_units), **STYLES["widget"])
|
|
||||||
label.grid(column=1, row=row)
|
|
||||||
self.bought_amount_labels[unit_type] = label
|
|
||||||
|
|
||||||
Label(self.frame, text="{}m".format(unit_price), **STYLES["widget"]).grid(column=2, row=row, sticky=E)
|
|
||||||
Button(self.frame, text="+", command=self.buy(unit_type), **STYLES["btn-primary"]).grid(column=3, row=row, padx=(10,0))
|
|
||||||
Button(self.frame, text="-", command=self.sell(unit_type), **STYLES["btn-warning"]).grid(column=4, row=row, padx=(10,5))
|
|
||||||
row += 1
|
|
||||||
|
|
||||||
units = {
|
units = {
|
||||||
PinpointStrike: db.find_unittype(PinpointStrike, self.game.player),
|
|
||||||
Embarking: db.find_unittype(Embarking, self.game.player),
|
|
||||||
CAS: db.find_unittype(CAS, self.game.player),
|
|
||||||
CAP: db.find_unittype(CAP, self.game.player),
|
CAP: db.find_unittype(CAP, self.game.player),
|
||||||
|
Embarking: db.find_unittype(Embarking, self.game.player),
|
||||||
AirDefence: db.find_unittype(AirDefence, self.game.player),
|
AirDefence: db.find_unittype(AirDefence, self.game.player),
|
||||||
|
CAS: db.find_unittype(CAS, self.game.player),
|
||||||
|
PinpointStrike: db.find_unittype(PinpointStrike, self.game.player),
|
||||||
}
|
}
|
||||||
|
|
||||||
# Header
|
# Header
|
||||||
head = Frame(self.frame, **STYLES["header"])
|
head = Frame(self.frame, **STYLES["header"])
|
||||||
head.grid(row=row, column=0, columnspan=5, sticky=NSEW, pady=5)
|
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)
|
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)
|
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)
|
Label(head, text=units_title, **STYLES["strong-grey"]).grid(row=0, column=1, sticky=NE+S)
|
||||||
row += 1
|
|
||||||
|
|
||||||
self.budget_label = Label(self.frame, text="Budget: {}m".format(self.game.budget), **STYLES["widget"])
|
self.budget_label = Label(self.frame, text="Budget: {}m".format(self.game.budget), **STYLES["widget"])
|
||||||
self.budget_label.grid(row=row, sticky=W)
|
self.budget_label.grid(row=1, sticky=W)
|
||||||
Button(self.frame, text="Back", command=self.dismiss, **STYLES["btn-primary"]).grid(column=4, row=row, padx=(0,15), pady=(0,5))
|
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
|
row += 1
|
||||||
|
|
||||||
for task_type, units in units.items():
|
for task_type in tasks_column:
|
||||||
Label(self.frame, text="{}".format(db.task_name(task_type)), **STYLES["strong"]).grid(row=row, columnspan=5, sticky=NSEW); row += 1
|
Label(self.frame, text="{}".format(db.task_name(task_type)), **STYLES["strong"]).grid(row=row, column=column, columnspan=5, sticky=NSEW)
|
||||||
|
row += 1
|
||||||
|
|
||||||
units = list(set(units))
|
units_column = list(set(units[task_type]))
|
||||||
units.sort(key=lambda x: db.PRICES[x])
|
units_column.sort(key=lambda x: db.PRICES[x])
|
||||||
for unit_type in units:
|
for unit_type in units_column:
|
||||||
purchase_row(unit_type, db.PRICES[unit_type])
|
purchase_row(unit_type, db.PRICES[unit_type])
|
||||||
|
|
||||||
|
column += 5
|
||||||
|
|
||||||
def dismiss(self):
|
def dismiss(self):
|
||||||
if sum([x for x in self.event.units.values()]) == 0:
|
if sum([x for x in self.event.units.values()]) == 0:
|
||||||
self.game.units_delivery_remove(self.event)
|
self.game.units_delivery_remove(self.event)
|
||||||
|
|||||||
@ -18,6 +18,9 @@ class ConfigurationMenu(Menu):
|
|||||||
self.enemy_skill_var = StringVar()
|
self.enemy_skill_var = StringVar()
|
||||||
self.enemy_skill_var.set(self.game.settings.enemy_skill)
|
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.takeoff_var = BooleanVar()
|
self.takeoff_var = BooleanVar()
|
||||||
self.takeoff_var.set(self.game.settings.only_player_takeoff)
|
self.takeoff_var.set(self.game.settings.only_player_takeoff)
|
||||||
|
|
||||||
@ -30,6 +33,7 @@ class ConfigurationMenu(Menu):
|
|||||||
def dismiss(self):
|
def dismiss(self):
|
||||||
self.game.settings.player_skill = self.player_skill_var.get()
|
self.game.settings.player_skill = self.player_skill_var.get()
|
||||||
self.game.settings.enemy_skill = self.enemy_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.only_player_takeoff = self.takeoff_var.get()
|
self.game.settings.only_player_takeoff = self.takeoff_var.get()
|
||||||
self.game.settings.night_disabled = self.night_var.get()
|
self.game.settings.night_disabled = self.night_var.get()
|
||||||
self.game.settings.cold_start = self.cold_start_var.get()
|
self.game.settings.cold_start = self.cold_start_var.get()
|
||||||
@ -49,6 +53,7 @@ class ConfigurationMenu(Menu):
|
|||||||
|
|
||||||
Label(body, text="Player coalition skill", **STYLES["widget"]).grid(row=0, column=0, sticky=W)
|
Label(body, text="Player coalition skill", **STYLES["widget"]).grid(row=0, column=0, sticky=W)
|
||||||
Label(body, text="Enemy coalition skill", **STYLES["widget"]).grid(row=1, column=0, sticky=W)
|
Label(body, text="Enemy coalition skill", **STYLES["widget"]).grid(row=1, column=0, sticky=W)
|
||||||
|
Label(body, text="Enemy AA and vehicle skill", **STYLES["widget"]).grid(row=2, column=0, sticky=W)
|
||||||
|
|
||||||
p_skill = OptionMenu(body, self.player_skill_var, "Average", "Good", "High", "Excellent")
|
p_skill = OptionMenu(body, self.player_skill_var, "Average", "Good", "High", "Excellent")
|
||||||
p_skill.grid(row=0, column=1, sticky=E, pady=5)
|
p_skill.grid(row=0, column=1, sticky=E, pady=5)
|
||||||
@ -58,26 +63,30 @@ class ConfigurationMenu(Menu):
|
|||||||
e_skill.grid(row=1, column=1, sticky=E)
|
e_skill.grid(row=1, column=1, sticky=E)
|
||||||
e_skill.configure(**STYLES["btn-primary"])
|
e_skill.configure(**STYLES["btn-primary"])
|
||||||
|
|
||||||
Label(body, text="Aircraft cold start", **STYLES["widget"]).grid(row=2, column=0, sticky=W)
|
e_skill = OptionMenu(body, self.enemy_vehicle_var, "Average", "Good", "High", "Excellent")
|
||||||
Label(body, text="Takeoff only for player group", **STYLES["widget"]).grid(row=3, column=0, sticky=W)
|
e_skill.grid(row=2, column=1, sticky=E)
|
||||||
Label(body, text="Disable night missions", **STYLES["widget"]).grid(row=4, column=0, sticky=W)
|
e_skill.configure(**STYLES["btn-primary"])
|
||||||
|
|
||||||
Checkbutton(body, variable=self.cold_start_var, **STYLES["radiobutton"]).grid(row=2, column=1, sticky=E)
|
Label(body, text="Aircraft cold start", **STYLES["widget"]).grid(row=3, column=0, sticky=W)
|
||||||
Checkbutton(body, variable=self.takeoff_var, **STYLES["radiobutton"]).grid(row=3, column=1, sticky=E)
|
Label(body, text="Takeoff only for player group", **STYLES["widget"]).grid(row=4, column=0, sticky=W)
|
||||||
Checkbutton(body, variable=self.night_var, **STYLES["radiobutton"]).grid(row=4, column=1, sticky=E)
|
Label(body, text="Disable night missions", **STYLES["widget"]).grid(row=5, column=0, sticky=W)
|
||||||
|
|
||||||
Button(body, text="Display logs", command=self.display_logs, **STYLES["btn-primary"]).grid(row=5, column=0, sticky=E, pady=30)
|
Checkbutton(body, variable=self.cold_start_var, **STYLES["radiobutton"]).grid(row=3, column=1, sticky=E)
|
||||||
Button(body, text="Back", command=self.dismiss, **STYLES["btn-primary"]).grid(row=5, column=1, sticky=E, pady=30)
|
Checkbutton(body, variable=self.takeoff_var, **STYLES["radiobutton"]).grid(row=5, column=1, sticky=E)
|
||||||
|
Checkbutton(body, variable=self.night_var, **STYLES["radiobutton"]).grid(row=5, column=1, sticky=E)
|
||||||
|
|
||||||
Label(body, text="Contributors: ", **STYLES["widget"]).grid(row=6, column=0, sticky=W)
|
Button(body, text="Display logs", command=self.display_logs, **STYLES["btn-primary"]).grid(row=6, column=0, sticky=E, pady=30)
|
||||||
|
Button(body, text="Back", command=self.dismiss, **STYLES["btn-primary"]).grid(row=6, column=1, sticky=E, pady=30)
|
||||||
|
|
||||||
Label(body, text="shdwp - author, maintainer", **STYLES["widget"]).grid(row=7, column=0, sticky=W)
|
Label(body, text="Contributors: ", **STYLES["widget"]).grid(row=7, column=0, sticky=W)
|
||||||
Button(body, text="[github]", command=lambda: webbrowser.open_new_tab("http://github.com/shdwp"), **STYLES["widget"]).grid(row=7, column=1, sticky=E)
|
|
||||||
|
|
||||||
Label(body, text="Khopa - contributions", **STYLES["widget"]).grid(row=8, column=0, sticky=W)
|
Label(body, text="shdwp - author, maintainer", **STYLES["widget"]).grid(row=8, column=0, sticky=W)
|
||||||
Button(body, text="[github]", command=lambda: webbrowser.open_new_tab("http://github.com/Khopa"), **STYLES["widget"]).grid(row=8, column=1, sticky=E)
|
Button(body, text="[github]", command=lambda: webbrowser.open_new_tab("http://github.com/shdwp"), **STYLES["widget"]).grid(row=9, column=1, sticky=E)
|
||||||
|
|
||||||
Button(body, text="Cheat +200m", command=self.cheat_money, **STYLES["btn-danger"]).grid(row=10, column=1, pady=30)
|
Label(body, text="Khopa - contributions", **STYLES["widget"]).grid(row=9, column=0, sticky=W)
|
||||||
|
Button(body, text="[github]", command=lambda: webbrowser.open_new_tab("http://github.com/Khopa"), **STYLES["widget"]).grid(row=9, column=1, sticky=E)
|
||||||
|
|
||||||
|
Button(body, text="Cheat +200m", command=self.cheat_money, **STYLES["btn-danger"]).grid(row=11, column=1, pady=30)
|
||||||
|
|
||||||
def display_logs(self):
|
def display_logs(self):
|
||||||
raise ShowLogsException()
|
raise ShowLogsException()
|
||||||
|
|||||||
@ -28,17 +28,21 @@ class MainMenu(Menu):
|
|||||||
|
|
||||||
self.window.clear_right_pane()
|
self.window.clear_right_pane()
|
||||||
self.upd.update()
|
self.upd.update()
|
||||||
row = 0
|
|
||||||
|
|
||||||
# Header :
|
# Header :
|
||||||
header = Frame(self.frame, **STYLES["header"])
|
header = Frame(self.frame, **STYLES["header"])
|
||||||
Button(header, text="Configuration", command=self.configuration_menu, **STYLES["btn-primary"]).grid(column=0, row=0, sticky=NE)
|
Button(header, text="Configuration", command=self.configuration_menu, **STYLES["btn-primary"]).grid(column=0, row=0, sticky=NW)
|
||||||
Label(header, text="Budget: {}m (+{}m)".format(self.game.budget, self.game.budget_reward_amount), **STYLES["strong"]).grid(column=1, row=0, sticky=NSEW, padx=50)
|
Label(header, text="Budget: {}m (+{}m)".format(self.game.budget, self.game.budget_reward_amount), **STYLES["strong"]).grid(column=1, row=0, sticky=NSEW, padx=50)
|
||||||
Button(header, text="Pass turn", command=self.pass_turn, **STYLES["btn-primary"]).grid(column=2, row=0, sticky=NW)
|
Button(header, text="Pass turn", command=self.pass_turn, **STYLES["btn-primary"]).grid(column=2, row=0, sticky=NE)
|
||||||
header.grid(column=0, row=0, sticky=N+EW)
|
header.grid(column=0, columnspan=99, row=0, sticky=N+EW)
|
||||||
|
|
||||||
body = LabelFrame(self.frame, **STYLES["body"])
|
events = self.game.events
|
||||||
body.grid(column=0, row=1, sticky=NSEW)
|
events.sort(key=lambda x: x.to_cp.name)
|
||||||
|
events.sort(key=lambda x: x.from_cp.name)
|
||||||
|
events.sort(key=lambda x: x.informational and 2 or (self.game.is_player_attack(x) and 1 or 0))
|
||||||
|
|
||||||
|
column = 0
|
||||||
|
row = 0
|
||||||
|
|
||||||
def label(text):
|
def label(text):
|
||||||
nonlocal row, body
|
nonlocal row, body
|
||||||
@ -58,21 +62,30 @@ class MainMenu(Menu):
|
|||||||
Button(body, text=">", command=self.start_event(event), **STYLES["btn-primary"]).grid(column=1, row=row, sticky=E)
|
Button(body, text=">", command=self.start_event(event), **STYLES["btn-primary"]).grid(column=1, row=row, sticky=E)
|
||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
|
def departure_header(text):
|
||||||
|
nonlocal row, body
|
||||||
|
Label(body, text=text, **STYLES["strong"]).grid(column=0, columnspan=2, row=row, sticky=N+EW, pady=(0, 5)); row += 1
|
||||||
|
|
||||||
def destination_header(text, pady=0):
|
def destination_header(text, pady=0):
|
||||||
nonlocal row, body
|
nonlocal row, body
|
||||||
Label(body, text=text, **STYLES["strong"]).grid(column=0, columnspan=2, row=row, sticky=N+EW, pady=(pady,0)); row += 1
|
Label(body, text=text, **STYLES["substrong"]).grid(column=0, columnspan=2, row=row, sticky=N+EW, pady=(pady,0)); row += 1
|
||||||
|
|
||||||
events = self.game.events
|
|
||||||
events.sort(key=lambda x: x.to_cp.name)
|
|
||||||
events.sort(key=lambda x: x.from_cp.name)
|
|
||||||
events.sort(key=lambda x: x.informational and 2 or (self.game.is_player_attack(x) and 1 or 0))
|
|
||||||
|
|
||||||
destination = None
|
destination = None
|
||||||
|
departure = None
|
||||||
deliveries = False
|
deliveries = False
|
||||||
for event in events:
|
for event in events:
|
||||||
if not event.informational:
|
if not event.informational:
|
||||||
|
if event.from_cp.name != departure:
|
||||||
|
body = LabelFrame(self.frame, **STYLES["body"])
|
||||||
|
body.grid(column=column, row=1, sticky=NSEW)
|
||||||
|
row = 0
|
||||||
|
column += 1
|
||||||
|
|
||||||
|
departure = event.from_cp.name
|
||||||
|
departure_header(event.from_cp.name)
|
||||||
|
|
||||||
if self.game.is_player_attack(event):
|
if self.game.is_player_attack(event):
|
||||||
new_destination = "From {} to {}".format(event.from_cp.name, event.to_cp.name)
|
new_destination = "At {}".format(event.to_cp.name)
|
||||||
else:
|
else:
|
||||||
new_destination = "Enemy attack"
|
new_destination = "Enemy attack"
|
||||||
if destination != new_destination:
|
if destination != new_destination:
|
||||||
|
|||||||
@ -12,6 +12,7 @@ GREEN = "#699245"
|
|||||||
YELLOW = "#BF9A46"
|
YELLOW = "#BF9A46"
|
||||||
RED = "#D0232E"
|
RED = "#D0232E"
|
||||||
BG_TITLE_COLOR = "#2D3E50"
|
BG_TITLE_COLOR = "#2D3E50"
|
||||||
|
BG_SUBTITLE_COLOR = "#3E4F61"
|
||||||
|
|
||||||
# Fonts
|
# Fonts
|
||||||
FONT_FAMILY = "Trebuchet MS"
|
FONT_FAMILY = "Trebuchet MS"
|
||||||
@ -25,8 +26,9 @@ STYLES = {}
|
|||||||
STYLES["label-frame"] = {"font": BOLD_FONT, "bg": BG_COLOR, "fg": FG_COLOR}
|
STYLES["label-frame"] = {"font": BOLD_FONT, "bg": BG_COLOR, "fg": FG_COLOR}
|
||||||
STYLES["frame-wrapper"] = {"bg": BG_COLOR, "relief":"sunken"}
|
STYLES["frame-wrapper"] = {"bg": BG_COLOR, "relief":"sunken"}
|
||||||
|
|
||||||
STYLES["body"] = {"bg": BG_COLOR, "padx": 25, "pady": 35}
|
STYLES["body"] = {"bg": BG_COLOR, "padx": 10, "pady": 10}
|
||||||
STYLES["strong"] = {"font": BOLD_FONT, "bg": BG_TITLE_COLOR, "fg": FG_COLOR}
|
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["strong-grey"] = {"font": BOLD_FONT, "bg": BG_TITLE_COLOR, "fg": FG_COLOR_LIGHT}
|
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["mission-preview"] = {"font": BOLD_FONT, "bg": YELLOW, "fg": FG_COLOR}
|
||||||
@ -39,6 +41,7 @@ STYLES["title"] = {"bg": BG_TITLE_COLOR, "fg": FG_COLOR, "padx": PADDING_X, "pad
|
|||||||
STYLES["title-green"] = {"bg": GREEN, "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["title-red"] = {"bg": RED, "fg": FG_COLOR, "padx": PADDING_X, "pady": PADDING_Y, "font": TITLE_FONT}
|
||||||
STYLES["header"] = {"bg": BG_TITLE_COLOR}
|
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"] = {"bg": GREEN, "fg": FG_COLOR, "padx": PADDING_X, "pady": 2, "font": DEFAULT_FONT}
|
||||||
STYLES["btn-danger"] = {"bg": RED, "fg": FG_COLOR, "padx": PADDING_X, "pady": 2, "font": DEFAULT_FONT}
|
STYLES["btn-danger"] = {"bg": RED, "fg": FG_COLOR, "padx": PADDING_X, "pady": 2, "font": DEFAULT_FONT}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user