Compare commits

..

5 Commits

Author SHA1 Message Date
RndName
40b147148b Open all files with utf-8 encoding
- will not be used for binary read/writes (rb,wb)!
- prevents a bug where units with special characters in the unit name can not be tracked anymore as there will be a name mismatch due to wrong encoding

(cherry-picked from b5b0d82)
2021-08-14 13:29:50 +02:00
RndName
2f56bae3e5 Enable sell button according to available aircraft
also added a tooltip which gives the user the hint that maybe the aircraft is assigned to mission and therefore the button is disabled

(cherry picked from adeebbc)
2021-08-13 00:01:51 +02:00
RndName
6febf546a8 Fix selling of units not visible
allow pending_deliveries to become negative again but still delete the delivery when the amount of a specific unit_type comes to exactly 0 to prevent emtpy group sizes

(cherry picked from ee8e8d4)
2021-08-13 00:01:04 +02:00
RndName
7754e5fd4d EWR heading towards conflict
(cherry picked from commit bc5ffde)
2021-08-11 21:20:02 +02:00
Dan Albert
81058d9e25 Bump version to 4.1.2. 2021-08-10 17:43:53 -07:00
13 changed files with 79 additions and 31 deletions

View File

@@ -1,3 +1,17 @@
# 4.1.2
Saves from 4.1.1 are compatible with 4.1.2.
## Features/Improvements
* **[Mission Generation]** EWRs are now also headed towards the center of the conflict
* **[UI]** Sell Button for aircraft will be disabled if there are no units available to be sold or all are already assigned to a mission
## Fixes
* **[UI]** Selling of Units is now visible again in the UI dialog and shows the correct amount of sold units
* **[Mission Generation]** Mission results and other files will now be opened with enforced utf-8 encoding to prevent an issue where destroyed ground units were untracked because of special characters in their names.
# 4.1.1
Saves from 4.1.0 are compatible with 4.1.1.

View File

@@ -288,7 +288,7 @@ class AircraftType(UnitType[Type[FlyingType]]):
logging.warning(f"No data for {aircraft.id}; it will not be available")
return
with data_path.open() as data_file:
with data_path.open(encoding="utf-8") as data_file:
data = yaml.safe_load(data_file)
try:

View File

@@ -67,7 +67,7 @@ class GroundUnitType(UnitType[Type[VehicleType]]):
logging.warning(f"No data for {vehicle.id}; it will not be available")
return
with data_path.open() as data_file:
with data_path.open(encoding="utf-8") as data_file:
data = yaml.safe_load(data_file)
try:

View File

@@ -389,7 +389,7 @@ class PollDebriefingFileThread(threading.Thread):
os.path.isfile("state.json")
and os.path.getmtime("state.json") > last_modified
):
with open("state.json", "r") as json_file:
with open("state.json", "r", encoding="utf-8") as json_file:
json_data = json.load(json_file)
debriefing = Debriefing(json_data, self.game, self.unit_map)
self.callback(debriefing)

View File

@@ -63,7 +63,7 @@ class Operation:
@classmethod
def prepare(cls, game: Game) -> None:
with open("resources/default_options.lua", "r") as f:
with open("resources/default_options.lua", "r", encoding="utf-8") as f:
options_dict = loads(f.read())["options"]
cls._set_mission(Mission(game.theater.terrain))
cls.game = game

View File

@@ -39,9 +39,8 @@ class PendingUnitDeliveries:
def sell(self, units: dict[UnitType[Any], int]) -> None:
for k, v in units.items():
if self.units[k] > v:
self.units[k] -= v
else:
self.units[k] -= v
if self.units[k] == 0:
del self.units[k]
def refund_all(self, game: Game) -> None:

View File

@@ -3,7 +3,7 @@ from pathlib import Path
MAJOR_VERSION = 4
MINOR_VERSION = 1
MICRO_VERSION = 1
MICRO_VERSION = 2
def _build_version_string() -> str:
@@ -12,7 +12,7 @@ def _build_version_string() -> str:
]
build_number_path = Path("resources/buildnumber")
if build_number_path.exists():
with build_number_path.open("r") as build_number_file:
with build_number_path.open("r", encoding="utf-8") as build_number_file:
components.append(build_number_file.readline())
if not Path("resources/final").exists():

View File

@@ -16,7 +16,11 @@ class EwrGenerator(VehicleGroupGenerator[EwrGroundObject]):
def generate(self) -> None:
self.add_unit(
self.unit_type, "EWR", self.position.x, self.position.y, self.heading
self.unit_type,
"EWR",
self.position.x,
self.position.y,
self.heading_to_conflict(),
)

View File

@@ -68,7 +68,8 @@ def run_ui(game: Optional[Game]) -> None:
# init the theme and load the stylesheet based on the theme index
liberation_theme.init()
with open(
"./resources/stylesheets/" + liberation_theme.get_theme_css_file()
"./resources/stylesheets/" + liberation_theme.get_theme_css_file(),
encoding="utf-8",
) as stylesheet:
logging.info("Loading stylesheet: %s", liberation_theme.get_theme_css_file())
app.setStyleSheet(stylesheet.read())

View File

@@ -228,7 +228,7 @@ class QWaitingForMissionResultWindow(QDialog):
)
print(file)
try:
with open(file[0], "r") as json_file:
with open(file[0], "r", encoding="utf-8") as json_file:
json_data = json.load(json_file)
json_data["mission_ended"] = True
debriefing = Debriefing(json_data, self.game, self.unit_map)

View File

@@ -80,7 +80,13 @@ class PurchaseGroup(QGroupBox):
def update_state(self) -> None:
self.buy_button.setEnabled(self.recruiter.enable_purchase(self.unit_type))
self.buy_button.setToolTip(
self.recruiter.purchase_tooltip(self.buy_button.isEnabled())
)
self.sell_button.setEnabled(self.recruiter.enable_sale(self.unit_type))
self.sell_button.setToolTip(
self.recruiter.sell_tooltip(self.sell_button.isEnabled())
)
self.amount_bought.setText(f"<b>{self.pending_units}</b>")
@@ -223,6 +229,18 @@ class QRecruitBehaviour:
def enable_sale(self, unit_type: UnitType) -> bool:
return True
def purchase_tooltip(self, is_enabled: bool) -> str:
if is_enabled:
return "Buy unit. Use Shift or Ctrl key to buy multiple units at once."
else:
return "Unit can not be bought."
def sell_tooltip(self, is_enabled: bool) -> str:
if is_enabled:
return "Sell unit. Use Shift or Ctrl key to buy multiple units at once."
else:
return "Unit can not be sold."
def info(self, unit_type: UnitType) -> None:
self.info_window = QUnitInfoWindow(self.game_model.game, unit_type)
self.info_window.show()

View File

@@ -85,9 +85,13 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
return True
def enable_sale(self, unit_type: AircraftType) -> bool:
if not self.cp.can_operate(unit_type):
return False
return True
return self.can_be_sold(unit_type)
def sell_tooltip(self, is_enabled: bool) -> str:
if is_enabled:
return "Sell unit. Use Shift or Ctrl key to sell multiple units at once."
else:
return "Can not be sold because either no aircraft are available or are already assigned to a mission."
def buy(self, unit_type: AircraftType) -> bool:
if self.maximum_units > 0:
@@ -112,24 +116,32 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
self.hangar_status.update_label()
return True
def can_be_sold(self, unit_type: AircraftType) -> bool:
inventory = self.game_model.game.aircraft_inventory.for_control_point(self.cp)
pending_deliveries = self.pending_deliveries.units.get(unit_type, 0)
return self.cp.can_operate(unit_type) and (
pending_deliveries > 0 or inventory.available(unit_type) > 0
)
def sell(self, unit_type: AircraftType) -> bool:
# Don't need to remove aircraft from the inventory if we're canceling
# orders.
if self.pending_deliveries.units.get(unit_type, 0) <= 0:
global_inventory = self.game_model.game.aircraft_inventory
inventory = global_inventory.for_control_point(self.cp)
try:
inventory.remove_aircraft(unit_type, 1)
except ValueError:
QMessageBox.critical(
self,
"Could not sell aircraft",
f"Attempted to sell one {unit_type} at {self.cp.name} "
"but none are available. Are all aircraft currently "
"assigned to a mission?",
QMessageBox.Ok,
)
return False
if not self.can_be_sold(unit_type):
QMessageBox.critical(
self,
"Could not sell aircraft",
f"Attempted to sell one {unit_type} at {self.cp.name} "
"but none are available. Are all aircraft currently "
"assigned to a mission?",
QMessageBox.Ok,
)
return False
inventory = self.game_model.game.aircraft_inventory.for_control_point(self.cp)
pending_deliveries = self.pending_deliveries.units.get(unit_type, 0)
if pending_deliveries <= 0 < inventory.available(unit_type):
inventory.remove_aircraft(unit_type, 1)
super().sell(unit_type)
self.hangar_status.update_label()

View File

@@ -42,7 +42,7 @@ class Campaign:
@classmethod
def from_json(cls, path: Path) -> Campaign:
with path.open() as campaign_file:
with path.open(encoding="utf-8") as campaign_file:
data = json.load(campaign_file)
sanitized_theater = data["theater"].replace(" ", "")