diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..d3ce4df3 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,76 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, sex characteristics, gender identity and expression, +level of experience, education, socio-economic status, nationality, personal +appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at khopa.studio@gmail.com. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org + +For answers to common questions about this code of conduct, see +https://www.contributor-covenant.org/faq diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..1f795289 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,26 @@ +First, note that we have a code of conduct, please follow it in all your interactions with the project. + +## Contributing as a non-developer + +* Report bugs by opening issues here on Github. +* Help others users on Discord by answering their questions. +* Raise awareness about the project, by making a video and/or a tutorial. + +Should you report a bug, please use the search bar at the top of the page to see if it has already been reported. +Note that you may need to remove the filter for open bugs if it's something we've recently fixed. + +## Making content for Liberation + +You can create new campaigns : See [campaign creation wiki](https://github.com/Khopa/dcs_liberation/wiki/Custom-Campaigns). +You can also improve existing campaigns. + +You can then submit new campaigns on the "campaigns" channel on Discord, or by making a pull request if you are comfortable with git. + +## Develop new features + +If you want to develop a new feature, we recommend you first open an issue describing the new feature and discuss it with us on Discord before starting development. +However, feel free to work on any existing issue. + +## Pull requests + +Please submit your pull requests on the **develop** branch. We expect a description of its content, and when applicable, a reference to the issue(s) it is resolving. diff --git a/changelog.md b/changelog.md index a576b068..616f2aab 100644 --- a/changelog.md +++ b/changelog.md @@ -1,3 +1,37 @@ +# 2.3.3 + +## Features/Improvements +* **[Campaigns]** Reworked Golan Heights campaign on Syria, (Added FOB and preset locations for SAMS) +* **[Campaigns]** Added a lite version of the Golan Heights campaign +* **[Campaigns]** Reworked Syrian Civil War campaign (Added FOB and preset locations for SAMS) +* **[Campaigns]** Reworked Emirates campaign +* **[Campaigns]** AA units added to frontlines and updated all factions to include some frontline AA units. +* **[Mission Generator]** Infantry will only be generated for APC and IFV groups +* **[Mission Generator]** Infantry squads size is not randomized anymore +* **[Mission Generator]** Infantry squads can have a mortar. +* **[Mission Generator]** SCUD missiles sites will now fire on enemy controls points in range when possible +* **[Factions]** Updated Nato Desert Storm to include F-14A +* **[Factions]** Updated Iraq 1991 factions to include Zsu-57 and Mig-29A +* **[Factions]** Germany 1944, added Stug III and Stug IV +* **[Factions]** Added factions Insurgents (Hard) with better and more weapons +* **[Plugins]** [The EWRS plugin](https://github.com/Bob7heBuilder/EWRS) is now included. +* **[UI]** Added enemy intelligence summary and details window. + +## Fixes: +* **[Factions]** AI would never buy artillery units for the frontline - fixed +* **[Factions]** Removed the F-111 unit from the NATO desert storm faction. (Recruiting it would cause crashes in DCS, since it is not a valid unit) +* **[Campaign]** Automatic redeployment of ground units would sometimes fail - fixed +* **[Mission Generator]** Artillery groups would retreat in the wrong direction - fixed +* **[Units]** Fixed SPG_Stryker_M1128_MGS not being in db +* **[UI]** Fixed and added many missing ground units icons +* **[UI]** Ship groups could be replaced by SAM sites in the UI, which would lead to broken mission being generated - fixed +* **[New Game Wizard]** Removed the "mid game" campaign generator option which is currently broken +* **[Mission Generator]** Empty navy groups will no longer be generated +* **[Mission Generator]** Fixed BAI, SEAD, and DEAD flights ocassionally being assigned the wrong targets. +* **[Flight Planner]** Fixed not being able to plan packages against opfor carriers +* **[UI]** Repaired SAMs no longer show as dead. +* **[UI]** Fixed not being able to manage a disbanded site after disbanding and closing the base menu. + # 2.3.2 ## Features/Improvements diff --git a/game/db.py b/game/db.py index ae3d1d81..8453dbcf 100644 --- a/game/db.py +++ b/game/db.py @@ -385,6 +385,7 @@ PRICES = { Armor.ATGM_M1045_HMMWV_TOW: 8, Armor.IFV_M2A2_Bradley: 12, Armor.APC_M1126_Stryker_ICV: 10, + Armor.SPG_M1128_Stryker_MGS: 14, Armor.ATGM_M1134_Stryker: 12, Armor.MBT_M60A3_Patton: 16, Armor.MBT_M1A2_Abrams: 25, @@ -408,6 +409,7 @@ PRICES = { Artillery.MLRS_BM_21_Grad: 15, Artillery.MLRS_9K57_Uragan_BM_27: 50, Artillery.MLRS_9A52_Smerch: 40, + Artillery._2B11_mortar: 4, Unarmed.Transport_UAZ_469: 3, Unarmed.Transport_Ural_375: 3, @@ -436,6 +438,7 @@ PRICES = { Armor.LAC_M8_Greyhound: 8, Armor.TD_M10_GMC: 14, Armor.StuG_III_Ausf__G: 12, + Armor.StuG_IV: 14, Artillery.M12_GMC: 10, Artillery.Sturmpanzer_IV_Brummbär: 10, Armor.Daimler_Armoured_Car: 8, @@ -755,6 +758,7 @@ UNIT_BY_TASK = { Armor.APC_M1126_Stryker_ICV, Armor.APC_M1126_Stryker_ICV, Armor.APC_M1126_Stryker_ICV, + Armor.SPG_M1128_Stryker_MGS, Armor.IFV_MCV_80, Armor.IFV_MCV_80, Armor.IFV_MCV_80, @@ -819,6 +823,7 @@ UNIT_BY_TASK = { Armor.TD_M10_GMC, Armor.TD_M10_GMC, Armor.StuG_III_Ausf__G, + Armor.StuG_IV, Artillery.M12_GMC, Artillery.Sturmpanzer_IV_Brummbär, Armor.Daimler_Armoured_Car, @@ -837,6 +842,30 @@ UNIT_BY_TASK = { Artillery.M12_GMC, Artillery.Sturmpanzer_IV_Brummbär, + AirDefence.AAA_ZU_23_on_Ural_375, + AirDefence.AAA_ZU_23_Insurgent_on_Ural_375, + AirDefence.AAA_ZSU_57_2, + AirDefence.SPAAA_ZSU_23_4_Shilka, + AirDefence.SAM_SA_8_Osa_9A33, + AirDefence.SAM_SA_9_Strela_1_9P31, + AirDefence.SAM_SA_13_Strela_10M3_9A35M3, + AirDefence.SAM_SA_15_Tor_9A331, + AirDefence.SAM_SA_19_Tunguska_2S6, + AirDefence.SPAAA_Gepard, + AirDefence.AAA_Vulcan_M163, + AirDefence.SAM_Linebacker_M6, + AirDefence.SAM_Chaparral_M48, + AirDefence.SAM_Avenger_M1097, + AirDefence.SAM_Roland_ADS, + AirDefence.HQ_7_Self_Propelled_LN, + AirDefence.AAA_8_8cm_Flak_18, + AirDefence.AAA_8_8cm_Flak_36, + AirDefence.AAA_8_8cm_Flak_37, + AirDefence.AAA_8_8cm_Flak_41, + AirDefence.AAA_Bofors_40mm, + AirDefence.AAA_M1_37mm, + AirDefence.AA_gun_QF_3_7, + frenchpack.DIM__TOYOTA_BLUE, frenchpack.DIM__TOYOTA_DESERT, frenchpack.DIM__TOYOTA_GREEN, @@ -862,23 +891,6 @@ UNIT_BY_TASK = { ], AirDefence: [ - - # those are listed multiple times here to balance prioritization more into lower tier AAs - AirDefence.AAA_Vulcan_M163, - AirDefence.AAA_Vulcan_M163, - AirDefence.AAA_Vulcan_M163, - AirDefence.SAM_Linebacker_M6, - - AirDefence.SPAAA_ZSU_23_4_Shilka, - AirDefence.AAA_ZU_23_Closed, - AirDefence.SAM_SA_9_Strela_1_9P31, - AirDefence.SAM_SA_8_Osa_9A33, - AirDefence.SAM_SA_19_Tunguska_2S6, - AirDefence.SAM_SA_6_Kub_LN_2P25, - AirDefence.SAM_SA_3_S_125_LN_5P73, - AirDefence.SAM_Hawk_PCP, - AirDefence.SAM_SA_2_LN_SM_90, - AirDefence.SAM_SA_11_Buk_LN_9A310M1, ], Reconnaissance: [Unarmed.Transport_M818, Unarmed.Transport_Ural_375, Unarmed.Transport_UAZ_469], Nothing: [Infantry.Infantry_M4, Infantry.Soldier_AK, ], @@ -1262,6 +1274,7 @@ INFANTRY: List[VehicleType] = [ Infantry.Soldier_RPG, Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Infantry_M4, Infantry.Soldier_M249, + Artillery._2B11_mortar, Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Soldier_AK, Infantry.Paratrooper_RPG_16, Infantry.Georgian_soldier_with_M4, Infantry.Georgian_soldier_with_M4, Infantry.Georgian_soldier_with_M4, diff --git a/game/event/event.py b/game/event/event.py index 4ecd5329..79b68430 100644 --- a/game/event/event.py +++ b/game/event/event.py @@ -152,12 +152,10 @@ class Event: loss.group.units.remove(loss.unit) loss.group.units_losts.append(loss.unit) - if not loss.ground_object.alive_unit_count: - loss.ground_object.is_dead = True def commit_building_losses(self, debriefing: Debriefing) -> None: for loss in debriefing.building_losses: - loss.ground_object.is_dead = True + loss.ground_object.kill() self.game.informations.append(Information( "Building destroyed", f"{loss.ground_object.dcs_identifier} has been destroyed at " diff --git a/game/game.py b/game/game.py index 4ec1f980..516095f9 100644 --- a/game/game.py +++ b/game/game.py @@ -12,7 +12,6 @@ from dcs.task import CAP, CAS, PinpointStrike from dcs.vehicles import AirDefence from game import db -from game.db import PLAYER_BUDGET_BASE, REWARDS from game.inventory import GlobalAircraftInventory from game.models.game_stats import GameStats from game.plugins import LuaPluginManager @@ -27,6 +26,7 @@ from .debriefing import Debriefing from .event.event import Event, UnitsDeliveryEvent from .event.frontlineattack import FrontlineAttackEvent from .factions.faction import Faction +from .income import Income from .infos.information import Information from .procurement import ProcurementAi from .settings import Settings @@ -167,30 +167,14 @@ class Game: front_line.control_point_a, front_line.control_point_b) - @property - def budget_reward_amount(self) -> int: - reward = PLAYER_BUDGET_BASE * len(self.theater.player_points()) - for cp in self.theater.player_points(): - for g in cp.ground_objects: - if g.category in REWARDS.keys() and not g.is_dead: - reward += REWARDS[g.category] - return int(reward * self.settings.player_income_multiplier) - def process_player_income(self): - self.budget += self.budget_reward_amount + self.budget += Income(self, player=True).total def process_enemy_income(self): # TODO: Clean up save compat. if not hasattr(self, "enemy_budget"): self.enemy_budget = 0 - - production = 0.0 - for enemy_point in self.theater.enemy_points(): - for g in enemy_point.ground_objects: - if g.category in REWARDS.keys() and not g.is_dead: - production = production + REWARDS[g.category] - - self.enemy_budget += production * self.settings.enemy_income_multiplier + self.enemy_budget += Income(self, player=False).total def units_delivery_event(self, to_cp: ControlPoint) -> UnitsDeliveryEvent: event = UnitsDeliveryEvent(attacker_name=self.player_name, diff --git a/game/income.py b/game/income.py new file mode 100644 index 00000000..b3fe5ab5 --- /dev/null +++ b/game/income.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +from dataclasses import dataclass +from typing import TYPE_CHECKING + +from game.db import PLAYER_BUDGET_BASE, REWARDS +from game.theater import ControlPoint + +if TYPE_CHECKING: + from game import Game + + +@dataclass(frozen=True) +class BuildingIncome: + name: str + category: str + number: int + income_per_building: int + + @property + def income(self) -> int: + return self.number * self.income_per_building + + +@dataclass(frozen=True) +class ControlPointIncome: + control_point: ControlPoint + income: int + + +class Income: + def __init__(self, game: Game, player: bool) -> None: + if player: + self.multiplier = game.settings.player_income_multiplier + else: + self.multiplier = game.settings.enemy_income_multiplier + self.control_points = [] + self.buildings = [] + + self.income_per_base = PLAYER_BUDGET_BASE if player else 0 + + names = set() + for cp in game.theater.control_points_for(player): + self.control_points.append( + ControlPointIncome(cp, self.income_per_base)) + for tgo in cp.ground_objects: + names.add(tgo.obj_name) + + for name in names: + count = 0 + tgos = game.theater.find_ground_objects_by_obj_name(name) + category = tgos[0].category + if category not in REWARDS: + continue + for tgo in tgos: + if not tgo.is_dead: + count += 1 + self.buildings.append(BuildingIncome(name, category, count, + REWARDS[category])) + + self.from_bases = sum(cp.income for cp in self.control_points) + self.total_buildings = sum(b.income for b in self.buildings) + self.total = ((self.total_buildings + self.from_bases) * + self.multiplier) diff --git a/game/procurement.py b/game/procurement.py index 6852c534..68e0a4f9 100644 --- a/game/procurement.py +++ b/game/procurement.py @@ -1,16 +1,16 @@ from __future__ import annotations -from dataclasses import dataclass import math import random +from dataclasses import dataclass from typing import Iterator, List, Optional, TYPE_CHECKING, Type from dcs.task import CAP, CAS -from dcs.unittype import FlyingType, UnitType, VehicleType +from dcs.unittype import FlyingType, VehicleType from game import db from game.factions.faction import Faction -from game.theater import ControlPoint, MissionTarget +from game.theater import ControlPoint, MissionTarget, TYPE_SHORAD from gen.flights.ai_flight_planner_db import ( capable_aircraft_for_task, preferred_aircraft_for_task, @@ -74,15 +74,25 @@ class ProcurementAi: return budget def random_affordable_ground_unit( - self, budget: int) -> Optional[Type[VehicleType]]: - affordable_units = [u for u in self.faction.frontline_units if + self, budget: int, cp: ControlPoint) -> Optional[Type[VehicleType]]: + affordable_units = [u for u in self.faction.frontline_units + self.faction.artillery_units if db.PRICES[u] <= budget] + + total_number_aa = cp.base.total_frontline_aa + cp.pending_frontline_aa_deliveries_count + total_non_aa = cp.base.total_armor + cp.pending_deliveries_count - total_number_aa + max_aa = math.ceil(total_non_aa/8) + + # Limit the number of AA units the AI will buy + if not total_number_aa < max_aa: + for unit in [u for u in affordable_units if u in TYPE_SHORAD]: + affordable_units.remove(unit) + if not affordable_units: return None return random.choice(affordable_units) def reinforce_front_line(self, budget: int) -> int: - if not self.faction.frontline_units: + if not self.faction.frontline_units and not self.faction.artillery_units: return budget while budget > 0: @@ -91,7 +101,7 @@ class ProcurementAi: break cp = random.choice(candidates) - unit = self.random_affordable_ground_unit(budget) + unit = self.random_affordable_ground_unit(budget, cp) if unit is None: # Can't afford any more units. break diff --git a/game/theater/base.py b/game/theater/base.py index 54b0e4f8..81512f3e 100644 --- a/game/theater/base.py +++ b/game/theater/base.py @@ -9,6 +9,7 @@ from dcs.unittype import FlyingType, UnitType, VehicleType from dcs.vehicles import AirDefence, Armor from game import db +from gen.ground_forces.ai_ground_planner_db import TYPE_SHORAD STRENGTH_AA_ASSEMBLE_MIN = 0.2 PLANES_SCRAMBLE_MIN_BASE = 2 @@ -36,6 +37,10 @@ class Base: def total_armor(self) -> int: return sum(self.armor.values()) + @property + def total_frontline_aa(self) -> int: + return sum([v for k, v in self.armor.items() if k in TYPE_SHORAD]) + @property def total_aa(self) -> int: return sum(self.aa.values()) @@ -98,11 +103,11 @@ class Base: self.armor = {k: v for k, v in self.armor.items() if k in applicable_units} def commision_units(self, units: typing.Dict[typing.Any, int]): - for value in units.values(): - assert value > 0 - assert value == math.floor(value) for unit_type, unit_count in units.items(): + if unit_count <= 0: + continue + for_task = db.unit_task(unit_type) target_dict = None diff --git a/game/theater/conflicttheater.py b/game/theater/conflicttheater.py index 4e180e7a..aef2dd40 100644 --- a/game/theater/conflicttheater.py +++ b/game/theater/conflicttheater.py @@ -503,8 +503,13 @@ class ConflictTheater: ) return new_point + def control_points_for(self, player: bool) -> Iterator[ControlPoint]: + for point in self.controlpoints: + if point.captured == player: + yield point + def player_points(self) -> List[ControlPoint]: - return [point for point in self.controlpoints if point.captured] + return list(self.control_points_for(player=True)) def conflicts(self, from_player=True) -> Iterator[FrontLine]: for cp in [x for x in self.controlpoints if x.captured == from_player]: @@ -512,7 +517,7 @@ class ConflictTheater: yield FrontLine(cp, connected_point, self) def enemy_points(self) -> List[ControlPoint]: - return [point for point in self.controlpoints if not point.captured] + return list(self.control_points_for(player=False)) def closest_control_point(self, point: Point) -> ControlPoint: closest = self.controlpoints[0] diff --git a/game/theater/controlpoint.py b/game/theater/controlpoint.py index 3ec23ede..a22ea097 100644 --- a/game/theater/controlpoint.py +++ b/game/theater/controlpoint.py @@ -20,6 +20,7 @@ from dcs.terrain.terrain import Airport, ParkingSlot from dcs.unittype import FlyingType from game import db +from gen.ground_forces.ai_ground_planner_db import TYPE_SHORAD from gen.runways import RunwayAssigner, RunwayData from gen.ground_forces.combat_stance import CombatStance from .base import Base @@ -457,6 +458,26 @@ class ControlPoint(MissionTarget, ABC): u.position.x = u.position.x + delta.x u.position.y = u.position.y + delta.y + @property + def pending_frontline_aa_deliveries_count(self): + """ + Get number of pending frontline aa units + """ + if self.pending_unit_deliveries: + return sum([v for k,v in self.pending_unit_deliveries.units.items() if k in TYPE_SHORAD]) + else: + return 0 + + @property + def pending_deliveries_count(self): + """ + Get number of pending units + """ + if self.pending_unit_deliveries: + return sum([v for k, v in self.pending_unit_deliveries.units.items()]) + else: + return 0 + class Airfield(ControlPoint): @@ -529,7 +550,6 @@ class NavalControlPoint(ControlPoint, ABC): return True def mission_types(self, for_player: bool) -> Iterator[FlightType]: - yield from super().mission_types(for_player) from gen.flights.flight import FlightType if self.is_friendly(for_player): yield from [ @@ -540,6 +560,7 @@ class NavalControlPoint(ControlPoint, ABC): ] else: yield FlightType.ANTISHIP + yield from super().mission_types(for_player) @property def heading(self) -> int: diff --git a/game/theater/theatergroundobject.py b/game/theater/theatergroundobject.py index 2908d5f3..431de495 100644 --- a/game/theater/theatergroundobject.py +++ b/game/theater/theatergroundobject.py @@ -85,10 +85,13 @@ class TheaterGroundObject(MissionTarget): self.dcs_identifier = dcs_identifier self.airbase_group = airbase_group self.sea_object = sea_object - self.is_dead = False # TODO: There is never more than one group. self.groups: List[Group] = [] + @property + def is_dead(self) -> bool: + return self.alive_unit_count == 0 + @property def units(self) -> List[Unit]: """ @@ -161,6 +164,9 @@ class BuildingGroundObject(TheaterGroundObject): sea_object=False ) self.object_id = object_id + # Other TGOs track deadness based on the number of alive units, but + # buildings don't have groups assigned to the TGO. + self._dead = False @property def group_name(self) -> str: @@ -171,6 +177,15 @@ class BuildingGroundObject(TheaterGroundObject): def waypoint_name(self) -> str: return f"{super().waypoint_name} #{self.object_id}" + @property + def is_dead(self) -> bool: + if not hasattr(self, "_dead"): + self._dead = False + return self._dead + + def kill(self) -> None: + self._dead = True + class NavalGroundObject(TheaterGroundObject): def mission_types(self, for_player: bool) -> Iterator[FlightType]: diff --git a/game/version.py b/game/version.py index c9bfe293..0a4d2acb 100644 --- a/game/version.py +++ b/game/version.py @@ -2,7 +2,7 @@ from pathlib import Path def _build_version_string() -> str: - components = ["2.3.2"] + components = ["2.3.3"] build_number_path = Path("resources/buildnumber") if build_number_path.exists(): with build_number_path.open("r") as build_number_file: diff --git a/gen/aircraft.py b/gen/aircraft.py index 87233d35..42454df4 100644 --- a/gen/aircraft.py +++ b/gen/aircraft.py @@ -1474,10 +1474,7 @@ class BaiIngressBuilder(PydcsWaypointBuilder): target_group = self.package.target if isinstance(target_group, TheaterGroundObject): - # Match search is used due to TheaterGroundObject.name not matching - # the Mission group name because of SkyNet prefixes. - tgroup = self.mission.find_group(target_group.group_name, - search="match") + tgroup = self.mission.find_group(target_group.group_name) if tgroup is not None: task = AttackGroup(tgroup.id, weapon_type=WeaponType.Auto) task.params["attackQtyLimit"] = False @@ -1527,10 +1524,7 @@ class DeadIngressBuilder(PydcsWaypointBuilder): target_group = self.package.target if isinstance(target_group, TheaterGroundObject): - # Match search is used due to TheaterGroundObject.name not matching - # the Mission group name because of SkyNet prefixes. - tgroup = self.mission.find_group(target_group.group_name, - search="match") + tgroup = self.mission.find_group(target_group.group_name) if tgroup is not None: task = AttackGroup(tgroup.id, weapon_type=WeaponType.Guided) task.params["expend"] = "All" @@ -1593,10 +1587,7 @@ class SeadIngressBuilder(PydcsWaypointBuilder): target_group = self.package.target if isinstance(target_group, TheaterGroundObject): - # Match search is used due to TheaterGroundObject.name not matching - # the Mission group name because of SkyNet prefixes. - tgroup = self.mission.find_group(target_group.group_name, - search="match") + tgroup = self.mission.find_group(target_group.group_name) if tgroup is not None: waypoint.add_task(EngageTargetsInZone( position=tgroup.position, diff --git a/gen/armor.py b/gen/armor.py index c02abecf..be4f1397 100644 --- a/gen/armor.py +++ b/gen/armor.py @@ -50,6 +50,8 @@ FIGHT_DISTANCE = 3500 RANDOM_OFFSET_ATTACK = 250 +INFANTRY_GROUP_SIZE = 5 + @dataclass(frozen=True) class JtacInfo: @@ -226,7 +228,7 @@ class GroundConflictGenerator: heading=forward_heading, move_formation=PointAction.OffRoad) - for i in range(random.randint(3, 10)): + for i in range(INFANTRY_GROUP_SIZE): u = random.choice(possible_infantry_units) position = infantry_position.random_point_within(55, 5) self.mission.vehicle_group( @@ -281,7 +283,7 @@ class GroundConflictGenerator: # Hold position dcs_group.points[1].tasks.append(Hold()) - retreat = self.find_retreat_point(dcs_group, heading_sum(forward_heading, 180), (int)(RETREAT_DISTANCE/3)) + retreat = self.find_retreat_point(dcs_group, forward_heading, (int)(RETREAT_DISTANCE/3)) dcs_group.add_waypoint(dcs_group.position.point_from_heading(forward_heading, 1), PointAction.OffRoad) dcs_group.points[2].tasks.append(Hold()) dcs_group.add_waypoint(retreat, PointAction.OffRoad) @@ -675,12 +677,14 @@ class GroundConflictGenerator: else: g.set_skill(self.game.settings.enemy_vehicle_skill) positioned_groups.append((g, group)) - self.gen_infantry_group_for_group( - g, - is_player, - self.mission.country(country), - opposite_heading(spawn_heading) - ) + + if group.role in [CombatGroupRole.APC, CombatGroupRole.IFV]: + self.gen_infantry_group_for_group( + g, + is_player, + self.mission.country(country), + opposite_heading(spawn_heading) + ) else: logging.warning(f"Unable to get valid position for {group}") diff --git a/gen/fleet/cn_dd_group.py b/gen/fleet/cn_dd_group.py index c2b51c88..a8fbdc44 100644 --- a/gen/fleet/cn_dd_group.py +++ b/gen/fleet/cn_dd_group.py @@ -32,6 +32,9 @@ class ChineseNavyGroupGenerator(ShipGroupGenerator): else: include_cc = False + if not any([include_frigate, include_dd, include_cc]): + include_frigate = True + if include_frigate: self.add_unit(Type_054A_Frigate, "FF1", self.position.x + 1200, self.position.y + 900, self.heading) self.add_unit(Type_054A_Frigate, "FF2", self.position.x + 1200, self.position.y - 900, self.heading) diff --git a/gen/fleet/ru_dd_group.py b/gen/fleet/ru_dd_group.py index 69d0af57..d67656a7 100644 --- a/gen/fleet/ru_dd_group.py +++ b/gen/fleet/ru_dd_group.py @@ -35,6 +35,9 @@ class RussianNavyGroupGenerator(ShipGroupGenerator): else: include_cc = False + if not any([include_frigate, include_dd, include_cc]): + include_frigate = True + if include_frigate: frigate_type = random.choice([FFL_1124_4_Grisha, FSG_1241_1MP_Molniya]) self.add_unit(frigate_type, "FF1", self.position.x + 1200, self.position.y + 900, self.heading) diff --git a/gen/ground_forces/ai_ground_planner.py b/gen/ground_forces/ai_ground_planner.py index 650f17cd..e98d82d2 100644 --- a/gen/ground_forces/ai_ground_planner.py +++ b/gen/ground_forces/ai_ground_planner.py @@ -3,180 +3,14 @@ from enum import Enum from typing import Dict, List from dcs.unittype import VehicleType -from dcs.vehicles import Armor, Artillery, Infantry, Unarmed -import pydcs_extensions.frenchpack.frenchpack as frenchpack from game.theater import ControlPoint +from gen.ground_forces.ai_ground_planner_db import * from gen.ground_forces.combat_stance import CombatStance -TYPE_TANKS = [ - Armor.MBT_T_55, - Armor.MBT_T_72B, - Armor.MBT_T_72B3, - Armor.MBT_T_80U, - Armor.MBT_T_90, - Armor.MBT_Leopard_2, - Armor.MBT_Leopard_1A3, - Armor.MBT_Leclerc, - Armor.MBT_Challenger_II, - Armor.MBT_M1A2_Abrams, - Armor.MBT_M60A3_Patton, - Armor.MBT_Merkava_Mk__4, - Armor.ZTZ_96B, - - # WW2 - Armor.MT_Pz_Kpfw_V_Panther_Ausf_G, - Armor.MT_Pz_Kpfw_IV_Ausf_H, - Armor.HT_Pz_Kpfw_VI_Tiger_I, - Armor.HT_Pz_Kpfw_VI_Ausf__B_Tiger_II, - Armor.MT_M4_Sherman, - Armor.MT_M4A4_Sherman_Firefly, - Armor.StuG_IV, - Armor.CT_Centaur_IV, - Armor.CT_Cromwell_IV, - Armor.HIT_Churchill_VII, - Armor.LT_Mk_VII_Tetrarch, - - # Mods - frenchpack.DIM__TOYOTA_BLUE, - frenchpack.DIM__TOYOTA_GREEN, - frenchpack.DIM__TOYOTA_DESERT, - frenchpack.DIM__KAMIKAZE, - - frenchpack.AMX_10RCR, - frenchpack.AMX_10RCR_SEPAR, - frenchpack.AMX_30B2, - frenchpack.Leclerc_Serie_XXI, - -] - -TYPE_ATGM = [ - Armor.ATGM_M1045_HMMWV_TOW, - Armor.ATGM_M1134_Stryker, - Armor.IFV_BMP_2, - - # WW2 (Tank Destroyers) - Armor.M30_Cargo_Carrier, - Armor.TD_Jagdpanzer_IV, - Armor.TD_Jagdpanther_G1, - Armor.TD_M10_GMC, - - # Mods - frenchpack.VBAE_CRAB_MMP, - frenchpack.VAB_MEPHISTO, - frenchpack.TRM_2000_PAMELA, - -] - -TYPE_IFV = [ - Armor.IFV_BMP_3, - Armor.IFV_BMP_2, - Armor.IFV_BMP_1, - Armor.IFV_Marder, - Armor.IFV_MCV_80, - Armor.IFV_LAV_25, - Armor.AC_Sd_Kfz_234_2_Puma, - Armor.IFV_M2A2_Bradley, - Armor.IFV_BMD_1, - Armor.ZBD_04A, - - # WW2 - Armor.AC_Sd_Kfz_234_2_Puma, - Armor.LAC_M8_Greyhound, - Armor.Daimler_Armoured_Car, - - # Mods - frenchpack.ERC_90, - frenchpack.VBAE_CRAB, - frenchpack.VAB_T20_13 - -] - -TYPE_APC = [ - Armor.APC_M1043_HMMWV_Armament, - Armor.APC_M1126_Stryker_ICV, - Armor.APC_M113, - Armor.APC_BTR_80, - Armor.APC_BTR_82A, - Armor.APC_MTLB, - Armor.APC_M2A1, - Armor.APC_Cobra, - Armor.APC_Sd_Kfz_251, - Armor.APC_AAV_7, - Armor.TPz_Fuchs, - Armor.ARV_BRDM_2, - Armor.ARV_BTR_RD, - Armor.FDDM_Grad, - - # WW2 - Armor.APC_M2A1, - Armor.APC_Sd_Kfz_251, - - # Mods - frenchpack.VAB__50, - frenchpack.VBL__50, - frenchpack.VBL_AANF1, - -] - -TYPE_ARTILLERY = [ - Artillery.MLRS_9A52_Smerch, - Artillery.SPH_2S1_Gvozdika, - Artillery.SPH_2S3_Akatsia, - Artillery.MLRS_BM_21_Grad, - Artillery.MLRS_9K57_Uragan_BM_27, - Artillery.SPH_M109_Paladin, - Artillery.MLRS_M270, - Artillery.SPH_2S9_Nona, - Artillery.SpGH_Dana, - Artillery.SPH_2S19_Msta, - Artillery.MLRS_FDDM, - - # WW2 - Artillery.Sturmpanzer_IV_Brummbär, - Artillery.M12_GMC -] - -TYPE_LOGI = [ - Unarmed.Transport_M818, - Unarmed.Transport_KAMAZ_43101, - Unarmed.Transport_Ural_375, - Unarmed.Transport_GAZ_66, - Unarmed.Transport_GAZ_3307, - Unarmed.Transport_GAZ_3308, - Unarmed.Transport_Ural_4320_31_Armored, - Unarmed.Transport_Ural_4320T, - Unarmed.Blitz_3_6_6700A, - Unarmed.Kübelwagen_82, - Unarmed.Sd_Kfz_7, - Unarmed.Sd_Kfz_2, - Unarmed.Willys_MB, - Unarmed.Land_Rover_109_S3, - Unarmed.Land_Rover_101_FC, - - # Mods - frenchpack.VBL, - frenchpack.VAB, - -] - -TYPE_INFANTRY = [ - Infantry.Infantry_Soldier_Insurgents, - Infantry.Soldier_AK, - Infantry.Infantry_M1_Garand, - Infantry.Infantry_Mauser_98, - Infantry.Infantry_SMLE_No_4_Mk_1, - Infantry.Georgian_soldier_with_M4, - Infantry.Infantry_Soldier_Rus, - Infantry.Paratrooper_AKS, - Infantry.Paratrooper_RPG_16, - Infantry.Soldier_M249, - Infantry.Infantry_M4, - Infantry.Soldier_RPG, -] - MAX_COMBAT_GROUP_PER_CP = 10 + class CombatGroupRole(Enum): TANK = 1 APC = 2 @@ -224,6 +58,7 @@ class CombatGroup: s += "UNITS " + self.units[0].name + " * " + str(len(self.units)) return s + class GroundPlanner: def __init__(self, cp:ControlPoint, game): @@ -243,7 +78,6 @@ class GroundPlanner: self.units_per_cp[cp.id] = [] self.reserve: List[CombatGroup] = [] - def plan_groundwar(self): if hasattr(self.cp, 'stance'): @@ -275,6 +109,9 @@ class GroundPlanner: elif key in TYPE_ATGM: collection = self.atgm_group role = CombatGroupRole.ATGM + elif key in TYPE_SHORAD: + collection = self.shorad_groups + role = CombatGroupRole.SHORAD else: print("Warning unit type not handled by ground generator") print(key) @@ -282,12 +119,16 @@ class GroundPlanner: available = self.cp.base.armor[key] while available > 0: - n = random.choice(group_size_choice) - if n > available: - if available >= 2: - n = 2 - else: - n = 1 + + if role == CombatGroupRole.SHORAD: + n = 1 + else: + n = random.choice(group_size_choice) + if n > available: + if available >= 2: + n = 2 + else: + n = 1 available -= n group = CombatGroup(role) diff --git a/gen/ground_forces/ai_ground_planner_db.py b/gen/ground_forces/ai_ground_planner_db.py new file mode 100644 index 00000000..c448611d --- /dev/null +++ b/gen/ground_forces/ai_ground_planner_db.py @@ -0,0 +1,199 @@ +from dcs.vehicles import AirDefence, Infantry, Unarmed, Artillery, Armor + +from pydcs_extensions.frenchpack import frenchpack + +TYPE_TANKS = [ + Armor.MBT_T_55, + Armor.MBT_T_72B, + Armor.MBT_T_72B3, + Armor.MBT_T_80U, + Armor.MBT_T_90, + Armor.MBT_Leopard_2, + Armor.MBT_Leopard_1A3, + Armor.MBT_Leclerc, + Armor.MBT_Challenger_II, + Armor.MBT_M1A2_Abrams, + Armor.MBT_M60A3_Patton, + Armor.MBT_Merkava_Mk__4, + Armor.ZTZ_96B, + + # WW2 + Armor.MT_Pz_Kpfw_V_Panther_Ausf_G, + Armor.MT_Pz_Kpfw_IV_Ausf_H, + Armor.HT_Pz_Kpfw_VI_Tiger_I, + Armor.HT_Pz_Kpfw_VI_Ausf__B_Tiger_II, + Armor.MT_M4_Sherman, + Armor.MT_M4A4_Sherman_Firefly, + Armor.StuG_IV, + Armor.CT_Centaur_IV, + Armor.CT_Cromwell_IV, + Armor.HIT_Churchill_VII, + Armor.LT_Mk_VII_Tetrarch, + + # Mods + frenchpack.DIM__TOYOTA_BLUE, + frenchpack.DIM__TOYOTA_GREEN, + frenchpack.DIM__TOYOTA_DESERT, + frenchpack.DIM__KAMIKAZE, + + frenchpack.AMX_10RCR, + frenchpack.AMX_10RCR_SEPAR, + frenchpack.AMX_30B2, + frenchpack.Leclerc_Serie_XXI, + +] + +TYPE_ATGM = [ + Armor.ATGM_M1045_HMMWV_TOW, + Armor.ATGM_M1134_Stryker, + Armor.IFV_BMP_2, + + # WW2 (Tank Destroyers) + Armor.M30_Cargo_Carrier, + Armor.TD_Jagdpanzer_IV, + Armor.TD_Jagdpanther_G1, + Armor.TD_M10_GMC, + + # Mods + frenchpack.VBAE_CRAB_MMP, + frenchpack.VAB_MEPHISTO, + frenchpack.TRM_2000_PAMELA, + +] + +TYPE_IFV = [ + Armor.IFV_BMP_3, + Armor.IFV_BMP_2, + Armor.IFV_BMP_1, + Armor.IFV_Marder, + Armor.IFV_MCV_80, + Armor.IFV_LAV_25, + Armor.SPG_M1128_Stryker_MGS, + Armor.AC_Sd_Kfz_234_2_Puma, + Armor.IFV_M2A2_Bradley, + Armor.IFV_BMD_1, + Armor.ZBD_04A, + + # WW2 + Armor.AC_Sd_Kfz_234_2_Puma, + Armor.LAC_M8_Greyhound, + Armor.Daimler_Armoured_Car, + + # Mods + frenchpack.ERC_90, + frenchpack.VBAE_CRAB, + frenchpack.VAB_T20_13 + +] + +TYPE_APC = [ + Armor.APC_M1043_HMMWV_Armament, + Armor.APC_M1126_Stryker_ICV, + Armor.APC_M113, + Armor.APC_BTR_80, + Armor.APC_BTR_82A, + Armor.APC_MTLB, + Armor.APC_M2A1, + Armor.APC_Cobra, + Armor.APC_Sd_Kfz_251, + Armor.APC_AAV_7, + Armor.TPz_Fuchs, + Armor.ARV_BRDM_2, + Armor.ARV_BTR_RD, + Armor.FDDM_Grad, + + # WW2 + Armor.APC_M2A1, + Armor.APC_Sd_Kfz_251, + + # Mods + frenchpack.VAB__50, + frenchpack.VBL__50, + frenchpack.VBL_AANF1, + +] + +TYPE_ARTILLERY = [ + Artillery.MLRS_9A52_Smerch, + Artillery.SPH_2S1_Gvozdika, + Artillery.SPH_2S3_Akatsia, + Artillery.MLRS_BM_21_Grad, + Artillery.MLRS_9K57_Uragan_BM_27, + Artillery.SPH_M109_Paladin, + Artillery.MLRS_M270, + Artillery.SPH_2S9_Nona, + Artillery.SpGH_Dana, + Artillery.SPH_2S19_Msta, + Artillery.MLRS_FDDM, + + # WW2 + Artillery.Sturmpanzer_IV_Brummbär, + Artillery.M12_GMC +] + +TYPE_LOGI = [ + Unarmed.Transport_M818, + Unarmed.Transport_KAMAZ_43101, + Unarmed.Transport_Ural_375, + Unarmed.Transport_GAZ_66, + Unarmed.Transport_GAZ_3307, + Unarmed.Transport_GAZ_3308, + Unarmed.Transport_Ural_4320_31_Armored, + Unarmed.Transport_Ural_4320T, + Unarmed.Blitz_3_6_6700A, + Unarmed.Kübelwagen_82, + Unarmed.Sd_Kfz_7, + Unarmed.Sd_Kfz_2, + Unarmed.Willys_MB, + Unarmed.Land_Rover_109_S3, + Unarmed.Land_Rover_101_FC, + + # Mods + frenchpack.VBL, + frenchpack.VAB, + +] + +TYPE_INFANTRY = [ + Infantry.Infantry_Soldier_Insurgents, + Infantry.Soldier_AK, + Infantry.Infantry_M1_Garand, + Infantry.Infantry_Mauser_98, + Infantry.Infantry_SMLE_No_4_Mk_1, + Infantry.Georgian_soldier_with_M4, + Infantry.Infantry_Soldier_Rus, + Infantry.Paratrooper_AKS, + Infantry.Paratrooper_RPG_16, + Infantry.Soldier_M249, + Infantry.Infantry_M4, + Infantry.Soldier_RPG, +] + +TYPE_SHORAD = [ + AirDefence.AAA_ZU_23_on_Ural_375, + AirDefence.AAA_ZU_23_Insurgent_on_Ural_375, + AirDefence.AAA_ZSU_57_2, + AirDefence.SPAAA_ZSU_23_4_Shilka, + AirDefence.SAM_SA_8_Osa_9A33, + AirDefence.SAM_SA_9_Strela_1_9P31, + AirDefence.SAM_SA_13_Strela_10M3_9A35M3, + AirDefence.SAM_SA_15_Tor_9A331, + AirDefence.SAM_SA_19_Tunguska_2S6, + + AirDefence.SPAAA_Gepard, + AirDefence.AAA_Vulcan_M163, + AirDefence.SAM_Linebacker_M6, + AirDefence.SAM_Chaparral_M48, + AirDefence.SAM_Avenger_M1097, + AirDefence.SAM_Roland_ADS, + AirDefence.HQ_7_Self_Propelled_LN, + + AirDefence.AAA_8_8cm_Flak_18, + AirDefence.AAA_8_8cm_Flak_36, + AirDefence.AAA_8_8cm_Flak_37, + AirDefence.AAA_8_8cm_Flak_41, + AirDefence.AAA_Bofors_40mm, + AirDefence.AAA_M1_37mm, + AirDefence.AA_gun_QF_3_7, + +] diff --git a/gen/groundobjectsgen.py b/gen/groundobjectsgen.py index ea18eb46..57a5544e 100644 --- a/gen/groundobjectsgen.py +++ b/gen/groundobjectsgen.py @@ -9,20 +9,21 @@ from __future__ import annotations import logging import random -from typing import Dict, Iterator, Optional, TYPE_CHECKING, Type +from typing import Dict, Iterator, Optional, TYPE_CHECKING, Type, List -from dcs import Mission +from dcs import Mission, Point from dcs.country import Country from dcs.statics import fortification_map, warehouse_map from dcs.task import ( ActivateBeaconCommand, ActivateICLSCommand, EPLRS, - OptAlarmState, + OptAlarmState, FireAtPoint, ) from dcs.unit import Ship, Unit, Vehicle from dcs.unitgroup import Group, ShipGroup, StaticGroup, VehicleGroup from dcs.unittype import StaticType, UnitType +from dcs.vehicles import vehicle_map from game import db from game.data.building_data import FORTIFICATION_UNITS, FORTIFICATION_UNITS_ID @@ -31,7 +32,7 @@ from game.theater import ControlPoint, TheaterGroundObject from game.theater.theatergroundobject import ( BuildingGroundObject, CarrierGroundObject, GenericCarrierGroundObject, - LhaGroundObject, ShipGroundObject, + LhaGroundObject, ShipGroundObject, MissileSiteGroundObject, ) from game.unitmap import UnitMap from game.utils import knots_to_kph, kph_to_mps, mps_to_kph @@ -50,7 +51,7 @@ AA_CP_MIN_DISTANCE = 40000 class GenericGroundObjectGenerator: """An unspecialized ground object generator. - Currently used only for SAM and missile (V1/V2) sites. + Currently used only for SAM """ def __init__(self, ground_object: TheaterGroundObject, country: Country, game: Game, mission: Mission, unit_map: UnitMap) -> None: @@ -111,6 +112,55 @@ class GenericGroundObjectGenerator: persistence_group, miz_group) +class MissileSiteGenerator(GenericGroundObjectGenerator): + + def generate(self) -> None: + super(MissileSiteGenerator, self).generate() + # Note : Only the SCUD missiles group can fire (V1 site cannot fire in game right now) + # TODO : Should be pre-planned ? + # TODO : Add delay to task to spread fire task over mission duration ? + for group in self.ground_object.groups: + vg = self.m.find_group(group.name) + targets = self.possible_missile_targets(vg) + if vg is not None and targets: + target = random.choice(targets) + real_target = target.point_from_heading(random.randint(0, 360), random.randint(0, 2500)) + vg.points[0].add_task(FireAtPoint(real_target)) + logging.info("Set up fire task for missile group.") + else: + logging.info("Couldn't setup missile site to fire, group was not generated.") + + def possible_missile_targets(self, vg: Group) -> List[Point]: + """ + Find enemy control points in range + :param vg: Vehicle group we are searching a target for (There is always only oe group right now) + :return: List of possible missile targets + """ + targets: List[Point] = [] + for cp in self.game.theater.controlpoints: + if cp.captured != self.ground_object.control_point.captured: + distance = cp.position.distance_to_point(vg.position) + if distance < self.missile_site_range: + targets.append(cp.position) + return targets + + @property + def missile_site_range(self) -> int: + """ + Get the missile site range + :return: Missile site range + """ + site_range = 0 + for group in self.ground_object.groups: + vg = self.m.find_group(group.name) + if vg is not None: + for u in vg.units: + if u.type in vehicle_map: + if vehicle_map[u.type].threat_range > site_range: + site_range = vehicle_map[u.type].threat_range + return site_range + + class BuildingSiteGenerator(GenericGroundObjectGenerator): """Generator for building sites. @@ -421,8 +471,11 @@ class GroundObjectsGenerator: generator = ShipObjectGenerator( ground_object, country, self.game, self.m, self.unit_map) + elif isinstance(ground_object, MissileSiteGroundObject): + generator = MissileSiteGenerator( + ground_object, country, self.game, self.m, + self.unit_map) else: - generator = GenericGroundObjectGenerator( ground_object, country, self.game, self.m, self.unit_map) diff --git a/pydcs b/pydcs index edc87fab..059c88c9 160000 --- a/pydcs +++ b/pydcs @@ -1 +1 @@ -Subproject commit edc87fab1d65d4e4153c84006f537e6ae6b0671a +Subproject commit 059c88c91b5be4b5b6406249a52527c3ccea3db9 diff --git a/qt_ui/widgets/QBudgetBox.py b/qt_ui/widgets/QBudgetBox.py index ad1d66a4..f732b685 100644 --- a/qt_ui/widgets/QBudgetBox.py +++ b/qt_ui/widgets/QBudgetBox.py @@ -1,6 +1,7 @@ from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox, QPushButton import qt_ui.uiconstants as CONST +from game.income import Income from qt_ui.windows.finances.QFinancesMenu import QFinancesMenu @@ -41,7 +42,7 @@ class QBudgetBox(QGroupBox): return self.game = game - self.setBudget(self.game.budget, self.game.budget_reward_amount) + self.setBudget(self.game.budget, Income(self.game, player=True).total) self.finances.setEnabled(True) def openFinances(self): diff --git a/qt_ui/widgets/QIntelBox.py b/qt_ui/widgets/QIntelBox.py new file mode 100644 index 00000000..3925baf3 --- /dev/null +++ b/qt_ui/widgets/QIntelBox.py @@ -0,0 +1,107 @@ +from typing import Optional + +from PySide2.QtWidgets import ( + QGridLayout, + QGroupBox, + QHBoxLayout, + QLabel, + QPushButton, +) + +from game import Game +from game.income import Income +from qt_ui.windows.intel import IntelWindow + + +class QIntelBox(QGroupBox): + def __init__(self, game: Game) -> None: + super().__init__("Intel") + self.setProperty("style", "IntelSummary") + + self.game = game + + columns = QHBoxLayout() + self.setLayout(columns) + + summary = QGridLayout() + columns.addLayout(summary) + + summary.addWidget(QLabel("Air superiority:"), 0, 0) + self.air_strength = QLabel() + summary.addWidget(self.air_strength, 0, 1) + + summary.addWidget(QLabel("Front line:"), 1, 0) + self.ground_strength = QLabel() + summary.addWidget(self.ground_strength, 1, 1) + + summary.addWidget(QLabel("Economic strength:"), 2, 0) + self.economic_strength = QLabel() + summary.addWidget(self.economic_strength, 2, 1) + + details = QPushButton("Details") + columns.addWidget(details) + details.clicked.connect(self.open_details_window) + + self.update_summary() + + self.details_window: Optional[IntelWindow] = None + + def set_game(self, game: Optional[Game]) -> None: + self.game = game + self.update_summary() + + @staticmethod + def forces_strength_text(own: int, enemy: int) -> str: + if not enemy: + return "enemy eliminated" + + ratio = own / enemy + if ratio < 0.6: + return "outnumbered" + if ratio < 0.8: + return "slightly outnumbered" + if ratio < 1.2: + return "evenly matched" + if ratio < 1.4: + return "slight advantage" + return "strong advantage" + + def economic_strength_text(self) -> str: + assert self.game is not None + own = Income(self.game, player=True).total + enemy = Income(self.game, player=False).total + + if not enemy: + return "enemy economy ruined" + + ratio = own / enemy + if ratio < 0.6: + return "strong disadvantage" + if ratio < 0.8: + return "slight disadvantage" + if ratio < 1.2: + return "evenly matched" + if ratio < 1.4: + return "slight advantage" + return "strong advantage" + + def update_summary(self) -> None: + if self.game is None: + self.air_strength.setText("no data") + self.ground_strength.setText("no data") + self.economic_strength.setText("no data") + return + + data = self.game.game_stats.data_per_turn[-1] + + self.air_strength.setText(self.forces_strength_text( + data.allied_units.aircraft_count, + data.enemy_units.aircraft_count)) + self.ground_strength.setText(self.forces_strength_text( + data.allied_units.vehicles_count, + data.enemy_units.vehicles_count)) + self.economic_strength.setText(self.economic_strength_text()) + + def open_details_window(self) -> None: + self.details_window = IntelWindow(self.game) + self.details_window.show() diff --git a/qt_ui/widgets/QTopPanel.py b/qt_ui/widgets/QTopPanel.py index 8fe1c347..6bf558ee 100644 --- a/qt_ui/widgets/QTopPanel.py +++ b/qt_ui/widgets/QTopPanel.py @@ -16,6 +16,7 @@ from gen.flights.traveltime import TotEstimator from qt_ui.models import GameModel from qt_ui.widgets.QBudgetBox import QBudgetBox from qt_ui.widgets.QFactionsInfos import QFactionsInfos +from qt_ui.widgets.QIntelBox import QIntelBox from qt_ui.widgets.clientslots import MaxPlayerCount from qt_ui.windows.GameUpdateSignal import GameUpdateSignal from qt_ui.windows.QWaitingForMissionResultWindow import \ @@ -71,6 +72,8 @@ class QTopPanel(QFrame): self.statistics.setProperty("style", "btn-primary") self.statistics.clicked.connect(self.openStatisticsWindow) + self.intel_box = QIntelBox(self.game) + self.buttonBox = QGroupBox("Misc") self.buttonBoxLayout = QHBoxLayout() self.buttonBoxLayout.addWidget(self.settings) @@ -90,6 +93,7 @@ class QTopPanel(QFrame): self.layout.addWidget(self.factionsInfos) self.layout.addWidget(self.conditionsWidget) self.layout.addWidget(self.budgetBox) + self.layout.addWidget(self.intel_box) self.layout.addWidget(self.buttonBox) self.layout.addStretch(1) self.layout.addWidget(self.proceedBox) @@ -106,6 +110,7 @@ class QTopPanel(QFrame): self.statistics.setEnabled(True) self.conditionsWidget.setCurrentTurn(game.turn, game.conditions) + self.intel_box.set_game(game) self.budgetBox.setGame(game) self.factionsInfos.setGame(game) diff --git a/qt_ui/widgets/map/QMapControlPoint.py b/qt_ui/widgets/map/QMapControlPoint.py index 8249d33a..e8607ff3 100644 --- a/qt_ui/widgets/map/QMapControlPoint.py +++ b/qt_ui/widgets/map/QMapControlPoint.py @@ -4,7 +4,7 @@ from PySide2.QtGui import QColor, QPainter from PySide2.QtWidgets import QAction, QMenu import qt_ui.uiconstants as const -from game.theater import ControlPoint +from game.theater import ControlPoint, NavalControlPoint from qt_ui.models import GameModel from qt_ui.windows.basemenu.QBaseMenu2 import QBaseMenu2 from .QMapObject import QMapObject @@ -108,7 +108,8 @@ class QMapControlPoint(QMapObject): def open_new_package_dialog(self) -> None: """Extends the default packagedialog to redirect to base menu for red air base.""" - if not self.control_point.captured: - self.on_click() - else: - super(QMapControlPoint, self).open_new_package_dialog() + is_navy = isinstance(self.control_point, NavalControlPoint) + if self.control_point.captured or is_navy: + super().open_new_package_dialog() + return + self.on_click() diff --git a/qt_ui/widgets/map/QMapObject.py b/qt_ui/widgets/map/QMapObject.py index 16f07061..a12feb33 100644 --- a/qt_ui/widgets/map/QMapObject.py +++ b/qt_ui/widgets/map/QMapObject.py @@ -47,7 +47,7 @@ class QMapObject(QGraphicsRectItem): object_details_action.triggered.connect(self.on_click) menu.addAction(object_details_action) - # Not all locations have valid objetives. Off-map spawns, for example, + # Not all locations have valid objectives. Off-map spawns, for example, # have no mission types. if list(self.mission_target.mission_types(for_player=True)): new_package_action = QAction(f"New package") diff --git a/qt_ui/windows/basemenu/base_defenses/QBaseInformation.py b/qt_ui/windows/basemenu/base_defenses/QBaseInformation.py index 3c920080..7db68d8c 100644 --- a/qt_ui/windows/basemenu/base_defenses/QBaseInformation.py +++ b/qt_ui/windows/basemenu/base_defenses/QBaseInformation.py @@ -7,7 +7,8 @@ from PySide2.QtWidgets import ( QWidget, ) -from game.theater import Airport, ControlPoint +from game.theater import Airport, ControlPoint, Fob +from game.theater.theatergroundobject import BuildingGroundObject from qt_ui.windows.basemenu.base_defenses.QBaseDefenseGroupInfo import \ QBaseDefenseGroupInfo @@ -30,9 +31,18 @@ class QBaseInformation(QFrame): scroll_content.setLayout(task_box_layout) for g in self.cp.ground_objects: - if g.airbase_group and len(g.groups) > 0: - group_info = QBaseDefenseGroupInfo(self.cp, g, self.game) - task_box_layout.addWidget(group_info) + # Airbase groups are the objects that are hidden on the map because + # they're shown in the base menu. + if not g.airbase_group: + continue + + # Of these, we need to ignore the FOB structure itself since that's + # not supposed to be targetable. + if isinstance(self.cp, Fob) and isinstance(g, BuildingGroundObject): + continue + + group_info = QBaseDefenseGroupInfo(self.cp, g, self.game) + task_box_layout.addWidget(group_info) scroll_content.setLayout(task_box_layout) scroll = QScrollArea() diff --git a/qt_ui/windows/finances/QFinancesMenu.py b/qt_ui/windows/finances/QFinancesMenu.py index 67cd27c9..3dfb195b 100644 --- a/qt_ui/windows/finances/QFinancesMenu.py +++ b/qt_ui/windows/finances/QFinancesMenu.py @@ -1,19 +1,69 @@ -from PySide2.QtWidgets import QDialog, QGridLayout, QLabel, QFrame, QSizePolicy +from PySide2.QtWidgets import ( + QDialog, + QFrame, + QGridLayout, + QLabel, + QSizePolicy, +) import qt_ui.uiconstants as CONST -from game.db import REWARDS, PLAYER_BUDGET_BASE from game.game import Game +from game.income import Income 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) + 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 FinancesLayout(QGridLayout): + def __init__(self, game: Game, player: bool) -> None: + super().__init__() + + income = Income(game, player) + + self.addWidget(QLabel("Control Points"), 0, 0) + self.addWidget(QLabel( + f"{len(income.control_points)} bases x {income.income_per_base}M"), + 0, 1) + self.addWidget(QLabel(f"{income.from_bases}M"), 0, 2) + + self.addWidget(QHorizontalSeparationLine(), 1, 0, 1, 3) + + buildings = reversed(sorted(income.buildings, key=lambda b: b.income)) + row = 2 + for row, building in enumerate(buildings, row): + self.addWidget( + QLabel(f"{building.category.upper()} [{building.name}]"), + row, 0) + self.addWidget(QLabel( + f"{building.number} buildings x {building.income_per_building}M"), + row, 1) + rlabel = QLabel(f"{building.income}M") + rlabel.setProperty("style", "green") + self.addWidget(rlabel, row, 2) + + self.addWidget(QHorizontalSeparationLine(), row + 1, 0, 1, 3) + self.addWidget(QLabel( + f"Income multiplier: {income.multiplier:.1f}"), + row + 2, 1 + ) + self.addWidget(QLabel(f"{income.total}M"), row + 2, 2) + + if player: + budget = game.budget + else: + budget = game.enemy_budget + self.addWidget(QLabel(f"Balance"), row + 3, 1) + self.addWidget(QLabel(f"{budget}M"), row + 3, 2) + self.setRowStretch(row + 4, 1) + class QFinancesMenu(QDialog): @@ -26,49 +76,4 @@ class QFinancesMenu(QDialog): self.setWindowIcon(CONST.ICONS["Money"]) self.setMinimumSize(450, 200) - reward = PLAYER_BUDGET_BASE * len(self.game.theater.player_points()) - layout = QGridLayout() - layout.addWidget(QLabel("Control Points"), 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("" + g.category.upper() + " [" + obj_name + "]"), 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( - f"Income multiplier: {game.settings.player_income_multiplier:.1f}"), - i + 2, 1 - ) - layout.addWidget( - QLabel("" + str(self.game.budget_reward_amount) + "M "), - i + 2, 2) + self.setLayout(FinancesLayout(game, player=True)) diff --git a/qt_ui/windows/groundobject/QGroundObjectMenu.py b/qt_ui/windows/groundobject/QGroundObjectMenu.py index d6907950..dfbc5c11 100644 --- a/qt_ui/windows/groundobject/QGroundObjectMenu.py +++ b/qt_ui/windows/groundobject/QGroundObjectMenu.py @@ -21,6 +21,7 @@ from game import Game, db from game.data.building_data import FORTIFICATION_BUILDINGS from game.db import PRICES, PinpointStrike, REWARDS, unit_type_of from game.theater import ControlPoint, TheaterGroundObject +from game.theater.theatergroundobject import NavalGroundObject from gen.defenses.armor_group_generator import \ generate_armor_group_of_type_and_size from gen.sam.sam_group_generator import get_faction_possible_sams_generator @@ -81,9 +82,10 @@ class QGroundObjectMenu(QDialog): self.buy_replace.clicked.connect(self.buy_group) self.buy_replace.setProperty("style", "btn-success") - if self.total_value > 0: - self.actionLayout.addWidget(self.sell_all_button) - self.actionLayout.addWidget(self.buy_replace) + if not isinstance(self.ground_object, NavalGroundObject): + if self.total_value > 0: + self.actionLayout.addWidget(self.sell_all_button) + self.actionLayout.addWidget(self.buy_replace) if self.cp.captured and self.ground_object.dcs_identifier == "AA": self.mainLayout.addLayout(self.actionLayout) diff --git a/qt_ui/windows/intel.py b/qt_ui/windows/intel.py new file mode 100644 index 00000000..497d65fb --- /dev/null +++ b/qt_ui/windows/intel.py @@ -0,0 +1,147 @@ +import itertools + +from PySide2.QtWidgets import ( + QDialog, + QFrame, + QGridLayout, + QLabel, + QLayout, + QScrollArea, + QSizePolicy, + QSpacerItem, + QTabWidget, + QVBoxLayout, + QWidget, +) + +from game.game import Game +from qt_ui.uiconstants import ICONS +from qt_ui.windows.finances.QFinancesMenu import FinancesLayout + + +class ScrollingFrame(QFrame): + def __init__(self) -> None: + super().__init__() + + widget = QWidget() + scroll_area = QScrollArea() + scroll_area.setWidgetResizable(True) + scroll_area.setWidget(widget) + + self.scrolling_layout = QVBoxLayout() + widget.setLayout(self.scrolling_layout) + + self.setLayout(QVBoxLayout()) + self.layout().addWidget(scroll_area) + + def addWidget(self, widget: QWidget, *args, **kwargs) -> None: + self.scrolling_layout.addWidget(widget, *args, **kwargs) + + def addLayout(self, layout: QLayout, *args, **kwargs) -> None: + self.scrolling_layout.addLayout(layout, *args, **kwargs) + + +class EconomyIntelTab(ScrollingFrame): + def __init__(self, game: Game) -> None: + super().__init__() + self.addLayout(FinancesLayout(game, player=False)) + + +class IntelTableLayout(QGridLayout): + def __init__(self) -> None: + super().__init__() + self.row = itertools.count(0) + + def add_header(self, text: str) -> None: + self.addWidget(QLabel(f"{text}"), next(self.row), 0) + + def add_spacer(self) -> None: + self.addItem( + QSpacerItem(0, 0, QSizePolicy.Preferred, QSizePolicy.Expanding), + next(self.row), 0) + + def add_row(self, text: str, count: int) -> None: + row = next(self.row) + self.addWidget(QLabel(text), row, 0) + self.addWidget(QLabel(str(count)), row, 1) + + +class AircraftIntelLayout(IntelTableLayout): + def __init__(self, game: Game, player: bool) -> None: + super().__init__() + + total = 0 + for control_point in game.theater.control_points_for(player): + base = control_point.base + total += base.total_aircraft + if not base.total_aircraft: + continue + + self.add_header(control_point.name) + for airframe, count in base.aircraft.items(): + if not count: + continue + self.add_row(airframe.id, count) + + self.add_spacer() + self.add_row("Total", total) + + +class AircraftIntelTab(ScrollingFrame): + def __init__(self, game: Game) -> None: + super().__init__() + self.addLayout(AircraftIntelLayout(game, player=False)) + + +class ArmyIntelLayout(IntelTableLayout): + def __init__(self, game: Game, player: bool) -> None: + super().__init__() + + total = 0 + for control_point in game.theater.control_points_for(player): + base = control_point.base + total += base.total_armor + if not base.total_armor: + continue + + self.add_header(control_point.name) + for vehicle, count in base.armor.items(): + if not count: + continue + self.add_row(vehicle.id, count) + + self.add_spacer() + self.add_row("Total", total) + + +class ArmyIntelTab(ScrollingFrame): + def __init__(self, game: Game) -> None: + super().__init__() + self.addLayout(ArmyIntelLayout(game, player=False)) + + +class IntelTabs(QTabWidget): + + def __init__(self, game: Game): + super().__init__() + + self.addTab(EconomyIntelTab(game), "Economy") + self.addTab(AircraftIntelTab(game), "Air forces") + self.addTab(ArmyIntelTab(game), "Ground forces") + + +class IntelWindow(QDialog): + + def __init__(self, game: Game): + super().__init__() + + self.game = game + self.setModal(True) + self.setWindowTitle("Intelligence") + self.setWindowIcon(ICONS["Statistics"]) + self.setMinimumSize(600, 500) + + layout = QVBoxLayout() + self.setLayout(layout) + + layout.addWidget(IntelTabs(game), stretch=1) diff --git a/qt_ui/windows/newgame/QNewGameWizard.py b/qt_ui/windows/newgame/QNewGameWizard.py index 3a14fafb..7838af3c 100644 --- a/qt_ui/windows/newgame/QNewGameWizard.py +++ b/qt_ui/windows/newgame/QNewGameWizard.py @@ -81,7 +81,7 @@ class NewGameWizard(QtWidgets.QWizard): enemy_budget=int(self.field("enemy_starting_money")), # QSlider forces integers, so we use 1 to 50 and divide by 10 to # give 0.1 to 5.0. - midgame=self.field("midGame"), + midgame=False, inverted=self.field("invertMap"), no_carrier=self.field("no_carrier"), no_lha=self.field("no_lha"), @@ -271,10 +271,10 @@ class TheaterConfiguration(QtWidgets.QWizardPage): mapSettingsLayout.addWidget(QtWidgets.QLabel("Invert Map"), 0, 0) mapSettingsLayout.addWidget(invertMap, 0, 1) - mapSettingsLayout.addWidget(QtWidgets.QLabel("Start at mid game"), 1, 0) - midgame = QtWidgets.QCheckBox() - self.registerField('midGame', midgame) - mapSettingsLayout.addWidget(midgame, 1, 1) + #mapSettingsLayout.addWidget(QtWidgets.QLabel("Start at mid game"), 1, 0) + #midgame = QtWidgets.QCheckBox() + #self.registerField('midGame', midgame) + #mapSettingsLayout.addWidget(midgame, 1, 1) mapSettingsGroup.setLayout(mapSettingsLayout) # Time Period diff --git a/resources/campaigns/emirates.json b/resources/campaigns/emirates.json index 147295e3..6579d3e8 100644 --- a/resources/campaigns/emirates.json +++ b/resources/campaigns/emirates.json @@ -3,106 +3,5 @@ "theater": "Persian Gulf", "authors": "Khopa", "description": "

In this scenario, you can play an invasion of the Emirates and Oman, where your forces starts in Fujairah.

Note: Fujairah airfield has very few slots for aircrafts, so it recommended to operate from carriers at the start of the campaign. Thus, a carrier-capable faction is recommended.

", - "player_points": [ - { - "type": "airbase", - "id": "Fujairah Intl", - "radials": [ - 180, - 225, - 270, - 315, - 0 - ], - "size": 1000, - "importance": 1, - "captured_invert": true - }, - { - "type": "lha", - "id": 1002, - "x": -79770, - "y": 49430, - "captured_invert": true - }, - { - "type": "carrier", - "id": 1001, - "x": -61770, - "y": 69039, - "captured_invert": true - } - ], - "enemy_points": [ - { - "type": "airbase", - "id": "Al Dhafra AB", - "size": 2000, - "importance": 1.2 - }, - { - "type": "airbase", - "id": "Al Ain International Airport", - "size": 2000, - "importance": 1 - }, - { - "type": "airbase", - "id": "Al Maktoum Intl", - "size": 2000, - "importance": 1 - }, - { - "type": "airbase", - "id": "Al Minhad AB", - "size": 1000, - "importance": 1 - }, - { - "type": "airbase", - "id": "Sharjah Intl", - "size": 2000, - "importance": 1 - }, - { - "type": "airbase", - "id": "Ras Al Khaimah", - "size": 1000, - "importance": 1 - } - ], - "links": [ - [ - "Al Ain International Airport", - "Al Dhafra AB" - ], - [ - "Al Dhafra AB", - "Al Maktoum Intl" - ], - [ - "Al Ain International Airport", - "Fujairah Intl" - ], - [ - "Al Ain International Airport", - "Al Maktoum Intl" - ], - [ - "Al Maktoum Intl", - "Al Minhad AB" - ], - [ - "Al Minhad AB", - "Sharjah Intl" - ], - [ - "Ras Al Khaimah", - "Sharjah Intl" - ], - [ - "Fujairah Intl", - "Sharjah Intl" - ] - ] + "miz": "emirates.miz" } \ No newline at end of file diff --git a/resources/campaigns/emirates.miz b/resources/campaigns/emirates.miz new file mode 100644 index 00000000..949e6575 Binary files /dev/null and b/resources/campaigns/emirates.miz differ diff --git a/resources/campaigns/golan_heights.json b/resources/campaigns/golan_heights.json new file mode 100644 index 00000000..01973830 --- /dev/null +++ b/resources/campaigns/golan_heights.json @@ -0,0 +1,7 @@ +{ + "name": "Syria - Battle for Golan Heights", + "theater": "Syria", + "authors": "Khopa", + "description": "

In this scenario, you start in Israel and the conflict is focused around the golan heights, an historically disputed territory.

You can use the inverted configuration to start on the Syrian side.

If this scenario is too heavy, try the lite version.

", + "miz": "golan_heights.miz" +} \ No newline at end of file diff --git a/resources/campaigns/golan_heights.miz b/resources/campaigns/golan_heights.miz new file mode 100644 index 00000000..3b7e720e Binary files /dev/null and b/resources/campaigns/golan_heights.miz differ diff --git a/resources/campaigns/golan_heights_battle.json b/resources/campaigns/golan_heights_battle.json deleted file mode 100644 index 6afd303f..00000000 --- a/resources/campaigns/golan_heights_battle.json +++ /dev/null @@ -1,83 +0,0 @@ -{ - "name": "Syria - Golan heights battle", - "theater": "Syria", - "authors": "Khopa", - "description": "

In this scenario, you start in Israel and the conflict is focused around the golan heights, an historically disputed territory.

", - "player_points": [ - { - "type": "airbase", - "id": "Ramat David", - "size": 1000, - "importance": 1.4 - }, - { - "type": "carrier", - "id": 1001, - "x": -280000, - "y": -238000, - "captured_invert": true - }, - { - "type": "lha", - "id": 1002, - "x": -237000, - "y": -89800, - "captured_invert": true - } - ], - "enemy_points": [ - { - "type": "airbase", - "id": "Khalkhalah", - "size": 1000, - "importance": 1.2 - }, - { - "type": "airbase", - "id": "King Hussein Air College", - "size": 1000, - "importance": 1.4 - }, - { - "type": "airbase", - "id": "Marj Ruhayyil", - "size": 1000, - "importance": 1 - }, - { - "type": "airbase", - "id": "Mezzeh", - "size": 1000, - "importance": 1.2 - }, - { - "type": "airbase", - "id": "Al-Dumayr", - "size": 1000, - "importance": 1.2, - "captured_invert": true - } - ], - "links": [ - [ - "Khalkhalah", - "Ramat David" - ], - [ - "Khalkhalah", - "King Hussein Air College" - ], - [ - "Khalkhalah", - "Marj Ruhayyil" - ], - [ - "Marj Ruhayyil", - "Mezzeh" - ], - [ - "Al-Dumayr", - "Marj Ruhayyil" - ] - ] -} \ No newline at end of file diff --git a/resources/campaigns/golan_heights_lite.json b/resources/campaigns/golan_heights_lite.json new file mode 100644 index 00000000..1abd6641 --- /dev/null +++ b/resources/campaigns/golan_heights_lite.json @@ -0,0 +1,7 @@ +{ + "name": "Syria - Battle for Golan Heights - Lite", + "theater": "Syria", + "authors": "Khopa", + "description": "

