New Moose-based Autolase alternative with UI options (#565)

This commit is contained in:
Taco 2025-08-27 13:24:00 -04:00 committed by GitHub
parent d2aa615133
commit e8190748eb
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 694 additions and 0 deletions

View File

@ -0,0 +1,610 @@
env.info("-----DCSRetribution|MOOSE Autolase plugin - configuration start ------")
-- Defaults (overridden by dcsRetribution.plugins.MooseAutolase when present)
JtacAlphaSmoke = true
JtacAlphaUHF = 250
JtacAlphaVHF = 123
JtacAlphaTargetsMax = 1
JtacAlphaRadiusNM = 50
JtacBravoSmoke = true
JtacBravoUHF = 249
JtacBravoVHF = 122
JtacBravoTargetsMax = 1
JtacBravoRadiusNM = 50
DangerCloseNM = 1
AutolaseSmokeDurationSec = 180
MooseAutolaseDebug = false
UseConvoyChaosSFX = true -- NEW: set false if ConvoyChaos.ogg not in mission
-- Pull from UI if available
if dcsRetribution and dcsRetribution.plugins and dcsRetribution.plugins.MooseAutolase then
local p = dcsRetribution.plugins.MooseAutolase
JtacAlphaSmoke = p.JtacAlphaSmoke
JtacAlphaUHF = p.JtacAlphaUHF
JtacAlphaVHF = p.JtacAlphaVHF
JtacAlphaTargetsMax = p.JtacAlphaTargetsMax
JtacAlphaRadiusNM = p.JtacAlphaRadiusNM
JtacBravoSmoke = p.JtacBravoSmoke
JtacBravoUHF = p.JtacBravoUHF
JtacBravoVHF = p.JtacBravoVHF
JtacBravoTargetsMax = p.JtacBravoTargetsMax
JtacBravoRadiusNM = p.JtacBravoRadiusNM
DangerCloseNM = p.DangerCloseNM
AutolaseSmokeDurationSec = p.AutolaseSmokeDurationSec
MooseAutolaseDebug = p.MooseAutolaseDebug
if p.UseConvoyChaosSFX ~= nil then UseConvoyChaosSFX = p.UseConvoyChaosSFX end
else
env.info("-----dcsRetribution.plugins.MooseAutolase NOT FOUND")
end
-- Debug output to DCS log
env.info("--------- JtacAlphaSmoke=" .. tostring(JtacAlphaSmoke) ..
" | JtacAlphaUHF=" .. tostring(JtacAlphaUHF) ..
" | JtacAlphaVHF=" .. tostring(JtacAlphaVHF) ..
" | JtacAlphaTargetsMax=" .. tostring(JtacAlphaTargetsMax) ..
" | JtacAlphaRadiusNM=" .. tostring(JtacAlphaRadiusNM) ..
" | JtacBravoSmoke=" .. tostring(JtacBravoSmoke) ..
" | JtacBravoUHF=" .. tostring(JtacBravoUHF) ..
" | JtacBravoVHF=" .. tostring(JtacBravoVHF) ..
" | JtacBravoTargetsMax=" .. tostring(JtacBravoTargetsMax) ..
" | JtacBravoRadiusNM=" .. tostring(JtacBravoRadiusNM) ..
" | DangerCloseNM=" .. tostring(DangerCloseNM) ..
" | UseConvoyChaosSFX=" .. tostring(UseConvoyChaosSFX) ..
" | MooseAutolaseDebug=" .. tostring(MooseAutolaseDebug) ..
" | AutolaseSmokeDurationSec=" .. tostring(AutolaseSmokeDurationSec)
)
-----------------------------------------------------------------
-- COORDINATE:Smoke duration override (uses AutolaseSmokeDurationSec when duration omitted)
-----------------------------------------------------------------
if not _G.__CoordSmokePatched and COORDINATE and COORDINATE.Smoke then
_G.__CoordSmokePatched = true
COORDINATE._Smoke_original = COORDINATE._Smoke_original or COORDINATE.Smoke
function COORDINATE:Smoke(color, duration, delay, name, offset, direction, distance)
local useDuration = (duration ~= nil) and duration or AutolaseSmokeDurationSec
if MooseAutolaseDebug and duration == nil then
env.info(string.format("[AutolaseSmokePatch] default duration %ds (color=%s)", useDuration, tostring(color)))
end
return COORDINATE._Smoke_original(self, color, useDuration, delay, name, offset, direction, distance)
end
end
-- Safe AM constant
local AM = (radio and radio.modulation and radio.modulation.AM) or 0
-- Utility: format integer values with thousands separators (e.g., 12,345)
local function FormatWithCommas(n)
local s = tostring(math.floor(n or 0))
local left, num, right = s:match('^([^%d]*%d)(%d*)(.-)$')
return left .. (num:reverse():gsub('(%d%d%d)', '%1,'):reverse()) .. right
end
-- Per-file durations (seconds). Adjust as needed.
local SFX_DURATION_DEFAULT = 5.0
local SFX_DURATIONS = {
["ConvoyChaos.ogg"] = 6.0,
["LaserOff.ogg"] = 1.0,
["LaserOn.ogg"] = 1.0,
["TargetLost.ogg"] = 1.0,
["TargetSmoke.ogg"] = 5.0, -- assumed from your note
}
local function GetSfxDuration(sfx)
return SFX_DURATIONS[sfx] or SFX_DURATION_DEFAULT
end
-- Unified transmitter (uses the JTACs own unit(1))
local function TransmitRadio(forGroup, freqMHz, sfx, text, dbgTag)
local unit = forGroup and forGroup:GetUnit(1)
if not unit then
if MooseAutolaseDebug then env.info(string.format("[%s] No unit to transmit on", dbgTag or "TX")) end
return
end
local Radio = unit:GetRadio()
if not Radio then
if MooseAutolaseDebug then env.info(string.format("[%s] No Radio on %s", dbgTag or "TX", unit:GetName())) end
return
end
Radio:SetFrequency(freqMHz)
Radio:SetModulation(AM)
Radio:SetPower(100)
Radio:SetFileName(sfx)
Radio:SetSubtitle(text, 60)
Radio:Broadcast()
if MooseAutolaseDebug then
env.info(string.format("[%s] tx @ %.3f MHz AM via %s (sfx=%s)", dbgTag or "TX", freqMHz, unit:GetName(), sfx))
end
end
-----------------------------------------------------------------
------ ALPHA
-----------------------------------------------------------------
if GROUP:FindByName("JTAC Alpha") then
if MooseAutolaseDebug then env.info("------JTAC Alpha Located-------") end
local JtacAlpha = GROUP:FindByName("JTAC Alpha")
local JtacAlphaCoord = JtacAlpha:GetCoordinate()
local AlphaDroneUnit = JtacAlpha:GetUnit(1)
local JtacAlphaFlightgroup = FLIGHTGROUP:New(JtacAlpha)
local JtacAlphaName = JtacAlpha:GetName()
if MooseAutolaseDebug then
MESSAGE:New("SETTING UP JTAC ALPHA FOR AUTOLASE (MOOSE)", 5, "RETRIBUTION", false):ToAll():ToLog()
end
local AlphaRacetrack = AUFTRAG:NewORBIT_CIRCLE(JtacAlphaCoord, 20000, 120)
JtacAlphaFlightgroup:SetDefaultInvisible(true)
JtacAlphaFlightgroup:SetDefaultImmortal(true)
JtacAlphaFlightgroup:AddMission(AlphaRacetrack)
local function _DumpMissionQueue(tag)
local lines = {}
local queue = JtacAlphaFlightgroup and JtacAlphaFlightgroup.missionqueue or nil
local function safe(call, default)
local ok, val = pcall(call); return ok and val or default
end
local function _describeAuftrag(idx, auf)
local name = safe(function() return auf:GetName() end,
safe(function() return auf.Name end, safe(function() return auf.name end, "AUFTRAG")))
local prio = safe(function() return auf:GetPriority() end,
safe(function() return auf.Priority end, safe(function() return auf.prio end, "?")))
local urgent = safe(function() return tostring(auf:GetUrgent()) end,
safe(function() return tostring(auf.Urgent) end, safe(function() return tostring(auf.urgent) end, "?")))
return string.format("%02d) %s [prio=%s, urgent=%s]", idx, tostring(name), tostring(prio), tostring(urgent))
end
if type(queue) == "table" then
local idx = 0
for i, auf in ipairs(queue) do
idx = i; table.insert(lines, _describeAuftrag(i, auf))
end
for k, auf in pairs(queue) do
if type(k) ~= "number" or k < 1 or k > idx then
table.insert(lines,
_describeAuftrag(#lines + 1, auf))
end
end
else
table.insert(lines, "(missionqueue not available on this FLIGHTGROUP)")
end
local text = string.format("JTAC %s MissionQueue — %s\n%s", JtacAlphaName, tag or "update",
table.concat(lines, "\n"))
if MooseAutolaseDebug then MESSAGE:New(text, 15, "Alpha Queue"):ToAll() end
end
local Alpha_AutolaseSet = SET_GROUP:New():FilterPrefixes("Alpha"):FilterCoalitions("blue"):FilterOnce()
Alpha_AutolaseSet:AddGroup(JtacAlpha)
local Alpha_DroneZone = ZONE_GROUP:New("Alpha_DroneZone", JtacAlpha,
1852 * JtacAlphaRadiusNM)
local Alpha_PilotSet = SET_CLIENT:New():FilterCoalitions("blue"):FilterZones({
Alpha_DroneZone }):FilterActive():FilterStart()
local Alpha_RetributionAutolase = AUTOLASE:New(Alpha_AutolaseSet, coalition.side.BLUE,
JtacAlphaName .. " Autolase", Alpha_PilotSet)
:SetMaxLasingTargets(JtacAlphaTargetsMax)
:SetLasingParameters(15000, AutolaseSmokeDurationSec)
:SetNotifyPilots(false)
:SetSmokeTargets(JtacAlphaSmoke, SMOKECOLOR.Red)
:EnableSmokeMenu({ Angle = 30, Distance = 40 })
Alpha_RetributionAutolase._currentOrbitAuftrag = AlphaRacetrack
Alpha_RetributionAutolase._homeCoord = JtacAlphaCoord
Alpha_RetributionAutolase._altHomeFt = 20000
Alpha_RetributionAutolase._altTgtFt = 18000
Alpha_RetributionAutolase._orbitSpeedKts = 120
Alpha_RetributionAutolase._lastLaserInfo = {}
function Alpha_RetributionAutolase:_ReplaceOrbitAt(coord, altFt, reasonTag)
if not coord then return end
if self._currentOrbitAuftrag then
pcall(function() self._currentOrbitAuftrag:Cancel() end); self._currentOrbitAuftrag = nil
end
local newOrbit = AUFTRAG:NewORBIT_CIRCLE(coord, altFt or self._altTgtFt, self._orbitSpeedKts)
newOrbit:SetPriority(1, true, 1)
JtacAlphaFlightgroup:AddMission(newOrbit)
self._currentOrbitAuftrag = newOrbit
if MooseAutolaseDebug then
env.info(string.format("JTAC %s orbit RECENTERED at %s (alt %d ft) [%s]",
JtacAlphaName, coord:ToStringMGRS(), altFt or self._altTgtFt, tostring(reasonTag or "update")))
end
_DumpMissionQueue(reasonTag or "orbit retask")
end
function Alpha_RetributionAutolase:OnAfterLasing(From, Event, To, LaserSpot)
if MooseAutolaseDebug then env.info(JtacAlphaName .. " ------ Laser On!") end
self._lastLaserInfo = {
code = LaserSpot and LaserSpot.lasercode or 0,
mgrs = (LaserSpot and LaserSpot.coordinate) and LaserSpot.coordinate:ToStringMGRS() or "N/A",
unittype = LaserSpot and LaserSpot.unittype or "Unknown",
reccename = LaserSpot and LaserSpot.reccename or "Unknown"
}
if LaserSpot and LaserSpot.coordinate then
self:_ReplaceOrbitAt(LaserSpot.coordinate, self._altTgtFt, "new lase")
else
self:_ReplaceOrbitAt(self._homeCoord, self._altHomeFt, "no coord")
end
-- pilot notifications (+ danger-close friendlies + BR fix + sound selection)
Alpha_PilotSet:ForEachClient(function(client)
if client and client:IsAlive() then
local laserspot = LaserSpot
if laserspot and laserspot.coordinate then
local clientCoord = client:GetCoordinate()
local BRInfo = laserspot.coordinate:ToStringBR(clientCoord)
local BRInfoClean = (BRInfo or "N/A"):gsub("^%s*:%s*", "")
-- DANGER CLOSE detection
local dangerNote, dangerClose = "", false
do
local tgtCoord = laserspot.coordinate
local DC_RADIUS_M = DangerCloseNM * 1852
local jtacSide = JtacAlpha:GetCoalition()
local sideStr = (jtacSide == coalition.side.RED and "red")
or (jtacSide == coalition.side.BLUE and "blue")
or "neutral"
local nearestCoord, nearestDist
local FriendlyGroundSet = SET_GROUP:New()
:FilterCoalitions(sideStr)
:FilterActive()
:FilterStart()
FriendlyGroundSet:ForEachGroup(function(g)
if g:IsGround() then
local c = g:GetCoordinate()
local d = c and tgtCoord and c:Get2DDistance(tgtCoord) or nil
if d and d <= DC_RADIUS_M and (not nearestDist or d < nearestDist) then
nearestDist, nearestCoord = d, c
end
end
end)
if nearestCoord and nearestDist then
dangerClose = true
nearestCoord:Smoke(SMOKECOLOR.Green, AutolaseSmokeDurationSec)
local brtxt = tgtCoord:ToStringBR(nearestCoord) or ""
local bearing = tonumber(brtxt:match("(%d+)")) or 0
local dirs = { "north", "northeast", "east", "southeast", "south", "southwest", "west",
"northwest" }
local idx = (math.floor((bearing + 22.5) / 45) % 8) + 1
local cardinal = dirs[idx]
local feet = math.floor(nearestDist * 3.28084 + 0.5)
local feetStr = (feet >= 1000) and FormatWithCommas(feet) or tostring(feet)
dangerNote = string.format(
"\nFriendlies are DANGER CLOSE, %s feet %s of target, marking with green smoke.",
feetStr, cardinal)
end
end
local text = string.format(
"%s is lasing %s code %d\nat %s\n%s%s",
laserspot.reccename or "Unknown",
laserspot.unittype or "Unknown",
laserspot.lasercode or 0,
laserspot.coordinate:ToStringMGRS(),
BRInfoClean,
dangerNote
)
-- choose SFX (unchanged from your working logic)
local function pickSFX(smokeOn)
if dangerClose and UseConvoyChaosSFX then return "ConvoyChaos.ogg" end
return (smokeOn and "TargetSmoke.ogg") or "LaserOn.ogg"
end
-- choose SFX exactly as you already do
local function pickSFX(smokeOn)
if dangerClose and UseConvoyChaosSFX then return "ConvoyChaos.ogg" end
return (smokeOn and "TargetSmoke.ogg") or "LaserOn.ogg"
end
local sfx = pickSFX(Alpha_RetributionAutolase.smoketargets)
local firstDur = GetSfxDuration(sfx)
-- UHF now
TransmitRadio(JtacAlpha, JtacAlphaUHF, sfx, text, "ALPHA UHF")
-- VHF after UHF completes (+pad)
TIMER:New(function()
TransmitRadio(JtacAlpha, JtacAlphaVHF, sfx, text, "ALPHA VHF")
end):Start(firstDur + 0.15)
MESSAGE:New(text, 60, "Alpha"):ToLog()
end
end
end)
end
function Alpha_RetributionAutolase:OnAfterTargetDestroyed(From, Event, To, UnitName, RecceName)
env.info("----JTAC Alpha's target destroyed, returning to home orbit-----")
self:_ReplaceOrbitAt(self._homeCoord, self._altHomeFt, "target destroyed")
end
function Alpha_RetributionAutolase:OnAfterTargetLost(From, Event, To, UnitName, RecceName)
if MooseAutolaseDebug then env.info(JtacAlphaName .. " ------ Target Lost!") end
Alpha_PilotSet:ForEachClient(function(client)
if client and client:IsAlive() then
local info = self._lastLaserInfo or {}
local text = string.format("%s LOST TARGET\n%s (code %d) at %s", info.reccename or RecceName,
info.unittype or "Unknown", info.code or 0, info.mgrs or "Unknown")
-- match your previous logic: TargetLost if smoke on, else LaserOff
local sfx = (Alpha_RetributionAutolase.smoketargets and "TargetLost.ogg") or "LaserOff.ogg"
local firstDur = GetSfxDuration(sfx)
TransmitRadio(JtacAlpha, JtacAlphaUHF, sfx, text, "ALPHA UHF LOST")
TIMER:New(function()
TransmitRadio(JtacAlpha, JtacAlphaVHF, sfx, text, "ALPHA VHF LOST")
end):Start(firstDur + 0.15)
MESSAGE:New(text, 60, "Alpha"):ToLog()
end
end)
self:_ReplaceOrbitAt(self._homeCoord, self._altHomeFt, "target lost")
end
if AlphaDroneUnit then
local unitName = AlphaDroneUnit:GetName()
local laserCode = 1688
Alpha_RetributionAutolase:SetRecceLaserCode(unitName, laserCode)
Alpha_RetributionAutolase:SetRecceSmokeColor(unitName, SMOKECOLOR.Red)
if MooseAutolaseDebug then env.info(string.format("%s assigned laser code %d", unitName, laserCode)) end
end
_DumpMissionQueue("initial")
else
if MooseAutolaseDebug then env.info("------JTAC Alpha NOT Located-------") end
end
-----------------------------------------------------------------
------ BRAVO
-----------------------------------------------------------------
if GROUP:FindByName("JTAC Bravo") then
if MooseAutolaseDebug then env.info("------JTAC Bravo Located-------") end
local JtacBravo = GROUP:FindByName("JTAC Bravo")
local JtacBravoCoord = JtacBravo:GetCoordinate()
local BravoDroneUnit = JtacBravo:GetUnit(1)
local JtacBravoName = JtacBravo:GetName()
local JtacBravoFlightgroup = FLIGHTGROUP:New(JtacBravo)
if MooseAutolaseDebug then
MESSAGE:New("SETTING UP JTAC BRAVO FOR AUTOLASE (MOOSE)", 5, "RETRIBUTION", false):ToAll():ToLog()
end
local BravoRacetrack = AUFTRAG:NewORBIT_CIRCLE(JtacBravoCoord, 15000, 120)
JtacBravoFlightgroup:SetDefaultInvisible(true)
JtacBravoFlightgroup:SetDefaultImmortal(true)
JtacBravoFlightgroup:AddMission(BravoRacetrack)
local function _DumpMissionQueue(tag)
local lines = {}
local queue = JtacBravoFlightgroup and JtacBravoFlightgroup.missionqueue or nil
local function safe(call, default)
local ok, val = pcall(call); return ok and val or default
end
local function _describeAuftrag(idx, auf)
local name = safe(function() return auf:GetName() end,
safe(function() return auf.Name end, safe(function() return auf.name end, "AUFTRAG")))
local prio = safe(function() return auf:GetPriority() end,
safe(function() return auf.Priority end, safe(function() return auf.prio end, "?")))
local urgent = safe(function() return tostring(auf:GetUrgent()) end,
safe(function() return tostring(auf.Urgent) end, safe(function() return tostring(auf.urgent) end, "?")))
return string.format("%02d) %s [prio=%s, urgent=%s]", idx, tostring(name), tostring(prio), tostring(urgent))
end
if type(queue) == "table" then
local idx = 0
for i, auf in ipairs(queue) do
idx = i; table.insert(lines, _describeAuftrag(i, auf))
end
for k, auf in pairs(queue) do
if type(k) ~= "number" or k < 1 or k > idx then
table.insert(lines,
_describeAuftrag(#lines + 1, auf))
end
end
else
table.insert(lines, "(missionqueue not available on this FLIGHTGROUP)")
end
local text = string.format("JTAC %s MissionQueue — %s\n%s", JtacBravoName, tag or "update",
table.concat(lines, "\n"))
if MooseAutolaseDebug then MESSAGE:New(text, 15, "Bravo Queue"):ToAll() end
end
local Bravo_AutolaseSet = SET_GROUP:New():FilterPrefixes("Bravo"):FilterCoalitions("blue"):FilterOnce()
Bravo_AutolaseSet:AddGroup(JtacBravo)
local Bravo_DroneZone = ZONE_GROUP:New("Bravo_DroneZone", JtacBravo,
1852 * JtacBravoRadiusNM)
local Bravo_PilotSet = SET_CLIENT:New():FilterCoalitions("blue"):FilterZones({
Bravo_DroneZone }):FilterActive():FilterStart()
local Bravo_RetributionAutolase = AUTOLASE:New(Bravo_AutolaseSet, coalition.side.BLUE,
JtacBravoName .. " Autolase", Bravo_PilotSet)
:SetMaxLasingTargets(JtacBravoTargetsMax)
:SetLasingParameters(10000, AutolaseSmokeDurationSec)
:SetNotifyPilots(false)
:SetSmokeTargets(JtacBravoSmoke, SMOKECOLOR.Red)
:EnableSmokeMenu({ Angle = 30, Distance = 40 })
Bravo_RetributionAutolase._currentOrbitAuftrag = BravoRacetrack
Bravo_RetributionAutolase._homeCoord = JtacBravoCoord
Bravo_RetributionAutolase._altHomeFt = 15000
Bravo_RetributionAutolase._altTgtFt = 16000
Bravo_RetributionAutolase._orbitSpeedKts = 120
Bravo_RetributionAutolase._lastLaserInfo = {}
function Bravo_RetributionAutolase:_ReplaceOrbitAt(coord, altFt, reasonTag)
if not coord then return end
if self._currentOrbitAuftrag then
pcall(function() self._currentOrbitAuftrag:Cancel() end); self._currentOrbitAuftrag = nil
end
local newOrbit = AUFTRAG:NewORBIT_CIRCLE(coord, altFt or self._altTgtFt, self._orbitSpeedKts)
newOrbit:SetPriority(1, true, 1)
JtacBravoFlightgroup:AddMission(newOrbit)
self._currentOrbitAuftrag = newOrbit
if MooseAutolaseDebug then
env.info(string.format("JTAC %s orbit RECENTERED at %s (alt %d ft) [%s]",
JtacBravoName, coord:ToStringMGRS(), altFt or self._altTgtFt, tostring(reasonTag or "update")))
end
_DumpMissionQueue(reasonTag or "orbit retask")
end
function Bravo_RetributionAutolase:OnAfterLasing(From, Event, To, LaserSpot)
if MooseAutolaseDebug then env.info(JtacBravoName .. " ------ Laser On!") end
self._lastLaserInfo = {
code = LaserSpot and LaserSpot.lasercode or 0,
mgrs = (LaserSpot and LaserSpot.coordinate) and LaserSpot.coordinate:ToStringMGRS() or "N/A",
unittype = LaserSpot and LaserSpot.unittype or "Unknown",
reccename = LaserSpot and LaserSpot.reccename or "Unknown"
}
if LaserSpot and LaserSpot.coordinate then
self:_ReplaceOrbitAt(LaserSpot.coordinate, self._altTgtFt, "new lase")
else
self:_ReplaceOrbitAt(self._homeCoord, self._altHomeFt, "no coord")
end
-- pilot notifications (+ danger-close friendlies + BR fix + sound selection)
Bravo_PilotSet:ForEachClient(function(client)
if client and client:IsAlive() then
local laserspot = LaserSpot
if laserspot and laserspot.coordinate then
local clientCoord = client:GetCoordinate()
local BRInfo = laserspot.coordinate:ToStringBR(clientCoord)
local BRInfoClean = (BRInfo or "N/A"):gsub("^%s*:%s*", "")
-- DANGER CLOSE detection
local dangerNote, dangerClose = "", false
do
local tgtCoord = laserspot.coordinate
local DC_RADIUS_M = DangerCloseNM * 1852
local jtacSide = JtacBravo:GetCoalition()
local sideStr = (jtacSide == coalition.side.RED and "red")
or (jtacSide == coalition.side.BLUE and "blue")
or "neutral"
local nearestCoord, nearestDist
local FriendlyGroundSet = SET_GROUP:New()
:FilterCoalitions(sideStr)
:FilterActive()
:FilterStart()
FriendlyGroundSet:ForEachGroup(function(g)
if g:IsGround() then
local c = g:GetCoordinate()
local d = c and tgtCoord and c:Get2DDistance(tgtCoord) or nil
if d and d <= DC_RADIUS_M and (not nearestDist or d < nearestDist) then
nearestDist, nearestCoord = d, c
end
end
end)
if nearestCoord and nearestDist then
dangerClose = true
nearestCoord:Smoke(SMOKECOLOR.Green, AutolaseSmokeDurationSec)
local brtxt = tgtCoord:ToStringBR(nearestCoord) or ""
local bearing = tonumber(brtxt:match("(%d+)")) or 0
local dirs = { "north", "northeast", "east", "southeast", "south", "southwest", "west",
"northwest" }
local idx = (math.floor((bearing + 22.5) / 45) % 8) + 1
local cardinal = dirs[idx]
local feet = math.floor(nearestDist * 3.28084 + 0.5)
local feetStr = (feet >= 1000) and FormatWithCommas(feet) or tostring(feet)
dangerNote = string.format(
"\nFriendlies are DANGER CLOSE, %s feet %s of target, marking with green smoke.",
feetStr, cardinal)
end
end
local text = string.format(
"%s is lasing %s code %d\nat %s\n%s%s",
laserspot.reccename or "Unknown",
laserspot.unittype or "Unknown",
laserspot.lasercode or 0,
laserspot.coordinate:ToStringMGRS(),
BRInfoClean,
dangerNote
)
local function pickSFX(smokeOn)
if dangerClose and UseConvoyChaosSFX then return "ConvoyChaos.ogg" end
return (smokeOn and "TargetSmoke.ogg") or "LaserOn.ogg"
end
local function pickSFX(smokeOn)
if dangerClose and UseConvoyChaosSFX then return "ConvoyChaos.ogg" end
return (smokeOn and "TargetSmoke.ogg") or "LaserOn.ogg"
end
local sfx = pickSFX(Bravo_RetributionAutolase.smoketargets)
local firstDur = GetSfxDuration(sfx)
TransmitRadio(JtacBravo, JtacBravoUHF, sfx, text, "BRAVO UHF")
TIMER:New(function()
TransmitRadio(JtacBravo, JtacBravoVHF, sfx, text, "BRAVO VHF")
end):Start(firstDur + 0.15)
MESSAGE:New(text, 60, "Bravo"):ToLog()
end
end
end)
end
function Bravo_RetributionAutolase:OnAfterTargetDestroyed(From, Event, To, UnitName, RecceName)
env.info("----JTAC Bravo's target destroyed, returning to home orbit-----")
self:_ReplaceOrbitAt(self._homeCoord, self._altHomeFt, "target destroyed")
end
function Bravo_RetributionAutolase:OnAfterTargetLost(From, Event, To, UnitName, RecceName)
if MooseAutolaseDebug then env.info(JtacBravoName .. " ------ Target Lost!") end
Bravo_PilotSet:ForEachClient(function(client)
if client and client:IsAlive() then
local info = self._lastLaserInfo or {}
local text = string.format("%s LOST TARGET\n%s (code %d) at %s", info.reccename or RecceName,
info.unittype or "Unknown", info.code or 0, info.mgrs or "Unknown")
local sfx = (Bravo_RetributionAutolase.smoketargets and "TargetLost.ogg") or "LaserOff.ogg"
local firstDur = GetSfxDuration(sfx)
TransmitRadio(JtacBravo, JtacBravoUHF, sfx, text, "BRAVO UHF LOST")
TIMER:New(function()
TransmitRadio(JtacBravo, JtacBravoVHF, sfx, text, "BRAVO VHF LOST")
end):Start(firstDur + 0.15)
MESSAGE:New(text, 60, "Bravo"):ToLog()
end
end)
self:_ReplaceOrbitAt(self._homeCoord, self._altHomeFt, "target lost")
end
if BravoDroneUnit then
local unitName = BravoDroneUnit:GetName()
local laserCode = 1688
Bravo_RetributionAutolase:SetRecceLaserCode(unitName, laserCode)
Bravo_RetributionAutolase:SetRecceSmokeColor(unitName, SMOKECOLOR.Red)
if MooseAutolaseDebug then env.info(string.format("%s assigned laser code %d", unitName, laserCode)) end
end
_DumpMissionQueue("initial")
else
if MooseAutolaseDebug then env.info("------JTAC Bravo NOT Located-------") end
end
env.info("-----DCSRetribution|MOOSE Autolase plugin - configuration end ------")

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,83 @@
{
"nameInUI": "Moose Autolase",
"defaultValue": false,
"specificOptions": [
{
"nameInUI": "JTAC Alpha - Smoke On/Off",
"mnemonic": "JtacAlphaSmoke",
"defaultValue": true
},
{
"nameInUI": "JTAC Alpha - UHF Frequency",
"mnemonic": "JtacAlphaUHF",
"defaultValue": 250
},
{
"nameInUI": "JTAC Alpha - VHF Frequency",
"mnemonic": "JtacAlphaVHF",
"defaultValue": 123
},
{
"nameInUI": "JTAC Alpha - Maximum Lasing Targets",
"mnemonic": "JtacAlphaTargetsMax",
"defaultValue": 1
},
{
"nameInUI": "JTAC Alpha - Notify Radius (NM)",
"mnemonic": "JtacAlphaRadiusNM",
"defaultValue": 50
},
{
"nameInUI": "JTAC Bravo - Smoke On/Off",
"mnemonic": "JtacBravoSmoke",
"defaultValue": true
},
{
"nameInUI": "JTAC Bravo - UHF Frequency",
"mnemonic": "JtacBravoUHF",
"defaultValue": 251
},
{
"nameInUI": "JTAC Bravo - VHF Frequency",
"mnemonic": "JtacBravoVHF",
"defaultValue": 124
},
{
"nameInUI": "JTAC Bravo - Maximum Lasing Targets",
"mnemonic": "JtacBravoTargetsMax",
"defaultValue": 1
},
{
"nameInUI": "JTAC Bravo - Notify Radius (NM)",
"mnemonic": "JtacBravoRadiusNM",
"defaultValue": 50
},
{
"nameInUI": "Danger Close Radius (NM)",
"mnemonic": "DangerCloseNM",
"minimumValue": 0.1,
"maximumValue": 2,
"defaultValue": 1.0
},
{
"nameInUI": "Debug Mode",
"mnemonic": "MooseAutolaseDebug",
"defaultValue": false
}
],
"scriptsWorkOrders": [],
"configurationWorkOrders": [
{
"file": "Plugin_Autolase_JTAC.lua",
"mnemonic": "MooseAutolase-config"
}
],
"otherResourceFiles": [
"SoundFiles/TargetLost.ogg",
"SoundFiles/TargetSmoke.ogg",
"SoundFiles/LaserOn.ogg",
"SoundFiles/LaserOff.ogg",
"SoundFiles/RadioOn.ogg",
"SoundFiles/ConvoyChaos.ogg"
]
}

View File

@ -10,5 +10,6 @@
"lotatc",
"skynetiads",
"splashdamage2",
"MooseAutolase",
"MooseMarkerOps"
]