mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Ground objects have 'Objective' name for easier search. Predefined Waypoint generator entirely reworked.
Added finances menu, and info panel.
This commit is contained in:
parent
6dec5ea8f8
commit
fc64e57495
@ -739,6 +739,14 @@ TIME_PERIODS = {
|
||||
"Syrian War [2011]": datetime(2011, 8, 7),
|
||||
}
|
||||
|
||||
REWARDS = {
|
||||
"power": 4, "warehouse": 2, "fuel": 2, "ammo": 2,
|
||||
"farp": 1, "fob": 1, "factory": 10, "comms": 10, "oil": 10
|
||||
}
|
||||
|
||||
# Base post-turn bonus value
|
||||
PLAYER_BUDGET_BASE = 20
|
||||
|
||||
CARRIER_CAPABLE = [
|
||||
FA_18C_hornet,
|
||||
F_14B,
|
||||
|
||||
@ -8,6 +8,7 @@ from dcs.vehicles import AirDefence
|
||||
from dcs.unittype import UnitType
|
||||
|
||||
from game import *
|
||||
from game.infos.information import Information
|
||||
from theater import *
|
||||
from gen.environmentgen import EnvironmentSettings
|
||||
from gen.conflictgen import Conflict
|
||||
@ -220,6 +221,10 @@ class Event:
|
||||
cp.base.aa = {}
|
||||
for g in cp.ground_objects:
|
||||
g.groups = []
|
||||
info = Information(cp.name + " lost !",
|
||||
"The ennemy took control of " + cp.name + "\nShame on us !",
|
||||
self.game.turn)
|
||||
self.game.informations.append(info)
|
||||
elif not(cp.captured) and new_owner_coalition == coalition:
|
||||
cp.captured = True
|
||||
cp.base.aircraft = {}
|
||||
@ -227,6 +232,10 @@ class Event:
|
||||
cp.base.aa = {}
|
||||
for g in cp.ground_objects:
|
||||
g.groups = []
|
||||
info = Information(cp.name + " captured !",
|
||||
"The ennemy took control of " + cp.name + "\nShame on us !",
|
||||
self.game.turn)
|
||||
self.game.informations.append(info)
|
||||
except Exception as e:
|
||||
print(e)
|
||||
|
||||
@ -281,17 +290,25 @@ class Event:
|
||||
|
||||
# No progress with defensive strategies
|
||||
if player_won and cp.stances[enemy_cp.id] in [CombatStance.DEFENSIVE, CombatStance.AMBUSH]:
|
||||
print("Defensive stance, no progress")
|
||||
delta = 0
|
||||
print("Defensive stance, progress is limited")
|
||||
delta = MINOR_DEFEAT_INFLUENCE
|
||||
|
||||
if player_won:
|
||||
print(cp.name + " won ! factor > " + str(delta))
|
||||
cp.base.affect_strength(delta)
|
||||
enemy_cp.base.affect_strength(-delta)
|
||||
info = Information("Frontline Report",
|
||||
"Our ground forces from " + cp.name + " are making progress toward " + enemy_cp.name,
|
||||
self.game.turn)
|
||||
self.game.informations.append(info)
|
||||
else:
|
||||
print(enemy_cp.name + " won ! factor > " + str(delta))
|
||||
print(cp.name + " lost ! factor > " + str(delta))
|
||||
enemy_cp.base.affect_strength(delta)
|
||||
cp.base.affect_strength(-delta)
|
||||
info = Information("Frontline Report",
|
||||
"Our ground forces from " + cp.name + " are losing ground against the enemy forces from" + enemy_cp.name,
|
||||
self.game.turn)
|
||||
self.game.informations.append(info)
|
||||
|
||||
def skip(self):
|
||||
pass
|
||||
@ -319,4 +336,9 @@ class UnitsDeliveryEvent(Event):
|
||||
self.units[k] = self.units.get(k, 0) + v
|
||||
|
||||
def skip(self):
|
||||
|
||||
for k, v in self.units.items():
|
||||
info = Information("Ally Reinforcement", str(k.id) + " x " + str(v) + " at " + self.to_cp.name, self.game.turn)
|
||||
self.game.informations.append(info)
|
||||
|
||||
self.to_cp.base.commision_units(self.units)
|
||||
|
||||
@ -4,7 +4,7 @@ from dcs.planes import *
|
||||
from dcs.helicopters import *
|
||||
|
||||
Lybia_2011 = {
|
||||
"country": "Libya",
|
||||
"country": "Russia",
|
||||
"side": "red",
|
||||
"units": [
|
||||
|
||||
|
||||
79
game/game.py
79
game/game.py
@ -6,6 +6,7 @@ import math
|
||||
from dcs.task import *
|
||||
from dcs.vehicles import *
|
||||
|
||||
from game.db import REWARDS, PLAYER_BUDGET_BASE
|
||||
from game.game_stats import GameStats
|
||||
from game.infos.information import Information
|
||||
from gen.conflictgen import Conflict
|
||||
@ -50,10 +51,7 @@ ENEMY_BASE_STRENGTH_RECOVERY = 0.05
|
||||
AWACS_BUDGET_COST = 4
|
||||
|
||||
# Initial budget value
|
||||
PLAYER_BUDGET_INITIAL = 450
|
||||
|
||||
# Base post-turn bonus value
|
||||
PLAYER_BUDGET_BASE = 20
|
||||
PLAYER_BUDGET_INITIAL = 650
|
||||
|
||||
# Bonus multiplier logarithm base
|
||||
PLAYER_BUDGET_IMPORTANCE_LOG = 2
|
||||
@ -86,6 +84,7 @@ class Game:
|
||||
self.planners = {}
|
||||
self.ground_planners = {}
|
||||
self.informations = []
|
||||
self.informations.append(Information("Game Start", "-" * 40, 0))
|
||||
|
||||
def _roll(self, prob, mult):
|
||||
if self.settings.version == "dev":
|
||||
@ -111,10 +110,12 @@ class Game:
|
||||
|
||||
def _commision_units(self, cp: ControlPoint):
|
||||
for for_task in [CAS, CAP, AirDefence]:
|
||||
limit = COMMISION_LIMITS_FACTORS[for_task] * math.pow(cp.importance, COMMISION_LIMITS_SCALE) * self.settings.multiplier
|
||||
limit = COMMISION_LIMITS_FACTORS[for_task] * math.pow(cp.importance,
|
||||
COMMISION_LIMITS_SCALE) * self.settings.multiplier
|
||||
missing_units = limit - cp.base.total_units(for_task)
|
||||
if missing_units > 0:
|
||||
awarded_points = COMMISION_AMOUNTS_FACTORS[for_task] * math.pow(cp.importance, COMMISION_AMOUNTS_SCALE) * self.settings.multiplier
|
||||
awarded_points = COMMISION_AMOUNTS_FACTORS[for_task] * math.pow(cp.importance,
|
||||
COMMISION_AMOUNTS_SCALE) * self.settings.multiplier
|
||||
points_to_spend = cp.base.append_commision_points(for_task, awarded_points)
|
||||
if points_to_spend > 0:
|
||||
unittypes = self.commision_unit_types(cp, for_task)
|
||||
@ -130,25 +131,8 @@ class Game:
|
||||
reward = PLAYER_BUDGET_BASE * len(self.theater.player_points())
|
||||
for cp in self.theater.player_points():
|
||||
for g in cp.ground_objects:
|
||||
# (Reward is per building)
|
||||
if g.category == "power":
|
||||
reward = reward + 4
|
||||
elif g.category == "warehouse":
|
||||
reward = reward + 2
|
||||
elif g.category == "fuel":
|
||||
reward = reward + 2
|
||||
elif g.category == "ammo":
|
||||
reward = reward + 2
|
||||
elif g.category == "farp":
|
||||
reward = reward + 1
|
||||
elif g.category == "fob":
|
||||
reward = reward + 1
|
||||
elif g.category == "factory":
|
||||
reward = reward + 10
|
||||
elif g.category == "comms":
|
||||
reward = reward + 10
|
||||
elif g.category == "oil":
|
||||
reward = reward + 10
|
||||
if g.category in REWARDS.keys():
|
||||
reward = reward + REWARDS[g.category]
|
||||
return reward
|
||||
else:
|
||||
return reward
|
||||
@ -197,9 +181,9 @@ class Game:
|
||||
else:
|
||||
return event.name == self.player_name
|
||||
|
||||
def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint]=None):
|
||||
def pass_turn(self, no_action=False, ignored_cps: typing.Collection[ControlPoint] = None):
|
||||
logging.info("Pass turn")
|
||||
|
||||
self.informations.append(Information("End of turn #" + str(self.turn), "-" * 40, 0))
|
||||
self.turn = self.turn + 1
|
||||
|
||||
for event in self.events:
|
||||
@ -210,7 +194,6 @@ class Game:
|
||||
else:
|
||||
event.skip()
|
||||
|
||||
|
||||
self._enemy_reinforcement()
|
||||
self._budget_player()
|
||||
|
||||
@ -246,34 +229,17 @@ class Game:
|
||||
gplanner.plan_groundwar()
|
||||
self.ground_planners[cp.id] = gplanner
|
||||
|
||||
|
||||
|
||||
def _enemy_reinforcement(self):
|
||||
MAX_ARMOR = 50 * self.settings.multiplier
|
||||
MAX_AIRCRAFT = 50 * self.settings.multiplier
|
||||
MAX_ARMOR = 30 * self.settings.multiplier
|
||||
MAX_AIRCRAFT = 25 * self.settings.multiplier
|
||||
|
||||
production = 0
|
||||
production = 0.0
|
||||
for enemy_point in self.theater.enemy_points():
|
||||
for g in enemy_point.ground_objects:
|
||||
if g.category == "power":
|
||||
production = production + 4
|
||||
elif g.category == "warehouse":
|
||||
production = production + 2
|
||||
elif g.category == "fuel":
|
||||
production = production + 2
|
||||
elif g.category == "ammo":
|
||||
production = production + 2
|
||||
elif g.category == "farp":
|
||||
production = production + 1
|
||||
elif g.category == "fob":
|
||||
production = production + 1
|
||||
elif g.category == "factory":
|
||||
production = production + 10
|
||||
elif g.category == "comms":
|
||||
production = production + 8
|
||||
elif g.category == "oil":
|
||||
production = production + 8
|
||||
if g.category in REWARDS.keys():
|
||||
production = production + REWARDS[g.category]
|
||||
|
||||
production = production * 0.75
|
||||
budget_for_armored_units = production / 2
|
||||
budget_for_aircraft = production / 2
|
||||
|
||||
@ -302,7 +268,7 @@ class Game:
|
||||
if target_cp.base.total_armor >= MAX_ARMOR:
|
||||
continue
|
||||
unit = random.choice(potential_units)
|
||||
price = db.PRICES[unit]*2
|
||||
price = db.PRICES[unit] * 2
|
||||
budget_for_armored_units -= price * 2
|
||||
target_cp.base.armor[unit] = target_cp.base.armor.get(unit, 0) + 2
|
||||
info = Information("Enemy Reinforcement", unit.id + " x 2 at " + target_cp.name, self.turn)
|
||||
@ -312,7 +278,8 @@ class Game:
|
||||
if budget_for_armored_units > 0:
|
||||
budget_for_aircraft += budget_for_armored_units
|
||||
|
||||
potential_units = [u for u in db.FACTIONS[self.enemy_name]["units"] if u in db.UNIT_BY_TASK[CAS] or u in db.UNIT_BY_TASK[CAP]]
|
||||
potential_units = [u for u in db.FACTIONS[self.enemy_name]["units"] if
|
||||
u in db.UNIT_BY_TASK[CAS] or u in db.UNIT_BY_TASK[CAP]]
|
||||
if len(potential_units) > 0 and len(potential_cp_armor) > 0:
|
||||
while budget_for_aircraft > 0:
|
||||
i = i + 1
|
||||
@ -322,22 +289,20 @@ class Game:
|
||||
if target_cp.base.total_planes >= MAX_AIRCRAFT:
|
||||
continue
|
||||
unit = random.choice(potential_units)
|
||||
price = db.PRICES[unit]*2
|
||||
price = db.PRICES[unit] * 2
|
||||
budget_for_aircraft -= price * 2
|
||||
target_cp.base.aircraft[unit] = target_cp.base.aircraft.get(unit, 0) + 2
|
||||
info = Information("Enemy Reinforcement", unit.id + " x 2 at " + target_cp.name, self.turn)
|
||||
print(str(info))
|
||||
self.informations.append(info)
|
||||
|
||||
|
||||
|
||||
@property
|
||||
def current_turn_daytime(self):
|
||||
return ["dawn", "day", "dusk", "night"][self.turn % 4]
|
||||
|
||||
@property
|
||||
def current_day(self):
|
||||
return self.date + timedelta(days=self.turn//4)
|
||||
return self.date + timedelta(days=self.turn // 4)
|
||||
|
||||
def next_unit_id(self):
|
||||
"""
|
||||
|
||||
@ -39,6 +39,8 @@ class FlightWaypoint():
|
||||
self.name = ""
|
||||
self.description = ""
|
||||
self.targets = []
|
||||
self.obj_name = ""
|
||||
self.pretty_name = ""
|
||||
|
||||
|
||||
class Flight:
|
||||
|
||||
@ -1,9 +1,48 @@
|
||||
from game import db
|
||||
import random
|
||||
|
||||
ALPHA_MILITARY = ["Alpha","Bravo","Charlie","Delta","Echo","Foxtrot",
|
||||
"Golf","Hotel","India","Juliet","Kilo","Lima","Mike",
|
||||
"November","Oscar","Papa","Quebec","Romeo","Sierra",
|
||||
"Tango","Uniform","Victor","Whisky","XRay","Yankee",
|
||||
"Zulu","Zero"]
|
||||
|
||||
class NameGenerator:
|
||||
number = 0
|
||||
|
||||
ANIMALS = [
|
||||
"SHARK", "TORTOISE", "BAT", "PANGOLIN", "AARDWOLF",
|
||||
"MONKEY", "BUFFALO", "DOG", "BOBCAT", "LYNX", "PANTHER", "TIGER",
|
||||
"LION", "OWL", "BUTTERFLY", "BISON", "DUCK", "COBRA", "MAMBA",
|
||||
"DOLPHIN", "PHEASANT", "ARMADILLLO", "RACOON", "ZEBRA", "COW", "COYOTE", "FOX",
|
||||
"LIGHTFOOT", "COTTONMOUTH", "TAURUS", "VIPER", "CASTOR", "GIRAFFE", "SNAKE",
|
||||
"MONSTER", "ALBATROSS", "HAWK", "DOVE", "MOCKINGBIRD", "GECKO", "ORYX", "GORILLA",
|
||||
"HARAMBE", "GOOSE", "MAVERICK", "HARE", "JACKAL", "LEOPARD", "CAT", "MUSK", "ORCA",
|
||||
"OCELOT", "BEAR", "PANDA", "GULL", "PENGUIN", "PYTHON", "RAVEN", "DEER", "MOOSE",
|
||||
"REINDEER", "SHEEP", "GAZELLE", "INSECT", "VULTURE", "WALLABY", "KANGAROO", "KOALA",
|
||||
"KIWI", "WHALE", "FISH", "RHINO", "HIPPO", "RAT", "WOODPECKER", "WORM", "BABOON",
|
||||
"YAK", "SCORPIO", "HORSE", "POODLE", "CENTIPEDE", "CHICKEN", "CHEETAH", "CHAMELEON",
|
||||
"CATFISH", "CATERPILLAR", "CARACAL", "CAMEL", "CAIMAN", "BARRACUDA", "BANDICOOT",
|
||||
"ALLIGATOR", "BONGO", "CORAL", "ELEPHANT", "ANTELOPE", "CRAB", "DACHSHUND", "DODO",
|
||||
"FLAMINGO", "FERRET", "FALCON", "BULLDOG", "DONKEY", "IGUANA", "TAMARIN", "HARRIER",
|
||||
"GRIZZLY", "GREYHOUND", "GRASSHOPPER", "JAGUAR", "LADYBUG", "KOMODO", "DRAGON", "LIZARD",
|
||||
"LLAMA", "LOBSTER", "OCTOPUS", "MANATEE", "MAGPIE", "MACAW", "OSTRICH", "OYSTER",
|
||||
"MOLE", "MULE", "MOTH", "MONGOOSE", "MOLLY", "MEERKAT", "MOUSE", "PEACOCK", "PIKE", "ROBIN",
|
||||
"RAGDOLL", "PLATYPUS", "PELICAN", "PARROT", "PORCUPINE", "PIRANHA", "PUMA", "PUG", "TAPIR",
|
||||
"TERMITE", "URCHIN", "SHRIMP", "TURKEY", "TOUCAN", "TETRA", "HUSKY", "STARFISH", "SWAN",
|
||||
"FROG", "SQUIRREL", "WALRUS", "WARTHOG", "CORGI", "WEASEL", "WOMBAT", "WOLVERINE", "MAMMOTH",
|
||||
"TOAD", "WOLF", "ZEBU", "SEAL", "SKATE", "JELLYFISH", "MOSQUITO", "LOCUST", "SLUG", "SNAIL",
|
||||
"HEDGEHOG", "PIGLET", "FENNEC", "BADGER", "ALPACA"
|
||||
]
|
||||
|
||||
def __init__(self):
|
||||
self.number = 0
|
||||
self.ANIMALS = NameGenerator.ANIMALS.copy()
|
||||
|
||||
def reset(self):
|
||||
self.number = 0
|
||||
self.ANIMALS = NameGenerator.ANIMALS.copy()
|
||||
|
||||
def next_unit_name(self, country, parent_base_id, unit_type):
|
||||
self.number += 1
|
||||
return "unit|{}|{}|{}|{}|".format(country.id, self.number, parent_base_id, db.unit_type_name(unit_type))
|
||||
@ -27,6 +66,16 @@ class NameGenerator:
|
||||
self.number += 1
|
||||
return "carrier|{}|{}|0|".format(country.id, self.number)
|
||||
|
||||
def random_objective_name(self):
|
||||
if len(self.ANIMALS) == 0:
|
||||
random.choice(ALPHA_MILITARY).upper() + " #" + str(random.randint(0, 100))
|
||||
else:
|
||||
animal = random.choice(self.ANIMALS)
|
||||
self.ANIMALS.remove(animal)
|
||||
return animal
|
||||
|
||||
|
||||
namegen = NameGenerator()
|
||||
|
||||
|
||||
|
||||
|
||||
@ -88,12 +88,10 @@ EVENT_ICONS: Dict[str, QPixmap] = {}
|
||||
|
||||
|
||||
def load_event_icons():
|
||||
for category, image in {
|
||||
"strike": "strike",
|
||||
FrontlineAttackEvent: "attack",
|
||||
UnitsDeliveryEvent: "delivery"}.items():
|
||||
EVENT_ICONS[category] = QPixmap("./resources/ui/events/" + image + ".png")
|
||||
|
||||
for image in os.listdir("./resources/ui/events/"):
|
||||
print(image)
|
||||
if image.endswith(".PNG"):
|
||||
EVENT_ICONS[image[:-4]] = QPixmap(os.path.join("./resources/ui/events/", image))
|
||||
|
||||
def load_aircraft_icons():
|
||||
for aircraft in os.listdir("./resources/ui/units/aircrafts/"):
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox
|
||||
from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox, QPushButton
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from qt_ui.windows.finances.QFinancesMenu import QFinancesMenu
|
||||
|
||||
|
||||
class QBudgetBox(QGroupBox):
|
||||
@ -8,16 +9,22 @@ class QBudgetBox(QGroupBox):
|
||||
UI Component to display current budget and player's money
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, game):
|
||||
super(QBudgetBox, self).__init__("Budget")
|
||||
|
||||
self.game = game
|
||||
self.money_icon = QLabel()
|
||||
self.money_icon.setPixmap(CONST.ICONS["Money"])
|
||||
self.money_amount = QLabel()
|
||||
|
||||
self.finances = QPushButton("Details")
|
||||
self.finances.setProperty("style", "btn-primary")
|
||||
self.finances.clicked.connect(self.openFinances)
|
||||
|
||||
self.layout = QHBoxLayout()
|
||||
self.layout.addWidget(self.money_icon)
|
||||
self.layout.addWidget(self.money_amount)
|
||||
self.layout.addWidget(self.finances)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def setBudget(self, budget, reward):
|
||||
@ -26,4 +33,12 @@ class QBudgetBox(QGroupBox):
|
||||
:param budget: Current money available
|
||||
:param reward: Planned reward for next turn
|
||||
"""
|
||||
self.money_amount.setText(str(budget) + "M (+" + str(reward) + "M)")
|
||||
self.money_amount.setText(str(budget) + "M (+" + str(reward) + "M)")
|
||||
|
||||
def setGame(self, game):
|
||||
self.game = game
|
||||
self.setBudget(self.game.budget, self.game.budget_reward_amount)
|
||||
|
||||
def openFinances(self):
|
||||
self.subwindow = QFinancesMenu(self.game)
|
||||
self.subwindow.show()
|
||||
@ -15,6 +15,7 @@ class QFactionsInfos(QGroupBox):
|
||||
self.setGame(game)
|
||||
|
||||
self.layout = QGridLayout()
|
||||
self.layout.setSpacing(0)
|
||||
self.layout.addWidget(QLabel("<b>Player : </b>"),0,0)
|
||||
self.layout.addWidget(self.player_name,0,1)
|
||||
self.layout.addWidget(QLabel("<b>Enemy : </b>"),1,0)
|
||||
|
||||
146
qt_ui/widgets/QPredefinedWaypointSelectionComboBox.py
Normal file
146
qt_ui/widgets/QPredefinedWaypointSelectionComboBox.py
Normal file
@ -0,0 +1,146 @@
|
||||
from PySide2.QtCore import QSortFilterProxyModel, Qt, QModelIndex
|
||||
from PySide2.QtGui import QStandardItem, QStandardItemModel
|
||||
from PySide2.QtWidgets import QComboBox, QCompleter
|
||||
from game import Game
|
||||
from gen.flights.flight import FlightWaypoint
|
||||
from theater import ControlPointType
|
||||
|
||||
|
||||
class QPredefinedWaypointSelectionComboBox(QComboBox):
|
||||
|
||||
def __init__(self, game: Game, parent=None):
|
||||
super(QPredefinedWaypointSelectionComboBox, self).__init__(parent)
|
||||
|
||||
self.game = game
|
||||
self.setFocusPolicy(Qt.StrongFocus)
|
||||
self.setEditable(True)
|
||||
self.completer = QCompleter(self)
|
||||
|
||||
# always show all completions
|
||||
self.completer.setCompletionMode(QCompleter.UnfilteredPopupCompletion)
|
||||
self.pFilterModel = QSortFilterProxyModel(self)
|
||||
self.pFilterModel.setFilterCaseSensitivity(Qt.CaseInsensitive)
|
||||
|
||||
self.completer.setPopup(self.view())
|
||||
|
||||
self.setCompleter(self.completer)
|
||||
|
||||
self.lineEdit().textEdited.connect(self.pFilterModel.setFilterFixedString)
|
||||
self.completer.activated.connect(self.setTextIfCompleterIsClicked)
|
||||
|
||||
self.find_possible_waypoints()
|
||||
|
||||
def setModel(self, model):
|
||||
super(QPredefinedWaypointSelectionComboBox, self).setModel(model)
|
||||
self.pFilterModel.setSourceModel(model)
|
||||
self.completer.setModel(self.pFilterModel)
|
||||
|
||||
def setModelColumn(self, column):
|
||||
self.completer.setCompletionColumn(column)
|
||||
self.pFilterModel.setFilterKeyColumn(column)
|
||||
super(QPredefinedWaypointSelectionComboBox, self).setModelColumn(column)
|
||||
|
||||
def view(self):
|
||||
return self.completer.popup()
|
||||
|
||||
def index(self):
|
||||
return self.currentIndex()
|
||||
|
||||
def setTextIfCompleterIsClicked(self, text):
|
||||
if text:
|
||||
index = self.findText(text)
|
||||
self.setCurrentIndex(index)
|
||||
|
||||
def get_selected_waypoints(self, include_all_from_same_location=False):
|
||||
n = self.currentText()
|
||||
|
||||
first_waypoint = None
|
||||
for w in self.wpts:
|
||||
if w.pretty_name == n:
|
||||
first_waypoint = w
|
||||
break
|
||||
|
||||
if first_waypoint is None:
|
||||
return []
|
||||
|
||||
waypoints = [first_waypoint]
|
||||
if include_all_from_same_location:
|
||||
for w in self.wpts:
|
||||
if w is not first_waypoint and w.obj_name and w.obj_name == first_waypoint.obj_name:
|
||||
waypoints.append(w)
|
||||
|
||||
return waypoints
|
||||
|
||||
def find_possible_waypoints(self):
|
||||
|
||||
self.wpts = []
|
||||
model = QStandardItemModel()
|
||||
i = 0
|
||||
|
||||
def add_model_item(i, model, name, wpt):
|
||||
print(name)
|
||||
item = QStandardItem(name)
|
||||
model.setItem(i, 0, item)
|
||||
self.wpts.append(wpt)
|
||||
return i + 1
|
||||
|
||||
for cp in self.game.theater.controlpoints:
|
||||
print(cp)
|
||||
if cp.captured:
|
||||
enemy_cp = [ecp for ecp in cp.connected_points if ecp.captured != cp.captured]
|
||||
for ecp in enemy_cp:
|
||||
wpt = FlightWaypoint((cp.position.x + ecp.position.x)/2, (cp.position.y + ecp.position.y)/2, 800)
|
||||
wpt.name = "Frontline " + cp.name + "/" + ecp.name + " [CAS]"
|
||||
wpt.pretty_name = wpt.name
|
||||
wpt.description = "Frontline"
|
||||
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
||||
|
||||
|
||||
for cp in self.game.theater.controlpoints:
|
||||
for ground_object in cp.ground_objects:
|
||||
if not ground_object.is_dead and not ground_object.dcs_identifier == "AA":
|
||||
wpt = FlightWaypoint(ground_object.position.x,ground_object.position.y, 0)
|
||||
wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + ground_object.category + " #" + str(ground_object.object_id)
|
||||
wpt.pretty_name = wpt.name
|
||||
wpt.obj_name = ground_object.obj_name
|
||||
if cp.captured:
|
||||
wpt.description = "Friendly Building"
|
||||
else:
|
||||
wpt.description = "Enemy Building"
|
||||
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
||||
|
||||
for cp in self.game.theater.controlpoints:
|
||||
|
||||
for ground_object in cp.ground_objects:
|
||||
if not ground_object.is_dead and ground_object.dcs_identifier == "AA":
|
||||
for g in ground_object.groups:
|
||||
for j, u in enumerate(g.units):
|
||||
wpt = FlightWaypoint(u.position.x, u.position.y, 0)
|
||||
wpt.name = wpt.name = "[" + str(ground_object.obj_name) + "] : " + u.type + " #" + str(j)
|
||||
wpt.pretty_name = wpt.name
|
||||
wpt.obj_name = ground_object.obj_name
|
||||
if cp.captured:
|
||||
wpt.description = "Friendly unit : " + u.type
|
||||
else:
|
||||
wpt.description = "Enemy unit : " + u.type
|
||||
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
||||
|
||||
for cp in self.game.theater.controlpoints:
|
||||
|
||||
wpt = FlightWaypoint(cp.position.x, cp.position.y, 0)
|
||||
wpt.name = cp.name
|
||||
if cp.captured:
|
||||
wpt.description = "Position of " + cp.name + " [Friendly Airbase]"
|
||||
else:
|
||||
wpt.description = "Position of " + cp.name + " [Enemy Airbase]"
|
||||
|
||||
if cp.cptype == ControlPointType.AIRCRAFT_CARRIER_GROUP:
|
||||
wpt.pretty_name = cp.name + " (Aircraft Carrier Group)"
|
||||
elif cp.cptype == ControlPointType.LHA_GROUP:
|
||||
wpt.pretty_name = cp.name + " (LHA Group)"
|
||||
else:
|
||||
wpt.pretty_name = cp.name + " (Airbase)"
|
||||
|
||||
i = add_model_item(i, model, wpt.pretty_name, wpt)
|
||||
|
||||
self.setModel(model)
|
||||
@ -1,8 +1,9 @@
|
||||
from PySide2.QtWidgets import QFrame, QHBoxLayout, QPushButton, QVBoxLayout
|
||||
from PySide2.QtWidgets import QFrame, QHBoxLayout, QPushButton, QVBoxLayout, QGroupBox
|
||||
|
||||
from game import Game
|
||||
from qt_ui.widgets.QBudgetBox import QBudgetBox
|
||||
from qt_ui.widgets.QFactionsInfos import QFactionsInfos
|
||||
from qt_ui.windows.finances.QFinancesMenu import QFinancesMenu
|
||||
from qt_ui.windows.stats.QStatsWindow import QStatsWindow
|
||||
from qt_ui.widgets.QTurnCounter import QTurnCounter
|
||||
|
||||
@ -17,13 +18,14 @@ class QTopPanel(QFrame):
|
||||
def __init__(self, game: Game):
|
||||
super(QTopPanel, self).__init__()
|
||||
self.game = game
|
||||
self.setMaximumHeight(70)
|
||||
self.init_ui()
|
||||
GameUpdateSignal.get_instance().gameupdated.connect(self.setGame)
|
||||
|
||||
def init_ui(self):
|
||||
|
||||
self.turnCounter = QTurnCounter()
|
||||
self.budgetBox = QBudgetBox()
|
||||
self.budgetBox = QBudgetBox(self.game)
|
||||
|
||||
self.passTurnButton = QPushButton("Pass Turn")
|
||||
self.passTurnButton.setIcon(CONST.ICONS["PassTurn"])
|
||||
@ -36,14 +38,9 @@ class QTopPanel(QFrame):
|
||||
self.proceedButton.clicked.connect(self.proceed)
|
||||
if self.game and self.game.turn == 0:
|
||||
self.proceedButton.setEnabled(False)
|
||||
elif not len(self.game.planners.keys()) == self.game.theater.controlpoints:
|
||||
self.proceedButton.setEnabled(False)
|
||||
else:
|
||||
self.proceedButton.setEnabled(True)
|
||||
|
||||
self.factionsInfos = QFactionsInfos(self.game)
|
||||
|
||||
self.submenus = QVBoxLayout()
|
||||
self.settings = QPushButton("Settings")
|
||||
self.settings.setIcon(CONST.ICONS["Settings"])
|
||||
self.settings.setProperty("style", "btn-primary")
|
||||
@ -54,28 +51,40 @@ class QTopPanel(QFrame):
|
||||
self.statistics.setProperty("style", "btn-primary")
|
||||
self.statistics.clicked.connect(self.openStatisticsWindow)
|
||||
|
||||
self.submenus.addWidget(self.settings)
|
||||
self.submenus.addWidget(self.statistics)
|
||||
self.buttonBox = QGroupBox("Misc")
|
||||
self.buttonBoxLayout = QHBoxLayout()
|
||||
self.buttonBoxLayout.addWidget(self.settings)
|
||||
self.buttonBoxLayout.addWidget(self.statistics)
|
||||
self.buttonBox.setLayout(self.buttonBoxLayout)
|
||||
|
||||
self.proceedBox = QGroupBox("Proceed")
|
||||
self.proceedBoxLayout = QHBoxLayout()
|
||||
self.proceedBoxLayout.addWidget(self.passTurnButton)
|
||||
self.proceedBoxLayout.addWidget(self.proceedButton)
|
||||
self.proceedBox.setLayout(self.proceedBoxLayout)
|
||||
|
||||
self.layout = QHBoxLayout()
|
||||
self.layout.addWidget(self.factionsInfos)
|
||||
self.layout.addWidget(self.turnCounter)
|
||||
self.layout.addWidget(self.budgetBox)
|
||||
self.layout.addLayout(self.submenus)
|
||||
self.layout.addWidget(self.buttonBox)
|
||||
self.layout.addStretch(1)
|
||||
self.layout.addWidget(self.passTurnButton)
|
||||
self.layout.addWidget(self.proceedButton)
|
||||
self.layout.addWidget(self.proceedBox)
|
||||
|
||||
self.layout.setContentsMargins(0,0,0,0)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def setGame(self, game:Game):
|
||||
self.game = game
|
||||
if game is not None:
|
||||
self.turnCounter.setCurrentTurn(self.game.turn, self.game.current_day)
|
||||
self.budgetBox.setBudget(self.game.budget, self.game.budget_reward_amount)
|
||||
self.budgetBox.setGame(self.game)
|
||||
self.factionsInfos.setGame(self.game)
|
||||
|
||||
if not len(self.game.planners.keys()) == self.game.theater.controlpoints:
|
||||
if not len(self.game.planners.keys()) == len(self.game.theater.controlpoints):
|
||||
self.proceedButton.setEnabled(False)
|
||||
else:
|
||||
self.proceedButton.setEnabled(True)
|
||||
|
||||
def openSettings(self):
|
||||
self.subwindow = QSettingsWindow(self.game)
|
||||
|
||||
@ -76,13 +76,6 @@ class QLiberationMap(QGraphicsView):
|
||||
scene.addItem(QMapControlPoint(self, pos[0] - CONST.CP_SIZE / 2, pos[1] - CONST.CP_SIZE / 2, CONST.CP_SIZE,
|
||||
CONST.CP_SIZE, cp, self.game))
|
||||
|
||||
text = scene.addText(cp.name, font=QFont("Trebuchet MS", 10, weight=5, italic=False))
|
||||
text.setPos(pos[0] + CONST.CP_SIZE, pos[1] - CONST.CP_SIZE / 2)
|
||||
|
||||
text = scene.addText(cp.name, font=QFont("Trebuchet MS", 10, weight=5, italic=False))
|
||||
text.setDefaultTextColor(Qt.white)
|
||||
text.setPos(pos[0] + CONST.CP_SIZE + 1, pos[1] - CONST.CP_SIZE / 2 + 1)
|
||||
|
||||
|
||||
if cp.captured:
|
||||
pen = QPen(brush=CONST.COLORS["blue"])
|
||||
@ -105,7 +98,7 @@ class QLiberationMap(QGraphicsView):
|
||||
|
||||
go_pos = self._transform_point(ground_object.position)
|
||||
if not ground_object.airbase_group:
|
||||
scene.addItem(QMapGroundObject(self, go_pos[0], go_pos[1], 16, 16, cp, ground_object))
|
||||
scene.addItem(QMapGroundObject(self, go_pos[0], go_pos[1], 12, 12, cp, ground_object))
|
||||
|
||||
if ground_object.category == "aa" and self.get_display_rule("sam"):
|
||||
max_range = 0
|
||||
@ -126,6 +119,7 @@ class QLiberationMap(QGraphicsView):
|
||||
self.scene_create_lines_for_cp(cp)
|
||||
|
||||
for cp in self.game.theater.controlpoints:
|
||||
pos = self._transform_point(cp.position)
|
||||
if self.get_display_rule("flight_paths"):
|
||||
if cp.id in self.game.planners.keys():
|
||||
planner = self.game.planners[cp.id]
|
||||
@ -139,6 +133,14 @@ class QLiberationMap(QGraphicsView):
|
||||
prev_pos = list(new_pos)
|
||||
scene.addLine(prev_pos[0] + 2, prev_pos[1] + 2, pos[0] + 2, pos[1] + 2, flight_path_pen)
|
||||
|
||||
for cp in self.game.theater.controlpoints:
|
||||
pos = self._transform_point(cp.position)
|
||||
text = scene.addText(cp.name, font=QFont("Trebuchet MS", 10, weight=5, italic=False))
|
||||
text.setPos(pos[0] + CONST.CP_SIZE, pos[1] - CONST.CP_SIZE / 2)
|
||||
text = scene.addText(cp.name, font=QFont("Trebuchet MS", 10, weight=5, italic=False))
|
||||
text.setDefaultTextColor(Qt.white)
|
||||
text.setPos(pos[0] + CONST.CP_SIZE + 1, pos[1] - CONST.CP_SIZE / 2 + 1)
|
||||
|
||||
def scene_create_lines_for_cp(self, cp: ControlPoint):
|
||||
scene = self.scene()
|
||||
pos = self._transform_point(cp.position)
|
||||
|
||||
@ -27,12 +27,12 @@ class QMapGroundObject(QGraphicsRectItem):
|
||||
units[u.type] = units[u.type]+1
|
||||
else:
|
||||
units[u.type] = 1
|
||||
tooltip = ""
|
||||
tooltip = "[" + self.model.obj_name + "]" + "\n"
|
||||
for unit in units.keys():
|
||||
tooltip = tooltip + str(unit) + "x" + str(units[unit]) + "\n"
|
||||
self.setToolTip(tooltip[:-1])
|
||||
else:
|
||||
self.setToolTip(cp.name + "'s " + self.model.category)
|
||||
self.setToolTip("[" + self.model.obj_name + "] : " + self.model.category)
|
||||
|
||||
|
||||
def paint(self, painter, option, widget=None):
|
||||
|
||||
@ -4,7 +4,8 @@ import webbrowser
|
||||
from PySide2 import QtGui
|
||||
from PySide2.QtCore import Qt
|
||||
from PySide2.QtGui import QIcon
|
||||
from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QMainWindow, QAction, QMessageBox, QDesktopWidget
|
||||
from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QMainWindow, QAction, QMessageBox, QDesktopWidget, \
|
||||
QSplitter
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game import Game
|
||||
@ -14,6 +15,7 @@ from qt_ui.widgets.map.QLiberationMap import QLiberationMap
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal, DebriefingSignal
|
||||
from qt_ui.windows.QDebriefingWindow import QDebriefingWindow
|
||||
from qt_ui.windows.QNewGameWizard import NewGameWizard
|
||||
from qt_ui.windows.infos.QInfoPanel import QInfoPanel
|
||||
from userdata import persistency
|
||||
|
||||
|
||||
@ -22,6 +24,7 @@ class QLiberationWindow(QMainWindow):
|
||||
def __init__(self):
|
||||
super(QLiberationWindow, self).__init__()
|
||||
|
||||
self.info_panel = None
|
||||
self.setGame(persistency.restore_game())
|
||||
|
||||
self.setGeometry(300, 100, 270, 100)
|
||||
@ -44,11 +47,16 @@ class QLiberationWindow(QMainWindow):
|
||||
def initUi(self):
|
||||
|
||||
self.liberation_map = QLiberationMap(self.game)
|
||||
self.info_panel = QInfoPanel(self.game)
|
||||
|
||||
hbox = QSplitter(Qt.Horizontal)
|
||||
hbox.addWidget(self.info_panel)
|
||||
hbox.addWidget(self.liberation_map)
|
||||
|
||||
vbox = QVBoxLayout()
|
||||
vbox.setMargin(0)
|
||||
vbox.addWidget(QTopPanel(self.game))
|
||||
vbox.addWidget(self.liberation_map)
|
||||
vbox.addWidget(hbox)
|
||||
|
||||
central_widget = QWidget()
|
||||
central_widget.setLayout(vbox)
|
||||
@ -164,6 +172,8 @@ class QLiberationWindow(QMainWindow):
|
||||
|
||||
def setGame(self, game: Game):
|
||||
self.game = game
|
||||
if self.info_panel:
|
||||
self.info_panel.setGame(game)
|
||||
|
||||
def showAboutDialog(self):
|
||||
text = "<h3>DCS Liberation</h3>" + \
|
||||
|
||||
@ -1,20 +1,13 @@
|
||||
import traceback
|
||||
|
||||
from PySide2.QtCore import Qt
|
||||
from PySide2.QtGui import QCloseEvent
|
||||
from PySide2.QtWidgets import QHBoxLayout, QLabel, QWidget, QDialog, QVBoxLayout, QGridLayout, QPushButton, \
|
||||
QGroupBox, QSizePolicy, QSpacerItem
|
||||
from dcs.unittype import UnitType
|
||||
from PySide2.QtWidgets import QHBoxLayout, QLabel, QWidget, QDialog, QGridLayout
|
||||
|
||||
from game.event import UnitsDeliveryEvent, ControlPointType
|
||||
from qt_ui.widgets.QBudgetBox import QBudgetBox
|
||||
from qt_ui.widgets.base.QAirportInformation import QAirportInformation
|
||||
from qt_ui.widgets.base.QBaseInformation import QBaseInformation
|
||||
from qt_ui.windows.basemenu.QBaseMenuTabs import QBaseMenuTabs
|
||||
from qt_ui.windows.mission.QPlannedFlightsView import QPlannedFlightsView
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from theater import ControlPoint, CAP, Embarking, CAS, PinpointStrike, db
|
||||
from game import Game
|
||||
from game.event import ControlPointType
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from qt_ui.windows.basemenu.QBaseMenuTabs import QBaseMenuTabs
|
||||
from theater import ControlPoint
|
||||
|
||||
|
||||
class QBaseMenu2(QDialog):
|
||||
@ -38,6 +31,8 @@ class QBaseMenu2(QDialog):
|
||||
if self.cp.captured:
|
||||
self.deliveryEvent = None
|
||||
|
||||
self.setWindowIcon(EVENT_ICONS["capture"])
|
||||
|
||||
self.setWindowFlags(Qt.WindowStaysOnTopHint)
|
||||
self.setMinimumSize(300, 200)
|
||||
self.setModal(True)
|
||||
|
||||
70
qt_ui/windows/finances/QFinancesMenu.py
Normal file
70
qt_ui/windows/finances/QFinancesMenu.py
Normal file
@ -0,0 +1,70 @@
|
||||
from PySide2.QtWidgets import QDialog, QGridLayout, QLabel, QFrame, QSizePolicy
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game.db import REWARDS, PLAYER_BUDGET_BASE
|
||||
from game.game import Game
|
||||
|
||||
|
||||
class QHorizontalSeparationLine(QFrame):
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setMinimumWidth(1)
|
||||
self.setFixedHeight(20)
|
||||
self.setFrameShape(QFrame.HLine)
|
||||
self.setFrameShadow(QFrame.Sunken)
|
||||
self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
|
||||
|
||||
class QFinancesMenu(QDialog):
|
||||
|
||||
def __init__(self, game: Game):
|
||||
super(QFinancesMenu, self).__init__()
|
||||
|
||||
self.game = game
|
||||
self.setModal(True)
|
||||
self.setWindowTitle("Finances")
|
||||
self.setWindowIcon(CONST.ICONS["Money"])
|
||||
self.setMinimumSize(450, 200)
|
||||
|
||||
reward = PLAYER_BUDGET_BASE * len(self.game.theater.player_points())
|
||||
layout = QGridLayout()
|
||||
layout.addWidget(QLabel("<b>Control Points</b>"), 0, 0)
|
||||
layout.addWidget(QLabel(str(len(self.game.theater.player_points())) + " bases x " + str(PLAYER_BUDGET_BASE) + "M"), 0, 1)
|
||||
layout.addWidget(QLabel(str(reward) + "M"), 0, 2)
|
||||
|
||||
layout.addWidget(QHorizontalSeparationLine(), 1, 0, 1, 3)
|
||||
|
||||
i = 2
|
||||
for cp in self.game.theater.player_points():
|
||||
obj_names = []
|
||||
[obj_names.append(ground_object.obj_name) for ground_object in cp.ground_objects if ground_object.obj_name not in obj_names]
|
||||
for obj_name in obj_names:
|
||||
reward = 0
|
||||
g = None
|
||||
cat = None
|
||||
number = 0
|
||||
for ground_object in cp.ground_objects:
|
||||
if ground_object.obj_name != obj_name or ground_object.is_dead:
|
||||
continue
|
||||
else:
|
||||
if g is None:
|
||||
g = ground_object
|
||||
cat = g.category
|
||||
if cat in REWARDS.keys():
|
||||
number = number + 1
|
||||
reward += REWARDS[cat]
|
||||
|
||||
if g is not None and cat in REWARDS.keys():
|
||||
layout.addWidget(QLabel("<b>" + g.category.upper() + " [" + obj_name + "]</b>"), i, 0)
|
||||
layout.addWidget(QLabel(str(number) + " buildings x " + str(REWARDS[cat]) + "M"), i, 1)
|
||||
rlabel = QLabel(str(reward) + "M")
|
||||
rlabel.setProperty("style", "green")
|
||||
layout.addWidget(rlabel, i, 2)
|
||||
i = i + 1
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
layout.addWidget(QHorizontalSeparationLine(), i+1, 0, 1, 3)
|
||||
|
||||
layout.addWidget(QLabel("<b>" + str(self.game.budget_reward_amount) + "M </b>"), i+2, 2)
|
||||
|
||||
12
qt_ui/windows/infos/QInfoItem.py
Normal file
12
qt_ui/windows/infos/QInfoItem.py
Normal file
@ -0,0 +1,12 @@
|
||||
from PySide2.QtGui import QStandardItem
|
||||
|
||||
from game.infos.information import Information
|
||||
|
||||
|
||||
class QInfoItem(QStandardItem):
|
||||
|
||||
def __init__(self, info: Information):
|
||||
super(QInfoItem, self).__init__()
|
||||
self.info = info
|
||||
self.setText("[%02d]" % self.info.turn + " " + self.info.title + ' : {:<16}'.format(info.text))
|
||||
self.setEditable(False)
|
||||
33
qt_ui/windows/infos/QInfoList.py
Normal file
33
qt_ui/windows/infos/QInfoList.py
Normal file
@ -0,0 +1,33 @@
|
||||
from PySide2.QtCore import QItemSelectionModel, QPoint
|
||||
from PySide2.QtGui import QStandardItemModel
|
||||
from PySide2.QtWidgets import QListView
|
||||
|
||||
from game import Game, game
|
||||
from qt_ui.windows.infos.QInfoItem import QInfoItem
|
||||
|
||||
|
||||
class QInfoList(QListView):
|
||||
|
||||
def __init__(self, game:Game):
|
||||
super(QInfoList, self).__init__()
|
||||
self.model = QStandardItemModel(self)
|
||||
self.setModel(self.model)
|
||||
self.game = game
|
||||
self.update_list()
|
||||
|
||||
self.selectionModel().setCurrentIndex(self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select)
|
||||
self.selectionModel().selectionChanged.connect(self.on_selected_info_changed)
|
||||
|
||||
def on_selected_info_changed(self):
|
||||
index = self.selectionModel().currentIndex().row()
|
||||
|
||||
def update_list(self):
|
||||
self.model.clear()
|
||||
if self.game is not None:
|
||||
for i, info in enumerate(reversed(self.game.informations)):
|
||||
self.model.appendRow(QInfoItem(info))
|
||||
self.selectionModel().setCurrentIndex(self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select)
|
||||
|
||||
def setGame(self, game):
|
||||
self.game = game
|
||||
self.update_list()
|
||||
28
qt_ui/windows/infos/QInfoPanel.py
Normal file
28
qt_ui/windows/infos/QInfoPanel.py
Normal file
@ -0,0 +1,28 @@
|
||||
from PySide2.QtWidgets import QFrame, QVBoxLayout, QLabel, QGroupBox
|
||||
|
||||
from game import Game
|
||||
from qt_ui.windows.infos.QInfoList import QInfoList
|
||||
|
||||
|
||||
class QInfoPanel(QGroupBox):
|
||||
|
||||
def __init__(self, game: Game):
|
||||
super(QInfoPanel, self).__init__("Info Panel")
|
||||
self.informations_list = QInfoList(game)
|
||||
self.init_ui()
|
||||
|
||||
def setGame(self, game):
|
||||
self.game = game
|
||||
self.informations_list.setGame(game)
|
||||
|
||||
def update(self):
|
||||
self.informations_list.update_list()
|
||||
|
||||
def init_ui(self):
|
||||
layout = QVBoxLayout()
|
||||
layout.addWidget(self.informations_list)
|
||||
layout.setSpacing(0)
|
||||
layout.setContentsMargins(0, 0, 0, 0)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
21
qt_ui/windows/infos/QInfoWidget.py
Normal file
21
qt_ui/windows/infos/QInfoWidget.py
Normal file
@ -0,0 +1,21 @@
|
||||
from PySide2.QtWidgets import QFrame, QLabel, QGridLayout
|
||||
|
||||
from game.infos.information import Information
|
||||
|
||||
|
||||
class QInfoWidget(QFrame):
|
||||
|
||||
def __init__(self, info: Information):
|
||||
super(QInfoWidget, self).__init__()
|
||||
self.info = info
|
||||
self.titleLabel = QLabel("<b>" + info.title + "</b>")
|
||||
self.textLabel = QLabel(info.text)
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
layout = QGridLayout()
|
||||
layout.addWidget(self.titleLabel,0,0)
|
||||
layout.addWidget(self.textLabel,1,0)
|
||||
self.setLayout(layout)
|
||||
|
||||
|
||||
@ -16,7 +16,7 @@ class QMissionPlanning(QDialog):
|
||||
super(QMissionPlanning, self).__init__()
|
||||
self.game = game
|
||||
self.setWindowFlags(Qt.WindowStaysOnTopHint)
|
||||
self.setMinimumSize(750, 420)
|
||||
self.setMinimumSize(800, 420)
|
||||
self.setModal(True)
|
||||
self.setWindowTitle("Mission Preparation")
|
||||
self.setWindowIcon(EVENT_ICONS["strike"])
|
||||
@ -133,8 +133,3 @@ class QMissionPlanning(QDialog):
|
||||
waiting = QWaitingForMissionResultWindow(self.gameEvent, self.game)
|
||||
waiting.show()
|
||||
self.close()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@ from gen.flights.flight import FlightWaypoint
|
||||
|
||||
class QFlightWaypointInfoBox(QGroupBox):
|
||||
|
||||
def __init__(self, flight_wpt:FlightWaypoint):
|
||||
def __init__(self, flight_wpt:FlightWaypoint = None):
|
||||
super(QFlightWaypointInfoBox, self).__init__("Waypoint")
|
||||
self.flight_wpt = flight_wpt
|
||||
if flight_wpt is None:
|
||||
@ -22,31 +22,31 @@ class QFlightWaypointInfoBox(QGroupBox):
|
||||
layout = QVBoxLayout()
|
||||
|
||||
x_pos_layout = QHBoxLayout()
|
||||
x_pos_layout.addWidget(QLabel("X : "))
|
||||
x_pos_layout.addWidget(QLabel("<b>X : </b>"))
|
||||
x_pos_layout.addWidget(self.x_position_label)
|
||||
x_pos_layout.addStretch()
|
||||
|
||||
y_pos_layout = QHBoxLayout()
|
||||
y_pos_layout.addWidget(QLabel("Y : "))
|
||||
y_pos_layout.addWidget(QLabel("<b>Y : </b>"))
|
||||
y_pos_layout.addWidget(self.y_position_label)
|
||||
y_pos_layout.addStretch()
|
||||
|
||||
alt_layout = QHBoxLayout()
|
||||
alt_layout.addWidget(QLabel("Alt : "))
|
||||
alt_layout.addWidget(QLabel("<b>Alt : </b>"))
|
||||
alt_layout.addWidget(self.alt_label)
|
||||
alt_layout.addStretch()
|
||||
|
||||
name_layout = QHBoxLayout()
|
||||
name_layout.addWidget(QLabel("Name : "))
|
||||
name_layout.addWidget(QLabel("<b>Name : </b>"))
|
||||
name_layout.addWidget(self.name_label)
|
||||
name_layout.addStretch()
|
||||
|
||||
desc_layout = QHBoxLayout()
|
||||
desc_layout.addWidget(QLabel("Description : "))
|
||||
desc_layout.addWidget(QLabel("<b>Description : </b>"))
|
||||
desc_layout.addWidget(self.desc_label)
|
||||
desc_layout.addStretch()
|
||||
|
||||
layout.addLayout(name_layout)
|
||||
#layout.addLayout(name_layout)
|
||||
layout.addLayout(x_pos_layout)
|
||||
layout.addLayout(y_pos_layout)
|
||||
layout.addLayout(alt_layout)
|
||||
|
||||
@ -7,7 +7,9 @@ from gen.flights.flight import FlightWaypoint
|
||||
|
||||
class QWaypointItem(QStandardItem):
|
||||
|
||||
def __init__(self, point: FlightWaypoint):
|
||||
def __init__(self, point: FlightWaypoint, number):
|
||||
super(QWaypointItem, self).__init__()
|
||||
self.setText('{0: <16}'.format(point.description) + " -- [X: " + str(int(point.x)) + "; Y: " + str(int(point.y)) + "; Alt: " + str(int(point.alt)) + "m]")
|
||||
self.number = number
|
||||
self.setText("%02d" % self.number + ' | ' + '{:<16}'.format(point.pretty_name))
|
||||
self.setEditable(False)
|
||||
|
||||
|
||||
@ -28,7 +28,8 @@ class QFlightWaypointList(QListView):
|
||||
self.model.clear()
|
||||
takeoff = FlightWaypoint(self.flight.from_cp.position.x, self.flight.from_cp.position.y, 0)
|
||||
takeoff.description = "Take Off"
|
||||
self.model.appendRow(QWaypointItem(takeoff))
|
||||
takeoff.name = takeoff.pretty_name = "Take Off from " + self.flight.from_cp.name
|
||||
self.model.appendRow(QWaypointItem(takeoff, 0))
|
||||
for i, point in enumerate(self.flight.points):
|
||||
self.model.appendRow(QWaypointItem(point))
|
||||
self.model.appendRow(QWaypointItem(point, i + 1))
|
||||
self.selectionModel().setCurrentIndex(self.indexAt(QPoint(1, 1)), QItemSelectionModel.Select)
|
||||
@ -1,11 +1,13 @@
|
||||
from PySide2.QtCore import Qt
|
||||
from PySide2.QtWidgets import QDialog, QGridLayout, QLabel, QComboBox, QHBoxLayout, QVBoxLayout, QPushButton
|
||||
from PySide2.QtWidgets import QDialog, QGridLayout, QLabel, QComboBox, QHBoxLayout, QVBoxLayout, QPushButton, QCheckBox
|
||||
from dcs import Point
|
||||
|
||||
from game import Game
|
||||
from gen.flights.flight import Flight, FlightWaypoint
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.widgets.QPredefinedWaypointSelectionComboBox import QPredefinedWaypointSelectionComboBox
|
||||
from qt_ui.windows.mission.flight.waypoints.QFlightWaypointInfoBox import QFlightWaypointInfoBox
|
||||
from theater import ControlPointType
|
||||
|
||||
PREDEFINED_WAYPOINT_CATEGORIES = [
|
||||
"Frontline (CAS AREA)",
|
||||
@ -23,135 +25,64 @@ class QPredefinedWaypointSelectionWindow(QDialog):
|
||||
self.game = game
|
||||
self.flight = flight
|
||||
self.setWindowFlags(Qt.WindowStaysOnTopHint)
|
||||
self.setMinimumSize(450, 350)
|
||||
self.setMinimumSize(400, 250)
|
||||
self.setModal(True)
|
||||
self.setWindowTitle("Add Predefined Waypoint")
|
||||
self.setWindowIcon(EVENT_ICONS["strike"])
|
||||
self.flight_waypoint_list = flight_waypoint_list
|
||||
|
||||
self.selected_cp = self.game.theater.controlpoints[0]
|
||||
self.cp_selection_box = QComboBox()
|
||||
for cp in self.game.theater.controlpoints:
|
||||
self.cp_selection_box.addItem(cp.name)
|
||||
|
||||
self.wpt_type_selection_box = QComboBox()
|
||||
for cat in PREDEFINED_WAYPOINT_CATEGORIES:
|
||||
self.wpt_type_selection_box.addItem(cat)
|
||||
|
||||
self.cp_selection_box.currentTextChanged.connect(self.on_parameters_changed)
|
||||
self.wpt_type_selection_box.currentTextChanged.connect(self.on_parameters_changed)
|
||||
|
||||
self.wpt_selection_box = QComboBox()
|
||||
self.wpt_selection_box = QPredefinedWaypointSelectionComboBox(self.game)
|
||||
self.wpt_selection_box.setMinimumWidth(200)
|
||||
self.wpt_selection_box.currentTextChanged.connect(self.on_select_wpt_changed)
|
||||
|
||||
self.selected_waypoint = None
|
||||
self.wpt_info = QFlightWaypointInfoBox(self.selected_waypoint)
|
||||
self.selected_waypoints = []
|
||||
self.wpt_info = QFlightWaypointInfoBox()
|
||||
|
||||
self.add_button = QPushButton("Add")
|
||||
self.add_button.clicked.connect(self.add_waypoint)
|
||||
|
||||
self.include_all = QCheckBox()
|
||||
self.include_all.stateChanged.connect(self.on_select_wpt_changed)
|
||||
self.include_all.setChecked(True)
|
||||
|
||||
self.init_ui()
|
||||
self.on_parameters_changed()
|
||||
self.on_select_wpt_changed()
|
||||
print("DONE")
|
||||
|
||||
|
||||
def init_ui(self):
|
||||
layout = QVBoxLayout()
|
||||
|
||||
near_layout = QHBoxLayout()
|
||||
near_layout.addWidget(QLabel("Near : "))
|
||||
near_layout.addWidget(self.cp_selection_box)
|
||||
near_layout.addStretch()
|
||||
|
||||
type_layout = QHBoxLayout()
|
||||
type_layout.addWidget(QLabel("Type : "))
|
||||
type_layout.addWidget(self.wpt_type_selection_box)
|
||||
type_layout.addStretch()
|
||||
|
||||
wpt_layout = QHBoxLayout()
|
||||
wpt_layout.addWidget(QLabel("Waypoint : "))
|
||||
wpt_layout.addWidget(self.wpt_selection_box)
|
||||
wpt_layout.addStretch()
|
||||
|
||||
layout.addLayout(near_layout)
|
||||
layout.addLayout(type_layout)
|
||||
include_all = QHBoxLayout()
|
||||
include_all.addWidget(QLabel("Include all objects from the same location : "))
|
||||
include_all.addWidget(self.include_all)
|
||||
include_all.addStretch()
|
||||
|
||||
layout.addLayout(wpt_layout)
|
||||
layout.addWidget(self.wpt_info)
|
||||
layout.addLayout(include_all)
|
||||
layout.addStretch()
|
||||
layout.addWidget(self.add_button)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def on_select_wpt_changed(self):
|
||||
self.selected_waypoint = self.wpt_selection_box.currentData()
|
||||
self.wpt_info.set_flight_waypoint(self.selected_waypoint)
|
||||
if self.selected_waypoint is None:
|
||||
self.selected_waypoints = self.wpt_selection_box.get_selected_waypoints(self.include_all.isChecked())
|
||||
if self.selected_waypoints is None or len(self.selected_waypoints) <= 0:
|
||||
self.add_button.setDisabled(True)
|
||||
else:
|
||||
self.wpt_info.set_flight_waypoint(self.selected_waypoints[0])
|
||||
self.add_button.setDisabled(False)
|
||||
|
||||
def on_parameters_changed(self):
|
||||
self.wpt_selection_box.clear()
|
||||
|
||||
select_cp_text = self.cp_selection_box.currentText()
|
||||
select_cp = None
|
||||
for cp in self.game.theater.controlpoints:
|
||||
if cp.name == select_cp_text:
|
||||
select_cp = cp
|
||||
break
|
||||
if select_cp is not None:
|
||||
selected_wpt_type = self.wpt_type_selection_box.currentText()
|
||||
|
||||
if selected_wpt_type == PREDEFINED_WAYPOINT_CATEGORIES[0]: # CAS
|
||||
enemy_cp = [cp for cp in select_cp.connected_points if cp.captured != select_cp.captured]
|
||||
for ecp in enemy_cp:
|
||||
wpt = FlightWaypoint((select_cp.position.x + ecp.position.x)/2, (select_cp.position.y + ecp.position.y)/2, 800)
|
||||
wpt.name = "Frontline with " + ecp.name + " [CAS]"
|
||||
wpt.description = "Frontline"
|
||||
self.wpt_selection_box.addItem(wpt.name, userData=wpt)
|
||||
if len(enemy_cp) == 0:
|
||||
self.wpt_selection_box.addItem("None", userData=None)
|
||||
elif selected_wpt_type == PREDEFINED_WAYPOINT_CATEGORIES[1]: # Building
|
||||
for ground_object in select_cp.ground_objects:
|
||||
if not ground_object.is_dead and not ground_object.dcs_identifier == "AA":
|
||||
wpt = FlightWaypoint(ground_object.position.x,ground_object.position.y, 0)
|
||||
wpt.name = ground_object.category + " #" + str(ground_object.object_id) + " @ site #" + str(ground_object.group_id)
|
||||
if select_cp.captured:
|
||||
wpt.description = "Friendly Building"
|
||||
else:
|
||||
wpt.description = "Enemy Building"
|
||||
self.wpt_selection_box.addItem(wpt.name, userData=wpt)
|
||||
elif selected_wpt_type == PREDEFINED_WAYPOINT_CATEGORIES[2]: # Known units position
|
||||
for ground_object in select_cp.ground_objects:
|
||||
if not ground_object.is_dead and ground_object.dcs_identifier == "AA":
|
||||
for g in ground_object.groups:
|
||||
for u in g.units:
|
||||
wpt = FlightWaypoint(ground_object.position.x, ground_object.position.y, 0)
|
||||
wpt.name = u.type + " @ site #" + str(ground_object.group_id)
|
||||
if select_cp.captured:
|
||||
wpt.description = "Friendly unit :" + u.type
|
||||
else:
|
||||
wpt.description = "Enemy unit :" + u.type
|
||||
self.wpt_selection_box.addItem(wpt.name, userData=wpt)
|
||||
elif selected_wpt_type == PREDEFINED_WAYPOINT_CATEGORIES[3]: # CAS
|
||||
wpt = FlightWaypoint(select_cp.position.x, select_cp.position.y, 0)
|
||||
wpt.name = select_cp.name
|
||||
if select_cp.captured:
|
||||
wpt.description = "Position of " + select_cp.name + " [Friendly Airbase]"
|
||||
else:
|
||||
wpt.description = "Position of " + select_cp.name + " [Enemy Airbase]"
|
||||
self.wpt_selection_box.addItem("Airbase", userData=wpt)
|
||||
else:
|
||||
self.wpt_selection_box.addItem("None", userData=None)
|
||||
else:
|
||||
self.wpt_selection_box.addItem("None", userData=None)
|
||||
|
||||
self.wpt_selection_box.setCurrentIndex(0)
|
||||
|
||||
def add_waypoint(self):
|
||||
if not self.selected_waypoint is None:
|
||||
self.flight.points.append(self.selected_waypoint)
|
||||
|
||||
for wpt in self.selected_waypoints:
|
||||
self.flight.points.append(wpt)
|
||||
|
||||
self.flight_waypoint_list.update_list()
|
||||
self.close()
|
||||
|
||||
|
||||
BIN
resources/ui/ground_assets/destroyed.png
Normal file
BIN
resources/ui/ground_assets/destroyed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 318 B |
@ -166,16 +166,13 @@ class Emirates(ConflictTheater):
|
||||
def __init__(self):
|
||||
super(Emirates, self).__init__()
|
||||
|
||||
self.al_dhafra = ControlPoint.from_airport(persiangulf.Al_Dhafra_AB, LAND, SIZE_BIG, IMPORTANCE_LOW)
|
||||
self.al_dhafra = ControlPoint.from_airport(persiangulf.Al_Dhafra_AB, LAND, SIZE_BIG, IMPORTANCE_MEDIUM)
|
||||
self.al_maktoum = ControlPoint.from_airport(persiangulf.Al_Maktoum_Intl, LAND, SIZE_BIG, IMPORTANCE_LOW)
|
||||
self.al_minhad = ControlPoint.from_airport(persiangulf.Al_Minhad_AB, LAND, SIZE_REGULAR, 1.1)
|
||||
self.sir_abu_nuayr = ControlPoint.from_airport(persiangulf.Sir_Abu_Nuayr, [0, 330], SIZE_SMALL, 1.1, has_frontline=False)
|
||||
self.dubai = ControlPoint.from_airport(persiangulf.Dubai_Intl, COAST_DL_E, SIZE_LARGE, IMPORTANCE_MEDIUM)
|
||||
self.sharjah = ControlPoint.from_airport(persiangulf.Sharjah_Intl, LAND, SIZE_BIG, 1.0)
|
||||
self.fujairah = ControlPoint.from_airport(persiangulf.Fujairah_Intl, COAST_V_W, SIZE_REGULAR, 1.0)
|
||||
self.ras_al_khaimah = ControlPoint.from_airport(persiangulf.Ras_Al_Khaimah, LAND, SIZE_REGULAR,IMPORTANCE_MEDIUM)
|
||||
self.al_ain = ControlPoint.from_airport(persiangulf.Al_Ain_International_Airport, LAND, SIZE_BIG,
|
||||
IMPORTANCE_HIGH)
|
||||
self.al_minhad = ControlPoint.from_airport(persiangulf.Al_Minhad_AB, LAND, SIZE_REGULAR, IMPORTANCE_LOW)
|
||||
self.sharjah = ControlPoint.from_airport(persiangulf.Sharjah_Intl, LAND, SIZE_BIG, IMPORTANCE_LOW)
|
||||
self.fujairah = ControlPoint.from_airport(persiangulf.Fujairah_Intl, COAST_V_W, SIZE_REGULAR, IMPORTANCE_LOW)
|
||||
self.ras_al_khaimah = ControlPoint.from_airport(persiangulf.Ras_Al_Khaimah, LAND, SIZE_REGULAR,IMPORTANCE_LOW)
|
||||
self.al_ain = ControlPoint.from_airport(persiangulf.Al_Ain_International_Airport, LAND, SIZE_BIG,IMPORTANCE_LOW)
|
||||
|
||||
self.east_carrier = ControlPoint.carrier("Carrier", Point(-61770, 69039), 1001)
|
||||
self.tarawa_carrier = ControlPoint.lha("LHA Carrier", Point(-79770, 49430), 1002)
|
||||
@ -183,12 +180,10 @@ class Emirates(ConflictTheater):
|
||||
self.add_controlpoint(self.al_dhafra, connected_to=[self.al_ain, self.al_maktoum])
|
||||
self.add_controlpoint(self.al_ain, connected_to=[self.fujairah, self.al_maktoum, self.al_dhafra])
|
||||
self.add_controlpoint(self.al_maktoum, connected_to=[self.al_dhafra, self.al_minhad, self.al_ain])
|
||||
self.add_controlpoint(self.al_minhad, connected_to=[self.al_maktoum, self.dubai])
|
||||
self.add_controlpoint(self.dubai, connected_to=[self.al_minhad, self.sharjah])
|
||||
self.add_controlpoint(self.sharjah, connected_to=[self.dubai, self.ras_al_khaimah, self.fujairah])
|
||||
self.add_controlpoint(self.al_minhad, connected_to=[self.al_maktoum, self.sharjah])
|
||||
self.add_controlpoint(self.sharjah, connected_to=[self.al_minhad, self.ras_al_khaimah, self.fujairah])
|
||||
self.add_controlpoint(self.ras_al_khaimah, connected_to=[self.sharjah])
|
||||
self.add_controlpoint(self.fujairah, connected_to=[self.sharjah, self.al_ain])
|
||||
self.add_controlpoint(self.sir_abu_nuayr, connected_to=[])
|
||||
|
||||
self.add_controlpoint(self.tarawa_carrier)
|
||||
self.add_controlpoint(self.east_carrier)
|
||||
|
||||
@ -4,6 +4,7 @@ import random
|
||||
import typing
|
||||
import logging
|
||||
|
||||
from gen import namegen
|
||||
from gen.defenses.armor_group_generator import generate_armor_group
|
||||
from gen.fleet.ship_group_generator import generate_carrier_group, generate_lha_group
|
||||
from gen.sam.sam_group_generator import generate_anti_air_group, generate_shorad_group
|
||||
@ -79,6 +80,7 @@ def generate_groundobjects(theater: ConflictTheater, game):
|
||||
g.cp_id = cp.id
|
||||
g.airbase_group = True
|
||||
g.dcs_identifier = "CARRIER"
|
||||
g.obj_name = namegen.random_objective_name()
|
||||
g.heading = 0
|
||||
g.position = Point(cp.position.x, cp.position.y)
|
||||
group = generate_carrier_group(faction, game, g)
|
||||
@ -98,6 +100,7 @@ def generate_groundobjects(theater: ConflictTheater, game):
|
||||
g.cp_id = cp.id
|
||||
g.airbase_group = True
|
||||
g.dcs_identifier = "LHA"
|
||||
g.obj_name = namegen.random_objective_name()
|
||||
g.heading = 0
|
||||
g.position = Point(cp.position.x, cp.position.y)
|
||||
group = generate_lha_group(faction, game, g)
|
||||
@ -124,6 +127,7 @@ def generate_groundobjects(theater: ConflictTheater, game):
|
||||
g.cp_id = cp.id
|
||||
g.airbase_group = True
|
||||
g.dcs_identifier = "AA"
|
||||
g.obj_name = namegen.random_objective_name()
|
||||
g.heading = 0
|
||||
g.position = Point(point.x, point.y)
|
||||
|
||||
@ -160,6 +164,8 @@ def find_location(on_ground, near, theater, min, max, others) -> typing.Optional
|
||||
"""
|
||||
point = None
|
||||
for _ in range(1000):
|
||||
|
||||
# Check if on land or sea
|
||||
p = near.random_point_within(max, min)
|
||||
if on_ground and theater.is_on_land(p):
|
||||
point = p
|
||||
@ -180,6 +186,20 @@ def find_location(on_ground, near, theater, min, max, others) -> typing.Optional
|
||||
if other.position.distance_to_point(point) < 10000:
|
||||
point = None
|
||||
break
|
||||
|
||||
if point:
|
||||
for other in theater.controlpoints:
|
||||
if other.position != near:
|
||||
if point is None:
|
||||
break
|
||||
if other.position.distance_to_point(point) < 30000:
|
||||
point = None
|
||||
break
|
||||
for ground_obj in other.ground_objects:
|
||||
if ground_obj.position.distance_to_point(point) < 10000:
|
||||
point = None
|
||||
break
|
||||
|
||||
if point:
|
||||
return point
|
||||
return None
|
||||
@ -201,13 +221,16 @@ def generate_cp_ground_points(cp: ControlPoint, theater, game, group_id, templat
|
||||
if cp.is_global:
|
||||
return False
|
||||
|
||||
amount = random.randrange(1, 7)
|
||||
amount = random.randrange(3, 8)
|
||||
for i in range(0, amount):
|
||||
|
||||
available_categories = list(templates)
|
||||
obj_name = namegen.random_objective_name()
|
||||
|
||||
if i >= amount - 1:
|
||||
tpl_category = "aa"
|
||||
else:
|
||||
if random.randint(0, 2) == 0:
|
||||
if random.randint(0, 3) == 0:
|
||||
tpl_category = "aa"
|
||||
else:
|
||||
tpl_category = random.choice(available_categories)
|
||||
@ -223,6 +246,7 @@ def generate_cp_ground_points(cp: ControlPoint, theater, game, group_id, templat
|
||||
group_id = group_id + 1
|
||||
|
||||
logging.info("generated {} for {}".format(tpl_category, cp))
|
||||
|
||||
for object in tpl:
|
||||
object_id += 1
|
||||
|
||||
@ -231,12 +255,12 @@ def generate_cp_ground_points(cp: ControlPoint, theater, game, group_id, templat
|
||||
g.object_id = object_id
|
||||
g.cp_id = cp.id
|
||||
g.airbase_gorup = False
|
||||
g.obj_name = obj_name
|
||||
|
||||
g.dcs_identifier = object["type"]
|
||||
g.heading = object["heading"]
|
||||
g.position = Point(point.x + object["offset"].x, point.y + object["offset"].y)
|
||||
|
||||
|
||||
if g.dcs_identifier == "AA":
|
||||
if cp.captured:
|
||||
faction = game.player_name
|
||||
|
||||
@ -49,15 +49,13 @@ class TheaterGroundObject:
|
||||
cp_id = 0
|
||||
group_id = 0
|
||||
object_id = 0
|
||||
|
||||
dcs_identifier = None # type: str
|
||||
is_dead = False
|
||||
airbase_group = False
|
||||
|
||||
heading = 0
|
||||
position = None # type: Point
|
||||
|
||||
groups = []
|
||||
obj_name = ""
|
||||
|
||||
@property
|
||||
def category(self) -> str:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user