In this scenario, you start in Israel and the conflict is focused around the golan heights, an historically disputed territory.

This scenario is designed to be performance friendly.

", + "miz": "golan_heights_lite.miz" +} \ No newline at end of file diff --git a/resources/campaigns/golan_heights_lite.miz b/resources/campaigns/golan_heights_lite.miz new file mode 100644 index 00000000..03f20d87 Binary files /dev/null and b/resources/campaigns/golan_heights_lite.miz differ diff --git a/resources/campaigns/syrian_civil_war.json b/resources/campaigns/syrian_civil_war.json index 0ca59b44..77f879fe 100644 --- a/resources/campaigns/syrian_civil_war.json +++ b/resources/campaigns/syrian_civil_war.json @@ -2,92 +2,6 @@ "name": "Syria - Syrian Civil War", "theater": "Syria", "authors": "Khopa", - "description": "

This scenario can be used to simulate parts of the Syrian Civil War.

", - "player_points": [ - { - "type": "airbase", - "id": "Bassel Al-Assad", - "size": 1000, - "importance": 1.4 - }, - { - "type": "airbase", - "id": "Marj Ruhayyil", - "size": 1000, - "importance": 1 - }, - { - "type": "carrier", - "id": 1001, - "x": 18537, - "y": -52000, - "captured_invert": true - }, - { - "type": "lha", - "id": 1002, - "x": 116000, - "y": -30000, - "captured_invert": true - } - ], - "enemy_points": [ - { - "type": "airbase", - "id": "Hama", - "size": 1000, - "importance": 1 - }, - { - "type": "airbase", - "id": "Aleppo", - "size": 1000, - "importance": 1.2, - "captured_invert": true - }, - { - "type": "airbase", - "id": "Al Qusayr", - "size": 1000, - "importance": 1 - }, - { - "type": "airbase", - "id": "Palmyra", - "size": 1000, - "importance": 1 - }, - { - "type": "airbase", - "id": "Al-Dumayr", - "size": 1000, - "importance": 1.2 - } - ], - "links": [ - [ - "Bassel Al-Assad", - "Hama" - ], - [ - "Al-Dumayr", - "Marj Ruhayyil" - ], - [ - "Aleppo", - "Hama" - ], - [ - "Al Qusayr", - "Hama" - ], - [ - "Al Qusayr", - "Al-Dumayr" - ], - [ - "Al Qusayr", - "Palmyra" - ] - ] + "description": "

This scenario can be used to simulate parts of the Syrian Civil War.

You start on the coast with an airbase in Latakia, and ground forces in Tartus.

This scenario can also be used to simulate a western invasion of Syria.

In inverted configuration you start in Aleppo.

", + "miz": "syrian_civil_war.miz" } \ No newline at end of file diff --git a/resources/campaigns/syrian_civil_war.miz b/resources/campaigns/syrian_civil_war.miz new file mode 100644 index 00000000..3fd34fe0 Binary files /dev/null and b/resources/campaigns/syrian_civil_war.miz differ diff --git a/resources/factions/NATO_Desert_Storm.json b/resources/factions/NATO_Desert_Storm.json index d983c89f..677cd77a 100644 --- a/resources/factions/NATO_Desert_Storm.json +++ b/resources/factions/NATO_Desert_Storm.json @@ -5,7 +5,8 @@ "description": "

A faction to recreate the actual unit lineup during Desert Storm as closely as possible

", "aircrafts": [ "F_15C", - "F_14A", + "F_14A_135_GR", + "F_14B", "F_15E", "F_16C_50", "FA_18C_hornet", @@ -16,7 +17,6 @@ "B_52H", "B_1B", "Tornado_IDS", - "F_111F", "F_4E", "F_117A", "M_2000C", @@ -32,7 +32,7 @@ ], "tankers": [ "KC_135", - "KC135MPRS" + "KC130" ], "frontline_units": [ "MBT_M1A2_Abrams", @@ -46,7 +46,8 @@ "IFV_MCV_80", "MBT_Challenger_II", "MBT_M60A3_Patton", - "SPG_M1128_Stryker_MGS" + "SPG_M1128_Stryker_MGS", + "SAM_Avenger_M1097" ], "artillery_units": [ "MLRS_M270", diff --git a/resources/factions/allies_1944.json b/resources/factions/allies_1944.json index 1430b8f7..62eefeb9 100644 --- a/resources/factions/allies_1944.json +++ b/resources/factions/allies_1944.json @@ -25,7 +25,9 @@ "LAC_M8_Greyhound", "TD_M10_GMC", "Daimler_Armoured_Car", - "LT_Mk_VII_Tetrarch" + "LT_Mk_VII_Tetrarch", + "AA_gun_QF_3_7", + "AAA_Bofors_40mm" ], "artillery_units": [ "M12_GMC" diff --git a/resources/factions/allies_1944_free.json b/resources/factions/allies_1944_free.json index 133d3bed..cbc68708 100644 --- a/resources/factions/allies_1944_free.json +++ b/resources/factions/allies_1944_free.json @@ -15,7 +15,8 @@ ], "frontline_units": [ "MT_M4_Sherman", - "APC_M2A1" + "APC_M2A1", + "AAA_Bofors_40mm" ], "artillery_units": [ ], diff --git a/resources/factions/bluefor_coldwar.json b/resources/factions/bluefor_coldwar.json index 874484b4..fc3795d7 100644 --- a/resources/factions/bluefor_coldwar.json +++ b/resources/factions/bluefor_coldwar.json @@ -25,7 +25,8 @@ ], "frontline_units": [ "MBT_M60A3_Patton", - "APC_M113" + "APC_M113", + "SAM_Chaparral_M48" ], "artillery_units": [ "SPH_M109_Paladin" diff --git a/resources/factions/bluefor_coldwar_a4.json b/resources/factions/bluefor_coldwar_a4.json index f5a5a56d..85144509 100644 --- a/resources/factions/bluefor_coldwar_a4.json +++ b/resources/factions/bluefor_coldwar_a4.json @@ -26,7 +26,8 @@ ], "frontline_units": [ "MBT_M60A3_Patton", - "APC_M113" + "APC_M113", + "SAM_Chaparral_M48" ], "artillery_units": [ "SPH_M109_Paladin" diff --git a/resources/factions/bluefor_coldwar_a4_mb339.json b/resources/factions/bluefor_coldwar_a4_mb339.json index 57c50355..127c922d 100644 --- a/resources/factions/bluefor_coldwar_a4_mb339.json +++ b/resources/factions/bluefor_coldwar_a4_mb339.json @@ -27,7 +27,8 @@ ], "frontline_units": [ "MBT_M60A3_Patton", - "APC_M113" + "APC_M113", + "SAM_Chaparral_M48" ], "artillery_units": [ "SPH_M109_Paladin" diff --git a/resources/factions/bluefor_modern.json b/resources/factions/bluefor_modern.json index f422a6eb..14590cc4 100644 --- a/resources/factions/bluefor_modern.json +++ b/resources/factions/bluefor_modern.json @@ -43,7 +43,9 @@ "IFV_Marder", "IFV_LAV_25", "APC_M1043_HMMWV_Armament", - "ATGM_M1045_HMMWV_TOW" + "ATGM_M1045_HMMWV_TOW", + "SAM_Linebacker_M6", + "SAM_Avenger_M1097" ], "artillery_units": [ "MLRS_M270", diff --git a/resources/factions/canada_2005.json b/resources/factions/canada_2005.json index 9a170a6f..3312dbac 100644 --- a/resources/factions/canada_2005.json +++ b/resources/factions/canada_2005.json @@ -20,7 +20,8 @@ "MBT_Leopard_2", "IFV_LAV_25", "APC_M113", - "IFV_MCV_80" + "IFV_MCV_80", + "SAM_Avenger_M1097" ], "artillery_units": [ ], diff --git a/resources/factions/china_2010.json b/resources/factions/china_2010.json index fd6f52ed..cc592f1d 100644 --- a/resources/factions/china_2010.json +++ b/resources/factions/china_2010.json @@ -22,7 +22,8 @@ "ZTZ_96B", "MBT_T_55", "ZBD_04A", - "IFV_BMP_1" + "IFV_BMP_1", + "HQ_7_Self_Propelled_LN" ], "artillery_units": [ "MLRS_9A52_Smerch", diff --git a/resources/factions/france_1995.json b/resources/factions/france_1995.json index 2c553009..25b897ac 100644 --- a/resources/factions/france_1995.json +++ b/resources/factions/france_1995.json @@ -24,7 +24,8 @@ "ATGM_M1134_Stryker", "IFV_LAV_25", "APC_M1043_HMMWV_Armament", - "ATGM_M1045_HMMWV_TOW" + "ATGM_M1045_HMMWV_TOW", + "SAM_Roland_ADS" ], "artillery_units": [ "MLRS_M270", @@ -36,7 +37,8 @@ "infantry_units": [ "Infantry_M4", "Soldier_M249", - "Stinger_MANPADS" + "Stinger_MANPADS", + "_2B11_mortar" ], "air_defenses": [ "RolandGenerator", diff --git a/resources/factions/france_2005_frenchpack.json b/resources/factions/france_2005_frenchpack.json index cb13cb4e..f9e0dca7 100644 --- a/resources/factions/france_2005_frenchpack.json +++ b/resources/factions/france_2005_frenchpack.json @@ -31,7 +31,8 @@ "VBAE_CRAB", "VBAE_CRAB_MMP", "AMX_30B2", - "Leclerc_Serie_XXI" + "Leclerc_Serie_XXI", + "SAM_Roland_ADS" ], "artillery_units": [ "MLRS_M270", diff --git a/resources/factions/france_2005_modded.json b/resources/factions/france_2005_modded.json index 34e4511a..dd0929fc 100644 --- a/resources/factions/france_2005_modded.json +++ b/resources/factions/france_2005_modded.json @@ -34,7 +34,8 @@ "VBAE_CRAB", "VBAE_CRAB_MMP", "AMX_30B2", - "Leclerc_Serie_XXI" + "Leclerc_Serie_XXI", + "SAM_Roland_ADS" ], "artillery_units": [ "MLRS_M270", diff --git a/resources/factions/georgia_2008.json b/resources/factions/georgia_2008.json index 45b8cfc1..0d861108 100644 --- a/resources/factions/georgia_2008.json +++ b/resources/factions/georgia_2008.json @@ -17,7 +17,8 @@ "IFV_BMP_1", "IFV_BMP_2", "MBT_T_72B", - "MBT_T_55" + "MBT_T_55", + "SAM_SA_13_Strela_10M3_9A35M3" ], "artillery_units": [ "MLRS_BM_21_Grad", diff --git a/resources/factions/germany_1942.json b/resources/factions/germany_1942.json index fda75025..1a84e1ff 100644 --- a/resources/factions/germany_1942.json +++ b/resources/factions/germany_1942.json @@ -13,7 +13,8 @@ "MT_Pz_Kpfw_IV_Ausf_H", "APC_Sd_Kfz_251", "AC_Sd_Kfz_234_2_Puma", - "TD_Jagdpanzer_IV" + "TD_Jagdpanzer_IV", + "AAA_8_8cm_Flak_18" ], "artillery_units": [ "Sturmpanzer_IV_Brummbär" diff --git a/resources/factions/germany_1944.json b/resources/factions/germany_1944.json index 273a4519..7cd95b44 100644 --- a/resources/factions/germany_1944.json +++ b/resources/factions/germany_1944.json @@ -18,7 +18,11 @@ "AC_Sd_Kfz_234_2_Puma", "Sd_Kfz_184_Elefant", "TD_Jagdpanther_G1", - "TD_Jagdpanzer_IV" + "TD_Jagdpanzer_IV", + "StuG_III_Ausf__G", + "StuG_IV", + "AAA_8_8cm_Flak_18", + "AAA_8_8cm_Flak_41" ], "artillery_units": [ "Sturmpanzer_IV_Brummbär" diff --git a/resources/factions/germany_1944_free.json b/resources/factions/germany_1944_free.json index 8fc2421c..a27417aa 100644 --- a/resources/factions/germany_1944_free.json +++ b/resources/factions/germany_1944_free.json @@ -10,7 +10,8 @@ ], "frontline_units": [ "MT_Pz_Kpfw_IV_Ausf_H", - "APC_Sd_Kfz_251" + "APC_Sd_Kfz_251", + "AAA_8_8cm_Flak_18" ], "artillery_units": [ ], diff --git a/resources/factions/germany_1990.json b/resources/factions/germany_1990.json index bdf243e7..c5275de1 100644 --- a/resources/factions/germany_1990.json +++ b/resources/factions/germany_1990.json @@ -22,7 +22,8 @@ "TPz_Fuchs", "MBT_Leopard_1A3", "MBT_Leopard_2", - "IFV_Marder" + "IFV_Marder", + "SPAAA_Gepard" ], "artillery_units": [ ], @@ -32,6 +33,7 @@ "infantry_units": [ "Infantry_M4", "Soldier_M249", + "_2B11_mortar", "Stinger_MANPADS" ], "air_defenses": [ diff --git a/resources/factions/india_2010.json b/resources/factions/india_2010.json index 7b6cedb3..609fe738 100644 --- a/resources/factions/india_2010.json +++ b/resources/factions/india_2010.json @@ -22,7 +22,8 @@ "frontline_units": [ "MBT_T_90", "MBT_T_72B", - "IFV_BMP_2" + "IFV_BMP_2", + "SAM_SA_19_Tunguska_2S6" ], "artillery_units": [ "MLRS_9K57_Uragan_BM_27", diff --git a/resources/factions/insurgents.json b/resources/factions/insurgents.json index 8634c534..f31a5966 100644 --- a/resources/factions/insurgents.json +++ b/resources/factions/insurgents.json @@ -22,6 +22,7 @@ "infantry_units": [ "Infantry_Soldier_Insurgents", "Soldier_RPG", + "_2B11_mortar", "SAM_SA_18_Igla_MANPADS" ], "air_defenses": [ diff --git a/resources/factions/insurgents_hard.json b/resources/factions/insurgents_hard.json new file mode 100644 index 00000000..f824e1c7 --- /dev/null +++ b/resources/factions/insurgents_hard.json @@ -0,0 +1,39 @@ +{ + "country": "Insurgents", + "name": "Insurgents (Hard)", + "authors": "Khopa", + "description": "

