mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
JTAC support
This commit is contained in:
parent
bff33e6992
commit
2a50768db1
@ -19,6 +19,9 @@
|
||||
* **[Mission Generator]** The briefing will now contain the carrier ATC frequency
|
||||
* **[Mission Generator]** The briefing contains a small situation update.
|
||||
* **[Mission Generator]** Previously destroyed units are visible in the mission. (And added a performance settings to disable this behaviour)
|
||||
* **[Campaign Generator]** Added Tarawa in caucasus campaigns
|
||||
* **[Campaign Generator]** Tuned the various existing campaign parameters
|
||||
* **[Campaign Generator]** Added small campaign : "Russia" on Caucasus Theater
|
||||
|
||||
## Fixed issues :
|
||||
* **[Mission Generator]** Carrier will sail into the wind, not in the same direction
|
||||
|
||||
@ -46,5 +46,5 @@ Australia_2005 = {
|
||||
"HMAS Adelaide"
|
||||
], "boat":[
|
||||
"ArleighBurkeGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
|
||||
@ -54,5 +54,5 @@ BLUEFOR_COLDWAR = {
|
||||
"LHA-4 Nassau",
|
||||
"LHA-5 Peleliu"
|
||||
], "boat": [
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
|
||||
@ -61,5 +61,5 @@ BLUEFOR_COLDWAR_A4 = {
|
||||
], "boat": [
|
||||
], "requirements": {
|
||||
"Community A-4E": "https://heclak.github.io/community-a4e-c/",
|
||||
}
|
||||
}, "has_jtac": True
|
||||
}
|
||||
|
||||
@ -64,5 +64,5 @@ BLUEFOR_COLDWAR_MODS = {
|
||||
], "requirements": {
|
||||
"MB-339A": "http://www.freccetricolorivirtuali.net/",
|
||||
"Community A-4E": "https://heclak.github.io/community-a4e-c/",
|
||||
}
|
||||
}, "has_jtac": True
|
||||
}
|
||||
|
||||
@ -78,5 +78,5 @@ BLUEFOR_MODERN = {
|
||||
"LHA-5 Peleliu"
|
||||
], "boat":[
|
||||
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
|
||||
@ -39,5 +39,5 @@ Canada_2005 = {
|
||||
Ticonderoga_class,
|
||||
], "boat":[
|
||||
"ArleighBurkeGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
|
||||
@ -73,5 +73,5 @@ China_2010 = {
|
||||
"002 Shandong",
|
||||
], "boat":[
|
||||
"Type54GroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
@ -42,5 +42,5 @@ France_1995 = {
|
||||
AirDefence.SAM_Roland_ADS
|
||||
], "boat":[
|
||||
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
@ -57,5 +57,5 @@ France_2005 = {
|
||||
"L9015 Dixmude"
|
||||
], "boat":[
|
||||
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
@ -75,5 +75,5 @@ France_2005_Modded = {
|
||||
], "requirements": {
|
||||
"frenchpack V3.5": "https://forums.eagle.ru/showthread.php?t=279974",
|
||||
"RAFALE 2.5.5": "https://www.digitalcombatsimulator.com/fr/files/3307478/",
|
||||
}
|
||||
}, "has_jtac": True
|
||||
}
|
||||
@ -51,5 +51,5 @@ India_2010 = {
|
||||
"INS Vikramaditya"
|
||||
], "boat":[
|
||||
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator", "MolniyaGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
@ -35,5 +35,5 @@ Israel_2000 = {
|
||||
AirDefence.SAM_Avenger_M1097
|
||||
], "boat": [
|
||||
"ArleighBurkeGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
@ -44,5 +44,5 @@ Italy_1990 = {
|
||||
"Cavour",
|
||||
], "boat":[
|
||||
"OliverHazardPerryGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
|
||||
@ -48,5 +48,5 @@ Italy_1990_MB339 = {
|
||||
"OliverHazardPerryGroupGenerator"
|
||||
], "requirements": {
|
||||
"MB-339A": "http://www.freccetricolorivirtuali.net/",
|
||||
}
|
||||
}, "has_jtac": True
|
||||
}
|
||||
|
||||
@ -50,5 +50,5 @@ Japan_2005 = {
|
||||
"Ise",
|
||||
], "boat":[
|
||||
"ArleighBurkeGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
|
||||
@ -34,5 +34,5 @@ Netherlands_1990 = {
|
||||
AirDefence.SAM_Avenger_M1097
|
||||
], "boat": [
|
||||
"OliverHazardPerryGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
|
||||
@ -36,5 +36,5 @@ Pakistan_2015 = {
|
||||
AirDefence.AAA_ZU_23_Closed
|
||||
], "boat": [
|
||||
"Type54GroupGenerator", "OliverHazardPerryGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
|
||||
@ -46,5 +46,5 @@ Spain_1990 = {
|
||||
"Juan Carlos I",
|
||||
], "boat":[
|
||||
"OliverHazardPerryGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
@ -27,5 +27,5 @@ Sweden_1990 = {
|
||||
],
|
||||
"shorad": [
|
||||
AirDefence.SAM_Avenger_M1097
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
@ -38,5 +38,5 @@ Turkey_2005 = {
|
||||
AirDefence.SPAAA_ZSU_23_4_Shilka
|
||||
], "boat":[
|
||||
"OliverHazardPerryGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
@ -32,5 +32,5 @@ UAE_2005 = {
|
||||
Armed_speedboat,
|
||||
], "boat":[
|
||||
"OliverHazardPerryGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
@ -48,5 +48,5 @@ UnitedKingdom_1990 = {
|
||||
"HMS Ark Royal",
|
||||
], "boat":[
|
||||
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
@ -61,5 +61,5 @@ USA_1990 = {
|
||||
"LHA-5 Peleliu"
|
||||
], "boat":[
|
||||
"ArleighBurkeGroupGenerator", "OliverHazardPerryGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
@ -66,5 +66,5 @@ USA_2005 = {
|
||||
"LHA-5 Peleliu"
|
||||
], "boat":[
|
||||
"ArleighBurkeGroupGenerator"
|
||||
]
|
||||
], "has_jtac": True
|
||||
}
|
||||
|
||||
@ -75,6 +75,7 @@ class Game:
|
||||
self.__culling_points = self.compute_conflicts_position()
|
||||
self.__frontlineData = []
|
||||
self.__destroyed_units = []
|
||||
self.jtacs = []
|
||||
self.savepath = ""
|
||||
|
||||
self.sanitize_sides()
|
||||
|
||||
@ -157,6 +157,7 @@ class Operation:
|
||||
self.airgen.generate_flights(cp, country, self.game.planners[cp.id])
|
||||
|
||||
# Generate ground units on frontline everywhere
|
||||
self.game.jtacs = []
|
||||
for player_cp, enemy_cp in self.game.theater.conflicts(True):
|
||||
conflict = Conflict.frontline_cas_conflict(self.attacker_name, self.defender_name,
|
||||
self.current_mission.country(self.attacker_country),
|
||||
@ -175,14 +176,14 @@ class Operation:
|
||||
else:
|
||||
self.current_mission.groundControl.red_tactical_commander = self.ca_slots
|
||||
|
||||
# triggers
|
||||
# Triggers
|
||||
if self.game.is_player_attack(self.conflict.attackers_country):
|
||||
cp = self.conflict.from_cp
|
||||
else:
|
||||
cp = self.conflict.to_cp
|
||||
self.triggersgen.generate()
|
||||
|
||||
# options
|
||||
# Options
|
||||
self.forcedoptionsgen.generate()
|
||||
|
||||
# Generate Visuals Smoke Effects
|
||||
@ -195,6 +196,18 @@ class Operation:
|
||||
load_mist.add_action(DoScript(String(f.read())))
|
||||
self.current_mission.triggerrules.triggers.append(load_mist)
|
||||
|
||||
# Load Ciribob's JTACAutoLase script
|
||||
load_autolase = TriggerStart(comment="Load JTAC script")
|
||||
with open("./resources/scripts/JTACAutoLase.lua") as f:
|
||||
|
||||
script = f.read()
|
||||
script = script + "\n"
|
||||
for jtac in self.game.jtacs:
|
||||
script = script + "\n" + "JTACAutoLase('" + str(jtac[2]) + "', " + str(jtac[1]) + ", true, \"vehicle\")" + "\n"
|
||||
|
||||
load_autolase.add_action(DoScript(String(script)))
|
||||
self.current_mission.triggerrules.triggers.append(load_autolase)
|
||||
|
||||
load_dcs_libe = TriggerStart(comment="Load DCS Liberation Script")
|
||||
with open("./resources/scripts/dcs_liberation.lua") as f:
|
||||
script = f.read()
|
||||
|
||||
@ -24,6 +24,7 @@ class Settings:
|
||||
self.sams = True # Legacy parameter do not use
|
||||
self.cold_start = False # Legacy parameter do not use
|
||||
self.version = None
|
||||
self.include_jtac_if_available = True
|
||||
|
||||
# Performance oriented
|
||||
self.perf_red_alert_state = True
|
||||
|
||||
14
gen/armor.py
14
gen/armor.py
@ -97,6 +97,20 @@ class GroundConflictGenerator:
|
||||
self.plan_action_for_groups(self.player_stance, player_groups, enemy_groups, self.conflict.heading + 90, self.conflict.from_cp, self.conflict.to_cp)
|
||||
self.plan_action_for_groups(self.enemy_stance, enemy_groups, player_groups, self.conflict.heading - 90, self.conflict.to_cp, self.conflict.from_cp)
|
||||
|
||||
# Add JTAC
|
||||
if "has_jtac" in self.game.player_faction and self.game.player_faction["has_jtac"] and self.game.settings.include_jtac_if_available:
|
||||
n = "JTAC" + str(self.conflict.from_cp.id) + str(self.conflict.to_cp.id)
|
||||
code = 1688 + len(self.game.jtacs)
|
||||
jtac = self.mission.flight_group(country=self.mission.country(self.game.player_country),
|
||||
name=n,
|
||||
aircraft_type=MQ_9_Reaper,
|
||||
position=position[0],
|
||||
airport=None,
|
||||
altitude=5000)
|
||||
jtac.points[0].tasks.append(OrbitAction(5000, 300, OrbitAction.OrbitPattern.Circle))
|
||||
jtac.points[0].tasks.append(SetInvisibleCommand(True))
|
||||
jtac.points[0].tasks.append(SetImmortalCommand(True))
|
||||
self.game.jtacs.append(("Frontline " + self.conflict.from_cp.name + "/" + self.conflict.to_cp.name, code, n))
|
||||
|
||||
def gen_infantry_group_for_group(self, group, is_player, side:Country, forward_heading):
|
||||
|
||||
|
||||
@ -24,6 +24,8 @@ class BriefingGenerator:
|
||||
self.targets = []
|
||||
self.waypoints = []
|
||||
|
||||
self.jtacs = []
|
||||
|
||||
def append_frequency(self, name: str, frequency: str):
|
||||
self.freqs.append((name, frequency))
|
||||
|
||||
@ -109,6 +111,12 @@ class BriefingGenerator:
|
||||
self.description += "ICLS Channel : " + str(cp.icls) + "\n"
|
||||
self.description += "-" * 50 + "\n"
|
||||
|
||||
|
||||
self.description += "JTACS [F-10 Menu] : \n"
|
||||
self.description += "==================="
|
||||
for jtac in self.game.jtacs:
|
||||
self.description += str(jtac[0]) + " -- Code : " + str(jtac[1]) + "\n"
|
||||
|
||||
self.m.set_description_text(self.description)
|
||||
|
||||
self.m.add_picture_blue(os.path.abspath("./resources/ui/splash_screen.png"))
|
||||
|
||||
@ -16,7 +16,7 @@ class QMissionPlanning(QDialog):
|
||||
super(QMissionPlanning, self).__init__()
|
||||
self.game = game
|
||||
self.setWindowFlags(Qt.WindowStaysOnTopHint)
|
||||
self.setMinimumSize(1000, 420)
|
||||
self.setMinimumSize(1000, 440)
|
||||
self.setModal(True)
|
||||
self.setWindowTitle("Mission Preparation")
|
||||
self.setWindowIcon(EVENT_ICONS["strike"])
|
||||
|
||||
@ -166,13 +166,23 @@ class QSettingsWindow(QDialog):
|
||||
self.generate_marks.setChecked(self.game.settings.generate_marks)
|
||||
self.generate_marks.toggled.connect(self.applySettings)
|
||||
|
||||
|
||||
if not hasattr(self.game.settings, "include_jtac_if_available"):
|
||||
self.game.settings.include_jtac_if_available = True
|
||||
|
||||
self.include_jtac_if_available = QCheckBox()
|
||||
self.include_jtac_if_available.setChecked(self.game.settings.include_jtac_if_available)
|
||||
self.include_jtac_if_available.toggled.connect(self.applySettings)
|
||||
|
||||
self.gameplayLayout.addWidget(QLabel("Use Supercarrier Module"), 0, 0)
|
||||
self.gameplayLayout.addWidget(self.supercarrier, 0, 1, Qt.AlignRight)
|
||||
self.gameplayLayout.addWidget(QLabel("Put Objective Markers on Map"), 1, 0)
|
||||
self.gameplayLayout.addWidget(self.generate_marks, 1, 1, Qt.AlignRight)
|
||||
self.gameplayLayout.addWidget(QLabel("Include JTAC (If available)"), 2, 0)
|
||||
self.gameplayLayout.addWidget(self.include_jtac_if_available, 2, 1, Qt.AlignRight)
|
||||
|
||||
self.performance = QGroupBox("Performance")
|
||||
self.performanceLayout = QGridLayout();
|
||||
self.performanceLayout = QGridLayout()
|
||||
self.performanceLayout.setAlignment(Qt.AlignTop)
|
||||
self.performance.setLayout(self.performanceLayout)
|
||||
|
||||
@ -288,6 +298,7 @@ class QSettingsWindow(QDialog):
|
||||
self.game.settings.map_coalition_visibility = self.mapVisibiitySelection.currentData()
|
||||
self.game.settings.external_views_allowed = self.ext_views.isChecked()
|
||||
self.game.settings.generate_marks = self.generate_marks.isChecked()
|
||||
self.game.settings.include_jtac_if_available = self.include_jtac_if_available.isChecked()
|
||||
|
||||
print(self.game.settings.map_coalition_visibility)
|
||||
|
||||
|
||||
Binary file not shown.
729
resources/scripts/JTACAutoLase.lua
Normal file
729
resources/scripts/JTACAutoLase.lua
Normal file
@ -0,0 +1,729 @@
|
||||
--[[
|
||||
JTAC Automatic Targeting and Laser Script
|
||||
|
||||
Allows a JTAC to mark and hold an IR and Laser point on a target allowing TGP's to lock onto the lase and ease
|
||||
of target location using NV Goggles
|
||||
|
||||
The JTAC will automatically switch targets when a target is destroyed or goes out of Line of Sight
|
||||
|
||||
NOTE: LOS doesn't include buildings or tree's... Sorry!
|
||||
|
||||
The script can also be useful in daylight by enabling the JTAC to mark enemy positions with Smoke.
|
||||
The JTAC will only move the smoke to the target every 5 minutes (to stop a huge trail of smoke markers) unless the target
|
||||
is destroyed, in which case the new target will be marked straight away with smoke.
|
||||
|
||||
You can also enable an F10 menu option for coalition units allowing the JTAC(s) to report their current status.
|
||||
|
||||
If a JTAC is down it won't report in.
|
||||
|
||||
USAGE:
|
||||
|
||||
Place JTAC units on the map with the mission editor putting each JTAC in it's own group containing only itself and no
|
||||
other units. Name the group something easy to remember e.g. JTAC1 and make sure the JTAC units have a unique name which must
|
||||
not be the same as the group name. The editor should do this for you but be careful if you copy and paste.
|
||||
|
||||
Load the script at the start of the mission with a Trigger Once or as the init script of the mission
|
||||
|
||||
Run the code below as a DO SCRIPT at the start of the mission, or after a delay if you prefer
|
||||
|
||||
JTACAutoLase('JTAC1', 1688)
|
||||
|
||||
OR
|
||||
|
||||
JTACAutoLase('JTAC1', 1688, false,"all") - means no smoke marks for this jtac and it will target all ground troops
|
||||
|
||||
OR
|
||||
|
||||
JTACAutoLase('JTAC1', 1688, true,"vehicle") - means smoke marks for this jtac and it will target ONLY ground vehicles
|
||||
|
||||
OR
|
||||
|
||||
JTACAutoLase('JTAC1', 1688, true,"troop") - means smoke marks for this jtac and it will target ONLY ground troops
|
||||
|
||||
OR
|
||||
|
||||
JTACAutoLase('JTAC1', 1688, true,"all", 4) - means BLUE smoke marks for this jtac and it will target all ground troops
|
||||
|
||||
Where JTAC1 is the Group name of the JTAC Group with one and only one JTAC unit.
|
||||
|
||||
The script doesn't care if the unit isn't activated when run, as it'll automatically activate when the JTAC is activated in
|
||||
the mission but there can be a delay of up to 30 seconds after activation for the JTAC to start searching for targets.
|
||||
|
||||
You can also run the code at any time if a JTAC is dynamically added to the map as long as you know the Group name of the JTAC.
|
||||
|
||||
Last Edit: 21/04/2015
|
||||
|
||||
Change log:
|
||||
Added new config of JTAC smoke colour globally or per JTAC
|
||||
Added new config of JTAC targetting to either target only troops or vehicles or all
|
||||
Added new induvidual config of JTAC smoke and location which will override global setting
|
||||
Added Lat / Lon + MGRS to JTAC Target position
|
||||
Changed Lasing method to update laser marker rather than create and destroy
|
||||
- This gives much better tracking behaviour!
|
||||
Fixed JTAC lasing through terrain.
|
||||
Fixed Lase staying on when JTAC Dies
|
||||
Fixed Lase staying on when target dies and there are no other targets
|
||||
Added Radio noise when message is shown
|
||||
Stop multiple JTACS targeting the same target
|
||||
|
||||
|
||||
Parts of MIST used. Source is https://github.com/mrSkortch/MissionScriptingTools/blob/master/mist.lua
|
||||
|
||||
]]
|
||||
|
||||
-- CONFIG
|
||||
JTAC_maxDistance = 50000 -- How far a JTAC can "see" in meters (with LOS)
|
||||
|
||||
JTAC_smokeOn = true -- enables marking of target with smoke, can be overriden by the JTACAutoLase in editor
|
||||
|
||||
JTAC_smokeColour = 1 -- Green = 0 , Red = 1, White = 2, Orange = 3, Blue = 4
|
||||
|
||||
JTAC_jtacStatusF10 = true -- enables F10 JTAC Status menu
|
||||
|
||||
JTAC_location = true -- shows location in JTAC message, can be overriden by the JTACAutoLase in editor
|
||||
|
||||
JTAC_lock = "all" -- "vehicle" OR "troop" OR "all" forces JTAC to only lock vehicles or troops or all ground units
|
||||
|
||||
-- END CONFIG
|
||||
|
||||
-- BE CAREFUL MODIFYING BELOW HERE
|
||||
|
||||
GLOBAL_JTAC_LASE = {}
|
||||
GLOBAL_JTAC_IR = {}
|
||||
GLOBAL_JTAC_SMOKE = {}
|
||||
GLOBAL_JTAC_UNITS = {} -- list of JTAC units for f10 command
|
||||
GLOBAL_JTAC_CURRENT_TARGETS = {}
|
||||
GLOBAL_JTAC_RADIO_ADDED = {} --keeps track of who's had the radio command added
|
||||
GLOBAL_JTAC_LASER_CODES = {} -- keeps track of laser codes for jtac
|
||||
|
||||
|
||||
function JTACAutoLase(jtacGroupName, laserCode,smoke,lock,colour)
|
||||
|
||||
if smoke == nil then
|
||||
|
||||
smoke = JTAC_smokeOn
|
||||
end
|
||||
|
||||
if lock == nil then
|
||||
|
||||
lock = JTAC_lock
|
||||
end
|
||||
|
||||
if colour == nil then
|
||||
colour = JTAC_smokeColour
|
||||
end
|
||||
|
||||
GLOBAL_JTAC_LASER_CODES[jtacGroupName] = laserCode
|
||||
|
||||
local jtacGroup = getGroup(jtacGroupName)
|
||||
local jtacUnit
|
||||
|
||||
if jtacGroup == nil or #jtacGroup == 0 then
|
||||
|
||||
notify("JTAC Group " .. jtacGroupName .. " KIA!", 10)
|
||||
|
||||
--remove from list
|
||||
GLOBAL_JTAC_UNITS[jtacGroupName] = nil
|
||||
|
||||
cleanupJTAC(jtacGroupName)
|
||||
|
||||
return
|
||||
else
|
||||
|
||||
jtacUnit = jtacGroup[1]
|
||||
--add to list
|
||||
GLOBAL_JTAC_UNITS[jtacGroupName] = jtacUnit:getName()
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- search for current unit
|
||||
|
||||
if jtacUnit:isActive() == false then
|
||||
|
||||
cleanupJTAC(jtacGroupName)
|
||||
|
||||
env.info(jtacGroupName .. ' Not Active - Waiting 30 seconds')
|
||||
timer.scheduleFunction(timerJTACAutoLase, { jtacGroupName, laserCode,smoke,lock,colour}, timer.getTime() + 30)
|
||||
|
||||
return
|
||||
end
|
||||
|
||||
local enemyUnit = getCurrentUnit(jtacUnit, jtacGroupName)
|
||||
|
||||
if enemyUnit == nil and GLOBAL_JTAC_CURRENT_TARGETS[jtacGroupName] ~= nil then
|
||||
|
||||
local tempUnitInfo = GLOBAL_JTAC_CURRENT_TARGETS[jtacGroupName]
|
||||
|
||||
-- env.info("TEMP UNIT INFO: " .. tempUnitInfo.name .. " " .. tempUnitInfo.unitType)
|
||||
|
||||
local tempUnit = Unit.getByName(tempUnitInfo.name)
|
||||
|
||||
if tempUnit ~= nil and tempUnit:getLife() > 0 and tempUnit:isActive() == true then
|
||||
notify(jtacGroupName .. " target " .. tempUnitInfo.unitType .. " lost. Scanning for Targets. ", 10)
|
||||
else
|
||||
notify(jtacGroupName .. " target " .. tempUnitInfo.unitType .. " KIA. Good Job! Scanning for Targets. ", 10)
|
||||
end
|
||||
|
||||
--remove from smoke list
|
||||
GLOBAL_JTAC_SMOKE[tempUnitInfo.name] = nil
|
||||
|
||||
-- remove from target list
|
||||
GLOBAL_JTAC_CURRENT_TARGETS[jtacGroupName] = nil
|
||||
|
||||
--stop lasing
|
||||
cancelLase(jtacGroupName)
|
||||
|
||||
end
|
||||
|
||||
|
||||
if enemyUnit == nil then
|
||||
enemyUnit = findNearestVisibleEnemy(jtacUnit,lock)
|
||||
|
||||
if enemyUnit ~= nil then
|
||||
|
||||
-- store current target for easy lookup
|
||||
GLOBAL_JTAC_CURRENT_TARGETS[jtacGroupName] = { name = enemyUnit:getName(), unitType = enemyUnit:getTypeName(), unitId = enemyUnit:getID() }
|
||||
|
||||
notify(jtacGroupName .. " lasing new target " .. enemyUnit:getTypeName() .. '. CODE: ' .. laserCode ..getPositionString(enemyUnit) , 10)
|
||||
|
||||
-- create smoke
|
||||
if smoke == true then
|
||||
|
||||
--create first smoke
|
||||
createSmokeMarker(enemyUnit,colour)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if enemyUnit ~= nil then
|
||||
|
||||
laseUnit(enemyUnit, jtacUnit, jtacGroupName, laserCode)
|
||||
|
||||
-- env.info('Timer timerSparkleLase '..jtacGroupName.." "..laserCode.." "..enemyUnit:getName())
|
||||
timer.scheduleFunction(timerJTACAutoLase, { jtacGroupName, laserCode, smoke,lock,colour }, timer.getTime() + 1)
|
||||
|
||||
|
||||
if smoke == true then
|
||||
local nextSmokeTime = GLOBAL_JTAC_SMOKE[enemyUnit:getName()]
|
||||
|
||||
--recreate smoke marker after 5 mins
|
||||
if nextSmokeTime ~= nil and nextSmokeTime < timer.getTime() then
|
||||
|
||||
createSmokeMarker(enemyUnit, colour)
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
-- env.info('LASE: No Enemies Nearby')
|
||||
|
||||
-- stop lazing the old spot
|
||||
cancelLase(jtacGroupName)
|
||||
-- env.info('Timer Slow timerSparkleLase '..jtacGroupName.." "..laserCode.." "..enemyUnit:getName())
|
||||
|
||||
timer.scheduleFunction(timerJTACAutoLase, { jtacGroupName, laserCode, smoke,lock,colour }, timer.getTime() + 5)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- used by the timer function
|
||||
function timerJTACAutoLase(args)
|
||||
|
||||
JTACAutoLase(args[1], args[2], args[3],args[4])
|
||||
end
|
||||
|
||||
function cleanupJTAC(jtacGroupName)
|
||||
-- clear laser - just in case
|
||||
cancelLase(jtacGroupName)
|
||||
|
||||
-- Cleanup
|
||||
GLOBAL_JTAC_UNITS[jtacGroupName] = nil
|
||||
|
||||
GLOBAL_JTAC_CURRENT_TARGETS[jtacGroupName] = nil
|
||||
end
|
||||
|
||||
|
||||
function notify(message, displayFor)
|
||||
|
||||
|
||||
trigger.action.outTextForCoalition(coalition.side.BLUE, message, displayFor)
|
||||
trigger.action.outSoundForCoalition(coalition.side.BLUE, "radiobeep.ogg")
|
||||
end
|
||||
|
||||
function createSmokeMarker(enemyUnit,colour)
|
||||
|
||||
--recreate in 5 mins
|
||||
GLOBAL_JTAC_SMOKE[enemyUnit:getName()] = timer.getTime() + 300.0
|
||||
|
||||
-- move smoke 2 meters above target for ease
|
||||
local enemyPoint = enemyUnit:getPoint()
|
||||
trigger.action.smoke({ x = enemyPoint.x, y = enemyPoint.y + 2.0, z = enemyPoint.z }, colour)
|
||||
end
|
||||
|
||||
function cancelLase(jtacGroupName)
|
||||
|
||||
--local index = "JTAC_"..jtacUnit:getID()
|
||||
|
||||
local tempLase = GLOBAL_JTAC_LASE[jtacGroupName]
|
||||
|
||||
if tempLase ~= nil then
|
||||
Spot.destroy(tempLase)
|
||||
GLOBAL_JTAC_LASE[jtacGroupName] = nil
|
||||
|
||||
-- env.info('Destroy laze '..index)
|
||||
|
||||
tempLase = nil
|
||||
end
|
||||
|
||||
local tempIR = GLOBAL_JTAC_IR[jtacGroupName]
|
||||
|
||||
if tempIR ~= nil then
|
||||
Spot.destroy(tempIR)
|
||||
GLOBAL_JTAC_IR[jtacGroupName] = nil
|
||||
|
||||
-- env.info('Destroy laze '..index)
|
||||
|
||||
tempIR = nil
|
||||
end
|
||||
end
|
||||
|
||||
function laseUnit(enemyUnit, jtacUnit, jtacGroupName, laserCode)
|
||||
|
||||
--cancelLase(jtacGroupName)
|
||||
|
||||
local spots = {}
|
||||
|
||||
local enemyVector = enemyUnit:getPoint()
|
||||
local enemyVectorUpdated = { x = enemyVector.x, y = enemyVector.y + 2.0, z = enemyVector.z }
|
||||
|
||||
local oldLase = GLOBAL_JTAC_LASE[jtacGroupName]
|
||||
local oldIR = GLOBAL_JTAC_IR[jtacGroupName]
|
||||
|
||||
if oldLase == nil or oldIR == nil then
|
||||
|
||||
-- create lase
|
||||
|
||||
local status, result = pcall(function()
|
||||
spots['irPoint'] = Spot.createInfraRed(jtacUnit, { x = 0, y = 2.0, z = 0 }, enemyVectorUpdated)
|
||||
spots['laserPoint'] = Spot.createLaser(jtacUnit, { x = 0, y = 2.0, z = 0 }, enemyVectorUpdated, laserCode)
|
||||
return spots
|
||||
end)
|
||||
|
||||
if not status then
|
||||
env.error('ERROR: ' .. assert(result), false)
|
||||
else
|
||||
if result.irPoint then
|
||||
|
||||
-- env.info(jtacUnit:getName() .. ' placed IR Pointer on '..enemyUnit:getName())
|
||||
|
||||
GLOBAL_JTAC_IR[jtacGroupName] = result.irPoint --store so we can remove after
|
||||
|
||||
end
|
||||
if result.laserPoint then
|
||||
|
||||
-- env.info(jtacUnit:getName() .. ' is Lasing '..enemyUnit:getName()..'. CODE:'..laserCode)
|
||||
|
||||
GLOBAL_JTAC_LASE[jtacGroupName] = result.laserPoint
|
||||
end
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
-- update lase
|
||||
|
||||
if oldLase~=nil then
|
||||
oldLase:setPoint(enemyVectorUpdated)
|
||||
end
|
||||
|
||||
if oldIR ~= nil then
|
||||
oldIR:setPoint(enemyVectorUpdated)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- get currently selected unit and check they're still in range
|
||||
function getCurrentUnit(jtacUnit, jtacGroupName)
|
||||
|
||||
|
||||
local unit = nil
|
||||
|
||||
if GLOBAL_JTAC_CURRENT_TARGETS[jtacGroupName] ~= nil then
|
||||
unit = Unit.getByName(GLOBAL_JTAC_CURRENT_TARGETS[jtacGroupName].name)
|
||||
end
|
||||
|
||||
local tempPoint = nil
|
||||
local tempDist = nil
|
||||
local tempPosition = nil
|
||||
|
||||
local jtacPosition = jtacUnit:getPosition()
|
||||
local jtacPoint = jtacUnit:getPoint()
|
||||
|
||||
if unit ~= nil and unit:getLife() > 0 and unit:isActive() == true then
|
||||
|
||||
-- calc distance
|
||||
tempPoint = unit:getPoint()
|
||||
-- tempPosition = unit:getPosition()
|
||||
|
||||
tempDist = getDistance(tempPoint.x, tempPoint.z, jtacPoint.x, jtacPoint.z)
|
||||
if tempDist < JTAC_maxDistance then
|
||||
-- calc visible
|
||||
|
||||
-- check slightly above the target as rounding errors can cause issues, plus the unit has some height anyways
|
||||
local offsetEnemyPos = { x = tempPoint.x, y = tempPoint.y + 2.0, z = tempPoint.z }
|
||||
local offsetJTACPos = { x = jtacPoint.x, y = jtacPoint.y + 2.0, z = jtacPoint.z }
|
||||
|
||||
if land.isVisible(offsetEnemyPos, offsetJTACPos) then
|
||||
return unit
|
||||
end
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
-- Find nearest enemy to JTAC that isn't blocked by terrain
|
||||
function findNearestVisibleEnemy(jtacUnit, targetType)
|
||||
|
||||
local x = 1
|
||||
local i = 1
|
||||
|
||||
local units = nil
|
||||
local groupName = nil
|
||||
|
||||
local nearestUnit = nil
|
||||
local nearestDistance = JTAC_maxDistance
|
||||
|
||||
local redGroups = coalition.getGroups(1, Group.Category.GROUND)
|
||||
|
||||
local jtacPoint = jtacUnit:getPoint()
|
||||
local jtacPosition = jtacUnit:getPosition()
|
||||
|
||||
local tempPoint = nil
|
||||
local tempPosition = nil
|
||||
|
||||
local tempDist = nil
|
||||
|
||||
-- finish this function
|
||||
for i = 1, #redGroups do
|
||||
if redGroups[i] ~= nil then
|
||||
groupName = redGroups[i]:getName()
|
||||
units = getGroup(groupName)
|
||||
if #units > 0 then
|
||||
|
||||
for x = 1, #units do
|
||||
|
||||
--check to see if a JTAC has already targeted this unit
|
||||
local targeted = alreadyTarget(jtacUnit,units[x])
|
||||
local allowedTarget = true
|
||||
|
||||
if targetType == "vehicle" then
|
||||
|
||||
allowedTarget = isVehicle(units[x])
|
||||
|
||||
elseif targetType == "troop" then
|
||||
|
||||
allowedTarget = isInfantry(units[x])
|
||||
|
||||
end
|
||||
|
||||
|
||||
if units[x]:isActive() == true and targeted == false and allowedTarget == true then
|
||||
|
||||
-- calc distance
|
||||
tempPoint = units[x]:getPoint()
|
||||
-- tempPosition = units[x]:getPosition()
|
||||
|
||||
tempDist = getDistance(tempPoint.x, tempPoint.z, jtacPoint.x, jtacPoint.z)
|
||||
|
||||
-- env.info("tempDist" ..tempDist)
|
||||
-- env.info("JTAC_maxDistance" ..JTAC_maxDistance)
|
||||
|
||||
if tempDist < JTAC_maxDistance and tempDist < nearestDistance then
|
||||
|
||||
local offsetEnemyPos = { x = tempPoint.x, y = tempPoint.y + 2.0, z = tempPoint.z }
|
||||
local offsetJTACPos = { x = jtacPoint.x, y = jtacPoint.y + 2.0, z = jtacPoint.z }
|
||||
|
||||
|
||||
-- calc visible
|
||||
if land.isVisible(offsetEnemyPos, offsetJTACPos) then
|
||||
|
||||
nearestDistance = tempDist
|
||||
nearestUnit = units[x]
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if nearestUnit == nil then
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
return nearestUnit
|
||||
end
|
||||
-- tests whether the unit is targeted by another JTAC
|
||||
function alreadyTarget(jtacUnit, enemyUnit)
|
||||
|
||||
for y , jtacTarget in pairs(GLOBAL_JTAC_CURRENT_TARGETS) do
|
||||
|
||||
if jtacTarget.unitId == enemyUnit:getID() then
|
||||
-- env.info("ALREADY TARGET")
|
||||
return true
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
|
||||
-- Returns only alive units from group but the group / unit may not be active
|
||||
|
||||
function getGroup(groupName)
|
||||
|
||||
local groupUnits = Group.getByName(groupName)
|
||||
|
||||
local filteredUnits = {} --contains alive units
|
||||
local x = 1
|
||||
|
||||
if groupUnits ~= nil then
|
||||
|
||||
groupUnits = groupUnits:getUnits()
|
||||
|
||||
if groupUnits ~= nil and #groupUnits > 0 then
|
||||
for x = 1, #groupUnits do
|
||||
if groupUnits[x]:getLife() > 0 then
|
||||
table.insert(filteredUnits, groupUnits[x])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return filteredUnits
|
||||
end
|
||||
|
||||
-- Distance measurement between two positions, assume flat world
|
||||
|
||||
function getDistance(xUnit, yUnit, xZone, yZone)
|
||||
local xDiff = xUnit - xZone
|
||||
local yDiff = yUnit - yZone
|
||||
|
||||
return math.sqrt(xDiff * xDiff + yDiff * yDiff)
|
||||
end
|
||||
|
||||
-- gets the JTAC status and displays to coalition units
|
||||
function getJTACStatus()
|
||||
|
||||
--returns the status of all JTAC units
|
||||
|
||||
local jtacGroupName = nil
|
||||
local jtacUnit = nil
|
||||
local jtacUnitName = nil
|
||||
|
||||
local message = "JTAC STATUS: \n\n"
|
||||
|
||||
for jtacGroupName, jtacUnitName in pairs(GLOBAL_JTAC_UNITS) do
|
||||
|
||||
--look up units
|
||||
jtacUnit = Unit.getByName(jtacUnitName)
|
||||
|
||||
if jtacUnit ~= nil and jtacUnit:getLife() > 0 and jtacUnit:isActive() == true then
|
||||
|
||||
local enemyUnit = getCurrentUnit(jtacUnit, jtacGroupName)
|
||||
|
||||
local laserCode = GLOBAL_JTAC_LASER_CODES[jtacGroupName]
|
||||
|
||||
if laserCode == nil then
|
||||
laserCode = "UNKNOWN"
|
||||
end
|
||||
|
||||
if enemyUnit ~= nil and enemyUnit:getLife() > 0 and enemyUnit:isActive() == true then
|
||||
message = message .. "" .. jtacGroupName .. " targeting " .. enemyUnit:getTypeName().. " CODE: ".. laserCode .. getPositionString(enemyUnit) .. "\n"
|
||||
else
|
||||
message = message .. "" .. jtacGroupName .. " searching for targets" .. getPositionString(jtacUnit) .."\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
notify(message, 10)
|
||||
end
|
||||
|
||||
|
||||
-- Radio command for players (F10 Menu)
|
||||
|
||||
function addRadioCommands()
|
||||
|
||||
--looop over all players and add command
|
||||
-- missionCommands.addCommandForCoalition( coalition.side.BLUE, "JTAC Status" ,nil, getJTACStatus ,nil)
|
||||
|
||||
timer.scheduleFunction(addRadioCommands, nil, timer.getTime() + 10)
|
||||
|
||||
local blueGroups = coalition.getGroups(coalition.side.BLUE)
|
||||
local x = 1
|
||||
|
||||
if blueGroups ~= nil then
|
||||
for x, tmpGroup in pairs(blueGroups) do
|
||||
|
||||
|
||||
local index = "GROUP_" .. Group.getID(tmpGroup)
|
||||
-- env.info("adding command for "..index)
|
||||
if GLOBAL_JTAC_RADIO_ADDED[index] == nil then
|
||||
-- env.info("about command for "..index)
|
||||
missionCommands.addCommandForGroup(Group.getID(tmpGroup), "JTAC Status", nil, getJTACStatus, nil)
|
||||
GLOBAL_JTAC_RADIO_ADDED[index] = true
|
||||
-- env.info("Added command for " .. index)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function isInfantry(unit)
|
||||
|
||||
local typeName = unit:getTypeName()
|
||||
|
||||
--type coerce tostring
|
||||
typeName = string.lower(typeName.."")
|
||||
|
||||
local soldierType = { "infantry","paratrooper","stinger","manpad"}
|
||||
|
||||
for key,value in pairs(soldierType) do
|
||||
if string.match(typeName, value) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
-- assume anything that isnt soldier is vehicle
|
||||
function isVehicle(unit)
|
||||
|
||||
if isInfantry(unit) then
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
|
||||
end
|
||||
|
||||
|
||||
function getPositionString(unit)
|
||||
|
||||
if JTAC_location == false then
|
||||
return ""
|
||||
end
|
||||
|
||||
local latLngStr = latLngString(unit,3)
|
||||
|
||||
local mgrsString = MGRSString(coord.LLtoMGRS(coord.LOtoLL(unit:getPosition().p)),5)
|
||||
|
||||
return " @ " .. latLngStr .. " - MGRS "..mgrsString
|
||||
|
||||
end
|
||||
|
||||
-- source of Function MIST - https://github.com/mrSkortch/MissionScriptingTools/blob/master/mist.lua
|
||||
function latLngString(unit, acc)
|
||||
|
||||
local lat, lon = coord.LOtoLL(unit:getPosition().p)
|
||||
|
||||
local latHemi, lonHemi
|
||||
if lat > 0 then
|
||||
latHemi = 'N'
|
||||
else
|
||||
latHemi = 'S'
|
||||
end
|
||||
|
||||
if lon > 0 then
|
||||
lonHemi = 'E'
|
||||
else
|
||||
lonHemi = 'W'
|
||||
end
|
||||
|
||||
lat = math.abs(lat)
|
||||
lon = math.abs(lon)
|
||||
|
||||
local latDeg = math.floor(lat)
|
||||
local latMin = (lat - latDeg)*60
|
||||
|
||||
local lonDeg = math.floor(lon)
|
||||
local lonMin = (lon - lonDeg)*60
|
||||
|
||||
-- degrees, decimal minutes.
|
||||
latMin = roundNumber(latMin, acc)
|
||||
lonMin = roundNumber(lonMin, acc)
|
||||
|
||||
if latMin == 60 then
|
||||
latMin = 0
|
||||
latDeg = latDeg + 1
|
||||
end
|
||||
|
||||
if lonMin == 60 then
|
||||
lonMin = 0
|
||||
lonDeg = lonDeg + 1
|
||||
end
|
||||
|
||||
local minFrmtStr -- create the formatting string for the minutes place
|
||||
if acc <= 0 then -- no decimal place.
|
||||
minFrmtStr = '%02d'
|
||||
else
|
||||
local width = 3 + acc -- 01.310 - that's a width of 6, for example.
|
||||
minFrmtStr = '%0' .. width .. '.' .. acc .. 'f'
|
||||
end
|
||||
|
||||
return string.format('%02d', latDeg) .. ' ' .. string.format(minFrmtStr, latMin) .. '\'' .. latHemi .. ' '
|
||||
.. string.format('%02d', lonDeg) .. ' ' .. string.format(minFrmtStr, lonMin) .. '\'' .. lonHemi
|
||||
|
||||
end
|
||||
|
||||
-- source of Function MIST - https://github.com/mrSkortch/MissionScriptingTools/blob/master/mist.lua
|
||||
function MGRSString(MGRS, acc)
|
||||
if acc == 0 then
|
||||
return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph
|
||||
else
|
||||
return MGRS.UTMZone .. ' ' .. MGRS.MGRSDigraph .. ' ' .. string.format('%0' .. acc .. 'd', roundNumber(MGRS.Easting/(10^(5-acc)), 0))
|
||||
.. ' ' .. string.format('%0' .. acc .. 'd', roundNumber(MGRS.Northing/(10^(5-acc)), 0))
|
||||
end
|
||||
end
|
||||
-- From http://lua-users.org/wiki/SimpleRound
|
||||
function roundNumber(num, idp)
|
||||
local mult = 10^(idp or 0)
|
||||
return math.floor(num * mult + 0.5) / mult
|
||||
end
|
||||
|
||||
-- add the radio commands
|
||||
if JTAC_jtacStatusF10 == true then
|
||||
timer.scheduleFunction(addRadioCommands, nil, timer.getTime() + 1)
|
||||
end
|
||||
|
||||
|
||||
|
||||
--DEBUG FUNCTIONS - IGNORE
|
||||
--function print_functions(o)
|
||||
--
|
||||
-- for key,value in pairs(getmetatable(o)) do
|
||||
-- env.info(tostring(key) .." ".. tostring(value))
|
||||
-- end
|
||||
--end
|
||||
--
|
||||
--function dump_table(o)
|
||||
-- if type(o) == 'table' then
|
||||
-- local s = '{ '
|
||||
-- for k,v in pairs(o) do
|
||||
-- if type(k) ~= 'number' then k = '"'..k..'"' end
|
||||
-- s = s .. '['..k..'] = ' .. dump_table(v) .. ','
|
||||
-- end
|
||||
-- return s .. '} '
|
||||
-- else
|
||||
-- return tostring(o)
|
||||
-- end
|
||||
--end
|
||||
Binary file not shown.
@ -3,7 +3,7 @@ import pickle
|
||||
from dcs.mission import Mission
|
||||
from dcs.planes import A_10C
|
||||
|
||||
for terrain in ["gulf", "nev", "channel", "normandy"]:
|
||||
for terrain in ["cau"]:
|
||||
print("Terrain " + terrain)
|
||||
m = Mission()
|
||||
m.load_file("./{}_terrain.miz".format(terrain))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user