From 820820eb925403a4846ace8ce57800691a6af78e Mon Sep 17 00:00:00 2001 From: Vasyl Horbachenko Date: Mon, 16 Jul 2018 23:58:01 +0300 Subject: [PATCH] frontline attack ops --- __init__.py | 39 -------- game/db.py | 5 + game/event/__init__.py | 6 +- game/event/{capture.py => baseattack.py} | 34 +++---- game/event/frontlineattack.py | 76 ++++++++++++++++ game/event/frontlinecas.py | 91 ------------------- .../{groundattack.py => insurgentattack.py} | 20 ++-- game/game.py | 10 +- game/operation/{capture.py => baseattack.py} | 6 +- .../{frontlinecas.py => frontlineattack.py} | 6 +- .../{groundattack.py => insurgentattack.py} | 6 +- gen/armor.py | 23 +++-- gen/conflictgen.py | 11 ++- gen/visualgen.py | 5 +- resources/tools/miz_diff.py | 39 ++++++++ theater/base.py | 5 +- ui/eventmenu.py | 17 ++-- ui/overviewcanvas.py | 10 +- userdata/persistency.py | 2 +- 19 files changed, 205 insertions(+), 206 deletions(-) rename game/event/{capture.py => baseattack.py} (72%) create mode 100644 game/event/frontlineattack.py delete mode 100644 game/event/frontlinecas.py rename game/event/{groundattack.py => insurgentattack.py} (59%) rename game/operation/{capture.py => baseattack.py} (93%) rename game/operation/{frontlinecas.py => frontlineattack.py} (90%) rename game/operation/{groundattack.py => insurgentattack.py} (87%) create mode 100644 resources/tools/miz_diff.py diff --git a/__init__.py b/__init__.py index 8a5d950f..92d39a9c 100755 --- a/__init__.py +++ b/__init__.py @@ -17,45 +17,6 @@ from theater import start_generator from userdata import persistency -""" -from dcs.lua.parse import * -a = loads(open("build/mission", "r").read()) -b = loads(open("build/mission_workin.lua", "r").read()) - - -def get(a, k): - b = a - for x in k.strip().split(" "): - if isinstance(a, dict): - y = a - a = a.get(x, None) - if a is None: - try: - a = y.get(int(x), None) - except: - pass - else: - break - if a is None: - pass - return a - -def cycle(kk, ref, v): - if isinstance(v, dict): - for k, v in v.items(): - cycle(kk + " " + str(k), ref, v) - elif isinstance(v, list): - for i, v in enumerate(v): - cycle(kk + " " + str(i), ref, v) - else: - if get(ref, kk) != v: - print(kk, v) - print(get(ref, kk)) - -cycle("", a, b) -sys.exit(0) -""" - persistency.setup(sys.argv[1]) dcs.planes.FlyingType.payload_dirs.append(os.path.join(os.path.dirname(os.path.realpath(__file__)), "resources\\payloads")) diff --git a/game/db.py b/game/db.py index 2a2e44c5..31c666f7 100644 --- a/game/db.py +++ b/game/db.py @@ -448,6 +448,11 @@ def unitdict_split(unit_dict: UnitsDict, count: int): if len(buffer_dict): yield buffer_dict + +def unitdict_restrict_count(unit_dict: UnitsDict, total_count: int) -> UnitsDict: + return list(unitdict_split(unit_dict, total_count))[0] + + def _validate_db(): # check unit by task uniquity total_set = set() diff --git a/game/event/__init__.py b/game/event/__init__.py index f43dc91a..4f9eee7c 100644 --- a/game/event/__init__.py +++ b/game/event/__init__.py @@ -1,8 +1,8 @@ from .event import * -from .frontlinecas import * +from .frontlineattack import * from .intercept import * -from .capture import * +from .baseattack import * from .navalintercept import * from .antiaastrike import * -from .groundattack import * +from .insurgentattack import * from .infantrytransport import * diff --git a/game/event/capture.py b/game/event/baseattack.py similarity index 72% rename from game/event/capture.py rename to game/event/baseattack.py index 304895c4..b7ecbf64 100644 --- a/game/event/capture.py +++ b/game/event/baseattack.py @@ -4,13 +4,13 @@ import random from dcs.task import * from game import db -from game.operation.capture import CaptureOperation +from game.operation.baseattack import BaseAttackOperation from userdata.debriefing import Debriefing from .event import Event -class CaptureEvent(Event): +class BaseAttackEvent(Event): silent = True BONUS_BASE = 15 STRENGTH_RECOVERY = 0.55 @@ -28,7 +28,7 @@ class CaptureEvent(Event): return not attackers_success def commit(self, debriefing: Debriefing): - super(CaptureEvent, self).commit(debriefing) + super(BaseAttackEvent, self).commit(debriefing) if self.is_successfull(debriefing): if self.from_cp.captured: self.to_cp.captured = True @@ -49,13 +49,13 @@ class CaptureEvent(Event): escort = self.from_cp.base.scramble_sweep(self.game.settings.multiplier) attackers = self.from_cp.base.armor - op = CaptureOperation(game=self.game, - attacker_name=self.attacker_name, - defender_name=self.defender_name, - attacker_clients={}, - defender_clients=clients, - from_cp=self.from_cp, - to_cp=self.to_cp) + op = BaseAttackOperation(game=self.game, + attacker_name=self.attacker_name, + defender_name=self.defender_name, + attacker_clients={}, + defender_clients=clients, + from_cp=self.from_cp, + to_cp=self.to_cp) op.setup(cas=cas, escort=escort, @@ -67,13 +67,13 @@ class CaptureEvent(Event): self.operation = op def player_attacking(self, cas: db.PlaneDict, escort: db.PlaneDict, armor: db.ArmorDict, clients: db.PlaneDict): - op = CaptureOperation(game=self.game, - attacker_name=self.attacker_name, - defender_name=self.defender_name, - attacker_clients=clients, - defender_clients={}, - from_cp=self.from_cp, - to_cp=self.to_cp) + op = BaseAttackOperation(game=self.game, + attacker_name=self.attacker_name, + defender_name=self.defender_name, + attacker_clients=clients, + defender_clients={}, + from_cp=self.from_cp, + to_cp=self.to_cp) defenders = self.to_cp.base.scramble_sweep(self.game.settings.multiplier) defenders.update(self.to_cp.base.scramble_cas(self.game.settings.multiplier)) diff --git a/game/event/frontlineattack.py b/game/event/frontlineattack.py new file mode 100644 index 00000000..b35f6d4e --- /dev/null +++ b/game/event/frontlineattack.py @@ -0,0 +1,76 @@ +import math +import random + +from dcs.task import * +from dcs.vehicles import AirDefence + +from game import * +from game.event import * +from game.operation.frontlineattack import FrontlineAttackOperation +from userdata.debriefing import Debriefing + + +class FrontlineAttackEvent(Event): + TARGET_VARIETY = 2 + TARGET_AMOUNT_FACTOR = 0.5 + ATTACKER_AMOUNT_FACTOR = 0.4 + ATTACKER_DEFENDER_FACTOR = 0.7 + STRENGTH_INFLUENCE = 0.3 + SUCCESS_MIN_TARGETS = 3 + + defenders = None # type: db.ArmorDict + + @property + def threat_description(self): + return "{} vehicles".format(self.to_cp.base.assemble_count()) + + def __str__(self): + return "Frontline attack from {} at {}".format(self.from_cp, self.to_cp) + + def is_successfull(self, debriefing: Debriefing): + total_targets = sum(self.defenders.values()) + destroyed_targets = 0 + for unit, count in debriefing.destroyed_units[self.defender_name].items(): + if unit in self.defenders: + destroyed_targets += count + + if self.from_cp.captured: + return float(destroyed_targets) >= min(self.SUCCESS_MIN_TARGETS, total_targets) + else: + return float(destroyed_targets) < min(self.SUCCESS_MIN_TARGETS, total_targets) + + def commit(self, debriefing: Debriefing): + super(FrontlineAttackEvent, self).commit(debriefing) + + if self.from_cp.captured: + if self.is_successfull(debriefing): + self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE) + else: + self.to_cp.base.affect_strength(+self.STRENGTH_INFLUENCE) + else: + if self.is_successfull(debriefing): + self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE) + else: + self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE) + + def skip(self): + if self.to_cp.captured: + self.to_cp.base.affect_strength(-0.1) + + def player_attacking(self, armor: db.ArmorDict, strikegroup: db.PlaneDict, clients: db.PlaneDict): + self.defenders = self.to_cp.base.assemble_cap() + + op = FrontlineAttackOperation(game=self.game, + attacker_name=self.attacker_name, + defender_name=self.defender_name, + attacker_clients=clients, + defender_clients={}, + from_cp=self.from_cp, + to_cp=self.to_cp) + + op.setup(target=self.defenders, + attackers=db.unitdict_restrict_count(armor, sum(self.defenders.values())), + strikegroup=strikegroup) + + self.operation = op + diff --git a/game/event/frontlinecas.py b/game/event/frontlinecas.py deleted file mode 100644 index 07c3e610..00000000 --- a/game/event/frontlinecas.py +++ /dev/null @@ -1,91 +0,0 @@ -import math -import random - -from dcs.task import * -from dcs.vehicles import AirDefence - -from game import * -from game.event import * -from game.operation.frontlinecas import FrontlineCASOperation -from userdata.debriefing import Debriefing - - -class FrontlineCASEvent(Event): - TARGET_VARIETY = 2 - TARGET_AMOUNT_FACTOR = 0.5 - ATTACKER_AMOUNT_FACTOR = 0.4 - STRENGTH_INFLUENCE = 0.3 - SUCCESS_MIN_TARGETS = 3 - - targets = None # type: db.ArmorDict - - @property - def threat_description(self): - if not self.game.is_player_attack(self): - return "{} aicraft".format(self.from_cp.base.scramble_count(self.game.settings.multiplier, CAS)) - else: - return super(FrontlineCASEvent, self).threat_description - - def __str__(self): - return "Frontline CAS from {} at {}".format(self.from_cp, self.to_cp) - - def is_successfull(self, debriefing: Debriefing): - total_targets = sum(self.targets.values()) - destroyed_targets = 0 - for unit, count in debriefing.destroyed_units[self.defender_name].items(): - if unit in self.targets: - destroyed_targets += count - - if self.from_cp.captured: - return float(destroyed_targets) >= min(self.SUCCESS_MIN_TARGETS, total_targets) - else: - return float(destroyed_targets) < min(self.SUCCESS_MIN_TARGETS, total_targets) - - def commit(self, debriefing: Debriefing): - super(FrontlineCASEvent, self).commit(debriefing) - - if self.from_cp.captured: - if self.is_successfull(debriefing): - self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE) - else: - self.to_cp.base.affect_strength(+self.STRENGTH_INFLUENCE) - else: - if self.is_successfull(debriefing): - self.from_cp.base.affect_strength(-self.STRENGTH_INFLUENCE) - else: - self.to_cp.base.affect_strength(-self.STRENGTH_INFLUENCE) - - def skip(self): - if self.to_cp.captured: - self.to_cp.base.affect_strength(-0.1) - - def player_attacking(self, strikegroup: db.PlaneDict, clients: db.PlaneDict): - suitable_armor_targets = db.find_unittype(PinpointStrike, self.defender_name) - random.shuffle(suitable_armor_targets) - - target_types = suitable_armor_targets[:self.TARGET_VARIETY] - typecount = max(math.floor(self.to_cp.base.assemble_count() * self.TARGET_AMOUNT_FACTOR), 1) - self.targets = {unittype: typecount for unittype in target_types} - - defense_aa_unit = random.choice(self.game.commision_unit_types(self.to_cp, AirDefence)) - self.targets[defense_aa_unit] = 1 - - suitable_armor_attackers = db.find_unittype(PinpointStrike, self.attacker_name) - random.shuffle(suitable_armor_attackers) - attacker_types = suitable_armor_attackers[:self.TARGET_VARIETY] - typecount = max(math.floor(self.from_cp.base.assemble_count() * self.ATTACKER_AMOUNT_FACTOR), 1) - attackers = {unittype: typecount for unittype in attacker_types} - - op = FrontlineCASOperation(game=self.game, - attacker_name=self.attacker_name, - defender_name=self.defender_name, - attacker_clients=clients, - defender_clients={}, - from_cp=self.from_cp, - to_cp=self.to_cp) - op.setup(target=self.targets, - attackers=attackers, - strikegroup=strikegroup) - - self.operation = op - diff --git a/game/event/groundattack.py b/game/event/insurgentattack.py similarity index 59% rename from game/event/groundattack.py rename to game/event/insurgentattack.py index 9b32523f..dbc068f7 100644 --- a/game/event/groundattack.py +++ b/game/event/insurgentattack.py @@ -5,11 +5,11 @@ from dcs.task import * from game import * from game.event import * -from game.event.frontlinecas import FrontlineCASEvent -from game.operation.groundattack import GroundAttackOperation +from game.event.frontlineattack import FrontlineAttackEvent +from game.operation.insurgentattack import InsurgentAttackOperation -class GroundAttackEvent(FrontlineCASEvent): +class InsurgentAttackEvent(FrontlineAttackEvent): def __str__(self): return "Destroy insurgents at {}".format(self.to_cp) @@ -24,13 +24,13 @@ class GroundAttackEvent(FrontlineCASEvent): typecount = max(math.floor(self.difficulty * self.TARGET_AMOUNT_FACTOR), 1) self.targets = {unittype: typecount for unittype in unittypes} - op = GroundAttackOperation(game=self.game, - attacker_name=self.attacker_name, - defender_name=self.defender_name, - attacker_clients={}, - defender_clients=clients, - from_cp=self.from_cp, - to_cp=self.to_cp) + op = InsurgentAttackOperation(game=self.game, + attacker_name=self.attacker_name, + defender_name=self.defender_name, + attacker_clients={}, + defender_clients=clients, + from_cp=self.from_cp, + to_cp=self.to_cp) op.setup(target=self.targets, strikegroup=strikegroup) diff --git a/game/game.py b/game/game.py index 1964b4e4..7256718e 100644 --- a/game/game.py +++ b/game/game.py @@ -39,17 +39,17 @@ For the enemy events, only 1 event of each type could be generated for a turn. Events: * CaptureEvent - capture base * InterceptEvent - air intercept -* FrontlineCASEvent - frontline CAS +* FrontlineAttack - frontline attack * GroundAttackEvent - destroy insurgents * NavalInterceptEvent - naval intercept * AntiAAStrikeEvent - anti-AA strike * InfantryTransportEvent - helicopter infantry transport """ EVENT_PROBABILITIES = { - CaptureEvent: [100, 10], + BaseAttackEvent: [100, 10], InterceptEvent: [25, 10], - FrontlineCASEvent: [250, 0], - GroundAttackEvent: [0, 10], + FrontlineAttackEvent: [100, 0], + InsurgentAttackEvent: [0, 10], NavalInterceptEvent: [25, 10], AntiAAStrikeEvent: [25, 10], InfantryTransportEvent: [25, 0], @@ -130,7 +130,7 @@ class Game: if event_class == NavalInterceptEvent: if player_cp.radials == LAND: continue - elif event_class == CaptureEvent: + elif event_class == BaseAttackEvent: if enemy_cap_generated: continue if enemy_cp.base.total_armor == 0: diff --git a/game/operation/capture.py b/game/operation/baseattack.py similarity index 93% rename from game/operation/capture.py rename to game/operation/baseattack.py index 851f9488..dee129fc 100644 --- a/game/operation/capture.py +++ b/game/operation/baseattack.py @@ -12,7 +12,7 @@ from gen.visualgen import * from .operation import Operation -class CaptureOperation(Operation): +class BaseAttackOperation(Operation): cas = None # type: db.PlaneDict escort = None # type: db.PlaneDict intercept = None # type: db.PlaneDict @@ -37,7 +37,7 @@ class CaptureOperation(Operation): self.aa = aa def prepare(self, terrain: dcs.terrain.Terrain, is_quick: bool): - super(CaptureOperation, self).prepare(terrain, is_quick) + super(BaseAttackOperation, self).prepare(terrain, is_quick) self.defenders_starting_position = None if self.game.player == self.defender_name: @@ -63,5 +63,5 @@ class CaptureOperation(Operation): self.airgen.generate_strikegroup_escort(self.escort, clients=self.attacker_clients, at=self.attackers_starting_position) self.visualgen.generate_target_smokes(self.to_cp) - super(CaptureOperation, self).generate() + super(BaseAttackOperation, self).generate() diff --git a/game/operation/frontlinecas.py b/game/operation/frontlineattack.py similarity index 90% rename from game/operation/frontlinecas.py rename to game/operation/frontlineattack.py index 3f2556b4..b89d9a69 100644 --- a/game/operation/frontlinecas.py +++ b/game/operation/frontlineattack.py @@ -18,7 +18,7 @@ from .operation import Operation MAX_DISTANCE_BETWEEN_GROUPS = 12000 -class FrontlineCASOperation(Operation): +class FrontlineAttackOperation(Operation): attackers = None # type: db.ArmorDict strikegroup = None # type: db.PlaneDict target = None # type: db.ArmorDict @@ -32,7 +32,7 @@ class FrontlineCASOperation(Operation): self.attackers = attackers def prepare(self, terrain: Terrain, is_quick: bool): - super(FrontlineCASOperation, self).prepare(terrain, is_quick) + super(FrontlineAttackOperation, self).prepare(terrain, is_quick) if self.defender_name == self.game.player: self.attackers_starting_position = None self.defenders_starting_position = None @@ -51,4 +51,4 @@ class FrontlineCASOperation(Operation): def generate(self): self.armorgen.generate_vec(self.attackers, self.target) self.airgen.generate_cas_strikegroup(self.strikegroup, clients=self.attacker_clients, at=self.attackers_starting_position) - super(FrontlineCASOperation, self).generate() + super(FrontlineAttackOperation, self).generate() diff --git a/game/operation/groundattack.py b/game/operation/insurgentattack.py similarity index 87% rename from game/operation/groundattack.py rename to game/operation/insurgentattack.py index 7b12ad04..92091002 100644 --- a/game/operation/groundattack.py +++ b/game/operation/insurgentattack.py @@ -13,7 +13,7 @@ from gen.conflictgen import Conflict from .operation import Operation -class GroundAttackOperation(Operation): +class InsurgentAttackOperation(Operation): strikegroup = None # type: db.PlaneDict target = None # type: db.ArmorDict @@ -24,7 +24,7 @@ class GroundAttackOperation(Operation): self.target = target def prepare(self, terrain: Terrain, is_quick: bool): - super(GroundAttackOperation, self).prepare(terrain, is_quick) + super(InsurgentAttackOperation, self).prepare(terrain, is_quick) conflict = Conflict.ground_attack_conflict( attacker=self.mission.country(self.attacker_name), @@ -41,4 +41,4 @@ class GroundAttackOperation(Operation): self.airgen.generate_defense(self.strikegroup, self.defender_clients, self.defenders_starting_position) self.armorgen.generate(self.target, {}) - super(GroundAttackOperation, self).generate() + super(InsurgentAttackOperation, self).generate() diff --git a/gen/armor.py b/gen/armor.py index 80895b04..c6bdb4c1 100644 --- a/gen/armor.py +++ b/gen/armor.py @@ -1,3 +1,4 @@ +from random import randint from itertools import zip_longest from game import db @@ -13,6 +14,10 @@ from dcs.country import * SPREAD_DISTANCE_FACTOR = 0.1, 0.3 SPREAD_DISTANCE_SIZE_FACTOR = 0.1 +FRONTLINE_CAS_FIGHTS_COUNT = 4, 8 +FRONTLINE_CAS_GROUP_MIN = 1, 2 +FRONTLINE_CAS_PADDING = 12000 + class ArmorConflictGenerator: def __init__(self, mission: Mission, conflict: Conflict): @@ -50,7 +55,7 @@ class ArmorConflictGenerator: side=self.conflict.attackers_side, unit=type, count=count, - at=position.point_from_heading(self.conflict.heading - 90, 600), + at=position.point_from_heading(self.conflict.heading - 90, 5000), to=position) if defenders: @@ -59,7 +64,7 @@ class ArmorConflictGenerator: side=self.conflict.defenders_side, unit=type, count=count, - at=position.point_from_heading(self.conflict.heading + 90, 600), + at=position.point_from_heading(self.conflict.heading + 90, 1000), to=position) def generate(self, attackers: db.ArmorDict, defenders: db.ArmorDict): @@ -78,16 +83,16 @@ class ArmorConflictGenerator: at=self.conflict.ground_defenders_location) def generate_vec(self, attackers: db.ArmorDict, defenders: db.ArmorDict): - defender_groups = list(db.unitdict_split(defenders, 6)) - distance_between_groups = min(self.conflict.distance / len(defender_groups), 12000) - total_distance = distance_between_groups * len(defender_groups) + fights_count = randint(*FRONTLINE_CAS_FIGHTS_COUNT) + single_fight_defenders_count = min(int(sum(defenders.values()) / fights_count), randint(*FRONTLINE_CAS_GROUP_MIN)) + defender_groups = list(db.unitdict_split(defenders, single_fight_defenders_count)) - attacker_groups = list(db.unitdict_split(attackers, - int(sum(attackers.values()) / len(defender_groups)))) + single_fight_attackers_count = min(int(sum(attackers.values()) / len(defender_groups)), randint(*FRONTLINE_CAS_GROUP_MIN)) + attacker_groups = list(db.unitdict_split(attackers, single_fight_attackers_count)) - position = self.conflict.center.point_from_heading(self.conflict.opposite_heading, total_distance / 2) for attacker_group_dict, target_group_dict in zip_longest(attacker_groups, defender_groups): - position = position.point_from_heading(self.conflict.heading, distance_between_groups) + position = self.conflict.position.point_from_heading(self.conflict.heading, + random.randint(FRONTLINE_CAS_PADDING, int(self.conflict.distance - FRONTLINE_CAS_PADDING))) self._generate_fight_at(attacker_group_dict, target_group_dict, position) def generate_passengers(self, count: int): diff --git a/gen/conflictgen.py b/gen/conflictgen.py index 299e6e14..3a60e0e8 100644 --- a/gen/conflictgen.py +++ b/gen/conflictgen.py @@ -38,8 +38,9 @@ NAVAL_INTERCEPT_DISTANCE_FACTOR = 1 NAVAL_INTERCEPT_DISTANCE_MAX = 40000 NAVAL_INTERCEPT_STEP = 5000 -FRONT_SMOKE_MIN_DISTANCE = 5000 -FRONT_SMOKE_DISTANCE_FACTOR = 0.5 +FRONTLINE_LENGTH = 80000 +FRONTLINE_MIN_CP_DISTANCE = 5000 +FRONTLINE_DISTANCE_STRENGTH_FACTOR = 0.7 def _opposite_heading(h): @@ -127,7 +128,7 @@ class Conflict: @classmethod def frontline_position(cls, from_cp: ControlPoint, to_cp: ControlPoint) -> typing.Tuple[Point, int]: - distance = max(from_cp.position.distance_to_point(to_cp.position) * FRONT_SMOKE_DISTANCE_FACTOR * to_cp.base.strength, FRONT_SMOKE_MIN_DISTANCE) + distance = max(from_cp.position.distance_to_point(to_cp.position) * 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 @@ -136,7 +137,7 @@ class Conflict: center_position, heading = cls.frontline_position(from_cp, to_cp) left_position = center_position - for offset in range(0, 80000, 1000): + for offset in range(0, int(FRONTLINE_LENGTH / 2), 1000): pos = center_position.point_from_heading(_heading_sum(heading, -90), offset) if not theater.is_on_land(pos): break @@ -144,7 +145,7 @@ class Conflict: left_position = pos right_position = center_position - for offset in range(0, 80000, 1000): + for offset in range(0, int(FRONTLINE_LENGTH / 2), 1000): pos = center_position.point_from_heading(_heading_sum(heading, 90), offset) if not theater.is_on_land(pos): break diff --git a/gen/visualgen.py b/gen/visualgen.py index a59c9986..175924e6 100644 --- a/gen/visualgen.py +++ b/gen/visualgen.py @@ -62,7 +62,6 @@ def __monkey_static_dict(self: Static): __original_static_dict = Static.dict Static.dict = __monkey_static_dict -FRONT_SMOKE_LENGTH = 80000 FRONT_SMOKE_SPACING = 800 FRONT_SMOKE_RANDOM_SPREAD = 4000 FRONT_SMOKE_TYPE_CHANCES = { @@ -100,9 +99,9 @@ class VisualGenerator: def _generate_frontline_smokes(self): for from_cp, to_cp in self.game.theater.conflicts(): point, heading = Conflict.frontline_position(from_cp, to_cp) - plane_start = point.point_from_heading(turn_heading(heading, 90), FRONT_SMOKE_LENGTH / 2) + plane_start = point.point_from_heading(turn_heading(heading, 90), FRONTLINE_LENGTH / 2) - for offset in range(0, FRONT_SMOKE_LENGTH, FRONT_SMOKE_SPACING): + for offset in range(0, FRONTLINE_LENGTH, FRONT_SMOKE_SPACING): position = plane_start.point_from_heading(turn_heading(heading, - 90), offset) for k, v in FRONT_SMOKE_TYPE_CHANCES.items(): diff --git a/resources/tools/miz_diff.py b/resources/tools/miz_diff.py new file mode 100644 index 00000000..500e6276 --- /dev/null +++ b/resources/tools/miz_diff.py @@ -0,0 +1,39 @@ +from dcs.lua.parse import * + + +a = loads(open("build/mission", "r").read()) +b = loads(open("build/mission_workin.lua", "r").read()) + + +def get(a, k): + b = a + for x in k.strip().split(" "): + if isinstance(a, dict): + y = a + a = a.get(x, None) + if a is None: + try: + a = y.get(int(x), None) + except: + pass + else: + break + if a is None: + pass + return a + + +def cycle(kk, ref, v): + if isinstance(v, dict): + for k, v in v.items(): + cycle(kk + " " + str(k), ref, v) + elif isinstance(v, list): + for i, v in enumerate(v): + cycle(kk + " " + str(i), ref, v) + else: + if get(ref, kk) != v: + print(kk, v) + print(get(ref, kk)) + + +cycle("", a, b) diff --git a/theater/base.py b/theater/base.py index eeed269d..ff5d815f 100644 --- a/theater/base.py +++ b/theater/base.py @@ -150,7 +150,7 @@ class Base: return min(min(max(count, PLANES_SCRAMBLE_MIN_BASE), int(PLANES_SCRAMBLE_MAX_BASE * multiplier)), count) def assemble_count(self): - return int(self.total_armor * min(self.strength + 0.5, 1)) + return int(self.total_armor * 0.5) def assemble_aa_count(self) -> int: if self.strength > STRENGTH_AA_ASSEMBLE_MIN: @@ -171,7 +171,8 @@ class Base: return self._find_best_armor(PinpointStrike, self.assemble_count()) def assemble_defense(self) -> typing.Dict[Armor, int]: - return self._find_best_armor(PinpointStrike, self.assemble_count()) + count = int(self.total_armor * min(self.strength + 0.5, 1)) + return self._find_best_armor(PinpointStrike, count) def assemble_aa(self, count=None) -> typing.Dict[AirDefence, int]: return self._find_best_unit(self.aa, AirDefence, count and min(count, self.total_aa) or self.assemble_aa_count()) diff --git a/ui/eventmenu.py b/ui/eventmenu.py index e1b2b81a..e4081975 100644 --- a/ui/eventmenu.py +++ b/ui/eventmenu.py @@ -172,8 +172,8 @@ class EventMenu(Menu): if amount > 0: scrambled_armor[unit_type] = amount - if type(self.event) is CaptureEvent: - e = self.event # type: CaptureEvent + if type(self.event) is BaseAttackEvent: + e = self.event # type: BaseAttackEvent if self.game.is_player_attack(self.event): e.player_attacking(cas=scrambled_cas, escort=scrambled_sweep, @@ -190,12 +190,9 @@ class EventMenu(Menu): else: e.player_defending(escort=scrambled_aircraft, clients=scrambled_clients) - elif type(self.event) is FrontlineCASEvent: - e = self.event # type: FrontlineCASEvent - if self.game.is_player_attack(self.event): - e.player_attacking(strikegroup=scrambled_aircraft, clients=scrambled_clients) - else: - e.player_defending(interceptors=scrambled_aircraft, clients=scrambled_clients) + elif type(self.event) is FrontlineAttackEvent: + e = self.event # type: FrontlineAttackEvent + e.player_attacking(armor=scrambled_armor, strikegroup=scrambled_aircraft, clients=scrambled_clients) elif type(self.event) is NavalInterceptEvent: e = self.event # type: NavalInterceptEvent @@ -209,8 +206,8 @@ class EventMenu(Menu): e.player_attacking(strikegroup=scrambled_aircraft, clients=scrambled_clients) else: e.player_defending(interceptors=scrambled_aircraft, clients=scrambled_clients) - elif type(self.event) is GroundAttackEvent: - e = self.event # type: GroundAttackEvent + elif type(self.event) is InsurgentAttackEvent: + e = self.event # type: InsurgentAttackEvent if self.game.is_player_attack(self.event): assert False else: diff --git a/ui/overviewcanvas.py b/ui/overviewcanvas.py index 7e0bd205..9fb58473 100644 --- a/ui/overviewcanvas.py +++ b/ui/overviewcanvas.py @@ -6,6 +6,7 @@ from tkinter.ttk import * from ui.window import * from game.game import * +from gen.conflictgen import Conflict from theater.conflicttheater import * @@ -44,7 +45,7 @@ class OverviewCanvas: def create_cp_title(self, coords, cp: ControlPoint): title = cp.name - font = ("Helvetica", 13) + font = ("Helvetica", 10) id = self.canvas.create_text(coords[0]+1, coords[1]+1, text=title, fill='white', font=font) self.canvas.tag_bind(id, "", self.display(cp)) @@ -74,9 +75,14 @@ class OverviewCanvas: self.canvas.create_line((coords[0], coords[1], connected_coords[0], connected_coords[1]), width=2, fill=color) + if cp.captured and not connected_cp.captured and Conflict.has_frontline_between(cp, connected_cp): + frontline_pos, heading, distance = Conflict.frontline_vector(cp, connected_cp, self.game.theater) + start_coords, end_coords = self.transform_point(frontline_pos), self.transform_point(frontline_pos.point_from_heading(heading, distance)) + self.canvas.create_line((*start_coords, *end_coords), width=2, fill=color) + for cp in self.game.theater.controlpoints: coords = self.transform_point(cp.position) - arc_size = 22 * math.pow(cp.importance, 1) + arc_size = 16 * math.pow(cp.importance, 1) extent = max(cp.base.strength * 180, 10) start = (180 - extent) / 2 diff --git a/userdata/persistency.py b/userdata/persistency.py index 3d40139c..f4feb69d 100644 --- a/userdata/persistency.py +++ b/userdata/persistency.py @@ -19,7 +19,7 @@ def base_path() -> str: if os.path.exists(openbeta_path): return openbeta_path else: - return os.path.join(_user_folder, "Saved Games" , "DCS") + return os.path.join(_user_folder, "Saved Games", "DCS") def _save_file() -> str: