------------------------------------------------------------------ -- VEAF helper for Hound-Elint -- By zip (2021) -- -- Features: -- --------- -- * This module offers support for integrating Hound-Elint in a mission -- -- See the documentation : https://veaf.github.io/documentation/ ------------------------------------------------------------------ veafHoundElint = {} ------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Global settings. Stores the script constants ------------------------------------------------------------------------------------------------------------------------------------------------------------- --- Identifier. All output in DCS.log will start with this. veafHoundElint.Id = "HOUND" --- Version. veafHoundElint.Version = "1.1.1" -- trace level, specific to this module --veafHoundElint.LogLevel = "debug" veaf.loggers.new(veafHoundElint.Id, veafHoundElint.LogLevel) -- delay before the mission groups are added to the Hound system at start veafHoundElint.DelayForStartup = 1 ------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Do not change anything below unless you know what you are doing! ------------------------------------------------------------------------------------------------------------------------------------------------------------- veafHoundElint.initialized = false veafHoundElint.prefix = nil veafHoundElint.redParameters = {} veafHoundElint.blueParameters = {} veafHoundElint.redHound = nil veafHoundElint.blueHound = nil veafHoundElint.elintUnitsTypes = {} veafHoundElint.globalSectorName = "GLOBAL" ------------------------------------------------------------------------------------------------------------------------------------------------------------- -- Utility methods ------------------------------------------------------------------------------------------------------------------------------------------------------------- ------------------------------------------------------------------------------------------------------------------------------------------------------------- -- core functions ------------------------------------------------------------------------------------------------------------------------------------------------------------- function veafHoundElint.getHoundOfCoalition(coa) --veaf.loggers.get(veafHoundElint.Id):trace(string.format("getHoundOfCoalition(%s)", veaf.p(coa))) local hound = nil if coa == coalition.side.RED then hound = veafHoundElint.redHound elseif coa == coalition.side.BLUE then hound = veafHoundElint.blueHound end return hound end function veafHoundElint.addPlatformToSystem(dcsGroup, alreadyAddedUnits, atMissionStart) if not veafHoundElint.initialized then return false end if not dcsGroup then veaf.loggers.get(veafHoundElint.Id):error("group does not exist") return false end local groupName = dcsGroup:getName() local coa = dcsGroup:getCoalition() local hound = veafHoundElint.getHoundOfCoalition(coa) veaf.loggers.get(veafHoundElint.Id):debug(string.format("addPlatformToSystem(%s) to %s", veaf.p(groupName), veaf.p(veaf.ifnn(hound,"name")))) veaf.loggers.get(veafHoundElint.Id):trace(string.format("atMissionStart=%s", veaf.p(atMissionStart))) local batchMode = (alreadyAddedUnits ~= nil) local alreadyAddedUnits = alreadyAddedUnits or {} if not(hound) then veaf.loggers.get(veafHoundElint.Id):error(string.format("no Hound system for the coalition of %s", veaf.p(groupName))) return false end local didSomething = false local _addUnitToSystem = function(dcsUnit, isFunctional) if not(atMissionStart) or isFunctional then local unitName = dcsUnit:getName() local unitType = dcsUnit:getDesc()["typeName"] veaf.loggers.get(veafHoundElint.Id):trace(string.format("checking unit %s of type %s", veaf.p(unitName), veaf.p(unitType))) -- check if the unitType is supported by Hound Elint if veafHoundElint.elintUnitsTypes[unitType] then veaf.loggers.get(veafHoundElint.Id):trace(string.format("-> supported elint type")) -- check the unit name vs the prefix if veafHoundElint.prefix then local _p1, _p2 = unitName:lower():find(veafHoundElint.prefix:lower()) veaf.loggers.get(veafHoundElint.Id):trace(string.format("_p1=%s", veaf.p(_p1))) veaf.loggers.get(veafHoundElint.Id):trace(string.format("_p2=%s", veaf.p(_p2))) if _p2 and _p1 == 1 then -- found the prefix at the beginning of the name if not(alreadyAddedUnits[unitName]) then veaf.loggers.get(veafHoundElint.Id):trace(string.format("adding a platform : %s", unitName)) local added = hound:addPlatform(unitName) -- no actual return value -- todo check if ok when HoundElint will give us a return value if added then didSomething = true alreadyAddedUnits[unitName] = true veaf.loggers.get(veafHoundElint.Id):trace(string.format("adding a platform -> OK")) end end end end end end end --veaf.loggers.get(veafHoundElint.Id):trace(string.format("batchMode = %s", veaf.p(batchMode))) veaf.loggers.get(veafHoundElint.Id):trace(string.format("dcsGroup=%s", veaf.p(mist.utils.deepCopy(dcsGroup)))) if Group.getByName(groupName) then for _, dcsUnit in pairs(dcsGroup:getUnits()) do veaf.loggers.get(veafHoundElint.Id):trace(string.format("dcsUnit.getName=%s", veaf.p(veaf.ifnn(dcsUnit, "getName")))) veaf.loggers.get(veafHoundElint.Id):trace(string.format("dcsUnit:isActive()=%s", veaf.p(dcsUnit:isActive()))) _addUnitToSystem(dcsUnit, dcsUnit:isActive()) end elseif StaticObject.getByName(groupName) then veaf.loggers.get(veafHoundElint.Id):trace("Group is Static") veaf.loggers.get(veafHoundElint.Id):trace(string.format("dcsGroup:isExist()=%s", veaf.p(dcsGroup:isExist()))) _addUnitToSystem(dcsGroup, dcsGroup:isExist()) end if didSomething and not(batchMode) then veaf.loggers.get(veafHoundElint.Id):trace(string.format("reactivating the Elint system")) -- reactivate the system hound:systemOn() end return didSomething end local function initializeHoundSystem(coa, parameters, atMissionStart) local hound = veafHoundElint.getHoundOfCoalition(coa) veaf.loggers.get(veafHoundElint.Id):debug(string.format("initializeHoundSystem %s",tostring(hound.name))) veaf.loggers.get(veafHoundElint.Id):debug(string.format("atMissionStart=%s",veaf.p(atMissionStart))) local alreadyAddedUnits = {} local dcsGroups = coalition.getGroups(coa) for _, dcsGroup in pairs(dcsGroups) do veafHoundElint.addPlatformToSystem(dcsGroup, alreadyAddedUnits, atMissionStart) end if parameters then if parameters.markers then hound:enableMarkers(HOUND.MARKER.DIAMOND) veaf.loggers.get(veafHoundElint.Id):debug("enabled markers") end if parameters.platformPositionErrors then hound:enablePlatformPosErrors() veaf.loggers.get(veafHoundElint.Id):debug("enabled platformPositionErrors") end if parameters.disableBDA then hound:disableBDA() veaf.loggers.get(veafHoundElint.Id):debug("disabled BDA") end if parameters.NATO_SectorCallsigns then hound:useNATOCallsignes(true) veaf.loggers.get(veafHoundElint.Id):debug("using NATO callsigns for zones") end if parameters.NATOmessages then hound:enableNATO() veaf.loggers.get(veafHoundElint.Id):debug("using NATO message format") end if parameters.ATISinterval and type(parameters.ATISinterval) == 'number' and parameters.ATISinterval > 0 then hound:setAtisUpdateInterval(parameters.ATISinterval) veaf.loggers.get(veafHoundElint.Id):debug(string.format("ATIS interval set to %s", veaf.p(parameters.ATISinterval))) end if parameters.preBriefedContacts then for _,name in pairs(parameters.preBriefedContacts) do veaf.loggers.get(veafHoundElint.Id):debug(string.format("Attempting to add Pre-brief target named %s", veaf.p(name))) if name and type(name) == 'string' and (Group.getByName(name) or Unit.getByName(name)) then hound:preBriefedContact(name) veaf.loggers.get(veafHoundElint.Id):debug("Pre-brief target added") end end end if parameters.debug then hound:onScreenDebug(true) veaf.loggers.get(veafHoundElint.Id):debug("Debug enabled") end end if parameters.sectors and type(parameters.sectors) == 'table' then veaf.loggers.get(veafHoundElint.Id):debug("Checking sectors...") for SectorName, sectorParameters in pairs(parameters.sectors) do local skip = false veaf.loggers.get(veafHoundElint.Id):debug(string.format("Given Sector Name : %s", veaf.p(SectorName))) veaf.loggers.get(veafHoundElint.Id):trace(string.format("Sector Params : %s", veaf.p(sectorParameters))) local SectorName = SectorName if not SectorName then veaf.loggers.get(veafHoundElint.Id):debug("No SectorName has been given...") SectorName = "default" skip = true end if SectorName ~= "default" and tostring(SectorName) then SectorName = tostring(SectorName) veaf.loggers.get(veafHoundElint.Id):debug(string.format("Retained Sector Name : %s", veaf.p(SectorName))) local sector = hound:addSector(SectorName) if sector then veaf.loggers.get(veafHoundElint.Id):debug("Added sector !") if SectorName:lower() ~= veafHoundElint.globalSectorName:lower() then veaf.loggers.get(veafHoundElint.Id):debug("Setting zone for sector...") hound:setZone(SectorName, SectorName) if not hound:getZone(SectorName) then veaf.loggers.get(veafHoundElint.Id):debug("Could not find zone for sector...") hound:removeSector(SectorName) skip = true else veaf.loggers.get(veafHoundElint.Id):debug("Zone found and set") end else veaf.loggers.get(veafHoundElint.Id):debug("No zone needs to be set for global sector") end else veaf.loggers.get(veafHoundElint.Id):debug("No sectors added, Hound problem...") skip = true end elseif SectorName ~= "default" then veaf.loggers.get(veafHoundElint.Id):debug("Given Sector Name could not be converted to string...") skip = true end if not skip then if veafHoundElint.hasSectorCallsign(sectorParameters) then veaf.loggers.get(veafHoundElint.Id):debug("Setting sector callsign...") if sectorParameters.callsign == true or not tostring(sectorParameters.callsign) then veaf.loggers.get(veafHoundElint.Id):debug("Using sector name as callsign") sectorParameters.callsign = SectorName end veaf.loggers.get(veafHoundElint.Id):trace(string.format("Callsign : %s", veaf.p(tostring(sectorParameters.callsign)))) hound:setCallsign(SectorName, tostring(sectorParameters.callsign)) end if veafHoundElint.hasTransmitterUnit(sectorParameters) then veaf.loggers.get(veafHoundElint.Id):debug("Setting transmitter unit...") veaf.loggers.get(veafHoundElint.Id):trace(string.format("transmitter unitName : %s", veaf.p(tostring(sectorParameters.transmitterUnit)))) hound:setTransmitter(SectorName, tostring(sectorParameters.transmitterUnit)) end if veafHoundElint.hasAtis(sectorParameters) then veaf.loggers.get(veafHoundElint.Id):debug("Setting up ATIS...") veaf.loggers.get(veafHoundElint.Id):trace(string.format("ATIS params : %s", veaf.p(sectorParameters.atis))) hound:enableAtis(SectorName, sectorParameters.atis) if sectorParameters.atis.reportEWR then veaf.loggers.get(veafHoundElint.Id):debug("ATIS will report EWRs as threats") hound:reportEWR(SectorName, sectorParameters.atis.reportEWR) end end if veafHoundElint.hasController(sectorParameters) then veaf.loggers.get(veafHoundElint.Id):debug("Setting up Controller...") veaf.loggers.get(veafHoundElint.Id):trace(string.format("Controller params : %s", veaf.p(sectorParameters.controller))) hound:enableController(SectorName, sectorParameters.controller) local textMode = not(veafHoundElint.hasControllerVoice(sectorParameters)) if textMode then veaf.loggers.get(veafHoundElint.Id):debug("Controller is text only") hound:enableText(SectorName) end end if veafHoundElint.hasNotifier(sectorParameters) then veaf.loggers.get(veafHoundElint.Id):debug("Setting up Notifier...") veaf.loggers.get(veafHoundElint.Id):trace(string.format("Notifier params : %s", veaf.p(sectorParameters.notifier))) hound:enableNotifier(SectorName, sectorParameters.notifier) end if veafHoundElint.hasNoAlerts(sectorParameters) then veaf.loggers.get(veafHoundElint.Id):debug("Disabling alerts for controller/ATIS") hound:disableAlerts(SectorName) end if veafHoundElint.hasNoTTS(sectorParameters) then veaf.loggers.get(veafHoundElint.Id):debug("Disabling TTS overall") hound:disableTTS(SectorName) end else veaf.loggers.get(veafHoundElint.Id):debug("Skipping sector") end end else veaf.loggers.get(veafHoundElint.Id):debug("No sectors to add/configure") end --activate the Hound system hound:systemOn() end ------------------------------------------------------------------------------------------------------------------------------------------------------------- -- initialisation ------------------------------------------------------------------------------------------------------------------------------------------------------------- local function createSystems(loadUnits, atMissionStart) veaf.loggers.get(veafHoundElint.Id):debug(string.format("createSystems(%s, %s)", veaf.p(loadUnits), veaf.p(atMissionStart))) veafHoundElint.redHound = HoundElint:create(coalition.side.RED) veafHoundElint.redHound.name = "RED Hound" veafHoundElint.blueHound = HoundElint:create(coalition.side.BLUE) veafHoundElint.blueHound.name = "BLUE Hound" if loadUnits then initializeHoundSystem(coalition.side.RED, veafHoundElint.redParameters, atMissionStart) initializeHoundSystem(coalition.side.BLUE, veafHoundElint.blueParameters, atMissionStart) end end -- reset the Hound networks and rebuild them. Useful when a dynamic combat zone is deactivated function veafHoundElint.reinitialize(delay) veaf.loggers.get(veafHoundElint.Id):debug(string.format("reinitialize(%s)", veaf.p(delay))) if not veafHoundElint.reinitializeTaskID then if delay then veafHoundElint.reinitializeTaskID = mist.scheduleFunction(veafHoundElint._reinitialize , nil, veafHoundElint.DelayForStartup) end end end function veafHoundElint._reinitialize() veaf.loggers.get(veafHoundElint.Id):debug(string.format("_reinitialize()")) if not veafHoundElint.initialized then return false end if veafHoundElint.redHound then veafHoundElint.redHound:systemOff() end if veafHoundElint.blueHound then veafHoundElint.blueHound:systemOff() end createSystems(true, false) if veafHoundElint.reinitializeTaskID then veafHoundElint.reinitializeTaskID = nil end end function veafHoundElint.hasSectorCallsign(parameters) return parameters.callsign and tostring(parameters.callsign) end function veafHoundElint.hasTransmitterUnit(parameters) return parameters and parameters.transmitterUnit and tostring(parameters.transmitterUnit) and Group.getByName(parameters.transmitterUnit) end function veafHoundElint.hasAtis(parameters) return parameters and parameters.atis end function veafHoundElint.hasController(parameters) return parameters and parameters.controller end function veafHoundElint.hasControllerVoice(parameters) return parameters and parameters.controller and parameters.controller.voiceEnabled end function veafHoundElint.hasNotifier(parameters) return parameters and parameters.notifier end function veafHoundElint.hasNoTTS(parameters) return parameters and parameters.disableTTS end function veafHoundElint.hasNoAlerts(parameters) return parameters and parameters.disableAlerts end function veafHoundElint.initialize(prefix, red, blue) veafHoundElint.prefix = prefix -- if nil, all capable units will be set as Elint platforms veafHoundElint.redParameters = red or {} veafHoundElint.blueParameters = blue or {} veaf.loggers.get(veafHoundElint.Id):info("Initializing module") veaf.loggers.get(veafHoundElint.Id):debug(string.format("red=%s",veaf.p(red))) veaf.loggers.get(veafHoundElint.Id):debug(string.format("blue=%s",veaf.p(blue))) -- prepare the list of units supported by Hound Elint for platformType, platformData in pairs(HOUND.DB.Platform[Object.Category.STATIC]) do veafHoundElint.elintUnitsTypes[platformType] = true end for platformType, platformData in pairs(HOUND.DB.Platform[Object.Category.UNIT]) do veafHoundElint.elintUnitsTypes[platformType] = true end veaf.loggers.get(veafHoundElint.Id):trace(string.format("veafHoundElint.elintUnitsTypes=%s",veaf.p(veafHoundElint.elintUnitsTypes))) veafHoundElint.initialized = true veaf.loggers.get(veafHoundElint.Id):info(string.format("Loading units")) createSystems(true, true) veaf.loggers.get(veafHoundElint.Id):info(string.format("Hound Elint has been initialized")) end veaf.loggers.get(veafHoundElint.Id):info(string.format("Loading version %s", veafHoundElint.Version)) HOUND.Utils.Marker._MarkId = 1235634 -- select a less obvious marker id range that `9999`