mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Merge branch 'master' of https://github.com/shdwp/dcs_pmcliberation
This commit is contained in:
commit
5f7724d44e
82
__init__.py
82
__init__.py
@ -1,90 +1,24 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
import pickle
|
||||||
|
|
||||||
import dcs
|
|
||||||
import os
|
|
||||||
|
|
||||||
import gen
|
|
||||||
import theater.caucasus
|
import theater.caucasus
|
||||||
import game.operation
|
|
||||||
import ui.window
|
import ui.window
|
||||||
import ui.mainmenu
|
import ui.mainmenu
|
||||||
|
|
||||||
from game.game import Game
|
from game.game import Game
|
||||||
from theater import start_generator
|
from theater import start_generator
|
||||||
from theater.controlpoint import *
|
from userdata import persistency
|
||||||
|
|
||||||
from dcs.planes import *
|
game = persistency.restore_game()
|
||||||
from dcs.vehicles import *
|
if not game:
|
||||||
|
theater = theater.caucasus.CaucasusTheater()
|
||||||
|
start_generator.generate_initial(theater, "Russia")
|
||||||
|
|
||||||
m = dcs.Mission()
|
game = Game(theater=theater)
|
||||||
theater = theater.caucasus.CaucasusTheater()
|
|
||||||
|
|
||||||
start_generator.generate_initial(theater, "Russia")
|
|
||||||
g = Game(theater=theater)
|
|
||||||
|
|
||||||
w = ui.window.Window()
|
w = ui.window.Window()
|
||||||
m = ui.mainmenu.MainMenu(w, None, g)
|
m = ui.mainmenu.MainMenu(w, None, game)
|
||||||
m.display()
|
m.display()
|
||||||
|
|
||||||
w.run()
|
w.run()
|
||||||
|
|
||||||
|
|
||||||
"""
|
|
||||||
selected_cp = None # type: ControlPoint
|
|
||||||
while True:
|
|
||||||
ptr = 0
|
|
||||||
|
|
||||||
print("Budget: {}m".format(g.budget))
|
|
||||||
|
|
||||||
if selected_cp is None:
|
|
||||||
print("Events:")
|
|
||||||
for event in g.events:
|
|
||||||
ptr += 1
|
|
||||||
print("{}. {} {}".format(ptr, event.attacker != g.side and "!" or " ", event))
|
|
||||||
|
|
||||||
print("Control Points:")
|
|
||||||
controlpoints = g.theater.controlpoints
|
|
||||||
controlpoints.sort(key=lambda x: x.captured)
|
|
||||||
for cp in g.theater.controlpoints:
|
|
||||||
ptr += 1
|
|
||||||
print("{}. [{}{}] {}{}{}{}".format(
|
|
||||||
ptr,
|
|
||||||
cp.captured and "x" or " ",
|
|
||||||
int(cp.base.readiness * 10),
|
|
||||||
cp.name,
|
|
||||||
"^" * cp.base.total_planes,
|
|
||||||
"." * cp.base.total_armor,
|
|
||||||
"*" * cp.base.total_aa))
|
|
||||||
|
|
||||||
events_boundary = len(g.events)
|
|
||||||
try:
|
|
||||||
selected_idx = int(input(">").strip()) - 1
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
|
|
||||||
if selected_idx == -1:
|
|
||||||
g.pass_turn()
|
|
||||||
continue
|
|
||||||
if selected_idx < events_boundary:
|
|
||||||
event = g.events[selected_idx]
|
|
||||||
else:
|
|
||||||
selected_cp = controlpoints[selected_idx - events_boundary]
|
|
||||||
else:
|
|
||||||
print("Units on the base: ")
|
|
||||||
for unit, count in selected_cp.base.all_units:
|
|
||||||
print("{} ({}) ".format(unit.name and unit.name or unit.id, count), end="")
|
|
||||||
print("")
|
|
||||||
|
|
||||||
try:
|
|
||||||
selected_idx = int(input(">").strip()) - 1
|
|
||||||
except:
|
|
||||||
continue
|
|
||||||
if selected_idx == -1:
|
|
||||||
selected_cp = None
|
|
||||||
|
|
||||||
if not os.path.exists("./build"):
|
|
||||||
os.mkdir("./build")
|
|
||||||
|
|
||||||
m.save("build/output.miz")
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
import typing
|
import typing
|
||||||
import dcs
|
|
||||||
|
|
||||||
import globals
|
|
||||||
|
|
||||||
from dcs.vehicles import *
|
from dcs.vehicles import *
|
||||||
from dcs.unitgroup import *
|
from dcs.unitgroup import *
|
||||||
175
game/event.py
175
game/event.py
@ -1,11 +1,3 @@
|
|||||||
import typing
|
|
||||||
import random
|
|
||||||
import math
|
|
||||||
|
|
||||||
import dcs
|
|
||||||
|
|
||||||
from theater.controlpoint import *
|
|
||||||
from userdata.debriefing_parser import *
|
|
||||||
from game.operation import *
|
from game.operation import *
|
||||||
|
|
||||||
DIFFICULTY_LOG_BASE = 1.5
|
DIFFICULTY_LOG_BASE = 1.5
|
||||||
@ -18,12 +10,12 @@ class Event:
|
|||||||
difficulty = 1 # type: int
|
difficulty = 1 # type: int
|
||||||
BONUS_BASE = 0
|
BONUS_BASE = 0
|
||||||
|
|
||||||
def __init__(self, attacker_name: str, defender_name: str, from_cp: ControlPoint, to_cp: ControlPoint):
|
def __init__(self, attacker_name: str, defender_name: str, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater):
|
||||||
self.mission = dcs.mission.Mission()
|
self.attacker_name = attacker_name
|
||||||
self.attacker = self.mission.country(attacker_name)
|
self.defender_name = defender_name
|
||||||
self.defender = self.mission.country(defender_name)
|
|
||||||
self.to_cp = to_cp
|
self.to_cp = to_cp
|
||||||
self.from_cp = from_cp
|
self.from_cp = from_cp
|
||||||
|
self.theater = theater
|
||||||
|
|
||||||
def bonus(self) -> int:
|
def bonus(self) -> int:
|
||||||
return math.ceil(math.log(self.difficulty, DIFFICULTY_LOG_BASE) * self.BONUS_BASE)
|
return math.ceil(math.log(self.difficulty, DIFFICULTY_LOG_BASE) * self.BONUS_BASE)
|
||||||
@ -31,10 +23,19 @@ class Event:
|
|||||||
def is_successfull(self, debriefing: Debriefing) -> bool:
|
def is_successfull(self, debriefing: Debriefing) -> bool:
|
||||||
return self.operation.is_successfull(debriefing)
|
return self.operation.is_successfull(debriefing)
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
self.operation.prepare(is_quick=False)
|
||||||
|
self.operation.generate()
|
||||||
|
self.operation.mission.save("build/nextturn.miz")
|
||||||
|
|
||||||
|
self.operation.prepare(is_quick=True)
|
||||||
|
self.operation.generate()
|
||||||
|
self.operation.mission.save('build/nextturn_quick.miz')
|
||||||
|
|
||||||
def commit(self, debriefing: Debriefing):
|
def commit(self, debriefing: Debriefing):
|
||||||
for country, losses in debriefing.destroyed_units.items():
|
for country, losses in debriefing.destroyed_units.items():
|
||||||
cp = None # type: ControlPoint
|
cp = None # type: ControlPoint
|
||||||
if country == self.attacker.name:
|
if country == self.attacker_name:
|
||||||
cp = self.from_cp
|
cp = self.from_cp
|
||||||
else:
|
else:
|
||||||
cp = self.to_cp
|
cp = self.to_cp
|
||||||
@ -84,27 +85,29 @@ class GroundInterceptEvent(Event):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def player_attacking(self, position: Point, strikegroup: db.PlaneDict, clients: db.PlaneDict):
|
def player_attacking(self, position: Point, strikegroup: db.PlaneDict, clients: db.PlaneDict):
|
||||||
suitable_unittypes = db.find_unittype(CAP, self.defender.name)
|
suitable_unittypes = db.find_unittype(CAP, self.defender_name)
|
||||||
random.shuffle(suitable_unittypes)
|
random.shuffle(suitable_unittypes)
|
||||||
unittypes = suitable_unittypes[:self.TARGET_VARIETY]
|
unittypes = suitable_unittypes[:self.TARGET_VARIETY]
|
||||||
typecount = max(math.floor(self.difficulty * self.TARGET_AMOUNT_FACTOR), 1)
|
typecount = max(math.floor(self.difficulty * self.TARGET_AMOUNT_FACTOR), 1)
|
||||||
|
|
||||||
self.targets = {unittype: typecount for unittype in unittypes}
|
self.targets = {unittype: typecount for unittype in unittypes}
|
||||||
self.operation = GroundInterceptOperation(mission=self.mission,
|
|
||||||
attacker=self.attacker,
|
op = GroundInterceptOperation(attacker_name=self.attacker_name,
|
||||||
defender=self.defender,
|
defender_name=self.defender_name,
|
||||||
attacker_clients=clients,
|
attacker_clients=clients,
|
||||||
defender_clients={},
|
defender_clients={},
|
||||||
from_cp=self.from_cp,
|
from_cp=self.from_cp)
|
||||||
position=position,
|
op.setup(position=position,
|
||||||
target=self.targets,
|
target=self.targets,
|
||||||
strikegroup=strikegroup)
|
strikegroup=strikegroup)
|
||||||
|
|
||||||
|
self.operation = op
|
||||||
|
|
||||||
|
|
||||||
class InterceptEvent(Event):
|
class InterceptEvent(Event):
|
||||||
ESCORT_AMOUNT_FACTOR = 2
|
ESCORT_AMOUNT_FACTOR = 2
|
||||||
BONUS_BASE = 5
|
BONUS_BASE = 5
|
||||||
STRENGTH_INFLUENCE = 0.25
|
STRENGTH_INFLUENCE = 0.25
|
||||||
|
GLOBAL_STRENGTH_INFLUENCE = 0.05
|
||||||
AIRDEFENSE_COUNT = 3
|
AIRDEFENSE_COUNT = 3
|
||||||
|
|
||||||
transport_unit = None # type: FlyingType
|
transport_unit = None # type: FlyingType
|
||||||
@ -123,7 +126,11 @@ class InterceptEvent(Event):
|
|||||||
super(InterceptEvent, self).commit(debriefing)
|
super(InterceptEvent, self).commit(debriefing)
|
||||||
|
|
||||||
if self.is_successfull(debriefing):
|
if self.is_successfull(debriefing):
|
||||||
self.to_cp.base.affect_strength(self.STRENGTH_INFLUENCE * float(self.from_cp.captured and -1 or 1))
|
if self.from_cp.is_global:
|
||||||
|
for cp in self.theater.enemy_points():
|
||||||
|
cp.base.affect_strength(-self.GLOBAL_STRENGTH_INFLUENCE)
|
||||||
|
else:
|
||||||
|
self.to_cp.base.affect_strength(self.STRENGTH_INFLUENCE * float(self.from_cp.captured and -1 or 1))
|
||||||
else:
|
else:
|
||||||
self.to_cp.base.affect_strength(self.STRENGTH_INFLUENCE * float(self.from_cp.captured and 1 or -1))
|
self.to_cp.base.affect_strength(self.STRENGTH_INFLUENCE * float(self.from_cp.captured and 1 or -1))
|
||||||
|
|
||||||
@ -133,39 +140,43 @@ class InterceptEvent(Event):
|
|||||||
|
|
||||||
def player_attacking(self, interceptors: db.PlaneDict, clients: db.PlaneDict):
|
def player_attacking(self, interceptors: db.PlaneDict, clients: db.PlaneDict):
|
||||||
escort = self.to_cp.base.scramble_sweep(self.to_cp)
|
escort = self.to_cp.base.scramble_sweep(self.to_cp)
|
||||||
self.transport_unit = random.choice(db.find_unittype(Transport, self.defender.name))
|
self.transport_unit = random.choice(db.find_unittype(Transport, self.defender_name))
|
||||||
assert self.transport_unit is not None
|
assert self.transport_unit is not None
|
||||||
|
|
||||||
airdefense_unit = db.find_unittype(AirDefence, self.defender.name)[0]
|
airdefense_unit = db.find_unittype(AirDefence, self.defender_name)[0]
|
||||||
|
|
||||||
self.operation = InterceptOperation(mission=self.mission,
|
op = InterceptOperation(attacker_name=self.attacker_name,
|
||||||
attacker=self.attacker,
|
defender_name=self.defender_name,
|
||||||
defender=self.defender,
|
attacker_clients=clients,
|
||||||
attacker_clients=clients,
|
defender_clients={},
|
||||||
defender_clients={},
|
from_cp=self.from_cp,
|
||||||
from_cp=self.from_cp,
|
to_cp=self.to_cp)
|
||||||
to_cp=self.to_cp,
|
|
||||||
escort=escort,
|
op.setup(escort=escort,
|
||||||
transport={self.transport_unit: 1},
|
transport={self.transport_unit: 1},
|
||||||
airdefense={airdefense_unit: self.AIRDEFENSE_COUNT},
|
airdefense={airdefense_unit: self.AIRDEFENSE_COUNT},
|
||||||
interceptors=interceptors)
|
interceptors=interceptors)
|
||||||
|
|
||||||
|
self.operation = op
|
||||||
|
|
||||||
def player_defending(self, escort: db.PlaneDict, clients: db.PlaneDict):
|
def player_defending(self, escort: db.PlaneDict, clients: db.PlaneDict):
|
||||||
interceptors = self.from_cp.base.scramble_interceptors_count(self.difficulty * self.ESCORT_AMOUNT_FACTOR)
|
interceptors = self.from_cp.base.scramble_interceptors_count(self.difficulty * self.ESCORT_AMOUNT_FACTOR)
|
||||||
self.transport_unit = random.choice(db.find_unittype(Transport, self.defender.name))
|
self.transport_unit = random.choice(db.find_unittype(Transport, self.defender_name))
|
||||||
assert self.transport_unit is not None
|
assert self.transport_unit is not None
|
||||||
|
|
||||||
self.operation = InterceptOperation(mission=self.mission,
|
op = InterceptOperation(attacker_name=self.attacker_name,
|
||||||
attacker=self.attacker,
|
defender_name=self.defender_name,
|
||||||
defender=self.defender,
|
attacker_clients={},
|
||||||
attacker_clients={},
|
defender_clients=clients,
|
||||||
defender_clients=clients,
|
from_cp=self.from_cp,
|
||||||
from_cp=self.from_cp,
|
to_cp=self.to_cp)
|
||||||
to_cp=self.to_cp,
|
|
||||||
escort=escort,
|
op.setup(escort=escort,
|
||||||
transport={self.transport_unit: 1},
|
transport={self.transport_unit: 1},
|
||||||
interceptors=interceptors,
|
interceptors=interceptors,
|
||||||
airdefense={})
|
airdefense={})
|
||||||
|
|
||||||
|
self.operation = op
|
||||||
|
|
||||||
|
|
||||||
class CaptureEvent(Event):
|
class CaptureEvent(Event):
|
||||||
@ -188,6 +199,9 @@ class CaptureEvent(Event):
|
|||||||
if self.is_successfull(debriefing):
|
if self.is_successfull(debriefing):
|
||||||
if self.from_cp.captured:
|
if self.from_cp.captured:
|
||||||
self.to_cp.captured = True
|
self.to_cp.captured = True
|
||||||
|
self.to_cp.base.filter_units(db.UNIT_BY_COUNTRY[self.attacker_name])
|
||||||
|
|
||||||
|
self.to_cp.base.affect_strength(+self.STRENGTH_RECOVERY)
|
||||||
else:
|
else:
|
||||||
if not self.from_cp.captured:
|
if not self.from_cp.captured:
|
||||||
self.to_cp.captured = False
|
self.to_cp.captured = False
|
||||||
@ -202,47 +216,52 @@ class CaptureEvent(Event):
|
|||||||
escort = self.from_cp.base.scramble_sweep(self.to_cp)
|
escort = self.from_cp.base.scramble_sweep(self.to_cp)
|
||||||
attackers = self.from_cp.base.assemble_cap(self.to_cp)
|
attackers = self.from_cp.base.assemble_cap(self.to_cp)
|
||||||
|
|
||||||
self.operation = CaptureOperation(mission=self.mission,
|
op = CaptureOperation(attacker_name=self.attacker_name,
|
||||||
attacker=self.attacker,
|
defender_name=self.defender_name,
|
||||||
defender=self.defender,
|
attacker_clients={},
|
||||||
attacker_clients={},
|
defender_clients=clients,
|
||||||
defender_clients=clients,
|
from_cp=self.from_cp,
|
||||||
from_cp=self.from_cp,
|
to_cp=self.to_cp)
|
||||||
to_cp=self.to_cp,
|
|
||||||
cas=cas,
|
op.setup(cas=cas,
|
||||||
escort=escort,
|
escort=escort,
|
||||||
attack=attackers,
|
attack=attackers,
|
||||||
intercept=interceptors,
|
intercept=interceptors,
|
||||||
defense=self.to_cp.base.armor,
|
defense=self.to_cp.base.armor,
|
||||||
aa=self.to_cp.base.aa)
|
aa=self.to_cp.base.aa)
|
||||||
|
|
||||||
|
self.operation = op
|
||||||
|
|
||||||
def player_attacking(self, cas: db.PlaneDict, escort: db.PlaneDict, armor: db.ArmorDict, clients: db.PlaneDict):
|
def player_attacking(self, cas: db.PlaneDict, escort: db.PlaneDict, armor: db.ArmorDict, clients: db.PlaneDict):
|
||||||
interceptors = self.to_cp.base.scramble_sweep(for_target=self.to_cp)
|
interceptors = self.to_cp.base.scramble_sweep(for_target=self.to_cp)
|
||||||
|
|
||||||
self.operation = CaptureOperation(mission=self.mission,
|
op = CaptureOperation(attacker_name=self.attacker_name,
|
||||||
attacker=self.attacker,
|
defender_name=self.defender_name,
|
||||||
defender=self.defender,
|
attacker_clients=clients,
|
||||||
attacker_clients=clients,
|
defender_clients={},
|
||||||
defender_clients={},
|
from_cp=self.from_cp,
|
||||||
from_cp=self.from_cp,
|
to_cp=self.to_cp)
|
||||||
to_cp=self.to_cp,
|
|
||||||
cas=cas,
|
op.setup(cas=cas,
|
||||||
escort=escort,
|
escort=escort,
|
||||||
attack=armor,
|
attack=armor,
|
||||||
intercept=interceptors,
|
intercept=interceptors,
|
||||||
defense=self.to_cp.base.armor,
|
defense=self.to_cp.base.armor,
|
||||||
aa=self.to_cp.base.aa)
|
aa=self.to_cp.base.aa)
|
||||||
|
|
||||||
|
self.operation = op
|
||||||
|
|
||||||
|
|
||||||
class UnitsDeliveryEvent(Event):
|
class UnitsDeliveryEvent(Event):
|
||||||
informational = True
|
informational = True
|
||||||
units = None # type: typing.Dict[UnitType, int]
|
units = None # type: typing.Dict[UnitType, int]
|
||||||
|
|
||||||
def __init__(self, attacker_name: str, defender_name: str, from_cp: ControlPoint, to_cp: ControlPoint):
|
def __init__(self, attacker_name: str, defender_name: str, from_cp: ControlPoint, to_cp: ControlPoint, theater: ConflictTheater):
|
||||||
super(UnitsDeliveryEvent, self).__init__(attacker_name=attacker_name,
|
super(UnitsDeliveryEvent, self).__init__(attacker_name=attacker_name,
|
||||||
defender_name=defender_name,
|
defender_name=defender_name,
|
||||||
from_cp=from_cp,
|
from_cp=from_cp,
|
||||||
to_cp=to_cp)
|
to_cp=to_cp,
|
||||||
|
theater=theater)
|
||||||
|
|
||||||
self.units = {}
|
self.units = {}
|
||||||
|
|
||||||
|
|||||||
69
game/game.py
69
game/game.py
@ -1,9 +1,3 @@
|
|||||||
import typing
|
|
||||||
import random
|
|
||||||
|
|
||||||
from theater.conflicttheater import *
|
|
||||||
from theater.controlpoint import *
|
|
||||||
from userdata.debriefing_parser import *
|
|
||||||
from game.event import *
|
from game.event import *
|
||||||
|
|
||||||
COMMISION_LIMITS_SCALE = 2
|
COMMISION_LIMITS_SCALE = 2
|
||||||
@ -24,12 +18,16 @@ COMMISION_AMOUNTS_FACTORS = {
|
|||||||
|
|
||||||
|
|
||||||
ENEMY_INTERCEPT_PROBABILITY_BASE = 10
|
ENEMY_INTERCEPT_PROBABILITY_BASE = 10
|
||||||
|
ENEMY_INTERCEPT_GLOBAL_PROBABILITY_BASE = 1
|
||||||
ENEMY_CAPTURE_PROBABILITY_BASE = 3
|
ENEMY_CAPTURE_PROBABILITY_BASE = 3
|
||||||
|
|
||||||
PLAYER_INTERCEPT_PROBABILITY_BASE = 30
|
PLAYER_INTERCEPT_PROBABILITY_BASE = 30
|
||||||
PLAYER_GROUNDINTERCEPT_PROBABILITY_BASE = 30
|
PLAYER_GROUNDINTERCEPT_PROBABILITY_BASE = 30
|
||||||
PLAYER_GLOBALINTERCEPT_PROBABILITY_BASE = 100
|
PLAYER_GLOBALINTERCEPT_PROBABILITY_BASE = 100
|
||||||
|
|
||||||
|
PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE = 50
|
||||||
|
PLAYER_INTERCEPT_GLOBAL_PROBABILITY_LOG = 2
|
||||||
|
|
||||||
PLAYER_BUDGET_BASE = 25
|
PLAYER_BUDGET_BASE = 25
|
||||||
PLAYER_BUDGET_IMPORTANCE_LOG = 2
|
PLAYER_BUDGET_IMPORTANCE_LOG = 2
|
||||||
|
|
||||||
@ -54,7 +52,8 @@ class Game:
|
|||||||
self.events.append(CaptureEvent(attacker_name=self.player,
|
self.events.append(CaptureEvent(attacker_name=self.player,
|
||||||
defender_name=self.enemy,
|
defender_name=self.enemy,
|
||||||
from_cp=from_cp,
|
from_cp=from_cp,
|
||||||
to_cp=to_cp))
|
to_cp=to_cp,
|
||||||
|
theater=self.theater))
|
||||||
|
|
||||||
def _generate_enemy_caps(self):
|
def _generate_enemy_caps(self):
|
||||||
for from_cp, to_cp in self.theater.conflicts(False):
|
for from_cp, to_cp in self.theater.conflicts(False):
|
||||||
@ -65,10 +64,12 @@ class Game:
|
|||||||
self.events.append(CaptureEvent(attacker_name=self.enemy,
|
self.events.append(CaptureEvent(attacker_name=self.enemy,
|
||||||
defender_name=self.player,
|
defender_name=self.player,
|
||||||
from_cp=from_cp,
|
from_cp=from_cp,
|
||||||
to_cp=to_cp))
|
to_cp=to_cp,
|
||||||
|
theater=self.theater))
|
||||||
break
|
break
|
||||||
|
|
||||||
def _generate_interceptions(self):
|
def _generate_interceptions(self):
|
||||||
|
enemy_interception = False
|
||||||
for from_cp, to_cp in self.theater.conflicts(False):
|
for from_cp, to_cp in self.theater.conflicts(False):
|
||||||
if from_cp.base.total_units(FighterSweep) == 0:
|
if from_cp.base.total_units(FighterSweep) == 0:
|
||||||
continue
|
continue
|
||||||
@ -77,15 +78,36 @@ class Game:
|
|||||||
self.events.append(InterceptEvent(attacker_name=self.enemy,
|
self.events.append(InterceptEvent(attacker_name=self.enemy,
|
||||||
defender_name=self.player,
|
defender_name=self.player,
|
||||||
from_cp=from_cp,
|
from_cp=from_cp,
|
||||||
to_cp=to_cp))
|
to_cp=to_cp,
|
||||||
|
theater=self.theater))
|
||||||
|
enemy_interception = True
|
||||||
break
|
break
|
||||||
|
|
||||||
|
for to_cp in self.theater.player_points():
|
||||||
|
if enemy_interception:
|
||||||
|
break
|
||||||
|
|
||||||
|
if to_cp in self.theater.conflicts(False):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if self._roll(ENEMY_INTERCEPT_GLOBAL_PROBABILITY_BASE, 1):
|
||||||
|
for from_cp, _ in self.theater.conflicts(False):
|
||||||
|
if from_cp.base.total_units(FighterSweep) > 0:
|
||||||
|
self.events.append(InterceptEvent(attacker_name=self.enemy,
|
||||||
|
defender_name=self.player,
|
||||||
|
from_cp=from_cp,
|
||||||
|
to_cp=to_cp,
|
||||||
|
theater=self.theater))
|
||||||
|
enemy_interception = True
|
||||||
|
break
|
||||||
|
|
||||||
for from_cp, to_cp in self.theater.conflicts(True):
|
for from_cp, to_cp in self.theater.conflicts(True):
|
||||||
if self._roll(PLAYER_INTERCEPT_PROBABILITY_BASE, from_cp.base.strength):
|
if self._roll(PLAYER_INTERCEPT_PROBABILITY_BASE, from_cp.base.strength):
|
||||||
self.events.append(InterceptEvent(attacker_name=self.player,
|
self.events.append(InterceptEvent(attacker_name=self.player,
|
||||||
defender_name=self.enemy,
|
defender_name=self.enemy,
|
||||||
from_cp=from_cp,
|
from_cp=from_cp,
|
||||||
to_cp=to_cp))
|
to_cp=to_cp,
|
||||||
|
theater=self.theater))
|
||||||
break
|
break
|
||||||
|
|
||||||
def _generate_groundinterceptions(self):
|
def _generate_groundinterceptions(self):
|
||||||
@ -94,7 +116,20 @@ class Game:
|
|||||||
self.events.append(GroundInterceptEvent(attacker_name=self.player,
|
self.events.append(GroundInterceptEvent(attacker_name=self.player,
|
||||||
defender_name=self.enemy,
|
defender_name=self.enemy,
|
||||||
from_cp=from_cp,
|
from_cp=from_cp,
|
||||||
to_cp=to_cp))
|
to_cp=to_cp,
|
||||||
|
theater=self.theater))
|
||||||
|
break
|
||||||
|
|
||||||
|
def _generate_globalinterceptions(self):
|
||||||
|
for from_cp in [x for x in self.theater.player_points() if x.is_global]:
|
||||||
|
probability = PLAYER_INTERCEPT_GLOBAL_PROBABILITY_BASE * math.log(len(self.theater.player_points()) + 1, PLAYER_INTERCEPT_GLOBAL_PROBABILITY_LOG)
|
||||||
|
if self._roll(probability, from_cp.base.strength):
|
||||||
|
to_cp = random.choice([x for x in self.theater.enemy_points() if x not in self.theater.conflicts()])
|
||||||
|
self.events.append(InterceptEvent(attacker_name=self.player,
|
||||||
|
defender_name=self.enemy,
|
||||||
|
from_cp=from_cp,
|
||||||
|
to_cp=to_cp,
|
||||||
|
theater=self.theater))
|
||||||
break
|
break
|
||||||
|
|
||||||
def _generate_global(self):
|
def _generate_global(self):
|
||||||
@ -134,7 +169,8 @@ class Game:
|
|||||||
event = UnitsDeliveryEvent(attacker_name=self.player,
|
event = UnitsDeliveryEvent(attacker_name=self.player,
|
||||||
defender_name=self.player,
|
defender_name=self.player,
|
||||||
from_cp=to_cp,
|
from_cp=to_cp,
|
||||||
to_cp=to_cp)
|
to_cp=to_cp,
|
||||||
|
theater=self.theater)
|
||||||
self.events.append(event)
|
self.events.append(event)
|
||||||
return event
|
return event
|
||||||
|
|
||||||
@ -143,8 +179,8 @@ class Game:
|
|||||||
self.events.remove(event)
|
self.events.remove(event)
|
||||||
|
|
||||||
def initiate_event(self, event: Event):
|
def initiate_event(self, event: Event):
|
||||||
event.operation.generate()
|
assert event in self.events
|
||||||
event.mission.save("build/next_mission.miz")
|
event.generate()
|
||||||
|
|
||||||
def finish_event(self, event: Event, debriefing: Debriefing):
|
def finish_event(self, event: Event, debriefing: Debriefing):
|
||||||
event.commit(debriefing)
|
event.commit(debriefing)
|
||||||
@ -154,7 +190,7 @@ class Game:
|
|||||||
self.events.remove(event)
|
self.events.remove(event)
|
||||||
|
|
||||||
def is_player_attack(self, event: Event):
|
def is_player_attack(self, event: Event):
|
||||||
return event.attacker.name == self.player
|
return event.attacker_name == self.player
|
||||||
|
|
||||||
def pass_turn(self, no_action=False):
|
def pass_turn(self, no_action=False):
|
||||||
for event in self.events:
|
for event in self.events:
|
||||||
@ -162,13 +198,14 @@ class Game:
|
|||||||
|
|
||||||
if not no_action:
|
if not no_action:
|
||||||
self._budget_player()
|
self._budget_player()
|
||||||
for cp in self.theater.enemy_bases():
|
for cp in self.theater.enemy_points():
|
||||||
self._commision_units(cp)
|
self._commision_units(cp)
|
||||||
|
|
||||||
self.events = [] # type: typing.List[Event]
|
self.events = [] # type: typing.List[Event]
|
||||||
self._fill_cap_events()
|
self._fill_cap_events()
|
||||||
self._generate_enemy_caps()
|
self._generate_enemy_caps()
|
||||||
self._generate_interceptions()
|
self._generate_interceptions()
|
||||||
|
self._generate_globalinterceptions()
|
||||||
self._generate_groundinterceptions()
|
self._generate_groundinterceptions()
|
||||||
self._generate_global()
|
self._generate_global()
|
||||||
|
|
||||||
|
|||||||
@ -1,14 +1,6 @@
|
|||||||
import typing
|
from userdata.debriefing import *
|
||||||
|
|
||||||
from globals import *
|
|
||||||
from userdata.debriefing_parser import *
|
|
||||||
from dcs.mission import *
|
|
||||||
from dcs.unitgroup import *
|
|
||||||
from dcs.vehicles import *
|
|
||||||
from theater.controlpoint import *
|
|
||||||
from theater.conflicttheater import *
|
from theater.conflicttheater import *
|
||||||
from theater.base import *
|
from theater.base import *
|
||||||
from shop import *
|
|
||||||
|
|
||||||
from gen.armor import *
|
from gen.armor import *
|
||||||
from gen.aircraft import *
|
from gen.aircraft import *
|
||||||
@ -18,13 +10,42 @@ from gen.conflictgen import *
|
|||||||
|
|
||||||
|
|
||||||
class Operation:
|
class Operation:
|
||||||
def __init__(self, mission: Mission, conflict: Conflict):
|
starting_position = None # type: db.StartingPosition
|
||||||
|
mission = None # type: dcs.Mission
|
||||||
|
conflict = None # type: Conflict
|
||||||
|
armorgen = None # type: ArmorConflictGenerator
|
||||||
|
airgen = None # type: AircraftConflictGenerator
|
||||||
|
aagen = None # type: AAConflictGenerator
|
||||||
|
shipgen = None # type: ShipGenerator
|
||||||
|
|
||||||
|
def __init__(self,
|
||||||
|
attacker_name: str,
|
||||||
|
defender_name: str,
|
||||||
|
attacker_clients: db.PlaneDict,
|
||||||
|
defender_clients: db.PlaneDict,
|
||||||
|
from_cp: ControlPoint,
|
||||||
|
to_cp: ControlPoint = None):
|
||||||
|
self.attacker_name = attacker_name
|
||||||
|
self.defender_name = defender_name
|
||||||
|
self.attacker_clients = attacker_clients
|
||||||
|
self.defender_clients = defender_clients
|
||||||
|
self.from_cp = from_cp
|
||||||
|
self.to_cp = to_cp
|
||||||
|
|
||||||
|
def initialize(self, mission: Mission, conflict: Conflict):
|
||||||
self.mission = mission
|
self.mission = mission
|
||||||
self.conflict = conflict
|
self.conflict = conflict
|
||||||
self.armorgen = ArmorConflictGenerator(self.mission, self.conflict)
|
|
||||||
self.airgen = AircraftConflictGenerator(self.mission, self.conflict)
|
self.armorgen = ArmorConflictGenerator(mission, conflict)
|
||||||
self.aagen = AAConflictGenerator(self.mission, self.conflict)
|
self.airgen = AircraftConflictGenerator(mission, conflict)
|
||||||
self.shipgen = ShipGenerator(self.mission, self.conflict)
|
self.aagen = AAConflictGenerator(mission, conflict)
|
||||||
|
self.shipgen = ShipGenerator(mission, conflict)
|
||||||
|
|
||||||
|
def prepare(self, is_quick: bool):
|
||||||
|
self.starting_position = is_quick and self.from_cp.at or None
|
||||||
|
|
||||||
|
def generate(self):
|
||||||
|
pass
|
||||||
|
|
||||||
def units_of(self, country_name: str) -> typing.Collection[UnitType]:
|
def units_of(self, country_name: str) -> typing.Collection[UnitType]:
|
||||||
return []
|
return []
|
||||||
@ -32,85 +53,81 @@ class Operation:
|
|||||||
def is_successfull(self, debriefing: Debriefing) -> bool:
|
def is_successfull(self, debriefing: Debriefing) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def generate(self):
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
class CaptureOperation(Operation):
|
class CaptureOperation(Operation):
|
||||||
def __init__(self,
|
cas = None # type: db.PlaneDict
|
||||||
mission: Mission,
|
escort = None # type: db.PlaneDict
|
||||||
attacker: Country,
|
intercept = None # type: db.PlaneDict
|
||||||
defender: Country,
|
attack = None # type: db.ArmorDict
|
||||||
attacker_clients: db.PlaneDict,
|
defense = None # type: db.ArmorDict
|
||||||
defender_clients: db.PlaneDict,
|
aa = None # type: db.AirDefenseDict
|
||||||
from_cp: ControlPoint,
|
|
||||||
to_cp: ControlPoint,
|
|
||||||
cas: db.PlaneDict,
|
|
||||||
escort: db.PlaneDict,
|
|
||||||
attack: db.ArmorDict,
|
|
||||||
intercept: db.PlaneDict,
|
|
||||||
defense: db.ArmorDict,
|
|
||||||
aa: db.AirDefenseDict):
|
|
||||||
conflict = to_cp.conflict_attack(from_cp, attacker, defender)
|
|
||||||
|
|
||||||
super(CaptureOperation, self).__init__(mission, conflict)
|
def setup(self,
|
||||||
self.from_cp = from_cp
|
cas: db.PlaneDict,
|
||||||
self.to_cp = to_cp
|
escort: db.PlaneDict,
|
||||||
self.attacker_clients = attacker_clients
|
attack: db.ArmorDict,
|
||||||
self.defender_clients = defender_clients
|
intercept: db.PlaneDict,
|
||||||
self.cas = cas
|
defense: db.ArmorDict,
|
||||||
self.escort = escort
|
aa: db.AirDefenseDict):
|
||||||
self.intercept = intercept
|
self.cas = cas
|
||||||
|
self.escort = escort
|
||||||
|
self.intercept = intercept
|
||||||
|
self.attack = attack
|
||||||
|
self.defense = defense
|
||||||
|
self.aa = aa
|
||||||
|
|
||||||
self.attack = attack
|
def prepare(self, is_quick: bool):
|
||||||
self.defense = defense
|
super(CaptureOperation, self).prepare(is_quick)
|
||||||
|
mission = dcs.Mission()
|
||||||
|
|
||||||
self.aa = aa
|
self.initialize(mission=mission,
|
||||||
|
conflict=self.to_cp.conflict_attack(self.from_cp,
|
||||||
|
mission.country(self.attacker_name),
|
||||||
|
mission.country(self.defender_name)))
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
self.armorgen.generate(self.attack, self.defense)
|
self.armorgen.generate(self.attack, self.defense)
|
||||||
self.aagen.generate(self.aa)
|
self.aagen.generate(self.aa)
|
||||||
self.airgen.generate_defense(self.intercept, clients=self.defender_clients)
|
self.airgen.generate_defense(self.intercept, clients=self.defender_clients)
|
||||||
|
|
||||||
self.airgen.generate_cas(self.cas, clients=self.attacker_clients, at=self.from_cp.at)
|
self.airgen.generate_cas(self.cas, clients=self.attacker_clients, at=self.starting_position)
|
||||||
self.airgen.generate_cas_escort(self.escort, clients=self.attacker_clients, at=self.from_cp.at)
|
self.airgen.generate_cas_escort(self.escort, clients=self.attacker_clients, at=self.starting_position)
|
||||||
|
|
||||||
|
|
||||||
class InterceptOperation(Operation):
|
class InterceptOperation(Operation):
|
||||||
def __init__(self,
|
escort = None # type: db.PlaneDict
|
||||||
mission: Mission,
|
transport = None # type: db.PlaneDict
|
||||||
attacker: Country,
|
interceptors = None # type: db.PlaneDict
|
||||||
defender: Country,
|
airdefense = None # type: db.AirDefenseDict
|
||||||
attacker_clients: db.PlaneDict,
|
|
||||||
defender_clients: db.PlaneDict,
|
|
||||||
from_cp: ControlPoint,
|
|
||||||
to_cp: ControlPoint,
|
|
||||||
escort: db.PlaneDict,
|
|
||||||
transport: db.PlaneDict,
|
|
||||||
airdefense: db.AirDefenseDict,
|
|
||||||
interceptors: db.PlaneDict):
|
|
||||||
heading = from_cp.position.heading_between_point(to_cp.position)
|
|
||||||
distance = from_cp.position.distance_to_point(to_cp.position)
|
|
||||||
position = from_cp.position.point_from_heading(heading, distance/2)
|
|
||||||
|
|
||||||
conflict = Conflict.intercept_conflict(
|
def setup(self,
|
||||||
attacker=attacker,
|
escort: db.PlaneDict,
|
||||||
defender=defender,
|
transport: db.PlaneDict,
|
||||||
position=position,
|
airdefense: db.AirDefenseDict,
|
||||||
heading=heading,
|
interceptors: db.PlaneDict):
|
||||||
radials=ALL_RADIALS
|
|
||||||
)
|
|
||||||
|
|
||||||
super(InterceptOperation, self).__init__(mission, conflict)
|
|
||||||
self.to_cp = to_cp
|
|
||||||
self.from_cp = from_cp
|
|
||||||
self.attacker_clients = attacker_clients
|
|
||||||
self.defender_clients = defender_clients
|
|
||||||
self.escort = escort
|
self.escort = escort
|
||||||
self.transport = transport
|
self.transport = transport
|
||||||
self.airdefense = airdefense
|
self.airdefense = airdefense
|
||||||
self.interceptors = interceptors
|
self.interceptors = interceptors
|
||||||
|
|
||||||
|
def prepare(self, is_quick: bool):
|
||||||
|
super(InterceptOperation, self).prepare(is_quick)
|
||||||
|
mission = dcs.Mission()
|
||||||
|
|
||||||
|
heading = self.from_cp.position.heading_between_point(self.to_cp.position)
|
||||||
|
distance = self.from_cp.position.distance_to_point(self.to_cp.position)
|
||||||
|
position = self.from_cp.position.point_from_heading(heading, distance/2)
|
||||||
|
conflict = Conflict.intercept_conflict(
|
||||||
|
attacker=mission.country(self.attacker_name),
|
||||||
|
defender=mission.country(self.defender_name),
|
||||||
|
position=position,
|
||||||
|
heading=randint(0, 360),
|
||||||
|
radials=ALL_RADIALS
|
||||||
|
)
|
||||||
|
|
||||||
|
self.initialize(mission=mission,
|
||||||
|
conflict=conflict)
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
self.airgen.generate_transport(self.transport, self.to_cp.at)
|
self.airgen.generate_transport(self.transport, self.to_cp.at)
|
||||||
self.airgen.generate_transport_escort(self.escort, clients=self.defender_clients)
|
self.airgen.generate_transport_escort(self.escort, clients=self.defender_clients)
|
||||||
@ -119,35 +136,31 @@ class InterceptOperation(Operation):
|
|||||||
if self.from_cp.is_global:
|
if self.from_cp.is_global:
|
||||||
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.shipgen.generate(self.from_cp.at))
|
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.shipgen.generate(self.from_cp.at))
|
||||||
else:
|
else:
|
||||||
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.from_cp.at)
|
self.airgen.generate_interception(self.interceptors, clients=self.attacker_clients, at=self.starting_position)
|
||||||
|
|
||||||
|
|
||||||
class GroundInterceptOperation(Operation):
|
class GroundInterceptOperation(Operation):
|
||||||
def __init__(self,
|
def setup(self,
|
||||||
mission: Mission,
|
position: Point,
|
||||||
attacker: Country,
|
target: db.ArmorDict,
|
||||||
defender: Country,
|
strikegroup: db.PlaneDict):
|
||||||
from_cp: ControlPoint,
|
self.position = position
|
||||||
attacker_clients: db.PlaneDict,
|
self.strikegroup = strikegroup
|
||||||
defender_clients: db.PlaneDict,
|
self.target = target
|
||||||
position: Point,
|
|
||||||
target: db.ArmorDict,
|
def prepare(self, is_quick: bool):
|
||||||
strikegroup: db.PlaneDict):
|
super(GroundInterceptOperation, self).prepare(is_quick)
|
||||||
|
mission = dcs.Mission()
|
||||||
conflict = Conflict.ground_intercept_conflict(
|
conflict = Conflict.ground_intercept_conflict(
|
||||||
attacker=attacker,
|
attacker=mission.country(self.defender_name),
|
||||||
defender=defender,
|
defender=mission.country(self.defender_name),
|
||||||
position=position,
|
position=self.position,
|
||||||
heading=randint(0, 360),
|
heading=randint(0, 360),
|
||||||
radials=ALL_RADIALS
|
radials=ALL_RADIALS
|
||||||
)
|
)
|
||||||
|
|
||||||
super(GroundInterceptOperation, self).__init__(mission, conflict)
|
super(GroundInterceptOperation, self).__init__(mission, conflict)
|
||||||
self.attacker_clients = attacker_clients
|
|
||||||
self.defender_clients = defender_clients
|
|
||||||
self.from_cp = from_cp
|
|
||||||
self.strikegroup = strikegroup
|
|
||||||
self.target = target
|
|
||||||
|
|
||||||
def generate(self):
|
def generate(self):
|
||||||
self.airgen.generate_cas(self.strikegroup, clients=self.attacker_clients, at=self.from_cp.at)
|
self.airgen.generate_cas(self.strikegroup, clients=self.attacker_clients, at=self.starting_position)
|
||||||
self.armorgen.generate({}, self.target)
|
self.armorgen.generate({}, self.target)
|
||||||
|
|||||||
16
gen/aaa.py
16
gen/aaa.py
@ -1,21 +1,9 @@
|
|||||||
import typing
|
from game import db
|
||||||
import pdb
|
|
||||||
import dcs
|
|
||||||
|
|
||||||
from random import randint
|
|
||||||
|
|
||||||
import globals
|
|
||||||
|
|
||||||
from .conflictgen import *
|
from .conflictgen import *
|
||||||
from .naming import *
|
from .naming import *
|
||||||
|
|
||||||
from dcs.mission import *
|
from dcs.mission import *
|
||||||
from dcs.vehicles import *
|
|
||||||
from dcs.unitgroup import *
|
|
||||||
from dcs.unittype import *
|
|
||||||
from dcs.mapping import *
|
|
||||||
from dcs.point import *
|
|
||||||
from dcs.task import *
|
|
||||||
|
|
||||||
DISTANCE_FACTOR = 4, 5
|
DISTANCE_FACTOR = 4, 5
|
||||||
|
|
||||||
@ -24,7 +12,7 @@ class AAConflictGenerator:
|
|||||||
self.m = mission
|
self.m = mission
|
||||||
self.conflict = conflict
|
self.conflict = conflict
|
||||||
|
|
||||||
def generate(self, units: typing.Dict[UnitType, int]):
|
def generate(self, units: db.AirDefenseDict):
|
||||||
for type, count in units.items():
|
for type, count in units.items():
|
||||||
for _, radial in zip(range(count), self.conflict.radials):
|
for _, radial in zip(range(count), self.conflict.radials):
|
||||||
distance = randint(self.conflict.size * DISTANCE_FACTOR[0], self.conflict.size * DISTANCE_FACTOR[1])
|
distance = randint(self.conflict.size * DISTANCE_FACTOR[0], self.conflict.size * DISTANCE_FACTOR[1])
|
||||||
|
|||||||
@ -1,21 +1,10 @@
|
|||||||
import typing
|
from game import db
|
||||||
import pdb
|
|
||||||
import dcs
|
|
||||||
|
|
||||||
from random import randint
|
|
||||||
|
|
||||||
import globals
|
|
||||||
|
|
||||||
from shop import db
|
|
||||||
from .conflictgen import *
|
from .conflictgen import *
|
||||||
from .naming import *
|
from .naming import *
|
||||||
|
|
||||||
from dcs.mission import *
|
from dcs.mission import *
|
||||||
from dcs.vehicles import *
|
|
||||||
from dcs.unitgroup import *
|
from dcs.unitgroup import *
|
||||||
from dcs.unittype import *
|
from dcs.unittype import *
|
||||||
from dcs.mapping import *
|
|
||||||
from dcs.point import *
|
|
||||||
from dcs.task import *
|
from dcs.task import *
|
||||||
|
|
||||||
SPREAD_DISTANCE_FACTOR = 1, 2
|
SPREAD_DISTANCE_FACTOR = 1, 2
|
||||||
|
|||||||
13
gen/armor.py
13
gen/armor.py
@ -1,20 +1,9 @@
|
|||||||
import typing
|
from game import db
|
||||||
import pdb
|
|
||||||
import dcs
|
|
||||||
|
|
||||||
from random import randint
|
|
||||||
|
|
||||||
import globals
|
|
||||||
|
|
||||||
from shop import db
|
|
||||||
from .conflictgen import *
|
from .conflictgen import *
|
||||||
from .naming import *
|
from .naming import *
|
||||||
|
|
||||||
from dcs.mission import *
|
from dcs.mission import *
|
||||||
from dcs.vehicles import *
|
|
||||||
from dcs.unitgroup import *
|
|
||||||
from dcs.unittype import *
|
from dcs.unittype import *
|
||||||
from dcs.mapping import *
|
|
||||||
from dcs.point import *
|
from dcs.point import *
|
||||||
from dcs.task import *
|
from dcs.task import *
|
||||||
from dcs.country import *
|
from dcs.country import *
|
||||||
|
|||||||
@ -1,20 +1,8 @@
|
|||||||
import typing
|
|
||||||
import pdb
|
|
||||||
import dcs
|
|
||||||
|
|
||||||
from random import randint
|
|
||||||
|
|
||||||
import globals
|
|
||||||
|
|
||||||
from .conflictgen import *
|
from .conflictgen import *
|
||||||
from .naming import *
|
from .naming import *
|
||||||
|
|
||||||
from dcs.mission import *
|
from dcs.mission import *
|
||||||
from dcs.vehicles import *
|
|
||||||
from dcs.unitgroup import *
|
from dcs.unitgroup import *
|
||||||
from dcs.unittype import *
|
|
||||||
from dcs.mapping import *
|
|
||||||
from dcs.point import *
|
|
||||||
from dcs.task import *
|
from dcs.task import *
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
import dcs
|
|
||||||
|
|
||||||
MISSION = dcs.mission.Mission()
|
|
||||||
US = MISSION.country("USA")
|
|
||||||
THEM = MISSION.country("Russia")
|
|
||||||
@ -1,11 +1,8 @@
|
|||||||
import typing
|
import typing
|
||||||
import math
|
import math
|
||||||
import random
|
|
||||||
import itertools
|
import itertools
|
||||||
|
|
||||||
import dcs
|
from game import db
|
||||||
|
|
||||||
from shop import db
|
|
||||||
from theater.controlpoint import ControlPoint
|
from theater.controlpoint import ControlPoint
|
||||||
|
|
||||||
from dcs.planes import *
|
from dcs.planes import *
|
||||||
@ -105,6 +102,10 @@ class Base:
|
|||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def filter_units(self, applicable_units: typing.Collection):
|
||||||
|
self.aircraft = {k: v for k, v in self.aircraft.items() if k in applicable_units}
|
||||||
|
self.armor = {k: v for k, v in self.aircraft.items() if k in applicable_units}
|
||||||
|
|
||||||
def commision_units(self, units: typing.Dict[typing.Any, int]):
|
def commision_units(self, units: typing.Dict[typing.Any, int]):
|
||||||
for value in units.values():
|
for value in units.values():
|
||||||
assert value > 0
|
assert value > 0
|
||||||
|
|||||||
@ -40,5 +40,5 @@ class ConflictTheater:
|
|||||||
for connected_point in [x for x in cp.connected_points if x.captured != from_player]:
|
for connected_point in [x for x in cp.connected_points if x.captured != from_player]:
|
||||||
yield (cp, connected_point)
|
yield (cp, connected_point)
|
||||||
|
|
||||||
def enemy_bases(self) -> typing.Collection[ControlPoint]:
|
def enemy_points(self) -> typing.Collection[ControlPoint]:
|
||||||
return [point for point in self.controlpoints if not point.captured]
|
return [point for point in self.controlpoints if not point.captured]
|
||||||
|
|||||||
@ -1,10 +1,3 @@
|
|||||||
import typing
|
|
||||||
import random
|
|
||||||
|
|
||||||
import dcs
|
|
||||||
|
|
||||||
from shop import db
|
|
||||||
from theater.controlpoint import *
|
|
||||||
from theater.base import *
|
from theater.base import *
|
||||||
from theater.conflicttheater import *
|
from theater.conflicttheater import *
|
||||||
|
|
||||||
@ -13,7 +6,7 @@ UNIT_AMOUNT_FACTOR = 1
|
|||||||
|
|
||||||
|
|
||||||
def generate_initial(theater: ConflictTheater, enemy: str):
|
def generate_initial(theater: ConflictTheater, enemy: str):
|
||||||
for cp in theater.enemy_bases():
|
for cp in theater.enemy_points():
|
||||||
if cp.captured:
|
if cp.captured:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,3 @@
|
|||||||
from shop import db
|
|
||||||
|
|
||||||
from tkinter import *
|
|
||||||
from ui.window import *
|
|
||||||
from ui.eventmenu import *
|
from ui.eventmenu import *
|
||||||
|
|
||||||
from game.game import *
|
from game.game import *
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
from tkinter import *
|
|
||||||
from ui.window import *
|
|
||||||
from ui.eventresultsmenu import *
|
from ui.eventresultsmenu import *
|
||||||
|
|
||||||
from shop import db
|
|
||||||
from game.game import *
|
from game.game import *
|
||||||
from game import event
|
from game import event, db
|
||||||
|
|
||||||
|
|
||||||
class EventMenu(Menu):
|
class EventMenu(Menu):
|
||||||
@ -55,7 +52,7 @@ class EventMenu(Menu):
|
|||||||
row += 1
|
row += 1
|
||||||
|
|
||||||
base = None # type: Base
|
base = None # type: Base
|
||||||
if self.event.attacker.name == self.game.player:
|
if self.event.attacker_name == self.game.player:
|
||||||
base = self.event.from_cp.base
|
base = self.event.from_cp.base
|
||||||
else:
|
else:
|
||||||
base = self.event.to_cp.base
|
base = self.event.to_cp.base
|
||||||
|
|||||||
@ -1,13 +1,7 @@
|
|||||||
import math
|
|
||||||
import itertools
|
|
||||||
|
|
||||||
from tkinter import *
|
|
||||||
from tkinter.ttk import *
|
from tkinter.ttk import *
|
||||||
from ui.window import *
|
from ui.window import *
|
||||||
|
|
||||||
from userdata.debriefing_parser import *
|
|
||||||
from game.game import *
|
from game.game import *
|
||||||
from game import event
|
|
||||||
|
|
||||||
|
|
||||||
class EventResultsMenu(Menu):
|
class EventResultsMenu(Menu):
|
||||||
@ -21,18 +15,22 @@ class EventResultsMenu(Menu):
|
|||||||
self.event = event
|
self.event = event
|
||||||
self.finished = False
|
self.finished = False
|
||||||
|
|
||||||
|
wait_for_debriefing(callback=self.process_debriefing)
|
||||||
|
|
||||||
def display(self):
|
def display(self):
|
||||||
self.window.clear_right_pane()
|
self.window.clear_right_pane()
|
||||||
|
|
||||||
if not self.finished:
|
if not self.finished:
|
||||||
Button(self.frame, text="no losses, succ", command=self.simulate_result(0, 1, True)).grid()
|
Button(self.frame, text="no losses, succ", command=self.simulate_result(0, 1, True)).grid()
|
||||||
Button(self.frame, text="no losses, fail", command=self.simulate_result(0, 1, False)).grid(column=1)
|
Button(self.frame, text="no losses, fail", command=self.simulate_result(0, 1, False)).grid(row=1, column=1)
|
||||||
|
|
||||||
Button(self.frame, text="half losses, succ", command=self.simulate_result(0.5, 0.5, True)).grid(row=1, )
|
Button(self.frame, text="half losses, succ", command=self.simulate_result(0.5, 0.5, True)).grid(row=2, )
|
||||||
Button(self.frame, text="half losses, fail", command=self.simulate_result(0.5, 0.5, False)).grid(row=1, column=1)
|
Button(self.frame, text="half losses, fail", command=self.simulate_result(0.5, 0.5, False)).grid(row=2, column=1)
|
||||||
|
|
||||||
Button(self.frame, text="full losses, succ", command=self.simulate_result(1, 0, True)).grid(row=2, )
|
Button(self.frame, text="full losses, succ", command=self.simulate_result(1, 0, True)).grid(row=3, )
|
||||||
Button(self.frame, text="full losses, fail", command=self.simulate_result(1, 0, False)).grid(row=2, column=1)
|
Button(self.frame, text="full losses, fail", command=self.simulate_result(1, 0, False)).grid(row=3, column=1)
|
||||||
|
|
||||||
|
Label(self.frame, text="Play the mission and save debriefing to {}".format(debriefing_directory_location())).grid(row=0, column=0)
|
||||||
else:
|
else:
|
||||||
row = 0
|
row = 0
|
||||||
if self.event.is_successfull(self.debriefing):
|
if self.event.is_successfull(self.debriefing):
|
||||||
@ -56,6 +54,15 @@ class EventResultsMenu(Menu):
|
|||||||
|
|
||||||
Button(self.frame, text="Okay", command=self.dismiss).grid(columnspan=1, row=row); row += 1
|
Button(self.frame, text="Okay", command=self.dismiss).grid(columnspan=1, row=row); row += 1
|
||||||
|
|
||||||
|
def process_debriefing(self, debriefing: Debriefing):
|
||||||
|
self.game.finish_event(event=self.event, debriefing=debriefing)
|
||||||
|
self.game.pass_turn()
|
||||||
|
|
||||||
|
self.finished = True
|
||||||
|
self.player_losses = debriefing.destroyed_units.get(self.game.player, {})
|
||||||
|
self.enemy_losses = debriefing.destroyed_units.get(self.game.enemy, {})
|
||||||
|
self.display()
|
||||||
|
|
||||||
def simulate_result(self, player_factor: float, enemy_factor: float, result: bool):
|
def simulate_result(self, player_factor: float, enemy_factor: float, result: bool):
|
||||||
def action():
|
def action():
|
||||||
debriefing = Debriefing()
|
debriefing = Debriefing()
|
||||||
|
|||||||
@ -1,12 +1,10 @@
|
|||||||
from tkinter import *
|
import pickle
|
||||||
from tkinter.ttk import *
|
|
||||||
|
|
||||||
from ui.window import *
|
|
||||||
from ui.eventmenu import *
|
|
||||||
from ui.basemenu import *
|
from ui.basemenu import *
|
||||||
from ui.overviewcanvas import *
|
from ui.overviewcanvas import *
|
||||||
|
|
||||||
from game.game import *
|
from game.game import *
|
||||||
|
from userdata import persistency
|
||||||
|
|
||||||
|
|
||||||
class MainMenu(Menu):
|
class MainMenu(Menu):
|
||||||
@ -22,9 +20,10 @@ class MainMenu(Menu):
|
|||||||
self.frame.grid_columnconfigure(0, weight=1)
|
self.frame.grid_columnconfigure(0, weight=1)
|
||||||
|
|
||||||
def display(self):
|
def display(self):
|
||||||
|
persistency.save_game(self.game)
|
||||||
|
|
||||||
self.window.clear_right_pane()
|
self.window.clear_right_pane()
|
||||||
self.upd.update()
|
self.upd.update()
|
||||||
|
|
||||||
row = 1
|
row = 1
|
||||||
|
|
||||||
def label(text):
|
def label(text):
|
||||||
|
|||||||
@ -79,7 +79,9 @@ class OverviewCanvas:
|
|||||||
extent=extent)
|
extent=extent)
|
||||||
self.canvas.tag_bind(cp_id, "<Button-1>", self.display(cp))
|
self.canvas.tag_bind(cp_id, "<Button-1>", self.display(cp))
|
||||||
self.create_cp_title((coords[0] + arc_size/2, coords[1] + arc_size/2), cp)
|
self.create_cp_title((coords[0] + arc_size/2, coords[1] + arc_size/2), cp)
|
||||||
self.canvas.create_text(coords[0], coords[1] - arc_size / 1.5, text="8/4/2", font=("Helvetica", 10))
|
|
||||||
|
units_title = "{}/{}/{}".format(cp.base.total_planes, cp.base.total_armor, cp.base.total_aa)
|
||||||
|
self.canvas.create_text(coords[0], coords[1] - arc_size / 1.5, text=units_title, font=("Helvetica", 10))
|
||||||
|
|
||||||
def display(self, cp: ControlPoint):
|
def display(self, cp: ControlPoint):
|
||||||
def action(_):
|
def action(_):
|
||||||
|
|||||||
@ -1,15 +0,0 @@
|
|||||||
import dcs
|
|
||||||
|
|
||||||
money = 2000
|
|
||||||
aircraft = []
|
|
||||||
armor = []
|
|
||||||
control_points = []
|
|
||||||
|
|
||||||
def add_aircraft(plane: dcs.planes.PlaneType):
|
|
||||||
aircraft.append(plane)
|
|
||||||
|
|
||||||
def add_armor(vehicle: dcs.vehicles.Armor):
|
|
||||||
armor.append(vehicle)
|
|
||||||
|
|
||||||
def add_control_point(cp):
|
|
||||||
control_points.append(cp)
|
|
||||||
52
userdata/debriefing.py
Normal file
52
userdata/debriefing.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import typing
|
||||||
|
|
||||||
|
import json
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
DEBRIEFING_LOG_EXTENSION = "log"
|
||||||
|
|
||||||
|
|
||||||
|
class Debriefing:
|
||||||
|
def __init__(self):
|
||||||
|
self.destroyed_units = {} # type: typing.Dict[str, typing.Dict[str, int]]
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parse(cls, path: str):
|
||||||
|
with open(path, "r") as f:
|
||||||
|
events = json.load(f)
|
||||||
|
|
||||||
|
return Debriefing()
|
||||||
|
|
||||||
|
|
||||||
|
def debriefing_directory_location() -> str:
|
||||||
|
return "build/debriefing"
|
||||||
|
|
||||||
|
|
||||||
|
def _logfiles_snapshot() -> typing.Dict[str, float]:
|
||||||
|
result = {}
|
||||||
|
for file in os.listdir(debriefing_directory_location()):
|
||||||
|
fullpath = os.path.join(debriefing_directory_location(), file)
|
||||||
|
result[file] = os.path.getmtime(fullpath)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def _poll_new_debriefing_log(snapshot: typing.Dict[str, float], callback: typing.Callable):
|
||||||
|
should_run = True
|
||||||
|
while should_run:
|
||||||
|
for file, timestamp in _logfiles_snapshot().items():
|
||||||
|
if file not in snapshot or timestamp != snapshot[file]:
|
||||||
|
callback(Debriefing.parse(os.path.join(debriefing_directory_location(), file)))
|
||||||
|
should_run = False
|
||||||
|
break
|
||||||
|
|
||||||
|
time.sleep(1)
|
||||||
|
|
||||||
|
|
||||||
|
def wait_for_debriefing(callback: typing.Callable):
|
||||||
|
threading.Thread(target=_poll_new_debriefing_log, args=(_logfiles_snapshot(), callback)).start()
|
||||||
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
import typing
|
|
||||||
import json
|
|
||||||
|
|
||||||
|
|
||||||
class Debriefing:
|
|
||||||
def __init__(self):
|
|
||||||
self.destroyed_units = {} # type: typing.Dict[str, typing.Dict[str, int]]
|
|
||||||
|
|
||||||
def parse(self, path: str):
|
|
||||||
with open(path, "r") as f:
|
|
||||||
events = json.load(f)
|
|
||||||
|
|
||||||
38
userdata/persistency.py
Normal file
38
userdata/persistency.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
import pickle
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
from game.game import Game
|
||||||
|
|
||||||
|
|
||||||
|
def _save_file() -> str:
|
||||||
|
return "build/save"
|
||||||
|
|
||||||
|
|
||||||
|
def _temporary_save_file() -> str:
|
||||||
|
return "build/save_tmp"
|
||||||
|
|
||||||
|
|
||||||
|
def _save_file_exists() -> bool:
|
||||||
|
return os.path.exists(_save_file())
|
||||||
|
|
||||||
|
|
||||||
|
def restore_game() -> Game:
|
||||||
|
if not _save_file_exists():
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(_save_file(), "rb") as f:
|
||||||
|
return pickle.load(f)
|
||||||
|
except:
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def save_game(game: Game) -> bool:
|
||||||
|
try:
|
||||||
|
with open(_temporary_save_file(), "wb") as f:
|
||||||
|
pickle.dump(game, f)
|
||||||
|
shutil.copy(_temporary_save_file(), _save_file())
|
||||||
|
return True
|
||||||
|
except:
|
||||||
|
return False
|
||||||
Loading…
x
Reference in New Issue
Block a user