Insurgents faction.

", + "aircrafts": [ + ], + "frontline_units": [ + "ATGM_M1045_HMMWV_TOW", + "APC_M1043_HMMWV_Armament", + "ARV_BRDM_2", + "APC_BTR_80", + "ARV_BTR_RD", + "IFV_BMP_1", + "MBT_T_55", + "AAA_ZU_23_Insurgent_on_Ural_375", + "AAA_ZSU_57_2" + ], + "artillery_units": [ + "MLRS_BM_21_Grad", + "SPH_2S19_Msta" + ], + "logistics_units": [ + "Transport_Ural_375", + "Transport_UAZ_469" + ], + "infantry_units": [ + "Infantry_Soldier_Insurgents", + "Soldier_RPG", + "_2B11_mortar", + "SAM_SA_18_Igla_MANPADS" + ], + "air_defenses": [ + "SA9Generator", + "ZSU57Generator", + "ZU23Generator", + "ZU23UralInsurgentGenerator" + ] +} diff --git a/resources/factions/iran_2015.json b/resources/factions/iran_2015.json index cb6ba5f2..b8621de2 100644 --- a/resources/factions/iran_2015.json +++ b/resources/factions/iran_2015.json @@ -27,7 +27,9 @@ "APC_BTR_80", "MBT_M60A3_Patton", "IFV_BMP_1", - "MBT_T_72B" + "MBT_T_72B", + "SPAAA_ZSU_23_4_Shilka", + "AAA_ZSU_57_2" ], "artillery_units": [ "MLRS_BM_21_Grad", diff --git a/resources/factions/iraq_1991.json b/resources/factions/iraq_1991.json index 36dc0672..0ff517ee 100644 --- a/resources/factions/iraq_1991.json +++ b/resources/factions/iraq_1991.json @@ -16,7 +16,8 @@ "Tu_22M3", "L_39C", "L_39ZA", - "Mi_24V" + "Mi_24V", + "MiG_29A" ], "awacs": [ "A_50" @@ -31,7 +32,9 @@ "MBT_T_72B", "APC_BTR_80", "ARV_BRDM_2", - "SPH_2S1_Gvozdika" + "SPH_2S1_Gvozdika", + "AAA_ZSU_57_2", + "SPAAA_ZSU_23_4_Shilka" ], "artillery_units": [ "MLRS_BM_21_Grad" diff --git a/resources/factions/israel_1948.json b/resources/factions/israel_1948.json index b2c86e7b..5f296689 100644 --- a/resources/factions/israel_1948.json +++ b/resources/factions/israel_1948.json @@ -15,7 +15,8 @@ "MT_M4A4_Sherman_Firefly", "APC_M2A1", "MT_M4_Sherman", - "LAC_M8_Greyhound" + "LAC_M8_Greyhound", + "AAA_Bofors_40mm" ], "artillery_units": [ ], diff --git a/resources/factions/israel_1973.json b/resources/factions/israel_1973.json index c0d3482b..b3b30840 100644 --- a/resources/factions/israel_1973.json +++ b/resources/factions/israel_1973.json @@ -19,7 +19,8 @@ "MT_M4_Sherman", "APC_M2A1", "MBT_M60A3_Patton", - "APC_M113" + "APC_M113", + "SAM_Chaparral_M48" ], "artillery_units": [ ], diff --git a/resources/factions/israel_1982.json b/resources/factions/israel_1982.json index b527416a..b975c7b9 100644 --- a/resources/factions/israel_1982.json +++ b/resources/factions/israel_1982.json @@ -22,7 +22,8 @@ "frontline_units": [ "APC_M113", "MBT_M60A3_Patton", - "MBT_Merkava_Mk__4" + "MBT_Merkava_Mk__4", + "AAA_Vulcan_M163" ], "artillery_units": [ ], diff --git a/resources/factions/israel_2000.json b/resources/factions/israel_2000.json index c23c315e..667df3bd 100644 --- a/resources/factions/israel_2000.json +++ b/resources/factions/israel_2000.json @@ -23,7 +23,8 @@ "APC_M113", "APC_M1043_HMMWV_Armament", "ATGM_M1045_HMMWV_TOW", - "MBT_Merkava_Mk__4" + "MBT_Merkava_Mk__4", + "AAA_Vulcan_M163" ], "artillery_units": [ "SPH_M109_Paladin", diff --git a/resources/factions/italy_1990.json b/resources/factions/italy_1990.json index 62ac4ce5..1f0250da 100644 --- a/resources/factions/italy_1990.json +++ b/resources/factions/italy_1990.json @@ -18,7 +18,8 @@ ], "frontline_units": [ "MBT_Leopard_1A3", - "APC_M113" + "APC_M113", + "SAM_Avenger_M1097" ], "artillery_units": [ "SPH_M109_Paladin" diff --git a/resources/factions/italy_1990_mb339.json b/resources/factions/italy_1990_mb339.json index 186926f7..00cc2914 100644 --- a/resources/factions/italy_1990_mb339.json +++ b/resources/factions/italy_1990_mb339.json @@ -19,7 +19,8 @@ ], "frontline_units": [ "MBT_Leopard_1A3", - "APC_M113" + "APC_M113", + "SAM_Avenger_M1097" ], "artillery_units": [ "SPH_M109_Paladin" diff --git a/resources/factions/japan_2005.json b/resources/factions/japan_2005.json index de03dbd8..a2f24933 100644 --- a/resources/factions/japan_2005.json +++ b/resources/factions/japan_2005.json @@ -23,7 +23,8 @@ "IFV_Marder", "TPz_Fuchs", "IFV_LAV_25", - "APC_M1043_HMMWV_Armament" + "APC_M1043_HMMWV_Armament", + "SPAAA_Gepard" ], "artillery_units": [ "SPH_M109_Paladin", diff --git a/resources/factions/libya_2011.json b/resources/factions/libya_2011.json index 8090ea3c..dd758824 100644 --- a/resources/factions/libya_2011.json +++ b/resources/factions/libya_2011.json @@ -20,7 +20,9 @@ "IFV_BMP_1", "ARV_BRDM_2", "MBT_T_72B", - "MBT_T_55" + "MBT_T_55", + "SPAAA_ZSU_23_4_Shilka", + "SAM_SA_8_Osa_9A33" ], "artillery_units": [ "MLRS_BM_21_Grad" diff --git a/resources/factions/netherlands_1990.json b/resources/factions/netherlands_1990.json index 44fc54ed..26462102 100644 --- a/resources/factions/netherlands_1990.json +++ b/resources/factions/netherlands_1990.json @@ -17,7 +17,8 @@ ], "frontline_units": [ "APC_M113", - "MBT_Leopard_1A3" + "MBT_Leopard_1A3", + "SAM_Avenger_M1097" ], "artillery_units": [ ], diff --git a/resources/factions/north_korea_2000.json b/resources/factions/north_korea_2000.json index 769c595d..794852d4 100644 --- a/resources/factions/north_korea_2000.json +++ b/resources/factions/north_korea_2000.json @@ -24,7 +24,9 @@ "IFV_BMP_1", "MBT_T_55", "MBT_T_72B", - "MBT_T_80U" + "MBT_T_80U", + "AAA_ZSU_57_2", + "SAM_SA_9_Strela_1_9P31" ], "artillery_units": [ "MLRS_BM_21_Grad", diff --git a/resources/factions/pakistan_2015.json b/resources/factions/pakistan_2015.json index 43ba4bba..32e1495d 100644 --- a/resources/factions/pakistan_2015.json +++ b/resources/factions/pakistan_2015.json @@ -23,7 +23,8 @@ "MBT_T_55", "ZBD_04A", "APC_BTR_80", - "APC_M113" + "APC_M113", + "HQ_7_Self_Propelled_LN" ], "artillery_units": [ "MLRS_9A52_Smerch", diff --git a/resources/factions/pmc_russian.json b/resources/factions/pmc_russian.json index 844bdb3c..aec2c021 100644 --- a/resources/factions/pmc_russian.json +++ b/resources/factions/pmc_russian.json @@ -13,7 +13,8 @@ "frontline_units": [ "APC_Cobra", "APC_BTR_80", - "ARV_BRDM_2" + "ARV_BRDM_2", + "SAM_SA_13_Strela_10M3_9A35M3" ], "artillery_units": [ "SPH_2S19_Msta" diff --git a/resources/factions/pmc_us.json b/resources/factions/pmc_us.json index e75e193f..0c46beca 100644 --- a/resources/factions/pmc_us.json +++ b/resources/factions/pmc_us.json @@ -11,7 +11,9 @@ ], "frontline_units": [ "APC_M1043_HMMWV_Armament", - "IFV_MCV_80" + "IFV_MCV_80", + "IFV_LAV_25", + "SAM_Avenger_M1097" ], "artillery_units": [ ], diff --git a/resources/factions/pmc_us_with_mb339.json b/resources/factions/pmc_us_with_mb339.json index ef01e093..e4f706e1 100644 --- a/resources/factions/pmc_us_with_mb339.json +++ b/resources/factions/pmc_us_with_mb339.json @@ -12,7 +12,9 @@ ], "frontline_units": [ "APC_M1043_HMMWV_Armament", - "IFV_MCV_80" + "IFV_MCV_80", + "IFV_LAV_25", + "SAM_Avenger_M1097" ], "artillery_units": [ ], diff --git a/resources/factions/russia_1955.json b/resources/factions/russia_1955.json index ca7e1994..d7cfff94 100644 --- a/resources/factions/russia_1955.json +++ b/resources/factions/russia_1955.json @@ -17,7 +17,8 @@ "FDDM_Grad", "APC_MTLB", "MBT_T_55", - "AAA_ZU_23_on_Ural_375" + "AAA_ZU_23_on_Ural_375", + "AAA_8_8cm_Flak_18" ], "artillery_units": [ "MLRS_BM_21_Grad" diff --git a/resources/factions/russia_1965.json b/resources/factions/russia_1965.json index 2de7b41f..9f986f1d 100644 --- a/resources/factions/russia_1965.json +++ b/resources/factions/russia_1965.json @@ -21,7 +21,9 @@ "ARV_BTR_RD", "IFV_BMD_1", "IFV_BMP_1", - "MBT_T_55" + "MBT_T_55", + "AAA_ZU_23_on_Ural_375", + "AAA_ZSU_57_2" ], "artillery_units": [ "MLRS_BM_21_Grad" diff --git a/resources/factions/russia_1970_limited_air.json b/resources/factions/russia_1970_limited_air.json index 8a1b8daa..9043ad72 100644 --- a/resources/factions/russia_1970_limited_air.json +++ b/resources/factions/russia_1970_limited_air.json @@ -14,7 +14,8 @@ "APC_BTR_80", "IFV_BMD_1", "IFV_BMP_1", - "MBT_T_55" + "MBT_T_55", + "AAA_ZSU_57_2" ], "artillery_units": [ "MLRS_BM_21_Grad", diff --git a/resources/factions/russia_1975.json b/resources/factions/russia_1975.json index a9a0884d..5630494c 100644 --- a/resources/factions/russia_1975.json +++ b/resources/factions/russia_1975.json @@ -25,7 +25,8 @@ "APC_BTR_80", "IFV_BMD_1", "IFV_BMP_1", - "MBT_T_55" + "MBT_T_55", + "SAM_SA_8_Osa_9A33" ], "artillery_units": [ "MLRS_BM_21_Grad", @@ -38,7 +39,8 @@ ], "infantry_units": [ "Infantry_Soldier_Rus", - "Soldier_RPG" + "Soldier_RPG", + "_2B11_mortar" ], "air_defenses": [ "ColdWarFlakGenerator", diff --git a/resources/factions/russia_1990.json b/resources/factions/russia_1990.json index dd9048bd..74c52bf3 100644 --- a/resources/factions/russia_1990.json +++ b/resources/factions/russia_1990.json @@ -29,7 +29,8 @@ "IFV_BMP_1", "IFV_BMP_2", "MBT_T_72B", - "MBT_T_80U" + "MBT_T_80U", + "SAM_SA_13_Strela_10M3_9A35M3" ], "artillery_units": [ "MLRS_9K57_Uragan_BM_27", @@ -43,6 +44,7 @@ "Paratrooper_AKS", "Infantry_Soldier_Rus", "Paratrooper_RPG_16", + "_2B11_mortar", "SAM_SA_18_Igla_S_MANPADS" ], "air_defenses": [ diff --git a/resources/factions/russia_2010.json b/resources/factions/russia_2010.json index 29414763..bd6d037a 100644 --- a/resources/factions/russia_2010.json +++ b/resources/factions/russia_2010.json @@ -34,7 +34,8 @@ "APC_BTR_82A", "MBT_T_90", "MBT_T_80U", - "MBT_T_72B3" + "MBT_T_72B3", + "SAM_SA_19_Tunguska_2S6" ], "artillery_units": [ "MLRS_9K57_Uragan_BM_27", @@ -48,6 +49,7 @@ "Paratrooper_AKS", "Infantry_Soldier_Rus", "Paratrooper_RPG_16", + "_2B11_mortar", "SAM_SA_18_Igla_MANPADS" ], "air_defenses": [ diff --git a/resources/factions/russia_2020.json b/resources/factions/russia_2020.json index b1c45b8a..91554c82 100644 --- a/resources/factions/russia_2020.json +++ b/resources/factions/russia_2020.json @@ -32,7 +32,8 @@ "IFV_BMP_3", "MBT_T_90", "MBT_T_80U", - "MBT_T_72B" + "MBT_T_72B", + "SAM_SA_19_Tunguska_2S6" ], "artillery_units": [ "MLRS_9K57_Uragan_BM_27", diff --git a/resources/factions/soviet_union_1943.json b/resources/factions/soviet_union_1943.json index e30a34dc..3b0bb9a5 100644 --- a/resources/factions/soviet_union_1943.json +++ b/resources/factions/soviet_union_1943.json @@ -11,7 +11,8 @@ "MT_M4_Sherman", "APC_M2A1", "Daimler_Armoured_Car", - "LT_Mk_VII_Tetrarch" + "LT_Mk_VII_Tetrarch", + "AAA_Bofors_40mm" ], "artillery_units": [ "MLRS_BM_21_Grad" diff --git a/resources/factions/spain_1990.json b/resources/factions/spain_1990.json index 8eb658bf..b736b672 100644 --- a/resources/factions/spain_1990.json +++ b/resources/factions/spain_1990.json @@ -20,7 +20,8 @@ "frontline_units": [ "MBT_M60A3_Patton", "MBT_Leopard_2", - "APC_M113" + "APC_M113", + "SAM_Avenger_M1097" ], "artillery_units": [ ], diff --git a/resources/factions/sweden_1970.json b/resources/factions/sweden_1970.json index 55362275..41a79c1e 100644 --- a/resources/factions/sweden_1970.json +++ b/resources/factions/sweden_1970.json @@ -18,7 +18,8 @@ "frontline_units": [ "IFV_MCV_80", "MBT_Leopard_2", - "APC_M1126_Stryker_ICV" + "APC_M1126_Stryker_ICV", + "SAM_Chaparral_M48" ], "artillery_units": [ ], @@ -32,7 +33,6 @@ "air_defenses": [ "ChaparralGenerator", "EarlyColdWarFlakGenerator", - "AvengerGenerator", "HawkGenerator", "VulcanGenerator" ], diff --git a/resources/factions/sweden_1990.json b/resources/factions/sweden_1990.json index c5d78b6e..e6c20950 100644 --- a/resources/factions/sweden_1990.json +++ b/resources/factions/sweden_1990.json @@ -17,7 +17,8 @@ "frontline_units": [ "IFV_MCV_80", "MBT_Leopard_2", - "APC_M1126_Stryker_ICV" + "APC_M1126_Stryker_ICV", + "SAM_Avenger_M1097" ], "artillery_units": [ ], diff --git a/resources/factions/syria_1948.json b/resources/factions/syria_1948.json index b8814e6e..3ff2e29d 100644 --- a/resources/factions/syria_1948.json +++ b/resources/factions/syria_1948.json @@ -11,7 +11,8 @@ "AC_Sd_Kfz_234_2_Puma", "APC_Sd_Kfz_251", "MT_Pz_Kpfw_IV_Ausf_H", - "MT_M4_Sherman" + "MT_M4_Sherman", + "AAA_Bofors_40mm" ], "artillery_units": [ ], diff --git a/resources/factions/syria_1967.json b/resources/factions/syria_1967.json index d63cc699..b84c590f 100644 --- a/resources/factions/syria_1967.json +++ b/resources/factions/syria_1967.json @@ -19,7 +19,9 @@ "frontline_units": [ "ARV_BRDM_2", "MT_Pz_Kpfw_IV_Ausf_H", - "MBT_T_55" + "MBT_T_55", + "AAA_ZU_23_on_Ural_375", + "AAA_ZSU_57_2" ], "artillery_units": [ "MLRS_BM_21_Grad" diff --git a/resources/factions/syria_1967_with_ww2_weapons.json b/resources/factions/syria_1967_with_ww2_weapons.json index d97cc2da..46b6bb34 100644 --- a/resources/factions/syria_1967_with_ww2_weapons.json +++ b/resources/factions/syria_1967_with_ww2_weapons.json @@ -22,7 +22,8 @@ "MBT_T_55", "MT_Pz_Kpfw_IV_Ausf_H", "StuG_III_Ausf__G", - "TD_Jagdpanzer_IV" + "TD_Jagdpanzer_IV", + "AAA_ZSU_57_2" ], "artillery_units": [ "MLRS_BM_21_Grad" diff --git a/resources/factions/syria_1973.json b/resources/factions/syria_1973.json index 1d1a5c55..83af1f67 100644 --- a/resources/factions/syria_1973.json +++ b/resources/factions/syria_1973.json @@ -19,7 +19,9 @@ "frontline_units": [ "IFV_BMP_1", "APC_MTLB", - "MBT_T_55" + "MBT_T_55", + "AAA_ZU_23_on_Ural_375", + "AAA_ZSU_57_2" ], "artillery_units": [ "MLRS_BM_21_Grad" diff --git a/resources/factions/syria_1982.json b/resources/factions/syria_1982.json index cde94609..ab74b0de 100644 --- a/resources/factions/syria_1982.json +++ b/resources/factions/syria_1982.json @@ -21,7 +21,9 @@ "IFV_BMP_1", "APC_MTLB", "MBT_T_55", - "MBT_T_72B" + "MBT_T_72B", + "AAA_ZU_23_on_Ural_375", + "AAA_ZSU_57_2" ], "artillery_units": [ "MLRS_BM_21_Grad" diff --git a/resources/factions/syria_2011.json b/resources/factions/syria_2011.json index 4153f679..25d94f56 100644 --- a/resources/factions/syria_2011.json +++ b/resources/factions/syria_2011.json @@ -31,7 +31,8 @@ "APC_Cobra", "MBT_T_55", "MBT_T_72B", - "MBT_T_90" + "MBT_T_90", + "AAA_ZSU_57_2" ], "artillery_units": [ "MLRS_9K57_Uragan_BM_27", diff --git a/resources/factions/turkey_2005.json b/resources/factions/turkey_2005.json index 0a11e63a..4aad1c46 100644 --- a/resources/factions/turkey_2005.json +++ b/resources/factions/turkey_2005.json @@ -21,7 +21,8 @@ "MBT_Leopard_1A3", "MBT_M60A3_Patton", "APC_Cobra", - "APC_BTR_80" + "APC_BTR_80", + "SAM_Avenger_M1097" ], "artillery_units": [ "SPH_M109_Paladin" diff --git a/resources/factions/uk_1944.json b/resources/factions/uk_1944.json index c771db2c..418e2d79 100644 --- a/resources/factions/uk_1944.json +++ b/resources/factions/uk_1944.json @@ -22,7 +22,8 @@ "CT_Centaur_IV", "HIT_Churchill_VII", "Daimler_Armoured_Car", - "LT_Mk_VII_Tetrarch" + "LT_Mk_VII_Tetrarch", + "AAA_Bofors_40mm" ], "artillery_units": [ ], diff --git a/resources/factions/uk_1990.json b/resources/factions/uk_1990.json index b3db7880..2522d20b 100644 --- a/resources/factions/uk_1990.json +++ b/resources/factions/uk_1990.json @@ -21,7 +21,8 @@ "MBT_Challenger_II", "IFV_MCV_80", "APC_M1043_HMMWV_Armament", - "ATGM_M1045_HMMWV_TOW" + "ATGM_M1045_HMMWV_TOW", + "SAM_Avenger_M1097" ], "artillery_units": [ "MLRS_M270", @@ -33,6 +34,7 @@ "infantry_units": [ "Infantry_M4", "Soldier_M249", + "_2B11_mortar", "Stinger_MANPADS" ], "air_defenses": [ diff --git a/resources/factions/ukraine_2010.json b/resources/factions/ukraine_2010.json index dac93cb8..b92f90c6 100644 --- a/resources/factions/ukraine_2010.json +++ b/resources/factions/ukraine_2010.json @@ -25,7 +25,8 @@ "IFV_BMP_2", "APC_BTR_80", "MBT_T_80U", - "MBT_T_72B" + "MBT_T_72B", + "SAM_SA_13_Strela_10M3_9A35M3" ], "artillery_units": [ ], diff --git a/resources/factions/us_aggressors.json b/resources/factions/us_aggressors.json index eefebd9a..7568ccd5 100644 --- a/resources/factions/us_aggressors.json +++ b/resources/factions/us_aggressors.json @@ -33,7 +33,8 @@ "ATGM_M1134_Stryker", "IFV_M2A2_Bradley", "IFV_LAV_25", - "APC_M1043_HMMWV_Armament" + "APC_M1043_HMMWV_Armament", + "SAM_Avenger_M1097" ], "artillery_units": [ "MLRS_M270", diff --git a/resources/factions/usa_1944.json b/resources/factions/usa_1944.json index f1c78ece..053ace3c 100644 --- a/resources/factions/usa_1944.json +++ b/resources/factions/usa_1944.json @@ -19,7 +19,8 @@ "APC_M2A1", "M30_Cargo_Carrier", "LAC_M8_Greyhound", - "TD_M10_GMC" + "TD_M10_GMC", + "AA_gun_QF_3_7" ], "artillery_units": [ "M12_GMC" diff --git a/resources/factions/usa_1955.json b/resources/factions/usa_1955.json index 482fd683..1c2a1ec8 100644 --- a/resources/factions/usa_1955.json +++ b/resources/factions/usa_1955.json @@ -12,7 +12,8 @@ "frontline_units": [ "MT_M4_Sherman", "MBT_M60A3_Patton", - "APC_M2A1" + "APC_M2A1", + "AAA_Bofors_40mm" ], "artillery_units": [ "M12_GMC" diff --git a/resources/factions/usa_1960.json b/resources/factions/usa_1960.json index 4397748f..e9d7c4c7 100644 --- a/resources/factions/usa_1960.json +++ b/resources/factions/usa_1960.json @@ -12,7 +12,8 @@ ], "frontline_units": [ "MBT_M60A3_Patton", - "APC_M113" + "APC_M113", + "AAA_Vulcan_M163" ], "artillery_units": [ ], diff --git a/resources/factions/usa_1965.json b/resources/factions/usa_1965.json index 2acd421a..e0a03e3f 100644 --- a/resources/factions/usa_1965.json +++ b/resources/factions/usa_1965.json @@ -11,7 +11,8 @@ ], "frontline_units": [ "MBT_M60A3_Patton", - "APC_M113" + "APC_M113", + "AAA_Vulcan_M163" ], "artillery_units": [ "SPH_M109_Paladin" diff --git a/resources/factions/usa_1975.json b/resources/factions/usa_1975.json index a72383d8..cd818384 100644 --- a/resources/factions/usa_1975.json +++ b/resources/factions/usa_1975.json @@ -12,7 +12,9 @@ ], "frontline_units": [ "MBT_M60A3_Patton", - "APC_M113" + "APC_M113", + "SAM_Chaparral_M48", + "AAA_Vulcan_M163" ], "artillery_units": [ "SPH_M109_Paladin" diff --git a/resources/factions/usa_1990.json b/resources/factions/usa_1990.json index dfe64438..e2da4d5f 100644 --- a/resources/factions/usa_1990.json +++ b/resources/factions/usa_1990.json @@ -32,7 +32,8 @@ "IFV_M2A2_Bradley", "IFV_LAV_25", "APC_M1043_HMMWV_Armament", - "ATGM_M1045_HMMWV_TOW" + "ATGM_M1045_HMMWV_TOW", + "SAM_Avenger_M1097" ], "artillery_units": [ "MLRS_M270", @@ -44,7 +45,8 @@ "infantry_units": [ "Infantry_M4", "Soldier_M249", - "Stinger_MANPADS" + "Stinger_MANPADS", + "_2B11_mortar" ], "air_defenses": [ "AvengerGenerator", diff --git a/resources/factions/usa_2005.json b/resources/factions/usa_2005.json index 5ebe5d1c..09a6fd1d 100644 --- a/resources/factions/usa_2005.json +++ b/resources/factions/usa_2005.json @@ -32,7 +32,9 @@ "IFV_M2A2_Bradley", "IFV_LAV_25", "APC_M1043_HMMWV_Armament", - "ATGM_M1045_HMMWV_TOW" + "ATGM_M1045_HMMWV_TOW", + "SAM_Avenger_M1097", + "SAM_Linebacker_M6" ], "artillery_units": [ "MLRS_M270", @@ -44,7 +46,8 @@ "infantry_units": [ "Infantry_M4", "Soldier_M249", - "Stinger_MANPADS" + "Stinger_MANPADS", + "_2B11_mortar" ], "air_defenses": [ "AvengerGenerator", diff --git a/resources/factions/usa_2005_c130.json b/resources/factions/usa_2005_c130.json index 356f62c0..af749b94 100644 --- a/resources/factions/usa_2005_c130.json +++ b/resources/factions/usa_2005_c130.json @@ -33,7 +33,9 @@ "IFV_M2A2_Bradley", "IFV_LAV_25", "APC_M1043_HMMWV_Armament", - "ATGM_M1045_HMMWV_TOW" + "ATGM_M1045_HMMWV_TOW", + "SAM_Avenger_M1097", + "SAM_Linebacker_M6" ], "artillery_units": [ "MLRS_M270", @@ -45,7 +47,8 @@ "infantry_units": [ "Infantry_M4", "Soldier_M249", - "Stinger_MANPADS" + "Stinger_MANPADS", + "_2B11_mortar" ], "air_defenses": [ "AvengerGenerator", diff --git a/resources/factions/usa_2005_modded.json b/resources/factions/usa_2005_modded.json index e4839515..de7375e6 100644 --- a/resources/factions/usa_2005_modded.json +++ b/resources/factions/usa_2005_modded.json @@ -33,7 +33,9 @@ "IFV_M2A2_Bradley", "IFV_LAV_25", "APC_M1043_HMMWV_Armament", - "ATGM_M1045_HMMWV_TOW" + "ATGM_M1045_HMMWV_TOW", + "SAM_Avenger_M1097", + "SAM_Linebacker_M6" ], "artillery_units": [ "MLRS_M270", @@ -45,7 +47,8 @@ "infantry_units": [ "Infantry_M4", "Soldier_M249", - "Stinger_MANPADS" + "Stinger_MANPADS", + "_2B11_mortar" ], "air_defenses": [ "AvengerGenerator", diff --git a/resources/factions/usn_1985.json b/resources/factions/usn_1985.json index 55bc56e5..cfdef2bc 100644 --- a/resources/factions/usn_1985.json +++ b/resources/factions/usn_1985.json @@ -20,7 +20,8 @@ "frontline_units": [ "MBT_M60A3_Patton", "APC_M113", - "APC_M1025_HMMWV" + "APC_M1025_HMMWV", + "AAA_Vulcan_M163" ], "artillery_units": [ "SPH_M109_Paladin", @@ -32,6 +33,7 @@ "infantry_units": [ "Infantry_M4", "Soldier_M249", + "_2B11_mortar", "Stinger_MANPADS" ], "air_defenses": [ diff --git a/resources/plugins/ewrs/LICENSE b/resources/plugins/ewrs/LICENSE new file mode 100644 index 00000000..76590432 --- /dev/null +++ b/resources/plugins/ewrs/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 Bob7heBuilder + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/resources/plugins/ewrs/ewrs.lua b/resources/plugins/ewrs/ewrs.lua new file mode 100644 index 00000000..b66b728a --- /dev/null +++ b/resources/plugins/ewrs/ewrs.lua @@ -0,0 +1,830 @@ +--[[ + Early Warning Radar Script - 1.5.3 - 07/11/2016 + + Allows use of units with radars to provide Bearing Range and Altitude information via text display to player aircraft + + Features: + - Uses in-game radar information to detect targets so terrain masking, beaming, low altitude flying, etc is effective for avoiding detection + - Dynamic. If valid units with radar are created during a mission (eg. via chopper with CTLD), they will be added to the EWRS radar network + - Can allow / disable BRA messages to fighters or sides + - Uses player aircraft or mission bullseye for BRA reference, can be changed via F10 radio menu or restricted to one reference in the script settings + - Can switch between imperial (feet, knots, NM) or metric (meters, km/h, km) measurements using F10 radio menu + - Ability to change the message display time and automated update interval + - Can choose to disable automated messages and allow players to request BRA from F10 menu + - Can allow players to request Bogey Dope at any time through F10 radio menu + + Built and Tested in DCS 1.5 - See https://github.com/Bob7heBuilder/EWRS for the latest version + + This script uses MIST 4.0.57 or later - https://github.com/mrSkortch/MissionScriptingTools + + At the moment, because of limitations within DCS to not show messages to individual units, the reference, measurements, and messages + are done per group. So a group of 4 fighters will each receive 4 BRA messages. Each message however, will have the player's name + in it, that its refering to. Its unfortunate, but nothing I can do about it. + + Changes: + - 1.3 - Added Option to allow picture report to be requested thru F10 menu instead of an automated display + - Fixed bug where a known unit type would sometimes still display as ??? + - 1.4 - Added setting to be able to limit the amount of threats displayed in a picture report + - Added option to enable Bogey Dopes + * Mission designer can turn on / off in script settings + * Pilots can request thru the F10 menu and it will show the BRA to the nearest hostile aircraft that has + been detected. It will always reference the requesting pilot's own aircraft. + - Finally implemented a cleaner workaround for some ground units being detected and listed in picture report + - 1.4.1 - Added some ships to search radar list, you will need to remove the comment markers (--) at the start of the line to activate + - 1.5 - Added ability to request picture of friendly aircraft positions referencing your own aircraft - Mission designer chooses if this feature is active or not + - 1.5.1 - Added Gazelle to acCategories + - 1.5.2 - Added F5E to acCategories + - 1.5.3 - Fixed bug with maxThreatDisplay set at 0 not displaying any threats + - Added Mistral Gazelle + - Added C-101CC +]] + +ewrs = {} --DO NOT REMOVE +ewrs.HELO = 1 +ewrs.ATTACK = 2 +ewrs.FIGHTER = 3 + +----SCRIPT OPTIONS---- + +ewrs.messageUpdateInterval = 30 --How often EWRS will update automated BRA messages (seconds) +ewrs.messageDisplayTime = 25 --How long EWRS BRA messages will show for (seconds) +ewrs.restrictToOneReference = false -- Disables the ability to change the BRA calls from pilot's own aircraft or bullseye. If this is true, set ewrs.defaultReference to the option you want to restrict to. +ewrs.defaultReference = "self" --The default reference for BRA calls - can be changed via f10 radio menu if ewrs.restrictToOneReference is false (self or bulls) +ewrs.defaultMeasurements = "imperial" --Default measurement units - can be changed via f10 radio menu (imperial or metric) +ewrs.disableFightersBRA = false -- disables BRA messages to fighters when true +ewrs.enableRedTeam = true -- enables / disables EWRS for the red team +ewrs.enableBlueTeam = true -- enables / disables EWRS for the blue team +ewrs.disableMessageWhenNoThreats = true -- disables message when no threats are detected - Thanks Rivvern - NOTE: If using ewrs.onDemand = true, this has no effect +ewrs.useImprovedDetectionLogic = true --this makes the messages more realistic. If the radar doesn't know the type or distance to the detected threat, it will be reflected in the picture report / BRA message +ewrs.onDemand = false --Setting to true will disable the automated messages to everyone and will add an F10 menu to get picture / BRA message. +ewrs.maxThreatDisplay = 5 -- Max amounts of threats to display on picture report (0 will display all) +ewrs.allowBogeyDope = true -- Allows pilots to request a bogey dope even with the automated messages running. It will display only the cloest threat, and will always reference the players own aircraft. +ewrs.allowFriendlyPicture = true -- Allows pilots to request picture of friendly aircraft +ewrs.maxFriendlyDisplay = 5 -- Limits the amount of friendly aircraft shown on friendly picture + +--[[ +Units with radar to use as part of the EWRS radar network +If you want to shorten the range of SAM radar detection, use their track radars instead of their search radars +NOTE that track radars require a search radar to detect targets (but the search radars do not need to be included in the list) +I haven't tested detection with ships (that have radar), but should work. +]] +ewrs.validSearchRadars = { +"p-10 s125 sr", --SA-3 Search Radar +"Kub 1S91 str", --SA-6 Search and Track Radar +"S-300PS 64H6E sr", --SA-10 Search Radar +"S-300 PS 40B6MD sr", --SA-10 Search Radar +"SA-11 Buk SR 9518M1", --SA-11 Search Radar +"55G6 EWR", --Early Warning Radar +"1L13 EWR", --Early Warning Radar +"A-50", --AWACS +"E-2D", --AWACS +"E-3A", --AWACS +"Roland Radar", --Roland Search Radar +"Hawk sr", --Hawk SAM Search Radar +"Patriot str", --Patriot SAM Search and Track Radar + +--Ships - I've left these commented out because I don't know which ones have radar +--and which ones don't. Just remove the comment to activate them (the '--' at the start of the line) + +--"MOSCOW", -- CG 1164 Moskva +--"TICONDEROG", -- CG-60 Normandy +--"PIOTR", -- CGN 1144.2 Pyotr Velikiy +--"KUZNECOW", -- CV 1143.5 Admiral Kuzentsov +--"VINSON", -- CVN-70 Carl Vinson +--"REZKY", -- FF 1135M Rezky +--"NEUSTRASH", -- FFG 11540 Neustrashimy +--"PERRY", -- FFG-7CL Oliver Hazzard Perry +--"ALBATROS", -- FFL 1124.4 Grisha +--"MOLNIYA", -- FSG 1241.1MP Molniya +} + +--[[ +Aircraft Type ENUMs +This is used to restrict BRA messages to fighters +Change the ewrs.TYPE for each aircraft (in ewrs.acCategories) to suit your needs +For now, BRA will be displayed to everyone unless ewrs.disableFightersBRA is true. +When this is true, anything in the list below that == ewrs.FIGHTER will NOT receive BRA messages +]] +ewrs.acCategories = { --Have I left anything out? Please let me know if I have +[ "A-10A" ] = ewrs.ATTACK , +[ "A-10C" ] = ewrs.ATTACK , +[ "Bf-109K-4" ] = ewrs.ATTACK , +[ "C-101EB" ] = ewrs.ATTACK , +[ "C-101CC" ] = ewrs.ATTACK , +[ "F-15C" ] = ewrs.FIGHTER , +[ "F-5E-3" ] = ewrs.ATTACK , +[ "FW-190D9" ] = ewrs.ATTACK , +[ "F-86F Sabre" ] = ewrs.FIGHTER , +[ "Hawk" ] = ewrs.ATTACK , +[ "Ka-50" ] = ewrs.HELO , +[ "L-39C" ] = ewrs.ATTACK , +[ "L-39ZA" ] = ewrs.ATTACK , +[ "Mi-8MT" ] = ewrs.HELO , +[ "MiG-15bis" ] = ewrs.ATTACK , +[ "MiG-21Bis" ] = ewrs.ATTACK , +[ "MiG-29A" ] = ewrs.FIGHTER , +[ "MiG-29S" ] = ewrs.FIGHTER , +[ "M-2000C" ] = ewrs.FIGHTER , +[ "P-51D" ] = ewrs.ATTACK , +[ "SA342M" ] = ewrs.HELO , +[ "SA342L" ] = ewrs.HELO , +[ "SA342Mistral" ] = ewrs.HELO , +[ "Su-25" ] = ewrs.ATTACK , +[ "Su-25T" ] = ewrs.ATTACK , +[ "Su-27" ] = ewrs.FIGHTER , +[ "Su-33" ] = ewrs.FIGHTER , +[ "TF-51D" ] = ewrs.ATTACK , +[ "UH-1H" ] = ewrs.HELO , +} + +----END OF SCRIPT OPTIONS---- + + +----INTERNAL FUNCTIONS ***** Be Careful changing things below here ***** ---- + + +function ewrs.getDistance(obj1PosX, obj1PosZ, obj2PosX, obj2PosZ) + local xDiff = obj1PosX - obj2PosX + local yDiff = obj1PosZ - obj2PosZ + return math.sqrt(xDiff * xDiff + yDiff * yDiff) -- meters +end + +function ewrs.getBearing(obj1PosX, obj1PosZ, obj2PosX, obj2PosZ) + local bearing = math.atan2(obj2PosZ - obj1PosZ, obj2PosX - obj1PosX) + if bearing < 0 then + bearing = bearing + 2 * math.pi + end + bearing = bearing * 180 / math.pi + return bearing -- degrees +end + +function ewrs.getHeading(vec) + local heading = math.atan2(vec.z,vec.x) + if heading < 0 then + heading = heading + 2 * math.pi + end + heading = heading * 180 / math.pi + return heading -- degrees +end + +function ewrs.getSpeed(velocity) + local speed = math.sqrt(velocity.x^2 + velocity.y^2 + velocity.z^2) --m/s + return speed -- m/s +end + +function ewrs.update() + timer.scheduleFunction(ewrs.update, nil, timer.getTime() + 5) + ewrs.buildActivePlayers() + ewrs.buildF10Menu() +end + +function ewrs.buildThreatTable(activePlayer, bogeyDope) + local function sortRanges(v1,v2) + return v1.range < v2.range + end + + local targets = {} + if activePlayer.side == 2 then + targets = ewrs.currentlyDetectedRedUnits + else + targets = ewrs.currentlyDetectedBlueUnits + end + + local bogeyDope = bogeyDope or false + local referenceX + local referenceZ + if ewrs.groupSettings[tostring(activePlayer.groupID)].reference == "self" or bogeyDope then + local _self = Unit.getByName(activePlayer.unitname) + local selfpos = _self:getPosition() + referenceX = selfpos.p.x + referenceZ = selfpos.p.z + else + local bullseye = coalition.getMainRefPoint(activePlayer.side) + referenceX = bullseye.x + referenceZ = bullseye.z + end + + local threatTable = {} + + for k,v in pairs(targets) do + local velocity = v["object"]:getVelocity() + local bogeypos = v["object"]:getPosition() + local bogeyType = nil + if ewrs.useImprovedDetectionLogic then + if v["type"] then + bogeyType = v["object"]:getTypeName() + else + bogeyType = " ??? " + end + else + bogeyType = v["object"]:getTypeName() + end + + local bearing = ewrs.getBearing(referenceX,referenceZ,bogeypos.p.x,bogeypos.p.z) + local heading = ewrs.getHeading(velocity) + local range = ewrs.getDistance(referenceX,referenceZ,bogeypos.p.x,bogeypos.p.z) -- meters + local altitude = bogeypos.p.y --meters + local speed = ewrs.getSpeed(velocity) --m/s + + if ewrs.groupSettings[tostring(activePlayer.groupID)].measurements == "metric" then + range = range / 1000 --change to KM + speed = mist.utils.mpsToKmph(speed) + --altitude already in meters + else + range = mist.utils.metersToNM(range) + speed = mist.utils.mpsToKnots(speed) + altitude = mist.utils.metersToFeet(altitude) + end + + if ewrs.useImprovedDetectionLogic then + if not v["distance"] then + range = ewrs.notAvailable + end + end + + local j = #threatTable + 1 + threatTable[j] = {} + threatTable[j].unitType = bogeyType + threatTable[j].bearing = bearing + threatTable[j].range = range + threatTable[j].altitude = altitude + threatTable[j].speed = speed + threatTable[j].heading = heading + end + + table.sort(threatTable,sortRanges) + + return threatTable +end + +function ewrs.outText(activePlayer, threatTable, bogeyDope, greeting) + local status, result = pcall(function() + + local message = {} + local altUnits + local speedUnits + local rangeUnits + local bogeyDope = bogeyDope or false + if ewrs.groupSettings[tostring(activePlayer.groupID)].measurements == "metric" then + altUnits = "m" + speedUnits = "Km/h" + rangeUnits = "Km" + else + altUnits = "ft" + speedUnits = "Knts" + rangeUnits = "NM" + end + + if #threatTable >= 1 then + local maxThreats = nil + local messageGreeting = nil + if greeting == nil then + if bogeyDope then + maxThreats = 1 + messageGreeting = "EWRS Bogey Dope for: " .. activePlayer.player + else + if ewrs.maxThreatDisplay == 0 then + maxThreats = 999 + else + maxThreats = ewrs.maxThreatDisplay + end + messageGreeting = "EWRS Picture Report for: " .. activePlayer.player .. " -- Reference: " .. ewrs.groupSettings[tostring(activePlayer.groupID)].reference + end + else + messageGreeting = greeting + maxThreats = ewrs.maxFriendlyDisplay + end + + --Display table + table.insert(message, "\n") + table.insert(message, messageGreeting) + table.insert(message, "\n\n") + table.insert(message, string.format( "%-16s", "TYPE")) + table.insert(message, string.format( "%-12s", "BRG")) + table.insert(message, string.format( "%-12s", "RNG")) + table.insert(message, string.format( "%-21s", "ALT")) + table.insert(message, string.format( "%-15s", "SPD")) + table.insert(message, string.format( "%-3s", "HDG")) + table.insert(message, "\n") + + for k = 1, maxThreats do + if threatTable[k] == nil then break end + table.insert(message, "\n") + table.insert(message, string.format( "%-16s", threatTable[k].unitType)) + if threatTable[k].range == ewrs.notAvailable then + table.insert(message, string.format( "%-12s", " ")) + table.insert(message, string.format( "%-12s", "POSITION")) + table.insert(message, string.format( "%-21s", " ")) + table.insert(message, string.format( "%-15s", "UNKNOWN")) + table.insert(message, string.format( "%-3s", " ")) + else + table.insert(message, string.format( "%03d", threatTable[k].bearing)) + table.insert(message, string.format( "%8.1f %s", threatTable[k].range, rangeUnits)) + table.insert(message, string.format( "%9d %s", threatTable[k].altitude, altUnits)) + table.insert(message, string.format( "%9d %s", threatTable[k].speed, speedUnits)) + table.insert(message, string.format( " %03d", threatTable[k].heading)) + end + table.insert(message, "\n") + end + trigger.action.outTextForGroup(activePlayer.groupID, table.concat(message), ewrs.messageDisplayTime) + else + if (not ewrs.disableMessageWhenNoThreats) or (ewrs.onDemand) and greeting == nil then + trigger.action.outTextForGroup(activePlayer.groupID, "\nEWRS Picture Report for: " .. activePlayer.player .. "\n\nNo targets detected", ewrs.messageDisplayTime) + end + if greeting ~= nil then + trigger.action.outTextForGroup(activePlayer.groupID, "\nEWRS Friendly Picture for: " .. activePlayer.player .. "\n\nNo friendlies detected", ewrs.messageDisplayTime) + end + end + end) + if not status then + env.error(string.format("EWRS outText Error: %s", result)) + end +end + +function ewrs.displayMessageToAll() + local status, result = pcall(function() + timer.scheduleFunction(ewrs.displayMessageToAll, nil, timer.getTime() + ewrs.messageUpdateInterval) + ewrs.findRadarUnits() + ewrs.getDetectedTargets() + for i = 1, #ewrs.activePlayers do + if ewrs.groupSettings[tostring(ewrs.activePlayers[i].groupID)].messages then + if ewrs.activePlayers[i].side == 1 and #ewrs.redEwrUnits > 0 or ewrs.activePlayers[i].side == 2 and #ewrs.blueEwrUnits > 0 then + ewrs.outText(ewrs.activePlayers[i], ewrs.buildThreatTable(ewrs.activePlayers[i])) + end -- if ewrs.activePlayers[i].side == 1 and #ewrs.redEwrUnits > 0 or ewrs.activePlayers[i].side == 2 and #ewrs.blueEwrUnits > 0 then + end -- if ewrs.groupSettings[tostring(ewrs.activePlayers[i].groupID)].messages then + end -- for i = 1, #ewrs.activePlayers do + end) + if not status then + env.error(string.format("EWRS displayMessageToAll Error: %s", result)) + end +end + +function ewrs.onDemandMessage(args) + local status, result = pcall(function() + ewrs.findRadarUnits() + ewrs.getDetectedTargets() + for i = 1, #ewrs.activePlayers do + if ewrs.activePlayers[i].groupID == args[1] then + ewrs.outText(ewrs.activePlayers[i], ewrs.buildThreatTable(ewrs.activePlayers[i],args[2]),args[2]) + end + end + end) + if not status then + env.error(string.format("EWRS onDemandMessage Error: %s", result)) + end +end + +function ewrs.buildFriendlyTable(friendlyNames,activePlayer) + local function sortRanges(v1,v2) + return v1.range < v2.range + end + + local units = {} + for i =1, #friendlyNames do + local unit = Unit.getByName(friendlyNames[i]) + if unit ~= nil and unit:isActive() then + + table.insert(units,unit) + else + --env.error("Friendly Picture - Unit not found: "..friendlyNames[i]) -- Client Planes that are not active will fall into here. + end + end + + local _self = Unit.getByName(activePlayer.unitname) + local selfpos = _self:getPosition() + local referenceX = selfpos.p.x + local referenceZ = selfpos.p.z + + local friendlyTable = {} + + for k,v in pairs(units) do + local velocity = v:getVelocity() + local pos = v:getPosition() + local bogeyType = v:getTypeName() + if pos.p.x ~= selfpos.p.x and pos.p.z ~= selfpos.p.z then --same position as self, means its you! + + local bearing = ewrs.getBearing(referenceX,referenceZ,pos.p.x,pos.p.z) + local heading = ewrs.getHeading(velocity) + local range = ewrs.getDistance(referenceX,referenceZ,pos.p.x,pos.p.z) -- meters + local altitude = pos.p.y --meters + local speed = ewrs.getSpeed(velocity) --m/s + + if ewrs.groupSettings[tostring(activePlayer.groupID)].measurements == "metric" then + range = range / 1000 --change to KM + speed = mist.utils.mpsToKmph(speed) + --altitude already in meters + else + range = mist.utils.metersToNM(range) + speed = mist.utils.mpsToKnots(speed) + altitude = mist.utils.metersToFeet(altitude) + end + + local j = #friendlyTable + 1 + friendlyTable[j] = {} + friendlyTable[j].unitType = bogeyType + friendlyTable[j].bearing = bearing + friendlyTable[j].range = range + friendlyTable[j].altitude = altitude + friendlyTable[j].speed = speed + friendlyTable[j].heading = heading + else + --env.info("Friendly Picture - Found Self") + end + end + + table.sort(friendlyTable,sortRanges) + + return friendlyTable +end + +function ewrs.friendlyPicture(args) + local status, result = pcall(function() + for i = 1, #ewrs.activePlayers do + if ewrs.activePlayers[i].groupID == args[1] then + local sideString = nil + if ewrs.activePlayers[i].side == 1 then + sideString = "[red]" + else + sideString = "[blue]" + end + local filter = {sideString.."[helicopter]", sideString.."[plane]"} + local friendlies = mist.makeUnitTable(filter) --find a way to do this only once if there is more then 1 person in a group + local friendlyTable = ewrs.buildFriendlyTable(friendlies,ewrs.activePlayers[i]) + local greeting = "EWRS Friendly Picture for: " .. ewrs.activePlayers[i].player + ewrs.outText(ewrs.activePlayers[i],friendlyTable,false,greeting) + end + end + end) + if not status then + env.error(string.format("EWRS friendlyPicture Error: %s", result)) + end +end + +function ewrs.buildActivePlayers() + local status, result = pcall(function() + local filter = { "[all][plane]","[all][helicopter]"} + local all_vecs = mist.makeUnitTable(filter) + ewrs.activePlayers = {} + for i = 1, #all_vecs do + local vec = Unit.getByName(all_vecs[i]) + if vec ~= nil and Unit.isActive(vec) then + playerName = Unit.getPlayerName(vec) + local groupID = ewrs.getGroupId(vec) + if playerName ~= nil then + unitCategory = ewrs.acCategories[Unit.getTypeName(vec)] + if ewrs.disableFightersBRA and unitCategory == ewrs.FIGHTER then + --DONT DO ANYTHING + else + local group = Unit.getGroup(vec) + if ewrs.enableBlueTeam and Unit.getCoalition(vec) == 2 then + ewrs.addPlayer(playerName, groupID, vec) + elseif ewrs.enableRedTeam and Unit.getCoalition(vec) == 1 then + ewrs.addPlayer(playerName, groupID, vec) + end + end + end + end + end + end) -- pcall + + if not status then + env.error(string.format("EWRS buildActivePlayers Error: %s", result)) + end +end + +--THANK YOU ciribob http://forums.eagle.ru/showpost.php?p=2499638&postcount=5 +--And Stonehouse for pointing me there +function ewrs.getGroupId(_unit) --Temp fix for client groups not being accessable + + local _unitDB = mist.DBs.unitsById[tonumber(_unit:getID())] + if _unitDB ~= nil and _unitDB.groupId then + return _unitDB.groupId + end + + return nil +end + +function ewrs.getGroupCategory(unit) + local unitDB = mist.DBs.unitsById[tonumber(unit:getID())] + if unitDB ~= nil and unitDB.category then + return unitDB.category + end + + return nil +end + +function ewrs.addPlayer(playerName, groupID, unit ) + local status, result = pcall(function() + local i = #ewrs.activePlayers + 1 + ewrs.activePlayers[i] = {} + ewrs.activePlayers[i].player = playerName + ewrs.activePlayers[i].groupID = groupID + ewrs.activePlayers[i].unitname = unit:getName() + ewrs.activePlayers[i].side = unit:getCoalition() + + -- add default settings to settings table if it hasn't been done yet + if ewrs.groupSettings[tostring(groupID)] == nil then + ewrs.addGroupSettings(tostring(groupID)) + end + end) + if not status then + env.error(string.format("EWRS addPlayer Error: %s", result)) + end +end + +-- filters units so ones detected by multiple radar sites still only get listed once +-- Filters out anything that isn't a plane or helicopter +function ewrs.filterUnits(units) + local newUnits = {} + for k,v in pairs(units) do + local valid = true + if v["object"]:getCategory() ~= Object.Category.UNIT then --rare but i've had it detect missiles + valid = false + end + if valid then --another check cause it seems AI radar can detected some ground units + local category = ewrs.getGroupCategory(v["object"]) + if category ~= "plane" and category ~= "helicopter" then valid = false end + end + + if valid then + for nk,nv in pairs (newUnits) do --recursive loop, can't see a way around this + if v["object"]:getName() == nv["object"]:getName() then + valid = false + --update already found unit incase the first detection(s) didn't know type or distance + if v["type"] then + nv["type"] = true + end + if v["distance"] then + nv["distance"] = true + end + end + end + end + + if valid then + table.insert(newUnits, v) + end + end + return newUnits +end + +function ewrs.getDetectedTargets() + if #ewrs.blueEwrUnits > 0 then + ewrs.currentlyDetectedRedUnits = ewrs.findDetectedTargets("red") + end + if #ewrs.redEwrUnits > 0 then + ewrs.currentlyDetectedBlueUnits = ewrs.findDetectedTargets("blue") + end +end + +function ewrs.findDetectedTargets(side) + local units = {} + local ewrUnits = {} + + if side == "red" then + ewrUnits = ewrs.blueEwrUnits + elseif side == "blue" then + ewrUnits = ewrs.redEwrUnits + end + + for n = 1, #ewrUnits do + local ewrUnit = Unit.getByName(ewrUnits[n]) + if ewrUnit ~= nil then + local ewrControl = ewrUnit:getGroup():getController() + local detectedTargets = ewrControl:getDetectedTargets(Controller.Detection.RADAR) + for k,v in pairs (detectedTargets) do + table.insert(units, v) + end + end + end + return ewrs.filterUnits(units) +end + +function ewrs.findRadarUnits() + local filter = {} + if ewrs.enableBlueTeam and ewrs.enableRedTeam then + filter = { "[all][plane]", "[all][vehicle]", "[all][ship]"} + elseif ewrs.enableBlueTeam then + filter = { "[blue][plane]", "[blue][vehicle]", "[blue][ship]"} + elseif ewrs.enableRedTeam then + filter = { "[red][plane]", "[red][vehicle]", "[red][ship]"} + end + local all_vecs = mist.makeUnitTable(filter) + local redUnits = {} + local blueUnits = {} + + for i = 1, #all_vecs do + local vec = Unit.getByName(all_vecs[i]) + + if vec ~= nil then + if Unit.isActive(vec) then + local vec_type = Unit.getTypeName(vec) + for n = 1, #ewrs.validSearchRadars do + if ewrs.validSearchRadars[n] == vec_type and Unit.getCoalition(vec) == 2 then + table.insert(blueUnits, Unit.getName(vec)) + break + end + if ewrs.validSearchRadars[n] == vec_type and Unit.getCoalition(vec) == 1 then + table.insert(redUnits, Unit.getName(vec)) + break + end + end --for n = 1, #ewrs.validSearchRadars do + end --if Unit.isActive(vec) then + end --if vec ~= nil then + end --for i = 1, #all_vecs do + ewrs.blueEwrUnits = blueUnits + ewrs.redEwrUnits = redUnits +end + +function ewrs.addGroupSettings(groupID) + ewrs.groupSettings[groupID] = {} + ewrs.groupSettings[groupID].reference = ewrs.defaultReference + ewrs.groupSettings[groupID].measurements = ewrs.defaultMeasurements + ewrs.groupSettings[groupID].messages = true +end + +function ewrs.setGroupReference(args) + local groupID = args[1] + ewrs.groupSettings[tostring(groupID)].reference = args[2] + trigger.action.outTextForGroup(groupID,"Reference changed to "..args[2],ewrs.messageDisplayTime) +end + +function ewrs.setGroupMeasurements(args) + local groupID = args[1] + ewrs.groupSettings[tostring(groupID)].measurements = args[2] + trigger.action.outTextForGroup(groupID,"Measurement units changed to "..args[2],ewrs.messageDisplayTime) +end + +function ewrs.setGroupMessages(args) + local groupID = args[1] + local onOff + if args[2] then onOff = "on" else onOff = "off" end + ewrs.groupSettings[tostring(groupID)].messages = args[2] + trigger.action.outTextForGroup(groupID,"Picture reports for group turned "..onOff,ewrs.messageDisplayTime) +end + +function ewrs.buildF10Menu() + local status, result = pcall(function() + for i = 1, #ewrs.activePlayers do + local groupID = ewrs.activePlayers[i].groupID + local stringGroupID = tostring(groupID) + if ewrs.builtF10Menus[stringGroupID] == nil then + local rootPath = missionCommands.addSubMenuForGroup(groupID, "EWRS") + + if ewrs.allowBogeyDope then + missionCommands.addCommandForGroup(groupID, "Request Bogey Dope",rootPath,ewrs.onDemandMessage,{groupID,true}) + end + + if ewrs.onDemand then + missionCommands.addCommandForGroup(groupID, "Request Picture",rootPath,ewrs.onDemandMessage,{groupID}) + end + + if ewrs.allowFriendlyPicture then + missionCommands.addCommandForGroup(groupID, "Request Friendly Picture",rootPath,ewrs.friendlyPicture,{groupID}) + end + + if not ewrs.restrictToOneReference then + local referenceSetPath = missionCommands.addSubMenuForGroup(groupID,"Set GROUP's reference point", rootPath) + missionCommands.addCommandForGroup(groupID, "Set to Bullseye",referenceSetPath,ewrs.setGroupReference,{groupID, "bulls"}) + missionCommands.addCommandForGroup(groupID, "Set to Self",referenceSetPath,ewrs.setGroupReference,{groupID, "self"}) + end + + local measurementsSetPath = missionCommands.addSubMenuForGroup(groupID,"Set GROUP's measurement units",rootPath) + missionCommands.addCommandForGroup(groupID, "Set to Imperial (feet, knts)",measurementsSetPath,ewrs.setGroupMeasurements,{groupID, "imperial"}) + missionCommands.addCommandForGroup(groupID, "Set to Metric (meters, km/h)",measurementsSetPath,ewrs.setGroupMeasurements,{groupID, "metric"}) + + if not ewrs.onDemand then + local messageOnOffPath = missionCommands.addSubMenuForGroup(groupID, "Turn Picture Report On/Off",rootPath) + missionCommands.addCommandForGroup(groupID, "Message ON", messageOnOffPath, ewrs.setGroupMessages, {groupID, true}) + missionCommands.addCommandForGroup(groupID, "Message OFF", messageOnOffPath, ewrs.setGroupMessages, {groupID, false}) + end + + ewrs.builtF10Menus[stringGroupID] = true + end + end + end) + + if not status then + env.error(string.format("EWRS buildF10Menu Error: %s", result)) + end +end + +--temp fix for ground units being detected by radar - FIXED +--[[ Leaving this here just in case I introduce threat based filtering, saves me writing it again +ewrs.validThreats = { +["A-10A"] = true, +["A-10C"] = true, +["A-50"] = true, +["AH-1W"] = true, +["AH-64A"] = true, +["AH-64D"] = true, +["An-26B"] = true, +["An-30M"] = true, +["B-1B"] = true, +["B-52H"] = true, +["Bf-109K-4"] = true, +["C-101CC"] = true, +["C-101EB"] = true, +["C-130"] = true, +["C-17A"] = true, +["CH-47D"] = true, +["CH-53E"] = true, +["E-2D"] = true, +["E-2C"] = true, +["E-3A"] = true, +["F-111F"] = true, +["F-117A"] = true, +["F-14A"] = true, +["F-15C"] = true, +["F-15E"] = true, +["F-16A"] = true, +["F-16A MLU"] = true, +["F-16C bl.50"] = true, +["F-16C bl.52d"] = true, +["F-4E"] = true, +["F-5E"] = true, +["F-5E-3"] = true, +["F-86F Sabre"] = true, +["F/A-18A"] = true, +["F/A-18C"] = true, +["FW-190D9"] = true, +["Hawk"] = true, +["IL-76MD"] = true, +["IL-78M"] = true, +["KC-135"] = true, +["Ka-27"] = true, +["Ka-50"] = true, +["Ka-52"] = true, +["L-39C"] = true, +["L-39ZA"] = true, +["M-2000C"] = true, +["MQ-9 Reaper"] = true, +["Mi-24V"] = true, +["Mi-26"] = true, +["Mi-28N"] = true, +["Mi-8MT"] = true, +["MiG-15bis"] = true, +["MiG-21Bis"] = true, +["MiG-23MLD"] = true, +["MiG-25PD"] = true, +["MiG-25RBT"] = true, +["MiG-27K"] = true, +["MiG-29A"] = true, +["MiG-29G"] = true, +["MiG-29K"] = true, +["MiG-29S"] = true, +["MiG-31"] = true, +["Mirage 2000-5"] = true, +["OH-58D"] = true, +["P-51D"] = true, +["RQ-1A Predator"] = true, +["S-3B"] = true, +["S-3B Tanker"] = true, +["SH-3W"] = true, +["SH-60B"] = true, +["Su-17M4"] = true, +["Su-24M"] = true, +["Su-24MR"] = true, +["Su-25"] = true, +["Su-25T"] = true, +["Su-25TM"] = true, +["Su-27"] = true, +["Su-30"] = true, +["Su-33"] = true, +["Su-34"] = true, +["TF-51D"] = true, +["Tornado GR4"] = true, +["Tornado IDS"] = true, +["Tu-142"] = true, +["Tu-160"] = true, +["Tu-22M3"] = true, +["Tu-95MS"] = true, +["UH-1H"] = true, +["UH-60A"] = true, +["Yak-40"] = true, +} +]] + +--SCRIPT INIT +ewrs.currentlyDetectedRedUnits = {} +ewrs.currentlyDetectedBlueUnits = {} +ewrs.redEwrUnits = {} +ewrs.blueEwrUnits = {} +ewrs.activePlayers = {} +ewrs.groupSettings = {} +ewrs.builtF10Menus = {} +ewrs.notAvailable = 999999 + +ewrs.update() +if not ewrs.onDemand then + timer.scheduleFunction(ewrs.displayMessageToAll, nil, timer.getTime() + ewrs.messageUpdateInterval) +end +trigger.action.outText("EWRS by Steggles is now running",15) +env.info("EWRS Running") + +--[[ +TODO: + - Add check on friendly picture to not give one if no AWACS / EWR units are active. Doesn't use radar info anyway. Maybe just leave it to help out people with SA? Feedback Please!! + - Clean up functions and arguments from bogeyDope and friendly picture additions + - Threat based filtering if theres interest. +]] \ No newline at end of file diff --git a/resources/plugins/ewrs/plugin.json b/resources/plugins/ewrs/plugin.json new file mode 100644 index 00000000..8787db14 --- /dev/null +++ b/resources/plugins/ewrs/plugin.json @@ -0,0 +1,12 @@ +{ + "nameInUI": "EWRS", + "defaultValue": false, + "specificOptions": [], + "scriptsWorkOrders": [ + { + "file": "ewrs.lua", + "mnemonic": "ewrs" + } + ], + "configurationWorkOrders": [] +} \ No newline at end of file diff --git a/resources/plugins/plugins.json b/resources/plugins/plugins.json index 377cda18..9b415eea 100644 --- a/resources/plugins/plugins.json +++ b/resources/plugins/plugins.json @@ -2,5 +2,6 @@ "base", "jtacautolase", "skynetiads", + "ewrs", "herculescargo" ] diff --git a/resources/stylesheets/style-dcs.css b/resources/stylesheets/style-dcs.css index 5cf07d77..f8539e83 100644 --- a/resources/stylesheets/style-dcs.css +++ b/resources/stylesheets/style-dcs.css @@ -546,7 +546,7 @@ QGroupBox[style="QWeatherWidget"] { padding: 0px; margin-left: 0px; margin-right: 5px; - margin-top: 1ex; + margin-top: 1px; margin-bottom: 5px; } @@ -555,4 +555,22 @@ QGroupBox[style="QWeatherWidget"] QLabel[style="text-sm"] { margin: 0px; font-size: 9px; line-height: 9px; +} + +QGroupBox[style="IntelSummary"] { + padding-left: 40px; + padding-right: 0px; + padding-top: 0px; + padding-bottom: 0px; + margin-left: 0px; + margin-right: 5px; + margin-top: 1px; + margin-bottom: 5px; +} + +QGroupBox[style="IntelSummary"] QLabel { + padding: 0px; + margin: 0px; + font-size: 9px; + line-height: 9px; } \ No newline at end of file diff --git a/resources/syrialandmap.p b/resources/syrialandmap.p index 658394d6..1b5cc168 100644 Binary files a/resources/syrialandmap.p and b/resources/syrialandmap.p differ diff --git a/resources/tools/syria_terrain.miz b/resources/tools/syria_terrain.miz index 9d6cc228..a50e4e92 100644 Binary files a/resources/tools/syria_terrain.miz and b/resources/tools/syria_terrain.miz differ diff --git a/resources/ui/units/aircrafts/F-14A-135-GR_24.jpg b/resources/ui/units/aircrafts/F-14A-135-GR_24.jpg new file mode 100644 index 00000000..6ff978cb Binary files /dev/null and b/resources/ui/units/aircrafts/F-14A-135-GR_24.jpg differ diff --git a/resources/ui/units/vehicles/BTR-82A_24.jpg b/resources/ui/units/vehicles/BTR-82A_24.jpg new file mode 100644 index 00000000..e5454a1d Binary files /dev/null and b/resources/ui/units/vehicles/BTR-82A_24.jpg differ diff --git a/resources/ui/units/vehicles/Bedford MWD_24.jpg b/resources/ui/units/vehicles/Bedford_MWD_24.jpg similarity index 100% rename from resources/ui/units/vehicles/Bedford MWD_24.jpg rename to resources/ui/units/vehicles/Bedford_MWD_24.jpg diff --git a/resources/ui/units/vehicles/Blitz 3.6-6700A_24.jpg b/resources/ui/units/vehicles/Blitz_36-6700A_24.jpg similarity index 100% rename from resources/ui/units/vehicles/Blitz 3.6-6700A_24.jpg rename to resources/ui/units/vehicles/Blitz_36-6700A_24.jpg diff --git a/resources/ui/units/vehicles/Centaur_IV_24.jpg b/resources/ui/units/vehicles/Centaur_IV_24.jpg new file mode 100644 index 00000000..dcbabd27 Binary files /dev/null and b/resources/ui/units/vehicles/Centaur_IV_24.jpg differ diff --git a/resources/ui/units/vehicles/M1043 HMMWV TOW_24.jpg b/resources/ui/units/vehicles/Churchill_VII_24.jpg similarity index 56% rename from resources/ui/units/vehicles/M1043 HMMWV TOW_24.jpg rename to resources/ui/units/vehicles/Churchill_VII_24.jpg index f24eddfd..2f46a79a 100644 Binary files a/resources/ui/units/vehicles/M1043 HMMWV TOW_24.jpg and b/resources/ui/units/vehicles/Churchill_VII_24.jpg differ diff --git a/resources/ui/units/vehicles/Cromwell IV_24.jpg b/resources/ui/units/vehicles/Cromwell_IV_24.jpg similarity index 100% rename from resources/ui/units/vehicles/Cromwell IV_24.jpg rename to resources/ui/units/vehicles/Cromwell_IV_24.jpg diff --git a/resources/ui/units/vehicles/Daimler_AC_24.jpg b/resources/ui/units/vehicles/Daimler_AC_24.jpg new file mode 100644 index 00000000..a81db45e Binary files /dev/null and b/resources/ui/units/vehicles/Daimler_AC_24.jpg differ diff --git a/resources/ui/units/vehicles/Elefant_SdKfz_184_24.jpg b/resources/ui/units/vehicles/Elefant_SdKfz_184_24.jpg new file mode 100644 index 00000000..210967d7 Binary files /dev/null and b/resources/ui/units/vehicles/Elefant_SdKfz_184_24.jpg differ diff --git a/resources/ui/units/vehicles/Flakscheinwerfer_37_24.jpg b/resources/ui/units/vehicles/Flakscheinwerfer_37_24.jpg new file mode 100644 index 00000000..f0996252 Binary files /dev/null and b/resources/ui/units/vehicles/Flakscheinwerfer_37_24.jpg differ diff --git a/resources/ui/units/vehicles/FuMG-401_24.jpg b/resources/ui/units/vehicles/FuMG-401_24.jpg new file mode 100644 index 00000000..9d60a3cc Binary files /dev/null and b/resources/ui/units/vehicles/FuMG-401_24.jpg differ diff --git a/resources/ui/units/vehicles/Grad-Ural.jpg b/resources/ui/units/vehicles/Grad-Ural.jpg new file mode 100644 index 00000000..d2ceef28 Binary files /dev/null and b/resources/ui/units/vehicles/Grad-Ural.jpg differ diff --git a/resources/ui/units/vehicles/Jagdpanzer IV_24.jpg b/resources/ui/units/vehicles/JagdPz_IV_24.jpg similarity index 100% rename from resources/ui/units/vehicles/Jagdpanzer IV_24.jpg rename to resources/ui/units/vehicles/JagdPz_IV_24.jpg diff --git a/resources/ui/units/vehicles/Jagdpanther_24.jpg b/resources/ui/units/vehicles/Jagdpanther_G1_24.jpg similarity index 100% rename from resources/ui/units/vehicles/Jagdpanther_24.jpg rename to resources/ui/units/vehicles/Jagdpanther_G1_24.jpg diff --git a/resources/ui/units/vehicles/KDO_Mod40_24.jpg b/resources/ui/units/vehicles/KDO_Mod40_24.jpg new file mode 100644 index 00000000..76068edc Binary files /dev/null and b/resources/ui/units/vehicles/KDO_Mod40_24.jpg differ diff --git a/resources/ui/units/vehicles/Kubelwagen_82_24.jpg b/resources/ui/units/vehicles/Kubelwagen_82_24.jpg new file mode 100644 index 00000000..01907104 Binary files /dev/null and b/resources/ui/units/vehicles/Kubelwagen_82_24.jpg differ diff --git a/resources/ui/units/vehicles/M1045 HMMWV TOW_24.jpg b/resources/ui/units/vehicles/M1045 HMMWV TOW_24.jpg new file mode 100644 index 00000000..c37355f0 Binary files /dev/null and b/resources/ui/units/vehicles/M1045 HMMWV TOW_24.jpg differ diff --git a/resources/ui/units/vehicles/M10_GMC_24.jpg b/resources/ui/units/vehicles/M10_GMC_24.jpg new file mode 100644 index 00000000..c8c84ed6 Binary files /dev/null and b/resources/ui/units/vehicles/M10_GMC_24.jpg differ diff --git a/resources/ui/units/vehicles/M12_24.jpg b/resources/ui/units/vehicles/M12_GMC_24.jpg similarity index 100% rename from resources/ui/units/vehicles/M12_24.jpg rename to resources/ui/units/vehicles/M12_GMC_24.jpg diff --git a/resources/ui/units/vehicles/M1_37mm_24.jpg b/resources/ui/units/vehicles/M1_37mm_24.jpg new file mode 100644 index 00000000..4d9fd1f8 Binary files /dev/null and b/resources/ui/units/vehicles/M1_37mm_24.jpg differ diff --git a/resources/ui/units/vehicles/M2A1_halftrack_24.jpg b/resources/ui/units/vehicles/M2A1_halftrack_24.jpg new file mode 100644 index 00000000..42692c7d Binary files /dev/null and b/resources/ui/units/vehicles/M2A1_halftrack_24.jpg differ diff --git a/resources/ui/units/vehicles/M30 Cargo Carrier_24.jpg b/resources/ui/units/vehicles/M30_CC_24.jpg similarity index 100% rename from resources/ui/units/vehicles/M30 Cargo Carrier_24.jpg rename to resources/ui/units/vehicles/M30_CC_24.jpg diff --git a/resources/ui/units/vehicles/M45_Quadmount_24.jpg b/resources/ui/units/vehicles/M45_Quadmount_24.jpg new file mode 100644 index 00000000..640841bb Binary files /dev/null and b/resources/ui/units/vehicles/M45_Quadmount_24.jpg differ diff --git a/resources/ui/units/vehicles/M4A4 Sherman Firefly_24.jpg b/resources/ui/units/vehicles/M4A4_Sherman_FF_24.jpg similarity index 100% rename from resources/ui/units/vehicles/M4A4 Sherman Firefly_24.jpg rename to resources/ui/units/vehicles/M4A4_Sherman_FF_24.jpg diff --git a/resources/ui/units/vehicles/M4A4 Sherman_24.jpg b/resources/ui/units/vehicles/M4_Sherman_24.jpg similarity index 100% rename from resources/ui/units/vehicles/M4A4 Sherman_24.jpg rename to resources/ui/units/vehicles/M4_Sherman_24.jpg diff --git a/resources/ui/units/vehicles/M4_Tractor_24.jpg b/resources/ui/units/vehicles/M4_Tractor_24.jpg new file mode 100644 index 00000000..a9c8a3f1 Binary files /dev/null and b/resources/ui/units/vehicles/M4_Tractor_24.jpg differ diff --git a/resources/ui/units/vehicles/M8_Greyhound_24.jpg b/resources/ui/units/vehicles/M8_Greyhound_24.jpg new file mode 100644 index 00000000..5f73175f Binary files /dev/null and b/resources/ui/units/vehicles/M8_Greyhound_24.jpg differ diff --git a/resources/ui/units/vehicles/Maschinensatz_33_24.jpg b/resources/ui/units/vehicles/Maschinensatz_33_24.jpg new file mode 100644 index 00000000..08fd8984 Binary files /dev/null and b/resources/ui/units/vehicles/Maschinensatz_33_24.jpg differ diff --git a/resources/ui/units/vehicles/PzKpfw IV H_24.jpg b/resources/ui/units/vehicles/Pz_IV_H_24.jpg similarity index 100% rename from resources/ui/units/vehicles/PzKpfw IV H_24.jpg rename to resources/ui/units/vehicles/Pz_IV_H_24.jpg diff --git a/resources/ui/units/vehicles/Panther G_24.jpg b/resources/ui/units/vehicles/Pz_V_Panther_G_24.jpg similarity index 100% rename from resources/ui/units/vehicles/Panther G_24.jpg rename to resources/ui/units/vehicles/Pz_V_Panther_G_24.jpg diff --git a/resources/ui/units/vehicles/QF_37_AA_24.jpg b/resources/ui/units/vehicles/QF_37_AA_24.jpg new file mode 100644 index 00000000..82f60ec5 Binary files /dev/null and b/resources/ui/units/vehicles/QF_37_AA_24.jpg differ diff --git a/resources/ui/units/vehicles/SAO 2-C9_24.jpg b/resources/ui/units/vehicles/SAO 2-C9_24.jpg new file mode 100644 index 00000000..12903bba Binary files /dev/null and b/resources/ui/units/vehicles/SAO 2-C9_24.jpg differ diff --git a/resources/ui/units/vehicles/SAU 2S3 Akatsia_24.jpg b/resources/ui/units/vehicles/SAU 2S3 Akatsia_24.jpg new file mode 100644 index 00000000..db08c862 Binary files /dev/null and b/resources/ui/units/vehicles/SAU 2S3 Akatsia_24.jpg differ diff --git a/resources/ui/units/vehicles/SAU Gvozdika_24.jpg b/resources/ui/units/vehicles/SAU Gvozdika_24.jpg new file mode 100644 index 00000000..30719cb1 Binary files /dev/null and b/resources/ui/units/vehicles/SAU Gvozdika_24.jpg differ diff --git a/resources/ui/units/vehicles/SAU Msta_24.jpg b/resources/ui/units/vehicles/SAU Msta_24.jpg new file mode 100644 index 00000000..10ea12a4 Binary files /dev/null and b/resources/ui/units/vehicles/SAU Msta_24.jpg differ diff --git a/resources/ui/units/vehicles/Sd_Kfz_234_2_Puma_24.jpg b/resources/ui/units/vehicles/Sd_Kfz_234_2_Puma_24.jpg new file mode 100644 index 00000000..2b514781 Binary files /dev/null and b/resources/ui/units/vehicles/Sd_Kfz_234_2_Puma_24.jpg differ diff --git a/resources/ui/units/vehicles/Sd_Kfz_251_24.jpg b/resources/ui/units/vehicles/Sd_Kfz_251_24.jpg new file mode 100644 index 00000000..fc45fc95 Binary files /dev/null and b/resources/ui/units/vehicles/Sd_Kfz_251_24.jpg differ diff --git a/resources/ui/units/vehicles/Sd_Kfz_2_24.jpg b/resources/ui/units/vehicles/Sd_Kfz_2_24.jpg new file mode 100644 index 00000000..0548a7a1 Binary files /dev/null and b/resources/ui/units/vehicles/Sd_Kfz_2_24.jpg differ diff --git a/resources/ui/units/vehicles/Sd_Kfz_7_24.jpg b/resources/ui/units/vehicles/Sd_Kfz_7_24.jpg new file mode 100644 index 00000000..ef52dc20 Binary files /dev/null and b/resources/ui/units/vehicles/Sd_Kfz_7_24.jpg differ diff --git a/resources/ui/units/vehicles/ShKH vz. 77 DANA_24.jpg b/resources/ui/units/vehicles/ShKH vz. 77 DANA_24.jpg new file mode 100644 index 00000000..7268a89d Binary files /dev/null and b/resources/ui/units/vehicles/ShKH vz. 77 DANA_24.jpg differ diff --git a/resources/ui/units/vehicles/Stug_III_24.jpg b/resources/ui/units/vehicles/Stug_III_24.jpg new file mode 100644 index 00000000..3539899e Binary files /dev/null and b/resources/ui/units/vehicles/Stug_III_24.jpg differ diff --git a/resources/ui/units/vehicles/Stug_IV_24.jpg b/resources/ui/units/vehicles/Stug_IV_24.jpg new file mode 100644 index 00000000..b1351db0 Binary files /dev/null and b/resources/ui/units/vehicles/Stug_IV_24.jpg differ diff --git a/resources/ui/units/vehicles/Sturmpanzer IV_24.jpg b/resources/ui/units/vehicles/Sturmpanzer IV_24.jpg new file mode 100644 index 00000000..21349a15 Binary files /dev/null and b/resources/ui/units/vehicles/Sturmpanzer IV_24.jpg differ diff --git a/resources/ui/units/vehicles/T-72B3_24.jpg b/resources/ui/units/vehicles/T-72B3_24.jpg new file mode 100644 index 00000000..8f08c893 Binary files /dev/null and b/resources/ui/units/vehicles/T-72B3_24.jpg differ diff --git a/resources/ui/units/vehicles/Tetrarch_24.jpg b/resources/ui/units/vehicles/Tetrarch_24.jpg new file mode 100644 index 00000000..cae41d37 Binary files /dev/null and b/resources/ui/units/vehicles/Tetrarch_24.jpg differ diff --git a/resources/ui/units/vehicles/Tiger II_24.jpg b/resources/ui/units/vehicles/Tiger_II_H_24.jpg similarity index 100% rename from resources/ui/units/vehicles/Tiger II_24.jpg rename to resources/ui/units/vehicles/Tiger_II_H_24.jpg diff --git a/resources/ui/units/vehicles/Tiger I_24.jpg b/resources/ui/units/vehicles/Tiger_I_24.jpg similarity index 100% rename from resources/ui/units/vehicles/Tiger I_24.jpg rename to resources/ui/units/vehicles/Tiger_I_24.jpg diff --git a/resources/ui/units/vehicles/Willys_MB_24.jpg b/resources/ui/units/vehicles/Willys_MB_24.jpg new file mode 100644 index 00000000..705eb2e1 Binary files /dev/null and b/resources/ui/units/vehicles/Willys_MB_24.jpg differ diff --git a/resources/ui/units/vehicles/ZSU-57-2_24.jpg b/resources/ui/units/vehicles/ZSU-57-2_24.jpg new file mode 100644 index 00000000..e518ad96 Binary files /dev/null and b/resources/ui/units/vehicles/ZSU-57-2_24.jpg differ diff --git a/resources/ui/units/vehicles/Bofors 40 mm_24.jpg b/resources/ui/units/vehicles/bofors40_24.jpg similarity index 100% rename from resources/ui/units/vehicles/Bofors 40 mm_24.jpg rename to resources/ui/units/vehicles/bofors40_24.jpg diff --git a/resources/ui/units/vehicles/flak18_24.jpg b/resources/ui/units/vehicles/flak18_24.jpg new file mode 100644 index 00000000..d8b4123b Binary files /dev/null and b/resources/ui/units/vehicles/flak18_24.jpg differ diff --git a/resources/ui/units/vehicles/flak30_24.jpg b/resources/ui/units/vehicles/flak30_24.jpg new file mode 100644 index 00000000..74cd7369 Binary files /dev/null and b/resources/ui/units/vehicles/flak30_24.jpg differ diff --git a/resources/ui/units/vehicles/flak36_24.jpg b/resources/ui/units/vehicles/flak36_24.jpg new file mode 100644 index 00000000..d039be18 Binary files /dev/null and b/resources/ui/units/vehicles/flak36_24.jpg differ diff --git a/resources/ui/units/vehicles/flak37_24.jpg b/resources/ui/units/vehicles/flak37_24.jpg new file mode 100644 index 00000000..b2008917 Binary files /dev/null and b/resources/ui/units/vehicles/flak37_24.jpg differ diff --git a/resources/ui/units/vehicles/flak38_24.jpg b/resources/ui/units/vehicles/flak38_24.jpg new file mode 100644 index 00000000..f54c1d37 Binary files /dev/null and b/resources/ui/units/vehicles/flak38_24.jpg differ diff --git a/resources/ui/units/vehicles/flak41_24.jpg b/resources/ui/units/vehicles/flak41_24.jpg new file mode 100644 index 00000000..10f7efa1 Binary files /dev/null and b/resources/ui/units/vehicles/flak41_24.jpg differ