mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
new options, landmaps, mission settings generation update & frontlike smokes generation
This commit is contained in:
parent
92e5514e8d
commit
e54e548bdd
@ -1,4 +1,7 @@
|
||||
#!/usr/bin/env python3
|
||||
import os
|
||||
import dcs
|
||||
|
||||
import theater.caucasus
|
||||
import theater.persiangulf
|
||||
import theater.nevada
|
||||
@ -11,6 +14,8 @@ from game.game import Game
|
||||
from theater import start_generator
|
||||
from userdata import persistency
|
||||
|
||||
dcs.planes.FlyingType.payload_dirs.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "resources\\payloads"))
|
||||
|
||||
|
||||
def proceed_to_main_menu(game: Game):
|
||||
m = ui.mainmenu.MainMenu(w, None, game)
|
||||
@ -22,7 +27,7 @@ game = persistency.restore_game()
|
||||
if not game:
|
||||
new_game_menu = None # type: NewGameMenu
|
||||
|
||||
def start_new_game(player_name: str, enemy_name: str, terrain: str):
|
||||
def start_new_game(player_name: str, enemy_name: str, terrain: str, sams: bool):
|
||||
if terrain == "persiangulf":
|
||||
conflicttheater = theater.persiangulf.PersianGulfTheater()
|
||||
elif terrain == "nevada":
|
||||
@ -30,7 +35,7 @@ if not game:
|
||||
else:
|
||||
conflicttheater = theater.caucasus.CaucasusTheater()
|
||||
|
||||
start_generator.generate_initial(conflicttheater, enemy_name)
|
||||
start_generator.generate_initial(conflicttheater, enemy_name, sams)
|
||||
proceed_to_main_menu(Game(player_name=player_name,
|
||||
enemy_name=enemy_name,
|
||||
theater=conflicttheater))
|
||||
|
||||
18
game/db.py
18
game/db.py
@ -115,10 +115,17 @@ UNIT_BY_TASK = {
|
||||
CAP: [Armor.MBT_T_90, Armor.MBT_T_80U, Armor.MBT_T_55, Armor.MBT_M1A2_Abrams, Armor.MBT_M60A3_Patton, Armor.ATGM_M1134_Stryker, Armor.APC_BTR_80, ],
|
||||
AirDefence: [
|
||||
AirDefence.AAA_Vulcan_M163,
|
||||
AirDefence.AAA_Vulcan_M163,
|
||||
AirDefence.AAA_Vulcan_M163,
|
||||
AirDefence.SAM_Avenger_M1097,
|
||||
AirDefence.SAM_Avenger_M1097,
|
||||
AirDefence.SAM_Patriot_ICC,
|
||||
|
||||
AirDefence.AAA_ZU_23_on_Ural_375,
|
||||
AirDefence.AAA_ZU_23_on_Ural_375,
|
||||
AirDefence.AAA_ZU_23_on_Ural_375,
|
||||
AirDefence.AAA_ZU_23_on_Ural_375,
|
||||
AirDefence.SAM_SA_18_Igla_MANPADS,
|
||||
AirDefence.SAM_SA_18_Igla_MANPADS,
|
||||
AirDefence.SAM_SA_19_Tunguska_2S6,
|
||||
AirDefence.SAM_SA_8_Osa_9A33,
|
||||
@ -126,6 +133,14 @@ UNIT_BY_TASK = {
|
||||
Carriage: [CVN_74_John_C__Stennis, CV_1143_5_Admiral_Kuznetsov, ],
|
||||
}
|
||||
|
||||
SAM_BAN = [
|
||||
AirDefence.SAM_Avenger_M1097,
|
||||
AirDefence.SAM_Patriot_ICC,
|
||||
|
||||
AirDefence.SAM_SA_19_Tunguska_2S6,
|
||||
AirDefence.SAM_SA_8_Osa_9A33,
|
||||
]
|
||||
|
||||
UNIT_BY_COUNTRY = {
|
||||
"Russia": [
|
||||
C_101CC,
|
||||
@ -256,7 +271,7 @@ def _validate_db():
|
||||
# check unit by task uniquity
|
||||
total_set = set()
|
||||
for t, unit_collection in UNIT_BY_TASK.items():
|
||||
for unit_type in unit_collection:
|
||||
for unit_type in set(unit_collection):
|
||||
assert unit_type not in total_set, "{} is duplicate".format(unit_type)
|
||||
total_set.add(unit_type)
|
||||
|
||||
@ -272,4 +287,5 @@ def _validate_db():
|
||||
for unit_type in total_set:
|
||||
assert unit_type in PRICES, "{} not in prices".format(unit_type)
|
||||
|
||||
|
||||
_validate_db()
|
||||
@ -258,7 +258,7 @@ class CaptureEvent(Event):
|
||||
attack=armor,
|
||||
intercept=interceptors,
|
||||
defense=self.to_cp.base.armor,
|
||||
aa=self.to_cp.base.aa)
|
||||
aa=self.to_cp.base.assemble_aa())
|
||||
|
||||
self.operation = op
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ COMMISION_LIMITS_FACTORS = {
|
||||
CAP: 2,
|
||||
CAS: 1,
|
||||
FighterSweep: 3,
|
||||
AirDefence: 2,
|
||||
AirDefence: 1,
|
||||
}
|
||||
|
||||
COMMISION_AMOUNTS_SCALE = 2
|
||||
@ -39,6 +39,8 @@ class Game:
|
||||
budget = PLAYER_BUDGET_INITIAL
|
||||
events = None # type: typing.List[Event]
|
||||
pending_transfers = None # type: typing.Dict[]
|
||||
player_skill = "Good"
|
||||
enemy_skill = "Average"
|
||||
|
||||
def __init__(self, player_name: str, enemy_name: str, theater: ConflictTheater):
|
||||
self.events = []
|
||||
|
||||
@ -7,8 +7,9 @@ from gen.aircraft import *
|
||||
from gen.aaa import *
|
||||
from gen.shipgen import *
|
||||
from gen.conflictgen import *
|
||||
from gen.envsettingsgen import *
|
||||
from gen.settingsgen import *
|
||||
from gen.awacsgen import *
|
||||
from gen.visualgen import *
|
||||
|
||||
|
||||
class Operation:
|
||||
@ -21,8 +22,9 @@ class Operation:
|
||||
aagen = None # type: AAConflictGenerator
|
||||
extra_aagen = None # type: ExtraAAConflictGenerator
|
||||
shipgen = None # type: ShipGenerator
|
||||
envgen = None # type: EnvironmentSettingsGenerator
|
||||
envgen = None # type: SettingsGenerator
|
||||
awacsgen = None # type: AWACSConflictGenerator
|
||||
visualgen = None # type: VisualGenerator
|
||||
|
||||
is_awacs_enabled = False
|
||||
|
||||
@ -52,7 +54,8 @@ class Operation:
|
||||
self.aagen = AAConflictGenerator(mission, conflict)
|
||||
self.shipgen = ShipGenerator(mission, conflict)
|
||||
self.awacsgen = AWACSConflictGenerator(mission, conflict, self.game)
|
||||
self.envgen = EnvironmentSettingsGenerator(mission, conflict, self.game)
|
||||
self.envgen = SettingsGenerator(mission, conflict, self.game)
|
||||
self.visualgen = VisualGenerator(mission, conflict, self.game)
|
||||
|
||||
player_name = self.from_cp.captured and self.attacker_name or self.defender_name
|
||||
enemy_name = self.from_cp.captured and self.defender_name or self.attacker_name
|
||||
@ -70,6 +73,8 @@ class Operation:
|
||||
self.defenders_starting_position = self.to_cp.at
|
||||
|
||||
def generate(self):
|
||||
self.visualgen.generate()
|
||||
|
||||
if self.is_awacs_enabled:
|
||||
self.awacsgen.generate()
|
||||
|
||||
@ -117,6 +122,11 @@ class CaptureOperation(Operation):
|
||||
|
||||
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
|
||||
super(CaptureOperation, self).prepare(terrain, is_quick)
|
||||
|
||||
self.defenders_starting_position = None
|
||||
if self.game.player == self.defender_name:
|
||||
self.attackers_starting_position = None
|
||||
|
||||
self.initialize(mission=self.mission,
|
||||
conflict=self.to_cp.conflict_attack(self.from_cp,
|
||||
self.mission.country(self.attacker_name),
|
||||
@ -131,6 +141,7 @@ class CaptureOperation(Operation):
|
||||
self.airgen.generate_cas(self.cas, clients=self.attacker_clients, at=self.attackers_starting_position)
|
||||
self.airgen.generate_cas_escort(self.escort, clients=self.attacker_clients, at=self.attackers_starting_position)
|
||||
|
||||
self.visualgen.generate_target_smokes(self.to_cp)
|
||||
super(CaptureOperation, self).generate()
|
||||
|
||||
|
||||
@ -152,6 +163,8 @@ class InterceptOperation(Operation):
|
||||
|
||||
def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool):
|
||||
super(InterceptOperation, self).prepare(terrain, is_quick)
|
||||
self.defenders_starting_position = None
|
||||
|
||||
conflict = Conflict.intercept_conflict(
|
||||
attacker=self.mission.country(self.attacker_name),
|
||||
defender=self.mission.country(self.defender_name),
|
||||
|
||||
@ -1,13 +1,14 @@
|
||||
import typing
|
||||
import random
|
||||
from datetime import datetime, timedelta
|
||||
from datetime import datetime, timedelta, time
|
||||
|
||||
from dcs.mission import Mission
|
||||
from dcs.triggers import *
|
||||
from dcs.condition import *
|
||||
from dcs.action import *
|
||||
from dcs.task import *
|
||||
from dcs.unit import Skill
|
||||
|
||||
from game import db
|
||||
from theater.weatherforecast import WeatherForecast
|
||||
from theater.conflicttheater import Conflict
|
||||
|
||||
@ -23,35 +24,27 @@ RANDOM_TIME = {
|
||||
|
||||
RANDOM_WEATHER = {
|
||||
0: 5, # thunderstorm
|
||||
1: 20, # heavy rain
|
||||
2: 30, # rain
|
||||
1: 10, # heavy rain
|
||||
2: 20, # rain
|
||||
3: 100, # random dynamic
|
||||
}
|
||||
|
||||
|
||||
class EnvironmentSettingsGenerator:
|
||||
class SettingsGenerator:
|
||||
def __init__(self, mission: Mission, conflict: Conflict, game):
|
||||
self.mission = mission
|
||||
self.conflict = conflict
|
||||
self.game = game
|
||||
|
||||
def _gen_random_time(self):
|
||||
start_time = datetime.today()
|
||||
daytime_map = {
|
||||
"day": timedelta(hours=random.randrange(9, 18)),
|
||||
"night": timedelta(hours=random.randrange(-3, 6)),
|
||||
"dusk": timedelta(hours=random.randrange(18, 21)),
|
||||
"dawn": timedelta(hours=random.randrange(6, 9)),
|
||||
}
|
||||
|
||||
time_period = None
|
||||
start_time = datetime.combine(datetime.today(), time())
|
||||
time_range = None
|
||||
for k, v in RANDOM_TIME.items():
|
||||
if random.randint(0, 100) <= v:
|
||||
time_period = k
|
||||
time_range = self.game.theater.daytime_map[k]
|
||||
break
|
||||
|
||||
print("generated {}".format(time_period))
|
||||
start_time += daytime_map[time_period]
|
||||
start_time += timedelta(hours=random.randint(*time_range))
|
||||
self.mission.start_time = start_time
|
||||
|
||||
def _gen_random_weather(self):
|
||||
@ -102,6 +95,16 @@ class EnvironmentSettingsGenerator:
|
||||
continue
|
||||
self.mission.terrain.airport_by_id(cp.at.id).set_coalition(cp.captured and player_coalition or enemy_coalition)
|
||||
|
||||
def _set_skill(self, player_coalition: str, enemy_coalition: str):
|
||||
for coalition_name, coalition in self.mission.coalition.items():
|
||||
skill_level = player_coalition == coalition_name and self.game.player_skill or self.game.enemy_skill
|
||||
for country in coalition.countries.values():
|
||||
for plane_group in country.plane_group:
|
||||
plane_group.set_skill(Skill(skill_level))
|
||||
|
||||
for vehicle_group in country.vehicle_group:
|
||||
vehicle_group.set_skill(Skill(skill_level))
|
||||
|
||||
def generate(self, is_quick: bool):
|
||||
player_coalition = self.game.player == "USA" and "blue" or "red"
|
||||
enemy_coalition = player_coalition == "blue" and "red" or "blue"
|
||||
@ -111,6 +114,7 @@ class EnvironmentSettingsGenerator:
|
||||
|
||||
self._gen_random_time()
|
||||
self._gen_random_weather()
|
||||
self._set_skill(player_coalition, enemy_coalition)
|
||||
self._set_allegiances(player_coalition, enemy_coalition)
|
||||
|
||||
if not is_quick:
|
||||
126
gen/visualgen.py
Normal file
126
gen/visualgen.py
Normal file
@ -0,0 +1,126 @@
|
||||
import typing
|
||||
import random
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
from dcs.mission import Mission
|
||||
from dcs.statics import *
|
||||
from dcs.unit import Static
|
||||
|
||||
from theater.conflicttheater import Conflict
|
||||
#from game.game import Game
|
||||
|
||||
|
||||
class Smoke(unittype.StaticType):
|
||||
id = "big_smoke"
|
||||
category = "Effects"
|
||||
name = "big_smoke"
|
||||
shape_name = 2
|
||||
rate = 100
|
||||
|
||||
|
||||
class BigSmoke(unittype.StaticType):
|
||||
id = "big_smoke"
|
||||
category = "Effects"
|
||||
name = "big_smoke"
|
||||
shape_name = 3
|
||||
rate = 100
|
||||
|
||||
|
||||
class MassiveSmoke(unittype.StaticType):
|
||||
id = "big_smoke"
|
||||
category = "Effects"
|
||||
name = "big_smoke"
|
||||
shape_name = 4
|
||||
rate = 100
|
||||
|
||||
|
||||
def __monkey_static_dict(self: Static):
|
||||
global __original_static_dict
|
||||
|
||||
d = __original_static_dict(self)
|
||||
if self.type == "big_smoke":
|
||||
d["effectPreset"] = self.shape_name
|
||||
return d
|
||||
|
||||
|
||||
__original_static_dict = Static.dict
|
||||
Static.dict = __monkey_static_dict
|
||||
|
||||
FRONT_SMOKE_MIN_DISTANCE = 10000
|
||||
FRONT_SMOKE_DISTANCE_FACTOR = 0.75
|
||||
FRONT_SMOKE_LENGTH = 80000
|
||||
FRONT_SMOKE_SPACING = 600
|
||||
FRONT_SMOKE_RANDOM_SPREAD = 1200
|
||||
FRONT_SMOKE_TYPE_CHANCES = {
|
||||
5: MassiveSmoke,
|
||||
40: BigSmoke,
|
||||
100: Smoke,
|
||||
}
|
||||
|
||||
DESTINATION_SMOKE_AMOUNT_FACTOR = 0.03
|
||||
DESTINATION_SMOKE_DISTANCE_FACTOR = 1
|
||||
DESTINATION_SMOKE_TYPE_CHANCES = {
|
||||
5: BigSmoke,
|
||||
100: Smoke,
|
||||
}
|
||||
|
||||
|
||||
def turn_heading(heading, fac):
|
||||
heading += fac
|
||||
if heading > 359:
|
||||
heading = heading - 359
|
||||
if heading < 0:
|
||||
heading = 359 + heading
|
||||
return heading
|
||||
|
||||
|
||||
class VisualGenerator:
|
||||
game = None # type: Game
|
||||
|
||||
def __init__(self, mission: Mission, conflict: Conflict, game):
|
||||
self.mission = mission
|
||||
self.conflict = conflict
|
||||
self.game = game
|
||||
|
||||
def _generate_frontline_smokes(self):
|
||||
for from_cp, to_cp in self.game.theater.conflicts():
|
||||
distance = max(from_cp.position.distance_to_point(to_cp.position) * FRONT_SMOKE_DISTANCE_FACTOR * to_cp.base.strength, FRONT_SMOKE_MIN_DISTANCE)
|
||||
heading = to_cp.position.heading_between_point(from_cp.position)
|
||||
point = to_cp.position.point_from_heading(heading, distance)
|
||||
plane_start = point.point_from_heading(turn_heading(heading, 90), FRONT_SMOKE_LENGTH / 2)
|
||||
|
||||
for offset in range(0, FRONT_SMOKE_LENGTH, FRONT_SMOKE_SPACING):
|
||||
position = plane_start.point_from_heading(turn_heading(heading, - 90), offset)
|
||||
|
||||
for k, v in FRONT_SMOKE_TYPE_CHANCES.items():
|
||||
if random.randint(0, 100) <= k:
|
||||
pos = position.random_point_within(FRONT_SMOKE_RANDOM_SPREAD, FRONT_SMOKE_RANDOM_SPREAD)
|
||||
if not self.game.theater.is_on_land(pos):
|
||||
break
|
||||
|
||||
self.mission.static_group(
|
||||
self.mission.country(self.game.enemy),
|
||||
"",
|
||||
_type=v,
|
||||
position=pos)
|
||||
break
|
||||
|
||||
def generate_target_smokes(self, target):
|
||||
spread = target.size * DESTINATION_SMOKE_DISTANCE_FACTOR
|
||||
for _ in range(0, int(target.size * DESTINATION_SMOKE_AMOUNT_FACTOR * (1.1 - target.base.strength))):
|
||||
for k, v in DESTINATION_SMOKE_TYPE_CHANCES.items():
|
||||
if random.randint(0, 100) <= k:
|
||||
position = target.position.random_point_within(0, spread)
|
||||
if not self.game.theater.is_on_land(position):
|
||||
break
|
||||
|
||||
self.mission.static_group(
|
||||
self.mission.country(self.game.enemy),
|
||||
"",
|
||||
_type=v,
|
||||
position=position)
|
||||
|
||||
break
|
||||
|
||||
def generate(self):
|
||||
self._generate_frontline_smokes()
|
||||
BIN
resources/cau_terrain.miz
Normal file
BIN
resources/cau_terrain.miz
Normal file
Binary file not shown.
BIN
resources/caulandmap.p
Normal file
BIN
resources/caulandmap.p
Normal file
Binary file not shown.
14
resources/generate_landmap.py
Normal file
14
resources/generate_landmap.py
Normal file
@ -0,0 +1,14 @@
|
||||
import pickle
|
||||
|
||||
from dcs.mission import Mission
|
||||
from dcs.terrain import PersianGulf
|
||||
|
||||
m = Mission()
|
||||
m.load_file("./gulf_terrain.miz")
|
||||
|
||||
landmap = []
|
||||
for plane_group in m.country("USA").plane_group:
|
||||
landmap.append([(x.position.x, x.position.y) for x in plane_group.points])
|
||||
|
||||
with open("gulflandmap.p", "wb") as f:
|
||||
pickle.dump(landmap, f)
|
||||
BIN
resources/gulf_terrain.miz
Normal file
BIN
resources/gulf_terrain.miz
Normal file
Binary file not shown.
BIN
resources/gulflandmap.p
Normal file
BIN
resources/gulflandmap.p
Normal file
Binary file not shown.
BIN
resources/nevada.gif
Normal file
BIN
resources/nevada.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 117 KiB |
BIN
resources/persiangulf.gif
Normal file
BIN
resources/persiangulf.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 80 KiB |
@ -127,7 +127,6 @@ class Base:
|
||||
|
||||
def commit_losses(self, units_lost: typing.Dict[typing.Any, int]):
|
||||
for unit_type, count in units_lost.items():
|
||||
target_array = None
|
||||
if unit_type in self.aircraft:
|
||||
target_array = self.aircraft
|
||||
elif unit_type in self.armor:
|
||||
@ -164,3 +163,7 @@ class Base:
|
||||
|
||||
def assemble_defense(self, factor: float) -> typing.Dict[Armor, int]:
|
||||
return self._find_best_armor(CAP, math.ceil(self.total_armor * factor * self.strength))
|
||||
|
||||
def assemble_aa(self) -> typing.Dict[AirDefence, int]:
|
||||
count = int(self.total_aa * (self.strength > 0.2 and self.strength or 0))
|
||||
return self._find_best_unit(self.aa, AirDefence, count)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
from dcs.terrain import caucasus
|
||||
from dcs import mapping
|
||||
|
||||
from .landmap import *
|
||||
from .conflicttheater import *
|
||||
from .base import *
|
||||
|
||||
@ -10,6 +11,13 @@ class CaucasusTheater(ConflictTheater):
|
||||
overview_image = "caumap.gif"
|
||||
reference_points = {(-317948.32727306, 635639.37385346): (282.5, 319),
|
||||
(-355692.3067714, 617269.96285781): (269, 352), }
|
||||
landmap_poly = load_poly("resources\\caulandmap.p")
|
||||
daytime_map = {
|
||||
"dawn": (6, 9),
|
||||
"day": (9, 18),
|
||||
"dusk": (18, 21),
|
||||
"night": (0, 5),
|
||||
}
|
||||
|
||||
soganlug = ControlPoint.from_airport(caucasus.Soganlug, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
|
||||
kutaisi = ControlPoint.from_airport(caucasus.Kutaisi, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
|
||||
@ -32,7 +40,7 @@ class CaucasusTheater(ConflictTheater):
|
||||
mineralnye = ControlPoint.from_airport(caucasus.Mineralnye_Vody, ALL_RADIALS, SIZE_BIG, IMPORTANCE_MEDIUM)
|
||||
mozdok = ControlPoint.from_airport(caucasus.Mozdok, ALL_RADIALS, SIZE_BIG, IMPORTANCE_MEDIUM)
|
||||
|
||||
carrier_1 = ControlPoint.carrier("Carrier", mapping.Point(-355810.6875, 516399.1875))
|
||||
carrier_1 = ControlPoint.carrier("Carrier", mapping.Point(-305810.6875, 406399.1875))
|
||||
|
||||
def __init__(self):
|
||||
super(CaucasusTheater, self).__init__()
|
||||
@ -63,3 +71,9 @@ class CaucasusTheater(ConflictTheater):
|
||||
self.carrier_1.captured = True
|
||||
self.soganlug.captured = True
|
||||
|
||||
self.sukhumi.captured = True
|
||||
self.gudauta.base.strength = 0.5
|
||||
|
||||
self.kobuleti.captured = True
|
||||
self.batumi.base.strength = 0.15
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ import itertools
|
||||
|
||||
import dcs
|
||||
|
||||
from .landmap import ray_tracing
|
||||
from .controlpoint import *
|
||||
|
||||
SIZE_TINY = 150
|
||||
@ -31,6 +32,8 @@ class ConflictTheater:
|
||||
controlpoints = None # type: typing.Collection[ControlPoint]
|
||||
reference_points = None # type: typing.Dict
|
||||
overview_image = None # type: str
|
||||
landmap_poly = None
|
||||
daytime_map = None # type: typing.Dict[str, typing.Tuple[int, int]]
|
||||
|
||||
def __init__(self):
|
||||
self.controlpoints = []
|
||||
@ -41,6 +44,15 @@ class ConflictTheater:
|
||||
|
||||
self.controlpoints.append(point)
|
||||
|
||||
def is_on_land(self, point: Point) -> bool:
|
||||
if not self.landmap_poly:
|
||||
return True
|
||||
|
||||
for poly in self.landmap_poly:
|
||||
return ray_tracing(point.x, point.y, poly)
|
||||
|
||||
return False
|
||||
|
||||
def player_points(self) -> typing.Collection[ControlPoint]:
|
||||
return [point for point in self.controlpoints if point.captured]
|
||||
|
||||
|
||||
24
theater/landmap.py
Normal file
24
theater/landmap.py
Normal file
@ -0,0 +1,24 @@
|
||||
import pickle
|
||||
|
||||
|
||||
def load_poly(filename: str):
|
||||
with open(filename, "rb") as f:
|
||||
return pickle.load(f)
|
||||
|
||||
|
||||
def ray_tracing(x, y, poly):
|
||||
n = len(poly)
|
||||
inside = False
|
||||
xints = 0.0
|
||||
p1x, p1y = poly[0]
|
||||
for i in range(n+1):
|
||||
p2x, p2y = poly[i % n]
|
||||
if y > min(p1y, p2y):
|
||||
if y <= max(p1y, p2y):
|
||||
if x <= max(p1x, p2x):
|
||||
if p1y != p2y:
|
||||
xints = (y-p1y)*(p2x-p1x)/(p2y-p1y)+p1x
|
||||
if p1x == p2x or x <= xints:
|
||||
inside = not inside
|
||||
p1x, p1y = p2x, p2y
|
||||
return inside
|
||||
@ -10,6 +10,12 @@ class NevadaTheater(ConflictTheater):
|
||||
overview_image = "nevada.gif"
|
||||
reference_points = {(nevada.Mina_Airport_3Q0.position.x, nevada.Mina_Airport_3Q0.position.y): (45, -360),
|
||||
(nevada.Laughlin_Airport.position.x, nevada.Laughlin_Airport.position.y): (440, 80), }
|
||||
daytime_map = {
|
||||
"dawn": (4, 6),
|
||||
"day": (6, 17),
|
||||
"dusk": (17, 19),
|
||||
"night": (0, 5),
|
||||
}
|
||||
|
||||
mina = ControlPoint.from_airport(nevada.Mina_Airport_3Q0, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
|
||||
tonopah = ControlPoint.from_airport(nevada.Tonopah_Airport, ALL_RADIALS, SIZE_SMALL, IMPORTANCE_LOW)
|
||||
@ -45,3 +51,5 @@ class NevadaTheater(ConflictTheater):
|
||||
self.add_controlpoint(self.laughlin, connected_to=[self.jean, self.las_vegas])
|
||||
|
||||
self.mina.captured = True
|
||||
self.pahute_mesa.captured = True
|
||||
self.groom_lake.captured = True
|
||||
|
||||
@ -3,6 +3,7 @@ from dcs import mapping
|
||||
|
||||
from .conflicttheater import *
|
||||
from .base import *
|
||||
from .landmap import load_poly
|
||||
|
||||
|
||||
class PersianGulfTheater(ConflictTheater):
|
||||
@ -10,6 +11,13 @@ class PersianGulfTheater(ConflictTheater):
|
||||
overview_image = "persiangulf.gif"
|
||||
reference_points = {(persiangulf.Sir_Abu_Nuayr.position.x, persiangulf.Sir_Abu_Nuayr.position.y): (351, 115),
|
||||
(persiangulf.Sirri_Island.position.x, persiangulf.Sirri_Island.position.y): (389, 22), }
|
||||
landmap_poly = load_poly("resources\\gulflandmap.p")
|
||||
daytime_map = {
|
||||
"dawn": (5, 7),
|
||||
"day": (7, 17),
|
||||
"dusk": (17, 19),
|
||||
"night": (0, 5),
|
||||
}
|
||||
|
||||
al_dhafra = ControlPoint.from_airport(persiangulf.Al_Dhafra_AB, ALL_RADIALS, SIZE_BIG, IMPORTANCE_LOW)
|
||||
al_maktoum = ControlPoint.from_airport(persiangulf.Al_Maktoum_Intl, ALL_RADIALS, SIZE_BIG, IMPORTANCE_LOW)
|
||||
|
||||
@ -1,11 +1,20 @@
|
||||
import math
|
||||
|
||||
from theater.base import *
|
||||
from theater.conflicttheater import *
|
||||
|
||||
UNIT_VARIETY = 3
|
||||
UNIT_AMOUNT_FACTOR = 16
|
||||
|
||||
COUNT_BY_TASK = {
|
||||
CAP: 12,
|
||||
FighterSweep: 16,
|
||||
CAS: 8,
|
||||
AirDefence: 0.5,
|
||||
}
|
||||
|
||||
def generate_initial(theater: ConflictTheater, enemy: str):
|
||||
|
||||
def generate_initial(theater: ConflictTheater, enemy: str, sams: bool):
|
||||
for cp in theater.enemy_points():
|
||||
if cp.captured:
|
||||
continue
|
||||
@ -15,10 +24,14 @@ def generate_initial(theater: ConflictTheater, enemy: str):
|
||||
assert cp.importance >= IMPORTANCE_LOW, "invalid importance {}".format(cp.importance)
|
||||
|
||||
importance_factor = (cp.importance - IMPORTANCE_LOW) / (IMPORTANCE_HIGH - IMPORTANCE_LOW)
|
||||
variety = int(UNIT_VARIETY + UNIT_VARIETY * importance_factor / 2)
|
||||
variety = int(UNIT_VARIETY)
|
||||
unittypes = db.choose_units(task, importance_factor, variety, enemy)
|
||||
|
||||
count = max(int(importance_factor * UNIT_AMOUNT_FACTOR), 1)
|
||||
if not sams:
|
||||
unittypes = [x for x in unittypes if x not in db.SAM_BAN]
|
||||
|
||||
count = max(COUNT_BY_TASK[task] * importance_factor, 1)
|
||||
count_per_type = max(int(float(count) / len(unittypes)), 1)
|
||||
for unit_type in unittypes:
|
||||
print("{} - {} {}".format(cp.name, db.unit_type_name(unit_type), count_per_type))
|
||||
cp.base.commision_units({unit_type: count_per_type})
|
||||
|
||||
@ -7,3 +7,26 @@ from ui.window import *
|
||||
class ConfigurationMenu(Menu):
|
||||
def __init__(self, window: Window, parent, game: Game):
|
||||
super(ConfigurationMenu, self).__init__(window, parent, game)
|
||||
self.frame = window.right_pane
|
||||
self.player_skill_var = StringVar()
|
||||
self.player_skill_var.set(self.game.player_skill)
|
||||
|
||||
self.enemy_skill_var = StringVar()
|
||||
self.enemy_skill_var.set(self.game.enemy_skill)
|
||||
|
||||
def dismiss(self):
|
||||
self.game.player_skill = self.player_skill_var.get()
|
||||
self.game.enemy_skill = self.enemy_skill_var.get()
|
||||
super(ConfigurationMenu, self).dismiss()
|
||||
|
||||
def display(self):
|
||||
self.window.clear_right_pane()
|
||||
|
||||
Label(self.frame, text="Player coalition skill").grid(row=0, column=0)
|
||||
Label(self.frame, text="Enemy coalition skill").grid(row=1, column=0)
|
||||
|
||||
OptionMenu(self.frame, self.player_skill_var, "Average", "Good", "High", "Excellent").grid(row=0, column=1)
|
||||
OptionMenu(self.frame, self.enemy_skill_var, "Average", "Good", "High", "Excellent").grid(row=1, column=1)
|
||||
|
||||
Button(self.frame, text="Back", command=self.dismiss).grid(row=2, column=0, columnspan=1)
|
||||
|
||||
|
||||
@ -30,9 +30,9 @@ class EventMenu(Menu):
|
||||
self.window.clear_right_pane()
|
||||
row = 0
|
||||
|
||||
def label(text, _row=None, _column=None):
|
||||
def label(text, _row=None, _column=None, sticky=None):
|
||||
nonlocal row
|
||||
Label(self.frame, text=text).grid(row=_row and _row or row, column=_column and _column or 0)
|
||||
Label(self.frame, text=text).grid(row=_row and _row or row, column=_column and _column or 0, sticky=sticky)
|
||||
|
||||
if _row is None:
|
||||
row += 1
|
||||
@ -62,7 +62,12 @@ class EventMenu(Menu):
|
||||
|
||||
row += 1
|
||||
|
||||
Checkbutton(self.frame, text="AWACS", var=self.awacs).grid(row=row, column=2)
|
||||
Button(self.frame, text="Commit", command=self.start).grid(column=1, row=row, sticky=E)
|
||||
Button(self.frame, text="Back", command=self.dismiss).grid(column=2, row=row, sticky=E)
|
||||
|
||||
awacs_enabled = self.game.budget >= AWACS_BUDGET_COST and NORMAL or DISABLED
|
||||
Checkbutton(self.frame, text="AWACS ({}m)".format(AWACS_BUDGET_COST), var=self.awacs, state=awacs_enabled).grid(row=row, column=0, sticky=W)
|
||||
|
||||
row += 1
|
||||
|
||||
label("Aircraft")
|
||||
@ -76,17 +81,14 @@ class EventMenu(Menu):
|
||||
scrable_row(unit_type, count)
|
||||
|
||||
if not self.base.total_planes:
|
||||
label("None")
|
||||
label("None", sticky=W)
|
||||
|
||||
label("Armor")
|
||||
for unit_type, count in self.base.armor.items():
|
||||
scramble_armor_row(unit_type, count)
|
||||
|
||||
if not self.base.total_armor:
|
||||
label("None")
|
||||
|
||||
Button(self.frame, text="Commit", command=self.start).grid(column=0, row=row)
|
||||
Button(self.frame, text="Back", command=self.dismiss).grid(column=2, row=row)
|
||||
label("None", sticky=W)
|
||||
|
||||
def start(self):
|
||||
if self.awacs.get() == 1:
|
||||
|
||||
@ -2,6 +2,7 @@ import pickle
|
||||
|
||||
from ui.basemenu import *
|
||||
from ui.overviewcanvas import *
|
||||
from ui.configurationmenu import *
|
||||
|
||||
from game.game import *
|
||||
from userdata import persistency
|
||||
@ -41,7 +42,8 @@ class MainMenu(Menu):
|
||||
row += 1
|
||||
Separator(self.frame, orient='horizontal').grid(row=row, sticky=EW); row += 1
|
||||
|
||||
Button(self.frame, text="Pass turn", command=self.pass_turn).grid(column=0, row=0, sticky=NE)
|
||||
Button(self.frame, text="Configuration", command=self.configuration_menu).grid(column=0, row=0, sticky=NE)
|
||||
Button(self.frame, text="Pass turn", command=self.pass_turn).grid(column=0, row=0, sticky=N)
|
||||
Label(self.frame, text="Budget: {}m (+{}m)".format(self.game.budget, self.game.budget_reward_amount)).grid(column=0, row=0, sticky=NW)
|
||||
Separator(self.frame, orient='horizontal').grid(row=row, sticky=EW); row += 1
|
||||
|
||||
@ -58,10 +60,16 @@ class MainMenu(Menu):
|
||||
self.game.pass_turn(no_action=True)
|
||||
self.display()
|
||||
|
||||
def configuration_menu(self):
|
||||
ConfigurationMenu(self.window, self, self.game).display()
|
||||
|
||||
def start_event(self, event) -> typing.Callable:
|
||||
return lambda: EventMenu(self.window, self, self.game, event).display()
|
||||
|
||||
def go_cp(self, cp: ControlPoint):
|
||||
if not cp.captured:
|
||||
return
|
||||
|
||||
if self.basemenu:
|
||||
self.basemenu.dismiss()
|
||||
self.basemenu = None
|
||||
|
||||
@ -7,6 +7,7 @@ from ui.window import *
|
||||
class NewGameMenu(Menu):
|
||||
selected_country = None # type: IntVar
|
||||
selected_terrain = None # type: IntVar
|
||||
sams = True
|
||||
|
||||
def __init__(self, window: Window, callback: typing.Callable):
|
||||
super(NewGameMenu, self).__init__(window, None, None)
|
||||
@ -19,6 +20,9 @@ class NewGameMenu(Menu):
|
||||
self.selected_terrain = IntVar()
|
||||
self.selected_terrain.set(0)
|
||||
|
||||
self.sams = BooleanVar()
|
||||
self.sams.set(1)
|
||||
|
||||
@property
|
||||
def player_country_name(self):
|
||||
if self.selected_country.get() == 0:
|
||||
@ -53,7 +57,11 @@ class NewGameMenu(Menu):
|
||||
Radiobutton(self.frame, text="Caucasus", variable=self.selected_terrain, value=0).grid(row=1, column=1)
|
||||
Radiobutton(self.frame, text="Nevada", variable=self.selected_terrain, value=1).grid(row=2, column=1)
|
||||
Radiobutton(self.frame, text="Persian Gulf", variable=self.selected_terrain, value=2).grid(row=3, column=1)
|
||||
Button(self.frame, text="Proceed", command=self.proceed).grid(row=4, column=0, columnspan=2)
|
||||
|
||||
Label(self.frame, text="Options").grid(row=1, column=2)
|
||||
Checkbutton(self.frame, text="SAMs", variable=self.sams).grid(row=1, column=2)
|
||||
|
||||
Button(self.frame, text="Proceed", command=self.proceed).grid(row=4, column=0, columnspan=3)
|
||||
|
||||
def proceed(self):
|
||||
self.callback(self.player_country_name, self.enemy_country_name, self.terrain_name)
|
||||
self.callback(self.player_country_name, self.enemy_country_name, self.terrain_name, bool(self.sams.get()))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user