Add cheat option to capture bases.

Capturing bases is sometimes really annoying because of the DCS unit
AI and our non-optimal ground victory heuristics. Add a cheat option
to allow the player to move on without the tedium.
This commit is contained in:
Dan Albert 2020-10-24 13:06:37 -07:00
parent dd2b61edf3
commit bfc602f22f
6 changed files with 76 additions and 21 deletions

View File

@ -195,29 +195,19 @@ class Event:
if cp.id == id: if cp.id == id:
if cp.captured and new_owner_coalition != coalition: if cp.captured and new_owner_coalition != coalition:
cp.captured = False for_player = False
info = Information(cp.name + " lost !", "The ennemy took control of " + cp.name + "\nShame on us !", self.game.turn) info = Information(cp.name + " lost !", "The ennemy took control of " + cp.name + "\nShame on us !", self.game.turn)
self.game.informations.append(info) self.game.informations.append(info)
pname = self.game.enemy_name
captured_cps.append(cp) captured_cps.append(cp)
elif not(cp.captured) and new_owner_coalition == coalition: elif not(cp.captured) and new_owner_coalition == coalition:
cp.captured = True for_player = True
info = Information(cp.name + " captured !", "We took control of " + cp.name + "! Great job !", self.game.turn) info = Information(cp.name + " captured !", "We took control of " + cp.name + "! Great job !", self.game.turn)
self.game.informations.append(info) self.game.informations.append(info)
pname = self.game.player_name
captured_cps.append(cp) captured_cps.append(cp)
else: else:
continue continue
cp.base.aircraft = {} cp.capture(self.game, for_player)
cp.base.armor = {}
airbase_def_id = 0
for g in cp.ground_objects:
g.groups = []
if g.airbase_group and pname != "":
generate_airbase_defense_group(airbase_def_id, g, pname, self.game, cp)
airbase_def_id = airbase_def_id + 1
for cp in captured_cps: for cp in captured_cps:
logging.info("Will run redeploy for " + cp.name) logging.info("Will run redeploy for " + cp.name)

View File

@ -237,10 +237,10 @@ class Game:
if not hasattr(self, "conditions"): if not hasattr(self, "conditions"):
self.conditions = self.generate_conditions() self.conditions = self.generate_conditions()
def pass_turn(self, no_action=False): def pass_turn(self, no_action: bool = False) -> None:
logging.info("Pass turn") logging.info("Pass turn")
self.informations.append(Information("End of turn #" + str(self.turn), "-" * 40, 0)) self.informations.append(Information("End of turn #" + str(self.turn), "-" * 40, 0))
self.turn = self.turn + 1 self.turn += 1
for event in self.events: for event in self.events:
if self.settings.version == "dev": if self.settings.version == "dev":
@ -261,6 +261,14 @@ class Game:
if not cp.is_carrier and not cp.is_lha: if not cp.is_carrier and not cp.is_lha:
cp.base.affect_strength(-PLAYER_BASE_STRENGTH_RECOVERY) cp.base.affect_strength(-PLAYER_BASE_STRENGTH_RECOVERY)
self.conditions = self.generate_conditions()
self.initialize_turn()
# Autosave progress
persistency.autosave(self)
def initialize_turn(self) -> None:
self.events = [] self.events = []
self._generate_events() self._generate_events()
@ -271,8 +279,6 @@ class Game:
for cp in self.theater.controlpoints: for cp in self.theater.controlpoints:
self.aircraft_inventory.set_from_control_point(cp) self.aircraft_inventory.set_from_control_point(cp)
self.conditions = self.generate_conditions()
# Plan flights & combat for next turn # Plan flights & combat for next turn
self.__culling_points = self.compute_conflicts_position() self.__culling_points = self.compute_conflicts_position()
self.ground_planners = {} self.ground_planners = {}
@ -286,9 +292,6 @@ class Game:
gplanner.plan_groundwar() gplanner.plan_groundwar()
self.ground_planners[cp.id] = gplanner self.ground_planners[cp.id] = gplanner
# Autosave progress
persistency.autosave(self)
def _enemy_reinforcement(self): def _enemy_reinforcement(self):
""" """
Compute and commision reinforcement for enemy bases Compute and commision reinforcement for enemy bases

View File

@ -1,6 +1,7 @@
from typing import Optional from typing import Optional
from PySide2.QtGui import QColor, QPainter from PySide2.QtGui import QColor, QPainter
from PySide2.QtWidgets import QAction, QMenu
import qt_ui.uiconstants as const import qt_ui.uiconstants as const
from qt_ui.models import GameModel from qt_ui.models import GameModel
@ -8,6 +9,7 @@ from qt_ui.windows.basemenu.QBaseMenu2 import QBaseMenu2
from theater import ControlPoint from theater import ControlPoint
from .QMapObject import QMapObject from .QMapObject import QMapObject
from ...displayoptions import DisplayOptions from ...displayoptions import DisplayOptions
from ...windows.GameUpdateSignal import GameUpdateSignal
class QMapControlPoint(QMapObject): class QMapControlPoint(QMapObject):
@ -20,6 +22,9 @@ class QMapControlPoint(QMapObject):
self.setZValue(1) self.setZValue(1)
self.setToolTip(self.control_point.name) self.setToolTip(self.control_point.name)
self.base_details_dialog: Optional[QBaseMenu2] = None self.base_details_dialog: Optional[QBaseMenu2] = None
self.capture_action = QAction(
f"CHEAT: Capture {self.control_point.name}")
self.capture_action.triggered.connect(self.cheat_capture)
def paint(self, painter, option, widget=None) -> None: def paint(self, painter, option, widget=None) -> None:
if DisplayOptions.control_points: if DisplayOptions.control_points:
@ -64,3 +69,24 @@ class QMapControlPoint(QMapObject):
self.game_model self.game_model
) )
self.base_details_dialog.show() self.base_details_dialog.show()
def add_context_menu_actions(self, menu: QMenu) -> None:
if self.control_point.is_fleet:
return
if self.control_point.captured:
return
for connected in self.control_point.connected_points:
if connected.captured:
break
else:
return
menu.addAction(self.capture_action)
def cheat_capture(self) -> None:
self.control_point.capture(self.game_model.game, for_player=True)
# Reinitialized ground planners and the like.
self.game_model.game.initialize_turn()
GameUpdateSignal.get_instance().updateGame(self.game_model.game)

View File

@ -37,6 +37,9 @@ class QMapObject(QGraphicsRectItem):
if event.button() == Qt.LeftButton: if event.button() == Qt.LeftButton:
self.on_click() self.on_click()
def add_context_menu_actions(self, menu: QMenu) -> None:
pass
def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent) -> None: def contextMenuEvent(self, event: QGraphicsSceneContextMenuEvent) -> None:
menu = QMenu("Menu", self.parent) menu = QMenu("Menu", self.parent)
@ -48,6 +51,8 @@ class QMapObject(QGraphicsRectItem):
new_package_action.triggered.connect(self.open_new_package_dialog) new_package_action.triggered.connect(self.open_new_package_dialog)
menu.addAction(new_package_action) menu.addAction(new_package_action)
self.add_context_menu_actions(menu)
menu.exec_(event.screenPos()) menu.exec_(event.screenPos())
@property @property

View File

@ -148,6 +148,9 @@ class Base:
elif self.strength <= 0: elif self.strength <= 0:
self.strength = BASE_MIN_STRENGTH self.strength = BASE_MIN_STRENGTH
def set_strength_to_minimum(self) -> None:
self.strength = BASE_MIN_STRENGTH
def scramble_count(self, multiplier: float, task: Task = None) -> int: def scramble_count(self, multiplier: float, task: Task = None) -> int:
if task: if task:
count = sum([v for k, v in self.aircraft.items() if db.unit_task(k) == task]) count = sum([v for k, v in self.aircraft.items() if db.unit_task(k) == task])

View File

@ -1,5 +1,7 @@
from __future__ import annotations
import re import re
from typing import Dict, List from typing import Dict, List, TYPE_CHECKING
from enum import Enum from enum import Enum
from dcs.mapping import Point from dcs.mapping import Point
@ -17,6 +19,9 @@ from .base import Base
from .missiontarget import MissionTarget from .missiontarget import MissionTarget
from .theatergroundobject import TheaterGroundObject from .theatergroundobject import TheaterGroundObject
if TYPE_CHECKING:
from game import Game
class ControlPointType(Enum): class ControlPointType(Enum):
AIRBASE = 0 # An airbase with slots for everything AIRBASE = 0 # An airbase with slots for everything
@ -207,3 +212,26 @@ class ControlPoint(MissionTarget):
def is_friendly(self, to_player: bool) -> bool: def is_friendly(self, to_player: bool) -> bool:
return self.captured == to_player return self.captured == to_player
def capture(self, game: Game, for_player: bool) -> None:
if for_player:
self.captured = True
faction_name = game.player_name
else:
self.captured = False
faction_name = game.enemy_name
self.base.set_strength_to_minimum()
self.base.aircraft = {}
self.base.armor = {}
# Handle cyclic dependency.
from .start_generator import generate_airbase_defense_group
airbase_def_id = 0
for ground_object in self.ground_objects:
ground_object.groups = []
if ground_object.airbase_group and faction_name != "":
generate_airbase_defense_group(airbase_def_id, ground_object,
faction_name, game, self)
airbase_def_id = airbase_def_id + 1